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