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