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