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