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