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