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