xref: /freebsd/contrib/ntp/ntpdc/ntpdc.c (revision d0b2dbfa)
1 /*
2  * ntpdc - control and monitor your ntpd daemon
3  */
4 #include <config.h>
5 #include <stdio.h>
6 #include <stddef.h>
7 #include <ctype.h>
8 #include <signal.h>
9 #include <setjmp.h>
10 #ifdef HAVE_UNISTD_H
11 # include <unistd.h>
12 #endif
13 #ifdef HAVE_FCNTL_H
14 # include <fcntl.h>
15 #endif
16 #ifdef SYS_WINNT
17 # include <mswsock.h>
18 #endif
19 #include <isc/net.h>
20 #include <isc/result.h>
21 
22 #include "ntpdc.h"
23 #include "ntp_select.h"
24 #include "ntp_stdlib.h"
25 #include "ntp_assert.h"
26 #include "ntp_lineedit.h"
27 #ifdef OPENSSL
28 #include "openssl/evp.h"
29 #include "openssl/objects.h"
30 #endif
31 #include <ssl_applink.c>
32 
33 #include "ntp_libopts.h"
34 #include "ntpdc-opts.h"
35 #include "safecast.h"
36 
37 #ifdef SYS_VXWORKS
38 				/* vxWorks needs mode flag -casey*/
39 # define open(name, flags)   open(name, flags, 0777)
40 # define SERVER_PORT_NUM     123
41 #endif
42 
43 /* We use COMMAND as an autogen keyword */
44 #ifdef COMMAND
45 # undef COMMAND
46 #endif
47 
48 /*
49  * Because we now potentially understand a lot of commands (and
50  * it requires a lot of commands to talk to ntpd) we will run
51  * interactive if connected to a terminal.
52  */
53 static	int	interactive = 0;	/* set to 1 when we should prompt */
54 static	const char *	prompt = "ntpdc> ";	/* prompt to ask him about */
55 
56 /*
57  * Keyid used for authenticated requests.  Obtained on the fly.
58  */
59 static	u_long	info_auth_keyid;
60 static int keyid_entered = 0;
61 
62 static	int	info_auth_keytype = NID_md5;	/* MD5 */
63 static	size_t	info_auth_hashlen = 16;		/* MD5 */
64 u_long	current_time;		/* needed by authkeys; not used */
65 
66 /*
67  * for get_systime()
68  */
69 s_char	sys_precision;		/* local clock precision (log2 s) */
70 
71 int		ntpdcmain	(int,	char **);
72 /*
73  * Built in command handler declarations
74  */
75 static	int	openhost	(const char *);
76 static	int	sendpkt		(void *, size_t);
77 static	void	growpktdata	(void);
78 static	int	getresponse	(int, int, size_t *, size_t *, const char **, size_t);
79 static	int	sendrequest	(int, int, int, size_t, size_t, const char *);
80 static	void	getcmds		(void);
81 static	RETSIGTYPE abortcmd	(int);
82 static	void	docmd		(const char *);
83 static	void	tokenize	(const char *, char **, int *);
84 static	int	findcmd		(char *, struct xcmd *, struct xcmd *, struct xcmd **);
85 static	int	getarg		(char *, int, arg_v *);
86 static	int	getnetnum	(const char *, sockaddr_u *, char *, int);
87 static	void	help		(struct parse *, FILE *);
88 static	int	helpsort	(const void *, const void *);
89 static	void	printusage	(struct xcmd *, FILE *);
90 static	void	timeout		(struct parse *, FILE *);
91 static	void	my_delay	(struct parse *, FILE *);
92 static	void	host		(struct parse *, FILE *);
93 static	void	keyid		(struct parse *, FILE *);
94 static	void	keytype		(struct parse *, FILE *);
95 static	void	passwd		(struct parse *, FILE *);
96 static	void	hostnames	(struct parse *, FILE *);
97 static	void	setdebug	(struct parse *, FILE *);
98 static	void	quit		(struct parse *, FILE *);
99 static	void	version		(struct parse *, FILE *);
100 static	void	warning		(const char *, ...)
101     __attribute__((__format__(__printf__, 1, 2)));
102 static	void	error		(const char *, ...)
103     __attribute__((__format__(__printf__, 1, 2)));
104 static	u_long	getkeyid	(const char *);
105 
106 
107 
108 /*
109  * Built-in commands we understand
110  */
111 static	struct xcmd builtins[] = {
112 	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
113 	  { "command", "", "", "" },
114 	  "tell the use and syntax of commands" },
115 	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
116 	  { "command", "", "", "" },
117 	  "tell the use and syntax of commands" },
118 	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
119 	  { "msec", "", "", "" },
120 	  "set the primary receive time out" },
121 	{ "delay",	my_delay,	{ OPT|NTP_INT, NO, NO, NO },
122 	  { "msec", "", "", "" },
123 	  "set the delay added to encryption time stamps" },
124 	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
125 	  { "-4|-6", "hostname", "", "" },
126 	  "specify the host whose NTP server we talk to" },
127 	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
128 	  { "", "", "", "" },
129 	  "specify a password to use for authenticated requests"},
130 	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
131 	  { "yes|no", "", "", "" },
132 	  "specify whether hostnames or net numbers are printed"},
133 	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
134 	  { "no|more|less", "", "", "" },
135 	  "set/change debugging level" },
136 	{ "quit",	quit,		{ NO, NO, NO, NO },
137 	  { "", "", "", "" },
138 	  "exit ntpdc" },
139 	{ "exit",	quit,		{ NO, NO, NO, NO },
140 	  { "", "", "", "" },
141 	  "exit ntpdc" },
142 	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
143 	  { "key#", "", "", "" },
144 	  "set/show keyid to use for authenticated requests" },
145 	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
146 	  { "(md5|des)", "", "", "" },
147 	  "set/show key authentication type for authenticated requests (des|md5)" },
148 	{ "version",	version,	{ NO, NO, NO, NO },
149 	  { "", "", "", "" },
150 	  "print version number" },
151 	{ 0,		0,		{ NO, NO, NO, NO },
152 	  { "", "", "", "" }, "" }
153 };
154 
155 
156 /*
157  * Default values we use.
158  */
159 #define	DEFHOST		"localhost"	/* default host name */
160 #define	DEFTIMEOUT	(5)		/* 5 second time out */
161 #define	DEFSTIMEOUT	(2)		/* 2 second time out after first */
162 #define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
163 #define	LENHOSTNAME	256		/* host name is 256 characters long */
164 #define	MAXCMDS		100		/* maximum commands on cmd line */
165 #define	MAXHOSTS	200		/* maximum hosts on cmd line */
166 #define	MAXLINE		512		/* maximum line length */
167 #define	MAXTOKENS	(1+1+MAXARGS+MOREARGS+2)	/* maximum number of usable tokens */
168 #define	SCREENWIDTH  	78		/* nominal screen width in columns */
169 
170 /*
171  * Some variables used and manipulated locally
172  */
173 static	struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
174 static	struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
175 static	l_fp delay_time;				/* delay time */
176 static	char currenthost[LENHOSTNAME];			/* current host name */
177 int showhostnames = 1;					/* show host names by default */
178 
179 static	int ai_fam_templ = AF_UNSPEC;		/* address family */
180 static	int ai_fam_default = AF_UNSPEC;	/* default address family */
181 static	SOCKET sockfd;					/* fd socket is opened on */
182 static	int havehost = 0;				/* set to 1 when host open */
183 int s_port = 0;
184 
185 /*
186  * Holds data returned from queries.  We allocate INITDATASIZE
187  * octets to begin with, increasing this as we need to.
188  */
189 #define	INITDATASIZE	(sizeof(struct resp_pkt) * 16)
190 #define	INCDATASIZE	(sizeof(struct resp_pkt) * 8)
191 
192 static	char *pktdata;
193 static	int pktdatasize;
194 
195 /*
196  * These are used to help the magic with old and new versions of ntpd.
197  */
198 int impl_ver = IMPL_XNTPD;
199 static int req_pkt_size = REQ_LEN_NOMAC;
200 
201 /*
202  * For commands typed on the command line (with the -c option)
203  */
204 static	int numcmds = 0;
205 static	const char *ccmds[MAXCMDS];
206 #define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
207 
208 /*
209  * When multiple hosts are specified.
210  */
211 static	int numhosts = 0;
212 static	const char *chosts[MAXHOSTS];
213 #define	ADDHOST(cp)	if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
214 
215 /*
216  * Error codes for internal use
217  */
218 #define	ERR_INCOMPLETE		16
219 #define	ERR_TIMEOUT		17
220 
221 /*
222  * Macro definitions we use
223  */
224 #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
225 #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
226 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
227 
228 /*
229  * Jump buffer for longjumping back to the command level.
230  *
231  * See ntpq/ntpq.c for an explanation why 'sig{set,long}jmp()' is used
232  * when available.
233  */
234 #if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
235 # define JMP_BUF	sigjmp_buf
236 # define SETJMP(x)	sigsetjmp((x), 1)
237 # define LONGJMP(x, v)	siglongjmp((x),(v))
238 #else
239 # define JMP_BUF	jmp_buf
240 # define SETJMP(x)	setjmp((x))
241 # define LONGJMP(x, v)	longjmp((x),(v))
242 #endif
243 static	JMP_BUF		interrupt_buf;
244 static	volatile int	jump = 0;
245 
246 /*
247  * Pointer to current output unit
248  */
249 static	FILE *current_output = NULL;
250 
251 /*
252  * Command table imported from ntpdc_ops.c
253  */
254 extern struct xcmd opcmds[];
255 
256 char const *progname;
257 
258 #ifdef NO_MAIN_ALLOWED
259 CALL(ntpdc,"ntpdc",ntpdcmain);
260 #else
261 int
262 main(
263 	int argc,
264 	char *argv[]
265 	)
266 {
267 	return ntpdcmain(argc, argv);
268 }
269 #endif
270 
271 #ifdef SYS_VXWORKS
272 void clear_globals(void)
273 {
274     showhostnames = 0;              /* show host names by default */
275     havehost = 0;                   /* set to 1 when host open */
276     numcmds = 0;
277     numhosts = 0;
278 }
279 #endif
280 
281 /*
282  * main - parse arguments and handle options
283  */
284 int
285 ntpdcmain(
286 	int argc,
287 	char *argv[]
288 	)
289 {
290 	delay_time.l_ui = 0;
291 	delay_time.l_uf = DEFDELAY;
292 
293 #ifdef SYS_VXWORKS
294 	clear_globals();
295 	taskPrioritySet(taskIdSelf(), 100 );
296 #endif
297 
298 	init_lib();	/* sets up ipv4_works, ipv6_works */
299 	ssl_applink();
300 	init_auth();
301 
302 	/* Check to see if we have IPv6. Otherwise default to IPv4 */
303 	if (!ipv6_works)
304 		ai_fam_default = AF_INET;
305 
306 	progname = argv[0];
307 
308 	{
309 		int optct = ntpOptionProcess(&ntpdcOptions, argc, argv);
310 		argc -= optct;
311 		argv += optct;
312 	}
313 
314 	if (HAVE_OPT(IPV4))
315 		ai_fam_default = AF_INET;
316 	else if (HAVE_OPT(IPV6))
317 		ai_fam_default = AF_INET6;
318 
319 	ai_fam_templ = ai_fam_default;
320 
321 	if (HAVE_OPT(COMMAND)) {
322 		int		cmdct = STACKCT_OPT( COMMAND );
323 		const char**	cmds  = STACKLST_OPT( COMMAND );
324 
325 		while (cmdct-- > 0) {
326 			ADDCMD(*cmds++);
327 		}
328 	}
329 
330 	debug = OPT_VALUE_SET_DEBUG_LEVEL;
331 
332 	if (HAVE_OPT(INTERACTIVE)) {
333 		interactive = 1;
334 	}
335 
336 	if (HAVE_OPT(NUMERIC)) {
337 		showhostnames = 0;
338 	}
339 
340 	if (HAVE_OPT(LISTPEERS)) {
341 		ADDCMD("listpeers");
342 	}
343 
344 	if (HAVE_OPT(PEERS)) {
345 		ADDCMD("peers");
346 	}
347 
348 	if (HAVE_OPT(SHOWPEERS)) {
349 		ADDCMD("dmpeers");
350 	}
351 
352 	if (ntp_optind == argc) {
353 		ADDHOST(DEFHOST);
354 	} else {
355 		for (; ntp_optind < argc; ntp_optind++)
356 		    ADDHOST(argv[ntp_optind]);
357 	}
358 
359 	if (numcmds == 0 && interactive == 0
360 	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
361 		interactive = 1;
362 	}
363 
364 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
365 	if (interactive)
366 		(void) signal_no_reset(SIGINT, abortcmd);
367 #endif /* SYS_WINNT */
368 
369 	/*
370 	 * Initialize the packet data buffer
371 	 */
372 	pktdatasize = INITDATASIZE;
373 	pktdata = emalloc(INITDATASIZE);
374 
375 	if (numcmds == 0) {
376 		(void) openhost(chosts[0]);
377 		getcmds();
378 	} else {
379 		int ihost;
380 		int icmd;
381 
382 		for (ihost = 0; ihost < numhosts; ihost++) {
383 			if (openhost(chosts[ihost]))
384 			    for (icmd = 0; icmd < numcmds; icmd++) {
385 				    if (numhosts > 1)
386 					printf ("--- %s ---\n",chosts[ihost]);
387 				    docmd(ccmds[icmd]);
388 			    }
389 		}
390 	}
391 #ifdef SYS_WINNT
392 	WSACleanup();
393 #endif
394 	return(0);
395 } /* main end */
396 
397 
398 /*
399  * openhost - open a socket to a host
400  */
401 static int
402 openhost(
403 	const char *hname
404 	)
405 {
406 	char temphost[LENHOSTNAME];
407 	int a_info;
408 	struct addrinfo hints, *ai = NULL;
409 	sockaddr_u addr;
410 	size_t octets;
411 	const char *cp;
412 	char name[LENHOSTNAME];
413 	char service[5];
414 
415 	/*
416 	 * We need to get by the [] if they were entered
417 	 */
418 	if (*hname == '[') {
419 		cp = strchr(hname + 1, ']');
420 		if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) {
421 			errno = EINVAL;
422 			warning("%s", "bad hostname/address");
423 			return 0;
424 		}
425 		memcpy(name, hname + 1, octets);
426 		name[octets] = '\0';
427 		hname = name;
428 	}
429 
430 	/*
431 	 * First try to resolve it as an ip address and if that fails,
432 	 * do a fullblown (dns) lookup. That way we only use the dns
433 	 * when it is needed and work around some implementations that
434 	 * will return an "IPv4-mapped IPv6 address" address if you
435 	 * give it an IPv4 address to lookup.
436 	 */
437 	strlcpy(service, "ntp", sizeof(service));
438 	ZERO(hints);
439 	hints.ai_family = ai_fam_templ;
440 	hints.ai_protocol = IPPROTO_UDP;
441 	hints.ai_socktype = SOCK_DGRAM;
442 	hints.ai_flags = Z_AI_NUMERICHOST;
443 
444 	a_info = getaddrinfo(hname, service, &hints, &ai);
445 	if (a_info == EAI_NONAME
446 #ifdef EAI_NODATA
447 	    || a_info == EAI_NODATA
448 #endif
449 	   ) {
450 		hints.ai_flags = AI_CANONNAME;
451 #ifdef AI_ADDRCONFIG
452 		hints.ai_flags |= AI_ADDRCONFIG;
453 #endif
454 		a_info = getaddrinfo(hname, service, &hints, &ai);
455 	}
456 	/*
457 	 * Some older implementations don't like AI_ADDRCONFIG.
458 	 * Some versions of Windows return WSANO_DATA when there is no
459 	 * global address and AI_ADDRCONFIG is used.  AI_ADDRCONFIG
460 	 * is useful to short-circuit DNS lookups for IP protocols
461 	 * for which the host has no local addresses.  Windows
462 	 * unfortunately instead interprets AI_ADDRCONFIG to relate
463 	 * to off-host connectivity and so fails lookup when
464 	 * localhost works.
465 	 * To further muddy matters, some versions of WS2tcpip.h
466 	 * comment out #define EAI_NODATA WSANODATA claiming it
467 	 * was removed from RFC 2553bis and mentioning a need to
468 	 * contact the authors to find out why, but "helpfully"
469 	 * #defines EAI_NODATA EAI_NONAME   (== WSAHOST_NOT_FOUND)
470 	 * So we get more ugly platform-specific workarounds.
471 	 */
472 	if (
473 #if defined(WIN32)
474 		WSANO_DATA == a_info || EAI_NONAME == a_info ||
475 #endif
476 		EAI_BADFLAGS == a_info) {
477 		hints.ai_flags = AI_CANONNAME;
478 		a_info = getaddrinfo(hname, service, &hints, &ai);
479 	}
480 	if (a_info != 0) {
481 		fprintf(stderr, "%s\n", gai_strerror(a_info));
482 		if (ai != NULL)
483 			freeaddrinfo(ai);
484 		return 0;
485 	}
486 
487 	/*
488 	 * getaddrinfo() has returned without error so ai should not
489 	 * be NULL.
490 	 */
491 	INSIST(ai != NULL);
492 	ZERO(addr);
493 	octets = min(sizeof(addr), ai->ai_addrlen);
494 	memcpy(&addr, ai->ai_addr, octets);
495 
496 	if (ai->ai_canonname == NULL)
497 		strlcpy(temphost, stoa(&addr), sizeof(temphost));
498 	else
499 		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
500 
501 	if (debug > 2)
502 		printf("Opening host %s\n", temphost);
503 
504 	if (havehost == 1) {
505 		if (debug > 2)
506 			printf("Closing old host %s\n", currenthost);
507 		closesocket(sockfd);
508 		havehost = 0;
509 	}
510 	strlcpy(currenthost, temphost, sizeof(currenthost));
511 
512 	/* port maps to the same in both families */
513 	s_port = NSRCPORT(&addr);;
514 #ifdef SYS_VXWORKS
515 	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
516 	if (ai->ai_family == AF_INET)
517 		*(struct sockaddr_in *)&hostaddr=
518 			*((struct sockaddr_in *)ai->ai_addr);
519 	else
520 		*(struct sockaddr_in6 *)&hostaddr=
521 			*((struct sockaddr_in6 *)ai->ai_addr);
522 #endif /* SYS_VXWORKS */
523 
524 #ifdef SYS_WINNT
525 	{
526 		int optionValue = SO_SYNCHRONOUS_NONALERT;
527 		int err;
528 
529 		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (void *)&optionValue, sizeof(optionValue));
530 		if (err != NO_ERROR) {
531 			(void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
532 			exit(1);
533 		}
534 	}
535 #endif /* SYS_WINNT */
536 
537 	sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
538 	if (sockfd == INVALID_SOCKET) {
539 		error("socket");
540 		exit(-1);
541 	}
542 
543 #ifdef NEED_RCVBUF_SLOP
544 # ifdef SO_RCVBUF
545 	{
546 		int rbufsize = INITDATASIZE + 2048; /* 2K for slop */
547 
548 		if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
549 			       (void *)&rbufsize, sizeof(int)) == -1)
550 		    error("setsockopt");
551 	}
552 # endif
553 #endif
554 
555 #ifdef SYS_VXWORKS
556 	if (connect(sockfd, (struct sockaddr *)&hostaddr,
557 		    sizeof(hostaddr)) == -1)
558 #else
559 	if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1)
560 #endif /* SYS_VXWORKS */
561 	{
562 		error("connect");
563 		exit(-1);
564 	}
565 
566 	freeaddrinfo(ai);
567 	havehost = 1;
568 	req_pkt_size = REQ_LEN_NOMAC;
569 	impl_ver = IMPL_XNTPD;
570 	return 1;
571 }
572 
573 
574 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
575 /*
576  * sendpkt - send a packet to the remote host
577  */
578 static int
579 sendpkt(
580 	void *	xdata,
581 	size_t	xdatalen
582 	)
583 {
584 	if (send(sockfd, xdata, xdatalen, 0) == -1) {
585 		warning("write to %s failed", currenthost);
586 		return -1;
587 	}
588 
589 	return 0;
590 }
591 
592 
593 /*
594  * growpktdata - grow the packet data area
595  */
596 static void
597 growpktdata(void)
598 {
599 	size_t priorsz;
600 
601 	priorsz = (size_t)pktdatasize;
602 	pktdatasize += INCDATASIZE;
603 	pktdata = erealloc_zero(pktdata, (size_t)pktdatasize, priorsz);
604 }
605 
606 
607 /*
608  * getresponse - get a (series of) response packet(s) and return the data
609  */
610 static int
611 getresponse(
612 	int implcode,
613 	int reqcode,
614 	size_t *ritems,
615 	size_t *rsize,
616 	const char **rdata,
617 	size_t esize
618 	)
619 {
620 	struct resp_pkt rpkt;
621 	struct sock_timeval tvo;
622 	size_t items;
623 	size_t i;
624 	size_t size;
625 	size_t datasize;
626 	char *datap;
627 	char *tmp_data;
628 	char haveseq[MAXSEQ+1];
629 	int firstpkt;
630 	int lastseq;
631 	int numrecv;
632 	int seq;
633 	fd_set fds;
634 	ssize_t n;
635 	int pad;
636 	/* absolute timeout checks. Not 'time_t' by intention! */
637 	uint32_t tobase;	/* base value for timeout */
638 	uint32_t tospan;	/* timeout span (max delay) */
639 	uint32_t todiff;	/* current delay */
640 
641 	/*
642 	 * This is pretty tricky.  We may get between 1 and many packets
643 	 * back in response to the request.  We peel the data out of
644 	 * each packet and collect it in one long block.  When the last
645 	 * packet in the sequence is received we'll know how many we
646 	 * should have had.  Note we use one long time out, should reconsider.
647 	 */
648 	*ritems = 0;
649 	*rsize = 0;
650 	firstpkt = 1;
651 	numrecv = 0;
652 	*rdata = datap = pktdata;
653 	lastseq = 999;	/* too big to be a sequence number */
654 	ZERO(haveseq);
655 	FD_ZERO(&fds);
656 	tobase = (uint32_t)time(NULL);
657 
658     again:
659 	if (firstpkt)
660 		tvo = tvout;
661 	else
662 		tvo = tvsout;
663 	tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0);
664 
665 	FD_SET(sockfd, &fds);
666 	n = select(sockfd+1, &fds, NULL, NULL, &tvo);
667 	if (n == -1) {
668 		warning("select fails");
669 		return -1;
670 	}
671 
672 	/*
673 	 * Check if this is already too late. Trash the data and fake a
674 	 * timeout if this is so.
675 	 */
676 	todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu;
677 	if ((n > 0) && (todiff > tospan)) {
678 		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
679 		n -= n; /* faked timeout return from 'select()'*/
680 	}
681 
682 	if (n == 0) {
683 		/*
684 		 * Timed out.  Return what we have
685 		 */
686 		if (firstpkt) {
687 			(void) fprintf(stderr,
688 				       "%s: timed out, nothing received\n",
689 				       currenthost);
690 			return ERR_TIMEOUT;
691 		} else {
692 			(void) fprintf(stderr,
693 				       "%s: timed out with incomplete data\n",
694 				       currenthost);
695 			if (debug) {
696 				printf("Received sequence numbers");
697 				for (n = 0; n <= MAXSEQ; n++)
698 				    if (haveseq[n])
699 					printf(" %zd,", (size_t)n);
700 				if (lastseq != 999)
701 				    printf(" last frame received\n");
702 				else
703 				    printf(" last frame not received\n");
704 			}
705 			return ERR_INCOMPLETE;
706 		}
707 	}
708 
709 	n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
710 	if (n == -1) {
711 		warning("read");
712 		return -1;
713 	}
714 
715 
716 	/*
717 	 * Check for format errors.  Bug proofing.
718 	 */
719 	if (n < (ssize_t)RESP_HEADER_SIZE) {
720 		if (debug)
721 			printf("Short (%zd byte) packet received\n", (size_t)n);
722 		goto again;
723 	}
724 	if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION ||
725 	    INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) {
726 		if (debug)
727 			printf("Packet received with version %d\n",
728 			       INFO_VERSION(rpkt.rm_vn_mode));
729 		goto again;
730 	}
731 	if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) {
732 		if (debug)
733 			printf("Packet received with mode %d\n",
734 			       INFO_MODE(rpkt.rm_vn_mode));
735 		goto again;
736 	}
737 	if (INFO_IS_AUTH(rpkt.auth_seq)) {
738 		if (debug)
739 			printf("Encrypted packet received\n");
740 		goto again;
741 	}
742 	if (!ISRESPONSE(rpkt.rm_vn_mode)) {
743 		if (debug)
744 			printf("Received request packet, wanted response\n");
745 		goto again;
746 	}
747 	if (INFO_MBZ(rpkt.mbz_itemsize) != 0) {
748 		if (debug)
749 			printf("Received packet with nonzero MBZ field!\n");
750 		goto again;
751 	}
752 
753 	/*
754 	 * Check implementation/request.  Could be old data getting to us.
755 	 */
756 	if (rpkt.implementation != implcode || rpkt.request != reqcode) {
757 		if (debug)
758 			printf(
759 			    "Received implementation/request of %d/%d, wanted %d/%d",
760 			    rpkt.implementation, rpkt.request,
761 			    implcode, reqcode);
762 		goto again;
763 	}
764 
765 	/*
766 	 * Check the error code.  If non-zero, return it.
767 	 */
768 	if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) {
769 		if (debug && ISMORE(rpkt.rm_vn_mode)) {
770 			printf("Error code %d received on not-final packet\n",
771 			       INFO_ERR(rpkt.err_nitems));
772 		}
773 		return (int)INFO_ERR(rpkt.err_nitems);
774 	}
775 
776 	/*
777 	 * Collect items and size.  Make sure they make sense.
778 	 */
779 	items = INFO_NITEMS(rpkt.err_nitems);
780 	size = INFO_ITEMSIZE(rpkt.mbz_itemsize);
781 	if (esize > size)
782 		pad = esize - size;
783 	else
784 		pad = 0;
785 	datasize = items * size;
786 	if ((size_t)datasize > (n-RESP_HEADER_SIZE)) {
787 		if (debug)
788 		    printf(
789 			    "Received items %zu, size %zu (total %zu), data in packet is %zu\n",
790 			    items, size, datasize, n-RESP_HEADER_SIZE);
791 		goto again;
792 	}
793 
794 	/*
795 	 * If this isn't our first packet, make sure the size matches
796 	 * the other ones.
797 	 */
798 	if (!firstpkt && size != *rsize) {
799 		if (debug)
800 		    printf("Received itemsize %zu, previous %zu\n",
801 			   size, *rsize);
802 		goto again;
803 	}
804 	/*
805 	 * If we've received this before, +toss it
806 	 */
807 	seq = INFO_SEQ(rpkt.auth_seq);
808 	if (haveseq[seq]) {
809 		if (debug)
810 		    printf("Received duplicate sequence number %d\n", seq);
811 		goto again;
812 	}
813 	haveseq[seq] = 1;
814 
815 	/*
816 	 * If this is the last in the sequence, record that.
817 	 */
818 	if (!ISMORE(rpkt.rm_vn_mode)) {
819 		if (lastseq != 999) {
820 			printf("Received second end sequence packet\n");
821 			goto again;
822 		}
823 		lastseq = seq;
824 	}
825 
826 	/*
827 	 * So far, so good.  Copy this data into the output array. Bump
828 	 * the timeout base, in case we expect more data.
829 	 */
830 	tobase = (uint32_t)time(NULL);
831 	if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
832 		size_t offset = datap - pktdata;
833 		growpktdata();
834 		*rdata = pktdata; /* might have been realloced ! */
835 		datap = pktdata + offset;
836 	}
837 	/*
838 	 * We now move the pointer along according to size and number of
839 	 * items.  This is so we can play nice with older implementations
840 	 */
841 
842 	tmp_data = rpkt.u.data;
843 	for (i = 0; i < items; i++) {
844 		memcpy(datap, tmp_data, (unsigned)size);
845 		tmp_data += size;
846 		zero_mem(datap + size, pad);
847 		datap += size + pad;
848 	}
849 
850 	if (firstpkt) {
851 		firstpkt = 0;
852 		*rsize = size + pad;
853 	}
854 	*ritems += items;
855 
856 	/*
857 	 * Finally, check the count of received packets.  If we've got them
858 	 * all, return
859 	 */
860 	++numrecv;
861 	if (numrecv <= lastseq)
862 		goto again;
863 	return INFO_OKAY;
864 }
865 
866 
867 /*
868  * sendrequest - format and send a request packet
869  *
870  * Historically, ntpdc has used a fixed-size request packet regardless
871  * of the actual payload size.  When authenticating, the timestamp, key
872  * ID, and digest have been placed just before the end of the packet.
873  * With the introduction in late 2009 of support for authenticated
874  * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
875  * come up four bytes short.
876  *
877  * To maintain interop while allowing for larger digests, the behavior
878  * is unchanged when using 16-octet digests.  For larger digests, the
879  * timestamp, key ID, and digest are placed immediately following the
880  * request payload, with the overall packet size variable.  ntpd can
881  * distinguish 16-octet digests by the overall request size being
882  * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled.  When using a
883  * longer digest, that request size should be avoided.
884  *
885  * With the form used with 20-octet and larger digests, the timestamp,
886  * key ID, and digest are located by ntpd relative to the start of the
887  * packet, and the size of the digest is then implied by the packet
888  * size.
889  */
890 static int
891 sendrequest(
892 	int implcode,
893 	int reqcode,
894 	int auth,
895 	size_t qitems,
896 	size_t qsize,
897 	const char *qdata
898 	)
899 {
900 	struct req_pkt qpkt;
901 	size_t	datasize;
902 	size_t	reqsize;
903 	u_long	key_id;
904 	l_fp	ts;
905 	l_fp *	ptstamp;
906 	size_t	maclen;
907 	char *	pass;
908 
909 	ZERO(qpkt);
910 	qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
911 	qpkt.implementation = (u_char)implcode;
912 	qpkt.request = (u_char)reqcode;
913 
914 	datasize = qitems * qsize;
915 	if (datasize && qdata != NULL) {
916 		memcpy(qpkt.u.data, qdata, datasize);
917 		qpkt.err_nitems = ERR_NITEMS(0, qitems);
918 		qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
919 	} else {
920 		qpkt.err_nitems = ERR_NITEMS(0, 0);
921 		qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);  /* allow for optional first item */
922 	}
923 
924 	if (!auth || (keyid_entered && info_auth_keyid == 0)) {
925 		qpkt.auth_seq = AUTH_SEQ(0, 0);
926 		return sendpkt(&qpkt, req_pkt_size);
927 	}
928 
929 	if (info_auth_keyid == 0) {
930 		key_id = getkeyid("Keyid: ");
931 		if (!key_id) {
932 			fprintf(stderr, "Invalid key identifier\n");
933 			return 1;
934 		}
935 		info_auth_keyid = key_id;
936 	}
937 	if (!authistrusted(info_auth_keyid)) {
938 		pass = getpass_keytype(info_auth_keytype);
939 		if ('\0' == pass[0]) {
940 			fprintf(stderr, "Invalid password\n");
941 			return 1;
942 		}
943 		authusekey(info_auth_keyid, info_auth_keytype,
944 			   (u_char *)pass);
945 		authtrust(info_auth_keyid, 1);
946 	}
947 	qpkt.auth_seq = AUTH_SEQ(1, 0);
948 	if (info_auth_hashlen > 16) {
949 		/*
950 		 * Only ntpd which expects REQ_LEN_NOMAC plus maclen
951 		 * octets in an authenticated request using a 16 octet
952 		 * digest (that is, a newer ntpd) will handle digests
953 		 * larger than 16 octets, so for longer digests, do
954 		 * not attempt to shorten the requests for downlevel
955 		 * ntpd compatibility.
956 		 */
957 		if (REQ_LEN_NOMAC != req_pkt_size)
958 			return 1;
959 		reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp);
960 		/* align to 32 bits */
961 		reqsize = (reqsize + 3) & ~3;
962 	} else
963 		reqsize = req_pkt_size;
964 	ptstamp = (void *)((char *)&qpkt + reqsize - sizeof *ptstamp);
965 	get_systime(&ts);
966 	L_ADD(&ts, &delay_time);
967 	HTONL_FP(&ts, ptstamp);
968 	maclen = authencrypt(
969 		info_auth_keyid, (void *)&qpkt, size2int_chk(reqsize));
970 	if (!maclen) {
971 		fprintf(stderr, "Key not found\n");
972 		return 1;
973 	} else if (maclen != (size_t)(info_auth_hashlen + sizeof(keyid_t))) {
974 		fprintf(stderr,
975 			"%zu octet MAC, %zu expected with %zu octet digest\n",
976 			maclen, (info_auth_hashlen + sizeof(keyid_t)),
977 			info_auth_hashlen);
978 		return 1;
979 	}
980 	return sendpkt(&qpkt, reqsize + maclen);
981 }
982 
983 
984 /*
985  * doquery - send a request and process the response
986  */
987 int
988 doquery(
989 	int implcode,
990 	int reqcode,
991 	int auth,
992 	size_t qitems,
993 	size_t qsize,
994 	const char *qdata,
995 	size_t *ritems,
996 	size_t *rsize,
997 	const char **rdata,
998  	int quiet_mask,
999 	int esize
1000 	)
1001 {
1002 	int res;
1003 	char junk[512];
1004 	fd_set fds;
1005 	struct sock_timeval tvzero;
1006 
1007 	/*
1008 	 * Check to make sure host is open
1009 	 */
1010 	if (!havehost) {
1011 		(void) fprintf(stderr, "***No host open, use `host' command\n");
1012 		return -1;
1013 	}
1014 
1015 	/*
1016 	 * Poll the socket and clear out any pending data
1017 	 */
1018 again:
1019 	do {
1020 		tvzero.tv_sec = tvzero.tv_usec = 0;
1021 		FD_ZERO(&fds);
1022 		FD_SET(sockfd, &fds);
1023 		res = select(sockfd+1, &fds, NULL, NULL, &tvzero);
1024 		if (res == -1) {
1025 			warning("polling select");
1026 			return -1;
1027 		} else if (res > 0)
1028 
1029 		    (void) recv(sockfd, junk, sizeof junk, 0);
1030 	} while (res > 0);
1031 
1032 
1033 	/*
1034 	 * send a request
1035 	 */
1036 	res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
1037 	if (res != 0)
1038 		return res;
1039 
1040 	/*
1041 	 * Get the response.  If we got a standard error, print a message
1042 	 */
1043 	res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize);
1044 
1045 	/*
1046 	 * Try to be compatible with older implementations of ntpd.
1047 	 */
1048 	if (res == INFO_ERR_FMT && req_pkt_size != 48) {
1049 		int oldsize;
1050 
1051 		oldsize = req_pkt_size;
1052 
1053 		switch(req_pkt_size) {
1054 		case REQ_LEN_NOMAC:
1055 			req_pkt_size = 160;
1056 			break;
1057 		case 160:
1058 			req_pkt_size = 48;
1059 			break;
1060 		}
1061 		if (impl_ver == IMPL_XNTPD) {
1062 			fprintf(stderr,
1063 			    "***Warning changing to older implementation\n");
1064 			return INFO_ERR_IMPL;
1065 		}
1066 
1067 		fprintf(stderr,
1068 		    "***Warning changing the request packet size from %d to %d\n",
1069 		    oldsize, req_pkt_size);
1070 		goto again;
1071 	}
1072 
1073  	/* log error message if not told to be quiet */
1074  	if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
1075 		switch(res) {
1076 		case INFO_ERR_IMPL:
1077 			/* Give us a chance to try the older implementation. */
1078 			if (implcode == IMPL_XNTPD)
1079 				break;
1080 			(void) fprintf(stderr,
1081 				       "***Server implementation incompatible with our own\n");
1082 			break;
1083 		case INFO_ERR_REQ:
1084 			(void) fprintf(stderr,
1085 				       "***Server doesn't implement this request\n");
1086 			break;
1087 		case INFO_ERR_FMT:
1088 			(void) fprintf(stderr,
1089 				       "***Server reports a format error in the received packet (shouldn't happen)\n");
1090 			break;
1091 		case INFO_ERR_NODATA:
1092 			(void) fprintf(stderr,
1093 				       "***Server reports data not found\n");
1094 			break;
1095 		case INFO_ERR_AUTH:
1096 			(void) fprintf(stderr, "***Permission denied\n");
1097 			break;
1098 		case ERR_TIMEOUT:
1099 			(void) fprintf(stderr, "***Request timed out\n");
1100 			break;
1101 		case ERR_INCOMPLETE:
1102 			(void) fprintf(stderr,
1103 				       "***Response from server was incomplete\n");
1104 			break;
1105 		default:
1106 			(void) fprintf(stderr,
1107 				       "***Server returns unknown error code %d\n", res);
1108 			break;
1109 		}
1110 	}
1111 	return res;
1112 }
1113 
1114 
1115 /*
1116  * getcmds - read commands from the standard input and execute them
1117  */
1118 static void
1119 getcmds(void)
1120 {
1121 	char *	line;
1122 	int	count;
1123 
1124 	ntp_readline_init(interactive ? prompt : NULL);
1125 
1126 	for (;;) {
1127 		line = ntp_readline(&count);
1128 		if (NULL == line)
1129 			break;
1130 		docmd(line);
1131 		free(line);
1132 	}
1133 
1134 	ntp_readline_uninit();
1135 }
1136 
1137 
1138 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1139 /*
1140  * abortcmd - catch interrupts and abort the current command
1141  */
1142 static RETSIGTYPE
1143 abortcmd(
1144 	int sig
1145 	)
1146 {
1147 	if (current_output == stdout)
1148 		(void)fflush(stdout);
1149 	putc('\n', stderr);
1150 	(void)fflush(stderr);
1151 	if (jump) {
1152 		jump = 0;
1153 		LONGJMP(interrupt_buf, 1);
1154 	}
1155 }
1156 #endif /* SYS_WINNT */
1157 
1158 /*
1159  * docmd - decode the command line and execute a command
1160  */
1161 static void
1162 docmd(
1163 	const char *cmdline
1164 	)
1165 {
1166 	char *tokens[1+MAXARGS+MOREARGS+2];
1167 	struct parse pcmd;
1168 	int ntok;
1169 	int i, ti;
1170 	int rval;
1171 	struct xcmd *xcmd;
1172 
1173 	ai_fam_templ = ai_fam_default;
1174 	/*
1175 	 * Tokenize the command line.  If nothing on it, return.
1176 	 */
1177 	if (strlen(cmdline) >= MAXLINE) {
1178 		fprintf(stderr, "***Command ignored, more than %d characters:\n%s\n",
1179 			MAXLINE - 1, cmdline);
1180 		return;
1181 	}
1182 	tokenize(cmdline, tokens, &ntok);
1183 	if (ntok == 0)
1184 	    return;
1185 
1186 	/*
1187 	 * Find the appropriate command description.
1188 	 */
1189 	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1190 	if (i == 0) {
1191 		(void) fprintf(stderr, "***Command `%s' unknown\n",
1192 			       tokens[0]);
1193 		return;
1194 	} else if (i >= 2) {
1195 		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1196 			       tokens[0]);
1197 		return;
1198 	}
1199 
1200 	/*
1201 	 * Save the keyword, then walk through the arguments, interpreting
1202 	 * as we go.
1203 	 */
1204 	pcmd.keyword = tokens[0];
1205 	pcmd.nargs = 0;
1206 	ti = 1;
1207 	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) {
1208 		if ((i+ti) >= ntok) {
1209 			if (!(xcmd->arg[i] & OPT)) {
1210 				printusage(xcmd, stderr);
1211 				return;
1212 			}
1213 			break;
1214 		}
1215 		if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>'))
1216 			break;
1217 		rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]);
1218 		if (rval == -1) {
1219 			ti++;
1220 			continue;
1221 		}
1222 		if (rval == 0)
1223 			return;
1224 		pcmd.nargs++;
1225 		i++;
1226 	}
1227 
1228 	/* Any extra args are assumed to be "OPT|NTP_STR". */
1229 	for ( ; i < MAXARGS + MOREARGS;) {
1230 	     if ((i+ti) >= ntok)
1231 		  break;
1232 		rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]);
1233 		if (rval == -1) {
1234 			ti++;
1235 			continue;
1236 		}
1237 		if (rval == 0)
1238 			return;
1239 		pcmd.nargs++;
1240 		i++;
1241 	}
1242 
1243 	i += ti;
1244 	if (i < ntok && *tokens[i] == '>') {
1245 		char *fname;
1246 
1247 		if (*(tokens[i]+1) != '\0')
1248 		    fname = tokens[i]+1;
1249 		else if ((i+1) < ntok)
1250 		    fname = tokens[i+1];
1251 		else {
1252 			(void) fprintf(stderr, "***No file for redirect\n");
1253 			return;
1254 		}
1255 
1256 		current_output = fopen(fname, "w");
1257 		if (current_output == NULL) {
1258 			(void) fprintf(stderr, "***Error opening %s: ", fname);
1259 			perror("");
1260 			return;
1261 		}
1262 	} else {
1263 		current_output = stdout;
1264 	}
1265 
1266 	if (interactive) {
1267 		if ( ! SETJMP(interrupt_buf)) {
1268 			jump = 1;
1269 			(xcmd->handler)(&pcmd, current_output);
1270 			jump = 0;
1271 		} else {
1272 			fflush(current_output);
1273 			fputs("\n >>> command aborted <<<\n", stderr);
1274 			fflush(stderr);
1275 		}
1276 	} else {
1277 		jump = 0;
1278 		(xcmd->handler)(&pcmd, current_output);
1279 	}
1280 	if ((NULL != current_output) && (stdout != current_output)) {
1281 		(void)fclose(current_output);
1282 		current_output = NULL;
1283 	}
1284 }
1285 
1286 
1287 /*
1288  * tokenize - turn a command line into tokens
1289  */
1290 static void
1291 tokenize(
1292 	const char *line,
1293 	char **tokens,
1294 	int *ntok
1295 	)
1296 {
1297 	register const char *cp;
1298 	register char *sp;
1299 	static char tspace[MAXLINE];
1300 
1301 	sp = tspace;
1302 	cp = line;
1303 	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1304 		tokens[*ntok] = sp;
1305 		while (ISSPACE(*cp))
1306 		    cp++;
1307 		if (ISEOL(*cp))
1308 		    break;
1309 		do {
1310 			*sp++ = *cp++;
1311 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
1312 
1313 		*sp++ = '\0';
1314 	}
1315 }
1316 
1317 
1318 
1319 /*
1320  * findcmd - find a command in a command description table
1321  */
1322 static int
1323 findcmd(
1324 	register char *str,
1325 	struct xcmd *clist1,
1326 	struct xcmd *clist2,
1327 	struct xcmd **cmd
1328 	)
1329 {
1330 	register struct xcmd *cl;
1331 	size_t clen;
1332 	int nmatch;
1333 	struct xcmd *nearmatch = NULL;
1334 	struct xcmd *clist;
1335 
1336 	clen = strlen(str);
1337 	nmatch = 0;
1338 	if (clist1 != 0)
1339 	    clist = clist1;
1340 	else if (clist2 != 0)
1341 	    clist = clist2;
1342 	else
1343 	    return 0;
1344 
1345     again:
1346 	for (cl = clist; cl->keyword != 0; cl++) {
1347 		/* do a first character check, for efficiency */
1348 		if (*str != *(cl->keyword))
1349 		    continue;
1350 		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1351 			/*
1352 			 * Could be extact match, could be approximate.
1353 			 * Is exact if the length of the keyword is the
1354 			 * same as the str.
1355 			 */
1356 			if (*((cl->keyword) + clen) == '\0') {
1357 				*cmd = cl;
1358 				return 1;
1359 			}
1360 			nmatch++;
1361 			nearmatch = cl;
1362 		}
1363 	}
1364 
1365 				/*
1366 				 * See if there is more to do.  If so, go again.  Sorry about the
1367 				 * goto, too much looking at BSD sources...
1368 				 */
1369 	if (clist == clist1 && clist2 != 0) {
1370 		clist = clist2;
1371 		goto again;
1372 	}
1373 
1374 				/*
1375 				 * If we got extactly 1 near match, use it, else return number
1376 				 * of matches.
1377 				 */
1378 	if (nmatch == 1) {
1379 		*cmd = nearmatch;
1380 		return 1;
1381 	}
1382 	return nmatch;
1383 }
1384 
1385 
1386 /*
1387  * getarg - interpret an argument token
1388  *
1389  * string is always set.
1390  * type is set to the decoded type.
1391  *
1392  * return:	 0 - failure
1393  *		 1 - success
1394  *		-1 - skip to next token
1395  */
1396 static int
1397 getarg(
1398 	char *str,
1399 	int code,
1400 	arg_v *argp
1401 	)
1402 {
1403 	ZERO(*argp);
1404 	argp->string = str;
1405 	argp->type   = code & ~OPT;
1406 
1407 	switch (argp->type) {
1408 	case NTP_STR:
1409 		break;
1410 	case NTP_ADD:
1411 		if (!strcmp("-6", str)) {
1412 			ai_fam_templ = AF_INET6;
1413 			return -1;
1414 		} else if (!strcmp("-4", str)) {
1415 			ai_fam_templ = AF_INET;
1416 			return -1;
1417 		}
1418 		if (!getnetnum(str, &(argp->netnum), (char *)0, ai_fam_templ)) {
1419 			return 0;
1420 		}
1421 		break;
1422 	case NTP_UINT:
1423 		if (!atouint(str, &argp->uval)) {
1424 			fprintf(stderr, "***Illegal unsigned value %s\n",
1425 				str);
1426 			return 0;
1427 		}
1428 		break;
1429 	case NTP_INT:
1430 		if (!atoint(str, &argp->ival)) {
1431 			fprintf(stderr, "***Illegal integer value %s\n",
1432 				str);
1433 			return 0;
1434 		}
1435 		break;
1436 	case IP_VERSION:
1437 		if (!strcmp("-6", str))
1438 			argp->ival = 6 ;
1439 		else if (!strcmp("-4", str))
1440 			argp->ival = 4 ;
1441 		else {
1442 			(void) fprintf(stderr,
1443 			    "***Version must be either 4 or 6\n");
1444 			return 0;
1445 		}
1446 		break;
1447 	}
1448 
1449 	return 1;
1450 }
1451 
1452 
1453 /*
1454  * getnetnum - given a host name, return its net number
1455  *	       and (optional) full name
1456  */
1457 static int
1458 getnetnum(
1459 	const char *hname,
1460 	sockaddr_u *num,
1461 	char *fullhost,
1462 	int af
1463 	)
1464 {
1465 	struct addrinfo hints, *ai = NULL;
1466 
1467 	ZERO(hints);
1468 	hints.ai_family = af;
1469 	hints.ai_flags = AI_CANONNAME;
1470 #ifdef AI_ADDRCONFIG
1471 	hints.ai_flags |= AI_ADDRCONFIG;
1472 #endif
1473 
1474 	/*
1475 	 * decodenetnum only works with addresses, but handles syntax
1476 	 * that getaddrinfo doesn't:  [2001::1]:1234
1477 	 */
1478 	if (decodenetnum(hname, num)) {
1479 		if (fullhost != NULL)
1480 			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1481 				    LENHOSTNAME, NULL, 0, 0);
1482 		return 1;
1483 	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1484 		INSIST(sizeof(*num) >= ai->ai_addrlen);
1485 		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1486 		if (fullhost != NULL) {
1487 			if (ai->ai_canonname != NULL)
1488 				strlcpy(fullhost, ai->ai_canonname,
1489 					LENHOSTNAME);
1490 			else
1491 				getnameinfo(&num->sa, SOCKLEN(num),
1492 					    fullhost, LENHOSTNAME, NULL,
1493 					    0, 0);
1494 		}
1495 		return 1;
1496 	}
1497 	fprintf(stderr, "***Can't find host %s\n", hname);
1498 
1499 	return 0;
1500 }
1501 
1502 
1503 /*
1504  * nntohost - convert network number to host name.  This routine enforces
1505  *	       the showhostnames setting.
1506  */
1507 const char *
1508 nntohost(
1509 	sockaddr_u *netnum
1510 	)
1511 {
1512 	if (!showhostnames || SOCK_UNSPEC(netnum))
1513 		return stoa(netnum);
1514 	else if (ISREFCLOCKADR(netnum))
1515 		return refnumtoa(netnum);
1516 	else
1517 		return socktohost(netnum);
1518 }
1519 
1520 
1521 /*
1522  * Finally, the built in command handlers
1523  */
1524 
1525 /*
1526  * help - tell about commands, or details of a particular command
1527  */
1528 static void
1529 help(
1530 	struct parse *pcmd,
1531 	FILE *fp
1532 	)
1533 {
1534 	struct xcmd *xcp;
1535 	char *cmd;
1536 	const char *list[100];
1537 	size_t word, words;
1538 	size_t row, rows;
1539 	size_t col, cols;
1540 	size_t length;
1541 
1542 	if (pcmd->nargs == 0) {
1543 		words = 0;
1544 		for (xcp = builtins; xcp->keyword != 0; xcp++) {
1545 			if (*(xcp->keyword) != '?')
1546 				list[words++] = xcp->keyword;
1547 		}
1548 		for (xcp = opcmds; xcp->keyword != 0; xcp++)
1549 			list[words++] = xcp->keyword;
1550 
1551 		qsort((void *)list, words, sizeof(list[0]), helpsort);
1552 		col = 0;
1553 		for (word = 0; word < words; word++) {
1554 			length = strlen(list[word]);
1555 			col = max(col, length);
1556 		}
1557 
1558 		cols = SCREENWIDTH / ++col;
1559 		rows = (words + cols - 1) / cols;
1560 
1561 		fprintf(fp, "ntpdc commands:\n");
1562 
1563 		for (row = 0; row < rows; row++) {
1564 			for (word = row; word < words; word += rows)
1565 				fprintf(fp, "%-*.*s", (int)col,
1566 					(int)col - 1, list[word]);
1567 			fprintf(fp, "\n");
1568 		}
1569 	} else {
1570 		cmd = pcmd->argval[0].string;
1571 		words = findcmd(cmd, builtins, opcmds, &xcp);
1572 		if (words == 0) {
1573 			fprintf(stderr,
1574 				"Command `%s' is unknown\n", cmd);
1575 			return;
1576 		} else if (words >= 2) {
1577 			fprintf(stderr,
1578 				"Command `%s' is ambiguous\n", cmd);
1579 			return;
1580 		}
1581 		fprintf(fp, "function: %s\n", xcp->comment);
1582 		printusage(xcp, fp);
1583 	}
1584 }
1585 
1586 
1587 /*
1588  * helpsort - do hostname qsort comparisons
1589  */
1590 static int
1591 helpsort(
1592 	const void *t1,
1593 	const void *t2
1594 	)
1595 {
1596 	const char * const *	name1 = t1;
1597 	const char * const *	name2 = t2;
1598 
1599 	return strcmp(*name1, *name2);
1600 }
1601 
1602 
1603 /*
1604  * printusage - print usage information for a command
1605  */
1606 static void
1607 printusage(
1608 	struct xcmd *xcp,
1609 	FILE *fp
1610 	)
1611 {
1612 	int i, opt46;
1613 
1614 	opt46 = 0;
1615 	(void) fprintf(fp, "usage: %s", xcp->keyword);
1616 	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
1617 		if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) {
1618 			(void) fprintf(fp, " [ -4|-6 ]");
1619 			opt46 = 1;
1620 		}
1621 		if (xcp->arg[i] & OPT)
1622 		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
1623 		else
1624 		    (void) fprintf(fp, " %s", xcp->desc[i]);
1625 	}
1626 	(void) fprintf(fp, "\n");
1627 }
1628 
1629 
1630 /*
1631  * timeout - set time out time
1632  */
1633 static void
1634 timeout(
1635 	struct parse *pcmd,
1636 	FILE *fp
1637 	)
1638 {
1639 	int val;
1640 
1641 	if (pcmd->nargs == 0) {
1642 		val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
1643 		(void) fprintf(fp, "primary timeout %d ms\n", val);
1644 	} else {
1645 		tvout.tv_sec = pcmd->argval[0].uval / 1000;
1646 		tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
1647 			* 1000;
1648 	}
1649 }
1650 
1651 
1652 /*
1653  * my_delay - set delay for auth requests
1654  */
1655 static void
1656 my_delay(
1657 	struct parse *pcmd,
1658 	FILE *fp
1659 	)
1660 {
1661 	int isneg;
1662 	u_long val;
1663 
1664 	if (pcmd->nargs == 0) {
1665 		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
1666 		(void) fprintf(fp, "delay %lu ms\n", val);
1667 	} else {
1668 		if (pcmd->argval[0].ival < 0) {
1669 			isneg = 1;
1670 			val = ~(u_long)(pcmd->argval[0].ival) + 1UL;
1671 		} else {
1672 			isneg = 0;
1673 			val = (u_long)pcmd->argval[0].ival;
1674 		}
1675 
1676 		delay_time.l_ui = val / 1000;
1677 		val %= 1000;
1678 		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
1679 
1680 		if (isneg)
1681 		    L_NEG(&delay_time);
1682 	}
1683 }
1684 
1685 
1686 /*
1687  * host - set the host we are dealing with.
1688  */
1689 static void
1690 host(
1691 	struct parse *pcmd,
1692 	FILE *fp
1693 	)
1694 {
1695 	int i;
1696 
1697 	if (pcmd->nargs == 0) {
1698 		if (havehost)
1699 		    (void) fprintf(fp, "current host is %s\n", currenthost);
1700 		else
1701 		    (void) fprintf(fp, "no current host\n");
1702 		return;
1703 	}
1704 
1705 	i = 0;
1706 	if (pcmd->nargs == 2) {
1707 		if (!strcmp("-4", pcmd->argval[i].string))
1708 			ai_fam_templ = AF_INET;
1709 		else if (!strcmp("-6", pcmd->argval[i].string))
1710 			ai_fam_templ = AF_INET6;
1711 		else {
1712 			if (havehost)
1713 				(void) fprintf(fp,
1714 				    "current host remains %s\n", currenthost);
1715 			else
1716 				(void) fprintf(fp, "still no current host\n");
1717 			return;
1718 		}
1719 		i = 1;
1720 	}
1721 	if (openhost(pcmd->argval[i].string)) {
1722 		(void) fprintf(fp, "current host set to %s\n", currenthost);
1723 	} else {
1724 		if (havehost)
1725 		    (void) fprintf(fp,
1726 				   "current host remains %s\n", currenthost);
1727 		else
1728 		    (void) fprintf(fp, "still no current host\n");
1729 	}
1730 }
1731 
1732 
1733 /*
1734  * keyid - get a keyid to use for authenticating requests
1735  */
1736 static void
1737 keyid(
1738 	struct parse *pcmd,
1739 	FILE *fp
1740 	)
1741 {
1742 	if (pcmd->nargs == 0) {
1743 		if (info_auth_keyid == 0 && !keyid_entered)
1744 		    (void) fprintf(fp, "no keyid defined\n");
1745 		else if (info_auth_keyid == 0 && keyid_entered)
1746 		    (void) fprintf(fp, "no keyid will be sent\n");
1747 		else
1748 		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
1749 	} else {
1750 		info_auth_keyid = pcmd->argval[0].uval;
1751 		keyid_entered = 1;
1752 	}
1753 }
1754 
1755 
1756 /*
1757  * keytype - get type of key to use for authenticating requests
1758  */
1759 static void
1760 keytype(
1761 	struct parse *pcmd,
1762 	FILE *fp
1763 	)
1764 {
1765 	const char *	digest_name;
1766 	size_t		digest_len;
1767 	int		key_type;
1768 
1769 	if (!pcmd->nargs) {
1770 		fprintf(fp, "keytype is %s with %lu octet digests\n",
1771 			keytype_name(info_auth_keytype),
1772 			(u_long)info_auth_hashlen);
1773 		return;
1774 	}
1775 
1776 	digest_name = pcmd->argval[0].string;
1777 	digest_len = 0;
1778 	key_type = keytype_from_text(digest_name, &digest_len);
1779 
1780 	if (!key_type) {
1781 		fprintf(fp, "keytype must be 'md5'%s\n",
1782 #ifdef OPENSSL
1783 			" or a digest type provided by OpenSSL");
1784 #else
1785 			"");
1786 #endif
1787 		return;
1788 	}
1789 
1790 	info_auth_keytype = key_type;
1791 	info_auth_hashlen = digest_len;
1792 }
1793 
1794 
1795 /*
1796  * passwd - get an authentication key
1797  */
1798 /*ARGSUSED*/
1799 static void
1800 passwd(
1801 	struct parse *pcmd,
1802 	FILE *fp
1803 	)
1804 {
1805 	char *pass;
1806 
1807 	if (info_auth_keyid == 0) {
1808 		info_auth_keyid = getkeyid("Keyid: ");
1809 		if (info_auth_keyid == 0) {
1810 			(void)fprintf(fp, "Keyid must be defined\n");
1811 			return;
1812 		}
1813 	}
1814 	if (pcmd->nargs >= 1)
1815 		pass = pcmd->argval[0].string;
1816 	else {
1817 		pass = getpass_keytype(info_auth_keytype);
1818 		if ('\0' == *pass) {
1819 			fprintf(fp, "Password unchanged\n");
1820 			return;
1821 		}
1822 	}
1823 	authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
1824 	authtrust(info_auth_keyid, 1);
1825 }
1826 
1827 
1828 /*
1829  * hostnames - set the showhostnames flag
1830  */
1831 static void
1832 hostnames(
1833 	struct parse *pcmd,
1834 	FILE *fp
1835 	)
1836 {
1837 	if (pcmd->nargs == 0) {
1838 		if (showhostnames)
1839 		    (void) fprintf(fp, "hostnames being shown\n");
1840 		else
1841 		    (void) fprintf(fp, "hostnames not being shown\n");
1842 	} else {
1843 		if (STREQ(pcmd->argval[0].string, "yes"))
1844 		    showhostnames = 1;
1845 		else if (STREQ(pcmd->argval[0].string, "no"))
1846 		    showhostnames = 0;
1847 		else
1848 		    (void)fprintf(stderr, "What?\n");
1849 	}
1850 }
1851 
1852 
1853 /*
1854  * setdebug - set/change debugging level
1855  */
1856 static void
1857 setdebug(
1858 	struct parse *pcmd,
1859 	FILE *fp
1860 	)
1861 {
1862 	if (pcmd->nargs == 0) {
1863 		(void) fprintf(fp, "debug level is %d\n", debug);
1864 		return;
1865 	} else if (STREQ(pcmd->argval[0].string, "no")) {
1866 		debug = 0;
1867 	} else if (STREQ(pcmd->argval[0].string, "more")) {
1868 		debug++;
1869 	} else if (STREQ(pcmd->argval[0].string, "less")) {
1870 		debug--;
1871 	} else {
1872 		(void) fprintf(fp, "What?\n");
1873 		return;
1874 	}
1875 	(void) fprintf(fp, "debug level set to %d\n", debug);
1876 }
1877 
1878 
1879 /*
1880  * quit - stop this nonsense
1881  */
1882 /*ARGSUSED*/
1883 static void
1884 quit(
1885 	struct parse *pcmd,
1886 	FILE *fp
1887 	)
1888 {
1889 	if (havehost)
1890 	    closesocket(sockfd);
1891 	exit(0);
1892 }
1893 
1894 
1895 /*
1896  * version - print the current version number
1897  */
1898 /*ARGSUSED*/
1899 static void
1900 version(
1901 	struct parse *pcmd,
1902 	FILE *fp
1903 	)
1904 {
1905 
1906 	(void) fprintf(fp, "%s\n", Version);
1907 	return;
1908 }
1909 
1910 
1911 static void __attribute__((__format__(__printf__, 1, 0)))
1912 vwarning(const char *fmt, va_list ap)
1913 {
1914 	int serrno = errno;
1915 	(void) fprintf(stderr, "%s: ", progname);
1916 	vfprintf(stderr, fmt, ap);
1917 	(void) fprintf(stderr, ": %s\n", strerror(serrno));
1918 }
1919 
1920 /*
1921  * warning - print a warning message
1922  */
1923 static void __attribute__((__format__(__printf__, 1, 2)))
1924 warning(
1925 	const char *fmt,
1926 	...
1927 	)
1928 {
1929 	va_list ap;
1930 	va_start(ap, fmt);
1931 	vwarning(fmt, ap);
1932 	va_end(ap);
1933 }
1934 
1935 
1936 /*
1937  * error - print a message and exit
1938  */
1939 static void __attribute__((__format__(__printf__, 1, 2)))
1940 error(
1941 	const char *fmt,
1942 	...
1943 	)
1944 {
1945 	va_list ap;
1946 	va_start(ap, fmt);
1947 	vwarning(fmt, ap);
1948 	va_end(ap);
1949 	exit(1);
1950 }
1951 
1952 /*
1953  * getkeyid - prompt the user for a keyid to use
1954  */
1955 static u_long
1956 getkeyid(
1957 	const char *keyprompt
1958 	)
1959 {
1960 	int c;
1961 	FILE *fi;
1962 	char pbuf[20];
1963 	size_t i;
1964 	size_t ilim;
1965 
1966 #ifndef SYS_WINNT
1967 	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
1968 #else
1969 	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
1970 #endif /* SYS_WINNT */
1971 		fi = stdin;
1972 	else
1973 		setbuf(fi, (char *)NULL);
1974 	fprintf(stderr, "%s", keyprompt); fflush(stderr);
1975 	for (i = 0, ilim = COUNTOF(pbuf) - 1;
1976 	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
1977 	     )
1978 		pbuf[i++] = (char)c;
1979 	pbuf[i] = '\0';
1980 	if (fi != stdin)
1981 		fclose(fi);
1982 
1983 	return (u_long) atoi(pbuf);
1984 }
1985