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