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