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