PageRenderTime 134ms CodeModel.GetById 14ms app.highlight 106ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/ntpd/ntp_control.c

https://bitbucket.org/freebsd/freebsd-head/
C | 3001 lines | 2635 code | 176 blank | 190 comment | 192 complexity | 8771b3cd377989ab6c93879321f7f61e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file