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