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