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