Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpd / ntp_control.c
blobd7dadf1be55308792dd23c6e0dcf126fd8e1f10b
1 /* $NetBSD$ */
3 /*
4 * ntp_control.c - respond to control messages and send async traps
5 */
7 #ifdef HAVE_CONFIG_H
8 # include <config.h>
9 #endif
11 #include "ntpd.h"
12 #include "ntp_io.h"
13 #include "ntp_refclock.h"
14 #include "ntp_control.h"
15 #include "ntp_unixtime.h"
16 #include "ntp_stdlib.h"
17 #include "ntp_config.h"
18 #include "ntp_assert.h"
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <signal.h>
23 #include <sys/stat.h>
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
27 #endif
28 #include <arpa/inet.h>
31 * Structure to hold request procedure information
34 struct ctl_proc {
35 short control_code; /* defined request code */
36 #define NO_REQUEST (-1)
37 u_short flags; /* flags word */
38 /* Only one flag. Authentication required or not. */
39 #define NOAUTH 0
40 #define AUTH 1
41 void (*handler) (struct recvbuf *, int); /* handle request */
46 * Request processing routines
48 static void ctl_error (int);
49 #ifdef REFCLOCK
50 static u_short ctlclkstatus (struct refclockstat *);
51 #endif
52 static void ctl_flushpkt (int);
53 static void ctl_putdata (const char *, unsigned int, int);
54 static void ctl_putstr (const char *, const char *,
55 unsigned int);
56 static void ctl_putdbl (const char *, double);
57 static void ctl_putuint (const char *, u_long);
58 static void ctl_puthex (const char *, u_long);
59 static void ctl_putint (const char *, long);
60 static void ctl_putts (const char *, l_fp *);
61 static void ctl_putadr (const char *, u_int32,
62 sockaddr_u *);
63 static void ctl_putid (const char *, char *);
64 static void ctl_putarray (const char *, double *, int);
65 static void ctl_putsys (int);
66 static void ctl_putpeer (int, struct peer *);
67 static void ctl_putfs (const char *, tstamp_t);
68 #ifdef REFCLOCK
69 static void ctl_putclock (int, struct refclockstat *, int);
70 #endif /* REFCLOCK */
71 static struct ctl_var *ctl_getitem (struct ctl_var *, char **);
72 static u_long count_var (struct ctl_var *);
73 static void control_unspec (struct recvbuf *, int);
74 static void read_status (struct recvbuf *, int);
75 static void read_variables (struct recvbuf *, int);
76 static void write_variables (struct recvbuf *, int);
77 static void read_clock_status (struct recvbuf *, int);
78 static void write_clock_status (struct recvbuf *, int);
79 static void set_trap (struct recvbuf *, int);
80 static void unset_trap (struct recvbuf *, int);
81 static void configure (struct recvbuf *, int);
82 static void save_config (struct recvbuf *, int);
83 static struct ctl_trap *ctlfindtrap (sockaddr_u *,
84 struct interface *);
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 { CTL_OP_SAVECONFIG, AUTH, save_config },
96 { CTL_OP_CONFIGURE, AUTH, configure },
97 { NO_REQUEST, 0 }
101 * System variable values. The array can be indexed by the variable
102 * index to find the textual name.
104 static struct ctl_var sys_var[] = {
105 { 0, PADDING, "" }, /* 0 */
106 { CS_LEAP, RW, "leap" }, /* 1 */
107 { CS_STRATUM, RO, "stratum" }, /* 2 */
108 { CS_PRECISION, RO, "precision" }, /* 3 */
109 { CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */
110 { CS_ROOTDISPERSION, RO, "rootdisp" }, /* 5 */
111 { CS_REFID, RO, "refid" }, /* 6 */
112 { CS_REFTIME, RO, "reftime" }, /* 7 */
113 { CS_POLL, RO, "tc" }, /* 8 */
114 { CS_PEERID, RO, "peer" }, /* 9 */
115 { CS_OFFSET, RO, "offset" }, /* 10 */
116 { CS_DRIFT, RO, "frequency" }, /* 11 */
117 { CS_JITTER, RO, "sys_jitter" }, /* 12 */
118 { CS_ERROR, RO, "clk_jitter" }, /* 13 */
119 { CS_CLOCK, RO, "clock" }, /* 14 */
120 { CS_PROCESSOR, RO, "processor" }, /* 15 */
121 { CS_SYSTEM, RO, "system" }, /* 16 */
122 { CS_VERSION, RO, "version" }, /* 17 */
123 { CS_STABIL, RO, "clk_wander" }, /* 18 */
124 { CS_VARLIST, RO, "sys_var_list" }, /* 19 */
125 { CS_TAI, RO, "tai" }, /* 20 */
126 { CS_LEAPTAB, RO, "leapsec" }, /* 21 */
127 { CS_LEAPEND, RO, "expire" }, /* 22 */
128 { CS_RATE, RO, "mintc" }, /* 23 */
129 #ifdef OPENSSL
130 { CS_FLAGS, RO, "flags" }, /* 24 */
131 { CS_HOST, RO, "host" }, /* 25 */
132 { CS_PUBLIC, RO, "update" }, /* 26 */
133 { CS_CERTIF, RO, "cert" }, /* 27 */
134 { CS_SIGNATURE, RO, "signature" }, /* 28 */
135 { CS_REVTIME, RO, "until" }, /* 29 */
136 { CS_GROUP, RO, "group" }, /* 30 */
137 { CS_DIGEST, RO, "digest" }, /* 31 */
138 #endif /* OPENSSL */
139 { 0, EOV, "" } /* 24/3 2*/
142 static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
145 * System variables we print by default (in fuzzball order,
146 * more-or-less)
148 static u_char def_sys_var[] = {
149 CS_VERSION,
150 CS_PROCESSOR,
151 CS_SYSTEM,
152 CS_LEAP,
153 CS_STRATUM,
154 CS_PRECISION,
155 CS_ROOTDELAY,
156 CS_ROOTDISPERSION,
157 CS_REFID,
158 CS_REFTIME,
159 CS_CLOCK,
160 CS_PEERID,
161 CS_POLL,
162 CS_RATE,
163 CS_OFFSET,
164 CS_DRIFT,
165 CS_JITTER,
166 CS_ERROR,
167 CS_STABIL,
168 CS_TAI,
169 CS_LEAPTAB,
170 CS_LEAPEND,
171 #ifdef OPENSSL
172 CS_HOST,
173 CS_GROUP,
174 CS_FLAGS,
175 CS_DIGEST,
176 CS_SIGNATURE,
177 CS_PUBLIC,
178 CS_CERTIF,
179 #endif /* OPENSSL */
185 * Peer variable list
187 static struct ctl_var peer_var[] = {
188 { 0, PADDING, "" }, /* 0 */
189 { CP_CONFIG, RO, "config" }, /* 1 */
190 { CP_AUTHENABLE, RO, "authenable" }, /* 2 */
191 { CP_AUTHENTIC, RO, "authentic" }, /* 3 */
192 { CP_SRCADR, RO, "srcadr" }, /* 4 */
193 { CP_SRCPORT, RO, "srcport" }, /* 5 */
194 { CP_DSTADR, RO, "dstadr" }, /* 6 */
195 { CP_DSTPORT, RO, "dstport" }, /* 7 */
196 { CP_LEAP, RO, "leap" }, /* 8 */
197 { CP_HMODE, RO, "hmode" }, /* 9 */
198 { CP_STRATUM, RO, "stratum" }, /* 10 */
199 { CP_PPOLL, RO, "ppoll" }, /* 11 */
200 { CP_HPOLL, RO, "hpoll" }, /* 12 */
201 { CP_PRECISION, RO, "precision" }, /* 13 */
202 { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */
203 { CP_ROOTDISPERSION, RO, "rootdisp" }, /* 15 */
204 { CP_REFID, RO, "refid" }, /* 16 */
205 { CP_REFTIME, RO, "reftime" }, /* 17 */
206 { CP_ORG, RO, "org" }, /* 18 */
207 { CP_REC, RO, "rec" }, /* 19 */
208 { CP_XMT, RO, "xleave" }, /* 20 */
209 { CP_REACH, RO, "reach" }, /* 21 */
210 { CP_UNREACH, RO, "unreach" }, /* 22 */
211 { CP_TIMER, RO, "timer" }, /* 23 */
212 { CP_DELAY, RO, "delay" }, /* 24 */
213 { CP_OFFSET, RO, "offset" }, /* 25 */
214 { CP_JITTER, RO, "jitter" }, /* 26 */
215 { CP_DISPERSION, RO, "dispersion" }, /* 27 */
216 { CP_KEYID, RO, "keyid" }, /* 28 */
217 { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */
218 { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */
219 { CP_PMODE, RO, "pmode" }, /* 31 */
220 { CP_RECEIVED, RO, "received"}, /* 32 */
221 { CP_SENT, RO, "sent" }, /* 33 */
222 { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */
223 { CP_FLASH, RO, "flash" }, /* 35 */
224 { CP_TTL, RO, "ttl" }, /* 36 */
225 { CP_VARLIST, RO, "peer_var_list" }, /* 37 */
226 { CP_IN, RO, "in" }, /* 38 */
227 { CP_OUT, RO, "out" }, /* 39 */
228 { CP_RATE, RO, "headway" }, /* 40 */
229 { CP_BIAS, RO, "bias" }, /* 41 */
230 #ifdef OPENSSL
231 { CP_FLAGS, RO, "flags" }, /* 42 */
232 { CP_HOST, RO, "host" }, /* 43 */
233 { CP_VALID, RO, "valid" }, /* 44 */
234 { CP_INITSEQ, RO, "initsequence" }, /* 45 */
235 { CP_INITKEY, RO, "initkey" }, /* 46 */
236 { CP_INITTSP, RO, "timestamp" }, /* 47 */
237 { CP_SIGNATURE, RO, "signature" }, /* 48 */
238 #endif /* OPENSSL */
239 { 0, EOV, "" } /* 42/49 */
244 * Peer variables we print by default
246 static u_char def_peer_var[] = {
247 CP_SRCADR,
248 CP_SRCPORT,
249 CP_DSTADR,
250 CP_DSTPORT,
251 CP_OUT,
252 CP_IN,
253 CP_LEAP,
254 CP_STRATUM,
255 CP_PRECISION,
256 CP_ROOTDELAY,
257 CP_ROOTDISPERSION,
258 CP_REFID,
259 CP_REFTIME,
260 CP_REC,
261 CP_REACH,
262 CP_UNREACH,
263 CP_HMODE,
264 CP_PMODE,
265 CP_HPOLL,
266 CP_PPOLL,
267 CP_RATE,
268 CP_FLASH,
269 CP_KEYID,
270 CP_TTL,
271 CP_OFFSET,
272 CP_DELAY,
273 CP_DISPERSION,
274 CP_JITTER,
275 CP_XMT,
276 CP_BIAS,
277 CP_FILTDELAY,
278 CP_FILTOFFSET,
279 CP_FILTERROR,
280 #ifdef OPENSSL
281 CP_HOST,
282 CP_FLAGS,
283 CP_SIGNATURE,
284 CP_VALID,
285 CP_INITSEQ,
286 #endif /* OPENSSL */
291 #ifdef REFCLOCK
293 * Clock variable list
295 static struct ctl_var clock_var[] = {
296 { 0, PADDING, "" }, /* 0 */
297 { CC_TYPE, RO, "type" }, /* 1 */
298 { CC_TIMECODE, RO, "timecode" }, /* 2 */
299 { CC_POLL, RO, "poll" }, /* 3 */
300 { CC_NOREPLY, RO, "noreply" }, /* 4 */
301 { CC_BADFORMAT, RO, "badformat" }, /* 5 */
302 { CC_BADDATA, RO, "baddata" }, /* 6 */
303 { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */
304 { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */
305 { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */
306 { CC_FUDGEVAL2, RO, "refid" }, /* 10 */
307 { CC_FLAGS, RO, "flags" }, /* 11 */
308 { CC_DEVICE, RO, "device" }, /* 12 */
309 { CC_VARLIST, RO, "clock_var_list" }, /* 13 */
310 { 0, EOV, "" } /* 14 */
315 * Clock variables printed by default
317 static u_char def_clock_var[] = {
318 CC_DEVICE,
319 CC_TYPE, /* won't be output if device = known */
320 CC_TIMECODE,
321 CC_POLL,
322 CC_NOREPLY,
323 CC_BADFORMAT,
324 CC_BADDATA,
325 CC_FUDGETIME1,
326 CC_FUDGETIME2,
327 CC_FUDGEVAL1,
328 CC_FUDGEVAL2,
329 CC_FLAGS,
332 #endif
336 * System and processor definitions.
338 #ifndef HAVE_UNAME
339 # ifndef STR_SYSTEM
340 # define STR_SYSTEM "UNIX"
341 # endif
342 # ifndef STR_PROCESSOR
343 # define STR_PROCESSOR "unknown"
344 # endif
346 static char str_system[] = STR_SYSTEM;
347 static char str_processor[] = STR_PROCESSOR;
348 #else
349 # include <sys/utsname.h>
350 static struct utsname utsnamebuf;
351 #endif /* HAVE_UNAME */
354 * Trap structures. We only allow a few of these, and send a copy of
355 * each async message to each live one. Traps time out after an hour, it
356 * is up to the trap receipient to keep resetting it to avoid being
357 * timed out.
359 /* ntp_request.c */
360 struct ctl_trap ctl_trap[CTL_MAXTRAPS];
361 int num_ctl_traps;
364 * Type bits, for ctlsettrap() call.
366 #define TRAP_TYPE_CONFIG 0 /* used by configuration code */
367 #define TRAP_TYPE_PRIO 1 /* priority trap */
368 #define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */
372 * List relating reference clock types to control message time sources.
373 * Index by the reference clock type. This list will only be used iff
374 * the reference clock driver doesn't set peer->sstclktype to something
375 * different than CTL_SST_TS_UNSPEC.
377 static u_char clocktypes[] = {
378 CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
379 CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */
380 CTL_SST_TS_UHF, /* deprecated REFCLK_GPS_TRAK (2) */
381 CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */
382 CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */
383 CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */
384 CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) IRIG_AUDIO? */
385 CTL_SST_TS_HF, /* REFCLK_CHU (7) */
386 CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */
387 CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */
388 CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
389 CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */
390 CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
391 CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */
392 CTL_SST_TS_LF, /* deprecated REFCLK_MSF_EES (14) */
393 CTL_SST_TS_NTP, /* not used (15) */
394 CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
395 CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
396 CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */
397 CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */
398 CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
399 CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */
400 CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */
401 CTL_SST_TS_NTP, /* not used (23) */
402 CTL_SST_TS_NTP, /* not used (24) */
403 CTL_SST_TS_NTP, /* not used (25) */
404 CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */
405 CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */
406 CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */
407 CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */
408 CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */
409 CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */
410 CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */
411 CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (33) */
412 CTL_SST_TS_LF, /* REFCLK_ULINK (34) */
413 CTL_SST_TS_LF, /* REFCLK_PCF (35) */
414 CTL_SST_TS_HF, /* REFCLK_WWV (36) */
415 CTL_SST_TS_LF, /* REFCLK_FG (37) */
416 CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */
417 CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */
418 CTL_SST_TS_LF, /* REFCLK_JJY (40) */
419 CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */
420 CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */
421 CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */
422 CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */
427 * Keyid used for authenticating write requests.
429 keyid_t ctl_auth_keyid;
432 * We keep track of the last error reported by the system internally
434 static u_char ctl_sys_last_event;
435 static u_char ctl_sys_num_events;
439 * Statistic counters to keep track of requests and responses.
441 u_long ctltimereset; /* time stats reset */
442 u_long numctlreq; /* number of requests we've received */
443 u_long numctlbadpkts; /* number of bad control packets */
444 u_long numctlresponses; /* number of resp packets sent with data */
445 u_long numctlfrags; /* number of fragments sent */
446 u_long numctlerrors; /* number of error responses sent */
447 u_long numctltooshort; /* number of too short input packets */
448 u_long numctlinputresp; /* number of responses on input */
449 u_long numctlinputfrag; /* number of fragments on input */
450 u_long numctlinputerr; /* number of input pkts with err bit set */
451 u_long numctlbadoffset; /* number of input pkts with nonzero offset */
452 u_long numctlbadversion; /* number of input pkts with unknown version */
453 u_long numctldatatooshort; /* data too short for count */
454 u_long numctlbadop; /* bad op code found in packet */
455 u_long numasyncmsgs; /* number of async messages we've sent */
458 * Response packet used by these routines. Also some state information
459 * so that we can handle packet formatting within a common set of
460 * subroutines. Note we try to enter data in place whenever possible,
461 * but the need to set the more bit correctly means we occasionally
462 * use the extra buffer and copy.
464 static struct ntp_control rpkt;
465 static u_char res_version;
466 static u_char res_opcode;
467 static associd_t res_associd;
468 static int res_offset;
469 static u_char * datapt;
470 static u_char * dataend;
471 static int datalinelen;
472 static int datanotbinflag;
473 static sockaddr_u *rmt_addr;
474 static struct interface *lcl_inter;
476 static u_char res_authenticate;
477 static u_char res_authokay;
478 static keyid_t res_keyid;
480 #define MAXDATALINELEN (72)
482 static u_char res_async; /* set to 1 if this is async trap response */
485 * Pointers for saving state when decoding request packets
487 static char *reqpt;
488 static char *reqend;
491 * init_control - initialize request data
493 void
494 init_control(void)
496 int i;
498 #ifdef HAVE_UNAME
499 uname(&utsnamebuf);
500 #endif /* HAVE_UNAME */
502 ctl_clr_stats();
504 ctl_auth_keyid = 0;
505 ctl_sys_last_event = EVNT_UNSPEC;
506 ctl_sys_num_events = 0;
508 num_ctl_traps = 0;
509 for (i = 0; i < CTL_MAXTRAPS; i++)
510 ctl_trap[i].tr_flags = 0;
515 * ctl_error - send an error response for the current request
517 static void
518 ctl_error(
519 int errcode
522 DPRINTF(3, ("sending control error %d\n", errcode));
525 * Fill in the fields. We assume rpkt.sequence and rpkt.associd
526 * have already been filled in.
528 rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode &
529 CTL_OP_MASK));
530 rpkt.status = htons((u_short) ((errcode<<8) & 0xff00));
531 rpkt.count = 0;
534 * send packet and bump counters
536 if (res_authenticate && sys_authenticate) {
537 int maclen;
539 *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) =
540 htonl(res_keyid);
541 maclen = authencrypt(res_keyid, (u_int32 *)&rpkt,
542 CTL_HEADER_LEN);
543 sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
544 CTL_HEADER_LEN + maclen);
545 } else {
546 sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
547 CTL_HEADER_LEN);
549 numctlerrors++;
553 * save_config - Implements ntpq -c "saveconfig <filename>"
554 * Writes current configuration including any runtime
555 * changes by ntpq's :config or config-from-file
557 void
558 save_config(
559 struct recvbuf *rbufp,
560 int restrict_mask
563 char reply[128];
564 #ifdef SAVECONFIG
565 char filespec[128];
566 char filename[128];
567 char fullpath[512];
568 const char savedconfig_eq[] = "savedconfig=";
569 char savedconfig[sizeof(savedconfig_eq) + sizeof(filename)];
570 time_t now;
571 int fd;
572 FILE *fptr;
573 #endif
575 if (restrict_mask & RES_NOMODIFY) {
576 snprintf(reply, sizeof(reply),
577 "saveconfig prohibited by restrict ... nomodify");
578 ctl_putdata(reply, strlen(reply), 0);
579 ctl_flushpkt(0);
580 msyslog(LOG_NOTICE,
581 "saveconfig from %s rejected due to nomodify restriction",
582 stoa(&rbufp->recv_srcadr));
583 return;
586 #ifdef SAVECONFIG
587 if (NULL == saveconfigdir) {
588 snprintf(reply, sizeof(reply),
589 "saveconfig prohibited, no saveconfigdir configured");
590 ctl_putdata(reply, strlen(reply), 0);
591 ctl_flushpkt(0);
592 msyslog(LOG_NOTICE,
593 "saveconfig from %s rejected, no saveconfigdir",
594 stoa(&rbufp->recv_srcadr));
595 return;
598 if (0 == reqend - reqpt)
599 return;
601 strncpy(filespec, reqpt, sizeof(filespec));
602 filespec[sizeof(filespec) - 1] = '\0';
604 time(&now);
607 * allow timestamping of the saved config filename with
608 * strftime() format such as:
609 * ntpq -c "saveconfig ntp-%Y%m%d-%H%M%S.conf"
611 if (0 == strftime(filename, sizeof(filename), filespec,
612 localtime(&now)))
613 strncpy(filename, filespec, sizeof(filename));
615 filename[sizeof(filename) - 1] = '\0';
617 if (strchr(filename, '\\') || strchr(filename, '/')) {
618 snprintf(reply, sizeof(reply),
619 "saveconfig does not allow directory in filename");
620 ctl_putdata(reply, strlen(reply), 0);
621 ctl_flushpkt(0);
622 msyslog(LOG_NOTICE,
623 "saveconfig with path from %s rejected",
624 stoa(&rbufp->recv_srcadr));
625 return;
628 snprintf(fullpath, sizeof(fullpath), "%s%s",
629 saveconfigdir, filename);
631 fd = open(fullpath, O_CREAT | O_TRUNC | O_WRONLY,
632 S_IRUSR | S_IWUSR);
633 if (-1 == fd)
634 fptr = NULL;
635 else
636 fptr = fdopen(fd, "w");
638 if (NULL == fptr || -1 == dump_all_config_trees(fptr, 1)) {
639 snprintf(reply, sizeof(reply),
640 "Unable to save configuration to file %s",
641 filename);
642 msyslog(LOG_ERR,
643 "saveconfig %s from %s failed", filename,
644 stoa(&rbufp->recv_srcadr));
645 } else {
646 snprintf(reply, sizeof(reply),
647 "Configuration saved to %s", filename);
648 msyslog(LOG_NOTICE,
649 "Configuration saved to %s (requested by %s)",
650 fullpath, stoa(&rbufp->recv_srcadr));
652 * save the output filename in system variable
653 * savedconfig, retrieved with:
654 * ntpq -c "rv 0 savedconfig"
656 snprintf(savedconfig, sizeof(savedconfig), "%s%s",
657 savedconfig_eq, filename);
658 set_sys_var(savedconfig, strlen(savedconfig) + 1, RO);
661 if (NULL != fptr)
662 fclose(fptr);
663 #else /* !SAVECONFIG follows */
664 snprintf(reply, sizeof(reply),
665 "saveconfig unavailable, configured with --disable-saveconfig");
666 #endif
668 ctl_putdata(reply, strlen(reply), 0);
669 ctl_flushpkt(0);
674 * process_control - process an incoming control message
676 void
677 process_control(
678 struct recvbuf *rbufp,
679 int restrict_mask
682 register struct ntp_control *pkt;
683 register int req_count;
684 register int req_data;
685 register struct ctl_proc *cc;
686 int properlen;
687 int maclen;
689 DPRINTF(3, ("in process_control()\n"));
692 * Save the addresses for error responses
694 numctlreq++;
695 rmt_addr = &rbufp->recv_srcadr;
696 lcl_inter = rbufp->dstadr;
697 pkt = (struct ntp_control *)&rbufp->recv_pkt;
700 * If the length is less than required for the header, or
701 * it is a response or a fragment, ignore this.
703 if (rbufp->recv_length < CTL_HEADER_LEN
704 || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR)
705 || pkt->offset != 0) {
706 DPRINTF(1, ("invalid format in control packet\n"));
707 if (rbufp->recv_length < CTL_HEADER_LEN)
708 numctltooshort++;
709 if (pkt->r_m_e_op & CTL_RESPONSE)
710 numctlinputresp++;
711 if (pkt->r_m_e_op & CTL_MORE)
712 numctlinputfrag++;
713 if (pkt->r_m_e_op & CTL_ERROR)
714 numctlinputerr++;
715 if (pkt->offset != 0)
716 numctlbadoffset++;
717 return;
719 res_version = PKT_VERSION(pkt->li_vn_mode);
720 if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {
721 DPRINTF(1, ("unknown version %d in control packet\n",
722 res_version));
723 numctlbadversion++;
724 return;
728 * Pull enough data from the packet to make intelligent
729 * responses
731 rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version,
732 MODE_CONTROL);
733 res_opcode = pkt->r_m_e_op;
734 rpkt.sequence = pkt->sequence;
735 rpkt.associd = pkt->associd;
736 rpkt.status = 0;
737 res_offset = 0;
738 res_associd = htons(pkt->associd);
739 res_async = 0;
740 res_authenticate = 0;
741 res_keyid = 0;
742 res_authokay = 0;
743 req_count = (int)ntohs(pkt->count);
744 datanotbinflag = 0;
745 datalinelen = 0;
746 datapt = rpkt.data;
747 dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
749 if ((rbufp->recv_length & 0x3) != 0)
750 DPRINTF(3, ("Control packet length %d unrounded\n",
751 rbufp->recv_length));
754 * We're set up now. Make sure we've got at least enough
755 * incoming data space to match the count.
757 req_data = rbufp->recv_length - CTL_HEADER_LEN;
758 if (req_data < req_count || rbufp->recv_length & 0x3) {
759 ctl_error(CERR_BADFMT);
760 numctldatatooshort++;
761 return;
764 properlen = req_count + CTL_HEADER_LEN;
765 /* round up proper len to a 8 octet boundary */
767 properlen = (properlen + 7) & ~7;
768 maclen = rbufp->recv_length - properlen;
769 if ((rbufp->recv_length & 3) == 0 &&
770 maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN &&
771 sys_authenticate) {
772 res_authenticate = 1;
773 res_keyid = ntohl(*(u_int32 *)((u_char *)pkt +
774 properlen));
776 DPRINTF(3, ("recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
777 rbufp->recv_length, properlen, res_keyid,
778 maclen));
780 if (!authistrusted(res_keyid))
781 DPRINTF(3, ("invalid keyid %08x\n", res_keyid));
782 else if (authdecrypt(res_keyid, (u_int32 *)pkt,
783 rbufp->recv_length - maclen,
784 maclen)) {
785 DPRINTF(3, ("authenticated okay\n"));
786 res_authokay = 1;
787 } else {
788 DPRINTF(3, ("authentication failed\n"));
789 res_keyid = 0;
794 * Set up translate pointers
796 reqpt = (char *)pkt->data;
797 reqend = reqpt + req_count;
800 * Look for the opcode processor
802 for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) {
803 if (cc->control_code == res_opcode) {
804 DPRINTF(3, ("opcode %d, found command handler\n",
805 res_opcode));
806 if (cc->flags == AUTH
807 && (!res_authokay
808 || res_keyid != ctl_auth_keyid)) {
809 ctl_error(CERR_PERMISSION);
810 return;
812 (cc->handler)(rbufp, restrict_mask);
813 return;
818 * Can't find this one, return an error.
820 numctlbadop++;
821 ctl_error(CERR_BADOP);
822 return;
827 * ctlpeerstatus - return a status word for this peer
829 u_short
830 ctlpeerstatus(
831 register struct peer *peer
834 u_short status;
836 status = peer->status;
837 if (!(peer->flags & FLAG_PREEMPT))
838 status |= CTL_PST_CONFIG;
839 if (peer->keyid != 0)
840 status |= CTL_PST_AUTHENABLE;
841 if (peer->flags & FLAG_AUTHENTIC)
842 status |= CTL_PST_AUTHENTIC;
843 if (peer->reach != 0)
844 status |= CTL_PST_REACH;
845 if (peer->cast_flags & (MDF_BCAST | MDF_MCAST | MDF_ACAST))
846 status |= CTL_PST_BCAST;
847 return (u_short)CTL_PEER_STATUS(status, peer->num_events,
848 peer->last_event);
853 * ctlclkstatus - return a status word for this clock
855 #ifdef REFCLOCK
856 static u_short
857 ctlclkstatus(
858 struct refclockstat *this_clock
861 return (u_short)CTL_PEER_STATUS(0, this_clock->lastevent,
862 this_clock->currentstatus);
864 #endif
868 * ctlsysstatus - return the system status word
870 u_short
871 ctlsysstatus(void)
873 register u_char this_clock;
875 this_clock = CTL_SST_TS_UNSPEC;
876 #ifdef REFCLOCK
877 if (sys_peer != 0) {
878 if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
879 this_clock = sys_peer->sstclktype;
880 } else {
881 if (sys_peer->refclktype < sizeof(clocktypes))
882 this_clock =
883 clocktypes[sys_peer->refclktype];
886 #else /* REFCLOCK */
887 if (sys_peer != 0)
888 this_clock = CTL_SST_TS_NTP;
889 #endif /* REFCLOCK */
890 return (u_short)CTL_SYS_STATUS(sys_leap, this_clock,
891 ctl_sys_num_events, ctl_sys_last_event);
896 * ctl_flushpkt - write out the current packet and prepare
897 * another if necessary.
899 static void
900 ctl_flushpkt(
901 int more
904 int dlen;
905 int sendlen;
907 if (!more && datanotbinflag) {
909 * Big hack, output a trailing \r\n
911 *datapt++ = '\r';
912 *datapt++ = '\n';
914 dlen = datapt - (u_char *)rpkt.data;
915 sendlen = dlen + CTL_HEADER_LEN;
918 * Pad to a multiple of 32 bits
920 while (sendlen & 0x3) {
921 *datapt++ = '\0';
922 sendlen++;
926 * Fill in the packet with the current info
928 rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode &
929 CTL_OP_MASK));
930 rpkt.count = htons((u_short) dlen);
931 rpkt.offset = htons( (u_short) res_offset);
932 if (res_async) {
933 register int i;
935 for (i = 0; i < CTL_MAXTRAPS; i++) {
936 if (ctl_trap[i].tr_flags & TRAP_INUSE) {
937 rpkt.li_vn_mode =
938 PKT_LI_VN_MODE(sys_leap,
939 ctl_trap[i].tr_version,
940 MODE_CONTROL);
941 rpkt.sequence =
942 htons(ctl_trap[i].tr_sequence);
943 sendpkt(&ctl_trap[i].tr_addr,
944 ctl_trap[i].tr_localaddr, -4,
945 (struct pkt *)&rpkt, sendlen);
946 if (!more)
947 ctl_trap[i].tr_sequence++;
948 numasyncmsgs++;
951 } else {
952 if (res_authenticate && sys_authenticate) {
953 int maclen;
954 int totlen = sendlen;
955 keyid_t keyid = htonl(res_keyid);
958 * If we are going to authenticate, then there
959 * is an additional requirement that the MAC
960 * begin on a 64 bit boundary.
962 while (totlen & 7) {
963 *datapt++ = '\0';
964 totlen++;
966 memcpy(datapt, &keyid, sizeof keyid);
967 maclen = authencrypt(res_keyid,
968 (u_int32 *)&rpkt, totlen);
969 sendpkt(rmt_addr, lcl_inter, -5,
970 (struct pkt *)&rpkt, totlen + maclen);
971 } else {
972 sendpkt(rmt_addr, lcl_inter, -6,
973 (struct pkt *)&rpkt, sendlen);
975 if (more)
976 numctlfrags++;
977 else
978 numctlresponses++;
982 * Set us up for another go around.
984 res_offset += dlen;
985 datapt = (u_char *)rpkt.data;
990 * ctl_putdata - write data into the packet, fragmenting and starting
991 * another if this one is full.
993 static void
994 ctl_putdata(
995 const char *dp,
996 unsigned int dlen,
997 int bin /* set to 1 when data is binary */
1000 int overhead;
1002 overhead = 0;
1003 if (!bin) {
1004 datanotbinflag = 1;
1005 overhead = 3;
1006 if (datapt != rpkt.data) {
1007 *datapt++ = ',';
1008 datalinelen++;
1009 if ((dlen + datalinelen + 1) >= MAXDATALINELEN)
1011 *datapt++ = '\r';
1012 *datapt++ = '\n';
1013 datalinelen = 0;
1014 } else {
1015 *datapt++ = ' ';
1016 datalinelen++;
1022 * Save room for trailing junk
1024 if (dlen + overhead + datapt > dataend) {
1026 * Not enough room in this one, flush it out.
1028 ctl_flushpkt(CTL_MORE);
1030 memmove((char *)datapt, dp, (unsigned)dlen);
1031 datapt += dlen;
1032 datalinelen += dlen;
1037 * ctl_putstr - write a tagged string into the response packet
1039 static void
1040 ctl_putstr(
1041 const char *tag,
1042 const char *data,
1043 unsigned int len
1046 register char *cp;
1047 register const char *cq;
1048 char buffer[400];
1050 cp = buffer;
1051 cq = tag;
1052 while (*cq != '\0')
1053 *cp++ = *cq++;
1054 if (len > 0) {
1055 *cp++ = '=';
1056 *cp++ = '"';
1057 if (len > (int) (sizeof(buffer) - (cp - buffer) - 1))
1058 len = sizeof(buffer) - (cp - buffer) - 1;
1059 memmove(cp, data, (unsigned)len);
1060 cp += len;
1061 *cp++ = '"';
1063 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1068 * ctl_putdbl - write a tagged, signed double into the response packet
1070 static void
1071 ctl_putdbl(
1072 const char *tag,
1073 double ts
1076 register char *cp;
1077 register const char *cq;
1078 char buffer[200];
1080 cp = buffer;
1081 cq = tag;
1082 while (*cq != '\0')
1083 *cp++ = *cq++;
1084 *cp++ = '=';
1085 (void)sprintf(cp, "%.3f", ts);
1086 while (*cp != '\0')
1087 cp++;
1088 ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
1092 * ctl_putuint - write a tagged unsigned integer into the response
1094 static void
1095 ctl_putuint(
1096 const char *tag,
1097 u_long uval
1100 register char *cp;
1101 register const char *cq;
1102 char buffer[200];
1104 cp = buffer;
1105 cq = tag;
1106 while (*cq != '\0')
1107 *cp++ = *cq++;
1109 *cp++ = '=';
1110 (void) sprintf(cp, "%lu", uval);
1111 while (*cp != '\0')
1112 cp++;
1113 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1117 * ctl_putfs - write a decoded filestamp into the response
1119 static void
1120 ctl_putfs(
1121 const char *tag,
1122 tstamp_t uval
1125 register char *cp;
1126 register const char *cq;
1127 char buffer[200];
1128 struct tm *tm = NULL;
1129 time_t fstamp;
1131 cp = buffer;
1132 cq = tag;
1133 while (*cq != '\0')
1134 *cp++ = *cq++;
1136 *cp++ = '=';
1137 fstamp = uval - JAN_1970;
1138 tm = gmtime(&fstamp);
1139 if (tm == NULL)
1140 return;
1142 sprintf(cp, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
1143 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
1144 while (*cp != '\0')
1145 cp++;
1146 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1151 * ctl_puthex - write a tagged unsigned integer, in hex, into the
1152 * response
1154 static void
1155 ctl_puthex(
1156 const char *tag,
1157 u_long uval
1160 register char *cp;
1161 register const char *cq;
1162 char buffer[200];
1164 cp = buffer;
1165 cq = tag;
1166 while (*cq != '\0')
1167 *cp++ = *cq++;
1169 *cp++ = '=';
1170 (void) sprintf(cp, "0x%lx", uval);
1171 while (*cp != '\0')
1172 cp++;
1173 ctl_putdata(buffer,(unsigned)( cp - buffer ), 0);
1178 * ctl_putint - write a tagged signed integer into the response
1180 static void
1181 ctl_putint(
1182 const char *tag,
1183 long ival
1186 register char *cp;
1187 register const char *cq;
1188 char buffer[200];
1190 cp = buffer;
1191 cq = tag;
1192 while (*cq != '\0')
1193 *cp++ = *cq++;
1195 *cp++ = '=';
1196 (void) sprintf(cp, "%ld", ival);
1197 while (*cp != '\0')
1198 cp++;
1199 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1204 * ctl_putts - write a tagged timestamp, in hex, into the response
1206 static void
1207 ctl_putts(
1208 const char *tag,
1209 l_fp *ts
1212 register char *cp;
1213 register const char *cq;
1214 char buffer[200];
1216 cp = buffer;
1217 cq = tag;
1218 while (*cq != '\0')
1219 *cp++ = *cq++;
1221 *cp++ = '=';
1222 (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui & 0xffffffffUL,
1223 ts->l_uf & 0xffffffffUL);
1224 while (*cp != '\0')
1225 cp++;
1226 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1231 * ctl_putadr - write an IP address into the response
1233 static void
1234 ctl_putadr(
1235 const char *tag,
1236 u_int32 addr32,
1237 sockaddr_u *addr
1240 register char *cp;
1241 register const char *cq;
1242 char buffer[200];
1244 cp = buffer;
1245 cq = tag;
1246 while (*cq != '\0')
1247 *cp++ = *cq++;
1249 *cp++ = '=';
1250 if (addr == NULL)
1251 cq = numtoa(addr32);
1252 else
1253 cq = stoa(addr);
1254 while (*cq != '\0')
1255 *cp++ = *cq++;
1256 ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
1260 * ctl_putid - write a tagged clock ID into the response
1262 static void
1263 ctl_putid(
1264 const char *tag,
1265 char *id
1268 register char *cp;
1269 register const char *cq;
1270 char buffer[200];
1272 cp = buffer;
1273 cq = tag;
1274 while (*cq != '\0')
1275 *cp++ = *cq++;
1277 *cp++ = '=';
1278 cq = id;
1279 while (*cq != '\0' && (cq - id) < 4)
1280 *cp++ = *cq++;
1281 ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1286 * ctl_putarray - write a tagged eight element double array into the response
1288 static void
1289 ctl_putarray(
1290 const char *tag,
1291 double *arr,
1292 int start
1295 register char *cp;
1296 register const char *cq;
1297 char buffer[200];
1298 int i;
1299 cp = buffer;
1300 cq = tag;
1301 while (*cq != '\0')
1302 *cp++ = *cq++;
1303 i = start;
1304 do {
1305 if (i == 0)
1306 i = NTP_SHIFT;
1307 i--;
1308 (void)sprintf(cp, " %.2f", arr[i] * 1e3);
1309 while (*cp != '\0')
1310 cp++;
1311 } while(i != start);
1312 ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
1317 * ctl_putsys - output a system variable
1319 static void
1320 ctl_putsys(
1321 int varid
1324 l_fp tmp;
1325 char str[256];
1326 #ifdef OPENSSL
1327 struct cert_info *cp;
1328 char cbuf[256];
1329 #endif /* OPENSSL */
1331 switch (varid) {
1333 case CS_LEAP:
1334 ctl_putuint(sys_var[CS_LEAP].text, sys_leap);
1335 break;
1337 case CS_STRATUM:
1338 ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum);
1339 break;
1341 case CS_PRECISION:
1342 ctl_putint(sys_var[CS_PRECISION].text, sys_precision);
1343 break;
1345 case CS_ROOTDELAY:
1346 ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay *
1347 1e3);
1348 break;
1350 case CS_ROOTDISPERSION:
1351 ctl_putdbl(sys_var[CS_ROOTDISPERSION].text,
1352 sys_rootdisp * 1e3);
1353 break;
1355 case CS_REFID:
1356 if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC)
1357 ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL);
1358 else
1359 ctl_putid(sys_var[CS_REFID].text,
1360 (char *)&sys_refid);
1361 break;
1363 case CS_REFTIME:
1364 ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
1365 break;
1367 case CS_POLL:
1368 ctl_putuint(sys_var[CS_POLL].text, sys_poll);
1369 break;
1371 case CS_PEERID:
1372 if (sys_peer == NULL)
1373 ctl_putuint(sys_var[CS_PEERID].text, 0);
1374 else
1375 ctl_putuint(sys_var[CS_PEERID].text,
1376 sys_peer->associd);
1377 break;
1379 case CS_OFFSET:
1380 ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3);
1381 break;
1383 case CS_DRIFT:
1384 ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6);
1385 break;
1387 case CS_JITTER:
1388 ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3);
1389 break;
1391 case CS_ERROR:
1392 ctl_putdbl(sys_var[CS_ERROR].text, clock_jitter * 1e3);
1393 break;
1395 case CS_CLOCK:
1396 get_systime(&tmp);
1397 ctl_putts(sys_var[CS_CLOCK].text, &tmp);
1398 break;
1400 case CS_PROCESSOR:
1401 #ifndef HAVE_UNAME
1402 ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor,
1403 sizeof(str_processor) - 1);
1404 #else
1405 ctl_putstr(sys_var[CS_PROCESSOR].text,
1406 utsnamebuf.machine, strlen(utsnamebuf.machine));
1407 #endif /* HAVE_UNAME */
1408 break;
1410 case CS_SYSTEM:
1411 #ifndef HAVE_UNAME
1412 ctl_putstr(sys_var[CS_SYSTEM].text, str_system,
1413 sizeof(str_system) - 1);
1414 #else
1415 sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release);
1416 ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str));
1417 #endif /* HAVE_UNAME */
1418 break;
1420 case CS_VERSION:
1421 ctl_putstr(sys_var[CS_VERSION].text, Version,
1422 strlen(Version));
1423 break;
1425 case CS_STABIL:
1426 ctl_putdbl(sys_var[CS_STABIL].text, clock_stability *
1427 1e6);
1428 break;
1430 case CS_VARLIST:
1432 char buf[CTL_MAX_DATA_LEN];
1433 register char *s, *t, *be;
1434 register const char *ss;
1435 register int i;
1436 register struct ctl_var *k;
1438 s = buf;
1439 be = buf + sizeof(buf);
1440 if (s + strlen(sys_var[CS_VARLIST].text) + 4 > be)
1441 break; /* really long var name */
1443 snprintf(s, sizeof(buf), "%s=\"",
1444 sys_var[CS_VARLIST].text);
1445 s += strlen(s);
1446 t = s;
1447 for (k = sys_var; !(k->flags & EOV); k++) {
1448 if (k->flags & PADDING)
1449 continue;
1450 i = strlen(k->text);
1451 if (s+i+1 >= be)
1452 break;
1454 if (s != t)
1455 *s++ = ',';
1456 memcpy(s, k->text, i);
1457 s += i;
1460 for (k = ext_sys_var; k && !(k->flags & EOV);
1461 k++) {
1462 if (k->flags & PADDING)
1463 continue;
1465 ss = k->text;
1466 if (!ss)
1467 continue;
1469 while (*ss && *ss != '=')
1470 ss++;
1471 i = ss - k->text;
1472 if (s + i + 1 >= be)
1473 break;
1475 if (s != t)
1476 *s++ = ',';
1477 memcpy(s, k->text,
1478 (unsigned)i);
1479 s += i;
1481 if (s+2 >= be)
1482 break;
1484 *s++ = '"';
1485 *s = '\0';
1487 ctl_putdata(buf, (unsigned)( s - buf ),
1490 break;
1492 case CS_TAI:
1493 if (sys_tai > 0)
1494 ctl_putuint(sys_var[CS_TAI].text, sys_tai);
1495 break;
1497 case CS_LEAPTAB:
1498 if (leap_sec > 0)
1499 ctl_putfs(sys_var[CS_LEAPTAB].text,
1500 leap_sec);
1501 break;
1503 case CS_LEAPEND:
1504 if (leap_expire > 0)
1505 ctl_putfs(sys_var[CS_LEAPEND].text,
1506 leap_expire);
1507 break;
1509 case CS_RATE:
1510 ctl_putuint(sys_var[CS_RATE].text, ntp_minpoll);
1511 break;
1513 #ifdef OPENSSL
1514 case CS_FLAGS:
1515 if (crypto_flags)
1516 ctl_puthex(sys_var[CS_FLAGS].text,
1517 crypto_flags);
1518 break;
1520 case CS_DIGEST:
1521 if (crypto_flags) {
1522 strcpy(str, OBJ_nid2ln(crypto_nid));
1523 ctl_putstr(sys_var[CS_DIGEST].text, str,
1524 strlen(str));
1526 break;
1528 case CS_SIGNATURE:
1529 if (crypto_flags) {
1530 const EVP_MD *dp;
1532 dp = EVP_get_digestbynid(crypto_flags >> 16);
1533 strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
1534 ctl_putstr(sys_var[CS_SIGNATURE].text, str,
1535 strlen(str));
1537 break;
1539 case CS_HOST:
1540 if (sys_hostname != NULL)
1541 ctl_putstr(sys_var[CS_HOST].text, sys_hostname,
1542 strlen(sys_hostname));
1543 break;
1545 case CS_GROUP:
1546 if (sys_groupname != NULL)
1547 ctl_putstr(sys_var[CS_GROUP].text, sys_groupname,
1548 strlen(sys_groupname));
1549 break;
1551 case CS_CERTIF:
1552 for (cp = cinfo; cp != NULL; cp = cp->link) {
1553 snprintf(cbuf, sizeof(cbuf), "%s %s 0x%x",
1554 cp->subject, cp->issuer, cp->flags);
1555 ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
1556 strlen(cbuf));
1557 ctl_putfs(sys_var[CS_REVTIME].text, cp->last);
1559 break;
1561 case CS_PUBLIC:
1562 if (hostval.tstamp != 0)
1563 ctl_putfs(sys_var[CS_PUBLIC].text,
1564 ntohl(hostval.tstamp));
1565 break;
1566 #endif /* OPENSSL */
1572 * ctl_putpeer - output a peer variable
1574 static void
1575 ctl_putpeer(
1576 int varid,
1577 struct peer *peer
1580 int temp;
1581 #ifdef OPENSSL
1582 char str[256];
1583 struct autokey *ap;
1584 #endif /* OPENSSL */
1586 switch (varid) {
1588 case CP_CONFIG:
1589 ctl_putuint(peer_var[CP_CONFIG].text,
1590 (unsigned)((peer->flags & FLAG_PREEMPT) == 0));
1591 break;
1593 case CP_AUTHENABLE:
1594 ctl_putuint(peer_var[CP_AUTHENABLE].text,
1595 (unsigned)(peer->keyid != 0));
1596 break;
1598 case CP_AUTHENTIC:
1599 ctl_putuint(peer_var[CP_AUTHENTIC].text,
1600 (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0));
1601 break;
1603 case CP_SRCADR:
1604 ctl_putadr(peer_var[CP_SRCADR].text, 0,
1605 &peer->srcadr);
1606 break;
1608 case CP_SRCPORT:
1609 ctl_putuint(peer_var[CP_SRCPORT].text,
1610 ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port));
1611 break;
1613 case CP_DSTADR:
1614 if (peer->dstadr) {
1615 ctl_putadr(peer_var[CP_DSTADR].text, 0,
1616 &(peer->dstadr->sin));
1617 } else {
1618 ctl_putadr(peer_var[CP_DSTADR].text, 0,
1619 NULL);
1621 break;
1623 case CP_DSTPORT:
1624 ctl_putuint(peer_var[CP_DSTPORT].text,
1625 (u_long)(peer->dstadr ?
1626 ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0));
1627 break;
1629 case CP_IN:
1630 if (peer->r21 > 0)
1631 ctl_putdbl(peer_var[CP_IN].text,
1632 peer->r21 / 1e3);
1633 break;
1635 case CP_OUT:
1636 if (peer->r34 >0)
1637 ctl_putdbl(peer_var[CP_OUT].text,
1638 peer->r34 / 1e3);
1639 break;
1641 case CP_RATE:
1642 ctl_putuint(peer_var[CP_RATE].text, peer->throttle);
1643 break;
1645 case CP_LEAP:
1646 ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
1647 break;
1649 case CP_HMODE:
1650 ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
1651 break;
1653 case CP_STRATUM:
1654 ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
1655 break;
1657 case CP_PPOLL:
1658 ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
1659 break;
1661 case CP_HPOLL:
1662 ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
1663 break;
1665 case CP_PRECISION:
1666 ctl_putint(peer_var[CP_PRECISION].text,
1667 peer->precision);
1668 break;
1670 case CP_ROOTDELAY:
1671 ctl_putdbl(peer_var[CP_ROOTDELAY].text,
1672 peer->rootdelay * 1e3);
1673 break;
1675 case CP_ROOTDISPERSION:
1676 ctl_putdbl(peer_var[CP_ROOTDISPERSION].text,
1677 peer->rootdisp * 1e3);
1678 break;
1680 case CP_REFID:
1681 if (peer->flags & FLAG_REFCLOCK) {
1682 ctl_putid(peer_var[CP_REFID].text,
1683 (char *)&peer->refid);
1684 } else {
1685 if (peer->stratum > 1 && peer->stratum <
1686 STRATUM_UNSPEC)
1687 ctl_putadr(peer_var[CP_REFID].text,
1688 peer->refid, NULL);
1689 else
1690 ctl_putid(peer_var[CP_REFID].text,
1691 (char *)&peer->refid);
1693 break;
1695 case CP_REFTIME:
1696 ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime);
1697 break;
1699 case CP_ORG:
1700 ctl_putts(peer_var[CP_ORG].text, &peer->aorg);
1701 break;
1703 case CP_REC:
1704 ctl_putts(peer_var[CP_REC].text, &peer->dst);
1705 break;
1707 case CP_XMT:
1708 if (peer->xleave != 0)
1709 ctl_putdbl(peer_var[CP_XMT].text, peer->xleave *
1710 1e3);
1711 break;
1713 case CP_BIAS:
1714 if (peer->bias != 0)
1715 ctl_putdbl(peer_var[CP_BIAS].text, peer->bias *
1716 1e3);
1717 break;
1719 case CP_REACH:
1720 ctl_puthex(peer_var[CP_REACH].text, peer->reach);
1721 break;
1723 case CP_FLASH:
1724 temp = peer->flash;
1725 ctl_puthex(peer_var[CP_FLASH].text, temp);
1726 break;
1728 case CP_TTL:
1729 if (peer->ttl > 0)
1730 ctl_putint(peer_var[CP_TTL].text,
1731 sys_ttl[peer->ttl]);
1732 break;
1734 case CP_UNREACH:
1735 ctl_putuint(peer_var[CP_UNREACH].text, peer->unreach);
1736 break;
1738 case CP_TIMER:
1739 ctl_putuint(peer_var[CP_TIMER].text,
1740 peer->nextdate - current_time);
1741 break;
1743 case CP_DELAY:
1744 ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3);
1745 break;
1747 case CP_OFFSET:
1748 ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset *
1749 1e3);
1750 break;
1752 case CP_JITTER:
1753 ctl_putdbl(peer_var[CP_JITTER].text, peer->jitter *
1754 1e3);
1755 break;
1757 case CP_DISPERSION:
1758 ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp *
1759 1e3);
1760 break;
1762 case CP_KEYID:
1763 if (peer->keyid > NTP_MAXKEY)
1764 ctl_puthex(peer_var[CP_KEYID].text,
1765 peer->keyid);
1766 else
1767 ctl_putuint(peer_var[CP_KEYID].text,
1768 peer->keyid);
1769 break;
1771 case CP_FILTDELAY:
1772 ctl_putarray(peer_var[CP_FILTDELAY].text,
1773 peer->filter_delay, (int)peer->filter_nextpt);
1774 break;
1776 case CP_FILTOFFSET:
1777 ctl_putarray(peer_var[CP_FILTOFFSET].text,
1778 peer->filter_offset, (int)peer->filter_nextpt);
1779 break;
1781 case CP_FILTERROR:
1782 ctl_putarray(peer_var[CP_FILTERROR].text,
1783 peer->filter_disp, (int)peer->filter_nextpt);
1784 break;
1786 case CP_PMODE:
1787 ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
1788 break;
1790 case CP_RECEIVED:
1791 ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
1792 break;
1794 case CP_SENT:
1795 ctl_putuint(peer_var[CP_SENT].text, peer->sent);
1796 break;
1798 case CP_VARLIST:
1800 char buf[CTL_MAX_DATA_LEN];
1801 register char *s, *t, *be;
1802 register int i;
1803 register struct ctl_var *k;
1805 s = buf;
1806 be = buf + sizeof(buf);
1807 if (s + strlen(peer_var[CP_VARLIST].text) + 4 > be)
1808 break; /* really long var name */
1810 snprintf(s, sizeof(buf), "%s=\"",
1811 peer_var[CP_VARLIST].text);
1812 s += strlen(s);
1813 t = s;
1814 for (k = peer_var; !(k->flags & EOV); k++) {
1815 if (k->flags & PADDING)
1816 continue;
1818 i = strlen(k->text);
1819 if (s + i + 1 >= be)
1820 break;
1822 if (s != t)
1823 *s++ = ',';
1824 memcpy(s, k->text, i);
1825 s += i;
1827 if (s+2 >= be)
1828 break;
1830 *s++ = '"';
1831 *s = '\0';
1832 ctl_putdata(buf, (unsigned)(s - buf), 0);
1834 break;
1835 #ifdef OPENSSL
1836 case CP_FLAGS:
1837 if (peer->crypto)
1838 ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto);
1839 break;
1841 case CP_SIGNATURE:
1842 if (peer->crypto) {
1843 const EVP_MD *dp;
1845 dp = EVP_get_digestbynid(peer->crypto >> 16);
1846 strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
1847 ctl_putstr(peer_var[CP_SIGNATURE].text, str,
1848 strlen(str));
1850 break;
1852 case CP_HOST:
1853 if (peer->subject != NULL)
1854 ctl_putstr(peer_var[CP_HOST].text,
1855 peer->subject, strlen(peer->subject));
1856 break;
1858 case CP_VALID: /* not used */
1859 break;
1861 case CP_INITSEQ:
1862 if ((ap = (struct autokey *)peer->recval.ptr) == NULL)
1863 break;
1865 ctl_putint(peer_var[CP_INITSEQ].text, ap->seq);
1866 ctl_puthex(peer_var[CP_INITKEY].text, ap->key);
1867 ctl_putfs(peer_var[CP_INITTSP].text,
1868 ntohl(peer->recval.tstamp));
1869 break;
1870 #endif /* OPENSSL */
1875 #ifdef REFCLOCK
1877 * ctl_putclock - output clock variables
1879 static void
1880 ctl_putclock(
1881 int varid,
1882 struct refclockstat *clock_stat,
1883 int mustput
1886 switch(varid) {
1888 case CC_TYPE:
1889 if (mustput || clock_stat->clockdesc == NULL
1890 || *(clock_stat->clockdesc) == '\0') {
1891 ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type);
1893 break;
1894 case CC_TIMECODE:
1895 ctl_putstr(clock_var[CC_TIMECODE].text,
1896 clock_stat->p_lastcode,
1897 (unsigned)clock_stat->lencode);
1898 break;
1900 case CC_POLL:
1901 ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls);
1902 break;
1904 case CC_NOREPLY:
1905 ctl_putuint(clock_var[CC_NOREPLY].text,
1906 clock_stat->noresponse);
1907 break;
1909 case CC_BADFORMAT:
1910 ctl_putuint(clock_var[CC_BADFORMAT].text,
1911 clock_stat->badformat);
1912 break;
1914 case CC_BADDATA:
1915 ctl_putuint(clock_var[CC_BADDATA].text,
1916 clock_stat->baddata);
1917 break;
1919 case CC_FUDGETIME1:
1920 if (mustput || (clock_stat->haveflags & CLK_HAVETIME1))
1921 ctl_putdbl(clock_var[CC_FUDGETIME1].text,
1922 clock_stat->fudgetime1 * 1e3);
1923 break;
1925 case CC_FUDGETIME2:
1926 if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) ctl_putdbl(clock_var[CC_FUDGETIME2].text,
1927 clock_stat->fudgetime2 * 1e3);
1928 break;
1930 case CC_FUDGEVAL1:
1931 if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1))
1932 ctl_putint(clock_var[CC_FUDGEVAL1].text,
1933 clock_stat->fudgeval1);
1934 break;
1936 case CC_FUDGEVAL2:
1937 if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) {
1938 if (clock_stat->fudgeval1 > 1)
1939 ctl_putadr(clock_var[CC_FUDGEVAL2].text,
1940 (u_int32)clock_stat->fudgeval2, NULL);
1941 else
1942 ctl_putid(clock_var[CC_FUDGEVAL2].text,
1943 (char *)&clock_stat->fudgeval2);
1945 break;
1947 case CC_FLAGS:
1948 if (mustput || (clock_stat->haveflags & (CLK_HAVEFLAG1 |
1949 CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4)))
1950 ctl_putuint(clock_var[CC_FLAGS].text,
1951 clock_stat->flags);
1952 break;
1954 case CC_DEVICE:
1955 if (clock_stat->clockdesc == NULL ||
1956 *(clock_stat->clockdesc) == '\0') {
1957 if (mustput)
1958 ctl_putstr(clock_var[CC_DEVICE].text,
1959 "", 0);
1960 } else {
1961 ctl_putstr(clock_var[CC_DEVICE].text,
1962 clock_stat->clockdesc,
1963 strlen(clock_stat->clockdesc));
1965 break;
1967 case CC_VARLIST:
1969 char buf[CTL_MAX_DATA_LEN];
1970 register char *s, *t, *be;
1971 register const char *ss;
1972 register int i;
1973 register struct ctl_var *k;
1975 s = buf;
1976 be = buf + sizeof(buf);
1977 if (s + strlen(clock_var[CC_VARLIST].text) + 4 >
1979 break; /* really long var name */
1981 snprintf(s, sizeof(buf), "%s=\"",
1982 clock_var[CC_VARLIST].text);
1983 s += strlen(s);
1984 t = s;
1986 for (k = clock_var; !(k->flags & EOV); k++) {
1987 if (k->flags & PADDING)
1988 continue;
1990 i = strlen(k->text);
1991 if (s + i + 1 >= be)
1992 break;
1994 if (s != t)
1995 *s++ = ',';
1996 memcpy(s, k->text, i);
1997 s += i;
2000 for (k = clock_stat->kv_list; k && !(k->flags &
2001 EOV); k++) {
2002 if (k->flags & PADDING)
2003 continue;
2005 ss = k->text;
2006 if (!ss)
2007 continue;
2009 while (*ss && *ss != '=')
2010 ss++;
2011 i = ss - k->text;
2012 if (s+i+1 >= be)
2013 break;
2015 if (s != t)
2016 *s++ = ',';
2017 memcpy(s, k->text, (unsigned)i);
2018 s += i;
2019 *s = '\0';
2021 if (s+2 >= be)
2022 break;
2024 *s++ = '"';
2025 *s = '\0';
2026 ctl_putdata(buf, (unsigned)( s - buf ), 0);
2028 break;
2031 #endif
2036 * ctl_getitem - get the next data item from the incoming packet
2038 static struct ctl_var *
2039 ctl_getitem(
2040 struct ctl_var *var_list,
2041 char **data
2044 register struct ctl_var *v;
2045 register char *cp;
2046 register char *tp;
2047 static struct ctl_var eol = { 0, EOV, };
2048 static char buf[128];
2051 * Delete leading commas and white space
2053 while (reqpt < reqend && (*reqpt == ',' ||
2054 isspace((unsigned char)*reqpt)))
2055 reqpt++;
2056 if (reqpt >= reqend)
2057 return (0);
2059 if (var_list == (struct ctl_var *)0)
2060 return (&eol);
2063 * Look for a first character match on the tag. If we find
2064 * one, see if it is a full match.
2066 v = var_list;
2067 cp = reqpt;
2068 while (!(v->flags & EOV)) {
2069 if (!(v->flags & PADDING) && *cp == *(v->text)) {
2070 tp = v->text;
2071 while (*tp != '\0' && *tp != '=' && cp <
2072 reqend && *cp == *tp) {
2073 cp++;
2074 tp++;
2076 if ((*tp == '\0') || (*tp == '=')) {
2077 while (cp < reqend && isspace((unsigned char)*cp))
2078 cp++;
2079 if (cp == reqend || *cp == ',') {
2080 buf[0] = '\0';
2081 *data = buf;
2082 if (cp < reqend)
2083 cp++;
2084 reqpt = cp;
2085 return v;
2087 if (*cp == '=') {
2088 cp++;
2089 tp = buf;
2090 while (cp < reqend && isspace((unsigned char)*cp))
2091 cp++;
2092 while (cp < reqend && *cp != ',') {
2093 *tp++ = *cp++;
2094 if (tp >= buf + sizeof(buf)) {
2095 ctl_error(CERR_BADFMT);
2096 numctlbadpkts++;
2097 #if 0 /* Avoid possible DOS attack */
2098 /* If we get a smarter msyslog we can re-enable this */
2099 msyslog(LOG_WARNING,
2100 "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n",
2101 stoa(rmt_addr), SRCPORT(rmt_addr)
2103 #endif
2104 return (0);
2107 if (cp < reqend)
2108 cp++;
2109 *tp-- = '\0';
2110 while (tp >= buf) {
2111 if (!isspace((unsigned int)(*tp)))
2112 break;
2113 *tp-- = '\0';
2115 reqpt = cp;
2116 *data = buf;
2117 return (v);
2120 cp = reqpt;
2122 v++;
2124 return v;
2129 * control_unspec - response to an unspecified op-code
2131 /*ARGSUSED*/
2132 static void
2133 control_unspec(
2134 struct recvbuf *rbufp,
2135 int restrict_mask
2138 struct peer *peer;
2141 * What is an appropriate response to an unspecified op-code?
2142 * I return no errors and no data, unless a specified assocation
2143 * doesn't exist.
2145 if (res_associd != 0) {
2146 if ((peer = findpeerbyassoc(res_associd)) == 0) {
2147 ctl_error(CERR_BADASSOC);
2148 return;
2150 rpkt.status = htons(ctlpeerstatus(peer));
2151 } else {
2152 rpkt.status = htons(ctlsysstatus());
2154 ctl_flushpkt(0);
2159 * read_status - return either a list of associd's, or a particular
2160 * peer's status.
2162 /*ARGSUSED*/
2163 static void
2164 read_status(
2165 struct recvbuf *rbufp,
2166 int restrict_mask
2169 register int i;
2170 register struct peer *peer;
2171 u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)];
2173 #ifdef DEBUG
2174 if (debug > 2)
2175 printf("read_status: ID %d\n", res_associd);
2176 #endif
2178 * Two choices here. If the specified association ID is
2179 * zero we return all known assocation ID's. Otherwise
2180 * we return a bunch of stuff about the particular peer.
2182 if (res_associd == 0) {
2183 register int n;
2185 n = 0;
2186 rpkt.status = htons(ctlsysstatus());
2187 for (i = 0; i < NTP_HASH_SIZE; i++) {
2188 for (peer = assoc_hash[i]; peer != 0;
2189 peer = peer->ass_next) {
2190 ass_stat[n++] = htons(peer->associd);
2191 ass_stat[n++] =
2192 htons(ctlpeerstatus(peer));
2193 if (n ==
2194 CTL_MAX_DATA_LEN/sizeof(u_short)) {
2195 ctl_putdata((char *)ass_stat,
2196 n * sizeof(u_short), 1);
2197 n = 0;
2202 if (n != 0)
2203 ctl_putdata((char *)ass_stat, n *
2204 sizeof(u_short), 1);
2205 ctl_flushpkt(0);
2206 } else {
2207 peer = findpeerbyassoc(res_associd);
2208 if (peer == 0) {
2209 ctl_error(CERR_BADASSOC);
2210 } else {
2211 register u_char *cp;
2213 rpkt.status = htons(ctlpeerstatus(peer));
2214 if (res_authokay)
2215 peer->num_events = 0;
2217 * For now, output everything we know about the
2218 * peer. May be more selective later.
2220 for (cp = def_peer_var; *cp != 0; cp++)
2221 ctl_putpeer((int)*cp, peer);
2222 ctl_flushpkt(0);
2229 * read_variables - return the variables the caller asks for
2231 /*ARGSUSED*/
2232 static void
2233 read_variables(
2234 struct recvbuf *rbufp,
2235 int restrict_mask
2238 register struct ctl_var *v;
2239 register int i;
2240 char *valuep;
2241 u_char *wants;
2242 unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE +
2243 1) : (CP_MAXCODE + 1);
2244 if (res_associd == 0) {
2246 * Wants system variables. Figure out which he wants
2247 * and give them to him.
2249 rpkt.status = htons(ctlsysstatus());
2250 if (res_authokay)
2251 ctl_sys_num_events = 0;
2252 gotvar += count_var(ext_sys_var);
2253 wants = (u_char *)emalloc(gotvar);
2254 memset((char *)wants, 0, gotvar);
2255 gotvar = 0;
2256 while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
2257 if (v->flags & EOV) {
2258 if ((v = ctl_getitem(ext_sys_var,
2259 &valuep)) != 0) {
2260 if (v->flags & EOV) {
2261 ctl_error(CERR_UNKNOWNVAR);
2262 free((char *)wants);
2263 return;
2265 wants[CS_MAXCODE + 1 +
2266 v->code] = 1;
2267 gotvar = 1;
2268 continue;
2269 } else {
2270 break; /* shouldn't happen ! */
2273 wants[v->code] = 1;
2274 gotvar = 1;
2276 if (gotvar) {
2277 for (i = 1; i <= CS_MAXCODE; i++)
2278 if (wants[i])
2279 ctl_putsys(i);
2280 for (i = 0; ext_sys_var &&
2281 !(ext_sys_var[i].flags & EOV); i++)
2282 if (wants[i + CS_MAXCODE + 1])
2283 ctl_putdata(ext_sys_var[i].text,
2284 strlen(ext_sys_var[i].text),
2286 } else {
2287 register u_char *cs;
2288 register struct ctl_var *kv;
2290 for (cs = def_sys_var; *cs != 0; cs++)
2291 ctl_putsys((int)*cs);
2292 for (kv = ext_sys_var; kv && !(kv->flags & EOV);
2293 kv++)
2294 if (kv->flags & DEF)
2295 ctl_putdata(kv->text,
2296 strlen(kv->text), 0);
2298 free((char *)wants);
2299 } else {
2300 register struct peer *peer;
2303 * Wants info for a particular peer. See if we know
2304 * the guy.
2306 peer = findpeerbyassoc(res_associd);
2307 if (peer == 0) {
2308 ctl_error(CERR_BADASSOC);
2309 return;
2311 rpkt.status = htons(ctlpeerstatus(peer));
2312 if (res_authokay)
2313 peer->num_events = 0;
2314 wants = (u_char *)emalloc(gotvar);
2315 memset((char*)wants, 0, gotvar);
2316 gotvar = 0;
2317 while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
2318 if (v->flags & EOV) {
2319 ctl_error(CERR_UNKNOWNVAR);
2320 free((char *)wants);
2321 return;
2323 wants[v->code] = 1;
2324 gotvar = 1;
2326 if (gotvar) {
2327 for (i = 1; i <= CP_MAXCODE; i++)
2328 if (wants[i])
2329 ctl_putpeer(i, peer);
2330 } else {
2331 register u_char *cp;
2333 for (cp = def_peer_var; *cp != 0; cp++)
2334 ctl_putpeer((int)*cp, peer);
2336 free((char *)wants);
2338 ctl_flushpkt(0);
2343 * write_variables - write into variables. We only allow leap bit
2344 * writing this way.
2346 /*ARGSUSED*/
2347 static void
2348 write_variables(
2349 struct recvbuf *rbufp,
2350 int restrict_mask
2353 register struct ctl_var *v;
2354 register int ext_var;
2355 char *valuep;
2356 long val = 0;
2359 * If he's trying to write into a peer tell him no way
2361 if (res_associd != 0) {
2362 ctl_error(CERR_PERMISSION);
2363 return;
2367 * Set status
2369 rpkt.status = htons(ctlsysstatus());
2372 * Look through the variables. Dump out at the first sign of
2373 * trouble.
2375 while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
2376 ext_var = 0;
2377 if (v->flags & EOV) {
2378 if ((v = ctl_getitem(ext_sys_var, &valuep)) !=
2379 0) {
2380 if (v->flags & EOV) {
2381 ctl_error(CERR_UNKNOWNVAR);
2382 return;
2384 ext_var = 1;
2385 } else {
2386 break;
2389 if (!(v->flags & CAN_WRITE)) {
2390 ctl_error(CERR_PERMISSION);
2391 return;
2393 if (!ext_var && (*valuep == '\0' || !atoint(valuep,
2394 &val))) {
2395 ctl_error(CERR_BADFMT);
2396 return;
2398 if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) {
2399 ctl_error(CERR_BADVALUE);
2400 return;
2403 if (ext_var) {
2404 char *s = (char *)emalloc(strlen(v->text) +
2405 strlen(valuep) + 2);
2406 const char *t;
2407 char *tt = s;
2409 t = v->text;
2410 while (*t && *t != '=')
2411 *tt++ = *t++;
2413 *tt++ = '=';
2414 strcat(tt, valuep);
2415 set_sys_var(s, strlen(s)+1, v->flags);
2416 free(s);
2417 } else {
2419 * This one seems sane. Save it.
2421 switch(v->code) {
2423 case CS_LEAP:
2424 default:
2425 ctl_error(CERR_UNSPEC); /* really */
2426 return;
2432 * If we got anything, do it. xxx nothing to do ***
2435 if (leapind != ~0 || leapwarn != ~0) {
2436 if (!leap_setleap((int)leapind, (int)leapwarn)) {
2437 ctl_error(CERR_PERMISSION);
2438 return;
2442 ctl_flushpkt(0);
2446 * configure() processes ntpq :config/config-from-file, allowing
2447 * generic runtime reconfiguration.
2449 static void configure(
2450 struct recvbuf *rbufp,
2451 int restrict_mask
2454 int data_count, retval, replace_nl;
2456 /* I haven't yet implemented changes to an existing association.
2457 * Hence check if the association id is 0
2459 if (res_associd != 0) {
2460 ctl_error(CERR_BADVALUE);
2461 return;
2464 if (restrict_mask & RES_NOMODIFY) {
2465 snprintf(remote_config.err_msg,
2466 sizeof(remote_config.err_msg),
2467 "runtime configuration prohibited by restrict ... nomodify");
2468 ctl_putdata(remote_config.err_msg,
2469 strlen(remote_config.err_msg), 0);
2470 ctl_flushpkt(0);
2471 msyslog(LOG_NOTICE,
2472 "runtime config from %s rejected due to nomodify restriction",
2473 stoa(&rbufp->recv_srcadr));
2474 return;
2477 /* Initialize the remote config buffer */
2478 data_count = reqend - reqpt;
2479 memcpy(remote_config.buffer, reqpt, data_count);
2480 if (data_count > 0
2481 && '\n' != remote_config.buffer[data_count - 1])
2482 remote_config.buffer[data_count++] = '\n';
2483 remote_config.buffer[data_count] = '\0';
2484 remote_config.pos = 0;
2485 remote_config.err_pos = 0;
2486 remote_config.no_errors = 0;
2488 /* do not include terminating newline in log */
2489 if (data_count > 0
2490 && '\n' == remote_config.buffer[data_count - 1]) {
2491 remote_config.buffer[data_count - 1] = '\0';
2492 replace_nl = 1;
2493 } else
2494 replace_nl = 0;
2496 DPRINTF(1, ("Got Remote Configuration Command: %s\n",
2497 remote_config.buffer));
2498 msyslog(LOG_NOTICE, "%s config: %s",
2499 stoa(&rbufp->recv_srcadr),
2500 remote_config.buffer);
2502 if (replace_nl)
2503 remote_config.buffer[data_count - 1] = '\n';
2505 config_remotely(&rbufp->recv_srcadr);
2508 * Check if errors were reported. If not, output 'Config
2509 * Succeeded'. Else output the error count. It would be nice
2510 * to output any parser error messages.
2512 if (0 == remote_config.no_errors) {
2513 retval = snprintf(remote_config.err_msg,
2514 sizeof(remote_config.err_msg),
2515 "Config Succeeded");
2516 if (retval > 0)
2517 remote_config.err_pos += retval;
2520 ctl_putdata(remote_config.err_msg, remote_config.err_pos, 0);
2521 ctl_flushpkt(0);
2523 DPRINTF(1, ("Reply: %s\n", remote_config.err_msg));
2525 if (remote_config.no_errors > 0)
2526 msyslog(LOG_NOTICE, "%d error in %s config",
2527 remote_config.no_errors,
2528 stoa(&rbufp->recv_srcadr));
2533 * read_clock_status - return clock radio status
2535 /*ARGSUSED*/
2536 static void
2537 read_clock_status(
2538 struct recvbuf *rbufp,
2539 int restrict_mask
2542 #ifndef REFCLOCK
2544 * If no refclock support, no data to return
2546 ctl_error(CERR_BADASSOC);
2547 #else
2548 register struct ctl_var *v;
2549 register int i;
2550 register struct peer *peer;
2551 char *valuep;
2552 u_char *wants;
2553 unsigned int gotvar;
2554 struct refclockstat clock_stat;
2556 if (res_associd == 0) {
2559 * Find a clock for this jerk. If the system peer
2560 * is a clock use it, else search the hash tables
2561 * for one.
2563 if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK))
2565 peer = sys_peer;
2566 } else {
2567 peer = 0;
2568 for (i = 0; peer == 0 && i < NTP_HASH_SIZE; i++) {
2569 for (peer = assoc_hash[i]; peer != 0;
2570 peer = peer->ass_next) {
2571 if (peer->flags & FLAG_REFCLOCK)
2572 break;
2575 if (peer == 0) {
2576 ctl_error(CERR_BADASSOC);
2577 return;
2580 } else {
2581 peer = findpeerbyassoc(res_associd);
2582 if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) {
2583 ctl_error(CERR_BADASSOC);
2584 return;
2589 * If we got here we have a peer which is a clock. Get his
2590 * status.
2592 clock_stat.kv_list = (struct ctl_var *)0;
2593 refclock_control(&peer->srcadr, (struct refclockstat *)0,
2594 &clock_stat);
2597 * Look for variables in the packet.
2599 rpkt.status = htons(ctlclkstatus(&clock_stat));
2600 gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list);
2601 wants = (u_char *)emalloc(gotvar);
2602 memset((char*)wants, 0, gotvar);
2603 gotvar = 0;
2604 while ((v = ctl_getitem(clock_var, &valuep)) != 0) {
2605 if (v->flags & EOV) {
2606 if ((v = ctl_getitem(clock_stat.kv_list,
2607 &valuep)) != 0) {
2608 if (v->flags & EOV) {
2609 ctl_error(CERR_UNKNOWNVAR);
2610 free((char*)wants);
2611 free_varlist(clock_stat.kv_list);
2612 return;
2614 wants[CC_MAXCODE + 1 + v->code] = 1;
2615 gotvar = 1;
2616 continue;
2617 } else {
2618 break; /* shouldn't happen ! */
2621 wants[v->code] = 1;
2622 gotvar = 1;
2625 if (gotvar) {
2626 for (i = 1; i <= CC_MAXCODE; i++)
2627 if (wants[i])
2628 ctl_putclock(i, &clock_stat, 1);
2629 for (i = 0; clock_stat.kv_list &&
2630 !(clock_stat.kv_list[i].flags & EOV); i++)
2631 if (wants[i + CC_MAXCODE + 1])
2632 ctl_putdata(clock_stat.kv_list[i].text,
2633 strlen(clock_stat.kv_list[i].text),
2635 } else {
2636 register u_char *cc;
2637 register struct ctl_var *kv;
2639 for (cc = def_clock_var; *cc != 0; cc++)
2640 ctl_putclock((int)*cc, &clock_stat, 0);
2641 for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV);
2642 kv++)
2643 if (kv->flags & DEF)
2644 ctl_putdata(kv->text, strlen(kv->text),
2648 free((char*)wants);
2649 free_varlist(clock_stat.kv_list);
2651 ctl_flushpkt(0);
2652 #endif
2657 * write_clock_status - we don't do this
2659 /*ARGSUSED*/
2660 static void
2661 write_clock_status(
2662 struct recvbuf *rbufp,
2663 int restrict_mask
2666 ctl_error(CERR_PERMISSION);
2670 * Trap support from here on down. We send async trap messages when the
2671 * upper levels report trouble. Traps can by set either by control
2672 * messages or by configuration.
2675 * set_trap - set a trap in response to a control message
2677 static void
2678 set_trap(
2679 struct recvbuf *rbufp,
2680 int restrict_mask
2683 int traptype;
2686 * See if this guy is allowed
2688 if (restrict_mask & RES_NOTRAP) {
2689 ctl_error(CERR_PERMISSION);
2690 return;
2694 * Determine his allowed trap type.
2696 traptype = TRAP_TYPE_PRIO;
2697 if (restrict_mask & RES_LPTRAP)
2698 traptype = TRAP_TYPE_NONPRIO;
2701 * Call ctlsettrap() to do the work. Return
2702 * an error if it can't assign the trap.
2704 if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype,
2705 (int)res_version))
2706 ctl_error(CERR_NORESOURCE);
2707 ctl_flushpkt(0);
2712 * unset_trap - unset a trap in response to a control message
2714 static void
2715 unset_trap(
2716 struct recvbuf *rbufp,
2717 int restrict_mask
2720 int traptype;
2723 * We don't prevent anyone from removing his own trap unless the
2724 * trap is configured. Note we also must be aware of the
2725 * possibility that restriction flags were changed since this
2726 * guy last set his trap. Set the trap type based on this.
2728 traptype = TRAP_TYPE_PRIO;
2729 if (restrict_mask & RES_LPTRAP)
2730 traptype = TRAP_TYPE_NONPRIO;
2733 * Call ctlclrtrap() to clear this out.
2735 if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype))
2736 ctl_error(CERR_BADASSOC);
2737 ctl_flushpkt(0);
2742 * ctlsettrap - called to set a trap
2745 ctlsettrap(
2746 sockaddr_u *raddr,
2747 struct interface *linter,
2748 int traptype,
2749 int version
2752 register struct ctl_trap *tp;
2753 register struct ctl_trap *tptouse;
2756 * See if we can find this trap. If so, we only need update
2757 * the flags and the time.
2759 if ((tp = ctlfindtrap(raddr, linter)) != NULL) {
2760 switch (traptype) {
2762 case TRAP_TYPE_CONFIG:
2763 tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED;
2764 break;
2766 case TRAP_TYPE_PRIO:
2767 if (tp->tr_flags & TRAP_CONFIGURED)
2768 return (1); /* don't change anything */
2769 tp->tr_flags = TRAP_INUSE;
2770 break;
2772 case TRAP_TYPE_NONPRIO:
2773 if (tp->tr_flags & TRAP_CONFIGURED)
2774 return (1); /* don't change anything */
2775 tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO;
2776 break;
2778 tp->tr_settime = current_time;
2779 tp->tr_resets++;
2780 return (1);
2784 * First we heard of this guy. Try to find a trap structure
2785 * for him to use, clearing out lesser priority guys if we
2786 * have to. Clear out anyone who's expired while we're at it.
2788 tptouse = NULL;
2789 for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
2790 if ((tp->tr_flags & TRAP_INUSE) &&
2791 !(tp->tr_flags & TRAP_CONFIGURED) &&
2792 ((tp->tr_settime + CTL_TRAPTIME) > current_time)) {
2793 tp->tr_flags = 0;
2794 num_ctl_traps--;
2796 if (!(tp->tr_flags & TRAP_INUSE)) {
2797 tptouse = tp;
2798 } else if (!(tp->tr_flags & TRAP_CONFIGURED)) {
2799 switch (traptype) {
2801 case TRAP_TYPE_CONFIG:
2802 if (tptouse == NULL) {
2803 tptouse = tp;
2804 break;
2806 if (tptouse->tr_flags & TRAP_NONPRIO &&
2807 !(tp->tr_flags & TRAP_NONPRIO))
2808 break;
2810 if (!(tptouse->tr_flags & TRAP_NONPRIO)
2811 && tp->tr_flags & TRAP_NONPRIO) {
2812 tptouse = tp;
2813 break;
2815 if (tptouse->tr_origtime <
2816 tp->tr_origtime)
2817 tptouse = tp;
2818 break;
2820 case TRAP_TYPE_PRIO:
2821 if (tp->tr_flags & TRAP_NONPRIO) {
2822 if (tptouse == NULL ||
2823 (tptouse->tr_flags &
2824 TRAP_INUSE &&
2825 tptouse->tr_origtime <
2826 tp->tr_origtime))
2827 tptouse = tp;
2829 break;
2831 case TRAP_TYPE_NONPRIO:
2832 break;
2838 * If we don't have room for him return an error.
2840 if (tptouse == NULL)
2841 return (0);
2844 * Set up this structure for him.
2846 tptouse->tr_settime = tptouse->tr_origtime = current_time;
2847 tptouse->tr_count = tptouse->tr_resets = 0;
2848 tptouse->tr_sequence = 1;
2849 tptouse->tr_addr = *raddr;
2850 tptouse->tr_localaddr = linter;
2851 tptouse->tr_version = (u_char) version;
2852 tptouse->tr_flags = TRAP_INUSE;
2853 if (traptype == TRAP_TYPE_CONFIG)
2854 tptouse->tr_flags |= TRAP_CONFIGURED;
2855 else if (traptype == TRAP_TYPE_NONPRIO)
2856 tptouse->tr_flags |= TRAP_NONPRIO;
2857 num_ctl_traps++;
2858 return (1);
2863 * ctlclrtrap - called to clear a trap
2866 ctlclrtrap(
2867 sockaddr_u *raddr,
2868 struct interface *linter,
2869 int traptype
2872 register struct ctl_trap *tp;
2874 if ((tp = ctlfindtrap(raddr, linter)) == NULL)
2875 return (0);
2877 if (tp->tr_flags & TRAP_CONFIGURED
2878 && traptype != TRAP_TYPE_CONFIG)
2879 return (0);
2881 tp->tr_flags = 0;
2882 num_ctl_traps--;
2883 return (1);
2888 * ctlfindtrap - find a trap given the remote and local addresses
2890 static struct ctl_trap *
2891 ctlfindtrap(
2892 sockaddr_u *raddr,
2893 struct interface *linter
2896 register struct ctl_trap *tp;
2898 for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
2899 if ((tp->tr_flags & TRAP_INUSE)
2900 && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr))
2901 && SOCK_EQ(raddr, &tp->tr_addr)
2902 && (linter == tp->tr_localaddr) )
2903 return (tp);
2905 return (struct ctl_trap *)NULL;
2910 * report_event - report an event to the trappers
2912 void
2913 report_event(
2914 int err, /* error code */
2915 struct peer *peer, /* peer structure pointer */
2916 const char *str /* protostats string */
2919 char statstr[NTP_MAXSTRLEN];
2920 int i;
2921 size_t len;
2924 * Report the error to the protostats file, system log and
2925 * trappers.
2927 if (peer == NULL) {
2930 * Discard a system report if the number of reports of
2931 * the same type exceeds the maximum.
2933 if (ctl_sys_last_event != (u_char)err)
2934 ctl_sys_num_events= 0;
2935 if (ctl_sys_num_events >= CTL_SYS_MAXEVENTS)
2936 return;
2938 ctl_sys_last_event = (u_char)err;
2939 ctl_sys_num_events++;
2940 snprintf(statstr, NTP_MAXSTRLEN,
2941 "0.0.0.0 %04x %02x %s",
2942 ctlsysstatus(), err, eventstr(err));
2943 if (str != NULL) {
2944 len = strlen(statstr);
2945 snprintf(statstr + len, sizeof(statstr) - len,
2946 " %s", str);
2948 NLOG(NLOG_SYSEVENT)
2949 msyslog(LOG_INFO, statstr);
2950 } else {
2953 * Discard a peer report if the number of reports of
2954 * the same type exceeds the maximum for that peer.
2956 char *src;
2957 u_char errlast;
2959 errlast = (u_char)err & ~PEER_EVENT;
2960 if (peer->last_event == errlast)
2961 peer->num_events = 0;
2962 if (peer->num_events >= CTL_PEER_MAXEVENTS)
2963 return;
2965 peer->last_event = errlast;
2966 peer->num_events++;
2967 if (ISREFCLOCKADR(&peer->srcadr))
2968 src = refnumtoa(&peer->srcadr);
2969 else
2970 src = stoa(&peer->srcadr);
2972 snprintf(statstr, NTP_MAXSTRLEN,
2973 "%s %04x %02x %s", src,
2974 ctlpeerstatus(peer), err, eventstr(err));
2975 if (str != NULL) {
2976 len = strlen(statstr);
2977 snprintf(statstr + len, sizeof(statstr) - len,
2978 " %s", str);
2980 NLOG(NLOG_PEEREVENT)
2981 msyslog(LOG_INFO, statstr);
2983 record_proto_stats(statstr);
2984 #if DEBUG
2985 if (debug)
2986 printf("event at %lu %s\n", current_time, statstr);
2987 #endif
2990 * If no trappers, return.
2992 if (num_ctl_traps <= 0)
2993 return;
2996 * Set up the outgoing packet variables
2998 res_opcode = CTL_OP_ASYNCMSG;
2999 res_offset = 0;
3000 res_async = 1;
3001 res_authenticate = 0;
3002 datapt = rpkt.data;
3003 dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
3004 if (!(err & PEER_EVENT)) {
3005 rpkt.associd = 0;
3006 rpkt.status = htons(ctlsysstatus());
3009 * For now, put everything we know about system
3010 * variables. Don't send crypto strings.
3012 for (i = 1; i <= CS_MAXCODE; i++) {
3013 #ifdef OPENSSL
3014 if (i > CS_VARLIST)
3015 continue;
3016 #endif /* OPENSSL */
3017 ctl_putsys(i);
3019 } else {
3020 NTP_INSIST(peer != NULL);
3021 rpkt.associd = htons(peer->associd);
3022 rpkt.status = htons(ctlpeerstatus(peer));
3025 * Dump it all. Later, maybe less.
3027 for (i = 1; i <= CP_MAXCODE; i++) {
3028 #ifdef OPENSSL
3029 if (i > CP_VARLIST)
3030 continue;
3031 #endif /* OPENSSL */
3032 ctl_putpeer(i, peer);
3034 #ifdef REFCLOCK
3036 * for clock exception events: add clock variables to
3037 * reflect info on exception
3039 if (err == PEVNT_CLOCK) {
3040 struct refclockstat clock_stat;
3041 struct ctl_var *kv;
3043 clock_stat.kv_list = (struct ctl_var *)0;
3044 refclock_control(&peer->srcadr,
3045 (struct refclockstat *)0, &clock_stat);
3047 ctl_puthex("refclockstatus",
3048 ctlclkstatus(&clock_stat));
3050 for (i = 1; i <= CC_MAXCODE; i++)
3051 ctl_putclock(i, &clock_stat, 0);
3052 for (kv = clock_stat.kv_list; kv &&
3053 !(kv->flags & EOV); kv++)
3054 if (kv->flags & DEF)
3055 ctl_putdata(kv->text,
3056 strlen(kv->text), 0);
3057 free_varlist(clock_stat.kv_list);
3059 #endif /* REFCLOCK */
3063 * We're done, return.
3065 ctl_flushpkt(0);
3070 * ctl_clr_stats - clear stat counters
3072 void
3073 ctl_clr_stats(void)
3075 ctltimereset = current_time;
3076 numctlreq = 0;
3077 numctlbadpkts = 0;
3078 numctlresponses = 0;
3079 numctlfrags = 0;
3080 numctlerrors = 0;
3081 numctlfrags = 0;
3082 numctltooshort = 0;
3083 numctlinputresp = 0;
3084 numctlinputfrag = 0;
3085 numctlinputerr = 0;
3086 numctlbadoffset = 0;
3087 numctlbadversion = 0;
3088 numctldatatooshort = 0;
3089 numctlbadop = 0;
3090 numasyncmsgs = 0;
3093 static u_long
3094 count_var(
3095 struct ctl_var *k
3098 register u_long c;
3100 if (!k)
3101 return (0);
3103 c = 0;
3104 while (!(k++->flags & EOV))
3105 c++;
3106 return (c);
3109 char *
3110 add_var(
3111 struct ctl_var **kv,
3112 u_long size,
3113 u_short def
3116 register u_long c;
3117 register struct ctl_var *k;
3119 c = count_var(*kv);
3121 k = *kv;
3122 *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var));
3123 if (k) {
3124 memmove((char *)*kv, (char *)k,
3125 sizeof(struct ctl_var)*c);
3126 free((char *)k);
3128 (*kv)[c].code = (u_short) c;
3129 (*kv)[c].text = (char *)emalloc(size);
3130 (*kv)[c].flags = def;
3131 (*kv)[c+1].code = 0;
3132 (*kv)[c+1].text = (char *)0;
3133 (*kv)[c+1].flags = EOV;
3134 return (char *)(*kv)[c].text;
3137 void
3138 set_var(
3139 struct ctl_var **kv,
3140 const char *data,
3141 u_long size,
3142 u_short def
3145 register struct ctl_var *k;
3146 register const char *s;
3147 register const char *t;
3148 char *td;
3150 if (!data || !size)
3151 return;
3153 k = *kv;
3154 if (k != NULL) {
3155 while (!(k->flags & EOV)) {
3156 s = data;
3157 t = k->text;
3158 if (t) {
3159 while (*t != '=' && *s - *t == 0) {
3160 s++;
3161 t++;
3163 if (*s == *t && ((*t == '=') || !*t)) {
3164 free((void *)k->text);
3165 td = (char *)emalloc(size);
3166 memmove(td, data, size);
3167 k->text =td;
3168 k->flags = def;
3169 return;
3171 } else {
3172 td = (char *)emalloc(size);
3173 memmove(td, data, size);
3174 k->text = td;
3175 k->flags = def;
3176 return;
3178 k++;
3181 td = add_var(kv, size, def);
3182 memmove(td, data, size);
3185 void
3186 set_sys_var(
3187 const char *data,
3188 u_long size,
3189 u_short def
3192 set_var(&ext_sys_var, data, size, def);
3195 void
3196 free_varlist(
3197 struct ctl_var *kv
3200 struct ctl_var *k;
3201 if (kv) {
3202 for (k = kv; !(k->flags & EOV); k++)
3203 free((void *)k->text);
3204 free((void *)kv);