154359Sroberto/*
254359Sroberto * ntp_control.c - respond to control messages and send async traps
354359Sroberto */
475202Sphk
575202Sphk/*
675202Sphk * $FreeBSD$
775202Sphk */
875202Sphk
954359Sroberto#ifdef HAVE_CONFIG_H
1054359Sroberto#include <config.h>
1154359Sroberto#endif
1254359Sroberto
1354359Sroberto#include "ntpd.h"
1454359Sroberto#include "ntp_io.h"
1554359Sroberto#include "ntp_refclock.h"
1654359Sroberto#include "ntp_control.h"
17182007Sroberto#include "ntp_unixtime.h"
1854359Sroberto#include "ntp_stdlib.h"
1954359Sroberto
2082502Sroberto#include <stdio.h>
2182502Sroberto#include <ctype.h>
2282502Sroberto#include <signal.h>
2382502Sroberto
2482502Sroberto#include <netinet/in.h>
2582502Sroberto#include <arpa/inet.h>
2682502Sroberto
27276158Sdes#ifndef MIN
28276158Sdes#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
29276158Sdes#endif
30276158Sdes
3154359Sroberto/*
3254359Sroberto * Structure to hold request procedure information
3354359Sroberto */
3454359Sroberto#define NOAUTH	0
3554359Sroberto#define AUTH	1
3654359Sroberto
3754359Sroberto#define NO_REQUEST	(-1)
3854359Sroberto
3954359Srobertostruct ctl_proc {
4082502Sroberto	short control_code;		/* defined request code */
4182502Sroberto	u_short flags;			/* flags word */
4282502Sroberto	void (*handler) P((struct recvbuf *, int)); /* handle request */
4354359Sroberto};
4454359Sroberto
4554359Sroberto/*
4654359Sroberto * Only one flag.  Authentication required or not.
4754359Sroberto */
4854359Sroberto#define NOAUTH	0
4954359Sroberto#define AUTH	1
5054359Sroberto
5154359Sroberto/*
5254359Sroberto * Request processing routines
5354359Sroberto */
5454359Srobertostatic	void	ctl_error	P((int));
55132455Sroberto#ifdef REFCLOCK
5654359Srobertostatic	u_short ctlclkstatus	P((struct refclockstat *));
57132455Sroberto#endif
5854359Srobertostatic	void	ctl_flushpkt	P((int));
5954359Srobertostatic	void	ctl_putdata	P((const char *, unsigned int, int));
6082502Srobertostatic	void	ctl_putstr	P((const char *, const char *,
6182502Sroberto				    unsigned int));
6254359Srobertostatic	void	ctl_putdbl	P((const char *, double));
6382502Srobertostatic	void	ctl_putuint	P((const char *, u_long));
6454359Srobertostatic	void	ctl_puthex	P((const char *, u_long));
6554359Srobertostatic	void	ctl_putint	P((const char *, long));
6654359Srobertostatic	void	ctl_putts	P((const char *, l_fp *));
67132455Srobertostatic	void	ctl_putadr	P((const char *, u_int32, struct sockaddr_storage*));
6854359Srobertostatic	void	ctl_putid	P((const char *, char *));
6954359Srobertostatic	void	ctl_putarray	P((const char *, double *, int));
7054359Srobertostatic	void	ctl_putsys	P((int));
7182502Srobertostatic	void	ctl_putpeer	P((int, struct peer *));
72182007Sroberto#ifdef OPENSSL
73182007Srobertostatic	void	ctl_putfs	P((const char *, tstamp_t));
74182007Sroberto#endif
7554359Sroberto#ifdef REFCLOCK
7654359Srobertostatic	void	ctl_putclock	P((int, struct refclockstat *, int));
7754359Sroberto#endif	/* REFCLOCK */
7854359Srobertostatic	struct ctl_var *ctl_getitem P((struct ctl_var *, char **));
7982502Srobertostatic	u_long count_var	P((struct ctl_var *));
8054359Srobertostatic	void	control_unspec	P((struct recvbuf *, int));
8182502Srobertostatic	void	read_status	P((struct recvbuf *, int));
8254359Srobertostatic	void	read_variables	P((struct recvbuf *, int));
8354359Srobertostatic	void	write_variables P((struct recvbuf *, int));
8482502Srobertostatic	void	read_clock_status P((struct recvbuf *, int));
8582502Srobertostatic	void	write_clock_status P((struct recvbuf *, int));
8654359Srobertostatic	void	set_trap	P((struct recvbuf *, int));
8754359Srobertostatic	void	unset_trap	P((struct recvbuf *, int));
88132455Srobertostatic	struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *,
8982502Sroberto				    struct interface *));
9054359Sroberto
9154359Srobertostatic	struct ctl_proc control_codes[] = {
9254359Sroberto	{ CTL_OP_UNSPEC,	NOAUTH, control_unspec },
9354359Sroberto	{ CTL_OP_READSTAT,	NOAUTH, read_status },
9454359Sroberto	{ CTL_OP_READVAR,	NOAUTH, read_variables },
9554359Sroberto	{ CTL_OP_WRITEVAR,	AUTH,	write_variables },
9654359Sroberto	{ CTL_OP_READCLOCK,	NOAUTH, read_clock_status },
9754359Sroberto	{ CTL_OP_WRITECLOCK,	NOAUTH, write_clock_status },
9854359Sroberto	{ CTL_OP_SETTRAP,	NOAUTH, set_trap },
9954359Sroberto	{ CTL_OP_UNSETTRAP,	NOAUTH, unset_trap },
10054359Sroberto	{ NO_REQUEST,		0 }
10154359Sroberto};
10254359Sroberto
10354359Sroberto/*
10482502Sroberto * System variable values. The array can be indexed by the variable
10582502Sroberto * index to find the textual name.
10654359Sroberto */
10782502Srobertostatic struct ctl_var sys_var[] = {
10854359Sroberto	{ 0,		PADDING, "" },		/* 0 */
10954359Sroberto	{ CS_LEAP,	RW, "leap" },		/* 1 */
11054359Sroberto	{ CS_STRATUM,	RO, "stratum" },	/* 2 */
11154359Sroberto	{ CS_PRECISION, RO, "precision" },	/* 3 */
11254359Sroberto	{ CS_ROOTDELAY, RO, "rootdelay" },	/* 4 */
11354359Sroberto	{ CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */
11454359Sroberto	{ CS_REFID,	RO, "refid" },		/* 6 */
11554359Sroberto	{ CS_REFTIME,	RO, "reftime" },	/* 7 */
11654359Sroberto	{ CS_POLL,	RO, "poll" },		/* 8 */
11754359Sroberto	{ CS_PEERID,	RO, "peer" },		/* 9 */
11854359Sroberto	{ CS_STATE,	RO, "state" },		/* 10 */
11982502Sroberto	{ CS_OFFSET,	RO, "offset" },		/* 11 */
12054359Sroberto	{ CS_DRIFT,	RO, "frequency" },	/* 12 */
12182502Sroberto	{ CS_JITTER,	RO, "jitter" },		/* 13 */
122182007Sroberto	{ CS_ERROR,	RO, "noise" },		/* 14 */
123182007Sroberto	{ CS_CLOCK,	RO, "clock" },		/* 15 */
124182007Sroberto	{ CS_PROCESSOR, RO, "processor" },	/* 16 */
125182007Sroberto	{ CS_SYSTEM,	RO, "system" },		/* 17 */
126182007Sroberto	{ CS_VERSION,	RO, "version" },	/* 18 */
127182007Sroberto	{ CS_STABIL,	RO, "stability" },	/* 19 */
128182007Sroberto	{ CS_VARLIST,	RO, "sys_var_list" },	/* 20 */
129132455Sroberto#ifdef OPENSSL
130182007Sroberto	{ CS_FLAGS,	RO, "flags" },		/* 21 */
131182007Sroberto	{ CS_HOST,	RO, "hostname" },	/* 22 */
132182007Sroberto	{ CS_PUBLIC,	RO, "update" },		/* 23 */
133182007Sroberto	{ CS_CERTIF,	RO, "cert" },		/* 24 */
134182007Sroberto	{ CS_REVTIME,	RO, "expire" },		/* 25 */
135182007Sroberto	{ CS_LEAPTAB,	RO, "leapsec" },	/* 26 */
136182007Sroberto	{ CS_TAI,	RO, "tai" },		/* 27 */
137182007Sroberto	{ CS_DIGEST,	RO, "signature" },	/* 28 */
138182007Sroberto	{ CS_IDENT,	RO, "ident" },		/* 29 */
139182007Sroberto	{ CS_REVOKE,	RO, "expire" },		/* 30 */
140132455Sroberto#endif /* OPENSSL */
141182007Sroberto	{ 0,		EOV, "" }		/* 21/31 */
14254359Sroberto};
14354359Sroberto
14482502Srobertostatic struct ctl_var *ext_sys_var = (struct ctl_var *)0;
14554359Sroberto
14654359Sroberto/*
14782502Sroberto * System variables we print by default (in fuzzball order,
14882502Sroberto * more-or-less)
14954359Sroberto */
15054359Srobertostatic	u_char def_sys_var[] = {
15182502Sroberto	CS_VERSION,
15254359Sroberto	CS_PROCESSOR,
15354359Sroberto	CS_SYSTEM,
15454359Sroberto	CS_LEAP,
15554359Sroberto	CS_STRATUM,
15654359Sroberto	CS_PRECISION,
15754359Sroberto	CS_ROOTDELAY,
15854359Sroberto	CS_ROOTDISPERSION,
15954359Sroberto	CS_PEERID,
16054359Sroberto	CS_REFID,
16154359Sroberto	CS_REFTIME,
16254359Sroberto	CS_POLL,
16354359Sroberto	CS_CLOCK,
16454359Sroberto	CS_STATE,
16554359Sroberto	CS_OFFSET,
16654359Sroberto	CS_DRIFT,
16782502Sroberto	CS_JITTER,
168182007Sroberto	CS_ERROR,
16954359Sroberto	CS_STABIL,
170132455Sroberto#ifdef OPENSSL
171132455Sroberto	CS_HOST,
172132455Sroberto	CS_DIGEST,
17382502Sroberto	CS_FLAGS,
174132455Sroberto	CS_PUBLIC,
175182007Sroberto	CS_IDENT,
17682502Sroberto	CS_LEAPTAB,
177182007Sroberto	CS_TAI,
178132455Sroberto	CS_CERTIF,
179132455Sroberto#endif /* OPENSSL */
18054359Sroberto	0
18154359Sroberto};
18254359Sroberto
18354359Sroberto
18454359Sroberto/*
18554359Sroberto * Peer variable list
18654359Sroberto */
18782502Srobertostatic struct ctl_var peer_var[] = {
18882502Sroberto	{ 0,		PADDING, "" },		/* 0 */
18982502Sroberto	{ CP_CONFIG,	RO, "config" },		/* 1 */
19082502Sroberto	{ CP_AUTHENABLE, RO,	"authenable" },	/* 2 */
19182502Sroberto	{ CP_AUTHENTIC, RO, "authentic" }, 	/* 3 */
19282502Sroberto	{ CP_SRCADR,	RO, "srcadr" },		/* 4 */
19382502Sroberto	{ CP_SRCPORT,	RO, "srcport" },	/* 5 */
19482502Sroberto	{ CP_DSTADR,	RO, "dstadr" },		/* 6 */
19582502Sroberto	{ CP_DSTPORT,	RO, "dstport" },	/* 7 */
19682502Sroberto	{ CP_LEAP,	RO, "leap" },		/* 8 */
19782502Sroberto	{ CP_HMODE,	RO, "hmode" },		/* 9 */
19882502Sroberto	{ CP_STRATUM,	RO, "stratum" },	/* 10 */
19982502Sroberto	{ CP_PPOLL,	RO, "ppoll" },		/* 11 */
20082502Sroberto	{ CP_HPOLL,	RO, "hpoll" },		/* 12 */
20182502Sroberto	{ CP_PRECISION,	RO, "precision" },	/* 13 */
20282502Sroberto	{ CP_ROOTDELAY,	RO, "rootdelay" },	/* 14 */
20354359Sroberto	{ CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */
20482502Sroberto	{ CP_REFID,	RO, "refid" },		/* 16 */
20582502Sroberto	{ CP_REFTIME,	RO, "reftime" },	/* 17 */
20682502Sroberto	{ CP_ORG,	RO, "org" },		/* 18 */
20782502Sroberto	{ CP_REC,	RO, "rec" },		/* 19 */
20882502Sroberto	{ CP_XMT,	RO, "xmt" },		/* 20 */
20982502Sroberto	{ CP_REACH,	RO, "reach" },		/* 21 */
210182007Sroberto	{ CP_UNREACH,	RO, "unreach" },	/* 22 */
21182502Sroberto	{ CP_TIMER,	RO, "timer" },		/* 23 */
21282502Sroberto	{ CP_DELAY,	RO, "delay" },		/* 24 */
21382502Sroberto	{ CP_OFFSET,	RO, "offset" },		/* 25 */
21482502Sroberto	{ CP_JITTER,	RO, "jitter" },		/* 26 */
21582502Sroberto	{ CP_DISPERSION, RO, "dispersion" },	/* 27 */
21682502Sroberto	{ CP_KEYID,	RO, "keyid" },		/* 28 */
21782502Sroberto	{ CP_FILTDELAY,	RO, "filtdelay=" },	/* 29 */
21882502Sroberto	{ CP_FILTOFFSET, RO, "filtoffset=" },	/* 30 */
21982502Sroberto	{ CP_PMODE,	RO, "pmode" },		/* 31 */
22082502Sroberto	{ CP_RECEIVED,	RO, "received"},	/* 32 */
22182502Sroberto	{ CP_SENT,	RO, "sent" },		/* 33 */
22282502Sroberto	{ CP_FILTERROR,	RO, "filtdisp=" },	/* 34 */
22382502Sroberto	{ CP_FLASH,	RO, "flash" },		/* 35 */
22482502Sroberto	{ CP_TTL,	RO, "ttl" },		/* 36 */
225182007Sroberto	{ CP_VARLIST,	RO, "peer_var_list" },	/* 37 */
226132455Sroberto#ifdef OPENSSL
227182007Sroberto	{ CP_FLAGS,	RO, "flags" },		/* 38 */
228182007Sroberto	{ CP_HOST,	RO, "hostname" },	/* 39 */
229182007Sroberto	{ CP_VALID,	RO, "valid" },		/* 40 */
230132455Sroberto	{ CP_INITSEQ,	RO, "initsequence" },   /* 41 */
231132455Sroberto	{ CP_INITKEY,	RO, "initkey" },	/* 42 */
232132455Sroberto	{ CP_INITTSP,	RO, "timestamp" },	/* 43 */
233132455Sroberto	{ CP_DIGEST,	RO, "signature" },	/* 44 */
234182007Sroberto	{ CP_IDENT,	RO, "trust" },		/* 45 */
235132455Sroberto#endif /* OPENSSL */
236182007Sroberto	{ 0,		EOV, "" }		/* 38/46 */
23754359Sroberto};
23854359Sroberto
23954359Sroberto
24054359Sroberto/*
24154359Sroberto * Peer variables we print by default
24254359Sroberto */
24382502Srobertostatic u_char def_peer_var[] = {
24454359Sroberto	CP_SRCADR,
24554359Sroberto	CP_SRCPORT,
24654359Sroberto	CP_DSTADR,
24754359Sroberto	CP_DSTPORT,
24882502Sroberto	CP_LEAP,
24954359Sroberto	CP_STRATUM,
25054359Sroberto	CP_PRECISION,
25154359Sroberto	CP_ROOTDELAY,
25254359Sroberto	CP_ROOTDISPERSION,
25354359Sroberto	CP_REFID,
25454359Sroberto	CP_REACH,
255182007Sroberto	CP_UNREACH,
25654359Sroberto	CP_HMODE,
25754359Sroberto	CP_PMODE,
25854359Sroberto	CP_HPOLL,
25954359Sroberto	CP_PPOLL,
26054359Sroberto	CP_FLASH,
26182502Sroberto	CP_KEYID,
26282502Sroberto	CP_TTL,
26382502Sroberto	CP_OFFSET,
26482502Sroberto	CP_DELAY,
26582502Sroberto	CP_DISPERSION,
26682502Sroberto	CP_JITTER,
26782502Sroberto	CP_REFTIME,
26854359Sroberto	CP_ORG,
26954359Sroberto	CP_REC,
27054359Sroberto	CP_XMT,
27154359Sroberto	CP_FILTDELAY,
27254359Sroberto	CP_FILTOFFSET,
27354359Sroberto	CP_FILTERROR,
274132455Sroberto#ifdef OPENSSL
275132455Sroberto	CP_HOST,
276132455Sroberto	CP_DIGEST,
277182007Sroberto	CP_VALID,
27882502Sroberto	CP_FLAGS,
279132455Sroberto	CP_IDENT,
28082502Sroberto	CP_INITSEQ,
281132455Sroberto#endif /* OPENSSL */
28254359Sroberto	0
28354359Sroberto};
28454359Sroberto
28554359Sroberto
28654359Sroberto#ifdef REFCLOCK
28754359Sroberto/*
28854359Sroberto * Clock variable list
28954359Sroberto */
29082502Srobertostatic struct ctl_var clock_var[] = {
29182502Sroberto	{ 0,		PADDING, "" },		/* 0 */
29282502Sroberto	{ CC_TYPE,	RO, "type" },		/* 1 */
29382502Sroberto	{ CC_TIMECODE,	RO, "timecode" },	/* 2 */
29482502Sroberto	{ CC_POLL,	RO, "poll" },		/* 3 */
29582502Sroberto	{ CC_NOREPLY,	RO, "noreply" },	/* 4 */
29682502Sroberto	{ CC_BADFORMAT, RO, "badformat" },	/* 5 */
29782502Sroberto	{ CC_BADDATA,	RO, "baddata" },	/* 6 */
29882502Sroberto	{ CC_FUDGETIME1, RO, "fudgetime1" },	/* 7 */
29982502Sroberto	{ CC_FUDGETIME2, RO, "fudgetime2" },	/* 8 */
30082502Sroberto	{ CC_FUDGEVAL1, RO, "stratum" },	/* 9 */
30182502Sroberto	{ CC_FUDGEVAL2, RO, "refid" },		/* 10 */
30282502Sroberto	{ CC_FLAGS,	RO, "flags" },		/* 11 */
30382502Sroberto	{ CC_DEVICE,	RO, "device" },		/* 12 */
30482502Sroberto	{ CC_VARLIST,	RO, "clock_var_list" },	/* 13 */
30582502Sroberto	{ 0,		EOV, ""  }		/* 14 */
30654359Sroberto};
30754359Sroberto
30854359Sroberto
30954359Sroberto/*
31054359Sroberto * Clock variables printed by default
31154359Sroberto */
31282502Srobertostatic u_char def_clock_var[] = {
31354359Sroberto	CC_DEVICE,
31482502Sroberto	CC_TYPE,	/* won't be output if device = known */
31554359Sroberto	CC_TIMECODE,
31654359Sroberto	CC_POLL,
31754359Sroberto	CC_NOREPLY,
31854359Sroberto	CC_BADFORMAT,
31954359Sroberto	CC_BADDATA,
32054359Sroberto	CC_FUDGETIME1,
32154359Sroberto	CC_FUDGETIME2,
32254359Sroberto	CC_FUDGEVAL1,
32354359Sroberto	CC_FUDGEVAL2,
32454359Sroberto	CC_FLAGS,
32554359Sroberto	0
32654359Sroberto};
32754359Sroberto#endif
32854359Sroberto
32954359Sroberto
33054359Sroberto/*
33182502Sroberto * System and processor definitions.
33254359Sroberto */
33354359Sroberto#ifndef HAVE_UNAME
33454359Sroberto# ifndef STR_SYSTEM
33582502Sroberto#  define		STR_SYSTEM	"UNIX"
33654359Sroberto# endif
33754359Sroberto# ifndef STR_PROCESSOR
33882502Sroberto#	define		STR_PROCESSOR	"unknown"
33954359Sroberto# endif
34054359Sroberto
34154359Srobertostatic char str_system[] = STR_SYSTEM;
34254359Srobertostatic char str_processor[] = STR_PROCESSOR;
34354359Sroberto#else
34454359Sroberto# include <sys/utsname.h>
34554359Srobertostatic struct utsname utsnamebuf;
34654359Sroberto#endif /* HAVE_UNAME */
34754359Sroberto
34854359Sroberto/*
34982502Sroberto * Trap structures. We only allow a few of these, and send a copy of
35082502Sroberto * each async message to each live one. Traps time out after an hour, it
35182502Sroberto * is up to the trap receipient to keep resetting it to avoid being
35282502Sroberto * timed out.
35354359Sroberto */
35454359Sroberto/* ntp_request.c */
35554359Srobertostruct ctl_trap ctl_trap[CTL_MAXTRAPS];
35654359Srobertoint num_ctl_traps;
35754359Sroberto
35854359Sroberto/*
35954359Sroberto * Type bits, for ctlsettrap() call.
36054359Sroberto */
36154359Sroberto#define TRAP_TYPE_CONFIG	0	/* used by configuration code */
36254359Sroberto#define TRAP_TYPE_PRIO		1	/* priority trap */
36354359Sroberto#define TRAP_TYPE_NONPRIO	2	/* nonpriority trap */
36454359Sroberto
36554359Sroberto
36654359Sroberto/*
36754359Sroberto * List relating reference clock types to control message time sources.
36882502Sroberto * Index by the reference clock type. This list will only be used iff
36982502Sroberto * the reference clock driver doesn't set peer->sstclktype to something
37082502Sroberto * different than CTL_SST_TS_UNSPEC.
37154359Sroberto */
37254359Srobertostatic u_char clocktypes[] = {
37354359Sroberto	CTL_SST_TS_NTP, 	/* REFCLK_NONE (0) */
37454359Sroberto	CTL_SST_TS_LOCAL,	/* REFCLK_LOCALCLOCK (1) */
375182007Sroberto	CTL_SST_TS_UHF, 	/* deprecated REFCLK_GPS_TRAK (2) */
37654359Sroberto	CTL_SST_TS_HF,		/* REFCLK_WWV_PST (3) */
37754359Sroberto	CTL_SST_TS_LF,		/* REFCLK_WWVB_SPECTRACOM (4) */
37854359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_TRUETIME (5) */
379182007Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GOES_TRAK (6) IRIG_AUDIO? */
38054359Sroberto	CTL_SST_TS_HF,		/* REFCLK_CHU (7) */
38154359Sroberto	CTL_SST_TS_LF,		/* REFCLOCK_PARSE (default) (8) */
38254359Sroberto	CTL_SST_TS_LF,		/* REFCLK_GPS_MX4200 (9) */
38354359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GPS_AS2201 (10) */
38454359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GPS_ARBITER (11) */
38554359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_IRIG_TPRO (12) */
38654359Sroberto	CTL_SST_TS_ATOM,	/* REFCLK_ATOM_LEITCH (13) */
387182007Sroberto	CTL_SST_TS_LF,		/* deprecated REFCLK_MSF_EES (14) */
388182007Sroberto	CTL_SST_TS_NTP, 	/* not used (15) */
38954359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_IRIG_BANCOMM (16) */
39054359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GPS_DATU (17) */
39154359Sroberto	CTL_SST_TS_TELEPHONE,	/* REFCLK_NIST_ACTS (18) */
39254359Sroberto	CTL_SST_TS_HF,		/* REFCLK_WWV_HEATH (19) */
39354359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GPS_NMEA (20) */
39454359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GPS_VME (21) */
39554359Sroberto	CTL_SST_TS_ATOM,	/* REFCLK_ATOM_PPS (22) */
396182007Sroberto	CTL_SST_TS_NTP,		/* not used (23) */
397182007Sroberto	CTL_SST_TS_NTP,		/* not used (24) */
398182007Sroberto	CTL_SST_TS_NTP, 	/* not used (25) */
39954359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_GPS_HP (26) */
40054359Sroberto	CTL_SST_TS_TELEPHONE,	/* REFCLK_ARCRON_MSF (27) */
40154359Sroberto	CTL_SST_TS_TELEPHONE,	/* REFCLK_SHM (28) */
40254359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_PALISADE (29) */
40354359Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_ONCORE (30) */
40454359Sroberto	CTL_SST_TS_UHF,		/* REFCLK_JUPITER (31) */
40554359Sroberto	CTL_SST_TS_LF,		/* REFCLK_CHRONOLOG (32) */
406182007Sroberto	CTL_SST_TS_LF,		/* REFCLK_DUMBCLOCK (33) */
407182007Sroberto	CTL_SST_TS_LF,		/* REFCLK_ULINK (34) */
40856746Sroberto	CTL_SST_TS_LF,		/* REFCLK_PCF (35) */
40982502Sroberto	CTL_SST_TS_LF,		/* REFCLK_WWV (36) */
41056746Sroberto	CTL_SST_TS_LF,		/* REFCLK_FG (37) */
41182502Sroberto	CTL_SST_TS_UHF, 	/* REFCLK_HOPF_SERIAL (38) */
41282502Sroberto	CTL_SST_TS_UHF,		/* REFCLK_HOPF_PCI (39) */
413106166Sroberto	CTL_SST_TS_LF,		/* REFCLK_JJY (40) */
414106166Sroberto	CTL_SST_TS_UHF,		/* REFCLK_TT560 (41) */
415106166Sroberto	CTL_SST_TS_UHF,		/* REFCLK_ZYFER (42) */
416106427Sroberto	CTL_SST_TS_UHF,		/* REFCLK_RIPENCC (43) */
417106427Sroberto	CTL_SST_TS_UHF,		/* REFCLK_NEOCLOCK4X (44) */
41854359Sroberto};
41954359Sroberto
42054359Sroberto
42154359Sroberto/*
42254359Sroberto * Keyid used for authenticating write requests.
42354359Sroberto */
42482502Srobertokeyid_t ctl_auth_keyid;
42554359Sroberto
42654359Sroberto/*
42754359Sroberto * We keep track of the last error reported by the system internally
42854359Sroberto */
42954359Srobertostatic	u_char ctl_sys_last_event;
43054359Srobertostatic	u_char ctl_sys_num_events;
43154359Sroberto
43254359Sroberto
43354359Sroberto/*
43454359Sroberto * Statistic counters to keep track of requests and responses.
43554359Sroberto */
43654359Srobertou_long ctltimereset;		/* time stats reset */
43754359Srobertou_long numctlreq;		/* number of requests we've received */
43854359Srobertou_long numctlbadpkts;		/* number of bad control packets */
43954359Srobertou_long numctlresponses; 	/* number of resp packets sent with data */
44082502Srobertou_long numctlfrags; 		/* number of fragments sent */
44154359Srobertou_long numctlerrors;		/* number of error responses sent */
44254359Srobertou_long numctltooshort;		/* number of too short input packets */
44354359Srobertou_long numctlinputresp; 	/* number of responses on input */
44454359Srobertou_long numctlinputfrag; 	/* number of fragments on input */
44554359Srobertou_long numctlinputerr;		/* number of input pkts with err bit set */
44654359Srobertou_long numctlbadoffset; 	/* number of input pkts with nonzero offset */
44754359Srobertou_long numctlbadversion;	/* number of input pkts with unknown version */
44854359Srobertou_long numctldatatooshort;	/* data too short for count */
44982502Srobertou_long numctlbadop; 		/* bad op code found in packet */
45054359Srobertou_long numasyncmsgs;		/* number of async messages we've sent */
45154359Sroberto
45254359Sroberto/*
45382502Sroberto * Response packet used by these routines. Also some state information
45454359Sroberto * so that we can handle packet formatting within a common set of
45554359Sroberto * subroutines.  Note we try to enter data in place whenever possible,
45654359Sroberto * but the need to set the more bit correctly means we occasionally
45754359Sroberto * use the extra buffer and copy.
45854359Sroberto */
45954359Srobertostatic struct ntp_control rpkt;
46054359Srobertostatic u_char	res_version;
46154359Srobertostatic u_char	res_opcode;
46282502Srobertostatic associd_t res_associd;
46354359Srobertostatic int	res_offset;
46454359Srobertostatic u_char * datapt;
46554359Srobertostatic u_char * dataend;
46654359Srobertostatic int	datalinelen;
46754359Srobertostatic int	datanotbinflag;
468132455Srobertostatic struct sockaddr_storage *rmt_addr;
46954359Srobertostatic struct interface *lcl_inter;
47054359Sroberto
47154359Srobertostatic u_char	res_authenticate;
47254359Srobertostatic u_char	res_authokay;
47382502Srobertostatic keyid_t	res_keyid;
47454359Sroberto
47554359Sroberto#define MAXDATALINELEN	(72)
47654359Sroberto
47754359Srobertostatic u_char	res_async;	/* set to 1 if this is async trap response */
47854359Sroberto
47954359Sroberto/*
48054359Sroberto * Pointers for saving state when decoding request packets
48154359Sroberto */
48254359Srobertostatic	char *reqpt;
48354359Srobertostatic	char *reqend;
48454359Sroberto
48554359Sroberto/*
48654359Sroberto * init_control - initialize request data
48754359Sroberto */
48854359Srobertovoid
48954359Srobertoinit_control(void)
49054359Sroberto{
49154359Sroberto	int i;
49254359Sroberto
49354359Sroberto#ifdef HAVE_UNAME
49454359Sroberto	uname(&utsnamebuf);
49554359Sroberto#endif /* HAVE_UNAME */
49654359Sroberto
49754359Sroberto	ctl_clr_stats();
49854359Sroberto
49954359Sroberto	ctl_auth_keyid = 0;
50054359Sroberto	ctl_sys_last_event = EVNT_UNSPEC;
50154359Sroberto	ctl_sys_num_events = 0;
50254359Sroberto
50354359Sroberto	num_ctl_traps = 0;
50454359Sroberto	for (i = 0; i < CTL_MAXTRAPS; i++)
50554359Sroberto		ctl_trap[i].tr_flags = 0;
50654359Sroberto}
50754359Sroberto
50854359Sroberto
50954359Sroberto/*
51054359Sroberto * ctl_error - send an error response for the current request
51154359Sroberto */
51254359Srobertostatic void
51354359Srobertoctl_error(
51454359Sroberto	int errcode
51554359Sroberto	)
51654359Sroberto{
51754359Sroberto#ifdef DEBUG
51854359Sroberto	if (debug >= 4)
51954359Sroberto		printf("sending control error %d\n", errcode);
52054359Sroberto#endif
52154359Sroberto	/*
52282502Sroberto	 * Fill in the fields. We assume rpkt.sequence and rpkt.associd
52354359Sroberto	 * have already been filled in.
52454359Sroberto	 */
52582502Sroberto	rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode &
52682502Sroberto	    CTL_OP_MASK));
52754359Sroberto	rpkt.status = htons((u_short) ((errcode<<8) & 0xff00));
52854359Sroberto	rpkt.count = 0;
52954359Sroberto
53054359Sroberto	/*
53154359Sroberto	 * send packet and bump counters
53254359Sroberto	 */
53354359Sroberto	if (res_authenticate && sys_authenticate) {
53454359Sroberto		int maclen;
53554359Sroberto
53682502Sroberto		*(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) =
53782502Sroberto		    htonl(res_keyid);
53854359Sroberto		maclen = authencrypt(res_keyid, (u_int32 *)&rpkt,
53982502Sroberto		    CTL_HEADER_LEN);
54054359Sroberto		sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
54182502Sroberto		    CTL_HEADER_LEN + maclen);
54254359Sroberto	} else {
54354359Sroberto		sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
54482502Sroberto		    CTL_HEADER_LEN);
54554359Sroberto	}
54654359Sroberto	numctlerrors++;
54754359Sroberto}
54854359Sroberto
54954359Sroberto
55054359Sroberto/*
55154359Sroberto * process_control - process an incoming control message
55254359Sroberto */
55354359Srobertovoid
55454359Srobertoprocess_control(
55554359Sroberto	struct recvbuf *rbufp,
55654359Sroberto	int restrict_mask
55754359Sroberto	)
55854359Sroberto{
55954359Sroberto	register struct ntp_control *pkt;
56054359Sroberto	register int req_count;
56154359Sroberto	register int req_data;
56254359Sroberto	register struct ctl_proc *cc;
56354359Sroberto	int properlen;
56454359Sroberto	int maclen;
56554359Sroberto
56654359Sroberto#ifdef DEBUG
56782502Sroberto	if (debug > 2)
56854359Sroberto		printf("in process_control()\n");
56954359Sroberto#endif
57054359Sroberto
57154359Sroberto	/*
57254359Sroberto	 * Save the addresses for error responses
57354359Sroberto	 */
57454359Sroberto	numctlreq++;
57554359Sroberto	rmt_addr = &rbufp->recv_srcadr;
57654359Sroberto	lcl_inter = rbufp->dstadr;
57754359Sroberto	pkt = (struct ntp_control *)&rbufp->recv_pkt;
57854359Sroberto
57954359Sroberto	/*
58054359Sroberto	 * If the length is less than required for the header, or
58154359Sroberto	 * it is a response or a fragment, ignore this.
58254359Sroberto	 */
58354359Sroberto	if (rbufp->recv_length < CTL_HEADER_LEN
58482502Sroberto	    || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR)
58582502Sroberto	    || pkt->offset != 0) {
58654359Sroberto#ifdef DEBUG
58754359Sroberto		if (debug)
58854359Sroberto			printf("invalid format in control packet\n");
58954359Sroberto#endif
59054359Sroberto		if (rbufp->recv_length < CTL_HEADER_LEN)
59154359Sroberto			numctltooshort++;
59254359Sroberto		if (pkt->r_m_e_op & CTL_RESPONSE)
59354359Sroberto			numctlinputresp++;
59454359Sroberto		if (pkt->r_m_e_op & CTL_MORE)
59554359Sroberto			numctlinputfrag++;
59654359Sroberto		if (pkt->r_m_e_op & CTL_ERROR)
59754359Sroberto			numctlinputerr++;
59854359Sroberto		if (pkt->offset != 0)
59954359Sroberto			numctlbadoffset++;
60054359Sroberto		return;
60154359Sroberto	}
60254359Sroberto	res_version = PKT_VERSION(pkt->li_vn_mode);
60354359Sroberto	if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {
60454359Sroberto#ifdef DEBUG
60554359Sroberto		if (debug)
60654359Sroberto			printf("unknown version %d in control packet\n",
60754359Sroberto			   res_version);
60854359Sroberto#endif
60954359Sroberto		numctlbadversion++;
61054359Sroberto		return;
61154359Sroberto	}
61254359Sroberto
61354359Sroberto	/*
61482502Sroberto	 * Pull enough data from the packet to make intelligent
61582502Sroberto	 * responses
61654359Sroberto	 */
61782502Sroberto	rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version,
61882502Sroberto	    MODE_CONTROL);
61954359Sroberto	res_opcode = pkt->r_m_e_op;
62054359Sroberto	rpkt.sequence = pkt->sequence;
62154359Sroberto	rpkt.associd = pkt->associd;
62254359Sroberto	rpkt.status = 0;
62354359Sroberto	res_offset = 0;
62454359Sroberto	res_associd = htons(pkt->associd);
62554359Sroberto	res_async = 0;
62654359Sroberto	res_authenticate = 0;
62754359Sroberto	res_keyid = 0;
62854359Sroberto	res_authokay = 0;
62954359Sroberto	req_count = (int)htons(pkt->count);
63054359Sroberto	datanotbinflag = 0;
63154359Sroberto	datalinelen = 0;
63254359Sroberto	datapt = rpkt.data;
63354359Sroberto	dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
63454359Sroberto
63554359Sroberto	/*
63682502Sroberto	 * We're set up now. Make sure we've got at least enough
63782502Sroberto	 * incoming data space to match the count.
63854359Sroberto	 */
63954359Sroberto	req_data = rbufp->recv_length - CTL_HEADER_LEN;
64054359Sroberto	if (req_data < req_count || rbufp->recv_length & 0x3) {
64154359Sroberto		ctl_error(CERR_BADFMT);
64254359Sroberto		numctldatatooshort++;
64354359Sroberto		return;
64454359Sroberto	}
64554359Sroberto
64654359Sroberto	properlen = req_count + CTL_HEADER_LEN;
64754359Sroberto#ifdef DEBUG
64882502Sroberto	if (debug > 2 && (rbufp->recv_length & 0x3) != 0)
64982502Sroberto		printf("Packet length %d unrounded\n",
65082502Sroberto		    rbufp->recv_length);
65154359Sroberto#endif
65254359Sroberto	/* round up proper len to a 8 octet boundary */
65354359Sroberto
65454359Sroberto	properlen = (properlen + 7) & ~7;
65554359Sroberto	maclen = rbufp->recv_length - properlen;
65654359Sroberto	if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 &&
65782502Sroberto	    maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN &&
65882502Sroberto	    sys_authenticate) {
65954359Sroberto		res_authenticate = 1;
66082502Sroberto		res_keyid = ntohl(*(u_int32 *)((u_char *)pkt +
66182502Sroberto		    properlen));
66254359Sroberto
66354359Sroberto#ifdef DEBUG
66482502Sroberto		if (debug > 2)
66554359Sroberto			printf(
66682502Sroberto			    "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
66782502Sroberto			    rbufp->recv_length, properlen, res_keyid, maclen);
66854359Sroberto#endif
66954359Sroberto		if (!authistrusted(res_keyid)) {
67054359Sroberto#ifdef DEBUG
67182502Sroberto			if (debug > 2)
67282502Sroberto				printf("invalid keyid %08x\n",
67382502Sroberto				    res_keyid);
67454359Sroberto#endif
67554359Sroberto		} else if (authdecrypt(res_keyid, (u_int32 *)pkt,
67682502Sroberto		    rbufp->recv_length - maclen, maclen)) {
67754359Sroberto#ifdef DEBUG
67882502Sroberto			if (debug > 2)
67954359Sroberto				printf("authenticated okay\n");
68054359Sroberto#endif
68154359Sroberto			res_authokay = 1;
68254359Sroberto		} else {
68354359Sroberto#ifdef DEBUG
68482502Sroberto			if (debug > 2)
68554359Sroberto				printf("authentication failed\n");
68654359Sroberto#endif
68754359Sroberto			res_keyid = 0;
68854359Sroberto		}
68954359Sroberto	}
69054359Sroberto
69154359Sroberto	/*
69254359Sroberto	 * Set up translate pointers
69354359Sroberto	 */
69454359Sroberto	reqpt = (char *)pkt->data;
69554359Sroberto	reqend = reqpt + req_count;
69654359Sroberto
69754359Sroberto	/*
69854359Sroberto	 * Look for the opcode processor
69954359Sroberto	 */
70054359Sroberto	for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) {
70154359Sroberto		if (cc->control_code == res_opcode) {
70254359Sroberto#ifdef DEBUG
70382502Sroberto			if (debug > 2)
70454359Sroberto				printf("opcode %d, found command handler\n",
70582502Sroberto				    res_opcode);
70654359Sroberto#endif
70782502Sroberto			if (cc->flags == AUTH && (!res_authokay ||
70882502Sroberto			    res_keyid != ctl_auth_keyid)) {
70954359Sroberto				ctl_error(CERR_PERMISSION);
71054359Sroberto				return;
71154359Sroberto			}
71254359Sroberto			(cc->handler)(rbufp, restrict_mask);
71354359Sroberto			return;
71454359Sroberto		}
71554359Sroberto	}
71654359Sroberto
71754359Sroberto	/*
71854359Sroberto	 * Can't find this one, return an error.
71954359Sroberto	 */
72054359Sroberto	numctlbadop++;
72154359Sroberto	ctl_error(CERR_BADOP);
72254359Sroberto	return;
72354359Sroberto}
72454359Sroberto
72554359Sroberto
72654359Sroberto/*
72754359Sroberto * ctlpeerstatus - return a status word for this peer
72854359Sroberto */
72954359Srobertou_short
73054359Srobertoctlpeerstatus(
73154359Sroberto	register struct peer *peer
73254359Sroberto	)
73354359Sroberto{
73454359Sroberto	register u_short status;
73554359Sroberto
73654359Sroberto	status = peer->status;
73754359Sroberto	if (peer->flags & FLAG_CONFIG)
73854359Sroberto		status |= CTL_PST_CONFIG;
73954359Sroberto	if (peer->flags & FLAG_AUTHENABLE)
74054359Sroberto		status |= CTL_PST_AUTHENABLE;
74154359Sroberto	if (peer->flags & FLAG_AUTHENTIC)
74254359Sroberto		status |= CTL_PST_AUTHENTIC;
74354359Sroberto	if (peer->reach != 0)
74454359Sroberto		status |= CTL_PST_REACH;
74554359Sroberto	return (u_short)CTL_PEER_STATUS(status, peer->num_events,
74682502Sroberto	    peer->last_event);
74754359Sroberto}
74854359Sroberto
74954359Sroberto
75054359Sroberto/*
75154359Sroberto * ctlclkstatus - return a status word for this clock
75254359Sroberto */
753132455Sroberto#ifdef REFCLOCK
75454359Srobertostatic u_short
75554359Srobertoctlclkstatus(
75654359Sroberto	struct refclockstat *this_clock
75754359Sroberto	)
75854359Sroberto{
759132455Sroberto	return ((u_short)(((this_clock->currentstatus) << 8) |
760132455Sroberto	    (this_clock->lastevent)));
76154359Sroberto}
762132455Sroberto#endif
76354359Sroberto
76454359Sroberto
76554359Sroberto/*
76654359Sroberto * ctlsysstatus - return the system status word
76754359Sroberto */
76854359Srobertou_short
76954359Srobertoctlsysstatus(void)
77054359Sroberto{
77154359Sroberto	register u_char this_clock;
77254359Sroberto
77354359Sroberto	this_clock = CTL_SST_TS_UNSPEC;
774182007Sroberto#ifdef REFCLOCK
77554359Sroberto	if (sys_peer != 0) {
77654359Sroberto		if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
77754359Sroberto			this_clock = sys_peer->sstclktype;
77854359Sroberto			if (pps_control)
77954359Sroberto				this_clock |= CTL_SST_TS_PPS;
78054359Sroberto		} else {
78154359Sroberto			if (sys_peer->refclktype < sizeof(clocktypes))
78282502Sroberto				this_clock =
78382502Sroberto				    clocktypes[sys_peer->refclktype];
78454359Sroberto			if (pps_control)
78554359Sroberto				this_clock |= CTL_SST_TS_PPS;
78654359Sroberto		}
78754359Sroberto	}
788182007Sroberto#endif /* REFCLOCK */
78954359Sroberto	return (u_short)CTL_SYS_STATUS(sys_leap, this_clock,
79082502Sroberto	    ctl_sys_num_events, ctl_sys_last_event);
79154359Sroberto}
79254359Sroberto
79354359Sroberto
79454359Sroberto/*
79554359Sroberto * ctl_flushpkt - write out the current packet and prepare
79654359Sroberto *		  another if necessary.
79754359Sroberto */
79854359Srobertostatic void
79954359Srobertoctl_flushpkt(
80054359Sroberto	int more
80154359Sroberto	)
80254359Sroberto{
80354359Sroberto	int dlen;
80454359Sroberto	int sendlen;
80554359Sroberto
80654359Sroberto	if (!more && datanotbinflag) {
80754359Sroberto		/*
80854359Sroberto		 * Big hack, output a trailing \r\n
80954359Sroberto		 */
81054359Sroberto		*datapt++ = '\r';
81154359Sroberto		*datapt++ = '\n';
81254359Sroberto	}
81354359Sroberto	dlen = datapt - (u_char *)rpkt.data;
81454359Sroberto	sendlen = dlen + CTL_HEADER_LEN;
81554359Sroberto
81654359Sroberto	/*
81754359Sroberto	 * Pad to a multiple of 32 bits
81854359Sroberto	 */
81954359Sroberto	while (sendlen & 0x3) {
82054359Sroberto		*datapt++ = '\0';
82154359Sroberto		sendlen++;
82254359Sroberto	}
82354359Sroberto
82454359Sroberto	/*
82554359Sroberto	 * Fill in the packet with the current info
82654359Sroberto	 */
82782502Sroberto	rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode &
82882502Sroberto	    CTL_OP_MASK));
82954359Sroberto	rpkt.count = htons((u_short) dlen);
83054359Sroberto	rpkt.offset = htons( (u_short) res_offset);
83154359Sroberto	if (res_async) {
83254359Sroberto		register int i;
83354359Sroberto
83454359Sroberto		for (i = 0; i < CTL_MAXTRAPS; i++) {
83554359Sroberto			if (ctl_trap[i].tr_flags & TRAP_INUSE) {
83682502Sroberto				rpkt.li_vn_mode =
83782502Sroberto				    PKT_LI_VN_MODE(sys_leap,
83882502Sroberto				    ctl_trap[i].tr_version,
83982502Sroberto				    MODE_CONTROL);
84082502Sroberto				rpkt.sequence =
84182502Sroberto				    htons(ctl_trap[i].tr_sequence);
84254359Sroberto				sendpkt(&ctl_trap[i].tr_addr,
84382502Sroberto					ctl_trap[i].tr_localaddr, -4,
84454359Sroberto					(struct pkt *)&rpkt, sendlen);
84554359Sroberto				if (!more)
84654359Sroberto					ctl_trap[i].tr_sequence++;
84754359Sroberto				numasyncmsgs++;
84854359Sroberto			}
84954359Sroberto		}
85054359Sroberto	} else {
85154359Sroberto		if (res_authenticate && sys_authenticate) {
85254359Sroberto			int maclen;
85354359Sroberto			int totlen = sendlen;
85482502Sroberto			keyid_t keyid = htonl(res_keyid);
85554359Sroberto
85654359Sroberto			/*
85782502Sroberto			 * If we are going to authenticate, then there
85882502Sroberto			 * is an additional requirement that the MAC
85982502Sroberto			 * begin on a 64 bit boundary.
86054359Sroberto			 */
86154359Sroberto			while (totlen & 7) {
86254359Sroberto				*datapt++ = '\0';
86354359Sroberto				totlen++;
86454359Sroberto			}
86554359Sroberto			memcpy(datapt, &keyid, sizeof keyid);
86682502Sroberto			maclen = authencrypt(res_keyid,
86782502Sroberto			    (u_int32 *)&rpkt, totlen);
86882502Sroberto			sendpkt(rmt_addr, lcl_inter, -5,
86982502Sroberto			    (struct pkt *)&rpkt, totlen + maclen);
87054359Sroberto		} else {
87182502Sroberto			sendpkt(rmt_addr, lcl_inter, -6,
87282502Sroberto			    (struct pkt *)&rpkt, sendlen);
87354359Sroberto		}
87454359Sroberto		if (more)
87554359Sroberto			numctlfrags++;
87654359Sroberto		else
87754359Sroberto			numctlresponses++;
87854359Sroberto	}
87954359Sroberto
88054359Sroberto	/*
88154359Sroberto	 * Set us up for another go around.
88254359Sroberto	 */
88354359Sroberto	res_offset += dlen;
88454359Sroberto	datapt = (u_char *)rpkt.data;
88554359Sroberto}
88654359Sroberto
88754359Sroberto
88854359Sroberto/*
88982502Sroberto * ctl_putdata - write data into the packet, fragmenting and starting
89082502Sroberto * another if this one is full.
89154359Sroberto */
89254359Srobertostatic void
89354359Srobertoctl_putdata(
89454359Sroberto	const char *dp,
89554359Sroberto	unsigned int dlen,
89654359Sroberto	int bin 		/* set to 1 when data is binary */
89754359Sroberto	)
89854359Sroberto{
89954359Sroberto	int overhead;
900276158Sdes	unsigned int currentlen;
90154359Sroberto
90254359Sroberto	overhead = 0;
90354359Sroberto	if (!bin) {
90454359Sroberto		datanotbinflag = 1;
90554359Sroberto		overhead = 3;
90654359Sroberto		if (datapt != rpkt.data) {
90754359Sroberto			*datapt++ = ',';
90854359Sroberto			datalinelen++;
90982502Sroberto			if ((dlen + datalinelen + 1) >= MAXDATALINELEN)
91082502Sroberto			    {
91154359Sroberto				*datapt++ = '\r';
91254359Sroberto				*datapt++ = '\n';
91354359Sroberto				datalinelen = 0;
91454359Sroberto			} else {
91554359Sroberto				*datapt++ = ' ';
91654359Sroberto				datalinelen++;
91754359Sroberto			}
91854359Sroberto		}
91954359Sroberto	}
92054359Sroberto
92154359Sroberto	/*
92254359Sroberto	 * Save room for trailing junk
92354359Sroberto	 */
924276158Sdes	while (dlen + overhead + datapt > dataend) {
92554359Sroberto		/*
92654359Sroberto		 * Not enough room in this one, flush it out.
92754359Sroberto		 */
928276158Sdes		currentlen = MIN(dlen, dataend - datapt);
929276158Sdes
930276158Sdes		memcpy(datapt, dp, currentlen);
931276158Sdes
932276158Sdes		datapt += currentlen;
933276158Sdes		dp += currentlen;
934276158Sdes		dlen -= currentlen;
935276158Sdes		datalinelen += currentlen;
936276158Sdes
93754359Sroberto		ctl_flushpkt(CTL_MORE);
93854359Sroberto	}
939276158Sdes
94054359Sroberto	memmove((char *)datapt, dp, (unsigned)dlen);
94154359Sroberto	datapt += dlen;
94254359Sroberto	datalinelen += dlen;
94354359Sroberto}
94454359Sroberto
94554359Sroberto
94654359Sroberto/*
94754359Sroberto * ctl_putstr - write a tagged string into the response packet
94854359Sroberto */
94954359Srobertostatic void
95054359Srobertoctl_putstr(
95154359Sroberto	const char *tag,
95254359Sroberto	const char *data,
95354359Sroberto	unsigned int len
95454359Sroberto	)
95554359Sroberto{
95654359Sroberto	register char *cp;
95754359Sroberto	register const char *cq;
95854359Sroberto	char buffer[400];
95954359Sroberto
96054359Sroberto	cp = buffer;
96154359Sroberto	cq = tag;
96254359Sroberto	while (*cq != '\0')
96354359Sroberto		*cp++ = *cq++;
96454359Sroberto	if (len > 0) {
96554359Sroberto		*cp++ = '=';
96654359Sroberto		*cp++ = '"';
96754359Sroberto		if (len > (int) (sizeof(buffer) - (cp - buffer) - 1))
96854359Sroberto			len = sizeof(buffer) - (cp - buffer) - 1;
96954359Sroberto		memmove(cp, data, (unsigned)len);
97054359Sroberto		cp += len;
97154359Sroberto		*cp++ = '"';
97254359Sroberto	}
97354359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
97454359Sroberto}
97554359Sroberto
97654359Sroberto
97754359Sroberto/*
97854359Sroberto * ctl_putdbl - write a tagged, signed double into the response packet
97954359Sroberto */
98054359Srobertostatic void
98154359Srobertoctl_putdbl(
98254359Sroberto	const char *tag,
98354359Sroberto	double ts
98454359Sroberto	)
98554359Sroberto{
98654359Sroberto	register char *cp;
98754359Sroberto	register const char *cq;
98854359Sroberto	char buffer[200];
98954359Sroberto
99054359Sroberto	cp = buffer;
99154359Sroberto	cq = tag;
99254359Sroberto	while (*cq != '\0')
99354359Sroberto		*cp++ = *cq++;
99454359Sroberto	*cp++ = '=';
99554359Sroberto	(void)sprintf(cp, "%.3f", ts);
99654359Sroberto	while (*cp != '\0')
99754359Sroberto		cp++;
99854359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
99954359Sroberto}
100054359Sroberto
100154359Sroberto/*
100254359Sroberto * ctl_putuint - write a tagged unsigned integer into the response
100354359Sroberto */
100454359Srobertostatic void
100554359Srobertoctl_putuint(
100654359Sroberto	const char *tag,
100754359Sroberto	u_long uval
100854359Sroberto	)
100954359Sroberto{
101054359Sroberto	register char *cp;
101154359Sroberto	register const char *cq;
101254359Sroberto	char buffer[200];
101354359Sroberto
101454359Sroberto	cp = buffer;
101554359Sroberto	cq = tag;
101654359Sroberto	while (*cq != '\0')
101754359Sroberto		*cp++ = *cq++;
101854359Sroberto
101954359Sroberto	*cp++ = '=';
102054359Sroberto	(void) sprintf(cp, "%lu", uval);
102154359Sroberto	while (*cp != '\0')
102254359Sroberto		cp++;
102354359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
102454359Sroberto}
102554359Sroberto
1026182007Sroberto/*
1027182007Sroberto * ctl_putfs - write a decoded filestamp into the response
1028182007Sroberto */
1029182007Sroberto#ifdef OPENSSL
1030182007Srobertostatic void
1031182007Srobertoctl_putfs(
1032182007Sroberto	const char *tag,
1033182007Sroberto	tstamp_t uval
1034182007Sroberto	)
1035182007Sroberto{
1036182007Sroberto	register char *cp;
1037182007Sroberto	register const char *cq;
1038182007Sroberto	char buffer[200];
1039182007Sroberto	struct tm *tm = NULL;
1040182007Sroberto	time_t fstamp;
104154359Sroberto
1042182007Sroberto	cp = buffer;
1043182007Sroberto	cq = tag;
1044182007Sroberto	while (*cq != '\0')
1045182007Sroberto		*cp++ = *cq++;
1046182007Sroberto
1047182007Sroberto	*cp++ = '=';
1048182007Sroberto	fstamp = uval - JAN_1970;
1049182007Sroberto	tm = gmtime(&fstamp);
1050182007Sroberto	if (tm == NULL)
1051182007Sroberto		return;
1052182007Sroberto
1053182007Sroberto	sprintf(cp, "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
1054182007Sroberto	    tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
1055182007Sroberto	while (*cp != '\0')
1056182007Sroberto		cp++;
1057182007Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
1058182007Sroberto}
1059182007Sroberto#endif
1060182007Sroberto
1061182007Sroberto
106254359Sroberto/*
106354359Sroberto * ctl_puthex - write a tagged unsigned integer, in hex, into the response
106454359Sroberto */
106554359Srobertostatic void
106654359Srobertoctl_puthex(
106754359Sroberto	const char *tag,
106854359Sroberto	u_long uval
106954359Sroberto	)
107054359Sroberto{
107154359Sroberto	register char *cp;
107254359Sroberto	register const char *cq;
107354359Sroberto	char buffer[200];
107454359Sroberto
107554359Sroberto	cp = buffer;
107654359Sroberto	cq = tag;
107754359Sroberto	while (*cq != '\0')
107854359Sroberto		*cp++ = *cq++;
107954359Sroberto
108054359Sroberto	*cp++ = '=';
108154359Sroberto	(void) sprintf(cp, "0x%lx", uval);
108254359Sroberto	while (*cp != '\0')
108354359Sroberto		cp++;
108454359Sroberto	ctl_putdata(buffer,(unsigned)( cp - buffer ), 0);
108554359Sroberto}
108654359Sroberto
108754359Sroberto
108854359Sroberto/*
108954359Sroberto * ctl_putint - write a tagged signed integer into the response
109054359Sroberto */
109154359Srobertostatic void
109254359Srobertoctl_putint(
109354359Sroberto	const char *tag,
109454359Sroberto	long ival
109554359Sroberto	)
109654359Sroberto{
109754359Sroberto	register char *cp;
109854359Sroberto	register const char *cq;
109954359Sroberto	char buffer[200];
110054359Sroberto
110154359Sroberto	cp = buffer;
110254359Sroberto	cq = tag;
110354359Sroberto	while (*cq != '\0')
110454359Sroberto		*cp++ = *cq++;
110554359Sroberto
110654359Sroberto	*cp++ = '=';
110754359Sroberto	(void) sprintf(cp, "%ld", ival);
110854359Sroberto	while (*cp != '\0')
110954359Sroberto		cp++;
111054359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
111154359Sroberto}
111254359Sroberto
111354359Sroberto
111454359Sroberto/*
111554359Sroberto * ctl_putts - write a tagged timestamp, in hex, into the response
111654359Sroberto */
111754359Srobertostatic void
111854359Srobertoctl_putts(
111954359Sroberto	const char *tag,
112054359Sroberto	l_fp *ts
112154359Sroberto	)
112254359Sroberto{
112354359Sroberto	register char *cp;
112454359Sroberto	register const char *cq;
112554359Sroberto	char buffer[200];
112654359Sroberto
112754359Sroberto	cp = buffer;
112854359Sroberto	cq = tag;
112954359Sroberto	while (*cq != '\0')
113054359Sroberto		*cp++ = *cq++;
113154359Sroberto
113254359Sroberto	*cp++ = '=';
1133182007Sroberto	(void) sprintf(cp, "0x%08lx.%08lx",
1134182007Sroberto			   ts->l_ui & ULONG_CONST(0xffffffff),
1135182007Sroberto			   ts->l_uf & ULONG_CONST(0xffffffff));
113654359Sroberto	while (*cp != '\0')
113754359Sroberto		cp++;
113854359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
113954359Sroberto}
114054359Sroberto
114154359Sroberto
114254359Sroberto/*
1143132455Sroberto * ctl_putadr - write an IP address into the response
114454359Sroberto */
114554359Srobertostatic void
114654359Srobertoctl_putadr(
114754359Sroberto	const char *tag,
1148132455Sroberto	u_int32 addr32,
1149132455Sroberto	struct sockaddr_storage* addr
115054359Sroberto	)
115154359Sroberto{
115254359Sroberto	register char *cp;
115354359Sroberto	register const char *cq;
115454359Sroberto	char buffer[200];
115554359Sroberto
115654359Sroberto	cp = buffer;
115754359Sroberto	cq = tag;
115854359Sroberto	while (*cq != '\0')
115954359Sroberto		*cp++ = *cq++;
116054359Sroberto
116154359Sroberto	*cp++ = '=';
1162132455Sroberto	if (addr == NULL)
1163132455Sroberto		cq = numtoa(addr32);
1164132455Sroberto	else
1165132455Sroberto		cq = stoa(addr);
116654359Sroberto	while (*cq != '\0')
116754359Sroberto		*cp++ = *cq++;
116854359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
116954359Sroberto}
117054359Sroberto
117154359Sroberto/*
117254359Sroberto * ctl_putid - write a tagged clock ID into the response
117354359Sroberto */
117454359Srobertostatic void
117554359Srobertoctl_putid(
117654359Sroberto	const char *tag,
117754359Sroberto	char *id
117854359Sroberto	)
117954359Sroberto{
118054359Sroberto	register char *cp;
118154359Sroberto	register const char *cq;
118254359Sroberto	char buffer[200];
118354359Sroberto
118454359Sroberto	cp = buffer;
118554359Sroberto	cq = tag;
118654359Sroberto	while (*cq != '\0')
118754359Sroberto		*cp++ = *cq++;
118854359Sroberto
118954359Sroberto	*cp++ = '=';
119054359Sroberto	cq = id;
119154359Sroberto	while (*cq != '\0' && (cq - id) < 4)
119254359Sroberto		*cp++ = *cq++;
119354359Sroberto	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
119454359Sroberto}
119554359Sroberto
119654359Sroberto
119754359Sroberto/*
119854359Sroberto * ctl_putarray - write a tagged eight element double array into the response
119954359Sroberto */
120054359Srobertostatic void
120154359Srobertoctl_putarray(
120254359Sroberto	const char *tag,
120354359Sroberto	double *arr,
120454359Sroberto	int start
120554359Sroberto	)
120654359Sroberto{
120754359Sroberto	register char *cp;
120854359Sroberto	register const char *cq;
120954359Sroberto	char buffer[200];
121054359Sroberto	int i;
121154359Sroberto	cp = buffer;
121254359Sroberto	cq = tag;
121354359Sroberto	while (*cq != '\0')
121454359Sroberto		*cp++ = *cq++;
121554359Sroberto	i = start;
121654359Sroberto	do {
121754359Sroberto		if (i == 0)
121854359Sroberto			i = NTP_SHIFT;
121954359Sroberto		i--;
122054359Sroberto		(void)sprintf(cp, " %.2f", arr[i] * 1e3);
122154359Sroberto		while (*cp != '\0')
122254359Sroberto			cp++;
122354359Sroberto	} while(i != start);
122454359Sroberto	ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
122554359Sroberto}
122654359Sroberto
122754359Sroberto
122854359Sroberto/*
122954359Sroberto * ctl_putsys - output a system variable
123054359Sroberto */
123154359Srobertostatic void
123254359Srobertoctl_putsys(
123354359Sroberto	int varid
123454359Sroberto	)
123554359Sroberto{
123654359Sroberto	l_fp tmp;
123782502Sroberto	char str[256];
1238132455Sroberto#ifdef OPENSSL
1239132455Sroberto	struct cert_info *cp;
1240132455Sroberto	char cbuf[256];
1241132455Sroberto#endif /* OPENSSL */
124254359Sroberto
124354359Sroberto	switch (varid) {
124482502Sroberto
124582502Sroberto	case CS_LEAP:
124654359Sroberto		ctl_putuint(sys_var[CS_LEAP].text, sys_leap);
124754359Sroberto		break;
124882502Sroberto
124982502Sroberto	case CS_STRATUM:
125054359Sroberto		ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum);
125154359Sroberto		break;
125282502Sroberto
125382502Sroberto	case CS_PRECISION:
125454359Sroberto		ctl_putint(sys_var[CS_PRECISION].text, sys_precision);
125554359Sroberto		break;
125682502Sroberto
125782502Sroberto	case CS_ROOTDELAY:
125882502Sroberto		ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay *
125982502Sroberto		    1e3);
126054359Sroberto		break;
126182502Sroberto
126282502Sroberto	case CS_ROOTDISPERSION:
126354359Sroberto		ctl_putdbl(sys_var[CS_ROOTDISPERSION].text,
126454359Sroberto		    sys_rootdispersion * 1e3);
126554359Sroberto		break;
126682502Sroberto
126782502Sroberto	case CS_REFID:
1268132455Sroberto		if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC)
1269132455Sroberto			ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL);
127054359Sroberto		else
127182502Sroberto			ctl_putid(sys_var[CS_REFID].text,
127282502Sroberto			    (char *)&sys_refid);
127354359Sroberto		break;
127482502Sroberto
127582502Sroberto	case CS_REFTIME:
127654359Sroberto		ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
127754359Sroberto		break;
127882502Sroberto
127982502Sroberto	case CS_POLL:
128054359Sroberto		ctl_putuint(sys_var[CS_POLL].text, sys_poll);
128154359Sroberto		break;
128282502Sroberto
128382502Sroberto	case CS_PEERID:
128454359Sroberto		if (sys_peer == NULL)
128554359Sroberto			ctl_putuint(sys_var[CS_PEERID].text, 0);
128654359Sroberto		else
128754359Sroberto			ctl_putuint(sys_var[CS_PEERID].text,
128854359Sroberto				sys_peer->associd);
128954359Sroberto		break;
129082502Sroberto
129182502Sroberto	case CS_STATE:
129254359Sroberto		ctl_putuint(sys_var[CS_STATE].text, (unsigned)state);
129354359Sroberto		break;
129482502Sroberto
129582502Sroberto	case CS_OFFSET:
129654359Sroberto		ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3);
129754359Sroberto		break;
129882502Sroberto
129982502Sroberto	case CS_DRIFT:
130054359Sroberto		ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6);
130154359Sroberto		break;
130282502Sroberto
130382502Sroberto	case CS_JITTER:
130482502Sroberto		ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3);
130554359Sroberto		break;
130682502Sroberto
1307182007Sroberto	case CS_ERROR:
1308182007Sroberto		ctl_putdbl(sys_var[CS_ERROR].text, clock_jitter * 1e3);
1309182007Sroberto		break;
1310182007Sroberto
131182502Sroberto	case CS_CLOCK:
131254359Sroberto		get_systime(&tmp);
131354359Sroberto		ctl_putts(sys_var[CS_CLOCK].text, &tmp);
131454359Sroberto		break;
131582502Sroberto
131682502Sroberto	case CS_PROCESSOR:
131754359Sroberto#ifndef HAVE_UNAME
131854359Sroberto		ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor,
131982502Sroberto		    sizeof(str_processor) - 1);
132054359Sroberto#else
132182502Sroberto		ctl_putstr(sys_var[CS_PROCESSOR].text,
132282502Sroberto		    utsnamebuf.machine, strlen(utsnamebuf.machine));
132354359Sroberto#endif /* HAVE_UNAME */
132454359Sroberto		break;
132582502Sroberto
132682502Sroberto	case CS_SYSTEM:
132754359Sroberto#ifndef HAVE_UNAME
132854359Sroberto		ctl_putstr(sys_var[CS_SYSTEM].text, str_system,
132982502Sroberto		    sizeof(str_system) - 1);
133054359Sroberto#else
1331132455Sroberto		sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release);
133254359Sroberto		ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str));
133354359Sroberto#endif /* HAVE_UNAME */
133454359Sroberto		break;
133582502Sroberto
133682502Sroberto	case CS_VERSION:
133782502Sroberto		ctl_putstr(sys_var[CS_VERSION].text, Version,
133882502Sroberto		    strlen(Version));
133954359Sroberto		break;
134054359Sroberto
134182502Sroberto	case CS_STABIL:
134282502Sroberto		ctl_putdbl(sys_var[CS_STABIL].text, clock_stability *
134382502Sroberto		    1e6);
134482502Sroberto		break;
134554359Sroberto
134682502Sroberto	case CS_VARLIST:
134782502Sroberto		{
134882502Sroberto			char buf[CTL_MAX_DATA_LEN];
134982502Sroberto			register char *s, *t, *be;
135082502Sroberto			register const char *ss;
135182502Sroberto			register int i;
135282502Sroberto			register struct ctl_var *k;
135354359Sroberto
135482502Sroberto			s = buf;
135582502Sroberto			be = buf + sizeof(buf) -
135682502Sroberto			    strlen(sys_var[CS_VARLIST].text) - 4;
135782502Sroberto			if (s > be)
135882502Sroberto				break;	/* really long var name */
135982502Sroberto
136082502Sroberto			strcpy(s, sys_var[CS_VARLIST].text);
136182502Sroberto			strcat(s, "=\"");
136282502Sroberto			s += strlen(s);
136382502Sroberto			t = s;
136482502Sroberto			for (k = sys_var; !(k->flags &EOV); k++) {
136582502Sroberto				if (k->flags & PADDING)
136654359Sroberto					continue;
136782502Sroberto				i = strlen(k->text);
136882502Sroberto				if (s+i+1 >= be)
136982502Sroberto				break;
137054359Sroberto
137182502Sroberto				if (s != t)
137282502Sroberto				*s++ = ',';
137382502Sroberto				strcpy(s, k->text);
137482502Sroberto				s += i;
137582502Sroberto			}
137654359Sroberto
137782502Sroberto			for (k = ext_sys_var; k && !(k->flags &EOV);
137882502Sroberto			    k++) {
137982502Sroberto				if (k->flags & PADDING)
138054359Sroberto					continue;
138154359Sroberto
138282502Sroberto				ss = k->text;
138382502Sroberto				if (!ss)
138454359Sroberto					continue;
138554359Sroberto
138682502Sroberto				while (*ss && *ss != '=')
138754359Sroberto					ss++;
138882502Sroberto				i = ss - k->text;
138982502Sroberto				if (s + i + 1 >= be)
139054359Sroberto					break;
139154359Sroberto
139282502Sroberto				if (s != t)
139382502Sroberto				*s++ = ',';
139482502Sroberto				strncpy(s, k->text,
139582502Sroberto				    (unsigned)i);
139682502Sroberto				s += i;
139782502Sroberto			}
139882502Sroberto			if (s+2 >= be)
139954359Sroberto				break;
140054359Sroberto
140182502Sroberto			*s++ = '"';
140282502Sroberto			*s = '\0';
140354359Sroberto
140482502Sroberto			ctl_putdata(buf, (unsigned)( s - buf ),
140582502Sroberto			    0);
140682502Sroberto		}
140782502Sroberto		break;
140882502Sroberto
1409132455Sroberto#ifdef OPENSSL
141082502Sroberto	case CS_FLAGS:
1411132455Sroberto		if (crypto_flags) {
1412132455Sroberto			ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags);
1413132455Sroberto		}
141482502Sroberto		break;
141582502Sroberto
1416132455Sroberto	case CS_DIGEST:
1417132455Sroberto		if (crypto_flags) {
1418132455Sroberto			const EVP_MD *dp;
1419132455Sroberto
1420132455Sroberto			dp = EVP_get_digestbynid(crypto_flags >> 16);
1421132455Sroberto			strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
1422132455Sroberto			ctl_putstr(sys_var[CS_DIGEST].text, str,
1423132455Sroberto			    strlen(str));
1424132455Sroberto		}
1425132455Sroberto		break;
1426132455Sroberto
142782502Sroberto	case CS_HOST:
1428132455Sroberto		if (sys_hostname != NULL)
1429132455Sroberto			ctl_putstr(sys_var[CS_HOST].text, sys_hostname,
1430132455Sroberto			    strlen(sys_hostname));
143182502Sroberto		break;
143282502Sroberto
143382502Sroberto	case CS_CERTIF:
1434132455Sroberto		for (cp = cinfo; cp != NULL; cp = cp->link) {
1435182007Sroberto			sprintf(cbuf, "%s %s 0x%x", cp->subject,
1436182007Sroberto			    cp->issuer, cp->flags);
1437132455Sroberto			ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
1438132455Sroberto			    strlen(cbuf));
1439182007Sroberto			ctl_putfs(sys_var[CS_REVOKE].text, cp->last);
1440132455Sroberto		}
144182502Sroberto		break;
144282502Sroberto
1443132455Sroberto	case CS_PUBLIC:
1444132455Sroberto		if (hostval.fstamp != 0)
1445182007Sroberto			ctl_putfs(sys_var[CS_PUBLIC].text,
1446182007Sroberto			    ntohl(hostval.tstamp));
144782502Sroberto		break;
144882502Sroberto
144982502Sroberto	case CS_REVTIME:
1450132455Sroberto		if (hostval.tstamp != 0)
1451182007Sroberto			ctl_putfs(sys_var[CS_REVTIME].text,
1452132455Sroberto			    ntohl(hostval.tstamp));
145382502Sroberto		break;
145482502Sroberto
1455182007Sroberto	case CS_IDENT:
1456182007Sroberto		if (iffpar_pkey != NULL)
1457182007Sroberto			ctl_putstr(sys_var[CS_IDENT].text,
1458182007Sroberto			    iffpar_file, strlen(iffpar_file));
1459182007Sroberto		if (gqpar_pkey != NULL)
1460182007Sroberto			ctl_putstr(sys_var[CS_IDENT].text,
1461182007Sroberto			    gqpar_file, strlen(gqpar_file));
1462182007Sroberto		if (mvpar_pkey != NULL)
1463182007Sroberto			ctl_putstr(sys_var[CS_IDENT].text,
1464182007Sroberto			    mvpar_file, strlen(mvpar_file));
1465182007Sroberto		break;
1466182007Sroberto
146782502Sroberto	case CS_LEAPTAB:
146882502Sroberto		if (tai_leap.fstamp != 0)
1469182007Sroberto			ctl_putfs(sys_var[CS_LEAPTAB].text,
147082502Sroberto			    ntohl(tai_leap.fstamp));
147182502Sroberto		break;
1472182007Sroberto
1473182007Sroberto	case CS_TAI:
1474182007Sroberto		ctl_putuint(sys_var[CS_TAI].text, sys_tai);
1475182007Sroberto		break;
1476132455Sroberto#endif /* OPENSSL */
147754359Sroberto	}
147854359Sroberto}
147954359Sroberto
148054359Sroberto
148154359Sroberto/*
148254359Sroberto * ctl_putpeer - output a peer variable
148354359Sroberto */
148454359Srobertostatic void
148554359Srobertoctl_putpeer(
148654359Sroberto	int varid,
148754359Sroberto	struct peer *peer
148854359Sroberto	)
148954359Sroberto{
1490182007Sroberto	int temp;
1491132455Sroberto#ifdef OPENSSL
1492132455Sroberto	char str[256];
1493132455Sroberto	struct autokey *ap;
1494132455Sroberto#endif /* OPENSSL */
1495132455Sroberto
149654359Sroberto	switch (varid) {
149782502Sroberto
149882502Sroberto	case CP_CONFIG:
149954359Sroberto		ctl_putuint(peer_var[CP_CONFIG].text,
150082502Sroberto		    (unsigned)((peer->flags & FLAG_CONFIG) != 0));
150154359Sroberto		break;
150282502Sroberto
150382502Sroberto	case CP_AUTHENABLE:
150454359Sroberto		ctl_putuint(peer_var[CP_AUTHENABLE].text,
150582502Sroberto		    (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0));
150654359Sroberto		break;
150782502Sroberto
150882502Sroberto	case CP_AUTHENTIC:
150954359Sroberto		ctl_putuint(peer_var[CP_AUTHENTIC].text,
151082502Sroberto		    (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0));
151154359Sroberto		break;
151282502Sroberto
151382502Sroberto	case CP_SRCADR:
1514132455Sroberto		ctl_putadr(peer_var[CP_SRCADR].text, 0,
1515132455Sroberto		    &peer->srcadr);
151654359Sroberto		break;
151782502Sroberto
151882502Sroberto	case CP_SRCPORT:
151954359Sroberto		ctl_putuint(peer_var[CP_SRCPORT].text,
1520132455Sroberto		    ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port));
152154359Sroberto		break;
152282502Sroberto
152382502Sroberto	case CP_DSTADR:
1524182007Sroberto		if (peer->dstadr) {
1525182007Sroberto			ctl_putadr(peer_var[CP_DSTADR].text, 0,
1526182007Sroberto				   &(peer->dstadr->sin));
1527182007Sroberto		} else {
1528182007Sroberto			ctl_putadr(peer_var[CP_DSTADR].text, 0,
1529182007Sroberto				   NULL);
1530182007Sroberto		}
153154359Sroberto		break;
153282502Sroberto
153382502Sroberto	case CP_DSTPORT:
153454359Sroberto		ctl_putuint(peer_var[CP_DSTPORT].text,
153582502Sroberto		    (u_long)(peer->dstadr ?
1536132455Sroberto		    ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0));
153754359Sroberto		break;
153882502Sroberto
153982502Sroberto	case CP_LEAP:
154054359Sroberto		ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
154154359Sroberto		break;
154282502Sroberto
154382502Sroberto	case CP_HMODE:
154454359Sroberto		ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
154554359Sroberto		break;
154682502Sroberto
154782502Sroberto	case CP_STRATUM:
154854359Sroberto		ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
154954359Sroberto		break;
155082502Sroberto
155182502Sroberto	case CP_PPOLL:
155254359Sroberto		ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
155354359Sroberto		break;
155482502Sroberto
155582502Sroberto	case CP_HPOLL:
155654359Sroberto		ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
155754359Sroberto		break;
155882502Sroberto
155982502Sroberto	case CP_PRECISION:
156082502Sroberto		ctl_putint(peer_var[CP_PRECISION].text,
156182502Sroberto		    peer->precision);
156254359Sroberto		break;
156382502Sroberto
156482502Sroberto	case CP_ROOTDELAY:
156582502Sroberto		ctl_putdbl(peer_var[CP_ROOTDELAY].text,
156682502Sroberto		    peer->rootdelay * 1e3);
156754359Sroberto		break;
156882502Sroberto
156982502Sroberto	case CP_ROOTDISPERSION:
157054359Sroberto		ctl_putdbl(peer_var[CP_ROOTDISPERSION].text,
157182502Sroberto		    peer->rootdispersion * 1e3);
157254359Sroberto		break;
157382502Sroberto
157482502Sroberto	case CP_REFID:
1575132455Sroberto		if (peer->flags & FLAG_REFCLOCK) {
1576182007Sroberto			ctl_putid(peer_var[CP_REFID].text,
1577182007Sroberto			   (char *)&peer->refid);
157882502Sroberto		} else {
1579132455Sroberto			if (peer->stratum > 1 && peer->stratum <
1580132455Sroberto			    STRATUM_UNSPEC)
1581132455Sroberto				ctl_putadr(peer_var[CP_REFID].text,
1582132455Sroberto				    peer->refid, NULL);
1583132455Sroberto			else
1584132455Sroberto				ctl_putid(peer_var[CP_REFID].text,
1585132455Sroberto				    (char *)&peer->refid);
158682502Sroberto		}
158754359Sroberto		break;
158882502Sroberto
158982502Sroberto	case CP_REFTIME:
159054359Sroberto		ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime);
159154359Sroberto		break;
159282502Sroberto
159382502Sroberto	case CP_ORG:
159454359Sroberto		ctl_putts(peer_var[CP_ORG].text, &peer->org);
159554359Sroberto		break;
159682502Sroberto
159782502Sroberto	case CP_REC:
159854359Sroberto		ctl_putts(peer_var[CP_REC].text, &peer->rec);
159954359Sroberto		break;
160082502Sroberto
160182502Sroberto	case CP_XMT:
160254359Sroberto		ctl_putts(peer_var[CP_XMT].text, &peer->xmt);
160354359Sroberto		break;
160482502Sroberto
160582502Sroberto	case CP_REACH:
160654359Sroberto		ctl_puthex(peer_var[CP_REACH].text, peer->reach);
160754359Sroberto		break;
160882502Sroberto
160982502Sroberto	case CP_FLASH:
1610182007Sroberto		temp = peer->flash;
1611182007Sroberto		ctl_puthex(peer_var[CP_FLASH].text, temp);
161254359Sroberto		break;
161382502Sroberto
161482502Sroberto	case CP_TTL:
1615132455Sroberto		ctl_putint(peer_var[CP_TTL].text, sys_ttl[peer->ttl]);
161654359Sroberto		break;
161782502Sroberto
1618182007Sroberto	case CP_UNREACH:
1619182007Sroberto		ctl_putuint(peer_var[CP_UNREACH].text, peer->unreach);
162082502Sroberto		break;
162182502Sroberto
162282502Sroberto	case CP_TIMER:
162354359Sroberto		ctl_putuint(peer_var[CP_TIMER].text,
162454359Sroberto		    peer->nextdate - current_time);
162554359Sroberto		break;
162682502Sroberto
162782502Sroberto	case CP_DELAY:
162854359Sroberto		ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3);
162954359Sroberto		break;
163082502Sroberto
163182502Sroberto	case CP_OFFSET:
163282502Sroberto		ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset *
163382502Sroberto		    1e3);
163454359Sroberto		break;
163582502Sroberto
163682502Sroberto	case CP_JITTER:
1637182007Sroberto		ctl_putdbl(peer_var[CP_JITTER].text, peer->jitter * 1e3);
163854359Sroberto		break;
163982502Sroberto
164082502Sroberto	case CP_DISPERSION:
164182502Sroberto		ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp *
164282502Sroberto		    1e3);
164354359Sroberto		break;
164482502Sroberto
164582502Sroberto	case CP_KEYID:
164654359Sroberto		ctl_putuint(peer_var[CP_KEYID].text, peer->keyid);
164754359Sroberto		break;
164882502Sroberto
164982502Sroberto	case CP_FILTDELAY:
165054359Sroberto		ctl_putarray(peer_var[CP_FILTDELAY].text,
165154359Sroberto		    peer->filter_delay, (int)peer->filter_nextpt);
165254359Sroberto		break;
165382502Sroberto
165482502Sroberto	case CP_FILTOFFSET:
165554359Sroberto		ctl_putarray(peer_var[CP_FILTOFFSET].text,
165654359Sroberto		    peer->filter_offset, (int)peer->filter_nextpt);
165754359Sroberto		break;
165882502Sroberto
165982502Sroberto	case CP_FILTERROR:
166054359Sroberto		ctl_putarray(peer_var[CP_FILTERROR].text,
166154359Sroberto		    peer->filter_disp, (int)peer->filter_nextpt);
166254359Sroberto		break;
166382502Sroberto
166482502Sroberto	case CP_PMODE:
166554359Sroberto		ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
166654359Sroberto		break;
166782502Sroberto
166882502Sroberto	case CP_RECEIVED:
166954359Sroberto		ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
167054359Sroberto		break;
167182502Sroberto
167282502Sroberto	case CP_SENT:
167354359Sroberto		ctl_putuint(peer_var[CP_SENT].text, peer->sent);
167454359Sroberto		break;
167554359Sroberto
167682502Sroberto	case CP_VARLIST:
167782502Sroberto		{
167882502Sroberto			char buf[CTL_MAX_DATA_LEN];
167982502Sroberto			register char *s, *t, *be;
168082502Sroberto			register int i;
168182502Sroberto			register struct ctl_var *k;
168254359Sroberto
168382502Sroberto			s = buf;
168482502Sroberto			be = buf + sizeof(buf) -
168582502Sroberto			    strlen(peer_var[CP_VARLIST].text) - 4;
168682502Sroberto			if (s > be)
168782502Sroberto				break;	/* really long var name */
168854359Sroberto
168982502Sroberto			strcpy(s, peer_var[CP_VARLIST].text);
169082502Sroberto			strcat(s, "=\"");
169182502Sroberto			s += strlen(s);
169282502Sroberto			t = s;
169382502Sroberto			for (k = peer_var; !(k->flags &EOV); k++) {
169482502Sroberto				if (k->flags & PADDING)
169554359Sroberto					continue;
169654359Sroberto
169782502Sroberto				i = strlen(k->text);
169882502Sroberto				if (s + i + 1 >= be)
169982502Sroberto				break;
170082502Sroberto
170182502Sroberto				if (s != t)
170254359Sroberto					*s++ = ',';
170382502Sroberto				strcpy(s, k->text);
170482502Sroberto				s += i;
170582502Sroberto			}
170682502Sroberto			if (s+2 >= be)
170754359Sroberto				break;
170854359Sroberto
170982502Sroberto			*s++ = '"';
171082502Sroberto			*s = '\0';
171182502Sroberto			ctl_putdata(buf, (unsigned)(s - buf), 0);
171282502Sroberto		}
171382502Sroberto		break;
1714132455Sroberto#ifdef OPENSSL
171582502Sroberto	case CP_FLAGS:
171682502Sroberto		if (peer->crypto)
171782502Sroberto			ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto);
171882502Sroberto		break;
171954359Sroberto
1720132455Sroberto	case CP_DIGEST:
1721132455Sroberto		if (peer->crypto) {
1722132455Sroberto			const EVP_MD *dp;
1723132455Sroberto
1724132455Sroberto			dp = EVP_get_digestbynid(peer->crypto >> 16);
1725132455Sroberto			strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
1726132455Sroberto			ctl_putstr(peer_var[CP_DIGEST].text, str,
1727132455Sroberto       	                     strlen(str));
1728132455Sroberto		}
172982502Sroberto		break;
173082502Sroberto
1731132455Sroberto	case CP_HOST:
1732132455Sroberto		if (peer->subject != NULL)
1733182007Sroberto			ctl_putstr(peer_var[CP_HOST].text,
1734182007Sroberto			    peer->subject, strlen(peer->subject));
173582502Sroberto		break;
173682502Sroberto
1737182007Sroberto	case CP_VALID:		/* not used */
1738182007Sroberto		break;
1739182007Sroberto
1740132455Sroberto	case CP_IDENT:
1741132455Sroberto		if (peer->issuer != NULL)
1742182007Sroberto			ctl_putstr(peer_var[CP_IDENT].text,
1743182007Sroberto			    peer->issuer, strlen(peer->issuer));
174482502Sroberto		break;
174582502Sroberto
174682502Sroberto	case CP_INITSEQ:
1747132455Sroberto		if ((ap = (struct autokey *)peer->recval.ptr) == NULL)
174854359Sroberto			break;
1749132455Sroberto		ctl_putint(peer_var[CP_INITSEQ].text, ap->seq);
1750132455Sroberto		ctl_puthex(peer_var[CP_INITKEY].text, ap->key);
1751182007Sroberto		ctl_putfs(peer_var[CP_INITTSP].text,
1752132455Sroberto		    ntohl(peer->recval.tstamp));
175382502Sroberto		break;
1754132455Sroberto#endif /* OPENSSL */
175554359Sroberto	}
175654359Sroberto}
175754359Sroberto
175854359Sroberto
175954359Sroberto#ifdef REFCLOCK
176054359Sroberto/*
176154359Sroberto * ctl_putclock - output clock variables
176254359Sroberto */
176354359Srobertostatic void
176454359Srobertoctl_putclock(
176554359Sroberto	int varid,
176654359Sroberto	struct refclockstat *clock_stat,
176754359Sroberto	int mustput
176854359Sroberto	)
176954359Sroberto{
177054359Sroberto	switch(varid) {
177182502Sroberto
177282502Sroberto	case CC_TYPE:
177354359Sroberto		if (mustput || clock_stat->clockdesc == NULL
177454359Sroberto			|| *(clock_stat->clockdesc) == '\0') {
177554359Sroberto			ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type);
177654359Sroberto		}
177754359Sroberto		break;
177882502Sroberto	case CC_TIMECODE:
177982502Sroberto		ctl_putstr(clock_var[CC_TIMECODE].text,
178082502Sroberto		    clock_stat->p_lastcode,
178182502Sroberto		    (unsigned)clock_stat->lencode);
178254359Sroberto		break;
178382502Sroberto
178482502Sroberto	case CC_POLL:
178554359Sroberto		ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls);
178654359Sroberto		break;
178782502Sroberto
178882502Sroberto	case CC_NOREPLY:
178982502Sroberto		ctl_putuint(clock_var[CC_NOREPLY].text,
179082502Sroberto		    clock_stat->noresponse);
179154359Sroberto		break;
179282502Sroberto
179382502Sroberto	case CC_BADFORMAT:
179482502Sroberto		ctl_putuint(clock_var[CC_BADFORMAT].text,
179582502Sroberto		    clock_stat->badformat);
179654359Sroberto		break;
179782502Sroberto
179882502Sroberto	case CC_BADDATA:
179982502Sroberto		ctl_putuint(clock_var[CC_BADDATA].text,
180082502Sroberto		    clock_stat->baddata);
180154359Sroberto		break;
180282502Sroberto
180382502Sroberto	case CC_FUDGETIME1:
180482502Sroberto		if (mustput || (clock_stat->haveflags & CLK_HAVETIME1))
180554359Sroberto			ctl_putdbl(clock_var[CC_FUDGETIME1].text,
180682502Sroberto			    clock_stat->fudgetime1 * 1e3);
180754359Sroberto		break;
180882502Sroberto
180982502Sroberto	case CC_FUDGETIME2:
181082502Sroberto		if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) 			ctl_putdbl(clock_var[CC_FUDGETIME2].text,
181182502Sroberto			    clock_stat->fudgetime2 * 1e3);
181254359Sroberto		break;
181382502Sroberto
181482502Sroberto	case CC_FUDGEVAL1:
181554359Sroberto		if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1))
181654359Sroberto			ctl_putint(clock_var[CC_FUDGEVAL1].text,
181782502Sroberto			    clock_stat->fudgeval1);
181854359Sroberto		break;
181982502Sroberto
182082502Sroberto	case CC_FUDGEVAL2:
182154359Sroberto		if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) {
182254359Sroberto			if (clock_stat->fudgeval1 > 1)
182382502Sroberto				ctl_putadr(clock_var[CC_FUDGEVAL2].text,
1824132455Sroberto				    (u_int32)clock_stat->fudgeval2, NULL);
182554359Sroberto			else
182682502Sroberto				ctl_putid(clock_var[CC_FUDGEVAL2].text,
182782502Sroberto				    (char *)&clock_stat->fudgeval2);
182854359Sroberto		}
182954359Sroberto		break;
183082502Sroberto
183182502Sroberto	case CC_FLAGS:
183282502Sroberto		if (mustput || (clock_stat->haveflags &	(CLK_HAVEFLAG1 |
183382502Sroberto		    CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4)))
183482502Sroberto			ctl_putuint(clock_var[CC_FLAGS].text,
183582502Sroberto			    clock_stat->flags);
183654359Sroberto		break;
183782502Sroberto
183882502Sroberto	case CC_DEVICE:
183982502Sroberto		if (clock_stat->clockdesc == NULL ||
184082502Sroberto		    *(clock_stat->clockdesc) == '\0') {
184154359Sroberto			if (mustput)
184282502Sroberto				ctl_putstr(clock_var[CC_DEVICE].text,
184382502Sroberto				    "", 0);
184454359Sroberto		} else {
184582502Sroberto			ctl_putstr(clock_var[CC_DEVICE].text,
184682502Sroberto			    clock_stat->clockdesc,
184782502Sroberto			    strlen(clock_stat->clockdesc));
184854359Sroberto		}
184954359Sroberto		break;
185054359Sroberto
185182502Sroberto	case CC_VARLIST:
185282502Sroberto		{
185382502Sroberto			char buf[CTL_MAX_DATA_LEN];
185482502Sroberto			register char *s, *t, *be;
185582502Sroberto			register const char *ss;
185682502Sroberto			register int i;
185782502Sroberto			register struct ctl_var *k;
185854359Sroberto
185982502Sroberto			s = buf;
186082502Sroberto			be = buf + sizeof(buf);
186182502Sroberto			if (s + strlen(clock_var[CC_VARLIST].text) + 4 >
186282502Sroberto			    be)
186382502Sroberto				break;	/* really long var name */
186454359Sroberto
186582502Sroberto			strcpy(s, clock_var[CC_VARLIST].text);
186682502Sroberto			strcat(s, "=\"");
186782502Sroberto			s += strlen(s);
186882502Sroberto			t = s;
186982502Sroberto
187082502Sroberto			for (k = clock_var; !(k->flags &EOV); k++) {
187182502Sroberto				if (k->flags & PADDING)
187254359Sroberto					continue;
187354359Sroberto
187482502Sroberto				i = strlen(k->text);
187582502Sroberto				if (s + i + 1 >= be)
187654359Sroberto					break;
187754359Sroberto
187882502Sroberto				if (s != t)
187982502Sroberto				*s++ = ',';
188082502Sroberto				strcpy(s, k->text);
188182502Sroberto				s += i;
188282502Sroberto			}
188382502Sroberto
188482502Sroberto			for (k = clock_stat->kv_list; k && !(k->flags &
188582502Sroberto			    EOV); k++) {
188682502Sroberto				if (k->flags & PADDING)
188754359Sroberto					continue;
188854359Sroberto
188982502Sroberto				ss = k->text;
189082502Sroberto				if (!ss)
189154359Sroberto					continue;
189254359Sroberto
189382502Sroberto				while (*ss && *ss != '=')
189454359Sroberto					ss++;
189582502Sroberto				i = ss - k->text;
189682502Sroberto				if (s+i+1 >= be)
189782502Sroberto					break;
189854359Sroberto
189982502Sroberto				if (s != t)
190054359Sroberto					*s++ = ',';
190182502Sroberto				strncpy(s, k->text, (unsigned)i);
190282502Sroberto				s += i;
190382502Sroberto				*s = '\0';
190482502Sroberto			}
190582502Sroberto			if (s+2 >= be)
190654359Sroberto				break;
190754359Sroberto
190882502Sroberto			*s++ = '"';
190982502Sroberto			*s = '\0';
191082502Sroberto			ctl_putdata(buf, (unsigned)( s - buf ), 0);
191182502Sroberto		}
191282502Sroberto		break;
191354359Sroberto	}
191454359Sroberto}
191554359Sroberto#endif
191654359Sroberto
191754359Sroberto
191854359Sroberto
191954359Sroberto/*
192054359Sroberto * ctl_getitem - get the next data item from the incoming packet
192154359Sroberto */
192254359Srobertostatic struct ctl_var *
192354359Srobertoctl_getitem(
192454359Sroberto	struct ctl_var *var_list,
192554359Sroberto	char **data
192654359Sroberto	)
192754359Sroberto{
192854359Sroberto	register struct ctl_var *v;
192954359Sroberto	register char *cp;
193054359Sroberto	register char *tp;
193154359Sroberto	static struct ctl_var eol = { 0, EOV, };
193254359Sroberto	static char buf[128];
193354359Sroberto
193454359Sroberto	/*
193554359Sroberto	 * Delete leading commas and white space
193654359Sroberto	 */
193782502Sroberto	while (reqpt < reqend && (*reqpt == ',' ||
193882502Sroberto	    isspace((unsigned char)*reqpt)))
193954359Sroberto		reqpt++;
194054359Sroberto	if (reqpt >= reqend)
194182502Sroberto		return (0);
194254359Sroberto
194354359Sroberto	if (var_list == (struct ctl_var *)0)
194482502Sroberto		return (&eol);
194554359Sroberto
194654359Sroberto	/*
194754359Sroberto	 * Look for a first character match on the tag.  If we find
194854359Sroberto	 * one, see if it is a full match.
194954359Sroberto	 */
195054359Sroberto	v = var_list;
195154359Sroberto	cp = reqpt;
195254359Sroberto	while (!(v->flags & EOV)) {
195354359Sroberto		if (!(v->flags & PADDING) && *cp == *(v->text)) {
195454359Sroberto			tp = v->text;
195582502Sroberto			while (*tp != '\0' && *tp != '=' && cp <
195682502Sroberto			    reqend && *cp == *tp) {
195754359Sroberto				cp++;
195854359Sroberto				tp++;
195954359Sroberto			}
196054359Sroberto			if ((*tp == '\0') || (*tp == '=')) {
196175259Sjedgar				while (cp < reqend && isspace((unsigned char)*cp))
196254359Sroberto					cp++;
196354359Sroberto				if (cp == reqend || *cp == ',') {
196454359Sroberto					buf[0] = '\0';
196554359Sroberto					*data = buf;
196654359Sroberto					if (cp < reqend)
196754359Sroberto						cp++;
196854359Sroberto					reqpt = cp;
196954359Sroberto					return v;
197054359Sroberto				}
197154359Sroberto				if (*cp == '=') {
197254359Sroberto					cp++;
197354359Sroberto					tp = buf;
1974132455Sroberto					while (cp < reqend && isspace((unsigned char)*cp))
197554359Sroberto						cp++;
197675202Sphk					while (cp < reqend && *cp != ',') {
197754359Sroberto						*tp++ = *cp++;
1978182007Sroberto						if (tp >= buf + sizeof(buf)) {
1979182007Sroberto							ctl_error(CERR_BADFMT);
1980182007Sroberto							numctlbadpkts++;
1981182007Sroberto#if 0	/* Avoid possible DOS attack */
1982182007Sroberto/* If we get a smarter msyslog we can re-enable this */
1983182007Sroberto							msyslog(LOG_WARNING,
1984182007Sroberto		"Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n",
1985182007Sroberto		stoa(rmt_addr), SRCPORT(rmt_addr)
1986182007Sroberto								);
1987182007Sroberto#endif
198875202Sphk							return (0);
1989182007Sroberto						}
199075202Sphk					}
199154359Sroberto					if (cp < reqend)
199254359Sroberto						cp++;
199382502Sroberto					*tp-- = '\0';
1994132455Sroberto					while (tp >= buf) {
1995182007Sroberto						if (!isspace((unsigned int)(*tp)))
199682502Sroberto							break;
1997132455Sroberto						*tp-- = '\0';
199882502Sroberto					}
199954359Sroberto					reqpt = cp;
200054359Sroberto					*data = buf;
200182502Sroberto					return (v);
200254359Sroberto				}
200354359Sroberto			}
200454359Sroberto			cp = reqpt;
200554359Sroberto		}
200654359Sroberto		v++;
200754359Sroberto	}
200854359Sroberto	return v;
200954359Sroberto}
201054359Sroberto
201154359Sroberto
201254359Sroberto/*
201354359Sroberto * control_unspec - response to an unspecified op-code
201454359Sroberto */
201554359Sroberto/*ARGSUSED*/
201654359Srobertostatic void
201754359Srobertocontrol_unspec(
201854359Sroberto	struct recvbuf *rbufp,
201954359Sroberto	int restrict_mask
202054359Sroberto	)
202154359Sroberto{
202254359Sroberto	struct peer *peer;
202354359Sroberto
202454359Sroberto	/*
202554359Sroberto	 * What is an appropriate response to an unspecified op-code?
202654359Sroberto	 * I return no errors and no data, unless a specified assocation
202754359Sroberto	 * doesn't exist.
202854359Sroberto	 */
202954359Sroberto	if (res_associd != 0) {
203082502Sroberto		if ((peer = findpeerbyassoc(res_associd)) == 0) {
203154359Sroberto			ctl_error(CERR_BADASSOC);
203254359Sroberto			return;
203354359Sroberto		}
203454359Sroberto		rpkt.status = htons(ctlpeerstatus(peer));
203554359Sroberto	} else {
203654359Sroberto		rpkt.status = htons(ctlsysstatus());
203754359Sroberto	}
203854359Sroberto	ctl_flushpkt(0);
203954359Sroberto}
204054359Sroberto
204154359Sroberto
204254359Sroberto/*
204354359Sroberto * read_status - return either a list of associd's, or a particular
204482502Sroberto * peer's status.
204554359Sroberto */
204654359Sroberto/*ARGSUSED*/
204754359Srobertostatic void
204854359Srobertoread_status(
204954359Sroberto	struct recvbuf *rbufp,
205054359Sroberto	int restrict_mask
205154359Sroberto	)
205254359Sroberto{
205354359Sroberto	register int i;
205454359Sroberto	register struct peer *peer;
205582502Sroberto	u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)];
205654359Sroberto
205754359Sroberto#ifdef DEBUG
205882502Sroberto	if (debug > 2)
205954359Sroberto		printf("read_status: ID %d\n", res_associd);
206054359Sroberto#endif
206154359Sroberto	/*
206282502Sroberto	 * Two choices here. If the specified association ID is
206354359Sroberto	 * zero we return all known assocation ID's.  Otherwise
206454359Sroberto	 * we return a bunch of stuff about the particular peer.
206554359Sroberto	 */
206654359Sroberto	if (res_associd == 0) {
206754359Sroberto		register int n;
206854359Sroberto
206954359Sroberto		n = 0;
207054359Sroberto		rpkt.status = htons(ctlsysstatus());
2071182007Sroberto		for (i = 0; i < NTP_HASH_SIZE; i++) {
207254359Sroberto			for (peer = assoc_hash[i]; peer != 0;
207382502Sroberto				peer = peer->ass_next) {
207454359Sroberto				ass_stat[n++] = htons(peer->associd);
207582502Sroberto				ass_stat[n++] =
207682502Sroberto				    htons(ctlpeerstatus(peer));
207782502Sroberto				if (n ==
207882502Sroberto				    CTL_MAX_DATA_LEN/sizeof(u_short)) {
207954359Sroberto					ctl_putdata((char *)ass_stat,
208082502Sroberto					    n * sizeof(u_short), 1);
208154359Sroberto					n = 0;
208254359Sroberto				}
208354359Sroberto			}
208454359Sroberto		}
208554359Sroberto
208654359Sroberto		if (n != 0)
208782502Sroberto			ctl_putdata((char *)ass_stat, n *
208882502Sroberto			    sizeof(u_short), 1);
208954359Sroberto		ctl_flushpkt(0);
209054359Sroberto	} else {
209182502Sroberto		peer = findpeerbyassoc(res_associd);
209254359Sroberto		if (peer == 0) {
209354359Sroberto			ctl_error(CERR_BADASSOC);
209454359Sroberto		} else {
209554359Sroberto			register u_char *cp;
209654359Sroberto
209754359Sroberto			rpkt.status = htons(ctlpeerstatus(peer));
209854359Sroberto			if (res_authokay)
209954359Sroberto				peer->num_events = 0;
210054359Sroberto			/*
210182502Sroberto			 * For now, output everything we know about the
210282502Sroberto			 * peer. May be more selective later.
210354359Sroberto			 */
210454359Sroberto			for (cp = def_peer_var; *cp != 0; cp++)
210554359Sroberto				ctl_putpeer((int)*cp, peer);
210654359Sroberto			ctl_flushpkt(0);
210754359Sroberto		}
210854359Sroberto	}
210954359Sroberto}
211054359Sroberto
211154359Sroberto
211254359Sroberto/*
211354359Sroberto * read_variables - return the variables the caller asks for
211454359Sroberto */
211554359Sroberto/*ARGSUSED*/
211654359Srobertostatic void
211754359Srobertoread_variables(
211854359Sroberto	struct recvbuf *rbufp,
211954359Sroberto	int restrict_mask
212054359Sroberto	)
212154359Sroberto{
212254359Sroberto	register struct ctl_var *v;
212354359Sroberto	register int i;
212454359Sroberto	char *valuep;
212554359Sroberto	u_char *wants;
212682502Sroberto	unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE +
212782502Sroberto	    1) : (CP_MAXCODE + 1);
212854359Sroberto	if (res_associd == 0) {
212954359Sroberto		/*
213082502Sroberto		 * Wants system variables. Figure out which he wants
213154359Sroberto		 * and give them to him.
213254359Sroberto		 */
213354359Sroberto		rpkt.status = htons(ctlsysstatus());
213454359Sroberto		if (res_authokay)
213554359Sroberto			ctl_sys_num_events = 0;
213654359Sroberto		gotvar += count_var(ext_sys_var);
213754359Sroberto		wants = (u_char *)emalloc(gotvar);
213854359Sroberto		memset((char *)wants, 0, gotvar);
213954359Sroberto		gotvar = 0;
214054359Sroberto		while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
214154359Sroberto			if (v->flags & EOV) {
214282502Sroberto				if ((v = ctl_getitem(ext_sys_var,
214382502Sroberto				    &valuep)) != 0) {
214454359Sroberto					if (v->flags & EOV) {
214554359Sroberto						ctl_error(CERR_UNKNOWNVAR);
214654359Sroberto						free((char *)wants);
214754359Sroberto						return;
214854359Sroberto					}
214982502Sroberto					wants[CS_MAXCODE + 1 +
215082502Sroberto					    v->code] = 1;
215154359Sroberto					gotvar = 1;
215254359Sroberto					continue;
215354359Sroberto				} else {
215454359Sroberto					break; /* shouldn't happen ! */
215554359Sroberto				}
215654359Sroberto			}
215754359Sroberto			wants[v->code] = 1;
215854359Sroberto			gotvar = 1;
215954359Sroberto		}
216054359Sroberto		if (gotvar) {
216154359Sroberto			for (i = 1; i <= CS_MAXCODE; i++)
216254359Sroberto				if (wants[i])
216382502Sroberto					ctl_putsys(i);
216482502Sroberto			for (i = 0; ext_sys_var &&
216582502Sroberto			    !(ext_sys_var[i].flags & EOV); i++)
216682502Sroberto				if (wants[i + CS_MAXCODE + 1])
216782502Sroberto					ctl_putdata(ext_sys_var[i].text,
216882502Sroberto					    strlen(ext_sys_var[i].text),
216982502Sroberto					    0);
217054359Sroberto		} else {
217154359Sroberto			register u_char *cs;
217254359Sroberto			register struct ctl_var *kv;
217354359Sroberto
217454359Sroberto			for (cs = def_sys_var; *cs != 0; cs++)
217554359Sroberto				ctl_putsys((int)*cs);
217682502Sroberto			for (kv = ext_sys_var; kv && !(kv->flags & EOV);
217782502Sroberto			    kv++)
217854359Sroberto				if (kv->flags & DEF)
217982502Sroberto					ctl_putdata(kv->text,
218082502Sroberto					    strlen(kv->text), 0);
218154359Sroberto		}
218254359Sroberto		free((char *)wants);
218354359Sroberto	} else {
218454359Sroberto		register struct peer *peer;
218554359Sroberto
218654359Sroberto		/*
218782502Sroberto		 * Wants info for a particular peer. See if we know
218854359Sroberto		 * the guy.
218954359Sroberto		 */
219082502Sroberto		peer = findpeerbyassoc(res_associd);
219154359Sroberto		if (peer == 0) {
219254359Sroberto			ctl_error(CERR_BADASSOC);
219354359Sroberto			return;
219454359Sroberto		}
219554359Sroberto		rpkt.status = htons(ctlpeerstatus(peer));
219654359Sroberto		if (res_authokay)
219754359Sroberto			peer->num_events = 0;
219854359Sroberto		wants = (u_char *)emalloc(gotvar);
219954359Sroberto		memset((char*)wants, 0, gotvar);
220054359Sroberto		gotvar = 0;
220154359Sroberto		while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
220254359Sroberto			if (v->flags & EOV) {
220354359Sroberto				ctl_error(CERR_UNKNOWNVAR);
220454359Sroberto				free((char *)wants);
220554359Sroberto				return;
220654359Sroberto			}
220754359Sroberto			wants[v->code] = 1;
220854359Sroberto			gotvar = 1;
220954359Sroberto		}
221054359Sroberto		if (gotvar) {
221154359Sroberto			for (i = 1; i <= CP_MAXCODE; i++)
221254359Sroberto				if (wants[i])
221382502Sroberto					ctl_putpeer(i, peer);
221454359Sroberto		} else {
221554359Sroberto			register u_char *cp;
221654359Sroberto
221754359Sroberto			for (cp = def_peer_var; *cp != 0; cp++)
221854359Sroberto				ctl_putpeer((int)*cp, peer);
221954359Sroberto		}
222054359Sroberto		free((char *)wants);
222154359Sroberto	}
222254359Sroberto	ctl_flushpkt(0);
222354359Sroberto}
222454359Sroberto
222554359Sroberto
222654359Sroberto/*
222782502Sroberto * write_variables - write into variables. We only allow leap bit
222882502Sroberto * writing this way.
222954359Sroberto */
223054359Sroberto/*ARGSUSED*/
223154359Srobertostatic void
223254359Srobertowrite_variables(
223354359Sroberto	struct recvbuf *rbufp,
223454359Sroberto	int restrict_mask
223554359Sroberto	)
223654359Sroberto{
223754359Sroberto	register struct ctl_var *v;
223854359Sroberto	register int ext_var;
223954359Sroberto	char *valuep;
2240132455Sroberto	long val = 0;
224154359Sroberto
224254359Sroberto	/*
224354359Sroberto	 * If he's trying to write into a peer tell him no way
224454359Sroberto	 */
224554359Sroberto	if (res_associd != 0) {
224654359Sroberto		ctl_error(CERR_PERMISSION);
224754359Sroberto		return;
224854359Sroberto	}
224954359Sroberto
225054359Sroberto	/*
225154359Sroberto	 * Set status
225254359Sroberto	 */
225354359Sroberto	rpkt.status = htons(ctlsysstatus());
225454359Sroberto
225554359Sroberto	/*
225682502Sroberto	 * Look through the variables. Dump out at the first sign of
225782502Sroberto	 * trouble.
225854359Sroberto	 */
225954359Sroberto	while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
226054359Sroberto		ext_var = 0;
226154359Sroberto		if (v->flags & EOV) {
226282502Sroberto			if ((v = ctl_getitem(ext_sys_var, &valuep)) !=
226382502Sroberto			    0) {
226454359Sroberto				if (v->flags & EOV) {
226554359Sroberto					ctl_error(CERR_UNKNOWNVAR);
226654359Sroberto					return;
226754359Sroberto				}
226854359Sroberto				ext_var = 1;
226954359Sroberto			} else {
227054359Sroberto				break;
227154359Sroberto			}
227254359Sroberto		}
227354359Sroberto		if (!(v->flags & CAN_WRITE)) {
227454359Sroberto			ctl_error(CERR_PERMISSION);
227554359Sroberto			return;
227654359Sroberto		}
227782502Sroberto		if (!ext_var && (*valuep == '\0' || !atoint(valuep,
227882502Sroberto		    &val))) {
227954359Sroberto			ctl_error(CERR_BADFMT);
228054359Sroberto			return;
228154359Sroberto		}
228254359Sroberto		if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) {
228354359Sroberto			ctl_error(CERR_BADVALUE);
228454359Sroberto			return;
228554359Sroberto		}
228654359Sroberto
228754359Sroberto		if (ext_var) {
228882502Sroberto			char *s = (char *)emalloc(strlen(v->text) +
228982502Sroberto			    strlen(valuep) + 2);
229054359Sroberto			const char *t;
229154359Sroberto			char *tt = s;
229254359Sroberto
229354359Sroberto			t = v->text;
229454359Sroberto			while (*t && *t != '=')
229554359Sroberto				*tt++ = *t++;
229654359Sroberto
229754359Sroberto			*tt++ = '=';
229854359Sroberto			strcat(tt, valuep);
229954359Sroberto			set_sys_var(s, strlen(s)+1, v->flags);
230054359Sroberto			free(s);
230154359Sroberto		} else {
230254359Sroberto			/*
230382502Sroberto			 * This one seems sane. Save it.
230454359Sroberto			 */
230554359Sroberto			switch(v->code) {
230682502Sroberto
230782502Sroberto			case CS_LEAP:
230882502Sroberto			default:
230982502Sroberto				ctl_error(CERR_UNSPEC); /* really */
231054359Sroberto				return;
231154359Sroberto			}
231254359Sroberto		}
231354359Sroberto	}
231454359Sroberto
231554359Sroberto	/*
231682502Sroberto	 * If we got anything, do it. xxx nothing to do ***
231754359Sroberto	 */
231854359Sroberto	/*
231954359Sroberto	  if (leapind != ~0 || leapwarn != ~0) {
232054359Sroberto	  	if (!leap_setleap((int)leapind, (int)leapwarn)) {
232154359Sroberto	  		ctl_error(CERR_PERMISSION);
232254359Sroberto	  		return;
232354359Sroberto	  	}
232454359Sroberto	  }
232554359Sroberto	*/
232654359Sroberto	ctl_flushpkt(0);
232754359Sroberto}
232854359Sroberto
232954359Sroberto
233054359Sroberto/*
233154359Sroberto * read_clock_status - return clock radio status
233254359Sroberto */
233354359Sroberto/*ARGSUSED*/
233454359Srobertostatic void
233554359Srobertoread_clock_status(
233654359Sroberto	struct recvbuf *rbufp,
233754359Sroberto	int restrict_mask
233854359Sroberto	)
233954359Sroberto{
234054359Sroberto#ifndef REFCLOCK
234154359Sroberto	/*
234254359Sroberto	 * If no refclock support, no data to return
234354359Sroberto	 */
234454359Sroberto	ctl_error(CERR_BADASSOC);
234554359Sroberto#else
234654359Sroberto	register struct ctl_var *v;
234754359Sroberto	register int i;
234854359Sroberto	register struct peer *peer;
234954359Sroberto	char *valuep;
235054359Sroberto	u_char *wants;
235154359Sroberto	unsigned int gotvar;
235254359Sroberto	struct refclockstat clock_stat;
235354359Sroberto
235454359Sroberto	if (res_associd == 0) {
235582502Sroberto
235654359Sroberto		/*
235754359Sroberto		 * Find a clock for this jerk.	If the system peer
235854359Sroberto		 * is a clock use it, else search the hash tables
235954359Sroberto		 * for one.
236054359Sroberto		 */
236182502Sroberto		if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK))
236282502Sroberto		    {
236354359Sroberto			peer = sys_peer;
236454359Sroberto		} else {
236554359Sroberto			peer = 0;
2366182007Sroberto			for (i = 0; peer == 0 && i < NTP_HASH_SIZE; i++) {
236754359Sroberto				for (peer = assoc_hash[i]; peer != 0;
236882502Sroberto					peer = peer->ass_next) {
236954359Sroberto					if (peer->flags & FLAG_REFCLOCK)
237054359Sroberto						break;
237154359Sroberto				}
237254359Sroberto			}
237354359Sroberto			if (peer == 0) {
237454359Sroberto				ctl_error(CERR_BADASSOC);
237554359Sroberto				return;
237654359Sroberto			}
237754359Sroberto		}
237854359Sroberto	} else {
237982502Sroberto		peer = findpeerbyassoc(res_associd);
238054359Sroberto		if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) {
238154359Sroberto			ctl_error(CERR_BADASSOC);
238254359Sroberto			return;
238354359Sroberto		}
238454359Sroberto	}
238554359Sroberto
238654359Sroberto	/*
238782502Sroberto	 * If we got here we have a peer which is a clock. Get his
238882502Sroberto	 * status.
238954359Sroberto	 */
239054359Sroberto	clock_stat.kv_list = (struct ctl_var *)0;
239182502Sroberto	refclock_control(&peer->srcadr, (struct refclockstat *)0,
239282502Sroberto	    &clock_stat);
239354359Sroberto
239454359Sroberto	/*
239554359Sroberto	 * Look for variables in the packet.
239654359Sroberto	 */
239754359Sroberto	rpkt.status = htons(ctlclkstatus(&clock_stat));
239882502Sroberto	gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list);
239954359Sroberto	wants = (u_char *)emalloc(gotvar);
240054359Sroberto	memset((char*)wants, 0, gotvar);
240154359Sroberto	gotvar = 0;
240254359Sroberto	while ((v = ctl_getitem(clock_var, &valuep)) != 0) {
240354359Sroberto		if (v->flags & EOV) {
240482502Sroberto			if ((v = ctl_getitem(clock_stat.kv_list,
240582502Sroberto			    &valuep)) != 0) {
240654359Sroberto				if (v->flags & EOV) {
240754359Sroberto					ctl_error(CERR_UNKNOWNVAR);
240854359Sroberto					free((char*)wants);
240954359Sroberto					free_varlist(clock_stat.kv_list);
241054359Sroberto					return;
241154359Sroberto				}
241282502Sroberto				wants[CC_MAXCODE + 1 + v->code] = 1;
241354359Sroberto				gotvar = 1;
241454359Sroberto				continue;
241554359Sroberto			} else {
241654359Sroberto				break; /* shouldn't happen ! */
241754359Sroberto			}
241854359Sroberto		}
241954359Sroberto		wants[v->code] = 1;
242054359Sroberto		gotvar = 1;
242154359Sroberto	}
242254359Sroberto
242354359Sroberto	if (gotvar) {
242454359Sroberto		for (i = 1; i <= CC_MAXCODE; i++)
242554359Sroberto			if (wants[i])
242654359Sroberto			ctl_putclock(i, &clock_stat, 1);
242782502Sroberto		for (i = 0; clock_stat.kv_list &&
242882502Sroberto		    !(clock_stat.kv_list[i].flags & EOV); i++)
242982502Sroberto			if (wants[i + CC_MAXCODE + 1])
243082502Sroberto				ctl_putdata(clock_stat.kv_list[i].text,
243182502Sroberto				    strlen(clock_stat.kv_list[i].text),
243282502Sroberto				    0);
243354359Sroberto	} else {
243454359Sroberto		register u_char *cc;
243554359Sroberto		register struct ctl_var *kv;
243654359Sroberto
243754359Sroberto		for (cc = def_clock_var; *cc != 0; cc++)
243854359Sroberto			ctl_putclock((int)*cc, &clock_stat, 0);
243982502Sroberto		for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV);
244082502Sroberto		    kv++)
244154359Sroberto			if (kv->flags & DEF)
244282502Sroberto				ctl_putdata(kv->text, strlen(kv->text),
244382502Sroberto				    0);
244454359Sroberto	}
244554359Sroberto
244654359Sroberto	free((char*)wants);
244754359Sroberto	free_varlist(clock_stat.kv_list);
244854359Sroberto
244954359Sroberto	ctl_flushpkt(0);
245054359Sroberto#endif
245154359Sroberto}
245254359Sroberto
245354359Sroberto
245454359Sroberto/*
245554359Sroberto * write_clock_status - we don't do this
245654359Sroberto */
245754359Sroberto/*ARGSUSED*/
245854359Srobertostatic void
245954359Srobertowrite_clock_status(
246054359Sroberto	struct recvbuf *rbufp,
246154359Sroberto	int restrict_mask
246254359Sroberto	)
246354359Sroberto{
246454359Sroberto	ctl_error(CERR_PERMISSION);
246554359Sroberto}
246654359Sroberto
246754359Sroberto/*
246882502Sroberto * Trap support from here on down. We send async trap messages when the
246982502Sroberto * upper levels report trouble. Traps can by set either by control
247054359Sroberto * messages or by configuration.
247154359Sroberto */
247254359Sroberto/*
247354359Sroberto * set_trap - set a trap in response to a control message
247454359Sroberto */
247554359Srobertostatic void
247654359Srobertoset_trap(
247754359Sroberto	struct recvbuf *rbufp,
247854359Sroberto	int restrict_mask
247954359Sroberto	)
248054359Sroberto{
248154359Sroberto	int traptype;
248254359Sroberto
248354359Sroberto	/*
248454359Sroberto	 * See if this guy is allowed
248554359Sroberto	 */
248654359Sroberto	if (restrict_mask & RES_NOTRAP) {
248754359Sroberto		ctl_error(CERR_PERMISSION);
248854359Sroberto		return;
248954359Sroberto	}
249054359Sroberto
249154359Sroberto	/*
249254359Sroberto	 * Determine his allowed trap type.
249354359Sroberto	 */
249454359Sroberto	traptype = TRAP_TYPE_PRIO;
249554359Sroberto	if (restrict_mask & RES_LPTRAP)
249654359Sroberto		traptype = TRAP_TYPE_NONPRIO;
249754359Sroberto
249854359Sroberto	/*
249954359Sroberto	 * Call ctlsettrap() to do the work.  Return
250054359Sroberto	 * an error if it can't assign the trap.
250154359Sroberto	 */
250254359Sroberto	if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype,
250382502Sroberto	    (int)res_version))
250454359Sroberto		ctl_error(CERR_NORESOURCE);
250554359Sroberto	ctl_flushpkt(0);
250654359Sroberto}
250754359Sroberto
250854359Sroberto
250954359Sroberto/*
251054359Sroberto * unset_trap - unset a trap in response to a control message
251154359Sroberto */
251254359Srobertostatic void
251354359Srobertounset_trap(
251454359Sroberto	struct recvbuf *rbufp,
251554359Sroberto	int restrict_mask
251654359Sroberto	)
251754359Sroberto{
251854359Sroberto	int traptype;
251954359Sroberto
252054359Sroberto	/*
252182502Sroberto	 * We don't prevent anyone from removing his own trap unless the
252282502Sroberto	 * trap is configured. Note we also must be aware of the
252382502Sroberto	 * possibility that restriction flags were changed since this
252482502Sroberto	 * guy last set his trap. Set the trap type based on this.
252554359Sroberto	 */
252654359Sroberto	traptype = TRAP_TYPE_PRIO;
252754359Sroberto	if (restrict_mask & RES_LPTRAP)
252854359Sroberto		traptype = TRAP_TYPE_NONPRIO;
252954359Sroberto
253054359Sroberto	/*
253154359Sroberto	 * Call ctlclrtrap() to clear this out.
253254359Sroberto	 */
253354359Sroberto	if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype))
253454359Sroberto		ctl_error(CERR_BADASSOC);
253554359Sroberto	ctl_flushpkt(0);
253654359Sroberto}
253754359Sroberto
253854359Sroberto
253954359Sroberto/*
254054359Sroberto * ctlsettrap - called to set a trap
254154359Sroberto */
254254359Srobertoint
254354359Srobertoctlsettrap(
2544132455Sroberto	struct sockaddr_storage *raddr,
254554359Sroberto	struct interface *linter,
254654359Sroberto	int traptype,
254754359Sroberto	int version
254854359Sroberto	)
254954359Sroberto{
255054359Sroberto	register struct ctl_trap *tp;
255154359Sroberto	register struct ctl_trap *tptouse;
255254359Sroberto
255354359Sroberto	/*
255454359Sroberto	 * See if we can find this trap.  If so, we only need update
255554359Sroberto	 * the flags and the time.
255654359Sroberto	 */
255754359Sroberto	if ((tp = ctlfindtrap(raddr, linter)) != NULL) {
255854359Sroberto		switch (traptype) {
255982502Sroberto
256082502Sroberto		case TRAP_TYPE_CONFIG:
256154359Sroberto			tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED;
256254359Sroberto			break;
256382502Sroberto
256482502Sroberto		case TRAP_TYPE_PRIO:
256554359Sroberto			if (tp->tr_flags & TRAP_CONFIGURED)
256682502Sroberto				return (1); /* don't change anything */
256754359Sroberto			tp->tr_flags = TRAP_INUSE;
256854359Sroberto			break;
256982502Sroberto
257082502Sroberto		case TRAP_TYPE_NONPRIO:
257154359Sroberto			if (tp->tr_flags & TRAP_CONFIGURED)
257282502Sroberto				return (1); /* don't change anything */
257354359Sroberto			tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO;
257454359Sroberto			break;
257554359Sroberto		}
257654359Sroberto		tp->tr_settime = current_time;
257754359Sroberto		tp->tr_resets++;
257882502Sroberto		return (1);
257954359Sroberto	}
258054359Sroberto
258154359Sroberto	/*
258254359Sroberto	 * First we heard of this guy.	Try to find a trap structure
258354359Sroberto	 * for him to use, clearing out lesser priority guys if we
258482502Sroberto	 * have to. Clear out anyone who's expired while we're at it.
258554359Sroberto	 */
258654359Sroberto	tptouse = NULL;
258754359Sroberto	for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
258854359Sroberto		if ((tp->tr_flags & TRAP_INUSE) &&
258982502Sroberto		    !(tp->tr_flags & TRAP_CONFIGURED) &&
259082502Sroberto		    ((tp->tr_settime + CTL_TRAPTIME) > current_time)) {
259154359Sroberto			tp->tr_flags = 0;
259254359Sroberto			num_ctl_traps--;
259354359Sroberto		}
259454359Sroberto		if (!(tp->tr_flags & TRAP_INUSE)) {
259554359Sroberto			tptouse = tp;
259654359Sroberto		} else if (!(tp->tr_flags & TRAP_CONFIGURED)) {
259754359Sroberto			switch (traptype) {
259882502Sroberto
259982502Sroberto			case TRAP_TYPE_CONFIG:
260054359Sroberto				if (tptouse == NULL) {
260154359Sroberto					tptouse = tp;
260254359Sroberto					break;
260354359Sroberto				}
260482502Sroberto				if (tptouse->tr_flags & TRAP_NONPRIO &&
260582502Sroberto				    !(tp->tr_flags & TRAP_NONPRIO))
260654359Sroberto					break;
260782502Sroberto
260854359Sroberto				if (!(tptouse->tr_flags & TRAP_NONPRIO)
260982502Sroberto				    && tp->tr_flags & TRAP_NONPRIO) {
261054359Sroberto					tptouse = tp;
261154359Sroberto					break;
261254359Sroberto				}
261382502Sroberto				if (tptouse->tr_origtime <
261482502Sroberto				    tp->tr_origtime)
261554359Sroberto					tptouse = tp;
261654359Sroberto				break;
261782502Sroberto
261882502Sroberto			case TRAP_TYPE_PRIO:
261954359Sroberto				if (tp->tr_flags & TRAP_NONPRIO) {
262054359Sroberto					if (tptouse == NULL ||
262182502Sroberto					    (tptouse->tr_flags &
262282502Sroberto					    TRAP_INUSE &&
262382502Sroberto					    tptouse->tr_origtime <
262482502Sroberto					    tp->tr_origtime))
262554359Sroberto						tptouse = tp;
262654359Sroberto				}
262754359Sroberto				break;
262882502Sroberto
262982502Sroberto			case TRAP_TYPE_NONPRIO:
263054359Sroberto				break;
263154359Sroberto			}
263254359Sroberto		}
263354359Sroberto	}
263454359Sroberto
263554359Sroberto	/*
263654359Sroberto	 * If we don't have room for him return an error.
263754359Sroberto	 */
263854359Sroberto	if (tptouse == NULL)
263982502Sroberto		return (0);
264054359Sroberto
264154359Sroberto	/*
264254359Sroberto	 * Set up this structure for him.
264354359Sroberto	 */
264454359Sroberto	tptouse->tr_settime = tptouse->tr_origtime = current_time;
264554359Sroberto	tptouse->tr_count = tptouse->tr_resets = 0;
264654359Sroberto	tptouse->tr_sequence = 1;
264754359Sroberto	tptouse->tr_addr = *raddr;
264854359Sroberto	tptouse->tr_localaddr = linter;
2649132455Sroberto	tptouse->tr_version = (u_char) version;
265054359Sroberto	tptouse->tr_flags = TRAP_INUSE;
265154359Sroberto	if (traptype == TRAP_TYPE_CONFIG)
265254359Sroberto		tptouse->tr_flags |= TRAP_CONFIGURED;
265354359Sroberto	else if (traptype == TRAP_TYPE_NONPRIO)
265454359Sroberto		tptouse->tr_flags |= TRAP_NONPRIO;
265554359Sroberto	num_ctl_traps++;
265682502Sroberto	return (1);
265754359Sroberto}
265854359Sroberto
265954359Sroberto
266054359Sroberto/*
266182502Sroberto * ctlclrtrap - called to clear a trap
266254359Sroberto */
266354359Srobertoint
266454359Srobertoctlclrtrap(
2665132455Sroberto	struct sockaddr_storage *raddr,
266654359Sroberto	struct interface *linter,
266754359Sroberto	int traptype
266854359Sroberto	)
266954359Sroberto{
267054359Sroberto	register struct ctl_trap *tp;
267154359Sroberto
267254359Sroberto	if ((tp = ctlfindtrap(raddr, linter)) == NULL)
267382502Sroberto		return (0);
267454359Sroberto
267554359Sroberto	if (tp->tr_flags & TRAP_CONFIGURED
267654359Sroberto		&& traptype != TRAP_TYPE_CONFIG)
267782502Sroberto		return (0);
267854359Sroberto
267954359Sroberto	tp->tr_flags = 0;
268054359Sroberto	num_ctl_traps--;
268182502Sroberto	return (1);
268254359Sroberto}
268354359Sroberto
268454359Sroberto
268554359Sroberto/*
268654359Sroberto * ctlfindtrap - find a trap given the remote and local addresses
268754359Sroberto */
268854359Srobertostatic struct ctl_trap *
268954359Srobertoctlfindtrap(
2690132455Sroberto	struct sockaddr_storage *raddr,
269154359Sroberto	struct interface *linter
269254359Sroberto	)
269354359Sroberto{
269454359Sroberto	register struct ctl_trap *tp;
269554359Sroberto
269654359Sroberto	for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
2697132455Sroberto		if ((tp->tr_flags & TRAP_INUSE)
2698132455Sroberto		    && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr))
2699132455Sroberto		    && SOCKCMP(raddr, &tp->tr_addr)
2700132455Sroberto	 	    && (linter == tp->tr_localaddr) )
2701132455Sroberto		return (tp);
270254359Sroberto	}
270354359Sroberto	return (struct ctl_trap *)NULL;
270454359Sroberto}
270554359Sroberto
270654359Sroberto
270754359Sroberto/*
270854359Sroberto * report_event - report an event to the trappers
270954359Sroberto */
271054359Srobertovoid
271154359Srobertoreport_event(
271254359Sroberto	int err,
271354359Sroberto	struct peer *peer
271454359Sroberto	)
271554359Sroberto{
271654359Sroberto	register int i;
271754359Sroberto
271854359Sroberto	/*
271954359Sroberto	 * Record error code in proper spots, but have mercy on the
272054359Sroberto	 * log file.
272154359Sroberto	 */
2722132455Sroberto	if (!(err & (PEER_EVENT | CRPT_EVENT))) {
272354359Sroberto		if (ctl_sys_num_events < CTL_SYS_MAXEVENTS)
272454359Sroberto			ctl_sys_num_events++;
272554359Sroberto		if (ctl_sys_last_event != (u_char)err) {
272654359Sroberto			NLOG(NLOG_SYSEVENT)
272782502Sroberto			    msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)",
272882502Sroberto			    eventstr(err), err,
272982502Sroberto			    sysstatstr(ctlsysstatus()), ctlsysstatus());
273054359Sroberto#ifdef DEBUG
273154359Sroberto			if (debug)
273254359Sroberto				printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n",
273382502Sroberto				    eventstr(err), err,
273482502Sroberto				    sysstatstr(ctlsysstatus()),
273582502Sroberto				    ctlsysstatus());
273654359Sroberto#endif
273754359Sroberto			ctl_sys_last_event = (u_char)err;
273854359Sroberto		}
273954359Sroberto	} else if (peer != 0) {
274054359Sroberto		char *src;
274154359Sroberto
274254359Sroberto#ifdef REFCLOCK
274354359Sroberto		if (ISREFCLOCKADR(&peer->srcadr))
2744132455Sroberto			src = refnumtoa(&peer->srcadr);
274554359Sroberto		else
274654359Sroberto#endif
2747132455Sroberto			src = stoa(&peer->srcadr);
274854359Sroberto
274954359Sroberto		peer->last_event = (u_char)(err & ~PEER_EVENT);
275054359Sroberto		if (peer->num_events < CTL_PEER_MAXEVENTS)
275154359Sroberto			peer->num_events++;
275254359Sroberto		NLOG(NLOG_PEEREVENT)
275382502Sroberto		    msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)",
275482502Sroberto		    src, eventstr(err), err,
275582502Sroberto		    peerstatstr(ctlpeerstatus(peer)),
275682502Sroberto		    ctlpeerstatus(peer));
275754359Sroberto#ifdef DEBUG
275854359Sroberto		if (debug)
275954359Sroberto			printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n",
276082502Sroberto			    src, eventstr(err), err,
276182502Sroberto			    peerstatstr(ctlpeerstatus(peer)),
276282502Sroberto			    ctlpeerstatus(peer));
276354359Sroberto#endif
276454359Sroberto	} else {
276582502Sroberto		msyslog(LOG_ERR,
276682502Sroberto		    "report_event: err '%s' (0x%02x), no peer",
276782502Sroberto		    eventstr(err), err);
276854359Sroberto#ifdef DEBUG
276982502Sroberto		printf(
277082502Sroberto		    "report_event: peer event '%s' (0x%02x), no peer\n",
277182502Sroberto		    eventstr(err), err);
277254359Sroberto#endif
277354359Sroberto		return;
277454359Sroberto	}
277554359Sroberto
277654359Sroberto	/*
277754359Sroberto	 * If no trappers, return.
277854359Sroberto	 */
277954359Sroberto	if (num_ctl_traps <= 0)
278054359Sroberto		return;
278154359Sroberto
278254359Sroberto	/*
278354359Sroberto	 * Set up the outgoing packet variables
278454359Sroberto	 */
278554359Sroberto	res_opcode = CTL_OP_ASYNCMSG;
278654359Sroberto	res_offset = 0;
278754359Sroberto	res_async = 1;
278854359Sroberto	res_authenticate = 0;
278954359Sroberto	datapt = rpkt.data;
279054359Sroberto	dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
279154359Sroberto	if (!(err & PEER_EVENT)) {
279254359Sroberto		rpkt.associd = 0;
279354359Sroberto		rpkt.status = htons(ctlsysstatus());
279454359Sroberto
279554359Sroberto		/*
279654359Sroberto		 * For now, put everything we know about system
279782502Sroberto		 * variables. Don't send crypto strings.
279854359Sroberto		 */
279982502Sroberto		for (i = 1; i <= CS_MAXCODE; i++) {
2800132455Sroberto#ifdef OPENSSL
280182502Sroberto			if (i > CS_VARLIST)
280282502Sroberto				continue;
2803132455Sroberto#endif /* OPENSSL */
280454359Sroberto			ctl_putsys(i);
280582502Sroberto		}
280654359Sroberto#ifdef REFCLOCK
280754359Sroberto		/*
280882502Sroberto		 * for clock exception events: add clock variables to
280982502Sroberto		 * reflect info on exception
281054359Sroberto		 */
281154359Sroberto		if (err == EVNT_CLOCKEXCPT) {
281254359Sroberto			struct refclockstat clock_stat;
281354359Sroberto			struct ctl_var *kv;
281454359Sroberto
281554359Sroberto			clock_stat.kv_list = (struct ctl_var *)0;
281654359Sroberto			refclock_control(&peer->srcadr,
281782502Sroberto			    (struct refclockstat *)0, &clock_stat);
281882502Sroberto			ctl_puthex("refclockstatus",
281982502Sroberto			    ctlclkstatus(&clock_stat));
282054359Sroberto			for (i = 1; i <= CC_MAXCODE; i++)
282154359Sroberto				ctl_putclock(i, &clock_stat, 0);
282282502Sroberto			for (kv = clock_stat.kv_list; kv &&
282382502Sroberto			    !(kv->flags & EOV); kv++)
282454359Sroberto				if (kv->flags & DEF)
282582502Sroberto					ctl_putdata(kv->text,
282682502Sroberto					    strlen(kv->text), 0);
282754359Sroberto			free_varlist(clock_stat.kv_list);
282854359Sroberto		}
2829132455Sroberto#endif /* REFCLOCK */
283054359Sroberto	} else {
283154359Sroberto		rpkt.associd = htons(peer->associd);
283254359Sroberto		rpkt.status = htons(ctlpeerstatus(peer));
283354359Sroberto
283454359Sroberto		/*
283582502Sroberto		 * Dump it all. Later, maybe less.
283654359Sroberto		 */
2837132455Sroberto		for (i = 1; i <= CP_MAXCODE; i++) {
2838132455Sroberto#ifdef OPENSSL
283982502Sroberto			if (i > CP_VARLIST)
284082502Sroberto				continue;
2841132455Sroberto#endif /* OPENSSL */
284254359Sroberto			ctl_putpeer(i, peer);
2843132455Sroberto		}
284454359Sroberto#ifdef REFCLOCK
284554359Sroberto		/*
284682502Sroberto		 * for clock exception events: add clock variables to
284782502Sroberto		 * reflect info on exception
284854359Sroberto		 */
284954359Sroberto		if (err == EVNT_PEERCLOCK) {
285054359Sroberto			struct refclockstat clock_stat;
285154359Sroberto			struct ctl_var *kv;
285254359Sroberto
285354359Sroberto			clock_stat.kv_list = (struct ctl_var *)0;
285454359Sroberto			refclock_control(&peer->srcadr,
285582502Sroberto			    (struct refclockstat *)0, &clock_stat);
285654359Sroberto
285754359Sroberto			ctl_puthex("refclockstatus",
285882502Sroberto			    ctlclkstatus(&clock_stat));
285954359Sroberto
286054359Sroberto			for (i = 1; i <= CC_MAXCODE; i++)
286154359Sroberto				ctl_putclock(i, &clock_stat, 0);
286282502Sroberto			for (kv = clock_stat.kv_list; kv &&
286382502Sroberto			    !(kv->flags & EOV); kv++)
286454359Sroberto				if (kv->flags & DEF)
286582502Sroberto					ctl_putdata(kv->text,
286682502Sroberto					    strlen(kv->text), 0);
286754359Sroberto			free_varlist(clock_stat.kv_list);
286854359Sroberto		}
2869132455Sroberto#endif /* REFCLOCK */
287054359Sroberto	}
287154359Sroberto
287254359Sroberto	/*
287354359Sroberto	 * We're done, return.
287454359Sroberto	 */
287554359Sroberto	ctl_flushpkt(0);
287654359Sroberto}
287754359Sroberto
287854359Sroberto
287954359Sroberto/*
288054359Sroberto * ctl_clr_stats - clear stat counters
288154359Sroberto */
288254359Srobertovoid
288354359Srobertoctl_clr_stats(void)
288454359Sroberto{
288554359Sroberto	ctltimereset = current_time;
288654359Sroberto	numctlreq = 0;
288754359Sroberto	numctlbadpkts = 0;
288854359Sroberto	numctlresponses = 0;
288954359Sroberto	numctlfrags = 0;
289054359Sroberto	numctlerrors = 0;
289154359Sroberto	numctlfrags = 0;
289254359Sroberto	numctltooshort = 0;
289354359Sroberto	numctlinputresp = 0;
289454359Sroberto	numctlinputfrag = 0;
289554359Sroberto	numctlinputerr = 0;
289654359Sroberto	numctlbadoffset = 0;
289754359Sroberto	numctlbadversion = 0;
289854359Sroberto	numctldatatooshort = 0;
289954359Sroberto	numctlbadop = 0;
290054359Sroberto	numasyncmsgs = 0;
290154359Sroberto}
290254359Sroberto
290354359Srobertostatic u_long
290454359Srobertocount_var(
290554359Sroberto	struct ctl_var *k
290654359Sroberto	)
290754359Sroberto{
290854359Sroberto	register u_long c;
290954359Sroberto
291054359Sroberto	if (!k)
291182502Sroberto		return (0);
291254359Sroberto
291354359Sroberto	c = 0;
291454359Sroberto	while (!(k++->flags & EOV))
291582502Sroberto		c++;
291682502Sroberto	return (c);
291754359Sroberto}
291854359Sroberto
291954359Srobertochar *
292054359Srobertoadd_var(
292154359Sroberto	struct ctl_var **kv,
292254359Sroberto	u_long size,
2923132455Sroberto	u_short def
292454359Sroberto	)
292554359Sroberto{
292654359Sroberto	register u_long c;
292754359Sroberto	register struct ctl_var *k;
292854359Sroberto
292954359Sroberto	c = count_var(*kv);
293054359Sroberto
293154359Sroberto	k = *kv;
293254359Sroberto	*kv  = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var));
293382502Sroberto	if (k) {
293482502Sroberto		memmove((char *)*kv, (char *)k,
293582502Sroberto		    sizeof(struct ctl_var)*c);
293654359Sroberto		free((char *)k);
293754359Sroberto	}
293854359Sroberto	(*kv)[c].code  = (u_short) c;
293954359Sroberto	(*kv)[c].text  = (char *)emalloc(size);
294054359Sroberto	(*kv)[c].flags = def;
294154359Sroberto	(*kv)[c+1].code  = 0;
294254359Sroberto	(*kv)[c+1].text  = (char *)0;
294354359Sroberto	(*kv)[c+1].flags = EOV;
294454359Sroberto	return (char *)(*kv)[c].text;
294554359Sroberto}
294654359Sroberto
294754359Srobertovoid
294854359Srobertoset_var(
294954359Sroberto	struct ctl_var **kv,
295054359Sroberto	const char *data,
295154359Sroberto	u_long size,
2952132455Sroberto	u_short def
295354359Sroberto	)
295454359Sroberto{
295554359Sroberto	register struct ctl_var *k;
295654359Sroberto	register const char *s;
295754359Sroberto	register const char *t;
295854359Sroberto	char *td;
295954359Sroberto
296054359Sroberto	if (!data || !size)
296154359Sroberto		return;
296254359Sroberto
2963132455Sroberto	k = *kv;
2964132455Sroberto	if (k != NULL) {
296582502Sroberto		while (!(k->flags & EOV)) {
296654359Sroberto			s = data;
296754359Sroberto			t = k->text;
296882502Sroberto			if (t)	{
296982502Sroberto				while (*t != '=' && *s - *t == 0) {
297054359Sroberto					s++;
297154359Sroberto					t++;
297254359Sroberto				}
297382502Sroberto				if (*s == *t && ((*t == '=') || !*t)) {
297454359Sroberto					free((void *)k->text);
297554359Sroberto					td = (char *)emalloc(size);
297654359Sroberto					memmove(td, data, size);
297754359Sroberto					k->text =td;
297854359Sroberto					k->flags = def;
297954359Sroberto					return;
298054359Sroberto				}
298182502Sroberto			} else {
298254359Sroberto				td = (char *)emalloc(size);
298354359Sroberto				memmove(td, data, size);
298454359Sroberto				k->text = td;
298554359Sroberto				k->flags = def;
298654359Sroberto				return;
298754359Sroberto			}
298854359Sroberto			k++;
298954359Sroberto		}
299054359Sroberto	}
299154359Sroberto	td = add_var(kv, size, def);
299254359Sroberto	memmove(td, data, size);
299354359Sroberto}
299454359Sroberto
299554359Srobertovoid
299654359Srobertoset_sys_var(
2997182007Sroberto	const char *data,
299854359Sroberto	u_long size,
2999132455Sroberto	u_short def
300054359Sroberto	)
300154359Sroberto{
300254359Sroberto	set_var(&ext_sys_var, data, size, def);
300354359Sroberto}
300454359Sroberto
300554359Srobertovoid
300654359Srobertofree_varlist(
300754359Sroberto	struct ctl_var *kv
300854359Sroberto	)
300954359Sroberto{
301054359Sroberto	struct ctl_var *k;
301182502Sroberto	if (kv) {
301254359Sroberto		for (k = kv; !(k->flags & EOV); k++)
301382502Sroberto			free((void *)k->text);
301454359Sroberto		free((void *)kv);
301554359Sroberto	}
301654359Sroberto}
3017