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