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