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