Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / ntp / ntpd / ntp_control.c
CommitLineData
984263bc
MD
1/*
2 * ntp_control.c - respond to control messages and send async traps
3 */
4
5/*
6 * $FreeBSD: src/contrib/ntp/ntpd/ntp_control.c,v 1.1.1.2.2.3 2001/12/21 17:39:12 roberto Exp $
1de703da 7 * $DragonFly: src/contrib/ntp/ntpd/Attic/ntp_control.c,v 1.2 2003/06/17 04:24:04 dillon Exp $
984263bc
MD
8 */
9
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
14#include "ntpd.h"
15#include "ntp_io.h"
16#include "ntp_refclock.h"
17#include "ntp_control.h"
18#include "ntp_stdlib.h"
19
20#include <stdio.h>
21#include <ctype.h>
22#include <signal.h>
23
24#include <netinet/in.h>
25#include <arpa/inet.h>
26
27#ifdef PUBKEY
28#include "ntp_crypto.h"
29#endif /* PUBKEY */
30
31/*
32 * Structure to hold request procedure information
33 */
34#define NOAUTH 0
35#define AUTH 1
36
37#define NO_REQUEST (-1)
38
39struct ctl_proc {
40 short control_code; /* defined request code */
41 u_short flags; /* flags word */
42 void (*handler) P((struct recvbuf *, int)); /* handle request */
43};
44
45/*
46 * Only one flag. Authentication required or not.
47 */
48#define NOAUTH 0
49#define AUTH 1
50
51/*
52 * Request processing routines
53 */
54static void ctl_error P((int));
55static u_short ctlclkstatus P((struct refclockstat *));
56static void ctl_flushpkt P((int));
57static void ctl_putdata P((const char *, unsigned int, int));
58static void ctl_putstr P((const char *, const char *,
59 unsigned int));
60static void ctl_putdbl P((const char *, double));
61static void ctl_putuint P((const char *, u_long));
62static void ctl_puthex P((const char *, u_long));
63static void ctl_putint P((const char *, long));
64static void ctl_putts P((const char *, l_fp *));
65static void ctl_putadr P((const char *, u_int32));
66static void ctl_putid P((const char *, char *));
67static void ctl_putarray P((const char *, double *, int));
68static void ctl_putsys P((int));
69static void ctl_putpeer P((int, struct peer *));
70#ifdef REFCLOCK
71static void ctl_putclock P((int, struct refclockstat *, int));
72#endif /* REFCLOCK */
73static struct ctl_var *ctl_getitem P((struct ctl_var *, char **));
74static u_long count_var P((struct ctl_var *));
75static void control_unspec P((struct recvbuf *, int));
76static void read_status P((struct recvbuf *, int));
77static void read_variables P((struct recvbuf *, int));
78static void write_variables P((struct recvbuf *, int));
79static void read_clock_status P((struct recvbuf *, int));
80static void write_clock_status P((struct recvbuf *, int));
81static void set_trap P((struct recvbuf *, int));
82static void unset_trap P((struct recvbuf *, int));
83static struct ctl_trap *ctlfindtrap P((struct sockaddr_in *,
84 struct interface *));
85
86static struct ctl_proc control_codes[] = {
87 { CTL_OP_UNSPEC, NOAUTH, control_unspec },
88 { CTL_OP_READSTAT, NOAUTH, read_status },
89 { CTL_OP_READVAR, NOAUTH, read_variables },
90 { CTL_OP_WRITEVAR, AUTH, write_variables },
91 { CTL_OP_READCLOCK, NOAUTH, read_clock_status },
92 { CTL_OP_WRITECLOCK, NOAUTH, write_clock_status },
93 { CTL_OP_SETTRAP, NOAUTH, set_trap },
94 { CTL_OP_UNSETTRAP, NOAUTH, unset_trap },
95 { NO_REQUEST, 0 }
96};
97
98/*
99 * System variable values. The array can be indexed by the variable
100 * index to find the textual name.
101 */
102static struct ctl_var sys_var[] = {
103 { 0, PADDING, "" }, /* 0 */
104 { CS_LEAP, RW, "leap" }, /* 1 */
105 { CS_STRATUM, RO, "stratum" }, /* 2 */
106 { CS_PRECISION, RO, "precision" }, /* 3 */
107 { CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */
108 { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */
109 { CS_REFID, RO, "refid" }, /* 6 */
110 { CS_REFTIME, RO, "reftime" }, /* 7 */
111 { CS_POLL, RO, "poll" }, /* 8 */
112 { CS_PEERID, RO, "peer" }, /* 9 */
113 { CS_STATE, RO, "state" }, /* 10 */
114 { CS_OFFSET, RO, "offset" }, /* 11 */
115 { CS_DRIFT, RO, "frequency" }, /* 12 */
116 { CS_JITTER, RO, "jitter" }, /* 13 */
117 { CS_CLOCK, RO, "clock" }, /* 14 */
118 { CS_PROCESSOR, RO, "processor" }, /* 15 */
119 { CS_SYSTEM, RO, "system" }, /* 16 */
120 { CS_VERSION, RO, "version" }, /* 17 */
121 { CS_STABIL, RO, "stability" }, /* 18 */
122 { CS_VARLIST, RO, "sys_var_list" }, /* 19 */
123#ifdef PUBKEY
124 { CS_FLAGS, RO, "flags" }, /* 20 */
125 { CS_HOST, RO, "hostname" }, /* 21 */
126 { CS_PUBLIC, RO, "publickey" }, /* 22 */
127 { CS_CERTIF, RO, "certificate" }, /* 23 */
128 { CS_DHPARAMS, RO, "params" }, /* 24 */
129 { CS_REVTIME, RO, "refresh" }, /* 25 */
130 { CS_LEAPTAB, RO, "leapseconds" }, /* 26 */
131 { CS_TAI, RO, "tai"}, /* 27 */
132#endif /* PUBKEY */
133 { 0, EOV, "" } /* 28 */
134};
135
136static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
137
138/*
139 * System variables we print by default (in fuzzball order,
140 * more-or-less)
141 */
142static u_char def_sys_var[] = {
143 CS_VERSION,
144 CS_PROCESSOR,
145 CS_SYSTEM,
146 CS_LEAP,
147 CS_STRATUM,
148 CS_PRECISION,
149 CS_ROOTDELAY,
150 CS_ROOTDISPERSION,
151 CS_PEERID,
152 CS_REFID,
153 CS_REFTIME,
154 CS_POLL,
155 CS_CLOCK,
156 CS_STATE,
157 CS_OFFSET,
158 CS_DRIFT,
159 CS_JITTER,
160 CS_STABIL,
161#ifdef PUBKEY
162 CS_FLAGS,
163 CS_HOST,
164 CS_CERTIF,
165 CS_DHPARAMS,
166 CS_REVTIME,
167 CS_LEAPTAB,
168#endif /* PUBKEY */
169 0
170};
171
172
173/*
174 * Peer variable list
175 */
176static struct ctl_var peer_var[] = {
177 { 0, PADDING, "" }, /* 0 */
178 { CP_CONFIG, RO, "config" }, /* 1 */
179 { CP_AUTHENABLE, RO, "authenable" }, /* 2 */
180 { CP_AUTHENTIC, RO, "authentic" }, /* 3 */
181 { CP_SRCADR, RO, "srcadr" }, /* 4 */
182 { CP_SRCPORT, RO, "srcport" }, /* 5 */
183 { CP_DSTADR, RO, "dstadr" }, /* 6 */
184 { CP_DSTPORT, RO, "dstport" }, /* 7 */
185 { CP_LEAP, RO, "leap" }, /* 8 */
186 { CP_HMODE, RO, "hmode" }, /* 9 */
187 { CP_STRATUM, RO, "stratum" }, /* 10 */
188 { CP_PPOLL, RO, "ppoll" }, /* 11 */
189 { CP_HPOLL, RO, "hpoll" }, /* 12 */
190 { CP_PRECISION, RO, "precision" }, /* 13 */
191 { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */
192 { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */
193 { CP_REFID, RO, "refid" }, /* 16 */
194 { CP_REFTIME, RO, "reftime" }, /* 17 */
195 { CP_ORG, RO, "org" }, /* 18 */
196 { CP_REC, RO, "rec" }, /* 19 */
197 { CP_XMT, RO, "xmt" }, /* 20 */
198 { CP_REACH, RO, "reach" }, /* 21 */
199 { CP_VALID, RO, "unreach" }, /* 22 */
200 { CP_TIMER, RO, "timer" }, /* 23 */
201 { CP_DELAY, RO, "delay" }, /* 24 */
202 { CP_OFFSET, RO, "offset" }, /* 25 */
203 { CP_JITTER, RO, "jitter" }, /* 26 */
204 { CP_DISPERSION, RO, "dispersion" }, /* 27 */
205 { CP_KEYID, RO, "keyid" }, /* 28 */
206 { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */
207 { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */
208 { CP_PMODE, RO, "pmode" }, /* 31 */
209 { CP_RECEIVED, RO, "received"}, /* 32 */
210 { CP_SENT, RO, "sent" }, /* 33 */
211 { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */
212 { CP_FLASH, RO, "flash" }, /* 35 */
213 { CP_TTL, RO, "ttl" }, /* 36 */
214 { CP_TTLMAX, RO, "ttlmax" }, /* 37 */
215 { CP_VARLIST, RO, "peer_var_list" }, /* 38 */
216#ifdef PUBKEY
217 { CP_FLAGS, RO, "flags" }, /* 38 */
218 { CP_HOST, RO, "hostname" }, /* 39 */
219 { CP_PUBLIC, RO, "publickey" }, /* 40 */
220 { CP_CERTIF, RO, "certificate" }, /* 41 */
221 { CP_SESKEY, RO, "pcookie" }, /* 42 */
222 { CP_SASKEY, RO, "hcookie" }, /* 43 */
223 { CP_INITSEQ, RO, "initsequence" }, /* 44 */
224 { CP_INITKEY, RO, "initkey" }, /* 45 */
225 { CP_INITTSP, RO, "timestamp" }, /* 46 */
226#endif /* PUBKEY */
227 { 0, EOV, "" } /* 47 */
228};
229
230
231/*
232 * Peer variables we print by default
233 */
234static u_char def_peer_var[] = {
235 CP_SRCADR,
236 CP_SRCPORT,
237 CP_DSTADR,
238 CP_DSTPORT,
239 CP_LEAP,
240 CP_STRATUM,
241 CP_PRECISION,
242 CP_ROOTDELAY,
243 CP_ROOTDISPERSION,
244 CP_REFID,
245 CP_REACH,
246 CP_VALID,
247 CP_HMODE,
248 CP_PMODE,
249 CP_HPOLL,
250 CP_PPOLL,
251 CP_FLASH,
252 CP_KEYID,
253 CP_TTL,
254 CP_TTLMAX,
255 CP_OFFSET,
256 CP_DELAY,
257 CP_DISPERSION,
258 CP_JITTER,
259 CP_REFTIME,
260 CP_ORG,
261 CP_REC,
262 CP_XMT,
263 CP_FILTDELAY,
264 CP_FILTOFFSET,
265 CP_FILTERROR,
266#ifdef PUBKEY
267 CP_FLAGS,
268 CP_HOST,
269 CP_CERTIF,
270 CP_SESKEY,
271 CP_INITSEQ,
272#endif /* PUBKEY */
273 0
274};
275
276
277#ifdef REFCLOCK
278/*
279 * Clock variable list
280 */
281static struct ctl_var clock_var[] = {
282 { 0, PADDING, "" }, /* 0 */
283 { CC_TYPE, RO, "type" }, /* 1 */
284 { CC_TIMECODE, RO, "timecode" }, /* 2 */
285 { CC_POLL, RO, "poll" }, /* 3 */
286 { CC_NOREPLY, RO, "noreply" }, /* 4 */
287 { CC_BADFORMAT, RO, "badformat" }, /* 5 */
288 { CC_BADDATA, RO, "baddata" }, /* 6 */
289 { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */
290 { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */
291 { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */
292 { CC_FUDGEVAL2, RO, "refid" }, /* 10 */
293 { CC_FLAGS, RO, "flags" }, /* 11 */
294 { CC_DEVICE, RO, "device" }, /* 12 */
295 { CC_VARLIST, RO, "clock_var_list" }, /* 13 */
296 { 0, EOV, "" } /* 14 */
297};
298
299
300/*
301 * Clock variables printed by default
302 */
303static u_char def_clock_var[] = {
304 CC_DEVICE,
305 CC_TYPE, /* won't be output if device = known */
306 CC_TIMECODE,
307 CC_POLL,
308 CC_NOREPLY,
309 CC_BADFORMAT,
310 CC_BADDATA,
311 CC_FUDGETIME1,
312 CC_FUDGETIME2,
313 CC_FUDGEVAL1,
314 CC_FUDGEVAL2,
315 CC_FLAGS,
316 0
317};
318#endif
319
320
321/*
322 * System and processor definitions.
323 */
324#ifndef HAVE_UNAME
325# ifndef STR_SYSTEM
326# define STR_SYSTEM "UNIX"
327# endif
328# ifndef STR_PROCESSOR
329# define STR_PROCESSOR "unknown"
330# endif
331
332static char str_system[] = STR_SYSTEM;
333static char str_processor[] = STR_PROCESSOR;
334#else
335# include <sys/utsname.h>
336static struct utsname utsnamebuf;
337#endif /* HAVE_UNAME */
338
339/*
340 * Trap structures. We only allow a few of these, and send a copy of
341 * each async message to each live one. Traps time out after an hour, it
342 * is up to the trap receipient to keep resetting it to avoid being
343 * timed out.
344 */
345/* ntp_request.c */
346struct ctl_trap ctl_trap[CTL_MAXTRAPS];
347int num_ctl_traps;
348
349/*
350 * Type bits, for ctlsettrap() call.
351 */
352#define TRAP_TYPE_CONFIG 0 /* used by configuration code */
353#define TRAP_TYPE_PRIO 1 /* priority trap */
354#define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */
355
356
357/*
358 * List relating reference clock types to control message time sources.
359 * Index by the reference clock type. This list will only be used iff
360 * the reference clock driver doesn't set peer->sstclktype to something
361 * different than CTL_SST_TS_UNSPEC.
362 */
363static u_char clocktypes[] = {
364 CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
365 CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */
366 CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */
367 CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */
368 CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */
369 CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */
370 CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */
371 CTL_SST_TS_HF, /* REFCLK_CHU (7) */
372 CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */
373 CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */
374 CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
375 CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */
376 CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
377 CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */
378 CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */
379 CTL_SST_TS_UHF, /* REFCLK_TRUETIME (15) */
380 CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
381 CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
382 CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */
383 CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */
384 CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
385 CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */
386 CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */
387 CTL_SST_TS_TELEPHONE, /* REFCLK_PTB_ACTS (23) */
388 CTL_SST_TS_TELEPHONE, /* REFCLK_USNO (24) */
389 CTL_SST_TS_UHF, /* REFCLK_TRUETIME (25) */
390 CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */
391 CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */
392 CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */
393 CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */
394 CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */
395 CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */
396 CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */
397 CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (32) */
398 CTL_SST_TS_LF, /* REFCLK_ULINK (33) */
399 CTL_SST_TS_LF, /* REFCLK_PCF (35) */
400 CTL_SST_TS_LF, /* REFCLK_WWV (36) */
401 CTL_SST_TS_LF, /* REFCLK_FG (37) */
402 CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */
403 CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */
404};
405
406
407/*
408 * Keyid used for authenticating write requests.
409 */
410keyid_t ctl_auth_keyid;
411
412/*
413 * We keep track of the last error reported by the system internally
414 */
415static u_char ctl_sys_last_event;
416static u_char ctl_sys_num_events;
417
418
419/*
420 * Statistic counters to keep track of requests and responses.
421 */
422u_long ctltimereset; /* time stats reset */
423u_long numctlreq; /* number of requests we've received */
424u_long numctlbadpkts; /* number of bad control packets */
425u_long numctlresponses; /* number of resp packets sent with data */
426u_long numctlfrags; /* number of fragments sent */
427u_long numctlerrors; /* number of error responses sent */
428u_long numctltooshort; /* number of too short input packets */
429u_long numctlinputresp; /* number of responses on input */
430u_long numctlinputfrag; /* number of fragments on input */
431u_long numctlinputerr; /* number of input pkts with err bit set */
432u_long numctlbadoffset; /* number of input pkts with nonzero offset */
433u_long numctlbadversion; /* number of input pkts with unknown version */
434u_long numctldatatooshort; /* data too short for count */
435u_long numctlbadop; /* bad op code found in packet */
436u_long numasyncmsgs; /* number of async messages we've sent */
437
438/*
439 * Response packet used by these routines. Also some state information
440 * so that we can handle packet formatting within a common set of
441 * subroutines. Note we try to enter data in place whenever possible,
442 * but the need to set the more bit correctly means we occasionally
443 * use the extra buffer and copy.
444 */
445static struct ntp_control rpkt;
446static u_char res_version;
447static u_char res_opcode;
448static associd_t res_associd;
449static int res_offset;
450static u_char * datapt;
451static u_char * dataend;
452static int datalinelen;
453static int datanotbinflag;
454static struct sockaddr_in *rmt_addr;
455static struct interface *lcl_inter;
456
457static u_char res_authenticate;
458static u_char res_authokay;
459static keyid_t res_keyid;
460
461#define MAXDATALINELEN (72)
462
463static u_char res_async; /* set to 1 if this is async trap response */
464
465/*
466 * Pointers for saving state when decoding request packets
467 */
468static char *reqpt;
469static char *reqend;
470
471/*
472 * init_control - initialize request data
473 */
474void
475init_control(void)
476{
477 int i;
478
479#ifdef HAVE_UNAME
480 uname(&utsnamebuf);
481#endif /* HAVE_UNAME */
482
483 ctl_clr_stats();
484
485 ctl_auth_keyid = 0;
486 ctl_sys_last_event = EVNT_UNSPEC;
487 ctl_sys_num_events = 0;
488
489 num_ctl_traps = 0;
490 for (i = 0; i < CTL_MAXTRAPS; i++)
491 ctl_trap[i].tr_flags = 0;
492}
493
494
495/*
496 * ctl_error - send an error response for the current request
497 */
498static void
499ctl_error(
500 int errcode
501 )
502{
503#ifdef DEBUG
504 if (debug >= 4)
505 printf("sending control error %d\n", errcode);
506#endif
507 /*
508 * Fill in the fields. We assume rpkt.sequence and rpkt.associd
509 * have already been filled in.
510 */
511 rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode &
512 CTL_OP_MASK));
513 rpkt.status = htons((u_short) ((errcode<<8) & 0xff00));
514 rpkt.count = 0;
515
516 /*
517 * send packet and bump counters
518 */
519 if (res_authenticate && sys_authenticate) {
520 int maclen;
521
522 *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) =
523 htonl(res_keyid);
524 maclen = authencrypt(res_keyid, (u_int32 *)&rpkt,
525 CTL_HEADER_LEN);
526 sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
527 CTL_HEADER_LEN + maclen);
528 } else {
529 sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
530 CTL_HEADER_LEN);
531 }
532 numctlerrors++;
533}
534
535
536/*
537 * process_control - process an incoming control message
538 */
539void
540process_control(
541 struct recvbuf *rbufp,
542 int restrict_mask
543 )
544{
545 register struct ntp_control *pkt;
546 register int req_count;
547 register int req_data;
548 register struct ctl_proc *cc;
549 int properlen;
550 int maclen;
551
552#ifdef DEBUG
553 if (debug > 2)
554 printf("in process_control()\n");
555#endif
556
557 /*
558 * Save the addresses for error responses
559 */
560 numctlreq++;
561 rmt_addr = &rbufp->recv_srcadr;
562 lcl_inter = rbufp->dstadr;
563 pkt = (struct ntp_control *)&rbufp->recv_pkt;
564
565 /*
566 * If the length is less than required for the header, or
567 * it is a response or a fragment, ignore this.
568 */
569 if (rbufp->recv_length < CTL_HEADER_LEN
570 || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR)
571 || pkt->offset != 0) {
572#ifdef DEBUG
573 if (debug)
574 printf("invalid format in control packet\n");
575#endif
576 if (rbufp->recv_length < CTL_HEADER_LEN)
577 numctltooshort++;
578 if (pkt->r_m_e_op & CTL_RESPONSE)
579 numctlinputresp++;
580 if (pkt->r_m_e_op & CTL_MORE)
581 numctlinputfrag++;
582 if (pkt->r_m_e_op & CTL_ERROR)
583 numctlinputerr++;
584 if (pkt->offset != 0)
585 numctlbadoffset++;
586 return;
587 }
588 res_version = PKT_VERSION(pkt->li_vn_mode);
589 if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {
590#ifdef DEBUG
591 if (debug)
592 printf("unknown version %d in control packet\n",
593 res_version);
594#endif
595 numctlbadversion++;
596 return;
597 }
598
599 /*
600 * Pull enough data from the packet to make intelligent
601 * responses
602 */
603 rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version,
604 MODE_CONTROL);
605 res_opcode = pkt->r_m_e_op;
606 rpkt.sequence = pkt->sequence;
607 rpkt.associd = pkt->associd;
608 rpkt.status = 0;
609 res_offset = 0;
610 res_associd = htons(pkt->associd);
611 res_async = 0;
612 res_authenticate = 0;
613 res_keyid = 0;
614 res_authokay = 0;
615 req_count = (int)htons(pkt->count);
616 datanotbinflag = 0;
617 datalinelen = 0;
618 datapt = rpkt.data;
619 dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
620
621 /*
622 * We're set up now. Make sure we've got at least enough
623 * incoming data space to match the count.
624 */
625 req_data = rbufp->recv_length - CTL_HEADER_LEN;
626 if (req_data < req_count || rbufp->recv_length & 0x3) {
627 ctl_error(CERR_BADFMT);
628 numctldatatooshort++;
629 return;
630 }
631
632 properlen = req_count + CTL_HEADER_LEN;
633#ifdef DEBUG
634 if (debug > 2 && (rbufp->recv_length & 0x3) != 0)
635 printf("Packet length %d unrounded\n",
636 rbufp->recv_length);
637#endif
638 /* round up proper len to a 8 octet boundary */
639
640 properlen = (properlen + 7) & ~7;
641 maclen = rbufp->recv_length - properlen;
642 if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 &&
643 maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN &&
644 sys_authenticate) {
645 res_authenticate = 1;
646 res_keyid = ntohl(*(u_int32 *)((u_char *)pkt +
647 properlen));
648
649#ifdef DEBUG
650 if (debug > 2)
651 printf(
652 "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
653 rbufp->recv_length, properlen, res_keyid, maclen);
654#endif
655 if (!authistrusted(res_keyid)) {
656#ifdef DEBUG
657 if (debug > 2)
658 printf("invalid keyid %08x\n",
659 res_keyid);
660#endif
661 } else if (authdecrypt(res_keyid, (u_int32 *)pkt,
662 rbufp->recv_length - maclen, maclen)) {
663#ifdef DEBUG
664 if (debug > 2)
665 printf("authenticated okay\n");
666#endif
667 res_authokay = 1;
668 } else {
669#ifdef DEBUG
670 if (debug > 2)
671 printf("authentication failed\n");
672#endif
673 res_keyid = 0;
674 }
675 }
676
677 /*
678 * Set up translate pointers
679 */
680 reqpt = (char *)pkt->data;
681 reqend = reqpt + req_count;
682
683 /*
684 * Look for the opcode processor
685 */
686 for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) {
687 if (cc->control_code == res_opcode) {
688#ifdef DEBUG
689 if (debug > 2)
690 printf("opcode %d, found command handler\n",
691 res_opcode);
692#endif
693 if (cc->flags == AUTH && (!res_authokay ||
694 res_keyid != ctl_auth_keyid)) {
695 ctl_error(CERR_PERMISSION);
696 return;
697 }
698 (cc->handler)(rbufp, restrict_mask);
699 return;
700 }
701 }
702
703 /*
704 * Can't find this one, return an error.
705 */
706 numctlbadop++;
707 ctl_error(CERR_BADOP);
708 return;
709}
710
711
712/*
713 * ctlpeerstatus - return a status word for this peer
714 */
715u_short
716ctlpeerstatus(
717 register struct peer *peer
718 )
719{
720 register u_short status;
721
722 status = peer->status;
723 if (peer->flags & FLAG_CONFIG)
724 status |= CTL_PST_CONFIG;
725 if (peer->flags & FLAG_AUTHENABLE)
726 status |= CTL_PST_AUTHENABLE;
727 if (peer->flags & FLAG_AUTHENTIC)
728 status |= CTL_PST_AUTHENTIC;
729 if (peer->reach != 0)
730 status |= CTL_PST_REACH;
731 return (u_short)CTL_PEER_STATUS(status, peer->num_events,
732 peer->last_event);
733}
734
735
736/*
737 * ctlclkstatus - return a status word for this clock
738 */
739static u_short
740ctlclkstatus(
741 struct refclockstat *this_clock
742 )
743{
744 return ((u_short)(this_clock->currentstatus) << 8) |
745 (u_short)(this_clock->lastevent);
746}
747
748
749/*
750 * ctlsysstatus - return the system status word
751 */
752u_short
753ctlsysstatus(void)
754{
755 register u_char this_clock;
756
757 this_clock = CTL_SST_TS_UNSPEC;
758 if (sys_peer != 0) {
759 if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
760 this_clock = sys_peer->sstclktype;
761 if (pps_control)
762 this_clock |= CTL_SST_TS_PPS;
763 } else {
764 if (sys_peer->refclktype < sizeof(clocktypes))
765 this_clock =
766 clocktypes[sys_peer->refclktype];
767 if (pps_control)
768 this_clock |= CTL_SST_TS_PPS;
769 }
770 }
771 return (u_short)CTL_SYS_STATUS(sys_leap, this_clock,
772 ctl_sys_num_events, ctl_sys_last_event);
773}
774
775
776/*
777 * ctl_flushpkt - write out the current packet and prepare
778 * another if necessary.
779 */
780static void
781ctl_flushpkt(
782 int more
783 )
784{
785 int dlen;
786 int sendlen;
787
788 if (!more && datanotbinflag) {
789 /*
790 * Big hack, output a trailing \r\n
791 */
792 *datapt++ = '\r';
793 *datapt++ = '\n';
794 }
795 dlen = datapt - (u_char *)rpkt.data;
796 sendlen = dlen + CTL_HEADER_LEN;
797
798 /*
799 * Pad to a multiple of 32 bits
800 */
801 while (sendlen & 0x3) {
802 *datapt++ = '\0';
803 sendlen++;
804 }
805
806 /*
807 * Fill in the packet with the current info
808 */
809 rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode &
810 CTL_OP_MASK));
811 rpkt.count = htons((u_short) dlen);
812 rpkt.offset = htons( (u_short) res_offset);
813 if (res_async) {
814 register int i;
815
816 for (i = 0; i < CTL_MAXTRAPS; i++) {
817 if (ctl_trap[i].tr_flags & TRAP_INUSE) {
818 rpkt.li_vn_mode =
819 PKT_LI_VN_MODE(sys_leap,
820 ctl_trap[i].tr_version,
821 MODE_CONTROL);
822 rpkt.sequence =
823 htons(ctl_trap[i].tr_sequence);
824 sendpkt(&ctl_trap[i].tr_addr,
825 ctl_trap[i].tr_localaddr, -4,
826 (struct pkt *)&rpkt, sendlen);
827 if (!more)
828 ctl_trap[i].tr_sequence++;
829 numasyncmsgs++;
830 }
831 }
832 } else {
833 if (res_authenticate && sys_authenticate) {
834 int maclen;
835 int totlen = sendlen;
836 keyid_t keyid = htonl(res_keyid);
837
838 /*
839 * If we are going to authenticate, then there
840 * is an additional requirement that the MAC
841 * begin on a 64 bit boundary.
842 */
843 while (totlen & 7) {
844 *datapt++ = '\0';
845 totlen++;
846 }
847 memcpy(datapt, &keyid, sizeof keyid);
848 maclen = authencrypt(res_keyid,
849 (u_int32 *)&rpkt, totlen);
850 sendpkt(rmt_addr, lcl_inter, -5,
851 (struct pkt *)&rpkt, totlen + maclen);
852 } else {
853 sendpkt(rmt_addr, lcl_inter, -6,
854 (struct pkt *)&rpkt, sendlen);
855 }
856 if (more)
857 numctlfrags++;
858 else
859 numctlresponses++;
860 }
861
862 /*
863 * Set us up for another go around.
864 */
865 res_offset += dlen;
866 datapt = (u_char *)rpkt.data;
867}
868
869
870/*
871 * ctl_putdata - write data into the packet, fragmenting and starting
872 * another if this one is full.
873 */
874static void
875ctl_putdata(
876 const char *dp,
877 unsigned int dlen,
878 int bin /* set to 1 when data is binary */
879 )
880{
881 int overhead;
882
883 overhead = 0;
884 if (!bin) {
885 datanotbinflag = 1;
886 overhead = 3;
887 if (datapt != rpkt.data) {
888 *datapt++ = ',';
889 datalinelen++;
890 if ((dlen + datalinelen + 1) >= MAXDATALINELEN)
891 {
892 *datapt++ = '\r';
893 *datapt++ = '\n';
894 datalinelen = 0;
895 } else {
896 *datapt++ = ' ';
897 datalinelen++;
898 }
899 }
900 }
901
902 /*
903 * Save room for trailing junk
904 */
905 if (dlen + overhead + datapt > dataend) {
906 /*
907 * Not enough room in this one, flush it out.
908 */
909 ctl_flushpkt(CTL_MORE);
910 }
911 memmove((char *)datapt, dp, (unsigned)dlen);
912 datapt += dlen;
913 datalinelen += dlen;
914}
915
916
917/*
918 * ctl_putstr - write a tagged string into the response packet
919 */
920static void
921ctl_putstr(
922 const char *tag,
923 const char *data,
924 unsigned int len
925 )
926{
927 register char *cp;
928 register const char *cq;
929 char buffer[400];
930
931 cp = buffer;
932 cq = tag;
933 while (*cq != '\0')
934 *cp++ = *cq++;
935 if (len > 0) {
936 *cp++ = '=';
937 *cp++ = '"';
938 if (len > (int) (sizeof(buffer) - (cp - buffer) - 1))
939 len = sizeof(buffer) - (cp - buffer) - 1;
940 memmove(cp, data, (unsigned)len);
941 cp += len;
942 *cp++ = '"';
943 }
944 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
945}
946
947
948/*
949 * ctl_putdbl - write a tagged, signed double into the response packet
950 */
951static void
952ctl_putdbl(
953 const char *tag,
954 double ts
955 )
956{
957 register char *cp;
958 register const char *cq;
959 char buffer[200];
960
961 cp = buffer;
962 cq = tag;
963 while (*cq != '\0')
964 *cp++ = *cq++;
965 *cp++ = '=';
966 (void)sprintf(cp, "%.3f", ts);
967 while (*cp != '\0')
968 cp++;
969 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
970}
971
972/*
973 * ctl_putuint - write a tagged unsigned integer into the response
974 */
975static void
976ctl_putuint(
977 const char *tag,
978 u_long uval
979 )
980{
981 register char *cp;
982 register const char *cq;
983 char buffer[200];
984
985 cp = buffer;
986 cq = tag;
987 while (*cq != '\0')
988 *cp++ = *cq++;
989
990 *cp++ = '=';
991 (void) sprintf(cp, "%lu", uval);
992 while (*cp != '\0')
993 cp++;
994 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
995}
996
997
998/*
999 * ctl_puthex - write a tagged unsigned integer, in hex, into the response
1000 */
1001static void
1002ctl_puthex(
1003 const char *tag,
1004 u_long uval
1005 )
1006{
1007 register char *cp;
1008 register const char *cq;
1009 char buffer[200];
1010
1011 cp = buffer;
1012 cq = tag;
1013 while (*cq != '\0')
1014 *cp++ = *cq++;
1015
1016 *cp++ = '=';
1017 (void) sprintf(cp, "0x%lx", uval);
1018 while (*cp != '\0')
1019 cp++;
1020 ctl_putdata(buffer,(unsigned)( cp - buffer ), 0);
1021}
1022
1023
1024/*
1025 * ctl_putint - write a tagged signed integer into the response
1026 */
1027static void
1028ctl_putint(
1029 const char *tag,
1030 long ival
1031 )
1032{
1033 register char *cp;
1034 register const char *cq;
1035 char buffer[200];
1036
1037 cp = buffer;
1038 cq = tag;
1039 while (*cq != '\0')
1040 *cp++ = *cq++;
1041
1042 *cp++ = '=';
1043 (void) sprintf(cp, "%ld", ival);
1044 while (*cp != '\0')
1045 cp++;
1046 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1047}
1048
1049
1050/*
1051 * ctl_putts - write a tagged timestamp, in hex, into the response
1052 */
1053static void
1054ctl_putts(
1055 const char *tag,
1056 l_fp *ts
1057 )
1058{
1059 register char *cp;
1060 register const char *cq;
1061 char buffer[200];
1062
1063 cp = buffer;
1064 cq = tag;
1065 while (*cq != '\0')
1066 *cp++ = *cq++;
1067
1068 *cp++ = '=';
1069 (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui & 0xffffffffL,
1070 ts->l_uf & 0xffffffffL);
1071 while (*cp != '\0')
1072 cp++;
1073 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1074}
1075
1076
1077/*
1078 * ctl_putadr - write a dotted quad IP address into the response
1079 */
1080static void
1081ctl_putadr(
1082 const char *tag,
1083 u_int32 addr
1084 )
1085{
1086 register char *cp;
1087 register const char *cq;
1088 char buffer[200];
1089
1090 cp = buffer;
1091 cq = tag;
1092 while (*cq != '\0')
1093 *cp++ = *cq++;
1094
1095 *cp++ = '=';
1096 cq = numtoa(addr);
1097 while (*cq != '\0')
1098 *cp++ = *cq++;
1099 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1100}
1101
1102
1103/*
1104 * ctl_putid - write a tagged clock ID into the response
1105 */
1106static void
1107ctl_putid(
1108 const char *tag,
1109 char *id
1110 )
1111{
1112 register char *cp;
1113 register const char *cq;
1114 char buffer[200];
1115
1116 cp = buffer;
1117 cq = tag;
1118 while (*cq != '\0')
1119 *cp++ = *cq++;
1120
1121 *cp++ = '=';
1122 cq = id;
1123 while (*cq != '\0' && (cq - id) < 4)
1124 *cp++ = *cq++;
1125 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1126}
1127
1128
1129/*
1130 * ctl_putarray - write a tagged eight element double array into the response
1131 */
1132static void
1133ctl_putarray(
1134 const char *tag,
1135 double *arr,
1136 int start
1137 )
1138{
1139 register char *cp;
1140 register const char *cq;
1141 char buffer[200];
1142 int i;
1143
1144 cp = buffer;
1145 cq = tag;
1146 while (*cq != '\0')
1147 *cp++ = *cq++;
1148 i = start;
1149 do {
1150 if (i == 0)
1151 i = NTP_SHIFT;
1152 i--;
1153 (void)sprintf(cp, " %.2f", arr[i] * 1e3);
1154 while (*cp != '\0')
1155 cp++;
1156 } while(i != start);
1157 ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
1158}
1159
1160
1161/*
1162 * ctl_putsys - output a system variable
1163 */
1164static void
1165ctl_putsys(
1166 int varid
1167 )
1168{
1169 l_fp tmp;
1170#ifdef HAVE_UNAME
1171 char str[256];
1172#endif
1173
1174 switch (varid) {
1175
1176 case CS_LEAP:
1177 ctl_putuint(sys_var[CS_LEAP].text, sys_leap);
1178 break;
1179
1180 case CS_STRATUM:
1181 ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum);
1182 break;
1183
1184 case CS_PRECISION:
1185 ctl_putint(sys_var[CS_PRECISION].text, sys_precision);
1186 break;
1187
1188 case CS_ROOTDELAY:
1189 ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay *
1190 1e3);
1191 break;
1192
1193 case CS_ROOTDISPERSION:
1194 ctl_putdbl(sys_var[CS_ROOTDISPERSION].text,
1195 sys_rootdispersion * 1e3);
1196 break;
1197
1198 case CS_REFID:
1199 if (sys_stratum > 1)
1200 ctl_putadr(sys_var[CS_REFID].text, sys_refid);
1201 else
1202 ctl_putid(sys_var[CS_REFID].text,
1203 (char *)&sys_refid);
1204 break;
1205
1206 case CS_REFTIME:
1207 ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
1208 break;
1209
1210 case CS_POLL:
1211 ctl_putuint(sys_var[CS_POLL].text, sys_poll);
1212 break;
1213
1214 case CS_PEERID:
1215 if (sys_peer == NULL)
1216 ctl_putuint(sys_var[CS_PEERID].text, 0);
1217 else
1218 ctl_putuint(sys_var[CS_PEERID].text,
1219 sys_peer->associd);
1220 break;
1221
1222 case CS_STATE:
1223 ctl_putuint(sys_var[CS_STATE].text, (unsigned)state);
1224 break;
1225
1226 case CS_OFFSET:
1227 ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3);
1228 break;
1229
1230 case CS_DRIFT:
1231 ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6);
1232 break;
1233
1234 case CS_JITTER:
1235 ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3);
1236 break;
1237
1238 case CS_CLOCK:
1239 get_systime(&tmp);
1240 ctl_putts(sys_var[CS_CLOCK].text, &tmp);
1241 break;
1242
1243 case CS_PROCESSOR:
1244#ifndef HAVE_UNAME
1245 ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor,
1246 sizeof(str_processor) - 1);
1247#else
1248 ctl_putstr(sys_var[CS_PROCESSOR].text,
1249 utsnamebuf.machine, strlen(utsnamebuf.machine));
1250#endif /* HAVE_UNAME */
1251 break;
1252
1253 case CS_SYSTEM:
1254#ifndef HAVE_UNAME
1255 ctl_putstr(sys_var[CS_SYSTEM].text, str_system,
1256 sizeof(str_system) - 1);
1257#else
1258 (void)strcpy(str, utsnamebuf.sysname);
1259 (void)strcat(str, utsnamebuf.release);
1260 ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str));
1261#endif /* HAVE_UNAME */
1262 break;
1263
1264 case CS_VERSION:
1265 ctl_putstr(sys_var[CS_VERSION].text, Version,
1266 strlen(Version));
1267 break;
1268
1269 case CS_STABIL:
1270 ctl_putdbl(sys_var[CS_STABIL].text, clock_stability *
1271 1e6);
1272 break;
1273
1274 case CS_VARLIST:
1275 {
1276 char buf[CTL_MAX_DATA_LEN];
1277 register char *s, *t, *be;
1278 register const char *ss;
1279 register int i;
1280 register struct ctl_var *k;
1281
1282 s = buf;
1283 be = buf + sizeof(buf) -
1284 strlen(sys_var[CS_VARLIST].text) - 4;
1285 if (s > be)
1286 break; /* really long var name */
1287
1288 strcpy(s, sys_var[CS_VARLIST].text);
1289 strcat(s, "=\"");
1290 s += strlen(s);
1291 t = s;
1292 for (k = sys_var; !(k->flags &EOV); k++) {
1293 if (k->flags & PADDING)
1294 continue;
1295 i = strlen(k->text);
1296 if (s+i+1 >= be)
1297 break;
1298
1299 if (s != t)
1300 *s++ = ',';
1301 strcpy(s, k->text);
1302 s += i;
1303 }
1304
1305 for (k = ext_sys_var; k && !(k->flags &EOV);
1306 k++) {
1307 if (k->flags & PADDING)
1308 continue;
1309
1310 ss = k->text;
1311 if (!ss)
1312 continue;
1313
1314 while (*ss && *ss != '=')
1315 ss++;
1316 i = ss - k->text;
1317 if (s + i + 1 >= be)
1318 break;
1319
1320 if (s != t)
1321 *s++ = ',';
1322 strncpy(s, k->text,
1323 (unsigned)i);
1324 s += i;
1325 }
1326 if (s+2 >= be)
1327 break;
1328
1329 *s++ = '"';
1330 *s = '\0';
1331
1332 ctl_putdata(buf, (unsigned)( s - buf ),
1333 0);
1334 }
1335 break;
1336
1337#ifdef PUBKEY
1338 case CS_FLAGS:
1339 if (crypto_flags)
1340 ctl_puthex(sys_var[CS_FLAGS].text,
1341 crypto_flags);
1342 break;
1343
1344 case CS_HOST:
1345 ctl_putstr(sys_var[CS_HOST].text, sys_hostname,
1346 strlen(sys_hostname));
1347 if (host.fstamp != 0)
1348 ctl_putuint(sys_var[CS_PUBLIC].text,
1349 ntohl(host.fstamp));
1350 break;
1351
1352 case CS_CERTIF:
1353 if (certif.fstamp != 0)
1354 ctl_putuint(sys_var[CS_CERTIF].text,
1355 ntohl(certif.fstamp));
1356 break;
1357
1358 case CS_DHPARAMS:
1359 if (dhparam.fstamp != 0)
1360 ctl_putuint(sys_var[CS_DHPARAMS].text,
1361 ntohl(dhparam.fstamp));
1362 break;
1363
1364 case CS_REVTIME:
1365 if (host.tstamp != 0)
1366 ctl_putuint(sys_var[CS_REVTIME].text,
1367 ntohl(host.tstamp));
1368 break;
1369
1370 case CS_LEAPTAB:
1371 if (tai_leap.fstamp != 0)
1372 ctl_putuint(sys_var[CS_LEAPTAB].text,
1373 ntohl(tai_leap.fstamp));
1374 if (sys_tai != 0)
1375 ctl_putuint(sys_var[CS_TAI].text, sys_tai);
1376 break;
1377#endif /* PUBKEY */
1378 }
1379}
1380
1381
1382/*
1383 * ctl_putpeer - output a peer variable
1384 */
1385static void
1386ctl_putpeer(
1387 int varid,
1388 struct peer *peer
1389 )
1390{
1391 switch (varid) {
1392
1393 case CP_CONFIG:
1394 ctl_putuint(peer_var[CP_CONFIG].text,
1395 (unsigned)((peer->flags & FLAG_CONFIG) != 0));
1396 break;
1397
1398 case CP_AUTHENABLE:
1399 ctl_putuint(peer_var[CP_AUTHENABLE].text,
1400 (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0));
1401 break;
1402
1403 case CP_AUTHENTIC:
1404 ctl_putuint(peer_var[CP_AUTHENTIC].text,
1405 (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0));
1406 break;
1407
1408 case CP_SRCADR:
1409 ctl_putadr(peer_var[CP_SRCADR].text,
1410 peer->srcadr.sin_addr.s_addr);
1411 break;
1412
1413 case CP_SRCPORT:
1414 ctl_putuint(peer_var[CP_SRCPORT].text,
1415 ntohs(peer->srcadr.sin_port));
1416 break;
1417
1418 case CP_DSTADR:
1419 ctl_putadr(peer_var[CP_DSTADR].text,
1420 peer->dstadr->sin.sin_addr.s_addr);
1421 break;
1422
1423 case CP_DSTPORT:
1424 ctl_putuint(peer_var[CP_DSTPORT].text,
1425 (u_long)(peer->dstadr ?
1426 ntohs(peer->dstadr->sin.sin_port) : 0));
1427 break;
1428
1429 case CP_LEAP:
1430 ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
1431 break;
1432
1433 case CP_HMODE:
1434 ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
1435 break;
1436
1437 case CP_STRATUM:
1438 ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
1439 break;
1440
1441 case CP_PPOLL:
1442 ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
1443 break;
1444
1445 case CP_HPOLL:
1446 ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
1447 break;
1448
1449 case CP_PRECISION:
1450 ctl_putint(peer_var[CP_PRECISION].text,
1451 peer->precision);
1452 break;
1453
1454 case CP_ROOTDELAY:
1455 ctl_putdbl(peer_var[CP_ROOTDELAY].text,
1456 peer->rootdelay * 1e3);
1457 break;
1458
1459 case CP_ROOTDISPERSION:
1460 ctl_putdbl(peer_var[CP_ROOTDISPERSION].text,
1461 peer->rootdispersion * 1e3);
1462 break;
1463
1464 case CP_REFID:
1465 if (peer->stratum > 1) {
1466 if (peer->flags & FLAG_REFCLOCK)
1467 ctl_putadr(peer_var[CP_REFID].text,
1468 peer->srcadr.sin_addr.s_addr);
1469 else
1470 ctl_putadr(peer_var[CP_REFID].text,
1471 peer->refid);
1472 } else {
1473 ctl_putid(peer_var[CP_REFID].text,
1474 (char *)&peer->refid);
1475 }
1476 break;
1477
1478 case CP_REFTIME:
1479 ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime);
1480 break;
1481
1482 case CP_ORG:
1483 ctl_putts(peer_var[CP_ORG].text, &peer->org);
1484 break;
1485
1486 case CP_REC:
1487 ctl_putts(peer_var[CP_REC].text, &peer->rec);
1488 break;
1489
1490 case CP_XMT:
1491 ctl_putts(peer_var[CP_XMT].text, &peer->xmt);
1492 break;
1493
1494 case CP_REACH:
1495 ctl_puthex(peer_var[CP_REACH].text, peer->reach);
1496 break;
1497
1498 case CP_FLASH:
1499 ctl_puthex(peer_var[CP_FLASH].text, peer->flash);
1500 break;
1501
1502 case CP_TTL:
1503 if (!(peer->cast_flags & MDF_ACAST))
1504 break;
1505 ctl_putint(peer_var[CP_TTL].text, peer->ttl);
1506 break;
1507
1508 case CP_TTLMAX:
1509 if (!(peer->cast_flags & (MDF_MCAST | MDF_ACAST)))
1510 break;
1511 ctl_putint(peer_var[CP_TTLMAX].text, peer->ttlmax);
1512 break;
1513
1514 case CP_VALID:
1515 ctl_putuint(peer_var[CP_VALID].text, peer->unreach);
1516 break;
1517
1518 case CP_TIMER:
1519 ctl_putuint(peer_var[CP_TIMER].text,
1520 peer->nextdate - current_time);
1521 break;
1522
1523 case CP_DELAY:
1524 ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3);
1525 break;
1526
1527 case CP_OFFSET:
1528 ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset *
1529 1e3);
1530 break;
1531
1532 case CP_JITTER:
1533 ctl_putdbl(peer_var[CP_JITTER].text,
1534 SQRT(peer->jitter) * 1e3);
1535 break;
1536
1537 case CP_DISPERSION:
1538 ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp *
1539 1e3);
1540 break;
1541
1542 case CP_KEYID:
1543 ctl_putuint(peer_var[CP_KEYID].text, peer->keyid);
1544 break;
1545
1546 case CP_FILTDELAY:
1547 ctl_putarray(peer_var[CP_FILTDELAY].text,
1548 peer->filter_delay, (int)peer->filter_nextpt);
1549 break;
1550
1551 case CP_FILTOFFSET:
1552 ctl_putarray(peer_var[CP_FILTOFFSET].text,
1553 peer->filter_offset, (int)peer->filter_nextpt);
1554 break;
1555
1556 case CP_FILTERROR:
1557 ctl_putarray(peer_var[CP_FILTERROR].text,
1558 peer->filter_disp, (int)peer->filter_nextpt);
1559 break;
1560
1561 case CP_PMODE:
1562 ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
1563 break;
1564
1565 case CP_RECEIVED:
1566 ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
1567 break;
1568
1569 case CP_SENT:
1570 ctl_putuint(peer_var[CP_SENT].text, peer->sent);
1571 break;
1572
1573 case CP_VARLIST:
1574 {
1575 char buf[CTL_MAX_DATA_LEN];
1576 register char *s, *t, *be;
1577 register int i;
1578 register struct ctl_var *k;
1579
1580 s = buf;
1581 be = buf + sizeof(buf) -
1582 strlen(peer_var[CP_VARLIST].text) - 4;
1583 if (s > be)
1584 break; /* really long var name */
1585
1586 strcpy(s, peer_var[CP_VARLIST].text);
1587 strcat(s, "=\"");
1588 s += strlen(s);
1589 t = s;
1590 for (k = peer_var; !(k->flags &EOV); k++) {
1591 if (k->flags & PADDING)
1592 continue;
1593
1594 i = strlen(k->text);
1595 if (s + i + 1 >= be)
1596 break;
1597
1598 if (s != t)
1599 *s++ = ',';
1600 strcpy(s, k->text);
1601 s += i;
1602 }
1603 if (s+2 >= be)
1604 break;
1605
1606 *s++ = '"';
1607 *s = '\0';
1608 ctl_putdata(buf, (unsigned)(s - buf), 0);
1609 }
1610 break;
1611#ifdef PUBKEY
1612 case CP_FLAGS:
1613 if (peer->crypto)
1614 ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto);
1615 break;
1616
1617 case CP_HOST:
1618 if (peer->keystr != NULL)
1619 ctl_putstr(peer_var[CP_HOST].text, peer->keystr,
1620 strlen(peer->keystr));
1621 if (peer->pubkey.fstamp != 0)
1622 ctl_putuint(peer_var[CP_PUBLIC].text,
1623 peer->pubkey.fstamp);
1624 break;
1625
1626 case CP_CERTIF:
1627 if (peer->certif.fstamp != 0)
1628 ctl_putuint(peer_var[CP_CERTIF].text,
1629 peer->certif.fstamp);
1630 break;
1631
1632 case CP_SESKEY:
1633 if (peer->pcookie.key != 0)
1634 ctl_puthex(peer_var[CP_SESKEY].text,
1635 peer->pcookie.key);
1636 if (peer->hcookie != 0)
1637 ctl_puthex(peer_var[CP_SASKEY].text,
1638 peer->hcookie);
1639 break;
1640
1641 case CP_INITSEQ:
1642 if (peer->recauto.key == 0)
1643 break;
1644 ctl_putint(peer_var[CP_INITSEQ].text,
1645 peer->recauto.seq);
1646 ctl_puthex(peer_var[CP_INITKEY].text,
1647 peer->recauto.key);
1648 ctl_putuint(peer_var[CP_INITTSP].text,
1649 peer->recauto.tstamp);
1650 break;
1651#endif /* PUBKEY */
1652 }
1653}
1654
1655
1656#ifdef REFCLOCK
1657/*
1658 * ctl_putclock - output clock variables
1659 */
1660static void
1661ctl_putclock(
1662 int varid,
1663 struct refclockstat *clock_stat,
1664 int mustput
1665 )
1666{
1667 switch(varid) {
1668
1669 case CC_TYPE:
1670 if (mustput || clock_stat->clockdesc == NULL
1671 || *(clock_stat->clockdesc) == '\0') {
1672 ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type);
1673 }
1674 break;
1675 case CC_TIMECODE:
1676 ctl_putstr(clock_var[CC_TIMECODE].text,
1677 clock_stat->p_lastcode,
1678 (unsigned)clock_stat->lencode);
1679 break;
1680
1681 case CC_POLL:
1682 ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls);
1683 break;
1684
1685 case CC_NOREPLY:
1686 ctl_putuint(clock_var[CC_NOREPLY].text,
1687 clock_stat->noresponse);
1688 break;
1689
1690 case CC_BADFORMAT:
1691 ctl_putuint(clock_var[CC_BADFORMAT].text,
1692 clock_stat->badformat);
1693 break;
1694
1695 case CC_BADDATA:
1696 ctl_putuint(clock_var[CC_BADDATA].text,
1697 clock_stat->baddata);
1698 break;
1699
1700 case CC_FUDGETIME1:
1701 if (mustput || (clock_stat->haveflags & CLK_HAVETIME1))
1702 ctl_putdbl(clock_var[CC_FUDGETIME1].text,
1703 clock_stat->fudgetime1 * 1e3);
1704 break;
1705
1706 case CC_FUDGETIME2:
1707 if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) ctl_putdbl(clock_var[CC_FUDGETIME2].text,
1708 clock_stat->fudgetime2 * 1e3);
1709 break;
1710
1711 case CC_FUDGEVAL1:
1712 if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1))
1713 ctl_putint(clock_var[CC_FUDGEVAL1].text,
1714 clock_stat->fudgeval1);
1715 break;
1716
1717 case CC_FUDGEVAL2:
1718 if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) {
1719 if (clock_stat->fudgeval1 > 1)
1720 ctl_putadr(clock_var[CC_FUDGEVAL2].text,
1721 (u_int32)clock_stat->fudgeval2);
1722 else
1723 ctl_putid(clock_var[CC_FUDGEVAL2].text,
1724 (char *)&clock_stat->fudgeval2);
1725 }
1726 break;
1727
1728 case CC_FLAGS:
1729 if (mustput || (clock_stat->haveflags & (CLK_HAVEFLAG1 |
1730 CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4)))
1731 ctl_putuint(clock_var[CC_FLAGS].text,
1732 clock_stat->flags);
1733 break;
1734
1735 case CC_DEVICE:
1736 if (clock_stat->clockdesc == NULL ||
1737 *(clock_stat->clockdesc) == '\0') {
1738 if (mustput)
1739 ctl_putstr(clock_var[CC_DEVICE].text,
1740 "", 0);
1741 } else {
1742 ctl_putstr(clock_var[CC_DEVICE].text,
1743 clock_stat->clockdesc,
1744 strlen(clock_stat->clockdesc));
1745 }
1746 break;
1747
1748 case CC_VARLIST:
1749 {
1750 char buf[CTL_MAX_DATA_LEN];
1751 register char *s, *t, *be;
1752 register const char *ss;
1753 register int i;
1754 register struct ctl_var *k;
1755
1756 s = buf;
1757 be = buf + sizeof(buf);
1758 if (s + strlen(clock_var[CC_VARLIST].text) + 4 >
1759 be)
1760 break; /* really long var name */
1761
1762 strcpy(s, clock_var[CC_VARLIST].text);
1763 strcat(s, "=\"");
1764 s += strlen(s);
1765 t = s;
1766
1767 for (k = clock_var; !(k->flags &EOV); k++) {
1768 if (k->flags & PADDING)
1769 continue;
1770
1771 i = strlen(k->text);
1772 if (s + i + 1 >= be)
1773 break;
1774
1775 if (s != t)
1776 *s++ = ',';
1777 strcpy(s, k->text);
1778 s += i;
1779 }
1780
1781 for (k = clock_stat->kv_list; k && !(k->flags &
1782 EOV); k++) {
1783 if (k->flags & PADDING)
1784 continue;
1785
1786 ss = k->text;
1787 if (!ss)
1788 continue;
1789
1790 while (*ss && *ss != '=')
1791 ss++;
1792 i = ss - k->text;
1793 if (s+i+1 >= be)
1794 break;
1795
1796 if (s != t)
1797 *s++ = ',';
1798 strncpy(s, k->text, (unsigned)i);
1799 s += i;
1800 *s = '\0';
1801 }
1802 if (s+2 >= be)
1803 break;
1804
1805 *s++ = '"';
1806 *s = '\0';
1807 ctl_putdata(buf, (unsigned)( s - buf ), 0);
1808 }
1809 break;
1810 }
1811}
1812#endif
1813
1814
1815
1816/*
1817 * ctl_getitem - get the next data item from the incoming packet
1818 */
1819static struct ctl_var *
1820ctl_getitem(
1821 struct ctl_var *var_list,
1822 char **data
1823 )
1824{
1825 register struct ctl_var *v;
1826 register char *cp;
1827 register char *tp;
1828 static struct ctl_var eol = { 0, EOV, };
1829 static char buf[128];
1830
1831 /*
1832 * Delete leading commas and white space
1833 */
1834 while (reqpt < reqend && (*reqpt == ',' ||
1835 isspace((unsigned char)*reqpt)))
1836 reqpt++;
1837 if (reqpt >= reqend)
1838 return (0);
1839
1840 if (var_list == (struct ctl_var *)0)
1841 return (&eol);
1842
1843 /*
1844 * Look for a first character match on the tag. If we find
1845 * one, see if it is a full match.
1846 */
1847 v = var_list;
1848 cp = reqpt;
1849 while (!(v->flags & EOV)) {
1850 if (!(v->flags & PADDING) && *cp == *(v->text)) {
1851 tp = v->text;
1852 while (*tp != '\0' && *tp != '=' && cp <
1853 reqend && *cp == *tp) {
1854 cp++;
1855 tp++;
1856 }
1857 if ((*tp == '\0') || (*tp == '=')) {
1858 while (cp < reqend && isspace((unsigned char)*cp))
1859 cp++;
1860 if (cp == reqend || *cp == ',') {
1861 buf[0] = '\0';
1862 *data = buf;
1863 if (cp < reqend)
1864 cp++;
1865 reqpt = cp;
1866 return v;
1867 }
1868 if (*cp == '=') {
1869 cp++;
1870 tp = buf;
1871 while (cp < reqend && isspace((unsigned char)*cp))
1872 cp++;
1873 while (cp < reqend && *cp != ',') {
1874 *tp++ = *cp++;
1875 if (tp >= buf + sizeof(buf))
1876 return (0);
1877 }
1878 if (cp < reqend)
1879 cp++;
1880 *tp-- = '\0';
1881 while (tp > buf) {
1882 *tp-- = '\0';
1883 if (!isspace((unsigned char)(*tp)))
1884 break;
1885 }
1886 reqpt = cp;
1887 *data = buf;
1888 return (v);
1889 }
1890 }
1891 cp = reqpt;
1892 }
1893 v++;
1894 }
1895 return v;
1896}
1897
1898
1899/*
1900 * control_unspec - response to an unspecified op-code
1901 */
1902/*ARGSUSED*/
1903static void
1904control_unspec(
1905 struct recvbuf *rbufp,
1906 int restrict_mask
1907 )
1908{
1909 struct peer *peer;
1910
1911 /*
1912 * What is an appropriate response to an unspecified op-code?
1913 * I return no errors and no data, unless a specified assocation
1914 * doesn't exist.
1915 */
1916 if (res_associd != 0) {
1917 if ((peer = findpeerbyassoc(res_associd)) == 0) {
1918 ctl_error(CERR_BADASSOC);
1919 return;
1920 }
1921 rpkt.status = htons(ctlpeerstatus(peer));
1922 } else {
1923 rpkt.status = htons(ctlsysstatus());
1924 }
1925 ctl_flushpkt(0);
1926}
1927
1928
1929/*
1930 * read_status - return either a list of associd's, or a particular
1931 * peer's status.
1932 */
1933/*ARGSUSED*/
1934static void
1935read_status(
1936 struct recvbuf *rbufp,
1937 int restrict_mask
1938 )
1939{
1940 register int i;
1941 register struct peer *peer;
1942 u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)];
1943
1944#ifdef DEBUG
1945 if (debug > 2)
1946 printf("read_status: ID %d\n", res_associd);
1947#endif
1948 /*
1949 * Two choices here. If the specified association ID is
1950 * zero we return all known assocation ID's. Otherwise
1951 * we return a bunch of stuff about the particular peer.
1952 */
1953 if (res_associd == 0) {
1954 register int n;
1955
1956 n = 0;
1957 rpkt.status = htons(ctlsysstatus());
1958 for (i = 0; i < HASH_SIZE; i++) {
1959 for (peer = assoc_hash[i]; peer != 0;
1960 peer = peer->ass_next) {
1961 ass_stat[n++] = htons(peer->associd);
1962 ass_stat[n++] =
1963 htons(ctlpeerstatus(peer));
1964 if (n ==
1965 CTL_MAX_DATA_LEN/sizeof(u_short)) {
1966 ctl_putdata((char *)ass_stat,
1967 n * sizeof(u_short), 1);
1968 n = 0;
1969 }
1970 }
1971 }
1972
1973 if (n != 0)
1974 ctl_putdata((char *)ass_stat, n *
1975 sizeof(u_short), 1);
1976 ctl_flushpkt(0);
1977 } else {
1978 peer = findpeerbyassoc(res_associd);
1979 if (peer == 0) {
1980 ctl_error(CERR_BADASSOC);
1981 } else {
1982 register u_char *cp;
1983
1984 rpkt.status = htons(ctlpeerstatus(peer));
1985 if (res_authokay)
1986 peer->num_events = 0;
1987 /*
1988 * For now, output everything we know about the
1989 * peer. May be more selective later.
1990 */
1991 for (cp = def_peer_var; *cp != 0; cp++)
1992 ctl_putpeer((int)*cp, peer);
1993 ctl_flushpkt(0);
1994 }
1995 }
1996}
1997
1998
1999/*
2000 * read_variables - return the variables the caller asks for
2001 */
2002/*ARGSUSED*/
2003static void
2004read_variables(
2005 struct recvbuf *rbufp,
2006 int restrict_mask
2007 )
2008{
2009 register struct ctl_var *v;
2010 register int i;
2011 char *valuep;
2012 u_char *wants;
2013 unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE +
2014 1) : (CP_MAXCODE + 1);
2015 if (res_associd == 0) {
2016 /*
2017 * Wants system variables. Figure out which he wants
2018 * and give them to him.
2019 */
2020 rpkt.status = htons(ctlsysstatus());
2021 if (res_authokay)
2022 ctl_sys_num_events = 0;
2023 gotvar += count_var(ext_sys_var);
2024 wants = (u_char *)emalloc(gotvar);
2025 memset((char *)wants, 0, gotvar);
2026 gotvar = 0;
2027 while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
2028 if (v->flags & EOV) {
2029 if ((v = ctl_getitem(ext_sys_var,
2030 &valuep)) != 0) {
2031 if (v->flags & EOV) {
2032 ctl_error(CERR_UNKNOWNVAR);
2033 free((char *)wants);
2034 return;
2035 }
2036 wants[CS_MAXCODE + 1 +
2037 v->code] = 1;
2038 gotvar = 1;
2039 continue;
2040 } else {
2041 break; /* shouldn't happen ! */
2042 }
2043 }
2044 wants[v->code] = 1;
2045 gotvar = 1;
2046 }
2047 if (gotvar) {
2048 for (i = 1; i <= CS_MAXCODE; i++)
2049 if (wants[i])
2050 ctl_putsys(i);
2051 for (i = 0; ext_sys_var &&
2052 !(ext_sys_var[i].flags & EOV); i++)
2053 if (wants[i + CS_MAXCODE + 1])
2054 ctl_putdata(ext_sys_var[i].text,
2055 strlen(ext_sys_var[i].text),
2056 0);
2057 } else {
2058 register u_char *cs;
2059 register struct ctl_var *kv;
2060
2061 for (cs = def_sys_var; *cs != 0; cs++)
2062 ctl_putsys((int)*cs);
2063 for (kv = ext_sys_var; kv && !(kv->flags & EOV);
2064 kv++)
2065 if (kv->flags & DEF)
2066 ctl_putdata(kv->text,
2067 strlen(kv->text), 0);
2068 }
2069 free((char *)wants);
2070 } else {
2071 register struct peer *peer;
2072
2073 /*
2074 * Wants info for a particular peer. See if we know
2075 * the guy.
2076 */
2077 peer = findpeerbyassoc(res_associd);
2078 if (peer == 0) {
2079 ctl_error(CERR_BADASSOC);
2080 return;
2081 }
2082 rpkt.status = htons(ctlpeerstatus(peer));
2083 if (res_authokay)
2084 peer->num_events = 0;
2085 wants = (u_char *)emalloc(gotvar);
2086 memset((char*)wants, 0, gotvar);
2087 gotvar = 0;
2088 while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
2089 if (v->flags & EOV) {
2090 ctl_error(CERR_UNKNOWNVAR);
2091 free((char *)wants);
2092 return;
2093 }
2094 wants[v->code] = 1;
2095 gotvar = 1;
2096 }
2097 if (gotvar) {
2098 for (i = 1; i <= CP_MAXCODE; i++)
2099 if (wants[i])
2100 ctl_putpeer(i, peer);
2101 } else {
2102 register u_char *cp;
2103
2104 for (cp = def_peer_var; *cp != 0; cp++)
2105 ctl_putpeer((int)*cp, peer);
2106 }
2107 free((char *)wants);
2108 }
2109 ctl_flushpkt(0);
2110}
2111
2112
2113/*
2114 * write_variables - write into variables. We only allow leap bit
2115 * writing this way.
2116 */
2117/*ARGSUSED*/
2118static void
2119write_variables(
2120 struct recvbuf *rbufp,
2121 int restrict_mask
2122 )
2123{
2124 register struct ctl_var *v;
2125 register int ext_var;
2126 char *valuep;
2127 long val;
2128
2129 /*
2130 * If he's trying to write into a peer tell him no way
2131 */
2132 if (res_associd != 0) {
2133 ctl_error(CERR_PERMISSION);
2134 return;
2135 }
2136
2137 /*
2138 * Set status
2139 */
2140 rpkt.status = htons(ctlsysstatus());
2141
2142 /*
2143 * Look through the variables. Dump out at the first sign of
2144 * trouble.
2145 */
2146 while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
2147 ext_var = 0;
2148 if (v->flags & EOV) {
2149 if ((v = ctl_getitem(ext_sys_var, &valuep)) !=
2150 0) {
2151 if (v->flags & EOV) {
2152 ctl_error(CERR_UNKNOWNVAR);
2153 return;
2154 }
2155 ext_var = 1;
2156 } else {
2157 break;
2158 }
2159 }
2160 if (!(v->flags & CAN_WRITE)) {
2161 ctl_error(CERR_PERMISSION);
2162 return;
2163 }
2164 if (!ext_var && (*valuep == '\0' || !atoint(valuep,
2165 &val))) {
2166 ctl_error(CERR_BADFMT);
2167 return;
2168 }
2169 if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) {
2170 ctl_error(CERR_BADVALUE);
2171 return;
2172 }
2173
2174 if (ext_var) {
2175 char *s = (char *)emalloc(strlen(v->text) +
2176 strlen(valuep) + 2);
2177 const char *t;
2178 char *tt = s;
2179
2180 t = v->text;
2181 while (*t && *t != '=')
2182 *tt++ = *t++;
2183
2184 *tt++ = '=';
2185 strcat(tt, valuep);
2186 set_sys_var(s, strlen(s)+1, v->flags);
2187 free(s);
2188 } else {
2189 /*
2190 * This one seems sane. Save it.
2191 */
2192 switch(v->code) {
2193
2194 case CS_LEAP:
2195 default:
2196 ctl_error(CERR_UNSPEC); /* really */
2197 return;
2198 }
2199 }
2200 }
2201
2202 /*
2203 * If we got anything, do it. xxx nothing to do ***
2204 */
2205 /*
2206 if (leapind != ~0 || leapwarn != ~0) {
2207 if (!leap_setleap((int)leapind, (int)leapwarn)) {
2208 ctl_error(CERR_PERMISSION);
2209 return;
2210 }
2211 }
2212 */
2213 ctl_flushpkt(0);
2214}
2215
2216
2217/*
2218 * read_clock_status - return clock radio status
2219 */
2220/*ARGSUSED*/
2221static void
2222read_clock_status(
2223 struct recvbuf *rbufp,
2224 int restrict_mask
2225 )
2226{
2227#ifndef REFCLOCK
2228 /*
2229 * If no refclock support, no data to return
2230 */
2231 ctl_error(CERR_BADASSOC);
2232#else
2233 register struct ctl_var *v;
2234 register int i;
2235 register struct peer *peer;
2236 char *valuep;
2237 u_char *wants;
2238 unsigned int gotvar;
2239 struct refclockstat clock_stat;
2240
2241 if (res_associd == 0) {
2242
2243 /*
2244 * Find a clock for this jerk. If the system peer
2245 * is a clock use it, else search the hash tables
2246 * for one.
2247 */
2248 if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK))
2249 {
2250 peer = sys_peer;
2251 } else {
2252 peer = 0;
2253 for (i = 0; peer == 0 && i < HASH_SIZE; i++) {
2254 for (peer = assoc_hash[i]; peer != 0;
2255 peer = peer->ass_next) {
2256 if (peer->flags & FLAG_REFCLOCK)
2257 break;
2258 }
2259 }
2260 if (peer == 0) {
2261 ctl_error(CERR_BADASSOC);
2262 return;
2263 }
2264 }
2265 } else {
2266 peer = findpeerbyassoc(res_associd);
2267 if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) {
2268 ctl_error(CERR_BADASSOC);
2269 return;
2270 }
2271 }
2272
2273 /*
2274 * If we got here we have a peer which is a clock. Get his
2275 * status.
2276 */
2277 clock_stat.kv_list = (struct ctl_var *)0;
2278 refclock_control(&peer->srcadr, (struct refclockstat *)0,
2279 &clock_stat);
2280
2281 /*
2282 * Look for variables in the packet.
2283 */
2284 rpkt.status = htons(ctlclkstatus(&clock_stat));
2285 gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list);
2286 wants = (u_char *)emalloc(gotvar);
2287 memset((char*)wants, 0, gotvar);
2288 gotvar = 0;
2289 while ((v = ctl_getitem(clock_var, &valuep)) != 0) {
2290 if (v->flags & EOV) {
2291 if ((v = ctl_getitem(clock_stat.kv_list,
2292 &valuep)) != 0) {
2293 if (v->flags & EOV) {
2294 ctl_error(CERR_UNKNOWNVAR);
2295 free((char*)wants);
2296 free_varlist(clock_stat.kv_list);
2297 return;
2298 }
2299 wants[CC_MAXCODE + 1 + v->code] = 1;
2300 gotvar = 1;
2301 continue;
2302 } else {
2303 break; /* shouldn't happen ! */
2304 }
2305 }
2306 wants[v->code] = 1;
2307 gotvar = 1;
2308 }
2309
2310 if (gotvar) {
2311 for (i = 1; i <= CC_MAXCODE; i++)
2312 if (wants[i])
2313 ctl_putclock(i, &clock_stat, 1);
2314 for (i = 0; clock_stat.kv_list &&
2315 !(clock_stat.kv_list[i].flags & EOV); i++)
2316 if (wants[i + CC_MAXCODE + 1])
2317 ctl_putdata(clock_stat.kv_list[i].text,
2318 strlen(clock_stat.kv_list[i].text),
2319 0);
2320 } else {
2321 register u_char *cc;
2322 register struct ctl_var *kv;
2323
2324 for (cc = def_clock_var; *cc != 0; cc++)
2325 ctl_putclock((int)*cc, &clock_stat, 0);
2326 for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV);
2327 kv++)
2328 if (kv->flags & DEF)
2329 ctl_putdata(kv->text, strlen(kv->text),
2330 0);
2331 }
2332
2333 free((char*)wants);
2334 free_varlist(clock_stat.kv_list);
2335
2336 ctl_flushpkt(0);
2337#endif
2338}
2339
2340
2341/*
2342 * write_clock_status - we don't do this
2343 */
2344/*ARGSUSED*/
2345static void
2346write_clock_status(
2347 struct recvbuf *rbufp,
2348 int restrict_mask
2349 )
2350{
2351 ctl_error(CERR_PERMISSION);
2352}
2353
2354/*
2355 * Trap support from here on down. We send async trap messages when the
2356 * upper levels report trouble. Traps can by set either by control
2357 * messages or by configuration.
2358 */
2359/*
2360 * set_trap - set a trap in response to a control message
2361 */
2362static void
2363set_trap(
2364 struct recvbuf *rbufp,
2365 int restrict_mask
2366 )
2367{
2368 int traptype;
2369
2370 /*
2371 * See if this guy is allowed
2372 */
2373 if (restrict_mask & RES_NOTRAP) {
2374 ctl_error(CERR_PERMISSION);
2375 return;
2376 }
2377
2378 /*
2379 * Determine his allowed trap type.
2380 */
2381 traptype = TRAP_TYPE_PRIO;
2382 if (restrict_mask & RES_LPTRAP)
2383 traptype = TRAP_TYPE_NONPRIO;
2384
2385 /*
2386 * Call ctlsettrap() to do the work. Return
2387 * an error if it can't assign the trap.
2388 */
2389 if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype,
2390 (int)res_version))
2391 ctl_error(CERR_NORESOURCE);
2392 ctl_flushpkt(0);
2393}
2394
2395
2396/*
2397 * unset_trap - unset a trap in response to a control message
2398 */
2399static void
2400unset_trap(
2401 struct recvbuf *rbufp,
2402 int restrict_mask
2403 )
2404{
2405 int traptype;
2406
2407 /*
2408 * We don't prevent anyone from removing his own trap unless the
2409 * trap is configured. Note we also must be aware of the
2410 * possibility that restriction flags were changed since this
2411 * guy last set his trap. Set the trap type based on this.
2412 */
2413 traptype = TRAP_TYPE_PRIO;
2414 if (restrict_mask & RES_LPTRAP)
2415 traptype = TRAP_TYPE_NONPRIO;
2416
2417 /*
2418 * Call ctlclrtrap() to clear this out.
2419 */
2420 if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype))
2421 ctl_error(CERR_BADASSOC);
2422 ctl_flushpkt(0);
2423}
2424
2425
2426/*
2427 * ctlsettrap - called to set a trap
2428 */
2429int
2430ctlsettrap(
2431 struct sockaddr_in *raddr,
2432 struct interface *linter,
2433 int traptype,
2434 int version
2435 )
2436{
2437 register struct ctl_trap *tp;
2438 register struct ctl_trap *tptouse;
2439
2440 /*
2441 * See if we can find this trap. If so, we only need update
2442 * the flags and the time.
2443 */
2444 if ((tp = ctlfindtrap(raddr, linter)) != NULL) {
2445 switch (traptype) {
2446
2447 case TRAP_TYPE_CONFIG:
2448 tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED;
2449 break;
2450
2451 case TRAP_TYPE_PRIO:
2452 if (tp->tr_flags & TRAP_CONFIGURED)
2453 return (1); /* don't change anything */
2454 tp->tr_flags = TRAP_INUSE;
2455 break;
2456
2457 case TRAP_TYPE_NONPRIO:
2458 if (tp->tr_flags & TRAP_CONFIGURED)
2459 return (1); /* don't change anything */
2460 tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO;
2461 break;
2462 }
2463 tp->tr_settime = current_time;
2464 tp->tr_resets++;
2465 return (1);
2466 }
2467
2468 /*
2469 * First we heard of this guy. Try to find a trap structure
2470 * for him to use, clearing out lesser priority guys if we
2471 * have to. Clear out anyone who's expired while we're at it.
2472 */
2473 tptouse = NULL;
2474 for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
2475 if ((tp->tr_flags & TRAP_INUSE) &&
2476 !(tp->tr_flags & TRAP_CONFIGURED) &&
2477 ((tp->tr_settime + CTL_TRAPTIME) > current_time)) {
2478 tp->tr_flags = 0;
2479 num_ctl_traps--;
2480 }
2481 if (!(tp->tr_flags & TRAP_INUSE)) {
2482 tptouse = tp;
2483 } else if (!(tp->tr_flags & TRAP_CONFIGURED)) {
2484 switch (traptype) {
2485
2486 case TRAP_TYPE_CONFIG:
2487 if (tptouse == NULL) {
2488 tptouse = tp;
2489 break;
2490 }
2491 if (tptouse->tr_flags & TRAP_NONPRIO &&
2492 !(tp->tr_flags & TRAP_NONPRIO))
2493 break;
2494
2495 if (!(tptouse->tr_flags & TRAP_NONPRIO)
2496 && tp->tr_flags & TRAP_NONPRIO) {
2497 tptouse = tp;
2498 break;
2499 }
2500 if (tptouse->tr_origtime <
2501 tp->tr_origtime)
2502 tptouse = tp;
2503 break;
2504
2505 case TRAP_TYPE_PRIO:
2506 if (tp->tr_flags & TRAP_NONPRIO) {
2507 if (tptouse == NULL ||
2508 (tptouse->tr_flags &
2509 TRAP_INUSE &&
2510 tptouse->tr_origtime <
2511 tp->tr_origtime))
2512 tptouse = tp;
2513 }
2514 break;
2515
2516 case TRAP_TYPE_NONPRIO:
2517 break;
2518 }
2519 }
2520 }
2521
2522 /*
2523 * If we don't have room for him return an error.
2524 */
2525 if (tptouse == NULL)
2526 return (0);
2527
2528 /*
2529 * Set up this structure for him.
2530 */
2531 tptouse->tr_settime = tptouse->tr_origtime = current_time;
2532 tptouse->tr_count = tptouse->tr_resets = 0;
2533 tptouse->tr_sequence = 1;
2534 tptouse->tr_addr = *raddr;
2535 tptouse->tr_localaddr = linter;
2536 tptouse->tr_version = version;
2537 tptouse->tr_flags = TRAP_INUSE;
2538 if (traptype == TRAP_TYPE_CONFIG)
2539 tptouse->tr_flags |= TRAP_CONFIGURED;
2540 else if (traptype == TRAP_TYPE_NONPRIO)
2541 tptouse->tr_flags |= TRAP_NONPRIO;
2542 num_ctl_traps++;
2543 return (1);
2544}
2545
2546
2547/*
2548 * ctlclrtrap - called to clear a trap
2549 */
2550int
2551ctlclrtrap(
2552 struct sockaddr_in *raddr,
2553 struct interface *linter,
2554 int traptype
2555 )
2556{
2557 register struct ctl_trap *tp;
2558
2559 if ((tp = ctlfindtrap(raddr, linter)) == NULL)
2560 return (0);
2561
2562 if (tp->tr_flags & TRAP_CONFIGURED
2563 && traptype != TRAP_TYPE_CONFIG)
2564 return (0);
2565
2566 tp->tr_flags = 0;
2567 num_ctl_traps--;
2568 return (1);
2569}
2570
2571
2572/*
2573 * ctlfindtrap - find a trap given the remote and local addresses
2574 */
2575static struct ctl_trap *
2576ctlfindtrap(
2577 struct sockaddr_in *raddr,
2578 struct interface *linter
2579 )
2580{
2581 register struct ctl_trap *tp;
2582
2583 for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
2584 if (tp->tr_flags & TRAP_INUSE && NSRCADR(raddr) ==
2585 NSRCADR(&tp->tr_addr) && NSRCPORT(raddr) ==
2586 NSRCPORT(&tp->tr_addr) && linter ==
2587 tp->tr_localaddr)
2588 return (tp);
2589 }
2590 return (struct ctl_trap *)NULL;
2591}
2592
2593
2594/*
2595 * report_event - report an event to the trappers
2596 */
2597void
2598report_event(
2599 int err,
2600 struct peer *peer
2601 )
2602{
2603 register int i;
2604
2605 /*
2606 * Record error code in proper spots, but have mercy on the
2607 * log file.
2608 */
2609 if (!(err & PEER_EVENT)) {
2610 if (ctl_sys_num_events < CTL_SYS_MAXEVENTS)
2611 ctl_sys_num_events++;
2612 if (ctl_sys_last_event != (u_char)err) {
2613 NLOG(NLOG_SYSEVENT)
2614 msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)",
2615 eventstr(err), err,
2616 sysstatstr(ctlsysstatus()), ctlsysstatus());
2617#ifdef DEBUG
2618 if (debug)
2619 printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n",
2620 eventstr(err), err,
2621 sysstatstr(ctlsysstatus()),
2622 ctlsysstatus());
2623#endif
2624 ctl_sys_last_event = (u_char)err;
2625 }
2626 } else if (peer != 0) {
2627 char *src;
2628
2629#ifdef REFCLOCK
2630 if (ISREFCLOCKADR(&peer->srcadr))
2631 src = refnumtoa(peer->srcadr.sin_addr.s_addr);
2632 else
2633#endif
2634 src = ntoa(&peer->srcadr);
2635
2636 peer->last_event = (u_char)(err & ~PEER_EVENT);
2637 if (peer->num_events < CTL_PEER_MAXEVENTS)
2638 peer->num_events++;
2639 NLOG(NLOG_PEEREVENT)
2640 msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)",
2641 src, eventstr(err), err,
2642 peerstatstr(ctlpeerstatus(peer)),
2643 ctlpeerstatus(peer));
2644#ifdef DEBUG
2645 if (debug)
2646 printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n",
2647 src, eventstr(err), err,
2648 peerstatstr(ctlpeerstatus(peer)),
2649 ctlpeerstatus(peer));
2650#endif
2651 } else {
2652 msyslog(LOG_ERR,
2653 "report_event: err '%s' (0x%02x), no peer",
2654 eventstr(err), err);
2655#ifdef DEBUG
2656 printf(
2657 "report_event: peer event '%s' (0x%02x), no peer\n",
2658 eventstr(err), err);
2659#endif
2660 return;
2661 }
2662
2663 /*
2664 * If no trappers, return.
2665 */
2666 if (num_ctl_traps <= 0)
2667 return;
2668
2669 /*
2670 * Set up the outgoing packet variables
2671 */
2672 res_opcode = CTL_OP_ASYNCMSG;
2673 res_offset = 0;
2674 res_async = 1;
2675 res_authenticate = 0;
2676 datapt = rpkt.data;
2677 dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
2678 if (!(err & PEER_EVENT)) {
2679 rpkt.associd = 0;
2680 rpkt.status = htons(ctlsysstatus());
2681
2682 /*
2683 * For now, put everything we know about system
2684 * variables. Don't send crypto strings.
2685 */
2686 for (i = 1; i <= CS_MAXCODE; i++) {
2687#ifdef PUBKEY
2688 if (i > CS_VARLIST)
2689 continue;
2690#endif /* PUBKEY */
2691 ctl_putsys(i);
2692 }
2693#ifdef REFCLOCK
2694 /*
2695 * for clock exception events: add clock variables to
2696 * reflect info on exception
2697 */
2698 if (err == EVNT_CLOCKEXCPT) {
2699 struct refclockstat clock_stat;
2700 struct ctl_var *kv;
2701
2702 clock_stat.kv_list = (struct ctl_var *)0;
2703 refclock_control(&peer->srcadr,
2704 (struct refclockstat *)0, &clock_stat);
2705 ctl_puthex("refclockstatus",
2706 ctlclkstatus(&clock_stat));
2707 for (i = 1; i <= CC_MAXCODE; i++)
2708 ctl_putclock(i, &clock_stat, 0);
2709 for (kv = clock_stat.kv_list; kv &&
2710 !(kv->flags & EOV); kv++)
2711 if (kv->flags & DEF)
2712 ctl_putdata(kv->text,
2713 strlen(kv->text), 0);
2714 free_varlist(clock_stat.kv_list);
2715 }
2716#endif /*REFCLOCK*/
2717 } else {
2718 rpkt.associd = htons(peer->associd);
2719 rpkt.status = htons(ctlpeerstatus(peer));
2720
2721 /*
2722 * Dump it all. Later, maybe less.
2723 */
2724 for (i = 1; i <= CP_MAXCODE; i++)
2725#ifdef PUBKEY
2726 if (i > CP_VARLIST)
2727 continue;
2728#endif /* PUBKEY */
2729 ctl_putpeer(i, peer);
2730#ifdef REFCLOCK
2731 /*
2732 * for clock exception events: add clock variables to
2733 * reflect info on exception
2734 */
2735 if (err == EVNT_PEERCLOCK) {
2736 struct refclockstat clock_stat;
2737 struct ctl_var *kv;
2738
2739 clock_stat.kv_list = (struct ctl_var *)0;
2740 refclock_control(&peer->srcadr,
2741 (struct refclockstat *)0, &clock_stat);
2742
2743 ctl_puthex("refclockstatus",
2744 ctlclkstatus(&clock_stat));
2745
2746 for (i = 1; i <= CC_MAXCODE; i++)
2747 ctl_putclock(i, &clock_stat, 0);
2748 for (kv = clock_stat.kv_list; kv &&
2749 !(kv->flags & EOV); kv++)
2750 if (kv->flags & DEF)
2751 ctl_putdata(kv->text,
2752 strlen(kv->text), 0);
2753 free_varlist(clock_stat.kv_list);
2754 }
2755#endif /*REFCLOCK*/
2756 }
2757
2758 /*
2759 * We're done, return.
2760 */
2761 ctl_flushpkt(0);
2762}
2763
2764
2765/*
2766 * ctl_clr_stats - clear stat counters
2767 */
2768void
2769ctl_clr_stats(void)
2770{
2771 ctltimereset = current_time;
2772 numctlreq = 0;
2773 numctlbadpkts = 0;
2774 numctlresponses = 0;
2775 numctlfrags = 0;
2776 numctlerrors = 0;
2777 numctlfrags = 0;
2778 numctltooshort = 0;
2779 numctlinputresp = 0;
2780 numctlinputfrag = 0;
2781 numctlinputerr = 0;
2782 numctlbadoffset = 0;
2783 numctlbadversion = 0;
2784 numctldatatooshort = 0;
2785 numctlbadop = 0;
2786 numasyncmsgs = 0;
2787}
2788
2789static u_long
2790count_var(
2791 struct ctl_var *k
2792 )
2793{
2794 register u_long c;
2795
2796 if (!k)
2797 return (0);
2798
2799 c = 0;
2800 while (!(k++->flags & EOV))
2801 c++;
2802 return (c);
2803}
2804
2805char *
2806add_var(
2807 struct ctl_var **kv,
2808 u_long size,
2809 int def
2810 )
2811{
2812 register u_long c;
2813 register struct ctl_var *k;
2814
2815 c = count_var(*kv);
2816
2817 k = *kv;
2818 *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var));
2819 if (k) {
2820 memmove((char *)*kv, (char *)k,
2821 sizeof(struct ctl_var)*c);
2822 free((char *)k);
2823 }
2824 (*kv)[c].code = (u_short) c;
2825 (*kv)[c].text = (char *)emalloc(size);
2826 (*kv)[c].flags = def;
2827 (*kv)[c+1].code = 0;
2828 (*kv)[c+1].text = (char *)0;
2829 (*kv)[c+1].flags = EOV;
2830 return (char *)(*kv)[c].text;
2831}
2832
2833void
2834set_var(
2835 struct ctl_var **kv,
2836 const char *data,
2837 u_long size,
2838 int def
2839 )
2840{
2841 register struct ctl_var *k;
2842 register const char *s;
2843 register const char *t;
2844 char *td;
2845
2846 if (!data || !size)
2847 return;
2848
2849 if ((k = *kv)) {
2850 while (!(k->flags & EOV)) {
2851 s = data;
2852 t = k->text;
2853 if (t) {
2854 while (*t != '=' && *s - *t == 0) {
2855 s++;
2856 t++;
2857 }
2858 if (*s == *t && ((*t == '=') || !*t)) {
2859 free((void *)k->text);
2860 td = (char *)emalloc(size);
2861 memmove(td, data, size);
2862 k->text =td;
2863 k->flags = def;
2864 return;
2865 }
2866 } else {
2867 td = (char *)emalloc(size);
2868 memmove(td, data, size);
2869 k->text = td;
2870 k->flags = def;
2871 return;
2872 }
2873 k++;
2874 }
2875 }
2876 td = add_var(kv, size, def);
2877 memmove(td, data, size);
2878}
2879
2880void
2881set_sys_var(
2882 char *data,
2883 u_long size,
2884 int def
2885 )
2886{
2887 set_var(&ext_sys_var, data, size, def);
2888}
2889
2890void
2891free_varlist(
2892 struct ctl_var *kv
2893 )
2894{
2895 struct ctl_var *k;
2896 if (kv) {
2897 for (k = kv; !(k->flags & EOV); k++)
2898 free((void *)k->text);
2899 free((void *)kv);
2900 }
2901}