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