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