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