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