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