ntpdc.c revision c41fbaf9bc76f0b7650e448fbd88d0a9815f47fd
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	size_t pad;
609
610	/*
611	 * This is pretty tricky.  We may get between 1 and many packets
612	 * back in response to the request.  We peel the data out of
613	 * each packet and collect it in one long block.  When the last
614	 * packet in the sequence is received we'll know how many we
615	 * should have had.  Note we use one long time out, should reconsider.
616	 */
617	*ritems = 0;
618	*rsize = 0;
619	firstpkt = 1;
620	numrecv = 0;
621	*rdata = datap = pktdata;
622	lastseq = 999;	/* too big to be a sequence number */
623	ZERO(haveseq);
624	FD_ZERO(&fds);
625
626    again:
627	if (firstpkt)
628		tvo = tvout;
629	else
630		tvo = tvsout;
631
632	FD_SET(sockfd, &fds);
633	n = select(sockfd+1, &fds, NULL, NULL, &tvo);
634	if (n == -1) {
635		warning("select fails");
636		return -1;
637	}
638	if (n == 0) {
639		/*
640		 * Timed out.  Return what we have
641		 */
642		if (firstpkt) {
643			(void) fprintf(stderr,
644				       "%s: timed out, nothing received\n",
645				       currenthost);
646			return ERR_TIMEOUT;
647		} else {
648			(void) fprintf(stderr,
649				       "%s: timed out with incomplete data\n",
650				       currenthost);
651			if (debug) {
652				printf("Received sequence numbers");
653				for (n = 0; n <= MAXSEQ; n++)
654				    if (haveseq[n])
655					printf(" %zd,", n);
656				if (lastseq != 999)
657				    printf(" last frame received\n");
658				else
659				    printf(" last frame not received\n");
660			}
661			return ERR_INCOMPLETE;
662		}
663	}
664
665	n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
666	if (n == -1) {
667		warning("read");
668		return -1;
669	}
670
671
672	/*
673	 * Check for format errors.  Bug proofing.
674	 */
675	if (n < (ssize_t)RESP_HEADER_SIZE) {
676		if (debug)
677			printf("Short (%zd byte) packet received\n", n);
678		goto again;
679	}
680	if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION ||
681	    INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) {
682		if (debug)
683			printf("Packet received with version %d\n",
684			       INFO_VERSION(rpkt.rm_vn_mode));
685		goto again;
686	}
687	if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) {
688		if (debug)
689			printf("Packet received with mode %d\n",
690			       INFO_MODE(rpkt.rm_vn_mode));
691		goto again;
692	}
693	if (INFO_IS_AUTH(rpkt.auth_seq)) {
694		if (debug)
695			printf("Encrypted packet received\n");
696		goto again;
697	}
698	if (!ISRESPONSE(rpkt.rm_vn_mode)) {
699		if (debug)
700			printf("Received request packet, wanted response\n");
701		goto again;
702	}
703	if (INFO_MBZ(rpkt.mbz_itemsize) != 0) {
704		if (debug)
705			printf("Received packet with nonzero MBZ field!\n");
706		goto again;
707	}
708
709	/*
710	 * Check implementation/request.  Could be old data getting to us.
711	 */
712	if (rpkt.implementation != implcode || rpkt.request != reqcode) {
713		if (debug)
714			printf(
715			    "Received implementation/request of %d/%d, wanted %d/%d",
716			    rpkt.implementation, rpkt.request,
717			    implcode, reqcode);
718		goto again;
719	}
720
721	/*
722	 * Check the error code.  If non-zero, return it.
723	 */
724	if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) {
725		if (debug && ISMORE(rpkt.rm_vn_mode)) {
726			printf("Error code %d received on not-final packet\n",
727			       INFO_ERR(rpkt.err_nitems));
728		}
729		return (int)INFO_ERR(rpkt.err_nitems);
730	}
731
732	/*
733	 * Collect items and size.  Make sure they make sense.
734	 */
735	items = INFO_NITEMS(rpkt.err_nitems);
736	size = INFO_ITEMSIZE(rpkt.mbz_itemsize);
737	if (esize > size)
738		pad = esize - size;
739	else
740		pad = 0;
741	datasize = items * size;
742	if ((size_t)datasize > (n-RESP_HEADER_SIZE)) {
743		if (debug)
744		    printf(
745			    "Received items %zu, size %zu (total %zu), data in packet is %zu\n",
746			    items, size, datasize, n-RESP_HEADER_SIZE);
747		goto again;
748	}
749
750	/*
751	 * If this isn't our first packet, make sure the size matches
752	 * the other ones.
753	 */
754	if (!firstpkt && size != *rsize) {
755		if (debug)
756		    printf("Received itemsize %zu, previous %zu\n",
757			   size, *rsize);
758		goto again;
759	}
760	/*
761	 * If we've received this before, +toss it
762	 */
763	seq = INFO_SEQ(rpkt.auth_seq);
764	if (haveseq[seq]) {
765		if (debug)
766		    printf("Received duplicate sequence number %d\n", seq);
767		goto again;
768	}
769	haveseq[seq] = 1;
770
771	/*
772	 * If this is the last in the sequence, record that.
773	 */
774	if (!ISMORE(rpkt.rm_vn_mode)) {
775		if (lastseq != 999) {
776			printf("Received second end sequence packet\n");
777			goto again;
778		}
779		lastseq = seq;
780	}
781
782	/*
783	 * So far, so good.  Copy this data into the output array.
784	 */
785	if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
786		size_t offset = datap - pktdata;
787		growpktdata();
788		*rdata = pktdata; /* might have been realloced ! */
789		datap = pktdata + offset;
790	}
791	/*
792	 * We now move the pointer along according to size and number of
793	 * items.  This is so we can play nice with older implementations
794	 */
795
796	tmp_data = rpkt.u.data;
797	for (i = 0; i < items; i++) {
798		memcpy(datap, tmp_data, (unsigned)size);
799		tmp_data += size;
800		zero_mem(datap + size, pad);
801		datap += size + pad;
802	}
803
804	if (firstpkt) {
805		firstpkt = 0;
806		*rsize = size + pad;
807	}
808	*ritems += items;
809
810	/*
811	 * Finally, check the count of received packets.  If we've got them
812	 * all, return
813	 */
814	++numrecv;
815	if (numrecv <= lastseq)
816		goto again;
817	return INFO_OKAY;
818}
819
820
821/*
822 * sendrequest - format and send a request packet
823 *
824 * Historically, ntpdc has used a fixed-size request packet regardless
825 * of the actual payload size.  When authenticating, the timestamp, key
826 * ID, and digest have been placed just before the end of the packet.
827 * With the introduction in late 2009 of support for authenticated
828 * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
829 * come up four bytes short.
830 *
831 * To maintain interop while allowing for larger digests, the behavior
832 * is unchanged when using 16-octet digests.  For larger digests, the
833 * timestamp, key ID, and digest are placed immediately following the
834 * request payload, with the overall packet size variable.  ntpd can
835 * distinguish 16-octet digests by the overall request size being
836 * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled.  When using a
837 * longer digest, that request size should be avoided.
838 *
839 * With the form used with 20-octet and larger digests, the timestamp,
840 * key ID, and digest are located by ntpd relative to the start of the
841 * packet, and the size of the digest is then implied by the packet
842 * size.
843 */
844static int
845sendrequest(
846	int implcode,
847	int reqcode,
848	int auth,
849	size_t qitems,
850	size_t qsize,
851	const char *qdata
852	)
853{
854	struct req_pkt qpkt;
855	size_t	datasize;
856	size_t	reqsize;
857	u_long	key_id;
858	l_fp	ts;
859	l_fp *	ptstamp;
860	size_t	maclen;
861	char *	pass;
862
863	ZERO(qpkt);
864	qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
865	qpkt.implementation = (u_char)implcode;
866	qpkt.request = (u_char)reqcode;
867
868	datasize = qitems * qsize;
869	if (datasize && qdata != NULL) {
870		memcpy(qpkt.u.data, qdata, datasize);
871		qpkt.err_nitems = ERR_NITEMS(0, qitems);
872		qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
873	} else {
874		qpkt.err_nitems = ERR_NITEMS(0, 0);
875		qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);  /* allow for optional first item */
876	}
877
878	if (!auth || (keyid_entered && info_auth_keyid == 0)) {
879		qpkt.auth_seq = AUTH_SEQ(0, 0);
880		return sendpkt(&qpkt, req_pkt_size);
881	}
882
883	if (info_auth_keyid == 0) {
884		key_id = getkeyid("Keyid: ");
885		if (!key_id) {
886			fprintf(stderr, "Invalid key identifier\n");
887			return 1;
888		}
889		info_auth_keyid = key_id;
890	}
891	if (!authistrusted(info_auth_keyid)) {
892		pass = getpass_keytype(info_auth_keytype);
893		if ('\0' == pass[0]) {
894			fprintf(stderr, "Invalid password\n");
895			return 1;
896		}
897		authusekey(info_auth_keyid, info_auth_keytype,
898			   (u_char *)pass);
899		authtrust(info_auth_keyid, 1);
900	}
901	qpkt.auth_seq = AUTH_SEQ(1, 0);
902	if (info_auth_hashlen > 16) {
903		/*
904		 * Only ntpd which expects REQ_LEN_NOMAC plus maclen
905		 * octets in an authenticated request using a 16 octet
906		 * digest (that is, a newer ntpd) will handle digests
907		 * larger than 16 octets, so for longer digests, do
908		 * not attempt to shorten the requests for downlevel
909		 * ntpd compatibility.
910		 */
911		if (REQ_LEN_NOMAC != req_pkt_size)
912			return 1;
913		reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp);
914		/* align to 32 bits */
915		reqsize = (reqsize + 3) & ~3;
916	} else
917		reqsize = req_pkt_size;
918	ptstamp = (void *)((char *)&qpkt + reqsize);
919	ptstamp--;
920	get_systime(&ts);
921	L_ADD(&ts, &delay_time);
922	HTONL_FP(&ts, ptstamp);
923	maclen = authencrypt(
924		info_auth_keyid, (void *)&qpkt, size2int_chk(reqsize));
925	if (!maclen) {
926		fprintf(stderr, "Key not found\n");
927		return 1;
928	} else if (maclen != (int)(info_auth_hashlen + sizeof(keyid_t))) {
929		fprintf(stderr,
930			"%zu octet MAC, %zu expected with %zu octet digest\n",
931			maclen, (info_auth_hashlen + sizeof(keyid_t)),
932			info_auth_hashlen);
933		return 1;
934	}
935	return sendpkt(&qpkt, reqsize + maclen);
936}
937
938
939/*
940 * doquery - send a request and process the response
941 */
942int
943doquery(
944	int implcode,
945	int reqcode,
946	int auth,
947	size_t qitems,
948	size_t qsize,
949	const char *qdata,
950	size_t *ritems,
951	size_t *rsize,
952	const char **rdata,
953 	int quiet_mask,
954	int esize
955	)
956{
957	int res;
958	char junk[512];
959	fd_set fds;
960	struct sock_timeval tvzero;
961
962	/*
963	 * Check to make sure host is open
964	 */
965	if (!havehost) {
966		(void) fprintf(stderr, "***No host open, use `host' command\n");
967		return -1;
968	}
969
970	/*
971	 * Poll the socket and clear out any pending data
972	 */
973again:
974	do {
975		tvzero.tv_sec = tvzero.tv_usec = 0;
976		FD_ZERO(&fds);
977		FD_SET(sockfd, &fds);
978		res = select(sockfd+1, &fds, NULL, NULL, &tvzero);
979		if (res == -1) {
980			warning("polling select");
981			return -1;
982		} else if (res > 0)
983
984		    (void) recv(sockfd, junk, sizeof junk, 0);
985	} while (res > 0);
986
987
988	/*
989	 * send a request
990	 */
991	res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
992	if (res != 0)
993		return res;
994
995	/*
996	 * Get the response.  If we got a standard error, print a message
997	 */
998	res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize);
999
1000	/*
1001	 * Try to be compatible with older implementations of ntpd.
1002	 */
1003	if (res == INFO_ERR_FMT && req_pkt_size != 48) {
1004		int oldsize;
1005
1006		oldsize = req_pkt_size;
1007
1008		switch(req_pkt_size) {
1009		case REQ_LEN_NOMAC:
1010			req_pkt_size = 160;
1011			break;
1012		case 160:
1013			req_pkt_size = 48;
1014			break;
1015		}
1016		if (impl_ver == IMPL_XNTPD) {
1017			fprintf(stderr,
1018			    "***Warning changing to older implementation\n");
1019			return INFO_ERR_IMPL;
1020		}
1021
1022		fprintf(stderr,
1023		    "***Warning changing the request packet size from %d to %d\n",
1024		    oldsize, req_pkt_size);
1025		goto again;
1026	}
1027
1028 	/* log error message if not told to be quiet */
1029 	if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
1030		switch(res) {
1031		case INFO_ERR_IMPL:
1032			/* Give us a chance to try the older implementation. */
1033			if (implcode == IMPL_XNTPD)
1034				break;
1035			(void) fprintf(stderr,
1036				       "***Server implementation incompatible with our own\n");
1037			break;
1038		case INFO_ERR_REQ:
1039			(void) fprintf(stderr,
1040				       "***Server doesn't implement this request\n");
1041			break;
1042		case INFO_ERR_FMT:
1043			(void) fprintf(stderr,
1044				       "***Server reports a format error in the received packet (shouldn't happen)\n");
1045			break;
1046		case INFO_ERR_NODATA:
1047			(void) fprintf(stderr,
1048				       "***Server reports data not found\n");
1049			break;
1050		case INFO_ERR_AUTH:
1051			(void) fprintf(stderr, "***Permission denied\n");
1052			break;
1053		case ERR_TIMEOUT:
1054			(void) fprintf(stderr, "***Request timed out\n");
1055			break;
1056		case ERR_INCOMPLETE:
1057			(void) fprintf(stderr,
1058				       "***Response from server was incomplete\n");
1059			break;
1060		default:
1061			(void) fprintf(stderr,
1062				       "***Server returns unknown error code %d\n", res);
1063			break;
1064		}
1065	}
1066	return res;
1067}
1068
1069
1070/*
1071 * getcmds - read commands from the standard input and execute them
1072 */
1073static void
1074getcmds(void)
1075{
1076	char *	line;
1077	int	count;
1078
1079	ntp_readline_init(interactive ? prompt : NULL);
1080
1081	for (;;) {
1082		line = ntp_readline(&count);
1083		if (NULL == line)
1084			break;
1085		docmd(line);
1086		free(line);
1087	}
1088
1089	ntp_readline_uninit();
1090}
1091
1092
1093#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1094/*
1095 * abortcmd - catch interrupts and abort the current command
1096 */
1097static RETSIGTYPE
1098abortcmd(
1099	int sig
1100	)
1101{
1102
1103	if (current_output == stdout)
1104	    (void) fflush(stdout);
1105	putc('\n', stderr);
1106	(void) fflush(stderr);
1107	if (jump) longjmp(interrupt_buf, 1);
1108}
1109#endif /* SYS_WINNT */
1110
1111/*
1112 * docmd - decode the command line and execute a command
1113 */
1114static void
1115docmd(
1116	const char *cmdline
1117	)
1118{
1119	char *tokens[1+MAXARGS+MOREARGS+2];
1120	struct parse pcmd;
1121	int ntok;
1122	int i, ti;
1123	int rval;
1124	struct xcmd *xcmd;
1125
1126	ai_fam_templ = ai_fam_default;
1127	/*
1128	 * Tokenize the command line.  If nothing on it, return.
1129	 */
1130	if (strlen(cmdline) >= MAXLINE) {
1131		fprintf(stderr, "***Command ignored, more than %d characters:\n%s\n",
1132			MAXLINE - 1, cmdline);
1133		return;
1134	}
1135	tokenize(cmdline, tokens, &ntok);
1136	if (ntok == 0)
1137	    return;
1138
1139	/*
1140	 * Find the appropriate command description.
1141	 */
1142	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1143	if (i == 0) {
1144		(void) fprintf(stderr, "***Command `%s' unknown\n",
1145			       tokens[0]);
1146		return;
1147	} else if (i >= 2) {
1148		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1149			       tokens[0]);
1150		return;
1151	}
1152
1153	/*
1154	 * Save the keyword, then walk through the arguments, interpreting
1155	 * as we go.
1156	 */
1157	pcmd.keyword = tokens[0];
1158	pcmd.nargs = 0;
1159	ti = 1;
1160	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) {
1161		if ((i+ti) >= ntok) {
1162			if (!(xcmd->arg[i] & OPT)) {
1163				printusage(xcmd, stderr);
1164				return;
1165			}
1166			break;
1167		}
1168		if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>'))
1169			break;
1170		rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]);
1171		if (rval == -1) {
1172			ti++;
1173			continue;
1174		}
1175		if (rval == 0)
1176			return;
1177		pcmd.nargs++;
1178		i++;
1179	}
1180
1181	/* Any extra args are assumed to be "OPT|NTP_STR". */
1182	for ( ; i < MAXARGS + MOREARGS;) {
1183	     if ((i+ti) >= ntok)
1184		  break;
1185		rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]);
1186		if (rval == -1) {
1187			ti++;
1188			continue;
1189		}
1190		if (rval == 0)
1191			return;
1192		pcmd.nargs++;
1193		i++;
1194	}
1195
1196	i += ti;
1197	if (i < ntok && *tokens[i] == '>') {
1198		char *fname;
1199
1200		if (*(tokens[i]+1) != '\0')
1201		    fname = tokens[i]+1;
1202		else if ((i+1) < ntok)
1203		    fname = tokens[i+1];
1204		else {
1205			(void) fprintf(stderr, "***No file for redirect\n");
1206			return;
1207		}
1208
1209		current_output = fopen(fname, "w");
1210		if (current_output == NULL) {
1211			(void) fprintf(stderr, "***Error opening %s: ", fname);
1212			perror("");
1213			return;
1214		}
1215	} else {
1216		current_output = stdout;
1217	}
1218
1219	if (interactive && setjmp(interrupt_buf)) {
1220		return;
1221	} else {
1222		jump = 1;
1223		(xcmd->handler)(&pcmd, current_output);
1224		jump = 0;
1225		if (current_output != stdout)
1226			(void) fclose(current_output);
1227		current_output = NULL;
1228	}
1229}
1230
1231
1232/*
1233 * tokenize - turn a command line into tokens
1234 */
1235static void
1236tokenize(
1237	const char *line,
1238	char **tokens,
1239	int *ntok
1240	)
1241{
1242	register const char *cp;
1243	register char *sp;
1244	static char tspace[MAXLINE];
1245
1246	sp = tspace;
1247	cp = line;
1248	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1249		tokens[*ntok] = sp;
1250		while (ISSPACE(*cp))
1251		    cp++;
1252		if (ISEOL(*cp))
1253		    break;
1254		do {
1255			*sp++ = *cp++;
1256		} while (!ISSPACE(*cp) && !ISEOL(*cp));
1257
1258		*sp++ = '\0';
1259	}
1260}
1261
1262
1263
1264/*
1265 * findcmd - find a command in a command description table
1266 */
1267static int
1268findcmd(
1269	register char *str,
1270	struct xcmd *clist1,
1271	struct xcmd *clist2,
1272	struct xcmd **cmd
1273	)
1274{
1275	register struct xcmd *cl;
1276	size_t clen;
1277	int nmatch;
1278	struct xcmd *nearmatch = NULL;
1279	struct xcmd *clist;
1280
1281	clen = strlen(str);
1282	nmatch = 0;
1283	if (clist1 != 0)
1284	    clist = clist1;
1285	else if (clist2 != 0)
1286	    clist = clist2;
1287	else
1288	    return 0;
1289
1290    again:
1291	for (cl = clist; cl->keyword != 0; cl++) {
1292		/* do a first character check, for efficiency */
1293		if (*str != *(cl->keyword))
1294		    continue;
1295		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1296			/*
1297			 * Could be extact match, could be approximate.
1298			 * Is exact if the length of the keyword is the
1299			 * same as the str.
1300			 */
1301			if (*((cl->keyword) + clen) == '\0') {
1302				*cmd = cl;
1303				return 1;
1304			}
1305			nmatch++;
1306			nearmatch = cl;
1307		}
1308	}
1309
1310				/*
1311				 * See if there is more to do.  If so, go again.  Sorry about the
1312				 * goto, too much looking at BSD sources...
1313				 */
1314	if (clist == clist1 && clist2 != 0) {
1315		clist = clist2;
1316		goto again;
1317	}
1318
1319				/*
1320				 * If we got extactly 1 near match, use it, else return number
1321				 * of matches.
1322				 */
1323	if (nmatch == 1) {
1324		*cmd = nearmatch;
1325		return 1;
1326	}
1327	return nmatch;
1328}
1329
1330
1331/*
1332 * getarg - interpret an argument token
1333 *
1334 * string is always set.
1335 * type is set to the decoded type.
1336 *
1337 * return:	 0 - failure
1338 *		 1 - success
1339 *		-1 - skip to next token
1340 */
1341static int
1342getarg(
1343	char *str,
1344	int code,
1345	arg_v *argp
1346	)
1347{
1348	int isneg;
1349	char *cp, *np;
1350	static const char *digits = "0123456789";
1351
1352	ZERO(*argp);
1353	argp->string = str;
1354	argp->type   = code & ~OPT;
1355
1356	switch (argp->type) {
1357	    case NTP_STR:
1358		break;
1359	    case NTP_ADD:
1360		if (!strcmp("-6", str)) {
1361			ai_fam_templ = AF_INET6;
1362			return -1;
1363		} else if (!strcmp("-4", str)) {
1364			ai_fam_templ = AF_INET;
1365			return -1;
1366		}
1367		if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
1368			return 0;
1369		}
1370		break;
1371	    case NTP_INT:
1372	    case NTP_UINT:
1373		isneg = 0;
1374		np = str;
1375		if (*np == '-') {
1376			np++;
1377			isneg = 1;
1378		}
1379
1380		argp->uval = 0;
1381		do {
1382			cp = strchr(digits, *np);
1383			if (cp == NULL) {
1384				(void) fprintf(stderr,
1385					       "***Illegal integer value %s\n", str);
1386				return 0;
1387			}
1388			argp->uval *= 10;
1389			argp->uval += (u_long)(cp - digits);
1390		} while (*(++np) != '\0');
1391
1392		if (isneg) {
1393			if ((code & ~OPT) == NTP_UINT) {
1394				(void) fprintf(stderr,
1395					       "***Value %s should be unsigned\n", str);
1396				return 0;
1397			}
1398			argp->ival = -argp->ival;
1399		}
1400		break;
1401	    case IP_VERSION:
1402		if (!strcmp("-6", str))
1403			argp->ival = 6 ;
1404		else if (!strcmp("-4", str))
1405			argp->ival = 4 ;
1406		else {
1407			(void) fprintf(stderr,
1408			    "***Version must be either 4 or 6\n");
1409			return 0;
1410		}
1411		break;
1412	}
1413
1414	return 1;
1415}
1416
1417
1418/*
1419 * getnetnum - given a host name, return its net number
1420 *	       and (optional) full name
1421 */
1422static int
1423getnetnum(
1424	const char *hname,
1425	sockaddr_u *num,
1426	char *fullhost,
1427	int af
1428	)
1429{
1430	struct addrinfo hints, *ai = NULL;
1431
1432	ZERO(hints);
1433	hints.ai_flags = AI_CANONNAME;
1434#ifdef AI_ADDRCONFIG
1435	hints.ai_flags |= AI_ADDRCONFIG;
1436#endif
1437
1438	/*
1439	 * decodenetnum only works with addresses, but handles syntax
1440	 * that getaddrinfo doesn't:  [2001::1]:1234
1441	 */
1442	if (decodenetnum(hname, num)) {
1443		if (fullhost != NULL)
1444			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1445				    LENHOSTNAME, NULL, 0, 0);
1446		return 1;
1447	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1448		INSIST(sizeof(*num) >= ai->ai_addrlen);
1449		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1450		if (fullhost != NULL) {
1451			if (ai->ai_canonname != NULL)
1452				strlcpy(fullhost, ai->ai_canonname,
1453					LENHOSTNAME);
1454			else
1455				getnameinfo(&num->sa, SOCKLEN(num),
1456					    fullhost, LENHOSTNAME, NULL,
1457					    0, 0);
1458		}
1459		return 1;
1460	}
1461	fprintf(stderr, "***Can't find host %s\n", hname);
1462
1463	return 0;
1464}
1465
1466
1467/*
1468 * nntohost - convert network number to host name.  This routine enforces
1469 *	       the showhostnames setting.
1470 */
1471const char *
1472nntohost(
1473	sockaddr_u *netnum
1474	)
1475{
1476	if (!showhostnames || SOCK_UNSPEC(netnum))
1477		return stoa(netnum);
1478	else if (ISREFCLOCKADR(netnum))
1479		return refnumtoa(netnum);
1480	else
1481		return socktohost(netnum);
1482}
1483
1484
1485/*
1486 * Finally, the built in command handlers
1487 */
1488
1489/*
1490 * help - tell about commands, or details of a particular command
1491 */
1492static void
1493help(
1494	struct parse *pcmd,
1495	FILE *fp
1496	)
1497{
1498	struct xcmd *xcp;
1499	char *cmd;
1500	const char *list[100];
1501	size_t word, words;
1502	size_t row, rows;
1503	size_t col, cols;
1504	size_t length;
1505
1506	if (pcmd->nargs == 0) {
1507		words = 0;
1508		for (xcp = builtins; xcp->keyword != 0; xcp++) {
1509			if (*(xcp->keyword) != '?')
1510				list[words++] = xcp->keyword;
1511		}
1512		for (xcp = opcmds; xcp->keyword != 0; xcp++)
1513			list[words++] = xcp->keyword;
1514
1515		qsort((void *)list, words, sizeof(list[0]), helpsort);
1516		col = 0;
1517		for (word = 0; word < words; word++) {
1518			length = strlen(list[word]);
1519			col = max(col, length);
1520		}
1521
1522		cols = SCREENWIDTH / ++col;
1523		rows = (words + cols - 1) / cols;
1524
1525		fprintf(fp, "ntpdc commands:\n");
1526
1527		for (row = 0; row < rows; row++) {
1528			for (word = row; word < words; word += rows)
1529				fprintf(fp, "%-*.*s", (int)col,
1530					(int)col - 1, list[word]);
1531			fprintf(fp, "\n");
1532		}
1533	} else {
1534		cmd = pcmd->argval[0].string;
1535		words = findcmd(cmd, builtins, opcmds, &xcp);
1536		if (words == 0) {
1537			fprintf(stderr,
1538				"Command `%s' is unknown\n", cmd);
1539			return;
1540		} else if (words >= 2) {
1541			fprintf(stderr,
1542				"Command `%s' is ambiguous\n", cmd);
1543			return;
1544		}
1545		fprintf(fp, "function: %s\n", xcp->comment);
1546		printusage(xcp, fp);
1547	}
1548}
1549
1550
1551/*
1552 * helpsort - do hostname qsort comparisons
1553 */
1554static int
1555helpsort(
1556	const void *t1,
1557	const void *t2
1558	)
1559{
1560	const char * const *	name1 = t1;
1561	const char * const *	name2 = t2;
1562
1563	return strcmp(*name1, *name2);
1564}
1565
1566
1567/*
1568 * printusage - print usage information for a command
1569 */
1570static void
1571printusage(
1572	struct xcmd *xcp,
1573	FILE *fp
1574	)
1575{
1576	int i, opt46;
1577
1578	opt46 = 0;
1579	(void) fprintf(fp, "usage: %s", xcp->keyword);
1580	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
1581		if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) {
1582			(void) fprintf(fp, " [ -4|-6 ]");
1583			opt46 = 1;
1584		}
1585		if (xcp->arg[i] & OPT)
1586		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
1587		else
1588		    (void) fprintf(fp, " %s", xcp->desc[i]);
1589	}
1590	(void) fprintf(fp, "\n");
1591}
1592
1593
1594/*
1595 * timeout - set time out time
1596 */
1597static void
1598timeout(
1599	struct parse *pcmd,
1600	FILE *fp
1601	)
1602{
1603	int val;
1604
1605	if (pcmd->nargs == 0) {
1606		val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
1607		(void) fprintf(fp, "primary timeout %d ms\n", val);
1608	} else {
1609		tvout.tv_sec = pcmd->argval[0].uval / 1000;
1610		tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
1611			* 1000;
1612	}
1613}
1614
1615
1616/*
1617 * my_delay - set delay for auth requests
1618 */
1619static void
1620my_delay(
1621	struct parse *pcmd,
1622	FILE *fp
1623	)
1624{
1625	int isneg;
1626	u_long val;
1627
1628	if (pcmd->nargs == 0) {
1629		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
1630		(void) fprintf(fp, "delay %lu ms\n", val);
1631	} else {
1632		if (pcmd->argval[0].ival < 0) {
1633			isneg = 1;
1634			val = (u_long)(-pcmd->argval[0].ival);
1635		} else {
1636			isneg = 0;
1637			val = (u_long)pcmd->argval[0].ival;
1638		}
1639
1640		delay_time.l_ui = val / 1000;
1641		val %= 1000;
1642		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
1643
1644		if (isneg)
1645		    L_NEG(&delay_time);
1646	}
1647}
1648
1649
1650/*
1651 * host - set the host we are dealing with.
1652 */
1653static void
1654host(
1655	struct parse *pcmd,
1656	FILE *fp
1657	)
1658{
1659	int i;
1660
1661	if (pcmd->nargs == 0) {
1662		if (havehost)
1663		    (void) fprintf(fp, "current host is %s\n", currenthost);
1664		else
1665		    (void) fprintf(fp, "no current host\n");
1666		return;
1667	}
1668
1669	i = 0;
1670	if (pcmd->nargs == 2) {
1671		if (!strcmp("-4", pcmd->argval[i].string))
1672			ai_fam_templ = AF_INET;
1673		else if (!strcmp("-6", pcmd->argval[i].string))
1674			ai_fam_templ = AF_INET6;
1675		else {
1676			if (havehost)
1677				(void) fprintf(fp,
1678				    "current host remains %s\n", currenthost);
1679			else
1680				(void) fprintf(fp, "still no current host\n");
1681			return;
1682		}
1683		i = 1;
1684	}
1685	if (openhost(pcmd->argval[i].string)) {
1686		(void) fprintf(fp, "current host set to %s\n", currenthost);
1687	} else {
1688		if (havehost)
1689		    (void) fprintf(fp,
1690				   "current host remains %s\n", currenthost);
1691		else
1692		    (void) fprintf(fp, "still no current host\n");
1693	}
1694}
1695
1696
1697/*
1698 * keyid - get a keyid to use for authenticating requests
1699 */
1700static void
1701keyid(
1702	struct parse *pcmd,
1703	FILE *fp
1704	)
1705{
1706	if (pcmd->nargs == 0) {
1707		if (info_auth_keyid == 0 && !keyid_entered)
1708		    (void) fprintf(fp, "no keyid defined\n");
1709		else if (info_auth_keyid == 0 && keyid_entered)
1710		    (void) fprintf(fp, "no keyid will be sent\n");
1711		else
1712		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
1713	} else {
1714		info_auth_keyid = pcmd->argval[0].uval;
1715		keyid_entered = 1;
1716	}
1717}
1718
1719
1720/*
1721 * keytype - get type of key to use for authenticating requests
1722 */
1723static void
1724keytype(
1725	struct parse *pcmd,
1726	FILE *fp
1727	)
1728{
1729	const char *	digest_name;
1730	size_t		digest_len;
1731	int		key_type;
1732
1733	if (!pcmd->nargs) {
1734		fprintf(fp, "keytype is %s with %lu octet digests\n",
1735			keytype_name(info_auth_keytype),
1736			(u_long)info_auth_hashlen);
1737		return;
1738	}
1739
1740	digest_name = pcmd->argval[0].string;
1741	digest_len = 0;
1742	key_type = keytype_from_text(digest_name, &digest_len);
1743
1744	if (!key_type) {
1745		fprintf(fp, "keytype must be 'md5'%s\n",
1746#ifdef OPENSSL
1747			" or a digest type provided by OpenSSL");
1748#else
1749			"");
1750#endif
1751		return;
1752	}
1753
1754	info_auth_keytype = key_type;
1755	info_auth_hashlen = digest_len;
1756}
1757
1758
1759/*
1760 * passwd - get an authentication key
1761 */
1762/*ARGSUSED*/
1763static void
1764passwd(
1765	struct parse *pcmd,
1766	FILE *fp
1767	)
1768{
1769	char *pass;
1770
1771	if (info_auth_keyid == 0) {
1772		info_auth_keyid = getkeyid("Keyid: ");
1773		if (info_auth_keyid == 0) {
1774			(void)fprintf(fp, "Keyid must be defined\n");
1775			return;
1776		}
1777	}
1778	if (pcmd->nargs >= 1)
1779		pass = pcmd->argval[0].string;
1780	else {
1781		pass = getpass_keytype(info_auth_keytype);
1782		if ('\0' == *pass) {
1783			fprintf(fp, "Password unchanged\n");
1784			return;
1785		}
1786	}
1787	authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
1788	authtrust(info_auth_keyid, 1);
1789}
1790
1791
1792/*
1793 * hostnames - set the showhostnames flag
1794 */
1795static void
1796hostnames(
1797	struct parse *pcmd,
1798	FILE *fp
1799	)
1800{
1801	if (pcmd->nargs == 0) {
1802		if (showhostnames)
1803		    (void) fprintf(fp, "hostnames being shown\n");
1804		else
1805		    (void) fprintf(fp, "hostnames not being shown\n");
1806	} else {
1807		if (STREQ(pcmd->argval[0].string, "yes"))
1808		    showhostnames = 1;
1809		else if (STREQ(pcmd->argval[0].string, "no"))
1810		    showhostnames = 0;
1811		else
1812		    (void)fprintf(stderr, "What?\n");
1813	}
1814}
1815
1816
1817/*
1818 * setdebug - set/change debugging level
1819 */
1820static void
1821setdebug(
1822	struct parse *pcmd,
1823	FILE *fp
1824	)
1825{
1826	if (pcmd->nargs == 0) {
1827		(void) fprintf(fp, "debug level is %d\n", debug);
1828		return;
1829	} else if (STREQ(pcmd->argval[0].string, "no")) {
1830		debug = 0;
1831	} else if (STREQ(pcmd->argval[0].string, "more")) {
1832		debug++;
1833	} else if (STREQ(pcmd->argval[0].string, "less")) {
1834		debug--;
1835	} else {
1836		(void) fprintf(fp, "What?\n");
1837		return;
1838	}
1839	(void) fprintf(fp, "debug level set to %d\n", debug);
1840}
1841
1842
1843/*
1844 * quit - stop this nonsense
1845 */
1846/*ARGSUSED*/
1847static void
1848quit(
1849	struct parse *pcmd,
1850	FILE *fp
1851	)
1852{
1853	if (havehost)
1854	    closesocket(sockfd);
1855	exit(0);
1856}
1857
1858
1859/*
1860 * version - print the current version number
1861 */
1862/*ARGSUSED*/
1863static void
1864version(
1865	struct parse *pcmd,
1866	FILE *fp
1867	)
1868{
1869
1870	(void) fprintf(fp, "%s\n", Version);
1871	return;
1872}
1873
1874
1875static void __attribute__((__format__(__printf__, 1, 0)))
1876vwarning(const char *fmt, va_list ap)
1877{
1878	int serrno = errno;
1879	(void) fprintf(stderr, "%s: ", progname);
1880	vfprintf(stderr, fmt, ap);
1881	(void) fprintf(stderr, ": %s\n", strerror(serrno));
1882}
1883
1884/*
1885 * warning - print a warning message
1886 */
1887static void __attribute__((__format__(__printf__, 1, 2)))
1888warning(
1889	const char *fmt,
1890	...
1891	)
1892{
1893	va_list ap;
1894	va_start(ap, fmt);
1895	vwarning(fmt, ap);
1896	va_end(ap);
1897}
1898
1899
1900/*
1901 * error - print a message and exit
1902 */
1903static void __attribute__((__format__(__printf__, 1, 2)))
1904error(
1905	const char *fmt,
1906	...
1907	)
1908{
1909	va_list ap;
1910	va_start(ap, fmt);
1911	vwarning(fmt, ap);
1912	va_end(ap);
1913	exit(1);
1914}
1915
1916/*
1917 * getkeyid - prompt the user for a keyid to use
1918 */
1919static u_long
1920getkeyid(
1921	const char *keyprompt
1922	)
1923{
1924	int c;
1925	FILE *fi;
1926	char pbuf[20];
1927	size_t i;
1928	size_t ilim;
1929
1930#ifndef SYS_WINNT
1931	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
1932#else
1933	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
1934#endif /* SYS_WINNT */
1935		fi = stdin;
1936	else
1937		setbuf(fi, (char *)NULL);
1938	fprintf(stderr, "%s", keyprompt); fflush(stderr);
1939	for (i = 0, ilim = COUNTOF(pbuf) - 1;
1940	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
1941	     )
1942		pbuf[i++] = (char)c;
1943	pbuf[i] = '\0';
1944	if (fi != stdin)
1945		fclose(fi);
1946
1947	return (u_long) atoi(pbuf);
1948}
1949