ntpq.c revision 293896
1/*
2 * ntpq - query an NTP server using mode 6 commands
3 */
4#include <config.h>
5#include <stdio.h>
6#include <ctype.h>
7#include <signal.h>
8#include <setjmp.h>
9#include <sys/types.h>
10#include <sys/time.h>
11#ifdef HAVE_UNISTD_H
12# include <unistd.h>
13#endif
14#ifdef HAVE_FCNTL_H
15# include <fcntl.h>
16#endif
17#ifdef SYS_WINNT
18# include <mswsock.h>
19#endif
20#include <isc/net.h>
21#include <isc/result.h>
22
23#include "ntpq.h"
24#include "ntp_assert.h"
25#include "ntp_stdlib.h"
26#include "ntp_unixtime.h"
27#include "ntp_calendar.h"
28#include "ntp_select.h"
29#include "ntp_assert.h"
30#include "lib_strbuf.h"
31#include "ntp_lineedit.h"
32#include "ntp_debug.h"
33#ifdef OPENSSL
34#include "openssl/evp.h"
35#include "openssl/objects.h"
36#include "openssl/err.h"
37#endif
38#include <ssl_applink.c>
39
40#include "ntp_libopts.h"
41#include "ntpq-opts.h"
42#include "safecast.h"
43
44#ifdef SYS_VXWORKS		/* vxWorks needs mode flag -casey*/
45# define open(name, flags)   open(name, flags, 0777)
46# define SERVER_PORT_NUM     123
47#endif
48
49/* we use COMMAND as an autogen keyword */
50#ifdef COMMAND
51# undef COMMAND
52#endif
53
54/*
55 * Because we potentially understand a lot of commands we will run
56 * interactive if connected to a terminal.
57 */
58int interactive = 0;		/* set to 1 when we should prompt */
59const char *prompt = "ntpq> ";	/* prompt to ask him about */
60
61/*
62 * use old readvars behavior?  --old-rv processing in ntpq resets
63 * this value based on the presence or absence of --old-rv.  It is
64 * initialized to 1 here to maintain backward compatibility with
65 * libntpq clients such as ntpsnmpd, which are free to reset it as
66 * desired.
67 */
68int	old_rv = 1;
69
70
71/*
72 * for get_systime()
73 */
74s_char	sys_precision;		/* local clock precision (log2 s) */
75
76/*
77 * Keyid used for authenticated requests.  Obtained on the fly.
78 */
79u_long info_auth_keyid = 0;
80
81static	int	info_auth_keytype = NID_md5;	/* MD5 */
82static	size_t	info_auth_hashlen = 16;		/* MD5 */
83u_long	current_time;		/* needed by authkeys; not used */
84
85/*
86 * Flag which indicates we should always send authenticated requests
87 */
88int always_auth = 0;
89
90/*
91 * Flag which indicates raw mode output.
92 */
93int rawmode = 0;
94
95/*
96 * Packet version number we use
97 */
98u_char pktversion = NTP_OLDVERSION + 1;
99
100/*
101 * Don't jump if no set jmp.
102 */
103volatile int jump = 0;
104
105/*
106 * Format values
107 */
108#define	PADDING	0
109#define	HA	1	/* host address */
110#define	NA	2	/* network address */
111#define	LP	3	/* leap (print in binary) */
112#define	RF	4	/* refid (sometimes string, sometimes not) */
113#define	AR	5	/* array of times */
114#define FX	6	/* test flags */
115#define TS	7	/* l_fp timestamp in hex */
116#define	OC	8	/* integer, print in octal */
117#define	EOV	255	/* end of table */
118
119/*
120 * For the most part ntpq simply displays what ntpd provides in the
121 * mostly plain-text mode 6 responses.  A few variable names are by
122 * default "cooked" to provide more human-friendly output.
123 */
124const var_format cookedvars[] = {
125	{ "leap",		LP },
126	{ "reach",		OC },
127	{ "refid",		RF },
128	{ "reftime",		TS },
129	{ "clock",		TS },
130	{ "org",		TS },
131	{ "rec",		TS },
132	{ "xmt",		TS },
133	{ "flash",		FX },
134	{ "srcadr",		HA },
135	{ "peeradr",		HA },	/* compat with others */
136	{ "dstadr",		NA },
137	{ "filtdelay",		AR },
138	{ "filtoffset",		AR },
139	{ "filtdisp",		AR },
140	{ "filterror",		AR },	/* compat with others */
141};
142
143
144
145/*
146 * flasher bits
147 */
148static const char *tstflagnames[] = {
149	"pkt_dup",		/* TEST1 */
150	"pkt_bogus",		/* TEST2 */
151	"pkt_unsync",		/* TEST3 */
152	"pkt_denied",		/* TEST4 */
153	"pkt_auth",		/* TEST5 */
154	"pkt_stratum",		/* TEST6 */
155	"pkt_header",		/* TEST7 */
156	"pkt_autokey",		/* TEST8 */
157	"pkt_crypto",		/* TEST9 */
158	"peer_stratum",		/* TEST10 */
159	"peer_dist",		/* TEST11 */
160	"peer_loop",		/* TEST12 */
161	"peer_unreach"		/* TEST13 */
162};
163
164
165int		ntpqmain	(int,	char **);
166/*
167 * Built in command handler declarations
168 */
169static	int	openhost	(const char *, int);
170static	void	dump_hex_printable(const void *, size_t);
171static	int	sendpkt		(void *, size_t);
172static	int	getresponse	(int, int, u_short *, size_t *, const char **, int);
173static	int	sendrequest	(int, associd_t, int, size_t, const char *);
174static	char *	tstflags	(u_long);
175#ifndef BUILD_AS_LIB
176static	void	getcmds		(void);
177#ifndef SYS_WINNT
178static	int	abortcmd	(void);
179#endif	/* SYS_WINNT */
180static	void	docmd		(const char *);
181static	void	tokenize	(const char *, char **, int *);
182static	int	getarg		(const char *, int, arg_v *);
183#endif	/* BUILD_AS_LIB */
184static	int	findcmd		(const char *, struct xcmd *,
185				 struct xcmd *, struct xcmd **);
186static	int	rtdatetolfp	(char *, l_fp *);
187static	int	decodearr	(char *, int *, l_fp *);
188static	void	help		(struct parse *, FILE *);
189static	int	helpsort	(const void *, const void *);
190static	void	printusage	(struct xcmd *, FILE *);
191static	void	timeout		(struct parse *, FILE *);
192static	void	auth_delay	(struct parse *, FILE *);
193static	void	host		(struct parse *, FILE *);
194static	void	ntp_poll	(struct parse *, FILE *);
195static	void	keyid		(struct parse *, FILE *);
196static	void	keytype		(struct parse *, FILE *);
197static	void	passwd		(struct parse *, FILE *);
198static	void	hostnames	(struct parse *, FILE *);
199static	void	setdebug	(struct parse *, FILE *);
200static	void	quit		(struct parse *, FILE *);
201static	void	version		(struct parse *, FILE *);
202static	void	raw		(struct parse *, FILE *);
203static	void	cooked		(struct parse *, FILE *);
204static	void	authenticate	(struct parse *, FILE *);
205static	void	ntpversion	(struct parse *, FILE *);
206static	void	warning		(const char *, ...)
207    __attribute__((__format__(__printf__, 1, 2)));
208static	void	error		(const char *, ...)
209    __attribute__((__format__(__printf__, 1, 2)));
210static	u_long	getkeyid	(const char *);
211static	void	atoascii	(const char *, size_t, char *, size_t);
212static	void	cookedprint	(int, size_t, const char *, int, int, FILE *);
213static	void	rawprint	(int, size_t, const char *, int, int, FILE *);
214static	void	startoutput	(void);
215static	void	output		(FILE *, const char *, const char *);
216static	void	endoutput	(FILE *);
217static	void	outputarr	(FILE *, char *, int, l_fp *);
218static	int	assoccmp	(const void *, const void *);
219static	void	on_ctrlc	(void);
220	u_short	varfmt		(const char *);
221
222void	ntpq_custom_opt_handler	(tOptions *, tOptDesc *);
223
224#ifdef OPENSSL
225# ifdef HAVE_EVP_MD_DO_ALL_SORTED
226static void list_md_fn(const EVP_MD *m, const char *from,
227		       const char *to, void *arg );
228# endif
229#endif
230static char *list_digest_names(void);
231
232/*
233 * Built-in commands we understand
234 */
235struct xcmd builtins[] = {
236	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
237	  { "command", "", "", "" },
238	  "tell the use and syntax of commands" },
239	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
240	  { "command", "", "", "" },
241	  "tell the use and syntax of commands" },
242	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
243	  { "msec", "", "", "" },
244	  "set the primary receive time out" },
245	{ "delay",	auth_delay,	{ OPT|NTP_INT, NO, NO, NO },
246	  { "msec", "", "", "" },
247	  "set the delay added to encryption time stamps" },
248	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
249	  { "-4|-6", "hostname", "", "" },
250	  "specify the host whose NTP server we talk to" },
251	{ "poll",	ntp_poll,	{ OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
252	  { "n", "verbose", "", "" },
253	  "poll an NTP server in client mode `n' times" },
254	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
255	  { "", "", "", "" },
256	  "specify a password to use for authenticated requests"},
257	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
258	  { "yes|no", "", "", "" },
259	  "specify whether hostnames or net numbers are printed"},
260	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
261	  { "no|more|less", "", "", "" },
262	  "set/change debugging level" },
263	{ "quit",	quit,		{ NO, NO, NO, NO },
264	  { "", "", "", "" },
265	  "exit ntpq" },
266	{ "exit",	quit,		{ NO, NO, NO, NO },
267	  { "", "", "", "" },
268	  "exit ntpq" },
269	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
270	  { "key#", "", "", "" },
271	  "set keyid to use for authenticated requests" },
272	{ "version",	version,	{ NO, NO, NO, NO },
273	  { "", "", "", "" },
274	  "print version number" },
275	{ "raw",	raw,		{ NO, NO, NO, NO },
276	  { "", "", "", "" },
277	  "do raw mode variable output" },
278	{ "cooked",	cooked,		{ NO, NO, NO, NO },
279	  { "", "", "", "" },
280	  "do cooked mode variable output" },
281	{ "authenticate", authenticate,	{ OPT|NTP_STR, NO, NO, NO },
282	  { "yes|no", "", "", "" },
283	  "always authenticate requests to this server" },
284	{ "ntpversion",	ntpversion,	{ OPT|NTP_UINT, NO, NO, NO },
285	  { "version number", "", "", "" },
286	  "set the NTP version number to use for requests" },
287	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
288	  { "key type %s", "", "", "" },
289	  NULL },
290	{ 0,		0,		{ NO, NO, NO, NO },
291	  { "", "", "", "" }, "" }
292};
293
294
295/*
296 * Default values we use.
297 */
298#define	DEFHOST		"localhost"	/* default host name */
299#define	DEFTIMEOUT	5		/* wait 5 seconds for 1st pkt */
300#define	DEFSTIMEOUT	3		/* and 3 more for each additional */
301/*
302 * Requests are automatically retried once, so total timeout with no
303 * response is a bit over 2 * DEFTIMEOUT, or 10 seconds.  At the other
304 * extreme, a request eliciting 32 packets of responses each for some
305 * reason nearly DEFSTIMEOUT seconds after the prior in that series,
306 * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
307 * 93 seconds to fail each of two times, or 186 seconds.
308 * Some commands involve a series of requests, such as "peers" and
309 * "mrulist", so the cumulative timeouts are even longer for those.
310 */
311#define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
312#define	LENHOSTNAME	256		/* host name is 256 characters long */
313#define	MAXCMDS		100		/* maximum commands on cmd line */
314#define	MAXHOSTS	200		/* maximum hosts on cmd line */
315#define	MAXLINE		512		/* maximum line length */
316#define	MAXTOKENS	(1+MAXARGS+2)	/* maximum number of usable tokens */
317#define	MAXVARLEN	256		/* maximum length of a variable name */
318#define	MAXVALLEN	2048		/* maximum length of a variable value */
319#define	MAXOUTLINE	72		/* maximum length of an output line */
320#define SCREENWIDTH	76		/* nominal screen width in columns */
321
322/*
323 * Some variables used and manipulated locally
324 */
325struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
326struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
327l_fp delay_time;				/* delay time */
328char currenthost[LENHOSTNAME];			/* current host name */
329int currenthostisnum;				/* is prior text from IP? */
330struct sockaddr_in hostaddr;			/* host address */
331int showhostnames = 1;				/* show host names by default */
332int wideremote = 0;				/* show wide remote names? */
333
334int ai_fam_templ;				/* address family */
335int ai_fam_default;				/* default address family */
336SOCKET sockfd;					/* fd socket is opened on */
337int havehost = 0;				/* set to 1 when host open */
338int s_port = 0;
339struct servent *server_entry = NULL;		/* server entry for ntp */
340
341
342/*
343 * Sequence number used for requests.  It is incremented before
344 * it is used.
345 */
346u_short sequence;
347
348/*
349 * Holds data returned from queries.  Declare buffer long to be sure of
350 * alignment.
351 */
352#define	DATASIZE	(MAXFRAGS*480)	/* maximum amount of data */
353long pktdata[DATASIZE/sizeof(long)];
354
355/*
356 * assoc_cache[] is a dynamic array which allows references to
357 * associations using &1 ... &N for n associations, avoiding manual
358 * lookup of the current association IDs for a given ntpd.  It also
359 * caches the status word for each association, retrieved incidentally.
360 */
361struct association *	assoc_cache;
362u_int assoc_cache_slots;/* count of allocated array entries */
363u_int numassoc;		/* number of cached associations */
364
365/*
366 * For commands typed on the command line (with the -c option)
367 */
368int numcmds = 0;
369const char *ccmds[MAXCMDS];
370#define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
371
372/*
373 * When multiple hosts are specified.
374 */
375
376u_int numhosts;
377
378chost chosts[MAXHOSTS];
379#define	ADDHOST(cp)						\
380	do {							\
381		if (numhosts < MAXHOSTS) {			\
382			chosts[numhosts].name = (cp);		\
383			chosts[numhosts].fam = ai_fam_templ;	\
384			numhosts++;				\
385		}						\
386	} while (0)
387
388/*
389 * Macro definitions we use
390 */
391#define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
392#define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
393#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
394
395/*
396 * Jump buffer for longjumping back to the command level
397 */
398jmp_buf interrupt_buf;
399
400/*
401 * Points at file being currently printed into
402 */
403FILE *current_output;
404
405/*
406 * Command table imported from ntpdc_ops.c
407 */
408extern struct xcmd opcmds[];
409
410char const *progname;
411
412#ifdef NO_MAIN_ALLOWED
413#ifndef BUILD_AS_LIB
414CALL(ntpq,"ntpq",ntpqmain);
415
416void clear_globals(void)
417{
418	extern int ntp_optind;
419	showhostnames = 0;	/* don'tshow host names by default */
420	ntp_optind = 0;
421	server_entry = NULL;	/* server entry for ntp */
422	havehost = 0;		/* set to 1 when host open */
423	numassoc = 0;		/* number of cached associations */
424	numcmds = 0;
425	numhosts = 0;
426}
427#endif /* !BUILD_AS_LIB */
428#endif /* NO_MAIN_ALLOWED */
429
430/*
431 * main - parse arguments and handle options
432 */
433#ifndef NO_MAIN_ALLOWED
434int
435main(
436	int argc,
437	char *argv[]
438	)
439{
440	return ntpqmain(argc, argv);
441}
442#endif
443
444#ifndef BUILD_AS_LIB
445int
446ntpqmain(
447	int argc,
448	char *argv[]
449	)
450{
451	u_int ihost;
452	int icmd;
453
454
455#ifdef SYS_VXWORKS
456	clear_globals();
457	taskPrioritySet(taskIdSelf(), 100 );
458#endif
459
460	delay_time.l_ui = 0;
461	delay_time.l_uf = DEFDELAY;
462
463	init_lib();	/* sets up ipv4_works, ipv6_works */
464	ssl_applink();
465	init_auth();
466
467	/* Check to see if we have IPv6. Otherwise default to IPv4 */
468	if (!ipv6_works)
469		ai_fam_default = AF_INET;
470
471	/* Fixup keytype's help based on available digest names */
472
473	{
474	    char *list;
475	    char *msg, *fmt;
476
477	    list = list_digest_names();
478	    for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) {
479		if (strcmp("keytype", builtins[icmd].keyword) == 0)
480		    break;
481	    }
482
483	    /* CID: 1295478 */
484	    /* This should only "trip" if "keytype" is removed from builtins */
485	    INSIST(icmd < sizeof(builtins)/sizeof(builtins[0]));
486
487#ifdef OPENSSL
488	    builtins[icmd].desc[0] = "digest-name";
489	    fmt = "set key type to use for authenticated requests, one of:%s";
490#else
491	    builtins[icmd].desc[0] = "md5";
492	    fmt = "set key type to use for authenticated requests (%s)";
493#endif
494	    msg = emalloc(strlen(fmt) + strlen(list) - strlen("%s") +1);
495	    sprintf(msg, fmt, list);
496	    builtins[icmd].comment = msg;
497	    free(list);
498	}
499
500	progname = argv[0];
501
502	{
503		int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
504		argc -= optct;
505		argv += optct;
506	}
507
508	/*
509	 * Process options other than -c and -p, which are specially
510	 * handled by ntpq_custom_opt_handler().
511	 */
512
513	debug = OPT_VALUE_SET_DEBUG_LEVEL;
514
515	if (HAVE_OPT(IPV4))
516		ai_fam_templ = AF_INET;
517	else if (HAVE_OPT(IPV6))
518		ai_fam_templ = AF_INET6;
519	else
520		ai_fam_templ = ai_fam_default;
521
522	if (HAVE_OPT(INTERACTIVE))
523		interactive = 1;
524
525	if (HAVE_OPT(NUMERIC))
526		showhostnames = 0;
527
528	if (HAVE_OPT(WIDE))
529		wideremote = 1;
530
531	old_rv = HAVE_OPT(OLD_RV);
532
533	if (0 == argc) {
534		ADDHOST(DEFHOST);
535	} else {
536		for (ihost = 0; ihost < (u_int)argc; ihost++) {
537			if ('-' == *argv[ihost]) {
538				//
539				// If I really cared I'd also check:
540				// 0 == argv[ihost][2]
541				//
542				// and there are other cases as well...
543				//
544				if ('4' == argv[ihost][1]) {
545					ai_fam_templ = AF_INET;
546					continue;
547				} else if ('6' == argv[ihost][1]) {
548					ai_fam_templ = AF_INET6;
549					continue;
550				} else {
551					// XXX Throw a usage error
552				}
553			}
554			ADDHOST(argv[ihost]);
555		}
556	}
557
558	if (numcmds == 0 && interactive == 0
559	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
560		interactive = 1;
561	}
562
563	set_ctrl_c_hook(on_ctrlc);
564#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
565	if (interactive)
566		push_ctrl_c_handler(abortcmd);
567#endif /* SYS_WINNT */
568
569	if (numcmds == 0) {
570		(void) openhost(chosts[0].name, chosts[0].fam);
571		getcmds();
572	} else {
573		for (ihost = 0; ihost < numhosts; ihost++) {
574			if (openhost(chosts[ihost].name, chosts[ihost].fam))
575				for (icmd = 0; icmd < numcmds; icmd++)
576					docmd(ccmds[icmd]);
577		}
578	}
579#ifdef SYS_WINNT
580	WSACleanup();
581#endif /* SYS_WINNT */
582	return 0;
583}
584#endif /* !BUILD_AS_LIB */
585
586/*
587 * openhost - open a socket to a host
588 */
589static	int
590openhost(
591	const char *hname,
592	int	    fam
593	)
594{
595	const char svc[] = "ntp";
596	char temphost[LENHOSTNAME];
597	int a_info, i;
598	struct addrinfo hints, *ai;
599	sockaddr_u addr;
600	size_t octets;
601	register const char *cp;
602	char name[LENHOSTNAME];
603
604	/*
605	 * We need to get by the [] if they were entered
606	 */
607
608	cp = hname;
609
610	if (*cp == '[') {
611		cp++;
612		for (i = 0; *cp && *cp != ']'; cp++, i++)
613			name[i] = *cp;
614		if (*cp == ']') {
615			name[i] = '\0';
616			hname = name;
617		} else {
618			return 0;
619		}
620	}
621
622	/*
623	 * First try to resolve it as an ip address and if that fails,
624	 * do a fullblown (dns) lookup. That way we only use the dns
625	 * when it is needed and work around some implementations that
626	 * will return an "IPv4-mapped IPv6 address" address if you
627	 * give it an IPv4 address to lookup.
628	 */
629	ZERO(hints);
630	hints.ai_family = fam;
631	hints.ai_protocol = IPPROTO_UDP;
632	hints.ai_socktype = SOCK_DGRAM;
633	hints.ai_flags = Z_AI_NUMERICHOST;
634	ai = NULL;
635
636	a_info = getaddrinfo(hname, svc, &hints, &ai);
637	if (a_info == EAI_NONAME
638#ifdef EAI_NODATA
639	    || a_info == EAI_NODATA
640#endif
641	   ) {
642		hints.ai_flags = AI_CANONNAME;
643#ifdef AI_ADDRCONFIG
644		hints.ai_flags |= AI_ADDRCONFIG;
645#endif
646		a_info = getaddrinfo(hname, svc, &hints, &ai);
647	}
648#ifdef AI_ADDRCONFIG
649	/* Some older implementations don't like AI_ADDRCONFIG. */
650	if (a_info == EAI_BADFLAGS) {
651		hints.ai_flags &= ~AI_ADDRCONFIG;
652		a_info = getaddrinfo(hname, svc, &hints, &ai);
653	}
654#endif
655	if (a_info != 0) {
656		fprintf(stderr, "%s\n", gai_strerror(a_info));
657		return 0;
658	}
659
660	INSIST(ai != NULL);
661	ZERO(addr);
662	octets = min(sizeof(addr), ai->ai_addrlen);
663	memcpy(&addr, ai->ai_addr, octets);
664
665	if (ai->ai_canonname == NULL) {
666		strlcpy(temphost, stoa(&addr), sizeof(temphost));
667		currenthostisnum = TRUE;
668	} else {
669		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
670		currenthostisnum = FALSE;
671	}
672
673	if (debug > 2)
674		printf("Opening host %s (%s)\n",
675			temphost,
676			(ai->ai_family == AF_INET)
677			? "AF_INET"
678			: (ai->ai_family == AF_INET6)
679			  ? "AF_INET6"
680			  : "AF-???"
681			);
682
683	if (havehost == 1) {
684		if (debug > 2)
685			printf("Closing old host %s\n", currenthost);
686		closesocket(sockfd);
687		havehost = 0;
688	}
689	strlcpy(currenthost, temphost, sizeof(currenthost));
690
691	/* port maps to the same location in both families */
692	s_port = NSRCPORT(&addr);
693#ifdef SYS_VXWORKS
694	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
695	if (ai->ai_family == AF_INET)
696		*(struct sockaddr_in *)&hostaddr=
697			*((struct sockaddr_in *)ai->ai_addr);
698	else
699		*(struct sockaddr_in6 *)&hostaddr=
700			*((struct sockaddr_in6 *)ai->ai_addr);
701#endif /* SYS_VXWORKS */
702
703#ifdef SYS_WINNT
704	{
705		int optionValue = SO_SYNCHRONOUS_NONALERT;
706		int err;
707
708		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
709				 (char *)&optionValue, sizeof(optionValue));
710		if (err) {
711			mfprintf(stderr,
712				 "setsockopt(SO_SYNCHRONOUS_NONALERT)"
713				 " error: %m\n");
714			freeaddrinfo(ai);
715			exit(1);
716		}
717	}
718#endif /* SYS_WINNT */
719
720	sockfd = socket(ai->ai_family, ai->ai_socktype,
721			ai->ai_protocol);
722	if (sockfd == INVALID_SOCKET) {
723		error("socket");
724		freeaddrinfo(ai);
725		return 0;
726	}
727
728
729#ifdef NEED_RCVBUF_SLOP
730# ifdef SO_RCVBUF
731	{ int rbufsize = DATASIZE + 2048;	/* 2K for slop */
732	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
733		       &rbufsize, sizeof(int)) == -1)
734		error("setsockopt");
735	}
736# endif
737#endif
738
739	if
740#ifdef SYS_VXWORKS
741	   (connect(sockfd, (struct sockaddr *)&hostaddr,
742		    sizeof(hostaddr)) == -1)
743#else
744	   (connect(sockfd, (struct sockaddr *)ai->ai_addr,
745		ai->ai_addrlen) == -1)
746#endif /* SYS_VXWORKS */
747	{
748		error("connect");
749		freeaddrinfo(ai);
750		return 0;
751	}
752	freeaddrinfo(ai);
753	havehost = 1;
754	numassoc = 0;
755
756	return 1;
757}
758
759
760static void
761dump_hex_printable(
762	const void *	data,
763	size_t		len
764	)
765{
766	const char *	cdata;
767	const char *	rowstart;
768	size_t		idx;
769	size_t		rowlen;
770	u_char		uch;
771
772	cdata = data;
773	while (len > 0) {
774		rowstart = cdata;
775		rowlen = min(16, len);
776		for (idx = 0; idx < rowlen; idx++) {
777			uch = *(cdata++);
778			printf("%02x ", uch);
779		}
780		for ( ; idx < 16 ; idx++)
781			printf("   ");
782		cdata = rowstart;
783		for (idx = 0; idx < rowlen; idx++) {
784			uch = *(cdata++);
785			printf("%c", (isprint(uch))
786					 ? uch
787					 : '.');
788		}
789		printf("\n");
790		len -= rowlen;
791	}
792}
793
794
795/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
796/*
797 * sendpkt - send a packet to the remote host
798 */
799static int
800sendpkt(
801	void *	xdata,
802	size_t	xdatalen
803	)
804{
805	if (debug >= 3)
806		printf("Sending %zu octets\n", xdatalen);
807
808	if (send(sockfd, xdata, xdatalen, 0) == -1) {
809		warning("write to %s failed", currenthost);
810		return -1;
811	}
812
813	if (debug >= 4) {
814		printf("Request packet:\n");
815		dump_hex_printable(xdata, xdatalen);
816	}
817	return 0;
818}
819
820/*
821 * getresponse - get a (series of) response packet(s) and return the data
822 */
823static int
824getresponse(
825	int opcode,
826	int associd,
827	u_short *rstatus,
828	size_t *rsize,
829	const char **rdata,
830	int timeo
831	)
832{
833	struct ntp_control rpkt;
834	struct sock_timeval tvo;
835	u_short offsets[MAXFRAGS+1];
836	u_short counts[MAXFRAGS+1];
837	u_short offset;
838	u_short count;
839	size_t numfrags;
840	size_t f;
841	size_t ff;
842	int seenlastfrag;
843	int shouldbesize;
844	fd_set fds;
845	int n;
846	int errcode;
847
848	/*
849	 * This is pretty tricky.  We may get between 1 and MAXFRAG packets
850	 * back in response to the request.  We peel the data out of
851	 * each packet and collect it in one long block.  When the last
852	 * packet in the sequence is received we'll know how much data we
853	 * should have had.  Note we use one long time out, should reconsider.
854	 */
855	*rsize = 0;
856	if (rstatus)
857		*rstatus = 0;
858	*rdata = (char *)pktdata;
859
860	numfrags = 0;
861	seenlastfrag = 0;
862
863	FD_ZERO(&fds);
864
865	/*
866	 * Loop until we have an error or a complete response.  Nearly all
867	 * code paths to loop again use continue.
868	 */
869	for (;;) {
870
871		if (numfrags == 0)
872			tvo = tvout;
873		else
874			tvo = tvsout;
875
876		FD_SET(sockfd, &fds);
877		n = select(sockfd+1, &fds, NULL, NULL, &tvo);
878		if (n == -1) {
879			warning("select fails");
880			return -1;
881		}
882		if (n == 0) {
883			/*
884			 * Timed out.  Return what we have
885			 */
886			if (numfrags == 0) {
887				if (timeo)
888					fprintf(stderr,
889						"%s: timed out, nothing received\n",
890						currenthost);
891				return ERR_TIMEOUT;
892			}
893			if (timeo)
894				fprintf(stderr,
895					"%s: timed out with incomplete data\n",
896					currenthost);
897			if (debug) {
898				fprintf(stderr,
899					"ERR_INCOMPLETE: Received fragments:\n");
900				for (f = 0; f < numfrags; f++)
901					fprintf(stderr,
902						"%2u: %5d %5d\t%3d octets\n",
903						(u_int)f, offsets[f],
904						offsets[f] +
905						counts[f],
906						counts[f]);
907				fprintf(stderr,
908					"last fragment %sreceived\n",
909					(seenlastfrag)
910					    ? ""
911					    : "not ");
912			}
913			return ERR_INCOMPLETE;
914		}
915
916		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
917		if (n == -1) {
918			warning("read");
919			return -1;
920		}
921
922		if (debug >= 4) {
923			printf("Response packet:\n");
924			dump_hex_printable(&rpkt, n);
925		}
926
927		/*
928		 * Check for format errors.  Bug proofing.
929		 */
930		if (n < (int)CTL_HEADER_LEN) {
931			if (debug)
932				printf("Short (%d byte) packet received\n", n);
933			continue;
934		}
935		if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
936		    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
937			if (debug)
938				printf("Packet received with version %d\n",
939				       PKT_VERSION(rpkt.li_vn_mode));
940			continue;
941		}
942		if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
943			if (debug)
944				printf("Packet received with mode %d\n",
945				       PKT_MODE(rpkt.li_vn_mode));
946			continue;
947		}
948		if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
949			if (debug)
950				printf("Received request packet, wanted response\n");
951			continue;
952		}
953
954		/*
955		 * Check opcode and sequence number for a match.
956		 * Could be old data getting to us.
957		 */
958		if (ntohs(rpkt.sequence) != sequence) {
959			if (debug)
960				printf("Received sequnce number %d, wanted %d\n",
961				       ntohs(rpkt.sequence), sequence);
962			continue;
963		}
964		if (CTL_OP(rpkt.r_m_e_op) != opcode) {
965			if (debug)
966			    printf(
967				    "Received opcode %d, wanted %d (sequence number okay)\n",
968				    CTL_OP(rpkt.r_m_e_op), opcode);
969			continue;
970		}
971
972		/*
973		 * Check the error code.  If non-zero, return it.
974		 */
975		if (CTL_ISERROR(rpkt.r_m_e_op)) {
976			errcode = (ntohs(rpkt.status) >> 8) & 0xff;
977			if (CTL_ISMORE(rpkt.r_m_e_op))
978				TRACE(1, ("Error code %d received on not-final packet\n",
979					  errcode));
980			if (errcode == CERR_UNSPEC)
981				return ERR_UNSPEC;
982			return errcode;
983		}
984
985		/*
986		 * Check the association ID to make sure it matches what
987		 * we sent.
988		 */
989		if (ntohs(rpkt.associd) != associd) {
990			TRACE(1, ("Association ID %d doesn't match expected %d\n",
991				  ntohs(rpkt.associd), associd));
992			/*
993			 * Hack for silly fuzzballs which, at the time of writing,
994			 * return an assID of sys.peer when queried for system variables.
995			 */
996#ifdef notdef
997			continue;
998#endif
999		}
1000
1001		/*
1002		 * Collect offset and count.  Make sure they make sense.
1003		 */
1004		offset = ntohs(rpkt.offset);
1005		count = ntohs(rpkt.count);
1006
1007		/*
1008		 * validate received payload size is padded to next 32-bit
1009		 * boundary and no smaller than claimed by rpkt.count
1010		 */
1011		if (n & 0x3) {
1012			TRACE(1, ("Response packet not padded, size = %d\n",
1013				  n));
1014			continue;
1015		}
1016
1017		shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
1018
1019		if (n < shouldbesize) {
1020			printf("Response packet claims %u octets payload, above %ld received\n",
1021			       count, (long)n - CTL_HEADER_LEN);
1022			return ERR_INCOMPLETE;
1023		}
1024
1025		if (debug >= 3 && shouldbesize > n) {
1026			u_int32 key;
1027			u_int32 *lpkt;
1028			int maclen;
1029
1030			/*
1031			 * Usually we ignore authentication, but for debugging purposes
1032			 * we watch it here.
1033			 */
1034			/* round to 8 octet boundary */
1035			shouldbesize = (shouldbesize + 7) & ~7;
1036
1037			maclen = n - shouldbesize;
1038			if (maclen >= (int)MIN_MAC_LEN) {
1039				printf(
1040					"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1041					n, shouldbesize, maclen);
1042				lpkt = (u_int32 *)&rpkt;
1043				printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1044				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1045				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1046				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1047				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1048				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1049				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1050				key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1051				printf("Authenticated with keyid %lu\n", (u_long)key);
1052				if (key != 0 && key != info_auth_keyid) {
1053					printf("We don't know that key\n");
1054				} else {
1055					if (authdecrypt(key, (u_int32 *)&rpkt,
1056					    n - maclen, maclen)) {
1057						printf("Auth okay!\n");
1058					} else {
1059						printf("Auth failed!\n");
1060					}
1061				}
1062			}
1063		}
1064
1065		TRACE(2, ("Got packet, size = %d\n", n));
1066		if (count > (n - CTL_HEADER_LEN)) {
1067			TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
1068				  count, (long)n - CTL_HEADER_LEN));
1069			continue;
1070		}
1071		if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1072			TRACE(1, ("Received count of 0 in non-final fragment\n"));
1073			continue;
1074		}
1075		if (offset + count > sizeof(pktdata)) {
1076			TRACE(1, ("Offset %u, count %u, too big for buffer\n",
1077				  offset, count));
1078			return ERR_TOOMUCH;
1079		}
1080		if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1081			TRACE(1, ("Received second last fragment packet\n"));
1082			continue;
1083		}
1084
1085		/*
1086		 * So far, so good.  Record this fragment, making sure it doesn't
1087		 * overlap anything.
1088		 */
1089		TRACE(2, ("Packet okay\n"));
1090
1091		if (numfrags > (MAXFRAGS - 1)) {
1092			TRACE(2, ("Number of fragments exceeds maximum %d\n",
1093				  MAXFRAGS - 1));
1094			return ERR_TOOMUCH;
1095		}
1096
1097		/*
1098		 * Find the position for the fragment relative to any
1099		 * previously received.
1100		 */
1101		for (f = 0;
1102		     f < numfrags && offsets[f] < offset;
1103		     f++) {
1104			/* empty body */ ;
1105		}
1106
1107		if (f < numfrags && offset == offsets[f]) {
1108			TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
1109				  count, offset, counts[f], offsets[f]));
1110			continue;
1111		}
1112
1113		if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1114			TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
1115				  offset, counts[f-1], offsets[f-1]));
1116			continue;
1117		}
1118
1119		if (f < numfrags && (offset + count) > offsets[f]) {
1120			TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
1121				  count, offset, offsets[f]));
1122			continue;
1123		}
1124
1125		for (ff = numfrags; ff > f; ff--) {
1126			offsets[ff] = offsets[ff-1];
1127			counts[ff] = counts[ff-1];
1128		}
1129		offsets[f] = offset;
1130		counts[f] = count;
1131		numfrags++;
1132
1133		/*
1134		 * Got that stuffed in right.  Figure out if this was the last.
1135		 * Record status info out of the last packet.
1136		 */
1137		if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1138			seenlastfrag = 1;
1139			if (rstatus != 0)
1140				*rstatus = ntohs(rpkt.status);
1141		}
1142
1143		/*
1144		 * Copy the data into the data buffer.
1145		 */
1146		memcpy((char *)pktdata + offset, &rpkt.u, count);
1147
1148		/*
1149		 * If we've seen the last fragment, look for holes in the sequence.
1150		 * If there aren't any, we're done.
1151		 */
1152		if (seenlastfrag && offsets[0] == 0) {
1153			for (f = 1; f < numfrags; f++)
1154				if (offsets[f-1] + counts[f-1] !=
1155				    offsets[f])
1156					break;
1157			if (f == numfrags) {
1158				*rsize = offsets[f-1] + counts[f-1];
1159				TRACE(1, ("%lu packets reassembled into response\n",
1160					  (u_long)numfrags));
1161				return 0;
1162			}
1163		}
1164	}  /* giant for (;;) collecting response packets */
1165}  /* getresponse() */
1166
1167
1168/*
1169 * sendrequest - format and send a request packet
1170 */
1171static int
1172sendrequest(
1173	int opcode,
1174	associd_t associd,
1175	int auth,
1176	size_t qsize,
1177	const char *qdata
1178	)
1179{
1180	struct ntp_control qpkt;
1181	size_t	pktsize;
1182	u_long	key_id;
1183	char *	pass;
1184	size_t	maclen;
1185
1186	/*
1187	 * Check to make sure the data will fit in one packet
1188	 */
1189	if (qsize > CTL_MAX_DATA_LEN) {
1190		fprintf(stderr,
1191			"***Internal error!  qsize (%zu) too large\n",
1192			qsize);
1193		return 1;
1194	}
1195
1196	/*
1197	 * Fill in the packet
1198	 */
1199	qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1200	qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1201	qpkt.sequence = htons(sequence);
1202	qpkt.status = 0;
1203	qpkt.associd = htons((u_short)associd);
1204	qpkt.offset = 0;
1205	qpkt.count = htons((u_short)qsize);
1206
1207	pktsize = CTL_HEADER_LEN;
1208
1209	/*
1210	 * If we have data, copy and pad it out to a 32-bit boundary.
1211	 */
1212	if (qsize > 0) {
1213		memcpy(&qpkt.u, qdata, (size_t)qsize);
1214		pktsize += qsize;
1215		while (pktsize & (sizeof(u_int32) - 1)) {
1216			qpkt.u.data[qsize++] = 0;
1217			pktsize++;
1218		}
1219	}
1220
1221	/*
1222	 * If it isn't authenticated we can just send it.  Otherwise
1223	 * we're going to have to think about it a little.
1224	 */
1225	if (!auth && !always_auth) {
1226		return sendpkt(&qpkt, pktsize);
1227	}
1228
1229	/*
1230	 * Pad out packet to a multiple of 8 octets to be sure
1231	 * receiver can handle it.
1232	 */
1233	while (pktsize & 7) {
1234		qpkt.u.data[qsize++] = 0;
1235		pktsize++;
1236	}
1237
1238	/*
1239	 * Get the keyid and the password if we don't have one.
1240	 */
1241	if (info_auth_keyid == 0) {
1242		key_id = getkeyid("Keyid: ");
1243		if (key_id == 0 || key_id > NTP_MAXKEY) {
1244			fprintf(stderr,
1245				"Invalid key identifier\n");
1246			return 1;
1247		}
1248		info_auth_keyid = key_id;
1249	}
1250	if (!authistrusted(info_auth_keyid)) {
1251		pass = getpass_keytype(info_auth_keytype);
1252		if ('\0' == pass[0]) {
1253			fprintf(stderr, "Invalid password\n");
1254			return 1;
1255		}
1256		authusekey(info_auth_keyid, info_auth_keytype,
1257			   (u_char *)pass);
1258		authtrust(info_auth_keyid, 1);
1259	}
1260
1261	/*
1262	 * Do the encryption.
1263	 */
1264	maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1265	if (!maclen) {
1266		fprintf(stderr, "Key not found\n");
1267		return 1;
1268	} else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1269		fprintf(stderr,
1270			"%zu octet MAC, %zu expected with %zu octet digest\n",
1271			maclen, (info_auth_hashlen + sizeof(keyid_t)),
1272			info_auth_hashlen);
1273		return 1;
1274	}
1275
1276	return sendpkt((char *)&qpkt, pktsize + maclen);
1277}
1278
1279
1280/*
1281 * show_error_msg - display the error text for a mode 6 error response.
1282 */
1283void
1284show_error_msg(
1285	int		m6resp,
1286	associd_t	associd
1287	)
1288{
1289	if (numhosts > 1)
1290		fprintf(stderr, "server=%s ", currenthost);
1291
1292	switch(m6resp) {
1293
1294	case CERR_BADFMT:
1295		fprintf(stderr,
1296		    "***Server reports a bad format request packet\n");
1297		break;
1298
1299	case CERR_PERMISSION:
1300		fprintf(stderr,
1301		    "***Server disallowed request (authentication?)\n");
1302		break;
1303
1304	case CERR_BADOP:
1305		fprintf(stderr,
1306		    "***Server reports a bad opcode in request\n");
1307		break;
1308
1309	case CERR_BADASSOC:
1310		fprintf(stderr,
1311		    "***Association ID %d unknown to server\n",
1312		    associd);
1313		break;
1314
1315	case CERR_UNKNOWNVAR:
1316		fprintf(stderr,
1317		    "***A request variable unknown to the server\n");
1318		break;
1319
1320	case CERR_BADVALUE:
1321		fprintf(stderr,
1322		    "***Server indicates a request variable was bad\n");
1323		break;
1324
1325	case ERR_UNSPEC:
1326		fprintf(stderr,
1327		    "***Server returned an unspecified error\n");
1328		break;
1329
1330	case ERR_TIMEOUT:
1331		fprintf(stderr, "***Request timed out\n");
1332		break;
1333
1334	case ERR_INCOMPLETE:
1335		fprintf(stderr,
1336		    "***Response from server was incomplete\n");
1337		break;
1338
1339	case ERR_TOOMUCH:
1340		fprintf(stderr,
1341		    "***Buffer size exceeded for returned data\n");
1342		break;
1343
1344	default:
1345		fprintf(stderr,
1346		    "***Server returns unknown error code %d\n",
1347		    m6resp);
1348	}
1349}
1350
1351/*
1352 * doquery - send a request and process the response, displaying
1353 *	     error messages for any error responses.
1354 */
1355int
1356doquery(
1357	int opcode,
1358	associd_t associd,
1359	int auth,
1360	size_t qsize,
1361	const char *qdata,
1362	u_short *rstatus,
1363	size_t *rsize,
1364	const char **rdata
1365	)
1366{
1367	return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
1368			 rsize, rdata, FALSE);
1369}
1370
1371
1372/*
1373 * doqueryex - send a request and process the response, optionally
1374 *	       displaying error messages for any error responses.
1375 */
1376int
1377doqueryex(
1378	int opcode,
1379	associd_t associd,
1380	int auth,
1381	size_t qsize,
1382	const char *qdata,
1383	u_short *rstatus,
1384	size_t *rsize,
1385	const char **rdata,
1386	int quiet
1387	)
1388{
1389	int res;
1390	int done;
1391
1392	/*
1393	 * Check to make sure host is open
1394	 */
1395	if (!havehost) {
1396		fprintf(stderr, "***No host open, use `host' command\n");
1397		return -1;
1398	}
1399
1400	done = 0;
1401	sequence++;
1402
1403    again:
1404	/*
1405	 * send a request
1406	 */
1407	res = sendrequest(opcode, associd, auth, qsize, qdata);
1408	if (res != 0)
1409		return res;
1410
1411	/*
1412	 * Get the response.  If we got a standard error, print a message
1413	 */
1414	res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1415
1416	if (res > 0) {
1417		if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1418			if (res == ERR_INCOMPLETE) {
1419				/*
1420				 * better bump the sequence so we don't
1421				 * get confused about differing fragments.
1422				 */
1423				sequence++;
1424			}
1425			done = 1;
1426			goto again;
1427		}
1428		if (!quiet)
1429			show_error_msg(res, associd);
1430
1431	}
1432	return res;
1433}
1434
1435
1436#ifndef BUILD_AS_LIB
1437/*
1438 * getcmds - read commands from the standard input and execute them
1439 */
1440static void
1441getcmds(void)
1442{
1443	char *	line;
1444	int	count;
1445
1446	ntp_readline_init(interactive ? prompt : NULL);
1447
1448	for (;;) {
1449		line = ntp_readline(&count);
1450		if (NULL == line)
1451			break;
1452		docmd(line);
1453		free(line);
1454	}
1455
1456	ntp_readline_uninit();
1457}
1458#endif /* !BUILD_AS_LIB */
1459
1460
1461#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1462/*
1463 * abortcmd - catch interrupts and abort the current command
1464 */
1465static int
1466abortcmd(void)
1467{
1468	if (current_output == stdout)
1469		(void) fflush(stdout);
1470	putc('\n', stderr);
1471	(void) fflush(stderr);
1472	if (jump) {
1473		jump = 0;
1474		longjmp(interrupt_buf, 1);
1475	}
1476	return TRUE;
1477}
1478#endif	/* !SYS_WINNT && !BUILD_AS_LIB */
1479
1480
1481#ifndef	BUILD_AS_LIB
1482/*
1483 * docmd - decode the command line and execute a command
1484 */
1485static void
1486docmd(
1487	const char *cmdline
1488	)
1489{
1490	char *tokens[1+MAXARGS+2];
1491	struct parse pcmd;
1492	int ntok;
1493	static int i;
1494	struct xcmd *xcmd;
1495
1496	/*
1497	 * Tokenize the command line.  If nothing on it, return.
1498	 */
1499	tokenize(cmdline, tokens, &ntok);
1500	if (ntok == 0)
1501	    return;
1502
1503	/*
1504	 * Find the appropriate command description.
1505	 */
1506	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1507	if (i == 0) {
1508		(void) fprintf(stderr, "***Command `%s' unknown\n",
1509			       tokens[0]);
1510		return;
1511	} else if (i >= 2) {
1512		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1513			       tokens[0]);
1514		return;
1515	}
1516
1517	/* Warn about ignored extra args */
1518	for (i = MAXARGS + 1; i < ntok ; ++i) {
1519		fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
1520	}
1521
1522	/*
1523	 * Save the keyword, then walk through the arguments, interpreting
1524	 * as we go.
1525	 */
1526	pcmd.keyword = tokens[0];
1527	pcmd.nargs = 0;
1528	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1529		if ((i+1) >= ntok) {
1530			if (!(xcmd->arg[i] & OPT)) {
1531				printusage(xcmd, stderr);
1532				return;
1533			}
1534			break;
1535		}
1536		if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1537			break;
1538		if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1539			return;
1540		pcmd.nargs++;
1541	}
1542
1543	i++;
1544	if (i < ntok && *tokens[i] == '>') {
1545		char *fname;
1546
1547		if (*(tokens[i]+1) != '\0')
1548			fname = tokens[i]+1;
1549		else if ((i+1) < ntok)
1550			fname = tokens[i+1];
1551		else {
1552			(void) fprintf(stderr, "***No file for redirect\n");
1553			return;
1554		}
1555
1556		current_output = fopen(fname, "w");
1557		if (current_output == NULL) {
1558			(void) fprintf(stderr, "***Error opening %s: ", fname);
1559			perror("");
1560			return;
1561		}
1562		i = 1;		/* flag we need a close */
1563	} else {
1564		current_output = stdout;
1565		i = 0;		/* flag no close */
1566	}
1567
1568	if (interactive && setjmp(interrupt_buf)) {
1569		jump = 0;
1570		return;
1571	} else {
1572		jump++;
1573		(xcmd->handler)(&pcmd, current_output);
1574		jump = 0;	/* HMS: 961106: was after fclose() */
1575		if (i) (void) fclose(current_output);
1576	}
1577
1578	return;
1579}
1580
1581
1582/*
1583 * tokenize - turn a command line into tokens
1584 *
1585 * SK: Modified to allow a quoted string
1586 *
1587 * HMS: If the first character of the first token is a ':' then (after
1588 * eating inter-token whitespace) the 2nd token is the rest of the line.
1589 */
1590
1591static void
1592tokenize(
1593	const char *line,
1594	char **tokens,
1595	int *ntok
1596	)
1597{
1598	register const char *cp;
1599	register char *sp;
1600	static char tspace[MAXLINE];
1601
1602	sp = tspace;
1603	cp = line;
1604	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1605		tokens[*ntok] = sp;
1606
1607		/* Skip inter-token whitespace */
1608		while (ISSPACE(*cp))
1609		    cp++;
1610
1611		/* If we're at EOL we're done */
1612		if (ISEOL(*cp))
1613		    break;
1614
1615		/* If this is the 2nd token and the first token begins
1616		 * with a ':', then just grab to EOL.
1617		 */
1618
1619		if (*ntok == 1 && tokens[0][0] == ':') {
1620			do {
1621				if (sp - tspace >= MAXLINE)
1622					goto toobig;
1623				*sp++ = *cp++;
1624			} while (!ISEOL(*cp));
1625		}
1626
1627		/* Check if this token begins with a double quote.
1628		 * If yes, continue reading till the next double quote
1629		 */
1630		else if (*cp == '\"') {
1631			++cp;
1632			do {
1633				if (sp - tspace >= MAXLINE)
1634					goto toobig;
1635				*sp++ = *cp++;
1636			} while ((*cp != '\"') && !ISEOL(*cp));
1637			/* HMS: a missing closing " should be an error */
1638		}
1639		else {
1640			do {
1641				if (sp - tspace >= MAXLINE)
1642					goto toobig;
1643				*sp++ = *cp++;
1644			} while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1645			/* HMS: Why check for a " in the previous line? */
1646		}
1647
1648		if (sp - tspace >= MAXLINE)
1649			goto toobig;
1650		*sp++ = '\0';
1651	}
1652	return;
1653
1654  toobig:
1655	*ntok = 0;
1656	fprintf(stderr,
1657		"***Line `%s' is too big\n",
1658		line);
1659	return;
1660}
1661
1662
1663/*
1664 * getarg - interpret an argument token
1665 */
1666static int
1667getarg(
1668	const char *str,
1669	int code,
1670	arg_v *argp
1671	)
1672{
1673	u_long ul;
1674
1675	switch (code & ~OPT) {
1676	case NTP_STR:
1677		argp->string = str;
1678		break;
1679
1680	case NTP_ADD:
1681		if (!getnetnum(str, &argp->netnum, NULL, 0))
1682			return 0;
1683		break;
1684
1685	case NTP_UINT:
1686		if ('&' == str[0]) {
1687			if (!atouint(&str[1], &ul)) {
1688				fprintf(stderr,
1689					"***Association index `%s' invalid/undecodable\n",
1690					str);
1691				return 0;
1692			}
1693			if (0 == numassoc) {
1694				dogetassoc(stdout);
1695				if (0 == numassoc) {
1696					fprintf(stderr,
1697						"***No associations found, `%s' unknown\n",
1698						str);
1699					return 0;
1700				}
1701			}
1702			ul = min(ul, numassoc);
1703			argp->uval = assoc_cache[ul - 1].assid;
1704			break;
1705		}
1706		if (!atouint(str, &argp->uval)) {
1707			fprintf(stderr, "***Illegal unsigned value %s\n",
1708				str);
1709			return 0;
1710		}
1711		break;
1712
1713	case NTP_INT:
1714		if (!atoint(str, &argp->ival)) {
1715			fprintf(stderr, "***Illegal integer value %s\n",
1716				str);
1717			return 0;
1718		}
1719		break;
1720
1721	case IP_VERSION:
1722		if (!strcmp("-6", str)) {
1723			argp->ival = 6;
1724		} else if (!strcmp("-4", str)) {
1725			argp->ival = 4;
1726		} else {
1727			fprintf(stderr, "***Version must be either 4 or 6\n");
1728			return 0;
1729		}
1730		break;
1731	}
1732
1733	return 1;
1734}
1735#endif	/* !BUILD_AS_LIB */
1736
1737
1738/*
1739 * findcmd - find a command in a command description table
1740 */
1741static int
1742findcmd(
1743	const char *	str,
1744	struct xcmd *	clist1,
1745	struct xcmd *	clist2,
1746	struct xcmd **	cmd
1747	)
1748{
1749	struct xcmd *cl;
1750	size_t clen;
1751	int nmatch;
1752	struct xcmd *nearmatch = NULL;
1753	struct xcmd *clist;
1754
1755	clen = strlen(str);
1756	nmatch = 0;
1757	if (clist1 != 0)
1758	    clist = clist1;
1759	else if (clist2 != 0)
1760	    clist = clist2;
1761	else
1762	    return 0;
1763
1764    again:
1765	for (cl = clist; cl->keyword != 0; cl++) {
1766		/* do a first character check, for efficiency */
1767		if (*str != *(cl->keyword))
1768		    continue;
1769		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1770			/*
1771			 * Could be extact match, could be approximate.
1772			 * Is exact if the length of the keyword is the
1773			 * same as the str.
1774			 */
1775			if (*((cl->keyword) + clen) == '\0') {
1776				*cmd = cl;
1777				return 1;
1778			}
1779			nmatch++;
1780			nearmatch = cl;
1781		}
1782	}
1783
1784	/*
1785	 * See if there is more to do.  If so, go again.  Sorry about the
1786	 * goto, too much looking at BSD sources...
1787	 */
1788	if (clist == clist1 && clist2 != 0) {
1789		clist = clist2;
1790		goto again;
1791	}
1792
1793	/*
1794	 * If we got extactly 1 near match, use it, else return number
1795	 * of matches.
1796	 */
1797	if (nmatch == 1) {
1798		*cmd = nearmatch;
1799		return 1;
1800	}
1801	return nmatch;
1802}
1803
1804
1805/*
1806 * getnetnum - given a host name, return its net number
1807 *	       and (optional) full name
1808 */
1809int
1810getnetnum(
1811	const char *hname,
1812	sockaddr_u *num,
1813	char *fullhost,
1814	int af
1815	)
1816{
1817	struct addrinfo hints, *ai = NULL;
1818
1819	ZERO(hints);
1820	hints.ai_flags = AI_CANONNAME;
1821#ifdef AI_ADDRCONFIG
1822	hints.ai_flags |= AI_ADDRCONFIG;
1823#endif
1824
1825	/*
1826	 * decodenetnum only works with addresses, but handles syntax
1827	 * that getaddrinfo doesn't:  [2001::1]:1234
1828	 */
1829	if (decodenetnum(hname, num)) {
1830		if (fullhost != NULL)
1831			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1832				    LENHOSTNAME, NULL, 0, 0);
1833		return 1;
1834	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1835		INSIST(sizeof(*num) >= ai->ai_addrlen);
1836		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1837		if (fullhost != NULL) {
1838			if (ai->ai_canonname != NULL)
1839				strlcpy(fullhost, ai->ai_canonname,
1840					LENHOSTNAME);
1841			else
1842				getnameinfo(&num->sa, SOCKLEN(num),
1843					    fullhost, LENHOSTNAME, NULL,
1844					    0, 0);
1845		}
1846		freeaddrinfo(ai);
1847		return 1;
1848	}
1849	fprintf(stderr, "***Can't find host %s\n", hname);
1850
1851	return 0;
1852}
1853
1854
1855/*
1856 * nntohost - convert network number to host name.  This routine enforces
1857 *	       the showhostnames setting.
1858 */
1859const char *
1860nntohost(
1861	sockaddr_u *netnum
1862	)
1863{
1864	return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
1865}
1866
1867
1868/*
1869 * nntohost_col - convert network number to host name in fixed width.
1870 *		  This routine enforces the showhostnames setting.
1871 *		  When displaying hostnames longer than the width,
1872 *		  the first part of the hostname is displayed.  When
1873 *		  displaying numeric addresses longer than the width,
1874 *		  Such as IPv6 addresses, the caller decides whether
1875 *		  the first or last of the numeric address is used.
1876 */
1877const char *
1878nntohost_col(
1879	sockaddr_u *	addr,
1880	size_t		width,
1881	int		preserve_lowaddrbits
1882	)
1883{
1884	const char *	out;
1885
1886	if (!showhostnames || SOCK_UNSPEC(addr)) {
1887		if (preserve_lowaddrbits)
1888			out = trunc_left(stoa(addr), width);
1889		else
1890			out = trunc_right(stoa(addr), width);
1891	} else if (ISREFCLOCKADR(addr)) {
1892		out = refnumtoa(addr);
1893	} else {
1894		out = trunc_right(socktohost(addr), width);
1895	}
1896	return out;
1897}
1898
1899
1900/*
1901 * nntohostp() is the same as nntohost() plus a :port suffix
1902 */
1903const char *
1904nntohostp(
1905	sockaddr_u *netnum
1906	)
1907{
1908	const char *	hostn;
1909	char *		buf;
1910
1911	if (!showhostnames || SOCK_UNSPEC(netnum))
1912		return sptoa(netnum);
1913	else if (ISREFCLOCKADR(netnum))
1914		return refnumtoa(netnum);
1915
1916	hostn = socktohost(netnum);
1917	LIB_GETBUF(buf);
1918	snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
1919
1920	return buf;
1921}
1922
1923/*
1924 * rtdatetolfp - decode an RT-11 date into an l_fp
1925 */
1926static int
1927rtdatetolfp(
1928	char *str,
1929	l_fp *lfp
1930	)
1931{
1932	register char *cp;
1933	register int i;
1934	struct calendar cal;
1935	char buf[4];
1936
1937	cal.yearday = 0;
1938
1939	/*
1940	 * An RT-11 date looks like:
1941	 *
1942	 * d[d]-Mth-y[y] hh:mm:ss
1943	 *
1944	 * (No docs, but assume 4-digit years are also legal...)
1945	 *
1946	 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1947	 */
1948	cp = str;
1949	if (!isdigit((int)*cp)) {
1950		if (*cp == '-') {
1951			/*
1952			 * Catch special case
1953			 */
1954			L_CLR(lfp);
1955			return 1;
1956		}
1957		return 0;
1958	}
1959
1960	cal.monthday = (u_char) (*cp++ - '0');	/* ascii dependent */
1961	if (isdigit((int)*cp)) {
1962		cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
1963		cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
1964	}
1965
1966	if (*cp++ != '-')
1967	    return 0;
1968
1969	for (i = 0; i < 3; i++)
1970	    buf[i] = *cp++;
1971	buf[3] = '\0';
1972
1973	for (i = 0; i < 12; i++)
1974	    if (STREQ(buf, months[i]))
1975		break;
1976	if (i == 12)
1977	    return 0;
1978	cal.month = (u_char)(i + 1);
1979
1980	if (*cp++ != '-')
1981	    return 0;
1982
1983	if (!isdigit((int)*cp))
1984	    return 0;
1985	cal.year = (u_short)(*cp++ - '0');
1986	if (isdigit((int)*cp)) {
1987		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1988		cal.year = (u_short)(*cp++ - '0');
1989	}
1990	if (isdigit((int)*cp)) {
1991		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1992		cal.year = (u_short)(cal.year + *cp++ - '0');
1993	}
1994	if (isdigit((int)*cp)) {
1995		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1996		cal.year = (u_short)(cal.year + *cp++ - '0');
1997	}
1998
1999	/*
2000	 * Catch special case.  If cal.year == 0 this is a zero timestamp.
2001	 */
2002	if (cal.year == 0) {
2003		L_CLR(lfp);
2004		return 1;
2005	}
2006
2007	if (*cp++ != ' ' || !isdigit((int)*cp))
2008	    return 0;
2009	cal.hour = (u_char)(*cp++ - '0');
2010	if (isdigit((int)*cp)) {
2011		cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
2012		cal.hour = (u_char)(cal.hour + *cp++ - '0');
2013	}
2014
2015	if (*cp++ != ':' || !isdigit((int)*cp))
2016	    return 0;
2017	cal.minute = (u_char)(*cp++ - '0');
2018	if (isdigit((int)*cp)) {
2019		cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
2020		cal.minute = (u_char)(cal.minute + *cp++ - '0');
2021	}
2022
2023	if (*cp++ != ':' || !isdigit((int)*cp))
2024	    return 0;
2025	cal.second = (u_char)(*cp++ - '0');
2026	if (isdigit((int)*cp)) {
2027		cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
2028		cal.second = (u_char)(cal.second + *cp++ - '0');
2029	}
2030
2031	/*
2032	 * For RT-11, 1972 seems to be the pivot year
2033	 */
2034	if (cal.year < 72)
2035		cal.year += 2000;
2036	if (cal.year < 100)
2037		cal.year += 1900;
2038
2039	lfp->l_ui = caltontp(&cal);
2040	lfp->l_uf = 0;
2041	return 1;
2042}
2043
2044
2045/*
2046 * decodets - decode a timestamp into an l_fp format number, with
2047 *	      consideration of fuzzball formats.
2048 */
2049int
2050decodets(
2051	char *str,
2052	l_fp *lfp
2053	)
2054{
2055	char *cp;
2056	char buf[30];
2057	size_t b;
2058
2059	/*
2060	 * If it starts with a 0x, decode as hex.
2061	 */
2062	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2063		return hextolfp(str+2, lfp);
2064
2065	/*
2066	 * If it starts with a '"', try it as an RT-11 date.
2067	 */
2068	if (*str == '"') {
2069		cp = str + 1;
2070		b = 0;
2071		while ('"' != *cp && '\0' != *cp &&
2072		       b < COUNTOF(buf) - 1)
2073			buf[b++] = *cp++;
2074		buf[b] = '\0';
2075		return rtdatetolfp(buf, lfp);
2076	}
2077
2078	/*
2079	 * Might still be hex.  Check out the first character.  Talk
2080	 * about heuristics!
2081	 */
2082	if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2083		return hextolfp(str, lfp);
2084
2085	/*
2086	 * Try it as a decimal.  If this fails, try as an unquoted
2087	 * RT-11 date.  This code should go away eventually.
2088	 */
2089	if (atolfp(str, lfp))
2090		return 1;
2091
2092	return rtdatetolfp(str, lfp);
2093}
2094
2095
2096/*
2097 * decodetime - decode a time value.  It should be in milliseconds
2098 */
2099int
2100decodetime(
2101	char *str,
2102	l_fp *lfp
2103	)
2104{
2105	return mstolfp(str, lfp);
2106}
2107
2108
2109/*
2110 * decodeint - decode an integer
2111 */
2112int
2113decodeint(
2114	char *str,
2115	long *val
2116	)
2117{
2118	if (*str == '0') {
2119		if (*(str+1) == 'x' || *(str+1) == 'X')
2120		    return hextoint(str+2, (u_long *)val);
2121		return octtoint(str, (u_long *)val);
2122	}
2123	return atoint(str, val);
2124}
2125
2126
2127/*
2128 * decodeuint - decode an unsigned integer
2129 */
2130int
2131decodeuint(
2132	char *str,
2133	u_long *val
2134	)
2135{
2136	if (*str == '0') {
2137		if (*(str + 1) == 'x' || *(str + 1) == 'X')
2138			return (hextoint(str + 2, val));
2139		return (octtoint(str, val));
2140	}
2141	return (atouint(str, val));
2142}
2143
2144
2145/*
2146 * decodearr - decode an array of time values
2147 */
2148static int
2149decodearr(
2150	char *str,
2151	int *narr,
2152	l_fp *lfparr
2153	)
2154{
2155	register char *cp, *bp;
2156	register l_fp *lfp;
2157	char buf[60];
2158
2159	lfp = lfparr;
2160	cp = str;
2161	*narr = 0;
2162
2163	while (*narr < 8) {
2164		while (isspace((int)*cp))
2165		    cp++;
2166		if (*cp == '\0')
2167		    break;
2168
2169		bp = buf;
2170		while (!isspace((int)*cp) && *cp != '\0')
2171		    *bp++ = *cp++;
2172		*bp++ = '\0';
2173
2174		if (!decodetime(buf, lfp))
2175		    return 0;
2176		(*narr)++;
2177		lfp++;
2178	}
2179	return 1;
2180}
2181
2182
2183/*
2184 * Finally, the built in command handlers
2185 */
2186
2187/*
2188 * help - tell about commands, or details of a particular command
2189 */
2190static void
2191help(
2192	struct parse *pcmd,
2193	FILE *fp
2194	)
2195{
2196	struct xcmd *xcp = NULL;	/* quiet warning */
2197	const char *cmd;
2198	const char *list[100];
2199	size_t word, words;
2200	size_t row, rows;
2201	size_t col, cols;
2202	size_t length;
2203
2204	if (pcmd->nargs == 0) {
2205		words = 0;
2206		for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2207			if (*(xcp->keyword) != '?' &&
2208			    words < COUNTOF(list))
2209				list[words++] = xcp->keyword;
2210		}
2211		for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2212			if (words < COUNTOF(list))
2213				list[words++] = xcp->keyword;
2214
2215		qsort((void *)list, words, sizeof(list[0]), helpsort);
2216		col = 0;
2217		for (word = 0; word < words; word++) {
2218			length = strlen(list[word]);
2219			col = max(col, length);
2220		}
2221
2222		cols = SCREENWIDTH / ++col;
2223		rows = (words + cols - 1) / cols;
2224
2225		fprintf(fp, "ntpq commands:\n");
2226
2227		for (row = 0; row < rows; row++) {
2228			for (word = row; word < words; word += rows)
2229				fprintf(fp, "%-*.*s", (int)col,
2230					(int)col - 1, list[word]);
2231			fprintf(fp, "\n");
2232		}
2233	} else {
2234		cmd = pcmd->argval[0].string;
2235		words = findcmd(cmd, builtins, opcmds, &xcp);
2236		if (words == 0) {
2237			fprintf(stderr,
2238				"Command `%s' is unknown\n", cmd);
2239			return;
2240		} else if (words >= 2) {
2241			fprintf(stderr,
2242				"Command `%s' is ambiguous\n", cmd);
2243			return;
2244		}
2245		fprintf(fp, "function: %s\n", xcp->comment);
2246		printusage(xcp, fp);
2247	}
2248}
2249
2250
2251/*
2252 * helpsort - do hostname qsort comparisons
2253 */
2254static int
2255helpsort(
2256	const void *t1,
2257	const void *t2
2258	)
2259{
2260	const char * const *	name1 = t1;
2261	const char * const *	name2 = t2;
2262
2263	return strcmp(*name1, *name2);
2264}
2265
2266
2267/*
2268 * printusage - print usage information for a command
2269 */
2270static void
2271printusage(
2272	struct xcmd *xcp,
2273	FILE *fp
2274	)
2275{
2276	register int i;
2277
2278	/* XXX: Do we need to warn about extra args here too? */
2279
2280	(void) fprintf(fp, "usage: %s", xcp->keyword);
2281	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2282		if (xcp->arg[i] & OPT)
2283		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2284		else
2285		    (void) fprintf(fp, " %s", xcp->desc[i]);
2286	}
2287	(void) fprintf(fp, "\n");
2288}
2289
2290
2291/*
2292 * timeout - set time out time
2293 */
2294static void
2295timeout(
2296	struct parse *pcmd,
2297	FILE *fp
2298	)
2299{
2300	int val;
2301
2302	if (pcmd->nargs == 0) {
2303		val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2304		(void) fprintf(fp, "primary timeout %d ms\n", val);
2305	} else {
2306		tvout.tv_sec = pcmd->argval[0].uval / 1000;
2307		tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2308			* 1000;
2309	}
2310}
2311
2312
2313/*
2314 * auth_delay - set delay for auth requests
2315 */
2316static void
2317auth_delay(
2318	struct parse *pcmd,
2319	FILE *fp
2320	)
2321{
2322	int isneg;
2323	u_long val;
2324
2325	if (pcmd->nargs == 0) {
2326		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2327		(void) fprintf(fp, "delay %lu ms\n", val);
2328	} else {
2329		if (pcmd->argval[0].ival < 0) {
2330			isneg = 1;
2331			val = (u_long)(-pcmd->argval[0].ival);
2332		} else {
2333			isneg = 0;
2334			val = (u_long)pcmd->argval[0].ival;
2335		}
2336
2337		delay_time.l_ui = val / 1000;
2338		val %= 1000;
2339		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
2340
2341		if (isneg)
2342		    L_NEG(&delay_time);
2343	}
2344}
2345
2346
2347/*
2348 * host - set the host we are dealing with.
2349 */
2350static void
2351host(
2352	struct parse *pcmd,
2353	FILE *fp
2354	)
2355{
2356	int i;
2357
2358	if (pcmd->nargs == 0) {
2359		if (havehost)
2360			(void) fprintf(fp, "current host is %s\n",
2361					   currenthost);
2362		else
2363			(void) fprintf(fp, "no current host\n");
2364		return;
2365	}
2366
2367	i = 0;
2368	ai_fam_templ = ai_fam_default;
2369	if (pcmd->nargs == 2) {
2370		if (!strcmp("-4", pcmd->argval[i].string))
2371			ai_fam_templ = AF_INET;
2372		else if (!strcmp("-6", pcmd->argval[i].string))
2373			ai_fam_templ = AF_INET6;
2374		else
2375			goto no_change;
2376		i = 1;
2377	}
2378	if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
2379		fprintf(fp, "current host set to %s\n", currenthost);
2380	} else {
2381    no_change:
2382		if (havehost)
2383			fprintf(fp, "current host remains %s\n",
2384				currenthost);
2385		else
2386			fprintf(fp, "still no current host\n");
2387	}
2388}
2389
2390
2391/*
2392 * poll - do one (or more) polls of the host via NTP
2393 */
2394/*ARGSUSED*/
2395static void
2396ntp_poll(
2397	struct parse *pcmd,
2398	FILE *fp
2399	)
2400{
2401	(void) fprintf(fp, "poll not implemented yet\n");
2402}
2403
2404
2405/*
2406 * keyid - get a keyid to use for authenticating requests
2407 */
2408static void
2409keyid(
2410	struct parse *pcmd,
2411	FILE *fp
2412	)
2413{
2414	if (pcmd->nargs == 0) {
2415		if (info_auth_keyid == 0)
2416		    (void) fprintf(fp, "no keyid defined\n");
2417		else
2418		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2419	} else {
2420		/* allow zero so that keyid can be cleared. */
2421		if(pcmd->argval[0].uval > NTP_MAXKEY)
2422		    (void) fprintf(fp, "Invalid key identifier\n");
2423		info_auth_keyid = pcmd->argval[0].uval;
2424	}
2425}
2426
2427/*
2428 * keytype - get type of key to use for authenticating requests
2429 */
2430static void
2431keytype(
2432	struct parse *pcmd,
2433	FILE *fp
2434	)
2435{
2436	const char *	digest_name;
2437	size_t		digest_len;
2438	int		key_type;
2439
2440	if (!pcmd->nargs) {
2441		fprintf(fp, "keytype is %s with %lu octet digests\n",
2442			keytype_name(info_auth_keytype),
2443			(u_long)info_auth_hashlen);
2444		return;
2445	}
2446
2447	digest_name = pcmd->argval[0].string;
2448	digest_len = 0;
2449	key_type = keytype_from_text(digest_name, &digest_len);
2450
2451	if (!key_type) {
2452		fprintf(fp, "keytype is not valid. "
2453#ifdef OPENSSL
2454			"Type \"help keytype\" for the available digest types.\n");
2455#else
2456			"Only \"md5\" is available.\n");
2457#endif
2458		return;
2459	}
2460
2461	info_auth_keytype = key_type;
2462	info_auth_hashlen = digest_len;
2463}
2464
2465
2466/*
2467 * passwd - get an authentication key
2468 */
2469/*ARGSUSED*/
2470static void
2471passwd(
2472	struct parse *pcmd,
2473	FILE *fp
2474	)
2475{
2476	const char *pass;
2477
2478	if (info_auth_keyid == 0) {
2479		info_auth_keyid = getkeyid("Keyid: ");
2480		if (info_auth_keyid == 0) {
2481			(void)fprintf(fp, "Keyid must be defined\n");
2482			return;
2483		}
2484	}
2485	if (pcmd->nargs >= 1)
2486		pass = pcmd->argval[0].string;
2487	else {
2488		pass = getpass_keytype(info_auth_keytype);
2489		if ('\0' == pass[0]) {
2490			fprintf(fp, "Password unchanged\n");
2491			return;
2492		}
2493	}
2494	authusekey(info_auth_keyid, info_auth_keytype,
2495		   (const u_char *)pass);
2496	authtrust(info_auth_keyid, 1);
2497}
2498
2499
2500/*
2501 * hostnames - set the showhostnames flag
2502 */
2503static void
2504hostnames(
2505	struct parse *pcmd,
2506	FILE *fp
2507	)
2508{
2509	if (pcmd->nargs == 0) {
2510		if (showhostnames)
2511		    (void) fprintf(fp, "hostnames being shown\n");
2512		else
2513		    (void) fprintf(fp, "hostnames not being shown\n");
2514	} else {
2515		if (STREQ(pcmd->argval[0].string, "yes"))
2516		    showhostnames = 1;
2517		else if (STREQ(pcmd->argval[0].string, "no"))
2518		    showhostnames = 0;
2519		else
2520		    (void)fprintf(stderr, "What?\n");
2521	}
2522}
2523
2524
2525
2526/*
2527 * setdebug - set/change debugging level
2528 */
2529static void
2530setdebug(
2531	struct parse *pcmd,
2532	FILE *fp
2533	)
2534{
2535	if (pcmd->nargs == 0) {
2536		(void) fprintf(fp, "debug level is %d\n", debug);
2537		return;
2538	} else if (STREQ(pcmd->argval[0].string, "no")) {
2539		debug = 0;
2540	} else if (STREQ(pcmd->argval[0].string, "more")) {
2541		debug++;
2542	} else if (STREQ(pcmd->argval[0].string, "less")) {
2543		debug--;
2544	} else {
2545		(void) fprintf(fp, "What?\n");
2546		return;
2547	}
2548	(void) fprintf(fp, "debug level set to %d\n", debug);
2549}
2550
2551
2552/*
2553 * quit - stop this nonsense
2554 */
2555/*ARGSUSED*/
2556static void
2557quit(
2558	struct parse *pcmd,
2559	FILE *fp
2560	)
2561{
2562	if (havehost)
2563	    closesocket(sockfd);	/* cleanliness next to godliness */
2564	exit(0);
2565}
2566
2567
2568/*
2569 * version - print the current version number
2570 */
2571/*ARGSUSED*/
2572static void
2573version(
2574	struct parse *pcmd,
2575	FILE *fp
2576	)
2577{
2578
2579	(void) fprintf(fp, "%s\n", Version);
2580	return;
2581}
2582
2583
2584/*
2585 * raw - set raw mode output
2586 */
2587/*ARGSUSED*/
2588static void
2589raw(
2590	struct parse *pcmd,
2591	FILE *fp
2592	)
2593{
2594	rawmode = 1;
2595	(void) fprintf(fp, "Output set to raw\n");
2596}
2597
2598
2599/*
2600 * cooked - set cooked mode output
2601 */
2602/*ARGSUSED*/
2603static void
2604cooked(
2605	struct parse *pcmd,
2606	FILE *fp
2607	)
2608{
2609	rawmode = 0;
2610	(void) fprintf(fp, "Output set to cooked\n");
2611	return;
2612}
2613
2614
2615/*
2616 * authenticate - always authenticate requests to this host
2617 */
2618static void
2619authenticate(
2620	struct parse *pcmd,
2621	FILE *fp
2622	)
2623{
2624	if (pcmd->nargs == 0) {
2625		if (always_auth) {
2626			(void) fprintf(fp,
2627				       "authenticated requests being sent\n");
2628		} else
2629		    (void) fprintf(fp,
2630				   "unauthenticated requests being sent\n");
2631	} else {
2632		if (STREQ(pcmd->argval[0].string, "yes")) {
2633			always_auth = 1;
2634		} else if (STREQ(pcmd->argval[0].string, "no")) {
2635			always_auth = 0;
2636		} else
2637		    (void)fprintf(stderr, "What?\n");
2638	}
2639}
2640
2641
2642/*
2643 * ntpversion - choose the NTP version to use
2644 */
2645static void
2646ntpversion(
2647	struct parse *pcmd,
2648	FILE *fp
2649	)
2650{
2651	if (pcmd->nargs == 0) {
2652		(void) fprintf(fp,
2653			       "NTP version being claimed is %d\n", pktversion);
2654	} else {
2655		if (pcmd->argval[0].uval < NTP_OLDVERSION
2656		    || pcmd->argval[0].uval > NTP_VERSION) {
2657			(void) fprintf(stderr, "versions %d to %d, please\n",
2658				       NTP_OLDVERSION, NTP_VERSION);
2659		} else {
2660			pktversion = (u_char) pcmd->argval[0].uval;
2661		}
2662	}
2663}
2664
2665
2666static void __attribute__((__format__(__printf__, 1, 0)))
2667vwarning(const char *fmt, va_list ap)
2668{
2669	int serrno = errno;
2670	(void) fprintf(stderr, "%s: ", progname);
2671	vfprintf(stderr, fmt, ap);
2672	(void) fprintf(stderr, ": %s\n", strerror(serrno));
2673}
2674
2675/*
2676 * warning - print a warning message
2677 */
2678static void __attribute__((__format__(__printf__, 1, 2)))
2679warning(
2680	const char *fmt,
2681	...
2682	)
2683{
2684	va_list ap;
2685	va_start(ap, fmt);
2686	vwarning(fmt, ap);
2687	va_end(ap);
2688}
2689
2690
2691/*
2692 * error - print a message and exit
2693 */
2694static void __attribute__((__format__(__printf__, 1, 2)))
2695error(
2696	const char *fmt,
2697	...
2698	)
2699{
2700	va_list ap;
2701	va_start(ap, fmt);
2702	vwarning(fmt, ap);
2703	va_end(ap);
2704	exit(1);
2705}
2706/*
2707 * getkeyid - prompt the user for a keyid to use
2708 */
2709static u_long
2710getkeyid(
2711	const char *keyprompt
2712	)
2713{
2714	int c;
2715	FILE *fi;
2716	char pbuf[20];
2717	size_t i;
2718	size_t ilim;
2719
2720#ifndef SYS_WINNT
2721	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2722#else
2723	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2724#endif /* SYS_WINNT */
2725		fi = stdin;
2726	else
2727		setbuf(fi, (char *)NULL);
2728	fprintf(stderr, "%s", keyprompt); fflush(stderr);
2729	for (i = 0, ilim = COUNTOF(pbuf) - 1;
2730	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
2731	     )
2732		pbuf[i++] = (char)c;
2733	pbuf[i] = '\0';
2734	if (fi != stdin)
2735		fclose(fi);
2736
2737	return (u_long) atoi(pbuf);
2738}
2739
2740
2741/*
2742 * atoascii - printable-ize possibly ascii data using the character
2743 *	      transformations cat -v uses.
2744 */
2745static void
2746atoascii(
2747	const char *in,
2748	size_t in_octets,
2749	char *out,
2750	size_t out_octets
2751	)
2752{
2753	const u_char *	pchIn;
2754	const u_char *	pchInLimit;
2755	u_char *	pchOut;
2756	u_char		c;
2757
2758	pchIn = (const u_char *)in;
2759	pchInLimit = pchIn + in_octets;
2760	pchOut = (u_char *)out;
2761
2762	if (NULL == pchIn) {
2763		if (0 < out_octets)
2764			*pchOut = '\0';
2765		return;
2766	}
2767
2768#define	ONEOUT(c)					\
2769do {							\
2770	if (0 == --out_octets) {			\
2771		*pchOut = '\0';				\
2772		return;					\
2773	}						\
2774	*pchOut++ = (c);				\
2775} while (0)
2776
2777	for (	; pchIn < pchInLimit; pchIn++) {
2778		c = *pchIn;
2779		if ('\0' == c)
2780			break;
2781		if (c & 0x80) {
2782			ONEOUT('M');
2783			ONEOUT('-');
2784			c &= 0x7f;
2785		}
2786		if (c < ' ') {
2787			ONEOUT('^');
2788			ONEOUT((u_char)(c + '@'));
2789		} else if (0x7f == c) {
2790			ONEOUT('^');
2791			ONEOUT('?');
2792		} else
2793			ONEOUT(c);
2794	}
2795	ONEOUT('\0');
2796
2797#undef ONEOUT
2798}
2799
2800
2801/*
2802 * makeascii - print possibly ascii data using the character
2803 *	       transformations that cat -v uses.
2804 */
2805void
2806makeascii(
2807	size_t length,
2808	const char *data,
2809	FILE *fp
2810	)
2811{
2812	const u_char *data_u_char;
2813	const u_char *cp;
2814	int c;
2815
2816	data_u_char = (const u_char *)data;
2817
2818	for (cp = data_u_char; cp < data_u_char + length; cp++) {
2819		c = (int)*cp;
2820		if (c & 0x80) {
2821			putc('M', fp);
2822			putc('-', fp);
2823			c &= 0x7f;
2824		}
2825
2826		if (c < ' ') {
2827			putc('^', fp);
2828			putc(c + '@', fp);
2829		} else if (0x7f == c) {
2830			putc('^', fp);
2831			putc('?', fp);
2832		} else
2833			putc(c, fp);
2834	}
2835}
2836
2837
2838/*
2839 * asciize - same thing as makeascii except add a newline
2840 */
2841void
2842asciize(
2843	int length,
2844	char *data,
2845	FILE *fp
2846	)
2847{
2848	makeascii(length, data, fp);
2849	putc('\n', fp);
2850}
2851
2852
2853/*
2854 * truncate string to fit clipping excess at end.
2855 *	"too long"	->	"too l"
2856 * Used for hostnames.
2857 */
2858const char *
2859trunc_right(
2860	const char *	src,
2861	size_t		width
2862	)
2863{
2864	size_t	sl;
2865	char *	out;
2866
2867
2868	sl = strlen(src);
2869	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
2870		LIB_GETBUF(out);
2871		memcpy(out, src, width);
2872		out[width] = '\0';
2873
2874		return out;
2875	}
2876
2877	return src;
2878}
2879
2880
2881/*
2882 * truncate string to fit by preserving right side and using '_' to hint
2883 *	"too long"	->	"_long"
2884 * Used for local IPv6 addresses, where low bits differentiate.
2885 */
2886const char *
2887trunc_left(
2888	const char *	src,
2889	size_t		width
2890	)
2891{
2892	size_t	sl;
2893	char *	out;
2894
2895
2896	sl = strlen(src);
2897	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
2898		LIB_GETBUF(out);
2899		out[0] = '_';
2900		memcpy(&out[1], &src[sl + 1 - width], width);
2901
2902		return out;
2903	}
2904
2905	return src;
2906}
2907
2908
2909/*
2910 * Some circular buffer space
2911 */
2912#define	CBLEN	80
2913#define	NUMCB	6
2914
2915char circ_buf[NUMCB][CBLEN];
2916int nextcb = 0;
2917
2918/*
2919 * nextvar - find the next variable in the buffer
2920 */
2921int
2922nextvar(
2923	size_t *datalen,
2924	const char **datap,
2925	char **vname,
2926	char **vvalue
2927	)
2928{
2929	const char *cp;
2930	const char *np;
2931	const char *cpend;
2932	size_t srclen;
2933	size_t len;
2934	static char name[MAXVARLEN];
2935	static char value[MAXVALLEN];
2936
2937	cp = *datap;
2938	cpend = cp + *datalen;
2939
2940	/*
2941	 * Space past commas and white space
2942	 */
2943	while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
2944		cp++;
2945	if (cp >= cpend)
2946		return 0;
2947
2948	/*
2949	 * Copy name until we hit a ',', an '=', a '\r' or a '\n'.  Backspace
2950	 * over any white space and terminate it.
2951	 */
2952	srclen = strcspn(cp, ",=\r\n");
2953	srclen = min(srclen, (size_t)(cpend - cp));
2954	len = srclen;
2955	while (len > 0 && isspace((unsigned char)cp[len - 1]))
2956		len--;
2957	if (len > 0)
2958		memcpy(name, cp, len);
2959	name[len] = '\0';
2960	*vname = name;
2961	cp += srclen;
2962
2963	/*
2964	 * Check if we hit the end of the buffer or a ','.  If so we are done.
2965	 */
2966	if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
2967		if (cp < cpend)
2968			cp++;
2969		*datap = cp;
2970		*datalen = size2int_sat(cpend - cp);
2971		*vvalue = NULL;
2972		return 1;
2973	}
2974
2975	/*
2976	 * So far, so good.  Copy out the value
2977	 */
2978	cp++;	/* past '=' */
2979	while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n'))
2980		cp++;
2981	np = cp;
2982	if ('"' == *np) {
2983		do {
2984			np++;
2985		} while (np < cpend && '"' != *np);
2986		if (np < cpend && '"' == *np)
2987			np++;
2988	} else {
2989		while (np < cpend && ',' != *np && '\r' != *np)
2990			np++;
2991	}
2992	len = np - cp;
2993	if (np > cpend || len >= sizeof(value) ||
2994	    (np < cpend && ',' != *np && '\r' != *np))
2995		return 0;
2996	memcpy(value, cp, len);
2997	/*
2998	 * Trim off any trailing whitespace
2999	 */
3000	while (len > 0 && isspace((unsigned char)value[len - 1]))
3001		len--;
3002	value[len] = '\0';
3003
3004	/*
3005	 * Return this.  All done.
3006	 */
3007	if (np < cpend && ',' == *np)
3008		np++;
3009	*datap = np;
3010	*datalen = size2int_sat(cpend - np);
3011	*vvalue = value;
3012	return 1;
3013}
3014
3015
3016u_short
3017varfmt(const char * varname)
3018{
3019	u_int n;
3020
3021	for (n = 0; n < COUNTOF(cookedvars); n++)
3022		if (!strcmp(varname, cookedvars[n].varname))
3023			return cookedvars[n].fmt;
3024
3025	return PADDING;
3026}
3027
3028
3029/*
3030 * printvars - print variables returned in response packet
3031 */
3032void
3033printvars(
3034	size_t length,
3035	const char *data,
3036	int status,
3037	int sttype,
3038	int quiet,
3039	FILE *fp
3040	)
3041{
3042	if (rawmode)
3043	    rawprint(sttype, length, data, status, quiet, fp);
3044	else
3045	    cookedprint(sttype, length, data, status, quiet, fp);
3046}
3047
3048
3049/*
3050 * rawprint - do a printout of the data in raw mode
3051 */
3052static void
3053rawprint(
3054	int datatype,
3055	size_t length,
3056	const char *data,
3057	int status,
3058	int quiet,
3059	FILE *fp
3060	)
3061{
3062	const char *cp;
3063	const char *cpend;
3064
3065	/*
3066	 * Essentially print the data as is.  We reformat unprintables, though.
3067	 */
3068	cp = data;
3069	cpend = data + length;
3070
3071	if (!quiet)
3072		(void) fprintf(fp, "status=0x%04x,\n", status);
3073
3074	while (cp < cpend) {
3075		if (*cp == '\r') {
3076			/*
3077			 * If this is a \r and the next character is a
3078			 * \n, supress this, else pretty print it.  Otherwise
3079			 * just output the character.
3080			 */
3081			if (cp == (cpend - 1) || *(cp + 1) != '\n')
3082			    makeascii(1, cp, fp);
3083		} else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp))
3084			putc(*cp, fp);
3085		else
3086			makeascii(1, cp, fp);
3087		cp++;
3088	}
3089}
3090
3091
3092/*
3093 * Global data used by the cooked output routines
3094 */
3095int out_chars;		/* number of characters output */
3096int out_linecount;	/* number of characters output on this line */
3097
3098
3099/*
3100 * startoutput - get ready to do cooked output
3101 */
3102static void
3103startoutput(void)
3104{
3105	out_chars = 0;
3106	out_linecount = 0;
3107}
3108
3109
3110/*
3111 * output - output a variable=value combination
3112 */
3113static void
3114output(
3115	FILE *fp,
3116	const char *name,
3117	const char *value
3118	)
3119{
3120	int len;
3121
3122	/* strlen of "name=value" */
3123	len = size2int_sat(strlen(name) + 1 + strlen(value));
3124
3125	if (out_chars != 0) {
3126		out_chars += 2;
3127		if ((out_linecount + len + 2) > MAXOUTLINE) {
3128			fputs(",\n", fp);
3129			out_linecount = 0;
3130		} else {
3131			fputs(", ", fp);
3132			out_linecount += 2;
3133		}
3134	}
3135
3136	fputs(name, fp);
3137	putc('=', fp);
3138	fputs(value, fp);
3139	out_chars += len;
3140	out_linecount += len;
3141}
3142
3143
3144/*
3145 * endoutput - terminate a block of cooked output
3146 */
3147static void
3148endoutput(
3149	FILE *fp
3150	)
3151{
3152	if (out_chars != 0)
3153		putc('\n', fp);
3154}
3155
3156
3157/*
3158 * outputarr - output an array of values
3159 */
3160static void
3161outputarr(
3162	FILE *fp,
3163	char *name,
3164	int narr,
3165	l_fp *lfp
3166	)
3167{
3168	char *bp;
3169	char *cp;
3170	size_t i;
3171	size_t len;
3172	char buf[256];
3173
3174	bp = buf;
3175	/*
3176	 * Hack to align delay and offset values
3177	 */
3178	for (i = (int)strlen(name); i < 11; i++)
3179	    *bp++ = ' ';
3180
3181	for (i = narr; i > 0; i--) {
3182		if (i != narr)
3183		    *bp++ = ' ';
3184		cp = lfptoms(lfp, 2);
3185		len = strlen(cp);
3186		if (len > 7) {
3187			cp[7] = '\0';
3188			len = 7;
3189		}
3190		while (len < 7) {
3191			*bp++ = ' ';
3192			len++;
3193		}
3194		while (*cp != '\0')
3195		    *bp++ = *cp++;
3196		lfp++;
3197	}
3198	*bp = '\0';
3199	output(fp, name, buf);
3200}
3201
3202static char *
3203tstflags(
3204	u_long val
3205	)
3206{
3207	register char *cp, *s;
3208	size_t cb;
3209	register int i;
3210	register const char *sep;
3211
3212	sep = "";
3213	s = cp = circ_buf[nextcb];
3214	if (++nextcb >= NUMCB)
3215		nextcb = 0;
3216	cb = sizeof(circ_buf[0]);
3217
3218	snprintf(cp, cb, "%02lx", val);
3219	cp += strlen(cp);
3220	cb -= strlen(cp);
3221	if (!val) {
3222		strlcat(cp, " ok", cb);
3223		cp += strlen(cp);
3224		cb -= strlen(cp);
3225	} else {
3226		if (cb) {
3227			*cp++ = ' ';
3228			cb--;
3229		}
3230		for (i = 0; i < (int)COUNTOF(tstflagnames); i++) {
3231			if (val & 0x1) {
3232				snprintf(cp, cb, "%s%s", sep,
3233					 tstflagnames[i]);
3234				sep = ", ";
3235				cp += strlen(cp);
3236				cb -= strlen(cp);
3237			}
3238			val >>= 1;
3239		}
3240	}
3241	if (cb)
3242		*cp = '\0';
3243
3244	return s;
3245}
3246
3247/*
3248 * cookedprint - output variables in cooked mode
3249 */
3250static void
3251cookedprint(
3252	int datatype,
3253	size_t length,
3254	const char *data,
3255	int status,
3256	int quiet,
3257	FILE *fp
3258	)
3259{
3260	char *name;
3261	char *value;
3262	char output_raw;
3263	int fmt;
3264	l_fp lfp;
3265	sockaddr_u hval;
3266	u_long uval;
3267	int narr;
3268	size_t len;
3269	l_fp lfparr[8];
3270	char b[12];
3271	char bn[2 * MAXVARLEN];
3272	char bv[2 * MAXVALLEN];
3273
3274	UNUSED_ARG(datatype);
3275
3276	if (!quiet)
3277		fprintf(fp, "status=%04x %s,\n", status,
3278			statustoa(datatype, status));
3279
3280	startoutput();
3281	while (nextvar(&length, &data, &name, &value)) {
3282		fmt = varfmt(name);
3283		output_raw = 0;
3284		switch (fmt) {
3285
3286		case PADDING:
3287			output_raw = '*';
3288			break;
3289
3290		case TS:
3291			if (!decodets(value, &lfp))
3292				output_raw = '?';
3293			else
3294				output(fp, name, prettydate(&lfp));
3295			break;
3296
3297		case HA:	/* fallthru */
3298		case NA:
3299			if (!decodenetnum(value, &hval)) {
3300				output_raw = '?';
3301			} else if (fmt == HA){
3302				output(fp, name, nntohost(&hval));
3303			} else {
3304				output(fp, name, stoa(&hval));
3305			}
3306			break;
3307
3308		case RF:
3309			if (decodenetnum(value, &hval)) {
3310				if (ISREFCLOCKADR(&hval))
3311					output(fp, name,
3312					       refnumtoa(&hval));
3313				else
3314					output(fp, name, stoa(&hval));
3315			} else if (strlen(value) <= 4) {
3316				output(fp, name, value);
3317			} else {
3318				output_raw = '?';
3319			}
3320			break;
3321
3322		case LP:
3323			if (!decodeuint(value, &uval) || uval > 3) {
3324				output_raw = '?';
3325			} else {
3326				b[0] = (0x2 & uval)
3327					   ? '1'
3328					   : '0';
3329				b[1] = (0x1 & uval)
3330					   ? '1'
3331					   : '0';
3332				b[2] = '\0';
3333				output(fp, name, b);
3334			}
3335			break;
3336
3337		case OC:
3338			if (!decodeuint(value, &uval)) {
3339				output_raw = '?';
3340			} else {
3341				snprintf(b, sizeof(b), "%03lo", uval);
3342				output(fp, name, b);
3343			}
3344			break;
3345
3346		case AR:
3347			if (!decodearr(value, &narr, lfparr))
3348				output_raw = '?';
3349			else
3350				outputarr(fp, name, narr, lfparr);
3351			break;
3352
3353		case FX:
3354			if (!decodeuint(value, &uval))
3355				output_raw = '?';
3356			else
3357				output(fp, name, tstflags(uval));
3358			break;
3359
3360		default:
3361			fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
3362				name, value, fmt);
3363			output_raw = '?';
3364			break;
3365		}
3366
3367		if (output_raw != 0) {
3368			/* TALOS-CAN-0063: avoid buffer overrun */
3369			atoascii(name, MAXVARLEN, bn, sizeof(bn));
3370			if (output_raw != '*') {
3371				atoascii(value, MAXVALLEN,
3372					 bv, sizeof(bv) - 1);
3373				len = strlen(bv);
3374				bv[len] = output_raw;
3375				bv[len+1] = '\0';
3376			} else {
3377				atoascii(value, MAXVALLEN,
3378					 bv, sizeof(bv));
3379			}
3380			output(fp, bn, bv);
3381		}
3382	}
3383	endoutput(fp);
3384}
3385
3386
3387/*
3388 * sortassoc - sort associations in the cache into ascending order
3389 */
3390void
3391sortassoc(void)
3392{
3393	if (numassoc > 1)
3394		qsort(assoc_cache, (size_t)numassoc,
3395		      sizeof(assoc_cache[0]), &assoccmp);
3396}
3397
3398
3399/*
3400 * assoccmp - compare two associations
3401 */
3402static int
3403assoccmp(
3404	const void *t1,
3405	const void *t2
3406	)
3407{
3408	const struct association *ass1 = t1;
3409	const struct association *ass2 = t2;
3410
3411	if (ass1->assid < ass2->assid)
3412		return -1;
3413	if (ass1->assid > ass2->assid)
3414		return 1;
3415	return 0;
3416}
3417
3418
3419/*
3420 * grow_assoc_cache() - enlarge dynamic assoc_cache array
3421 *
3422 * The strategy is to add an assumed 4k page size at a time, leaving
3423 * room for malloc() bookkeeping overhead equivalent to 4 pointers.
3424 */
3425void
3426grow_assoc_cache(void)
3427{
3428	static size_t	prior_sz;
3429	size_t		new_sz;
3430
3431	new_sz = prior_sz + 4 * 1024;
3432	if (0 == prior_sz) {
3433		new_sz -= 4 * sizeof(void *);
3434	}
3435	assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
3436	prior_sz = new_sz;
3437	assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0]));
3438}
3439
3440
3441/*
3442 * ntpq_custom_opt_handler - autoopts handler for -c and -p
3443 *
3444 * By default, autoopts loses the relative order of -c and -p options
3445 * on the command line.  This routine replaces the default handler for
3446 * those routines and builds a list of commands to execute preserving
3447 * the order.
3448 */
3449void
3450ntpq_custom_opt_handler(
3451	tOptions *pOptions,
3452	tOptDesc *pOptDesc
3453	)
3454{
3455	switch (pOptDesc->optValue) {
3456
3457	default:
3458		fprintf(stderr,
3459			"ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3460			pOptDesc->optValue, pOptDesc->optValue);
3461		exit(1);
3462
3463	case 'c':
3464		ADDCMD(pOptDesc->pzLastArg);
3465		break;
3466
3467	case 'p':
3468		ADDCMD("peers");
3469		break;
3470	}
3471}
3472/*
3473 * Obtain list of digest names
3474 */
3475
3476#ifdef OPENSSL
3477# ifdef HAVE_EVP_MD_DO_ALL_SORTED
3478struct hstate {
3479   char *list;
3480   const char **seen;
3481   int idx;
3482};
3483#define K_PER_LINE 8
3484#define K_NL_PFX_STR "\n    "
3485#define K_DELIM_STR ", "
3486static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg )
3487{
3488    size_t len, n;
3489    const char *name, *cp, **seen;
3490    struct hstate *hstate = arg;
3491    EVP_MD_CTX ctx;
3492    u_int digest_len;
3493    u_char digest[EVP_MAX_MD_SIZE];
3494
3495    if (!m)
3496        return; /* Ignore aliases */
3497
3498    name = EVP_MD_name(m);
3499
3500    /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
3501
3502    for( cp = name; *cp; cp++ ) {
3503	if( islower(*cp) )
3504	    return;
3505    }
3506    len = (cp - name) + 1;
3507
3508    /* There are duplicates.  Discard if name has been seen. */
3509
3510    for (seen = hstate->seen; *seen; seen++)
3511        if (!strcmp(*seen, name))
3512	    return;
3513    n = (seen - hstate->seen) + 2;
3514    hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
3515    hstate->seen[n-2] = name;
3516    hstate->seen[n-1] = NULL;
3517
3518    /* Discard MACs that NTP won't accept.
3519     * Keep this consistent with keytype_from_text() in ssl_init.c.
3520     */
3521
3522    EVP_DigestInit(&ctx, EVP_get_digestbyname(name));
3523    EVP_DigestFinal(&ctx, digest, &digest_len);
3524    if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t)))
3525        return;
3526
3527    if (hstate->list != NULL)
3528	len += strlen(hstate->list);
3529    len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR);
3530
3531    if (hstate->list == NULL) {
3532	hstate->list = (char *)emalloc(len);
3533	hstate->list[0] = '\0';
3534    } else
3535	hstate->list = (char *)erealloc(hstate->list, len);
3536
3537    sprintf(hstate->list + strlen(hstate->list), "%s%s",
3538	    ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR),
3539	    name);
3540    if (hstate->idx >= K_PER_LINE)
3541	hstate->idx = 1;
3542    else
3543	hstate->idx++;
3544}
3545# endif
3546#endif
3547
3548static char *list_digest_names(void)
3549{
3550    char *list = NULL;
3551
3552#ifdef OPENSSL
3553# ifdef HAVE_EVP_MD_DO_ALL_SORTED
3554    struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
3555
3556    hstate.seen = (const char **) emalloc_zero(1*sizeof( const char * )); // replaces -> calloc(1, sizeof( const char * ));
3557
3558    INIT_SSL();
3559    EVP_MD_do_all_sorted(list_md_fn, &hstate);
3560    list = hstate.list;
3561    free(hstate.seen);
3562# else
3563    list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
3564    strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
3565# endif
3566#else
3567    list = (char *)emalloc(sizeof("md5"));
3568    strcpy(list, "md5");
3569#endif
3570
3571    return list;
3572}
3573
3574#define CTRLC_STACK_MAX 4
3575static volatile size_t		ctrlc_stack_len = 0;
3576static volatile Ctrl_C_Handler	ctrlc_stack[CTRLC_STACK_MAX];
3577
3578
3579
3580int/*BOOL*/
3581push_ctrl_c_handler(
3582	Ctrl_C_Handler func
3583	)
3584{
3585	size_t size = ctrlc_stack_len;
3586	if (func && (size < CTRLC_STACK_MAX)) {
3587		ctrlc_stack[size] = func;
3588		ctrlc_stack_len = size + 1;
3589		return TRUE;
3590	}
3591	return FALSE;
3592}
3593
3594int/*BOOL*/
3595pop_ctrl_c_handler(
3596	Ctrl_C_Handler func
3597	)
3598{
3599	size_t size = ctrlc_stack_len;
3600	if (size) {
3601		--size;
3602		if (func == NULL || func == ctrlc_stack[size]) {
3603			ctrlc_stack_len = size;
3604			return TRUE;
3605		}
3606	}
3607	return FALSE;
3608}
3609
3610static void
3611on_ctrlc(void)
3612{
3613	size_t size = ctrlc_stack_len;
3614	while (size)
3615		if ((*ctrlc_stack[--size])())
3616			break;
3617}
3618