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