1ef64b99roberto/*
2ef64b99roberto * ntpdc - control and monitor your ntpd daemon
3ef64b99roberto */
4047f369cy#include <config.h>
5ef64b99roberto#include <stdio.h>
6d54cfbdroberto#include <stddef.h>
77a6072eroberto#include <ctype.h>
87a6072eroberto#include <signal.h>
97a6072eroberto#include <setjmp.h>
10047f369cy#ifdef HAVE_UNISTD_H
11047f369cy# include <unistd.h>
12047f369cy#endif
13047f369cy#ifdef HAVE_FCNTL_H
14047f369cy# include <fcntl.h>
15047f369cy#endif
16047f369cy#ifdef SYS_WINNT
17047f369cy# include <mswsock.h>
18047f369cy#endif
19047f369cy#include <isc/net.h>
20047f369cy#include <isc/result.h>
217a6072eroberto
2240b8e41roberto#include "ntpdc.h"
2340b8e41roberto#include "ntp_select.h"
2440b8e41roberto#include "ntp_stdlib.h"
25d54cfbdroberto#include "ntp_assert.h"
26d54cfbdroberto#include "ntp_lineedit.h"
27047f369cy#ifdef OPENSSL
28047f369cy#include "openssl/evp.h"
29047f369cy#include "openssl/objects.h"
30047f369cy#endif
31d54cfbdroberto#include <ssl_applink.c>
3240b8e41roberto
33d54cfbdroberto#include "ntp_libopts.h"
347a6072eroberto#include "ntpdc-opts.h"
358518518delphij#include "safecast.h"
36ef64b99roberto
37ef64b99roberto#ifdef SYS_VXWORKS
387a6072eroberto				/* vxWorks needs mode flag -casey*/
397a6072eroberto# define open(name, flags)   open(name, flags, 0777)
407a6072eroberto# define SERVER_PORT_NUM     123
417a6072eroberto#endif
427a6072eroberto
437a6072eroberto/* We use COMMAND as an autogen keyword */
447a6072eroberto#ifdef COMMAND
457a6072eroberto# undef COMMAND
46ef64b99roberto#endif
47ef64b99roberto
48ef64b99roberto/*
49ef64b99roberto * Because we now potentially understand a lot of commands (and
50ef64b99roberto * it requires a lot of commands to talk to ntpd) we will run
51ef64b99roberto * interactive if connected to a terminal.
52ef64b99roberto */
53ef64b99robertostatic	int	interactive = 0;	/* set to 1 when we should prompt */
54ef64b99robertostatic	const char *	prompt = "ntpdc> ";	/* prompt to ask him about */
55ef64b99roberto
56ef64b99roberto/*
57ef64b99roberto * Keyid used for authenticated requests.  Obtained on the fly.
58ef64b99roberto */
59ef64b99robertostatic	u_long	info_auth_keyid;
607a6072erobertostatic int keyid_entered = 0;
61ef64b99roberto
62d54cfbdrobertostatic	int	info_auth_keytype = NID_md5;	/* MD5 */
63d54cfbdrobertostatic	size_t	info_auth_hashlen = 16;		/* MD5 */
64ef64b99robertou_long	current_time;		/* needed by authkeys; not used */
65ef64b99roberto
667a6072eroberto/*
677a6072eroberto * for get_systime()
687a6072eroberto */
697a6072erobertos_char	sys_precision;		/* local clock precision (log2 s) */
707a6072eroberto
71d54cfbdrobertoint		ntpdcmain	(int,	char **);
72ef64b99roberto/*
73ef64b99roberto * Built in command handler declarations
74ef64b99roberto */
75d54cfbdrobertostatic	int	openhost	(const char *);
76d54cfbdrobertostatic	int	sendpkt		(void *, size_t);
77d54cfbdrobertostatic	void	growpktdata	(void);
788518518delphijstatic	int	getresponse	(int, int, size_t *, size_t *, const char **, size_t);
798518518delphijstatic	int	sendrequest	(int, int, int, size_t, size_t, const char *);
80d54cfbdrobertostatic	void	getcmds		(void);
81d54cfbdrobertostatic	RETSIGTYPE abortcmd	(int);
82d54cfbdrobertostatic	void	docmd		(const char *);
83d54cfbdrobertostatic	void	tokenize	(const char *, char **, int *);
84d54cfbdrobertostatic	int	findcmd		(char *, struct xcmd *, struct xcmd *, struct xcmd **);
85d54cfbdrobertostatic	int	getarg		(char *, int, arg_v *);
86d54cfbdrobertostatic	int	getnetnum	(const char *, sockaddr_u *, char *, int);
87d54cfbdrobertostatic	void	help		(struct parse *, FILE *);
88d54cfbdrobertostatic	int	helpsort	(const void *, const void *);
89d54cfbdrobertostatic	void	printusage	(struct xcmd *, FILE *);
90d54cfbdrobertostatic	void	timeout		(struct parse *, FILE *);
91d54cfbdrobertostatic	void	my_delay	(struct parse *, FILE *);
92d54cfbdrobertostatic	void	host		(struct parse *, FILE *);
93d54cfbdrobertostatic	void	keyid		(struct parse *, FILE *);
94d54cfbdrobertostatic	void	keytype		(struct parse *, FILE *);
95d54cfbdrobertostatic	void	passwd		(struct parse *, FILE *);
96d54cfbdrobertostatic	void	hostnames	(struct parse *, FILE *);
97d54cfbdrobertostatic	void	setdebug	(struct parse *, FILE *);
98d54cfbdrobertostatic	void	quit		(struct parse *, FILE *);
99d54cfbdrobertostatic	void	version		(struct parse *, FILE *);
100bdc155dcystatic	void	warning		(const char *, ...)
101bdc155dcy    __attribute__((__format__(__printf__, 1, 2)));
102bdc155dcystatic	void	error		(const char *, ...)
103bdc155dcy    __attribute__((__format__(__printf__, 1, 2)));
104d54cfbdrobertostatic	u_long	getkeyid	(const char *);
105ef64b99roberto
106ef64b99roberto
107ef64b99roberto
108ef64b99roberto/*
109ef64b99roberto * Built-in commands we understand
110ef64b99roberto */
111ef64b99robertostatic	struct xcmd builtins[] = {
112ef64b99roberto	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
113ef64b99roberto	  { "command", "", "", "" },
114ef64b99roberto	  "tell the use and syntax of commands" },
115ef64b99roberto	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
116ef64b99roberto	  { "command", "", "", "" },
117ef64b99roberto	  "tell the use and syntax of commands" },
1187a6072eroberto	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
119ef64b99roberto	  { "msec", "", "", "" },
120ef64b99roberto	  "set the primary receive time out" },
1217a6072eroberto	{ "delay",	my_delay,	{ OPT|NTP_INT, NO, NO, NO },
122ef64b99roberto	  { "msec", "", "", "" },
123ef64b99roberto	  "set the delay added to encryption time stamps" },
124118e757roberto	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
125118e757roberto	  { "-4|-6", "hostname", "", "" },
126ef64b99roberto	  "specify the host whose NTP server we talk to" },
127ef64b99roberto	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
128ef64b99roberto	  { "", "", "", "" },
129ef64b99roberto	  "specify a password to use for authenticated requests"},
130ef64b99roberto	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
131ef64b99roberto	  { "yes|no", "", "", "" },
132ef64b99roberto	  "specify whether hostnames or net numbers are printed"},
133ef64b99roberto	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
134ef64b99roberto	  { "no|more|less", "", "", "" },
135ef64b99roberto	  "set/change debugging level" },
136ef64b99roberto	{ "quit",	quit,		{ NO, NO, NO, NO },
137ef64b99roberto	  { "", "", "", "" },
138ef64b99roberto	  "exit ntpdc" },
139ef64b99roberto	{ "exit",	quit,		{ NO, NO, NO, NO },
140ef64b99roberto	  { "", "", "", "" },
141ef64b99roberto	  "exit ntpdc" },
1427a6072eroberto	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
143ef64b99roberto	  { "key#", "", "", "" },
144ef64b99roberto	  "set/show keyid to use for authenticated requests" },
145ef64b99roberto	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
146ef64b99roberto	  { "(md5|des)", "", "", "" },
147ef64b99roberto	  "set/show key authentication type for authenticated requests (des|md5)" },
148ef64b99roberto	{ "version",	version,	{ NO, NO, NO, NO },
149ef64b99roberto	  { "", "", "", "" },
150ef64b99roberto	  "print version number" },
151ef64b99roberto	{ 0,		0,		{ NO, NO, NO, NO },
152ef64b99roberto	  { "", "", "", "" }, "" }
153ef64b99roberto};
154ef64b99roberto
155ef64b99roberto
156ef64b99roberto/*
157ef64b99roberto * Default values we use.
158ef64b99roberto */
159d54cfbdroberto#define	DEFHOST		"localhost"	/* default host name */
160ef64b99roberto#define	DEFTIMEOUT	(5)		/* 5 second time out */
161ef64b99roberto#define	DEFSTIMEOUT	(2)		/* 2 second time out after first */
162ef64b99roberto#define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
163ef64b99roberto#define	LENHOSTNAME	256		/* host name is 256 characters long */
164ef64b99roberto#define	MAXCMDS		100		/* maximum commands on cmd line */
165ef64b99roberto#define	MAXHOSTS	200		/* maximum hosts on cmd line */
166ef64b99roberto#define	MAXLINE		512		/* maximum line length */
1677a6072eroberto#define	MAXTOKENS	(1+1+MAXARGS+MOREARGS+2)	/* maximum number of usable tokens */
1687a6072eroberto#define	SCREENWIDTH  	78		/* nominal screen width in columns */
169ef64b99roberto
170ef64b99roberto/*
171ef64b99roberto * Some variables used and manipulated locally
172ef64b99roberto */
173d54cfbdrobertostatic	struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
174d54cfbdrobertostatic	struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
175ef64b99robertostatic	l_fp delay_time;				/* delay time */
176ef64b99robertostatic	char currenthost[LENHOSTNAME];			/* current host name */
177118e757robertoint showhostnames = 1;					/* show host names by default */
178ef64b99roberto
179837c91fcystatic	int ai_fam_templ = AF_UNSPEC;		/* address family */
180837c91fcystatic	int ai_fam_default = AF_UNSPEC;	/* default address family */
181118e757robertostatic	SOCKET sockfd;					/* fd socket is opened on */
182ef64b99robertostatic	int havehost = 0;				/* set to 1 when host open */
183118e757robertoint s_port = 0;
184ef64b99roberto
185ef64b99roberto/*
186ef64b99roberto * Holds data returned from queries.  We allocate INITDATASIZE
187ef64b99roberto * octets to begin with, increasing this as we need to.
188ef64b99roberto */
189ef64b99roberto#define	INITDATASIZE	(sizeof(struct resp_pkt) * 16)
190ef64b99roberto#define	INCDATASIZE	(sizeof(struct resp_pkt) * 8)
191ef64b99roberto
192ef64b99robertostatic	char *pktdata;
193ef64b99robertostatic	int pktdatasize;
194ef64b99roberto
195ef64b99roberto/*
196f771469roberto * These are used to help the magic with old and new versions of ntpd.
197f771469roberto */
198118e757robertoint impl_ver = IMPL_XNTPD;
199f771469robertostatic int req_pkt_size = REQ_LEN_NOMAC;
200f771469roberto
201f771469roberto/*
202ef64b99roberto * For commands typed on the command line (with the -c option)
203ef64b99roberto */
204ef64b99robertostatic	int numcmds = 0;
205ef64b99robertostatic	const char *ccmds[MAXCMDS];
206ef64b99roberto#define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
207ef64b99roberto
208ef64b99roberto/*
209ef64b99roberto * When multiple hosts are specified.
210ef64b99roberto */
211ef64b99robertostatic	int numhosts = 0;
212ef64b99robertostatic	const char *chosts[MAXHOSTS];
213ef64b99roberto#define	ADDHOST(cp)	if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
214ef64b99roberto
215ef64b99roberto/*
216ef64b99roberto * Error codes for internal use
217ef64b99roberto */
218ef64b99roberto#define	ERR_INCOMPLETE		16
219ef64b99roberto#define	ERR_TIMEOUT		17
220ef64b99roberto
221ef64b99roberto/*
222ef64b99roberto * Macro definitions we use
223ef64b99roberto */
224ef64b99roberto#define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
225ef64b99roberto#define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
226ef64b99roberto#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
227ef64b99roberto
228ef64b99roberto/*
22975715b3delphij * Jump buffer for longjumping back to the command level.
23075715b3delphij *
23175715b3delphij * See ntpq/ntpq.c for an explanation why 'sig{set,long}jmp()' is used
23275715b3delphij * when available.
233ef64b99roberto */
23475715b3delphij#if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
23575715b3delphij# define JMP_BUF	sigjmp_buf
23675715b3delphij# define SETJMP(x)	sigsetjmp((x), 1)
23775715b3delphij# define LONGJMP(x, v)	siglongjmp((x),(v))
23875715b3delphij#else
23975715b3delphij# define JMP_BUF	jmp_buf
24075715b3delphij# define SETJMP(x)	setjmp((x))
24175715b3delphij# define LONGJMP(x, v)	longjmp((x),(v))
24275715b3delphij#endif
24375715b3delphijstatic	JMP_BUF		interrupt_buf;
24475715b3delphijstatic	volatile int	jump = 0;
245ef64b99roberto
246ef64b99roberto/*
247ef64b99roberto * Pointer to current output unit
248ef64b99roberto */
24975715b3delphijstatic	FILE *current_output = NULL;
250ef64b99roberto
251ef64b99roberto/*
252ef64b99roberto * Command table imported from ntpdc_ops.c
253ef64b99roberto */
254ef64b99robertoextern struct xcmd opcmds[];
255ef64b99roberto
256aae1e7dglebiuschar const *progname;
257ef64b99roberto
258ef64b99roberto#ifdef NO_MAIN_ALLOWED
259ef64b99robertoCALL(ntpdc,"ntpdc",ntpdcmain);
260ef64b99roberto#else
261ef64b99robertoint
262ef64b99robertomain(
263ef64b99roberto	int argc,
264ef64b99roberto	char *argv[]
265ef64b99roberto	)
266ef64b99roberto{
267ef64b99roberto	return ntpdcmain(argc, argv);
268ef64b99roberto}
269ef64b99roberto#endif
270ef64b99roberto
271ef64b99roberto#ifdef SYS_VXWORKS
272ef64b99robertovoid clear_globals(void)
273ef64b99roberto{
274ef64b99roberto    showhostnames = 0;              /* show host names by default */
275ef64b99roberto    havehost = 0;                   /* set to 1 when host open */
276ef64b99roberto    numcmds = 0;
277ef64b99roberto    numhosts = 0;
278ef64b99roberto}
279ef64b99roberto#endif
280ef64b99roberto
281ef64b99roberto/*
282ef64b99roberto * main - parse arguments and handle options
283ef64b99roberto */
284ef64b99robertoint
285ef64b99robertontpdcmain(
286ef64b99roberto	int argc,
287ef64b99roberto	char *argv[]
288ef64b99roberto	)
289ef64b99roberto{
290ef64b99roberto	delay_time.l_ui = 0;
291ef64b99roberto	delay_time.l_uf = DEFDELAY;
292ef64b99roberto
293ef64b99roberto#ifdef SYS_VXWORKS
294ef64b99roberto	clear_globals();
295ef64b99roberto	taskPrioritySet(taskIdSelf(), 100 );
296ef64b99roberto#endif
297ef64b99roberto
298d54cfbdroberto	init_lib();	/* sets up ipv4_works, ipv6_works */
299d54cfbdroberto	ssl_applink();
300047f369cy	init_auth();
301118e757roberto
302d54cfbdroberto	/* Check to see if we have IPv6. Otherwise default to IPv4 */
303d54cfbdroberto	if (!ipv6_works)
304118e757roberto		ai_fam_default = AF_INET;
305118e757roberto
306ef64b99roberto	progname = argv[0];
3077a6072eroberto
3087a6072eroberto	{
309d54cfbdroberto		int optct = ntpOptionProcess(&ntpdcOptions, argc, argv);
3107a6072eroberto		argc -= optct;
3117a6072eroberto		argv += optct;
3127a6072eroberto	}
3137a6072eroberto
314d54cfbdroberto	if (HAVE_OPT(IPV4))
315837c91fcy		ai_fam_default = AF_INET;
316d54cfbdroberto	else if (HAVE_OPT(IPV6))
317837c91fcy		ai_fam_default = AF_INET6;
318837c91fcy
319837c91fcy	ai_fam_templ = ai_fam_default;
3207a6072eroberto
3217a6072eroberto	if (HAVE_OPT(COMMAND)) {
3227a6072eroberto		int		cmdct = STACKCT_OPT( COMMAND );
3237a6072eroberto		const char**	cmds  = STACKLST_OPT( COMMAND );
3247a6072eroberto
3257a6072eroberto		while (cmdct-- > 0) {
3267a6072eroberto			ADDCMD(*cmds++);
3277a6072eroberto		}
3287a6072eroberto	}
3297a6072eroberto
330047f369cy	debug = OPT_VALUE_SET_DEBUG_LEVEL;
3317a6072eroberto
3327a6072eroberto	if (HAVE_OPT(INTERACTIVE)) {
3337a6072eroberto		interactive = 1;
3347a6072eroberto	}
3357a6072eroberto
3367a6072eroberto	if (HAVE_OPT(NUMERIC)) {
3377a6072eroberto		showhostnames = 0;
3387a6072eroberto	}
3397a6072eroberto
3407a6072eroberto	if (HAVE_OPT(LISTPEERS)) {
3417a6072eroberto		ADDCMD("listpeers");
3427a6072eroberto	}
3437a6072eroberto
3447a6072eroberto	if (HAVE_OPT(PEERS)) {
3457a6072eroberto		ADDCMD("peers");
3467a6072eroberto	}
3477a6072eroberto
3487a6072eroberto	if (HAVE_OPT(SHOWPEERS)) {
3497a6072eroberto		ADDCMD("dmpeers");
3507a6072eroberto	}
3517a6072eroberto
3527a6072eroberto	if (ntp_optind == argc) {
3537a6072eroberto		ADDHOST(DEFHOST);
3547a6072eroberto	} else {
3557a6072eroberto		for (; ntp_optind < argc; ntp_optind++)
3567a6072eroberto		    ADDHOST(argv[ntp_optind]);
3577a6072eroberto	}
3587a6072eroberto
3597a6072eroberto	if (numcmds == 0 && interactive == 0
3607a6072eroberto	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
3617a6072eroberto		interactive = 1;
3627a6072eroberto	}
3637a6072eroberto
364ef64b99roberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
365ef64b99roberto	if (interactive)
36675715b3delphij		(void) signal_no_reset(SIGINT, abortcmd);
367ef64b99roberto#endif /* SYS_WINNT */
368ef64b99roberto
369ef64b99roberto	/*
370ef64b99roberto	 * Initialize the packet data buffer
371ef64b99roberto	 */
372ef64b99roberto	pktdatasize = INITDATASIZE;
373d54cfbdroberto	pktdata = emalloc(INITDATASIZE);
374ef64b99roberto
375ef64b99roberto	if (numcmds == 0) {
376ef64b99roberto		(void) openhost(chosts[0]);
377ef64b99roberto		getcmds();
378ef64b99roberto	} else {
379ef64b99roberto		int ihost;
380ef64b99roberto		int icmd;
381ef64b99roberto
382ef64b99roberto		for (ihost = 0; ihost < numhosts; ihost++) {
383ef64b99roberto			if (openhost(chosts[ihost]))
384ef64b99roberto			    for (icmd = 0; icmd < numcmds; icmd++) {
385ef64b99roberto				    if (numhosts > 1)
386ef64b99roberto					printf ("--- %s ---\n",chosts[ihost]);
387ef64b99roberto				    docmd(ccmds[icmd]);
388ef64b99roberto			    }
389ef64b99roberto		}
390ef64b99roberto	}
391ef64b99roberto#ifdef SYS_WINNT
392ef64b99roberto	WSACleanup();
393ef64b99roberto#endif
394ef64b99roberto	return(0);
395ef64b99roberto} /* main end */
396ef64b99roberto
397ef64b99roberto
398ef64b99roberto/*
399ef64b99roberto * openhost - open a socket to a host
400ef64b99roberto */
401ef64b99robertostatic int
402ef64b99robertoopenhost(
403ef64b99roberto	const char *hname
404ef64b99roberto	)
405ef64b99roberto{
406ef64b99roberto	char temphost[LENHOSTNAME];
40775715b3delphij	int a_info;
408118e757roberto	struct addrinfo hints, *ai = NULL;
409047f369cy	sockaddr_u addr;
410047f369cy	size_t octets;
41175715b3delphij	const char *cp;
412118e757roberto	char name[LENHOSTNAME];
413118e757roberto	char service[5];
414ef64b99roberto
415118e757roberto	/*
416118e757roberto	 * We need to get by the [] if they were entered
417118e757roberto	 */
41875715b3delphij	if (*hname == '[') {
41975715b3delphij		cp = strchr(hname + 1, ']');
42075715b3delphij		if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) {
42175715b3delphij			errno = EINVAL;
42275715b3delphij			warning("%s", "bad hostname/address");
423d54cfbdroberto			return 0;
424d54cfbdroberto		}
42575715b3delphij		memcpy(name, hname + 1, octets);
42675715b3delphij		name[octets] = '\0';
42775715b3delphij		hname = name;
42875715b3delphij	}
429118e757roberto
430118e757roberto	/*
431118e757roberto	 * First try to resolve it as an ip address and if that fails,
432118e757roberto	 * do a fullblown (dns) lookup. That way we only use the dns
433118e757roberto	 * when it is needed and work around some implementations that
434118e757roberto	 * will return an "IPv4-mapped IPv6 address" address if you
435118e757roberto	 * give it an IPv4 address to lookup.
436118e757roberto	 */
437047f369cy	strlcpy(service, "ntp", sizeof(service));
438047f369cy	ZERO(hints);
439118e757roberto	hints.ai_family = ai_fam_templ;
440118e757roberto	hints.ai_protocol = IPPROTO_UDP;
441118e757roberto	hints.ai_socktype = SOCK_DGRAM;
442d54cfbdroberto	hints.ai_flags = Z_AI_NUMERICHOST;
443118e757roberto
444118e757roberto	a_info = getaddrinfo(hname, service, &hints, &ai);
4457a6072eroberto	if (a_info == EAI_NONAME
4467a6072eroberto#ifdef EAI_NODATA
4477a6072eroberto	    || a_info == EAI_NODATA
4487a6072eroberto#endif
4497a6072eroberto	   ) {
450118e757roberto		hints.ai_flags = AI_CANONNAME;
451118e757roberto#ifdef AI_ADDRCONFIG
452118e757roberto		hints.ai_flags |= AI_ADDRCONFIG;
453118e757roberto#endif
454118e757roberto		a_info = getaddrinfo(hname, service, &hints, &ai);
455118e757roberto	}
456118e757roberto	/* Some older implementations don't like AI_ADDRCONFIG. */
457118e757roberto	if (a_info == EAI_BADFLAGS) {
458118e757roberto		hints.ai_flags = AI_CANONNAME;
459118e757roberto		a_info = getaddrinfo(hname, service, &hints, &ai);
460118e757roberto	}
461118e757roberto	if (a_info != 0) {
462047f369cy		fprintf(stderr, "%s\n", gai_strerror(a_info));
4637a6072eroberto		if (ai != NULL)
4647a6072eroberto			freeaddrinfo(ai);
465118e757roberto		return 0;
466118e757roberto	}
467118e757roberto
468d54cfbdroberto	/*
469d54cfbdroberto	 * getaddrinfo() has returned without error so ai should not
470d54cfbdroberto	 * be NULL.
471d54cfbdroberto	 */
472047f369cy	INSIST(ai != NULL);
473047f369cy	ZERO(addr);
474047f369cy	octets = min(sizeof(addr), ai->ai_addrlen);
475047f369cy	memcpy(&addr, ai->ai_addr, octets);
476d54cfbdroberto
477047f369cy	if (ai->ai_canonname == NULL)
478047f369cy		strlcpy(temphost, stoa(&addr), sizeof(temphost));
479047f369cy	else
480047f369cy		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
481ef64b99roberto
482ef64b99roberto	if (debug > 2)
483047f369cy		printf("Opening host %s\n", temphost);
484ef64b99roberto
485ef64b99roberto	if (havehost == 1) {
486ef64b99roberto		if (debug > 2)
487047f369cy			printf("Closing old host %s\n", currenthost);
488047f369cy		closesocket(sockfd);
489ef64b99roberto		havehost = 0;
490ef64b99roberto	}
491047f369cy	strlcpy(currenthost, temphost, sizeof(currenthost));
492118e757roberto
493118e757roberto	/* port maps to the same in both families */
494047f369cy	s_port = NSRCPORT(&addr);;
495118e757roberto#ifdef SYS_VXWORKS
496118e757roberto	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
497118e757roberto	if (ai->ai_family == AF_INET)
498118e757roberto		*(struct sockaddr_in *)&hostaddr=
499118e757roberto			*((struct sockaddr_in *)ai->ai_addr);
500118e757roberto	else
501118e757roberto		*(struct sockaddr_in6 *)&hostaddr=
502118e757roberto			*((struct sockaddr_in6 *)ai->ai_addr);
503118e757roberto#endif /* SYS_VXWORKS */
504ef64b99roberto
505ef64b99roberto#ifdef SYS_WINNT
506ef64b99roberto	{
507ef64b99roberto		int optionValue = SO_SYNCHRONOUS_NONALERT;
508ef64b99roberto		int err;
5097a6072eroberto
51030f4731delphij		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (void *)&optionValue, sizeof(optionValue));
511ef64b99roberto		if (err != NO_ERROR) {
512ef64b99roberto			(void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
513ef64b99roberto			exit(1);
514ef64b99roberto		}
515ef64b99roberto	}
516047f369cy#endif /* SYS_WINNT */
517118e757roberto
518118e757roberto	sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
519ef64b99roberto	if (sockfd == INVALID_SOCKET) {
520bdc155dcy		error("socket");
521ef64b99roberto		exit(-1);
522ef64b99roberto	}
523ef64b99roberto
524ef64b99roberto#ifdef NEED_RCVBUF_SLOP
525ef64b99roberto# ifdef SO_RCVBUF
526ef64b99roberto	{
527ef64b99roberto		int rbufsize = INITDATASIZE + 2048; /* 2K for slop */
528ef64b99roberto
529ef64b99roberto		if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
53030f4731delphij			       (void *)&rbufsize, sizeof(int)) == -1)
531bdc155dcy		    error("setsockopt");
532ef64b99roberto	}
533ef64b99roberto# endif
534ef64b99roberto#endif
535ef64b99roberto
536118e757roberto#ifdef SYS_VXWORKS
537118e757roberto	if (connect(sockfd, (struct sockaddr *)&hostaddr,
5388518518delphij		    sizeof(hostaddr)) == -1)
539118e757roberto#else
5408518518delphij	if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1)
541118e757roberto#endif /* SYS_VXWORKS */
5428518518delphij	{
543bdc155dcy		error("connect");
544047f369cy		exit(-1);
545047f369cy	}
546d54cfbdroberto
547d54cfbdroberto	freeaddrinfo(ai);
548ef64b99roberto	havehost = 1;
549f771469roberto	req_pkt_size = REQ_LEN_NOMAC;
550118e757roberto	impl_ver = IMPL_XNTPD;
551ef64b99roberto	return 1;
552ef64b99roberto}
553ef64b99roberto
554ef64b99roberto
555ef64b99roberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
556ef64b99roberto/*
557ef64b99roberto * sendpkt - send a packet to the remote host
558ef64b99roberto */
559ef64b99robertostatic int
560ef64b99robertosendpkt(
561d54cfbdroberto	void *	xdata,
562d54cfbdroberto	size_t	xdatalen
563ef64b99roberto	)
564ef64b99roberto{
565d54cfbdroberto	if (send(sockfd, xdata, xdatalen, 0) == -1) {
566bdc155dcy		warning("write to %s failed", currenthost);
567ef64b99roberto		return -1;
568ef64b99roberto	}
569ef64b99roberto
570ef64b99roberto	return 0;
571ef64b99roberto}
572ef64b99roberto
573ef64b99roberto
574ef64b99roberto/*
575ef64b99roberto * growpktdata - grow the packet data area
576ef64b99roberto */
577ef64b99robertostatic void
578ef64b99robertogrowpktdata(void)
579ef64b99roberto{
580047f369cy	size_t priorsz;
581047f369cy
582047f369cy	priorsz = (size_t)pktdatasize;
583ef64b99roberto	pktdatasize += INCDATASIZE;
584047f369cy	pktdata = erealloc_zero(pktdata, (size_t)pktdatasize, priorsz);
585ef64b99roberto}
586ef64b99roberto
587ef64b99roberto
588ef64b99roberto/*
589ef64b99roberto * getresponse - get a (series of) response packet(s) and return the data
590ef64b99roberto */
591ef64b99robertostatic int
592ef64b99robertogetresponse(
593ef64b99roberto	int implcode,
594ef64b99roberto	int reqcode,
5958518518delphij	size_t *ritems,
5968518518delphij	size_t *rsize,
5978518518delphij	const char **rdata,
5988518518delphij	size_t esize
599ef64b99roberto	)
600ef64b99roberto{
601ef64b99roberto	struct resp_pkt rpkt;
602d54cfbdroberto	struct sock_timeval tvo;
6038518518delphij	size_t items;
6048518518delphij	size_t i;
6058518518delphij	size_t size;
6068518518delphij	size_t datasize;
607ef64b99roberto	char *datap;
608118e757roberto	char *tmp_data;
609ef64b99roberto	char haveseq[MAXSEQ+1];
610ef64b99roberto	int firstpkt;
611ef64b99roberto	int lastseq;
612ef64b99roberto	int numrecv;
613ef64b99roberto	int seq;
614ef64b99roberto	fd_set fds;
615bdc155dcy	ssize_t n;
616a835b8fdelphij	int pad;
617a835b8fdelphij	/* absolute timeout checks. Not 'time_t' by intention! */
618a835b8fdelphij	uint32_t tobase;	/* base value for timeout */
619a835b8fdelphij	uint32_t tospan;	/* timeout span (max delay) */
620a835b8fdelphij	uint32_t todiff;	/* current delay */
621ef64b99roberto
622ef64b99roberto	/*
623ef64b99roberto	 * This is pretty tricky.  We may get between 1 and many packets
624ef64b99roberto	 * back in response to the request.  We peel the data out of
625ef64b99roberto	 * each packet and collect it in one long block.  When the last
626ef64b99roberto	 * packet in the sequence is received we'll know how many we
627ef64b99roberto	 * should have had.  Note we use one long time out, should reconsider.
628ef64b99roberto	 */
629ef64b99roberto	*ritems = 0;
630ef64b99roberto	*rsize = 0;
631ef64b99roberto	firstpkt = 1;
632ef64b99roberto	numrecv = 0;
633ef64b99roberto	*rdata = datap = pktdata;
634ef64b99roberto	lastseq = 999;	/* too big to be a sequence number */
635047f369cy	ZERO(haveseq);
636ef64b99roberto	FD_ZERO(&fds);
637a835b8fdelphij	tobase = (uint32_t)time(NULL);
638ef64b99roberto
639ef64b99roberto    again:
640ef64b99roberto	if (firstpkt)
641d54cfbdroberto		tvo = tvout;
642ef64b99roberto	else
643d54cfbdroberto		tvo = tvsout;
644a835b8fdelphij	tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0);
645ef64b99roberto
646ef64b99roberto	FD_SET(sockfd, &fds);
6478518518delphij	n = select(sockfd+1, &fds, NULL, NULL, &tvo);
648ef64b99roberto	if (n == -1) {
649bdc155dcy		warning("select fails");
650ef64b99roberto		return -1;
651ef64b99roberto	}
652a835b8fdelphij
653a835b8fdelphij	/*
654a835b8fdelphij	 * Check if this is already too late. Trash the data and fake a
655a835b8fdelphij	 * timeout if this is so.
656a835b8fdelphij	 */
657a835b8fdelphij	todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu;
658a835b8fdelphij	if ((n > 0) && (todiff > tospan)) {
659a835b8fdelphij		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
6607058597delphij		n -= n; /* faked timeout return from 'select()'*/
661a835b8fdelphij	}
662a835b8fdelphij
663ef64b99roberto	if (n == 0) {
664ef64b99roberto		/*
665ef64b99roberto		 * Timed out.  Return what we have
666ef64b99roberto		 */
667ef64b99roberto		if (firstpkt) {
668ef64b99roberto			(void) fprintf(stderr,
6698518518delphij				       "%s: timed out, nothing received\n",
6708518518delphij				       currenthost);
671ef64b99roberto			return ERR_TIMEOUT;
672ef64b99roberto		} else {
673ef64b99roberto			(void) fprintf(stderr,
674ef64b99roberto				       "%s: timed out with incomplete data\n",
675ef64b99roberto				       currenthost);
676ef64b99roberto			if (debug) {
677ef64b99roberto				printf("Received sequence numbers");
678ef64b99roberto				for (n = 0; n <= MAXSEQ; n++)
679ef64b99roberto				    if (haveseq[n])
6805a3cfd0delphij					printf(" %zd,", (size_t)n);
681ef64b99roberto				if (lastseq != 999)
682ef64b99roberto				    printf(" last frame received\n");
683ef64b99roberto				else
684ef64b99roberto				    printf(" last frame not received\n");
685ef64b99roberto			}
686ef64b99roberto			return ERR_INCOMPLETE;
687ef64b99roberto		}
688ef64b99roberto	}
689ef64b99roberto
690ef64b99roberto	n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
691ef64b99roberto	if (n == -1) {
692bdc155dcy		warning("read");
693ef64b99roberto		return -1;
694ef64b99roberto	}
695ef64b99roberto
696ef64b99roberto
697ef64b99roberto	/*
698ef64b99roberto	 * Check for format errors.  Bug proofing.
699ef64b99roberto	 */
700bdc155dcy	if (n < (ssize_t)RESP_HEADER_SIZE) {
701ef64b99roberto		if (debug)
7025a3cfd0delphij			printf("Short (%zd byte) packet received\n", (size_t)n);
703ef64b99roberto		goto again;
704ef64b99roberto	}
705ef64b99roberto	if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION ||
706ef64b99roberto	    INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) {
707ef64b99roberto		if (debug)
708047f369cy			printf("Packet received with version %d\n",
709047f369cy			       INFO_VERSION(rpkt.rm_vn_mode));
710ef64b99roberto		goto again;
711ef64b99roberto	}
712ef64b99roberto	if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) {
713ef64b99roberto		if (debug)
714047f369cy			printf("Packet received with mode %d\n",
715047f369cy			       INFO_MODE(rpkt.rm_vn_mode));
716ef64b99roberto		goto again;
717ef64b99roberto	}
718ef64b99roberto	if (INFO_IS_AUTH(rpkt.auth_seq)) {
719ef64b99roberto		if (debug)
720047f369cy			printf("Encrypted packet received\n");
721ef64b99roberto		goto again;
722ef64b99roberto	}
723ef64b99roberto	if (!ISRESPONSE(rpkt.rm_vn_mode)) {
724ef64b99roberto		if (debug)
725047f369cy			printf("Received request packet, wanted response\n");
726ef64b99roberto		goto again;
727ef64b99roberto	}
728ef64b99roberto	if (INFO_MBZ(rpkt.mbz_itemsize) != 0) {
729ef64b99roberto		if (debug)
730047f369cy			printf("Received packet with nonzero MBZ field!\n");
731ef64b99roberto		goto again;
732ef64b99roberto	}
733ef64b99roberto
734ef64b99roberto	/*
735ef64b99roberto	 * Check implementation/request.  Could be old data getting to us.
736ef64b99roberto	 */
737ef64b99roberto	if (rpkt.implementation != implcode || rpkt.request != reqcode) {
738ef64b99roberto		if (debug)
739047f369cy			printf(
740ef64b99roberto			    "Received implementation/request of %d/%d, wanted %d/%d",
741ef64b99roberto			    rpkt.implementation, rpkt.request,
742ef64b99roberto			    implcode, reqcode);
743ef64b99roberto		goto again;
744ef64b99roberto	}
745ef64b99roberto
746ef64b99roberto	/*
747ef64b99roberto	 * Check the error code.  If non-zero, return it.
748ef64b99roberto	 */
749ef64b99roberto	if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) {
750ef64b99roberto		if (debug && ISMORE(rpkt.rm_vn_mode)) {
751ef64b99roberto			printf("Error code %d received on not-final packet\n",
752ef64b99roberto			       INFO_ERR(rpkt.err_nitems));
753ef64b99roberto		}
754ef64b99roberto		return (int)INFO_ERR(rpkt.err_nitems);
755ef64b99roberto	}
756ef64b99roberto
757ef64b99roberto	/*
758ef64b99roberto	 * Collect items and size.  Make sure they make sense.
759ef64b99roberto	 */
760ef64b99roberto	items = INFO_NITEMS(rpkt.err_nitems);
761ef64b99roberto	size = INFO_ITEMSIZE(rpkt.mbz_itemsize);
762118e757roberto	if (esize > size)
763118e757roberto		pad = esize - size;
764118e757roberto	else
765118e757roberto		pad = 0;
766d54cfbdroberto	datasize = items * size;
767d54cfbdroberto	if ((size_t)datasize > (n-RESP_HEADER_SIZE)) {
768ef64b99roberto		if (debug)
769ef64b99roberto		    printf(
7708518518delphij			    "Received items %zu, size %zu (total %zu), data in packet is %zu\n",
771bdc155dcy			    items, size, datasize, n-RESP_HEADER_SIZE);
772ef64b99roberto		goto again;
773ef64b99roberto	}
774ef64b99roberto
775ef64b99roberto	/*
776ef64b99roberto	 * If this isn't our first packet, make sure the size matches
777ef64b99roberto	 * the other ones.
778ef64b99roberto	 */
779047f369cy	if (!firstpkt && size != *rsize) {
780ef64b99roberto		if (debug)
7818518518delphij		    printf("Received itemsize %zu, previous %zu\n",
782ef64b99roberto			   size, *rsize);
783ef64b99roberto		goto again;
784ef64b99roberto	}
785ef64b99roberto	/*
786118e757roberto	 * If we've received this before, +toss it
787ef64b99roberto	 */
788ef64b99roberto	seq = INFO_SEQ(rpkt.auth_seq);
789ef64b99roberto	if (haveseq[seq]) {
790ef64b99roberto		if (debug)
791ef64b99roberto		    printf("Received duplicate sequence number %d\n", seq);
792ef64b99roberto		goto again;
793ef64b99roberto	}
794ef64b99roberto	haveseq[seq] = 1;
795ef64b99roberto
796ef64b99roberto	/*
797ef64b99roberto	 * If this is the last in the sequence, record that.
798ef64b99roberto	 */
799ef64b99roberto	if (!ISMORE(rpkt.rm_vn_mode)) {
800ef64b99roberto		if (lastseq != 999) {
801ef64b99roberto			printf("Received second end sequence packet\n");
802ef64b99roberto			goto again;
803ef64b99roberto		}
804ef64b99roberto		lastseq = seq;
805ef64b99roberto	}
806ef64b99roberto
807ef64b99roberto	/*
808a835b8fdelphij	 * So far, so good.  Copy this data into the output array. Bump
809a835b8fdelphij	 * the timeout base, in case we expect more data.
810ef64b99roberto	 */
811a835b8fdelphij	tobase = (uint32_t)time(NULL);
812118e757roberto	if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
8138518518delphij		size_t offset = datap - pktdata;
814ef64b99roberto		growpktdata();
815d54cfbdroberto		*rdata = pktdata; /* might have been realloced ! */
816ef64b99roberto		datap = pktdata + offset;
817ef64b99roberto	}
818118e757roberto	/*
819118e757roberto	 * We now move the pointer along according to size and number of
820118e757roberto	 * items.  This is so we can play nice with older implementations
821118e757roberto	 */
822118e757roberto
823047f369cy	tmp_data = rpkt.u.data;
824d54cfbdroberto	for (i = 0; i < items; i++) {
825d54cfbdroberto		memcpy(datap, tmp_data, (unsigned)size);
826118e757roberto		tmp_data += size;
827047f369cy		zero_mem(datap + size, pad);
828118e757roberto		datap += size + pad;
829118e757roberto	}
830118e757roberto
831ef64b99roberto	if (firstpkt) {
832ef64b99roberto		firstpkt = 0;
833118e757roberto		*rsize = size + pad;
834ef64b99roberto	}
835ef64b99roberto	*ritems += items;
836ef64b99roberto
837ef64b99roberto	/*
838ef64b99roberto	 * Finally, check the count of received packets.  If we've got them
839ef64b99roberto	 * all, return
840ef64b99roberto	 */
841ef64b99roberto	++numrecv;
842ef64b99roberto	if (numrecv <= lastseq)
843d54cfbdroberto		goto again;
844ef64b99roberto	return INFO_OKAY;
845ef64b99roberto}
846ef64b99roberto
847ef64b99roberto
848ef64b99roberto/*
849ef64b99roberto * sendrequest - format and send a request packet
850d54cfbdroberto *
851d54cfbdroberto * Historically, ntpdc has used a fixed-size request packet regardless
852d54cfbdroberto * of the actual payload size.  When authenticating, the timestamp, key
853d54cfbdroberto * ID, and digest have been placed just before the end of the packet.
854d54cfbdroberto * With the introduction in late 2009 of support for authenticated
855d54cfbdroberto * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
856d54cfbdroberto * come up four bytes short.
857d54cfbdroberto *
858d54cfbdroberto * To maintain interop while allowing for larger digests, the behavior
859d54cfbdroberto * is unchanged when using 16-octet digests.  For larger digests, the
860d54cfbdroberto * timestamp, key ID, and digest are placed immediately following the
861d54cfbdroberto * request payload, with the overall packet size variable.  ntpd can
862d54cfbdroberto * distinguish 16-octet digests by the overall request size being
863d54cfbdroberto * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled.  When using a
864d54cfbdroberto * longer digest, that request size should be avoided.
865d54cfbdroberto *
866d54cfbdroberto * With the form used with 20-octet and larger digests, the timestamp,
867d54cfbdroberto * key ID, and digest are located by ntpd relative to the start of the
868d54cfbdroberto * packet, and the size of the digest is then implied by the packet
869d54cfbdroberto * size.
870ef64b99roberto */
871ef64b99robertostatic int
872ef64b99robertosendrequest(
873ef64b99roberto	int implcode,
874ef64b99roberto	int reqcode,
875ef64b99roberto	int auth,
8768518518delphij	size_t qitems,
877d54cfbdroberto	size_t qsize,
8788518518delphij	const char *qdata
879ef64b99roberto	)
880ef64b99roberto{
881ef64b99roberto	struct req_pkt qpkt;
882d54cfbdroberto	size_t	datasize;
883d54cfbdroberto	size_t	reqsize;
884d54cfbdroberto	u_long	key_id;
885d54cfbdroberto	l_fp	ts;
886d54cfbdroberto	l_fp *	ptstamp;
8878518518delphij	size_t	maclen;
888d54cfbdroberto	char *	pass;
889ef64b99roberto
890047f369cy	ZERO(qpkt);
891ef64b99roberto	qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
892ef64b99roberto	qpkt.implementation = (u_char)implcode;
893ef64b99roberto	qpkt.request = (u_char)reqcode;
894ef64b99roberto
895ef64b99roberto	datasize = qitems * qsize;
896d54cfbdroberto	if (datasize && qdata != NULL) {
897047f369cy		memcpy(qpkt.u.data, qdata, datasize);
898ef64b99roberto		qpkt.err_nitems = ERR_NITEMS(0, qitems);
899ef64b99roberto		qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
900ef64b99roberto	} else {
901ef64b99roberto		qpkt.err_nitems = ERR_NITEMS(0, 0);
9027a6072eroberto		qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);  /* allow for optional first item */
903ef64b99roberto	}
904ef64b99roberto
9057a6072eroberto	if (!auth || (keyid_entered && info_auth_keyid == 0)) {
906ef64b99roberto		qpkt.auth_seq = AUTH_SEQ(0, 0);
907d54cfbdroberto		return sendpkt(&qpkt, req_pkt_size);
908d54cfbdroberto	}
909ef64b99roberto
910d54cfbdroberto	if (info_auth_keyid == 0) {
911d54cfbdroberto		key_id = getkeyid("Keyid: ");
912d54cfbdroberto		if (!key_id) {
913d54cfbdroberto			fprintf(stderr, "Invalid key identifier\n");
914d54cfbdroberto			return 1;
915ef64b99roberto		}
916d54cfbdroberto		info_auth_keyid = key_id;
917d54cfbdroberto	}
918d54cfbdroberto	if (!authistrusted(info_auth_keyid)) {
919d54cfbdroberto		pass = getpass_keytype(info_auth_keytype);
920d54cfbdroberto		if ('\0' == pass[0]) {
921d54cfbdroberto			fprintf(stderr, "Invalid password\n");
922d54cfbdroberto			return 1;
923ef64b99roberto		}
924d54cfbdroberto		authusekey(info_auth_keyid, info_auth_keytype,
925d54cfbdroberto			   (u_char *)pass);
926ef64b99roberto		authtrust(info_auth_keyid, 1);
927ef64b99roberto	}
928d54cfbdroberto	qpkt.auth_seq = AUTH_SEQ(1, 0);
929d54cfbdroberto	if (info_auth_hashlen > 16) {
930d54cfbdroberto		/*
931d54cfbdroberto		 * Only ntpd which expects REQ_LEN_NOMAC plus maclen
932d54cfbdroberto		 * octets in an authenticated request using a 16 octet
933d54cfbdroberto		 * digest (that is, a newer ntpd) will handle digests
934d54cfbdroberto		 * larger than 16 octets, so for longer digests, do
935d54cfbdroberto		 * not attempt to shorten the requests for downlevel
936d54cfbdroberto		 * ntpd compatibility.
937d54cfbdroberto		 */
938d54cfbdroberto		if (REQ_LEN_NOMAC != req_pkt_size)
939d54cfbdroberto			return 1;
940d54cfbdroberto		reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp);
941d54cfbdroberto		/* align to 32 bits */
942d54cfbdroberto		reqsize = (reqsize + 3) & ~3;
943d54cfbdroberto	} else
944d54cfbdroberto		reqsize = req_pkt_size;
945d54cfbdroberto	ptstamp = (void *)((char *)&qpkt + reqsize);
946d54cfbdroberto	ptstamp--;
947d54cfbdroberto	get_systime(&ts);
948d54cfbdroberto	L_ADD(&ts, &delay_time);
949d54cfbdroberto	HTONL_FP(&ts, ptstamp);
9508518518delphij	maclen = authencrypt(
9518518518delphij		info_auth_keyid, (void *)&qpkt, size2int_chk(reqsize));
952d54cfbdroberto	if (!maclen) {
953d54cfbdroberto		fprintf(stderr, "Key not found\n");
954d54cfbdroberto		return 1;
95575715b3delphij	} else if (maclen != (size_t)(info_auth_hashlen + sizeof(keyid_t))) {
956d54cfbdroberto		fprintf(stderr,
9578518518delphij			"%zu octet MAC, %zu expected with %zu octet digest\n",
958bdc155dcy			maclen, (info_auth_hashlen + sizeof(keyid_t)),
959bdc155dcy			info_auth_hashlen);
960d54cfbdroberto		return 1;
961d54cfbdroberto	}
962d54cfbdroberto	return sendpkt(&qpkt, reqsize + maclen);
963ef64b99roberto}
964ef64b99roberto
965ef64b99roberto
966ef64b99roberto/*
967ef64b99roberto * doquery - send a request and process the response
968ef64b99roberto */
969ef64b99robertoint
970ef64b99robertodoquery(
971ef64b99roberto	int implcode,
972ef64b99roberto	int reqcode,
973ef64b99roberto	int auth,
9748518518delphij	size_t qitems,
9758518518delphij	size_t qsize,
9768518518delphij	const char *qdata,
9778518518delphij	size_t *ritems,
9788518518delphij	size_t *rsize,
9798518518delphij	const char **rdata,
980118e757roberto 	int quiet_mask,
981118e757roberto	int esize
982ef64b99roberto	)
983ef64b99roberto{
984ef64b99roberto	int res;
985ef64b99roberto	char junk[512];
986ef64b99roberto	fd_set fds;
987d54cfbdroberto	struct sock_timeval tvzero;
988ef64b99roberto
989ef64b99roberto	/*
990ef64b99roberto	 * Check to make sure host is open
991ef64b99roberto	 */
992ef64b99roberto	if (!havehost) {
993ef64b99roberto		(void) fprintf(stderr, "***No host open, use `host' command\n");
994ef64b99roberto		return -1;
995ef64b99roberto	}
996ef64b99roberto
997ef64b99roberto	/*
998ef64b99roberto	 * Poll the socket and clear out any pending data
999ef64b99roberto	 */
1000f771469robertoagain:
1001ef64b99roberto	do {
1002ef64b99roberto		tvzero.tv_sec = tvzero.tv_usec = 0;
1003ef64b99roberto		FD_ZERO(&fds);
1004ef64b99roberto		FD_SET(sockfd, &fds);
10058518518delphij		res = select(sockfd+1, &fds, NULL, NULL, &tvzero);
1006ef64b99roberto		if (res == -1) {
1007bdc155dcy			warning("polling select");
1008ef64b99roberto			return -1;
1009ef64b99roberto		} else if (res > 0)
1010ef64b99roberto
1011ef64b99roberto		    (void) recv(sockfd, junk, sizeof junk, 0);
1012ef64b99roberto	} while (res > 0);
1013ef64b99roberto
1014ef64b99roberto
1015ef64b99roberto	/*
1016ef64b99roberto	 * send a request
1017ef64b99roberto	 */
1018ef64b99roberto	res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
1019ef64b99roberto	if (res != 0)
1020d54cfbdroberto		return res;
1021ef64b99roberto
1022ef64b99roberto	/*
1023ef64b99roberto	 * Get the response.  If we got a standard error, print a message
1024ef64b99roberto	 */
1025118e757roberto	res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize);
1026ef64b99roberto
1027f771469roberto	/*
1028f771469roberto	 * Try to be compatible with older implementations of ntpd.
1029f771469roberto	 */
1030f771469roberto	if (res == INFO_ERR_FMT && req_pkt_size != 48) {
1031f771469roberto		int oldsize;
1032f771469roberto
1033f771469roberto		oldsize = req_pkt_size;
1034f771469roberto
1035f771469roberto		switch(req_pkt_size) {
1036f771469roberto		case REQ_LEN_NOMAC:
1037118e757roberto			req_pkt_size = 160;
1038118e757roberto			break;
1039118e757roberto		case 160:
1040f771469roberto			req_pkt_size = 48;
1041f771469roberto			break;
1042f771469roberto		}
1043118e757roberto		if (impl_ver == IMPL_XNTPD) {
1044118e757roberto			fprintf(stderr,
1045118e757roberto			    "***Warning changing to older implementation\n");
1046118e757roberto			return INFO_ERR_IMPL;
1047118e757roberto		}
1048f771469roberto
1049f771469roberto		fprintf(stderr,
1050f771469roberto		    "***Warning changing the request packet size from %d to %d\n",
1051f771469roberto		    oldsize, req_pkt_size);
1052f771469roberto		goto again;
1053f771469roberto	}
1054f771469roberto
1055ef64b99roberto 	/* log error message if not told to be quiet */
1056ef64b99roberto 	if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
1057ef64b99roberto		switch(res) {
1058d54cfbdroberto		case INFO_ERR_IMPL:
1059118e757roberto			/* Give us a chance to try the older implementation. */
1060118e757roberto			if (implcode == IMPL_XNTPD)
1061118e757roberto				break;
1062ef64b99roberto			(void) fprintf(stderr,
1063047f369cy				       "***Server implementation incompatible with our own\n");
1064ef64b99roberto			break;
1065d54cfbdroberto		case INFO_ERR_REQ:
1066ef64b99roberto			(void) fprintf(stderr,
1067ef64b99roberto				       "***Server doesn't implement this request\n");
1068ef64b99roberto			break;
1069d54cfbdroberto		case INFO_ERR_FMT:
1070ef64b99roberto			(void) fprintf(stderr,
1071ef64b99roberto				       "***Server reports a format error in the received packet (shouldn't happen)\n");
1072ef64b99roberto			break;
1073d54cfbdroberto		case INFO_ERR_NODATA:
1074ef64b99roberto			(void) fprintf(stderr,
1075ef64b99roberto				       "***Server reports data not found\n");
1076ef64b99roberto			break;
1077d54cfbdroberto		case INFO_ERR_AUTH:
1078ef64b99roberto			(void) fprintf(stderr, "***Permission denied\n");
1079ef64b99roberto			break;
1080d54cfbdroberto		case ERR_TIMEOUT:
1081ef64b99roberto			(void) fprintf(stderr, "***Request timed out\n");
1082ef64b99roberto			break;
1083d54cfbdroberto		case ERR_INCOMPLETE:
1084ef64b99roberto			(void) fprintf(stderr,
1085ef64b99roberto				       "***Response from server was incomplete\n");
1086ef64b99roberto			break;
1087d54cfbdroberto		default:
1088ef64b99roberto			(void) fprintf(stderr,
1089ef64b99roberto				       "***Server returns unknown error code %d\n", res);
1090ef64b99roberto			break;
1091ef64b99roberto		}
1092ef64b99roberto	}
1093ef64b99roberto	return res;
1094ef64b99roberto}
1095ef64b99roberto
1096ef64b99roberto
1097ef64b99roberto/*
1098ef64b99roberto * getcmds - read commands from the standard input and execute them
1099ef64b99roberto */
1100ef64b99robertostatic void
1101ef64b99robertogetcmds(void)
1102ef64b99roberto{
1103d54cfbdroberto	char *	line;
1104d54cfbdroberto	int	count;
1105d54cfbdroberto
1106d54cfbdroberto	ntp_readline_init(interactive ? prompt : NULL);
110740b8e41roberto
110840b8e41roberto	for (;;) {
1109d54cfbdroberto		line = ntp_readline(&count);
1110d54cfbdroberto		if (NULL == line)
1111d54cfbdroberto			break;
111240b8e41roberto		docmd(line);
111340b8e41roberto		free(line);
111440b8e41roberto	}
1115ef64b99roberto
1116d54cfbdroberto	ntp_readline_uninit();
1117ef64b99roberto}
1118ef64b99roberto
1119ef64b99roberto
1120118e757roberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1121ef64b99roberto/*
1122ef64b99roberto * abortcmd - catch interrupts and abort the current command
1123ef64b99roberto */
1124ef64b99robertostatic RETSIGTYPE
1125ef64b99robertoabortcmd(
1126ef64b99roberto	int sig
1127ef64b99roberto	)
1128ef64b99roberto{
1129ef64b99roberto	if (current_output == stdout)
113075715b3delphij		(void)fflush(stdout);
1131ef64b99roberto	putc('\n', stderr);
113275715b3delphij	(void)fflush(stderr);
113375715b3delphij	if (jump) {
113475715b3delphij		jump = 0;
113575715b3delphij		LONGJMP(interrupt_buf, 1);
113675715b3delphij	}
1137ef64b99roberto}
1138118e757roberto#endif /* SYS_WINNT */
1139ef64b99roberto
1140ef64b99roberto/*
1141ef64b99roberto * docmd - decode the command line and execute a command
1142ef64b99roberto */
1143ef64b99robertostatic void
1144ef64b99robertodocmd(
1145ef64b99roberto	const char *cmdline
1146ef64b99roberto	)
1147ef64b99roberto{
11487a6072eroberto	char *tokens[1+MAXARGS+MOREARGS+2];
1149ef64b99roberto	struct parse pcmd;
1150ef64b99roberto	int ntok;
1151118e757roberto	int i, ti;
1152118e757roberto	int rval;
1153ef64b99roberto	struct xcmd *xcmd;
1154ef64b99roberto
1155118e757roberto	ai_fam_templ = ai_fam_default;
1156ef64b99roberto	/*
1157ef64b99roberto	 * Tokenize the command line.  If nothing on it, return.
1158ef64b99roberto	 */
1159047f369cy	if (strlen(cmdline) >= MAXLINE) {
1160047f369cy		fprintf(stderr, "***Command ignored, more than %d characters:\n%s\n",
1161047f369cy			MAXLINE - 1, cmdline);
1162047f369cy		return;
1163047f369cy	}
1164ef64b99roberto	tokenize(cmdline, tokens, &ntok);
1165ef64b99roberto	if (ntok == 0)
1166ef64b99roberto	    return;
1167ef64b99roberto
1168ef64b99roberto	/*
1169ef64b99roberto	 * Find the appropriate command description.
1170ef64b99roberto	 */
1171ef64b99roberto	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1172ef64b99roberto	if (i == 0) {
1173ef64b99roberto		(void) fprintf(stderr, "***Command `%s' unknown\n",
1174ef64b99roberto			       tokens[0]);
1175ef64b99roberto		return;
1176ef64b99roberto	} else if (i >= 2) {
1177ef64b99roberto		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1178ef64b99roberto			       tokens[0]);
1179ef64b99roberto		return;
1180ef64b99roberto	}
1181ef64b99roberto
1182ef64b99roberto	/*
1183ef64b99roberto	 * Save the keyword, then walk through the arguments, interpreting
1184ef64b99roberto	 * as we go.
1185ef64b99roberto	 */
1186ef64b99roberto	pcmd.keyword = tokens[0];
1187ef64b99roberto	pcmd.nargs = 0;
1188118e757roberto	ti = 1;
1189118e757roberto	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) {
1190118e757roberto		if ((i+ti) >= ntok) {
1191ef64b99roberto			if (!(xcmd->arg[i] & OPT)) {
1192ef64b99roberto				printusage(xcmd, stderr);
1193ef64b99roberto				return;
1194ef64b99roberto			}
1195ef64b99roberto			break;
1196ef64b99roberto		}
1197118e757roberto		if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>'))
1198118e757roberto			break;
1199118e757roberto		rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]);
1200118e757roberto		if (rval == -1) {
1201118e757roberto			ti++;
1202118e757roberto			continue;
1203118e757roberto		}
1204118e757roberto		if (rval == 0)
1205118e757roberto			return;
1206ef64b99roberto		pcmd.nargs++;
1207118e757roberto		i++;
1208ef64b99roberto	}
1209ef64b99roberto
12107a6072eroberto	/* Any extra args are assumed to be "OPT|NTP_STR". */
12117a6072eroberto	for ( ; i < MAXARGS + MOREARGS;) {
12127a6072eroberto	     if ((i+ti) >= ntok)
12137a6072eroberto		  break;
12147a6072eroberto		rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]);
12157a6072eroberto		if (rval == -1) {
12167a6072eroberto			ti++;
12177a6072eroberto			continue;
12187a6072eroberto		}
12197a6072eroberto		if (rval == 0)
12207a6072eroberto			return;
12217a6072eroberto		pcmd.nargs++;
12227a6072eroberto		i++;
12237a6072eroberto	}
12247a6072eroberto
1225118e757roberto	i += ti;
1226ef64b99roberto	if (i < ntok && *tokens[i] == '>') {
1227ef64b99roberto		char *fname;
1228ef64b99roberto
1229ef64b99roberto		if (*(tokens[i]+1) != '\0')
1230ef64b99roberto		    fname = tokens[i]+1;
1231ef64b99roberto		else if ((i+1) < ntok)
1232ef64b99roberto		    fname = tokens[i+1];
1233ef64b99roberto		else {
1234ef64b99roberto			(void) fprintf(stderr, "***No file for redirect\n");
1235ef64b99roberto			return;
1236ef64b99roberto		}
1237ef64b99roberto
1238ef64b99roberto		current_output = fopen(fname, "w");
1239ef64b99roberto		if (current_output == NULL) {
1240ef64b99roberto			(void) fprintf(stderr, "***Error opening %s: ", fname);
1241ef64b99roberto			perror("");
1242ef64b99roberto			return;
1243ef64b99roberto		}
1244ef64b99roberto	} else {
1245ef64b99roberto		current_output = stdout;
1246ef64b99roberto	}
1247ef64b99roberto
124875715b3delphij	if (interactive) {
124975715b3delphij		if ( ! SETJMP(interrupt_buf)) {
125075715b3delphij			jump = 1;
125175715b3delphij			(xcmd->handler)(&pcmd, current_output);
125275715b3delphij			jump = 0;
125375715b3delphij		} else {
125475715b3delphij			fflush(current_output);
125575715b3delphij			fputs("\n >>> command aborted <<<\n", stderr);
125675715b3delphij			fflush(stderr);
125775715b3delphij		}
1258ef64b99roberto	} else {
1259ef64b99roberto		jump = 0;
126075715b3delphij		(xcmd->handler)(&pcmd, current_output);
126175715b3delphij	}
126275715b3delphij	if ((NULL != current_output) && (stdout != current_output)) {
126375715b3delphij		(void)fclose(current_output);
1264118e757roberto		current_output = NULL;
1265ef64b99roberto	}
1266ef64b99roberto}
1267ef64b99roberto
1268ef64b99roberto
1269ef64b99roberto/*
1270ef64b99roberto * tokenize - turn a command line into tokens
1271ef64b99roberto */
1272ef64b99robertostatic void
1273ef64b99robertotokenize(
1274ef64b99roberto	const char *line,
1275ef64b99roberto	char **tokens,
1276ef64b99roberto	int *ntok
1277ef64b99roberto	)
1278ef64b99roberto{
1279ef64b99roberto	register const char *cp;
1280ef64b99roberto	register char *sp;
1281ef64b99roberto	static char tspace[MAXLINE];
1282ef64b99roberto
1283ef64b99roberto	sp = tspace;
1284ef64b99roberto	cp = line;
1285ef64b99roberto	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1286ef64b99roberto		tokens[*ntok] = sp;
1287ef64b99roberto		while (ISSPACE(*cp))
1288ef64b99roberto		    cp++;
1289ef64b99roberto		if (ISEOL(*cp))
1290ef64b99roberto		    break;
1291ef64b99roberto		do {
1292ef64b99roberto			*sp++ = *cp++;
1293ef64b99roberto		} while (!ISSPACE(*cp) && !ISEOL(*cp));
1294ef64b99roberto
1295ef64b99roberto		*sp++ = '\0';
1296ef64b99roberto	}
1297ef64b99roberto}
1298ef64b99roberto
1299ef64b99roberto
1300ef64b99roberto
1301ef64b99roberto/*
1302ef64b99roberto * findcmd - find a command in a command description table
1303ef64b99roberto */
1304ef64b99robertostatic int
1305ef64b99robertofindcmd(
1306ef64b99roberto	register char *str,
1307ef64b99roberto	struct xcmd *clist1,
1308ef64b99roberto	struct xcmd *clist2,
1309ef64b99roberto	struct xcmd **cmd
1310ef64b99roberto	)
1311ef64b99roberto{
1312ef64b99roberto	register struct xcmd *cl;
13138518518delphij	size_t clen;
1314ef64b99roberto	int nmatch;
1315ef64b99roberto	struct xcmd *nearmatch = NULL;
1316ef64b99roberto	struct xcmd *clist;
1317ef64b99roberto
1318ef64b99roberto	clen = strlen(str);
1319ef64b99roberto	nmatch = 0;
1320ef64b99roberto	if (clist1 != 0)
1321ef64b99roberto	    clist = clist1;
1322ef64b99roberto	else if (clist2 != 0)
1323ef64b99roberto	    clist = clist2;
1324ef64b99roberto	else
1325ef64b99roberto	    return 0;
1326ef64b99roberto
1327ef64b99roberto    again:
1328ef64b99roberto	for (cl = clist; cl->keyword != 0; cl++) {
1329ef64b99roberto		/* do a first character check, for efficiency */
1330ef64b99roberto		if (*str != *(cl->keyword))
1331ef64b99roberto		    continue;
1332ef64b99roberto		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1333ef64b99roberto			/*
1334ef64b99roberto			 * Could be extact match, could be approximate.
1335ef64b99roberto			 * Is exact if the length of the keyword is the
1336ef64b99roberto			 * same as the str.
1337ef64b99roberto			 */
1338ef64b99roberto			if (*((cl->keyword) + clen) == '\0') {
1339ef64b99roberto				*cmd = cl;
1340ef64b99roberto				return 1;
1341ef64b99roberto			}
1342ef64b99roberto			nmatch++;
1343ef64b99roberto			nearmatch = cl;
1344ef64b99roberto		}
1345ef64b99roberto	}
1346ef64b99roberto
1347ef64b99roberto				/*
1348ef64b99roberto				 * See if there is more to do.  If so, go again.  Sorry about the
1349ef64b99roberto				 * goto, too much looking at BSD sources...
1350ef64b99roberto				 */
1351ef64b99roberto	if (clist == clist1 && clist2 != 0) {
1352ef64b99roberto		clist = clist2;
1353ef64b99roberto		goto again;
1354ef64b99roberto	}
1355ef64b99roberto
1356ef64b99roberto				/*
1357ef64b99roberto				 * If we got extactly 1 near match, use it, else return number
1358ef64b99roberto				 * of matches.
1359ef64b99roberto				 */
1360ef64b99roberto	if (nmatch == 1) {
1361ef64b99roberto		*cmd = nearmatch;
1362ef64b99roberto		return 1;
1363ef64b99roberto	}
1364ef64b99roberto	return nmatch;
1365ef64b99roberto}
1366ef64b99roberto
1367ef64b99roberto
1368118e757roberto/*
1369ef64b99roberto * getarg - interpret an argument token
1370118e757roberto *
13717a6072eroberto * string is always set.
13727a6072eroberto * type is set to the decoded type.
13737a6072eroberto *
1374118e757roberto * return:	 0 - failure
1375118e757roberto *		 1 - success
1376118e757roberto *		-1 - skip to next token
1377ef64b99roberto */
1378ef64b99robertostatic int
1379ef64b99robertogetarg(
1380ef64b99roberto	char *str,
1381ef64b99roberto	int code,
1382ef64b99roberto	arg_v *argp
1383ef64b99roberto	)
1384ef64b99roberto{
1385047f369cy	ZERO(*argp);
13867a6072eroberto	argp->string = str;
13877a6072eroberto	argp->type   = code & ~OPT;
13887a6072eroberto
13897a6072eroberto	switch (argp->type) {
1390837c91fcy	case NTP_STR:
1391ef64b99roberto		break;
1392837c91fcy	case NTP_ADD:
1393118e757roberto		if (!strcmp("-6", str)) {
1394118e757roberto			ai_fam_templ = AF_INET6;
1395118e757roberto			return -1;
1396118e757roberto		} else if (!strcmp("-4", str)) {
1397118e757roberto			ai_fam_templ = AF_INET;
1398118e757roberto			return -1;
1399118e757roberto		}
1400837c91fcy		if (!getnetnum(str, &(argp->netnum), (char *)0, ai_fam_templ)) {
1401ef64b99roberto			return 0;
1402ef64b99roberto		}
1403ef64b99roberto		break;
1404837c91fcy	case NTP_UINT:
1405837c91fcy		if (!atouint(str, &argp->uval)) {
1406837c91fcy			fprintf(stderr, "***Illegal unsigned value %s\n",
1407837c91fcy				str);
1408837c91fcy			return 0;
1409ef64b99roberto		}
1410837c91fcy		break;
1411837c91fcy	case NTP_INT:
1412837c91fcy		if (!atoint(str, &argp->ival)) {
1413837c91fcy			fprintf(stderr, "***Illegal integer value %s\n",
1414837c91fcy				str);
1415837c91fcy			return 0;
1416ef64b99roberto		}
1417ef64b99roberto		break;
1418837c91fcy	case IP_VERSION:
1419118e757roberto		if (!strcmp("-6", str))
1420118e757roberto			argp->ival = 6 ;
1421118e757roberto		else if (!strcmp("-4", str))
1422118e757roberto			argp->ival = 4 ;
1423118e757roberto		else {
1424118e757roberto			(void) fprintf(stderr,
1425118e757roberto			    "***Version must be either 4 or 6\n");
1426118e757roberto			return 0;
1427118e757roberto		}
1428118e757roberto		break;
1429ef64b99roberto	}
1430ef64b99roberto
1431ef64b99roberto	return 1;
1432ef64b99roberto}
1433ef64b99roberto
1434ef64b99roberto
1435ef64b99roberto/*
1436ef64b99roberto * getnetnum - given a host name, return its net number
1437ef64b99roberto *	       and (optional) full name
1438ef64b99roberto */
1439ef64b99robertostatic int
1440ef64b99robertogetnetnum(
1441ef64b99roberto	const char *hname,
1442d54cfbdroberto	sockaddr_u *num,
1443118e757roberto	char *fullhost,
1444118e757roberto	int af
1445ef64b99roberto	)
1446ef64b99roberto{
1447118e757roberto	struct addrinfo hints, *ai = NULL;
1448118e757roberto
1449d54cfbdroberto	ZERO(hints);
1450837c91fcy	hints.ai_family = af;
1451118e757roberto	hints.ai_flags = AI_CANONNAME;
1452118e757roberto#ifdef AI_ADDRCONFIG
1453118e757roberto	hints.ai_flags |= AI_ADDRCONFIG;
1454118e757roberto#endif
1455118e757roberto
1456d54cfbdroberto	/*
1457d54cfbdroberto	 * decodenetnum only works with addresses, but handles syntax
1458d54cfbdroberto	 * that getaddrinfo doesn't:  [2001::1]:1234
1459d54cfbdroberto	 */
1460ef64b99roberto	if (decodenetnum(hname, num)) {
1461d54cfbdroberto		if (fullhost != NULL)
1462d54cfbdroberto			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1463d54cfbdroberto				    LENHOSTNAME, NULL, 0, 0);
1464ef64b99roberto		return 1;
14657a6072eroberto	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1466aae1e7dglebius		INSIST(sizeof(*num) >= ai->ai_addrlen);
1467d54cfbdroberto		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1468d54cfbdroberto		if (fullhost != NULL) {
1469047f369cy			if (ai->ai_canonname != NULL)
1470047f369cy				strlcpy(fullhost, ai->ai_canonname,
1471d54cfbdroberto					LENHOSTNAME);
1472047f369cy			else
1473d54cfbdroberto				getnameinfo(&num->sa, SOCKLEN(num),
1474d54cfbdroberto					    fullhost, LENHOSTNAME, NULL,
1475d54cfbdroberto					    0, 0);
1476d54cfbdroberto		}
1477ef64b99roberto		return 1;
1478ef64b99roberto	}
1479d54cfbdroberto	fprintf(stderr, "***Can't find host %s\n", hname);
1480d54cfbdroberto
1481d54cfbdroberto	return 0;
1482ef64b99roberto}
1483ef64b99roberto
1484047f369cy
1485ef64b99roberto/*
1486ef64b99roberto * nntohost - convert network number to host name.  This routine enforces
1487ef64b99roberto *	       the showhostnames setting.
1488ef64b99roberto */
1489047f369cyconst char *
1490ef64b99robertonntohost(
1491d54cfbdroberto	sockaddr_u *netnum
1492ef64b99roberto	)
1493ef64b99roberto{
1494047f369cy	if (!showhostnames || SOCK_UNSPEC(netnum))
1495d54cfbdroberto		return stoa(netnum);
1496047f369cy	else if (ISREFCLOCKADR(netnum))
1497118e757roberto		return refnumtoa(netnum);
1498047f369cy	else
1499047f369cy		return socktohost(netnum);
1500ef64b99roberto}
1501ef64b99roberto
1502ef64b99roberto
1503ef64b99roberto/*
1504ef64b99roberto * Finally, the built in command handlers
1505ef64b99roberto */
1506ef64b99roberto
1507ef64b99roberto/*
1508ef64b99roberto * help - tell about commands, or details of a particular command
1509ef64b99roberto */
1510ef64b99robertostatic void
1511ef64b99robertohelp(
1512ef64b99roberto	struct parse *pcmd,
1513ef64b99roberto	FILE *fp
1514ef64b99roberto	)
1515ef64b99roberto{
1516ef64b99roberto	struct xcmd *xcp;
1517ef64b99roberto	char *cmd;
15187a6072eroberto	const char *list[100];
1519d54cfbdroberto	size_t word, words;
1520d54cfbdroberto	size_t row, rows;
1521d54cfbdroberto	size_t col, cols;
1522d54cfbdroberto	size_t length;
1523ef64b99roberto
1524ef64b99roberto	if (pcmd->nargs == 0) {
15257a6072eroberto		words = 0;
1526ef64b99roberto		for (xcp = builtins; xcp->keyword != 0; xcp++) {
1527ef64b99roberto			if (*(xcp->keyword) != '?')
1528d54cfbdroberto				list[words++] = xcp->keyword;
1529ef64b99roberto		}
1530d54cfbdroberto		for (xcp = opcmds; xcp->keyword != 0; xcp++)
1531d54cfbdroberto			list[words++] = xcp->keyword;
1532ef64b99roberto
1533047f369cy		qsort((void *)list, words, sizeof(list[0]), helpsort);
15347a6072eroberto		col = 0;
15357a6072eroberto		for (word = 0; word < words; word++) {
1536d54cfbdroberto			length = strlen(list[word]);
1537d54cfbdroberto			col = max(col, length);
1538ef64b99roberto		}
15397a6072eroberto
15407a6072eroberto		cols = SCREENWIDTH / ++col;
1541d54cfbdroberto		rows = (words + cols - 1) / cols;
15427a6072eroberto
1543d54cfbdroberto		fprintf(fp, "ntpdc commands:\n");
15447a6072eroberto
15457a6072eroberto		for (row = 0; row < rows; row++) {
1546d54cfbdroberto			for (word = row; word < words; word += rows)
1547047f369cy				fprintf(fp, "%-*.*s", (int)col,
1548047f369cy					(int)col - 1, list[word]);
1549d54cfbdroberto			fprintf(fp, "\n");
1550ef64b99roberto		}
1551ef64b99roberto	} else {
1552ef64b99roberto		cmd = pcmd->argval[0].string;
15537a6072eroberto		words = findcmd(cmd, builtins, opcmds, &xcp);
15547a6072eroberto		if (words == 0) {
1555d54cfbdroberto			fprintf(stderr,
1556d54cfbdroberto				"Command `%s' is unknown\n", cmd);
1557ef64b99roberto			return;
15587a6072eroberto		} else if (words >= 2) {
1559d54cfbdroberto			fprintf(stderr,
1560d54cfbdroberto				"Command `%s' is ambiguous\n", cmd);
1561ef64b99roberto			return;
1562ef64b99roberto		}
1563d54cfbdroberto		fprintf(fp, "function: %s\n", xcp->comment);
1564ef64b99roberto		printusage(xcp, fp);
1565ef64b99roberto	}
1566ef64b99roberto}
1567ef64b99roberto
1568ef64b99roberto
1569ef64b99roberto/*
1570ef64b99roberto * helpsort - do hostname qsort comparisons
1571ef64b99roberto */
1572ef64b99robertostatic int
1573ef64b99robertohelpsort(
1574ef64b99roberto	const void *t1,
1575ef64b99roberto	const void *t2
1576ef64b99roberto	)
1577ef64b99roberto{
1578d54cfbdroberto	const char * const *	name1 = t1;
1579d54cfbdroberto	const char * const *	name2 = t2;
1580ef64b99roberto
1581ef64b99roberto	return strcmp(*name1, *name2);
1582ef64b99roberto}
1583ef64b99roberto
1584ef64b99roberto
1585ef64b99roberto/*
1586ef64b99roberto * printusage - print usage information for a command
1587ef64b99roberto */
1588ef64b99robertostatic void
1589ef64b99robertoprintusage(
1590ef64b99roberto	struct xcmd *xcp,
1591ef64b99roberto	FILE *fp
1592ef64b99roberto	)
1593ef64b99roberto{
1594118e757roberto	int i, opt46;
1595ef64b99roberto
1596118e757roberto	opt46 = 0;
1597ef64b99roberto	(void) fprintf(fp, "usage: %s", xcp->keyword);
1598ef64b99roberto	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
15997a6072eroberto		if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) {
1600118e757roberto			(void) fprintf(fp, " [ -4|-6 ]");
1601118e757roberto			opt46 = 1;
1602118e757roberto		}
1603ef64b99roberto		if (xcp->arg[i] & OPT)
1604ef64b99roberto		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
1605ef64b99roberto		else
1606ef64b99roberto		    (void) fprintf(fp, " %s", xcp->desc[i]);
1607ef64b99roberto	}
1608ef64b99roberto	(void) fprintf(fp, "\n");
1609ef64b99roberto}
1610ef64b99roberto
1611ef64b99roberto
1612ef64b99roberto/*
1613ef64b99roberto * timeout - set time out time
1614ef64b99roberto */
1615ef64b99robertostatic void
1616ef64b99robertotimeout(
1617ef64b99roberto	struct parse *pcmd,
1618ef64b99roberto	FILE *fp
1619ef64b99roberto	)
1620ef64b99roberto{
1621ef64b99roberto	int val;
1622ef64b99roberto
1623ef64b99roberto	if (pcmd->nargs == 0) {
1624ef64b99roberto		val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
1625ef64b99roberto		(void) fprintf(fp, "primary timeout %d ms\n", val);
1626ef64b99roberto	} else {
1627ef64b99roberto		tvout.tv_sec = pcmd->argval[0].uval / 1000;
1628ef64b99roberto		tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
1629ef64b99roberto			* 1000;
1630ef64b99roberto	}
1631ef64b99roberto}
1632ef64b99roberto
1633ef64b99roberto
1634ef64b99roberto/*
1635ef64b99roberto * my_delay - set delay for auth requests
1636ef64b99roberto */
1637ef64b99robertostatic void
1638ef64b99robertomy_delay(
1639ef64b99roberto	struct parse *pcmd,
1640ef64b99roberto	FILE *fp
1641ef64b99roberto	)
1642ef64b99roberto{
1643ef64b99roberto	int isneg;
1644ef64b99roberto	u_long val;
1645ef64b99roberto
1646ef64b99roberto	if (pcmd->nargs == 0) {
1647ef64b99roberto		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
1648ef64b99roberto		(void) fprintf(fp, "delay %lu ms\n", val);
1649ef64b99roberto	} else {
1650ef64b99roberto		if (pcmd->argval[0].ival < 0) {
1651ef64b99roberto			isneg = 1;
1652837c91fcy			val = ~(u_long)(pcmd->argval[0].ival) + 1UL;
1653ef64b99roberto		} else {
1654ef64b99roberto			isneg = 0;
1655ef64b99roberto			val = (u_long)pcmd->argval[0].ival;
1656ef64b99roberto		}
1657ef64b99roberto
1658ef64b99roberto		delay_time.l_ui = val / 1000;
1659ef64b99roberto		val %= 1000;
1660ef64b99roberto		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
1661ef64b99roberto
1662ef64b99roberto		if (isneg)
1663ef64b99roberto		    L_NEG(&delay_time);
1664ef64b99roberto	}
1665ef64b99roberto}
1666ef64b99roberto
1667ef64b99roberto
1668ef64b99roberto/*
1669ef64b99roberto * host - set the host we are dealing with.
1670ef64b99roberto */
1671ef64b99robertostatic void
1672ef64b99robertohost(
1673ef64b99roberto	struct parse *pcmd,
1674ef64b99roberto	FILE *fp
1675ef64b99roberto	)
1676ef64b99roberto{
1677118e757roberto	int i;
1678118e757roberto
1679ef64b99roberto	if (pcmd->nargs == 0) {
1680ef64b99roberto		if (havehost)
1681ef64b99roberto		    (void) fprintf(fp, "current host is %s\n", currenthost);
1682ef64b99roberto		else
1683ef64b99roberto		    (void) fprintf(fp, "no current host\n");
1684118e757roberto		return;
1685118e757roberto	}
1686118e757roberto
1687118e757roberto	i = 0;
1688118e757roberto	if (pcmd->nargs == 2) {
1689118e757roberto		if (!strcmp("-4", pcmd->argval[i].string))
1690118e757roberto			ai_fam_templ = AF_INET;
1691118e757roberto		else if (!strcmp("-6", pcmd->argval[i].string))
1692118e757roberto			ai_fam_templ = AF_INET6;
1693118e757roberto		else {
1694118e757roberto			if (havehost)
1695118e757roberto				(void) fprintf(fp,
1696118e757roberto				    "current host remains %s\n", currenthost);
1697118e757roberto			else
1698118e757roberto				(void) fprintf(fp, "still no current host\n");
1699118e757roberto			return;
1700118e757roberto		}
1701118e757roberto		i = 1;
1702118e757roberto	}
1703118e757roberto	if (openhost(pcmd->argval[i].string)) {
1704ef64b99roberto		(void) fprintf(fp, "current host set to %s\n", currenthost);
1705ef64b99roberto	} else {
1706ef64b99roberto		if (havehost)
1707ef64b99roberto		    (void) fprintf(fp,
1708ef64b99roberto				   "current host remains %s\n", currenthost);
1709ef64b99roberto		else
1710ef64b99roberto		    (void) fprintf(fp, "still no current host\n");
1711ef64b99roberto	}
1712ef64b99roberto}
1713ef64b99roberto
1714ef64b99roberto
1715ef64b99roberto/*
1716ef64b99roberto * keyid - get a keyid to use for authenticating requests
1717ef64b99roberto */
1718ef64b99robertostatic void
1719ef64b99robertokeyid(
1720ef64b99roberto	struct parse *pcmd,
1721ef64b99roberto	FILE *fp
1722ef64b99roberto	)
1723ef64b99roberto{
1724ef64b99roberto	if (pcmd->nargs == 0) {
17257a6072eroberto		if (info_auth_keyid == 0 && !keyid_entered)
1726ef64b99roberto		    (void) fprintf(fp, "no keyid defined\n");
17277a6072eroberto		else if (info_auth_keyid == 0 && keyid_entered)
17287a6072eroberto		    (void) fprintf(fp, "no keyid will be sent\n");
1729ef64b99roberto		else
1730ef64b99roberto		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
1731ef64b99roberto	} else {
1732ef64b99roberto		info_auth_keyid = pcmd->argval[0].uval;
17337a6072eroberto		keyid_entered = 1;
1734ef64b99roberto	}
1735ef64b99roberto}
1736ef64b99roberto
1737ef64b99roberto
1738ef64b99roberto/*
1739ef64b99roberto * keytype - get type of key to use for authenticating requests
1740ef64b99roberto */
1741ef64b99robertostatic void
1742ef64b99robertokeytype(
1743ef64b99roberto	struct parse *pcmd,
1744ef64b99roberto	FILE *fp
1745ef64b99roberto	)
1746ef64b99roberto{
1747d54cfbdroberto	const char *	digest_name;
1748d54cfbdroberto	size_t		digest_len;
1749d54cfbdroberto	int		key_type;
1750d54cfbdroberto
1751d54cfbdroberto	if (!pcmd->nargs) {
1752d54cfbdroberto		fprintf(fp, "keytype is %s with %lu octet digests\n",
1753d54cfbdroberto			keytype_name(info_auth_keytype),
1754d54cfbdroberto			(u_long)info_auth_hashlen);
1755d54cfbdroberto		return;
1756d54cfbdroberto	}
1757ef64b99roberto
1758d54cfbdroberto	digest_name = pcmd->argval[0].string;
1759d54cfbdroberto	digest_len = 0;
1760d54cfbdroberto	key_type = keytype_from_text(digest_name, &digest_len);
1761ef64b99roberto
1762d54cfbdroberto	if (!key_type) {
1763d54cfbdroberto		fprintf(fp, "keytype must be 'md5'%s\n",
1764d54cfbdroberto#ifdef OPENSSL
1765d54cfbdroberto			" or a digest type provided by OpenSSL");
1766d54cfbdroberto#else
1767d54cfbdroberto			"");
1768d54cfbdroberto#endif
1769d54cfbdroberto		return;
1770d54cfbdroberto	}
1771d54cfbdroberto
1772d54cfbdroberto	info_auth_keytype = key_type;
1773d54cfbdroberto	info_auth_hashlen = digest_len;
1774d54cfbdroberto}
1775ef64b99roberto
1776ef64b99roberto
1777ef64b99roberto/*
1778ef64b99roberto * passwd - get an authentication key
1779ef64b99roberto */
1780ef64b99roberto/*ARGSUSED*/
1781ef64b99robertostatic void
1782ef64b99robertopasswd(
1783ef64b99roberto	struct parse *pcmd,
1784ef64b99roberto	FILE *fp
1785ef64b99roberto	)
1786ef64b99roberto{
1787ef64b99roberto	char *pass;
1788ef64b99roberto
1789ef64b99roberto	if (info_auth_keyid == 0) {
1790ef64b99roberto		info_auth_keyid = getkeyid("Keyid: ");
1791ef64b99roberto		if (info_auth_keyid == 0) {
1792ef64b99roberto			(void)fprintf(fp, "Keyid must be defined\n");
1793ef64b99roberto			return;
1794ef64b99roberto		}
1795ef64b99roberto	}
1796047f369cy	if (pcmd->nargs >= 1)
1797047f369cy		pass = pcmd->argval[0].string;
1798047f369cy	else {
1799d54cfbdroberto		pass = getpass_keytype(info_auth_keytype);
1800047f369cy		if ('\0' == *pass) {
1801047f369cy			fprintf(fp, "Password unchanged\n");
1802047f369cy			return;
180340b8e41roberto		}
1804ef64b99roberto	}
1805047f369cy	authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
1806047f369cy	authtrust(info_auth_keyid, 1);
1807ef64b99roberto}
1808ef64b99roberto
1809ef64b99roberto
1810ef64b99roberto/*
1811ef64b99roberto * hostnames - set the showhostnames flag
1812ef64b99roberto */
1813ef64b99robertostatic void
1814ef64b99robertohostnames(
1815ef64b99roberto	struct parse *pcmd,
1816ef64b99roberto	FILE *fp
1817ef64b99roberto	)
1818ef64b99roberto{
1819ef64b99roberto	if (pcmd->nargs == 0) {
1820ef64b99roberto		if (showhostnames)
1821ef64b99roberto		    (void) fprintf(fp, "hostnames being shown\n");
1822ef64b99roberto		else
1823ef64b99roberto		    (void) fprintf(fp, "hostnames not being shown\n");
1824ef64b99roberto	} else {
1825ef64b99roberto		if (STREQ(pcmd->argval[0].string, "yes"))
1826ef64b99roberto		    showhostnames = 1;
1827ef64b99roberto		else if (STREQ(pcmd->argval[0].string, "no"))
1828ef64b99roberto		    showhostnames = 0;
1829ef64b99roberto		else
1830ef64b99roberto		    (void)fprintf(stderr, "What?\n");
1831ef64b99roberto	}
1832ef64b99roberto}
1833ef64b99roberto
1834ef64b99roberto
1835ef64b99roberto/*
1836ef64b99roberto * setdebug - set/change debugging level
1837ef64b99roberto */
1838ef64b99robertostatic void
1839ef64b99robertosetdebug(
1840ef64b99roberto	struct parse *pcmd,
1841ef64b99roberto	FILE *fp
1842ef64b99roberto	)
1843ef64b99roberto{
1844ef64b99roberto	if (pcmd->nargs == 0) {
1845ef64b99roberto		(void) fprintf(fp, "debug level is %d\n", debug);
1846ef64b99roberto		return;
1847ef64b99roberto	} else if (STREQ(pcmd->argval[0].string, "no")) {
1848ef64b99roberto		debug = 0;
1849ef64b99roberto	} else if (STREQ(pcmd->argval[0].string, "more")) {
1850ef64b99roberto		debug++;
1851ef64b99roberto	} else if (STREQ(pcmd->argval[0].string, "less")) {
1852ef64b99roberto		debug--;
1853ef64b99roberto	} else {
1854ef64b99roberto		(void) fprintf(fp, "What?\n");
1855ef64b99roberto		return;
1856ef64b99roberto	}
1857ef64b99roberto	(void) fprintf(fp, "debug level set to %d\n", debug);
1858ef64b99roberto}
1859ef64b99roberto
1860ef64b99roberto
1861ef64b99roberto/*
1862ef64b99roberto * quit - stop this nonsense
1863ef64b99roberto */
1864ef64b99roberto/*ARGSUSED*/
1865ef64b99robertostatic void
1866ef64b99robertoquit(
1867ef64b99roberto	struct parse *pcmd,
1868ef64b99roberto	FILE *fp
1869ef64b99roberto	)
1870ef64b99roberto{
1871ef64b99roberto	if (havehost)
1872ef64b99roberto	    closesocket(sockfd);
1873ef64b99roberto	exit(0);
1874ef64b99roberto}
1875ef64b99roberto
1876ef64b99roberto
1877ef64b99roberto/*
1878ef64b99roberto * version - print the current version number
1879ef64b99roberto */
1880ef64b99roberto/*ARGSUSED*/
1881ef64b99robertostatic void
1882ef64b99robertoversion(
1883ef64b99roberto	struct parse *pcmd,
1884ef64b99roberto	FILE *fp
1885ef64b99roberto	)
1886ef64b99roberto{
1887ef64b99roberto
1888ef64b99roberto	(void) fprintf(fp, "%s\n", Version);
1889ef64b99roberto	return;
1890ef64b99roberto}
1891ef64b99roberto
1892ef64b99roberto
1893bdc155dcystatic void __attribute__((__format__(__printf__, 1, 0)))
1894bdc155dcyvwarning(const char *fmt, va_list ap)
1895bdc155dcy{
1896bdc155dcy	int serrno = errno;
1897bdc155dcy	(void) fprintf(stderr, "%s: ", progname);
1898bdc155dcy	vfprintf(stderr, fmt, ap);
1899bdc155dcy	(void) fprintf(stderr, ": %s\n", strerror(serrno));
1900bdc155dcy}
1901bdc155dcy
1902ef64b99roberto/*
1903ef64b99roberto * warning - print a warning message
1904ef64b99roberto */
1905bdc155dcystatic void __attribute__((__format__(__printf__, 1, 2)))
1906ef64b99robertowarning(
1907ef64b99roberto	const char *fmt,
1908bdc155dcy	...
1909ef64b99roberto	)
1910ef64b99roberto{
1911bdc155dcy	va_list ap;
1912bdc155dcy	va_start(ap, fmt);
1913bdc155dcy	vwarning(fmt, ap);
1914bdc155dcy	va_end(ap);
1915ef64b99roberto}
1916ef64b99roberto
1917ef64b99roberto
1918ef64b99roberto/*
1919ef64b99roberto * error - print a message and exit
1920ef64b99roberto */
1921bdc155dcystatic void __attribute__((__format__(__printf__, 1, 2)))
1922ef64b99robertoerror(
1923ef64b99roberto	const char *fmt,
1924bdc155dcy	...
1925ef64b99roberto	)
1926ef64b99roberto{
1927bdc155dcy	va_list ap;
1928bdc155dcy	va_start(ap, fmt);
1929bdc155dcy	vwarning(fmt, ap);
1930bdc155dcy	va_end(ap);
1931ef64b99roberto	exit(1);
1932ef64b99roberto}
1933ef64b99roberto
1934ef64b99roberto/*
1935ef64b99roberto * getkeyid - prompt the user for a keyid to use
1936ef64b99roberto */
1937ef64b99robertostatic u_long
1938ef64b99robertogetkeyid(
1939ef64b99roberto	const char *keyprompt
1940ef64b99roberto	)
1941ef64b99roberto{
1942d54cfbdroberto	int c;
1943ef64b99roberto	FILE *fi;
1944ef64b99roberto	char pbuf[20];
1945d54cfbdroberto	size_t i;
1946d54cfbdroberto	size_t ilim;
1947ef64b99roberto
1948ef64b99roberto#ifndef SYS_WINNT
1949ef64b99roberto	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
1950ef64b99roberto#else
1951d54cfbdroberto	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
1952ef64b99roberto#endif /* SYS_WINNT */
1953ef64b99roberto		fi = stdin;
1954d54cfbdroberto	else
1955ef64b99roberto		setbuf(fi, (char *)NULL);
1956ef64b99roberto	fprintf(stderr, "%s", keyprompt); fflush(stderr);
1957d54cfbdroberto	for (i = 0, ilim = COUNTOF(pbuf) - 1;
1958d54cfbdroberto	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
1959d54cfbdroberto	     )
1960d54cfbdroberto		pbuf[i++] = (char)c;
1961d54cfbdroberto	pbuf[i] = '\0';
1962ef64b99roberto	if (fi != stdin)
1963d54cfbdroberto		fclose(fi);
1964d54cfbdroberto
1965d54cfbdroberto	return (u_long) atoi(pbuf);
1966ef64b99roberto}
1967