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