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