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