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