ntpq.c revision 358659
1/*
2 * ntpq - query an NTP server using mode 6 commands
3 */
4#include <config.h>
5#include <ctype.h>
6#include <signal.h>
7#include <setjmp.h>
8#include <stddef.h>
9#include <stdio.h>
10#include <sys/types.h>
11#include <sys/time.h>
12#ifdef HAVE_UNISTD_H
13# include <unistd.h>
14#endif
15#ifdef HAVE_FCNTL_H
16# include <fcntl.h>
17#endif
18#ifdef SYS_WINNT
19# include <mswsock.h>
20#endif
21#include <isc/net.h>
22#include <isc/result.h>
23
24#include "ntpq.h"
25#include "ntp_assert.h"
26#include "ntp_stdlib.h"
27#include "ntp_unixtime.h"
28#include "ntp_calendar.h"
29#include "ntp_select.h"
30#include "ntp_assert.h"
31#include "lib_strbuf.h"
32#include "ntp_lineedit.h"
33#include "ntp_debug.h"
34#ifdef OPENSSL
35# include "openssl/evp.h"
36# include "openssl/objects.h"
37# include "openssl/err.h"
38# ifdef SYS_WINNT
39#  include "openssl/opensslv.h"
40#  if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L
41#     define HAVE_EVP_MD_DO_ALL_SORTED	1
42#  endif
43# endif
44# include "libssl_compat.h"
45# ifdef HAVE_OPENSSL_CMAC_H
46#  include <openssl/cmac.h>
47#  define CMAC "AES128CMAC"
48# endif
49#endif
50#include <ssl_applink.c>
51
52#include "ntp_libopts.h"
53#include "safecast.h"
54
55#ifdef SYS_VXWORKS		/* vxWorks needs mode flag -casey*/
56# define open(name, flags)   open(name, flags, 0777)
57# define SERVER_PORT_NUM     123
58#endif
59
60/* we use COMMAND as an autogen keyword */
61#ifdef COMMAND
62# undef COMMAND
63#endif
64
65/*
66 * Because we potentially understand a lot of commands we will run
67 * interactive if connected to a terminal.
68 */
69int interactive = 0;		/* set to 1 when we should prompt */
70const char *prompt = "ntpq> ";	/* prompt to ask him about */
71
72/*
73 * use old readvars behavior?  --old-rv processing in ntpq resets
74 * this value based on the presence or absence of --old-rv.  It is
75 * initialized to 1 here to maintain backward compatibility with
76 * libntpq clients such as ntpsnmpd, which are free to reset it as
77 * desired.
78 */
79int	old_rv = 1;
80
81/*
82 * How should we display the refid?
83 * REFID_HASH, REFID_IPV4
84 */
85te_Refid drefid = -1;
86
87/*
88 * for get_systime()
89 */
90s_char	sys_precision;		/* local clock precision (log2 s) */
91
92/*
93 * Keyid used for authenticated requests.  Obtained on the fly.
94 */
95u_long info_auth_keyid = 0;
96
97static	int	info_auth_keytype = NID_md5;	/* MD5 */
98static	size_t	info_auth_hashlen = 16;		/* MD5 */
99u_long	current_time;		/* needed by authkeys; not used */
100
101/*
102 * Flag which indicates we should always send authenticated requests
103 */
104int always_auth = 0;
105
106/*
107 * Flag which indicates raw mode output.
108 */
109int rawmode = 0;
110
111/*
112 * Packet version number we use
113 */
114u_char pktversion = NTP_OLDVERSION + 1;
115
116
117/*
118 * Format values
119 */
120#define	PADDING	0
121#define	HA	1	/* host address */
122#define	NA	2	/* network address */
123#define	LP	3	/* leap (print in binary) */
124#define	RF	4	/* refid (sometimes string, sometimes not) */
125#define	AU	5	/* array of unsigned times */
126#define FX	6	/* test flags */
127#define TS	7	/* l_fp timestamp in hex */
128#define	OC	8	/* integer, print in octal */
129#define	AS	9	/* array of signed times */
130#define	SN	10	/* signed number: must display +/- sign */
131#define	EOV	255	/* end of table */
132
133/*
134 * For the most part ntpq simply displays what ntpd provides in the
135 * mostly plain-text mode 6 responses.  A few variable names are by
136 * default "cooked" to provide more human-friendly output.
137 */
138const var_format cookedvars[] = {
139	{ "leap",		LP },
140	{ "reach",		OC },
141	{ "refid",		RF },
142	{ "reftime",		TS },
143	{ "clock",		TS },
144	{ "org",		TS },
145	{ "rec",		TS },
146	{ "xmt",		TS },
147	{ "flash",		FX },
148	{ "srcadr",		HA },
149	{ "peeradr",		HA },	/* compat with others */
150	{ "dstadr",		NA },
151	{ "filtdelay",		AU },
152	{ "filtoffset",		AS },
153	{ "filtdisp",		AU },
154	{ "filterror",		AU },	/* compat with others */
155	{ "offset",		SN },
156	{ "frequency",		SN }
157};
158
159
160
161/*
162 * flasher bits
163 */
164static const char *tstflagnames[] = {
165	"pkt_dup",		/* TEST1 */
166	"pkt_bogus",		/* TEST2 */
167	"pkt_unsync",		/* TEST3 */
168	"pkt_denied",		/* TEST4 */
169	"pkt_auth",		/* TEST5 */
170	"pkt_stratum",		/* TEST6 */
171	"pkt_header",		/* TEST7 */
172	"pkt_autokey",		/* TEST8 */
173	"pkt_crypto",		/* TEST9 */
174	"peer_stratum",		/* TEST10 */
175	"peer_dist",		/* TEST11 */
176	"peer_loop",		/* TEST12 */
177	"peer_unreach"		/* TEST13 */
178};
179
180
181int		ntpqmain	(int,	char **);
182/*
183 * Built in command handler declarations
184 */
185static	int	openhost	(const char *, int);
186static	void	dump_hex_printable(const void *, size_t);
187static	int	sendpkt		(void *, size_t);
188static	int	getresponse	(int, int, u_short *, size_t *, const char **, int);
189static	int	sendrequest	(int, associd_t, int, size_t, const char *);
190static	char *	tstflags	(u_long);
191#ifndef BUILD_AS_LIB
192static	void	getcmds		(void);
193#ifndef SYS_WINNT
194static	int	abortcmd	(void);
195#endif	/* SYS_WINNT */
196static	void	docmd		(const char *);
197static	void	tokenize	(const char *, char **, int *);
198static	int	getarg		(const char *, int, arg_v *);
199#endif	/* BUILD_AS_LIB */
200static	int	findcmd		(const char *, struct xcmd *,
201				 struct xcmd *, struct xcmd **);
202static	int	rtdatetolfp	(char *, l_fp *);
203static	int	decodearr	(char *, int *, l_fp *, int);
204static	void	help		(struct parse *, FILE *);
205static	int	helpsort	(const void *, const void *);
206static	void	printusage	(struct xcmd *, FILE *);
207static	void	timeout		(struct parse *, FILE *);
208static	void	auth_delay	(struct parse *, FILE *);
209static	void	host		(struct parse *, FILE *);
210static	void	ntp_poll	(struct parse *, FILE *);
211static	void	keyid		(struct parse *, FILE *);
212static	void	keytype		(struct parse *, FILE *);
213static	void	passwd		(struct parse *, FILE *);
214static	void	hostnames	(struct parse *, FILE *);
215static	void	setdebug	(struct parse *, FILE *);
216static	void	quit		(struct parse *, FILE *);
217static	void	showdrefid	(struct parse *, FILE *);
218static	void	version		(struct parse *, FILE *);
219static	void	raw		(struct parse *, FILE *);
220static	void	cooked		(struct parse *, FILE *);
221static	void	authenticate	(struct parse *, FILE *);
222static	void	ntpversion	(struct parse *, FILE *);
223static	void	warning		(const char *, ...) NTP_PRINTF(1, 2);
224static	void	error		(const char *, ...) NTP_PRINTF(1, 2);
225static	u_long	getkeyid	(const char *);
226static	void	atoascii	(const char *, size_t, char *, size_t);
227static	void	cookedprint	(int, size_t, const char *, int, int, FILE *);
228static	void	rawprint	(int, size_t, const char *, int, int, FILE *);
229static	void	startoutput	(void);
230static	void	output		(FILE *, const char *, const char *);
231static	void	endoutput	(FILE *);
232static	void	outputarr	(FILE *, char *, int, l_fp *, int);
233static	int	assoccmp	(const void *, const void *);
234	u_short	varfmt		(const char *);
235	void	ntpq_custom_opt_handler(tOptions *, tOptDesc *);
236
237#ifndef BUILD_AS_LIB
238static	char   *list_digest_names(void);
239static	char   *insert_cmac	(char *list);
240static	void	on_ctrlc	(void);
241static	int	my_easprintf	(char**, const char *, ...) NTP_PRINTF(2, 3);
242# if defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED)
243static	void	list_md_fn	(const EVP_MD *m, const char *from,
244				 const char *to, void *arg);
245# endif /* defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED) */
246#endif /* !defined(BUILD_AS_LIB) */
247
248
249/* read a character from memory and expand to integer */
250static inline int
251pgetc(
252	const char *cp
253	)
254{
255	return (int)*(const unsigned char*)cp;
256}
257
258
259
260/*
261 * Built-in commands we understand
262 */
263struct xcmd builtins[] = {
264	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
265	  { "command", "", "", "" },
266	  "tell the use and syntax of commands" },
267	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
268	  { "command", "", "", "" },
269	  "tell the use and syntax of commands" },
270	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
271	  { "msec", "", "", "" },
272	  "set the primary receive time out" },
273	{ "delay",	auth_delay,	{ OPT|NTP_INT, NO, NO, NO },
274	  { "msec", "", "", "" },
275	  "set the delay added to encryption time stamps" },
276	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
277	  { "-4|-6", "hostname", "", "" },
278	  "specify the host whose NTP server we talk to" },
279	{ "poll",	ntp_poll,	{ OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
280	  { "n", "verbose", "", "" },
281	  "poll an NTP server in client mode `n' times" },
282	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
283	  { "", "", "", "" },
284	  "specify a password to use for authenticated requests"},
285	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
286	  { "yes|no", "", "", "" },
287	  "specify whether hostnames or net numbers are printed"},
288	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
289	  { "no|more|less", "", "", "" },
290	  "set/change debugging level" },
291	{ "quit",	quit,		{ NO, NO, NO, NO },
292	  { "", "", "", "" },
293	  "exit ntpq" },
294	{ "exit",	quit,		{ NO, NO, NO, NO },
295	  { "", "", "", "" },
296	  "exit ntpq" },
297	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
298	  { "key#", "", "", "" },
299	  "set keyid to use for authenticated requests" },
300	{ "drefid",	showdrefid,	{ OPT|NTP_STR, NO, NO, NO },
301	  { "hash|ipv4", "", "", "" },
302	  "display refid's as IPv4 or hash" },
303	{ "version",	version,	{ NO, NO, NO, NO },
304	  { "", "", "", "" },
305	  "print version number" },
306	{ "raw",	raw,		{ NO, NO, NO, NO },
307	  { "", "", "", "" },
308	  "do raw mode variable output" },
309	{ "cooked",	cooked,		{ NO, NO, NO, NO },
310	  { "", "", "", "" },
311	  "do cooked mode variable output" },
312	{ "authenticate", authenticate,	{ OPT|NTP_STR, NO, NO, NO },
313	  { "yes|no", "", "", "" },
314	  "always authenticate requests to this server" },
315	{ "ntpversion",	ntpversion,	{ OPT|NTP_UINT, NO, NO, NO },
316	  { "version number", "", "", "" },
317	  "set the NTP version number to use for requests" },
318	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
319	  { "key type %s", "", "", "" },
320	  NULL },
321	{ 0,		0,		{ NO, NO, NO, NO },
322	  { "", "", "", "" }, "" }
323};
324
325
326/*
327 * Default values we use.
328 */
329#define	DEFHOST		"localhost"	/* default host name */
330#define	DEFTIMEOUT	5		/* wait 5 seconds for 1st pkt */
331#define	DEFSTIMEOUT	3		/* and 3 more for each additional */
332/*
333 * Requests are automatically retried once, so total timeout with no
334 * response is a bit over 2 * DEFTIMEOUT, or 10 seconds.  At the other
335 * extreme, a request eliciting 32 packets of responses each for some
336 * reason nearly DEFSTIMEOUT seconds after the prior in that series,
337 * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
338 * 93 seconds to fail each of two times, or 186 seconds.
339 * Some commands involve a series of requests, such as "peers" and
340 * "mrulist", so the cumulative timeouts are even longer for those.
341 */
342#define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
343#define	LENHOSTNAME	256		/* host name is 256 characters long */
344#define	MAXCMDS		100		/* maximum commands on cmd line */
345#define	MAXHOSTS	200		/* maximum hosts on cmd line */
346#define	MAXLINE		512		/* maximum line length */
347#define	MAXTOKENS	(1+MAXARGS+2)	/* maximum number of usable tokens */
348#define	MAXVARLEN	256		/* maximum length of a variable name */
349#define	MAXVALLEN	2048		/* maximum length of a variable value */
350#define	MAXOUTLINE	72		/* maximum length of an output line */
351#define SCREENWIDTH	76		/* nominal screen width in columns */
352
353/*
354 * Some variables used and manipulated locally
355 */
356struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
357struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
358l_fp delay_time;				/* delay time */
359char currenthost[LENHOSTNAME];			/* current host name */
360int currenthostisnum;				/* is prior text from IP? */
361struct sockaddr_in hostaddr;			/* host address */
362int showhostnames = 1;				/* show host names by default */
363int wideremote = 0;				/* show wide remote names? */
364
365int ai_fam_templ;				/* address family */
366int ai_fam_default;				/* default address family */
367SOCKET sockfd;					/* fd socket is opened on */
368int havehost = 0;				/* set to 1 when host open */
369int s_port = 0;
370struct servent *server_entry = NULL;		/* server entry for ntp */
371
372
373/*
374 * Sequence number used for requests.  It is incremented before
375 * it is used.
376 */
377u_short sequence;
378
379/*
380 * Holds data returned from queries.  Declare buffer long to be sure of
381 * alignment.
382 */
383#define	DATASIZE	(MAXFRAGS*480)	/* maximum amount of data */
384long pktdata[DATASIZE/sizeof(long)];
385
386/*
387 * assoc_cache[] is a dynamic array which allows references to
388 * associations using &1 ... &N for n associations, avoiding manual
389 * lookup of the current association IDs for a given ntpd.  It also
390 * caches the status word for each association, retrieved incidentally.
391 */
392struct association *	assoc_cache;
393u_int assoc_cache_slots;/* count of allocated array entries */
394u_int numassoc;		/* number of cached associations */
395
396/*
397 * For commands typed on the command line (with the -c option)
398 */
399size_t numcmds = 0;
400const char *ccmds[MAXCMDS];
401#define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
402
403/*
404 * When multiple hosts are specified.
405 */
406
407u_int numhosts;
408
409chost chosts[MAXHOSTS];
410#define	ADDHOST(cp)						\
411	do {							\
412		if (numhosts < MAXHOSTS) {			\
413			chosts[numhosts].name = (cp);		\
414			chosts[numhosts].fam = ai_fam_templ;	\
415			numhosts++;				\
416		}						\
417	} while (0)
418
419/*
420 * Macro definitions we use
421 */
422#define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
423#define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
424#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
425
426/*
427 * Jump buffer for longjumping back to the command level.
428 *
429 * Since we do this from a signal handler, we use 'sig{set,long}jmp()'
430 * if available. The signal is blocked by default during the excution of
431 * a signal handler, and it is unspecified if '{set,long}jmp()' save and
432 * restore the signal mask. They do on BSD, it depends on the GLIBC
433 * version on Linux, and the gods know what happens on other OSes...
434 *
435 * So we use the 'sig{set,long}jmp()' functions where available, because
436 * for them the semantics are well-defined. If we have to fall back to
437 * '{set,long}jmp()', the CTRL-C handling might be a bit erratic.
438 */
439#if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
440# define JMP_BUF	sigjmp_buf
441# define SETJMP(x)	sigsetjmp((x), 1)
442# define LONGJMP(x, v)	siglongjmp((x),(v))
443#else
444# define JMP_BUF	jmp_buf
445# define SETJMP(x)	setjmp((x))
446# define LONGJMP(x, v)	longjmp((x),(v))
447#endif
448static	JMP_BUF		interrupt_buf;
449static	volatile int	jump = 0;
450
451/*
452 * Points at file being currently printed into
453 */
454FILE *current_output = NULL;
455
456/*
457 * Command table imported from ntpdc_ops.c
458 */
459extern struct xcmd opcmds[];
460
461char const *progname;
462
463#ifdef NO_MAIN_ALLOWED
464#ifndef BUILD_AS_LIB
465CALL(ntpq,"ntpq",ntpqmain);
466
467void clear_globals(void)
468{
469	extern int ntp_optind;
470	showhostnames = 0;	/* don'tshow host names by default */
471	ntp_optind = 0;
472	server_entry = NULL;	/* server entry for ntp */
473	havehost = 0;		/* set to 1 when host open */
474	numassoc = 0;		/* number of cached associations */
475	numcmds = 0;
476	numhosts = 0;
477}
478#endif /* !BUILD_AS_LIB */
479#endif /* NO_MAIN_ALLOWED */
480
481/*
482 * main - parse arguments and handle options
483 */
484#ifndef NO_MAIN_ALLOWED
485int
486main(
487	int argc,
488	char *argv[]
489	)
490{
491	return ntpqmain(argc, argv);
492}
493#endif
494
495
496#ifndef BUILD_AS_LIB
497int
498ntpqmain(
499	int argc,
500	char *argv[]
501	)
502{
503	u_int ihost;
504	size_t icmd;
505
506
507#ifdef SYS_VXWORKS
508	clear_globals();
509	taskPrioritySet(taskIdSelf(), 100 );
510#endif
511
512	delay_time.l_ui = 0;
513	delay_time.l_uf = DEFDELAY;
514
515	init_lib();	/* sets up ipv4_works, ipv6_works */
516	ssl_applink();
517	init_auth();
518
519	/* Check to see if we have IPv6. Otherwise default to IPv4 */
520	if (!ipv6_works)
521		ai_fam_default = AF_INET;
522
523	/* Fixup keytype's help based on available digest names */
524
525	{
526	    char *list;
527	    char *msg;
528
529	    list = list_digest_names();
530
531	    for (icmd = 0; icmd < sizeof(builtins)/sizeof(*builtins); icmd++) {
532		if (strcmp("keytype", builtins[icmd].keyword) == 0) {
533		    break;
534		}
535	    }
536
537	    /* CID: 1295478 */
538	    /* This should only "trip" if "keytype" is removed from builtins */
539	    INSIST(icmd < sizeof(builtins)/sizeof(*builtins));
540
541#ifdef OPENSSL
542	    builtins[icmd].desc[0] = "digest-name";
543	    my_easprintf(&msg,
544			 "set key type to use for authenticated requests, one of:%s",
545			 list);
546#else
547	    builtins[icmd].desc[0] = "md5";
548	    my_easprintf(&msg,
549			 "set key type to use for authenticated requests (%s)",
550			 list);
551#endif
552	    builtins[icmd].comment = msg;
553	    free(list);
554	}
555
556	progname = argv[0];
557
558	{
559		int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
560		argc -= optct;
561		argv += optct;
562	}
563
564	/*
565	 * Process options other than -c and -p, which are specially
566	 * handled by ntpq_custom_opt_handler().
567	 */
568
569	debug = OPT_VALUE_SET_DEBUG_LEVEL;
570
571	if (HAVE_OPT(IPV4))
572		ai_fam_templ = AF_INET;
573	else if (HAVE_OPT(IPV6))
574		ai_fam_templ = AF_INET6;
575	else
576		ai_fam_templ = ai_fam_default;
577
578	if (HAVE_OPT(INTERACTIVE))
579		interactive = 1;
580
581	if (HAVE_OPT(NUMERIC))
582		showhostnames = 0;
583
584	if (HAVE_OPT(WIDE))
585		wideremote = 1;
586
587	old_rv = HAVE_OPT(OLD_RV);
588
589	drefid = OPT_VALUE_REFID;
590
591	if (0 == argc) {
592		ADDHOST(DEFHOST);
593	} else {
594		for (ihost = 0; ihost < (u_int)argc; ihost++) {
595			if ('-' == *argv[ihost]) {
596				//
597				// If I really cared I'd also check:
598				// 0 == argv[ihost][2]
599				//
600				// and there are other cases as well...
601				//
602				if ('4' == argv[ihost][1]) {
603					ai_fam_templ = AF_INET;
604					continue;
605				} else if ('6' == argv[ihost][1]) {
606					ai_fam_templ = AF_INET6;
607					continue;
608				} else {
609					// XXX Throw a usage error
610				}
611			}
612			ADDHOST(argv[ihost]);
613		}
614	}
615
616	if (numcmds == 0 && interactive == 0
617	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
618		interactive = 1;
619	}
620
621	set_ctrl_c_hook(on_ctrlc);
622#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
623	if (interactive)
624		push_ctrl_c_handler(abortcmd);
625#endif /* SYS_WINNT */
626
627	if (numcmds == 0) {
628		(void) openhost(chosts[0].name, chosts[0].fam);
629		getcmds();
630	} else {
631		for (ihost = 0; ihost < numhosts; ihost++) {
632			if (openhost(chosts[ihost].name, chosts[ihost].fam)) {
633				if (ihost && current_output)
634					fputc('\n', current_output);
635				for (icmd = 0; icmd < numcmds; icmd++) {
636					if (icmd && current_output)
637						fputc('\n', current_output);
638					docmd(ccmds[icmd]);
639				}
640			}
641		}
642	}
643#ifdef SYS_WINNT
644	WSACleanup();
645#endif /* SYS_WINNT */
646	return 0;
647}
648#endif /* !BUILD_AS_LIB */
649
650/*
651 * openhost - open a socket to a host
652 */
653static	int
654openhost(
655	const char *hname,
656	int	    fam
657	)
658{
659	const char svc[] = "ntp";
660	char temphost[LENHOSTNAME];
661	int a_info;
662	struct addrinfo hints, *ai;
663	sockaddr_u addr;
664	size_t octets;
665	const char *cp;
666	char name[LENHOSTNAME];
667
668	/*
669	 * We need to get by the [] if they were entered
670	 */
671	if (*hname == '[') {
672		cp = strchr(hname + 1, ']');
673		if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) {
674			errno = EINVAL;
675			warning("%s", "bad hostname/address");
676			return 0;
677		}
678		memcpy(name, hname + 1, octets);
679		name[octets] = '\0';
680		hname = name;
681	}
682
683	/*
684	 * First try to resolve it as an ip address and if that fails,
685	 * do a fullblown (dns) lookup. That way we only use the dns
686	 * when it is needed and work around some implementations that
687	 * will return an "IPv4-mapped IPv6 address" address if you
688	 * give it an IPv4 address to lookup.
689	 */
690	ZERO(hints);
691	hints.ai_family = fam;
692	hints.ai_protocol = IPPROTO_UDP;
693	hints.ai_socktype = SOCK_DGRAM;
694	hints.ai_flags = Z_AI_NUMERICHOST;
695	ai = NULL;
696
697	a_info = getaddrinfo(hname, svc, &hints, &ai);
698	if (a_info == EAI_NONAME
699#ifdef EAI_NODATA
700	    || a_info == EAI_NODATA
701#endif
702	   ) {
703		hints.ai_flags = AI_CANONNAME;
704#ifdef AI_ADDRCONFIG
705		hints.ai_flags |= AI_ADDRCONFIG;
706#endif
707		a_info = getaddrinfo(hname, svc, &hints, &ai);
708	}
709#ifdef AI_ADDRCONFIG
710	/* Some older implementations don't like AI_ADDRCONFIG. */
711	if (a_info == EAI_BADFLAGS) {
712		hints.ai_flags &= ~AI_ADDRCONFIG;
713		a_info = getaddrinfo(hname, svc, &hints, &ai);
714	}
715#endif
716	if (a_info != 0) {
717		fprintf(stderr, "%s\n", gai_strerror(a_info));
718		return 0;
719	}
720
721	INSIST(ai != NULL);
722	ZERO(addr);
723	octets = min(sizeof(addr), ai->ai_addrlen);
724	memcpy(&addr, ai->ai_addr, octets);
725
726	if (ai->ai_canonname == NULL) {
727		strlcpy(temphost, stoa(&addr), sizeof(temphost));
728		currenthostisnum = TRUE;
729	} else {
730		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
731		currenthostisnum = FALSE;
732	}
733
734	if (debug > 2)
735		printf("Opening host %s (%s)\n",
736			temphost,
737			(ai->ai_family == AF_INET)
738			? "AF_INET"
739			: (ai->ai_family == AF_INET6)
740			  ? "AF_INET6"
741			  : "AF-???"
742			);
743
744	if (havehost == 1) {
745		if (debug > 2)
746			printf("Closing old host %s\n", currenthost);
747		closesocket(sockfd);
748		havehost = 0;
749	}
750	strlcpy(currenthost, temphost, sizeof(currenthost));
751
752	/* port maps to the same location in both families */
753	s_port = NSRCPORT(&addr);
754#ifdef SYS_VXWORKS
755	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
756	if (ai->ai_family == AF_INET)
757		*(struct sockaddr_in *)&hostaddr=
758			*((struct sockaddr_in *)ai->ai_addr);
759	else
760		*(struct sockaddr_in6 *)&hostaddr=
761			*((struct sockaddr_in6 *)ai->ai_addr);
762#endif /* SYS_VXWORKS */
763
764#ifdef SYS_WINNT
765	{
766		int optionValue = SO_SYNCHRONOUS_NONALERT;
767		int err;
768
769		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
770				 (void *)&optionValue, sizeof(optionValue));
771		if (err) {
772			mfprintf(stderr,
773				 "setsockopt(SO_SYNCHRONOUS_NONALERT)"
774				 " error: %m\n");
775			freeaddrinfo(ai);
776			exit(1);
777		}
778	}
779#endif /* SYS_WINNT */
780
781	sockfd = socket(ai->ai_family, ai->ai_socktype,
782			ai->ai_protocol);
783	if (sockfd == INVALID_SOCKET) {
784		error("socket");
785		freeaddrinfo(ai);
786		return 0;
787	}
788
789
790#ifdef NEED_RCVBUF_SLOP
791# ifdef SO_RCVBUF
792	{ int rbufsize = DATASIZE + 2048;	/* 2K for slop */
793	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
794		       (void *)&rbufsize, sizeof(int)) == -1)
795		error("setsockopt");
796	}
797# endif
798#endif
799
800	if
801#ifdef SYS_VXWORKS
802	   (connect(sockfd, (struct sockaddr *)&hostaddr,
803		    sizeof(hostaddr)) == -1)
804#else
805	   (connect(sockfd, (struct sockaddr *)ai->ai_addr,
806		ai->ai_addrlen) == -1)
807#endif /* SYS_VXWORKS */
808	{
809		error("connect");
810		freeaddrinfo(ai);
811		return 0;
812	}
813	freeaddrinfo(ai);
814	havehost = 1;
815	numassoc = 0;
816
817	return 1;
818}
819
820
821static void
822dump_hex_printable(
823	const void *	data,
824	size_t		len
825	)
826{
827	/* every line shows at most 16 bytes, so we need a buffer of
828	 *   4 * 16 (2 xdigits, 1 char, one sep for xdigits)
829	 * + 2 * 1  (block separators)
830	 * + <LF> + <NUL>
831	 *---------------
832	 *  68 bytes
833	 */
834	static const char s_xdig[16] = "0123456789ABCDEF";
835
836	char lbuf[68];
837	int  ch, rowlen;
838	const u_char * cdata = data;
839	char *xptr, *pptr;
840
841	while (len) {
842		memset(lbuf, ' ', sizeof(lbuf));
843		xptr = lbuf;
844		pptr = lbuf + 3*16 + 2;
845
846		rowlen = (len > 16) ? 16 : (int)len;
847		len -= rowlen;
848
849		do {
850			ch = *cdata++;
851
852			*xptr++ = s_xdig[ch >> 4  ];
853			*xptr++ = s_xdig[ch & 0x0F];
854			if (++xptr == lbuf + 3*8)
855				++xptr;
856
857			*pptr++ = isprint(ch) ? (char)ch : '.';
858		} while (--rowlen);
859
860		*pptr++ = '\n';
861		*pptr   = '\0';
862		fputs(lbuf, stdout);
863	}
864}
865
866
867/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
868/*
869 * sendpkt - send a packet to the remote host
870 */
871static int
872sendpkt(
873	void *	xdata,
874	size_t	xdatalen
875	)
876{
877	if (debug >= 3)
878		printf("Sending %zu octets\n", xdatalen);
879
880	if (send(sockfd, xdata, xdatalen, 0) == -1) {
881		warning("write to %s failed", currenthost);
882		return -1;
883	}
884
885	if (debug >= 4) {
886		printf("Request packet:\n");
887		dump_hex_printable(xdata, xdatalen);
888	}
889	return 0;
890}
891
892/*
893 * getresponse - get a (series of) response packet(s) and return the data
894 */
895static int
896getresponse(
897	int opcode,
898	int associd,
899	u_short *rstatus,
900	size_t *rsize,
901	const char **rdata,
902	int timeo
903	)
904{
905	struct ntp_control rpkt;
906	struct sock_timeval tvo;
907	u_short offsets[MAXFRAGS+1];
908	u_short counts[MAXFRAGS+1];
909	u_short offset;
910	u_short count;
911	size_t numfrags;
912	size_t f;
913	size_t ff;
914	int seenlastfrag;
915	int shouldbesize;
916	fd_set fds;
917	int n;
918	int errcode;
919	/* absolute timeout checks. Not 'time_t' by intention! */
920	uint32_t tobase;	/* base value for timeout */
921	uint32_t tospan;	/* timeout span (max delay) */
922	uint32_t todiff;	/* current delay */
923
924	memset(offsets, 0, sizeof(offsets));
925	memset(counts , 0, sizeof(counts ));
926
927	/*
928	 * This is pretty tricky.  We may get between 1 and MAXFRAG packets
929	 * back in response to the request.  We peel the data out of
930	 * each packet and collect it in one long block.  When the last
931	 * packet in the sequence is received we'll know how much data we
932	 * should have had.  Note we use one long time out, should reconsider.
933	 */
934	*rsize = 0;
935	if (rstatus)
936		*rstatus = 0;
937	*rdata = (char *)pktdata;
938
939	numfrags = 0;
940	seenlastfrag = 0;
941
942	tobase = (uint32_t)time(NULL);
943
944	FD_ZERO(&fds);
945
946	/*
947	 * Loop until we have an error or a complete response.  Nearly all
948	 * code paths to loop again use continue.
949	 */
950	for (;;) {
951
952		if (numfrags == 0)
953			tvo = tvout;
954		else
955			tvo = tvsout;
956		tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0);
957
958		FD_SET(sockfd, &fds);
959		n = select(sockfd+1, &fds, NULL, NULL, &tvo);
960		if (n == -1) {
961#if !defined(SYS_WINNT) && defined(EINTR)
962			/* Windows does not know about EINTR (until very
963			 * recently) and the handling of console events
964			 * is *very* different from POSIX/UNIX signal
965			 * handling anyway.
966			 *
967			 * Under non-windows targets we map EINTR as
968			 * 'last packet was received' and try to exit
969			 * the receive sequence.
970			 */
971			if (errno == EINTR) {
972				seenlastfrag = 1;
973				goto maybe_final;
974			}
975#endif
976			warning("select fails");
977			return -1;
978		}
979
980		/*
981		 * Check if this is already too late. Trash the data and
982		 * fake a timeout if this is so.
983		 */
984		todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu;
985		if ((n > 0) && (todiff > tospan)) {
986			n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
987			n -= n; /* faked timeout return from 'select()',
988				 * execute RMW cycle on 'n'
989				 */
990		}
991
992		if (n <= 0) {
993			/*
994			 * Timed out.  Return what we have
995			 */
996			if (numfrags == 0) {
997				if (timeo)
998					fprintf(stderr,
999						"%s: timed out, nothing received\n",
1000						currenthost);
1001				return ERR_TIMEOUT;
1002			}
1003			if (timeo)
1004				fprintf(stderr,
1005					"%s: timed out with incomplete data\n",
1006					currenthost);
1007			if (debug) {
1008				fprintf(stderr,
1009					"ERR_INCOMPLETE: Received fragments:\n");
1010				for (f = 0; f < numfrags; f++)
1011					fprintf(stderr,
1012						"%2u: %5d %5d\t%3d octets\n",
1013						(u_int)f, offsets[f],
1014						offsets[f] +
1015						counts[f],
1016						counts[f]);
1017				fprintf(stderr,
1018					"last fragment %sreceived\n",
1019					(seenlastfrag)
1020					    ? ""
1021					    : "not ");
1022			}
1023			return ERR_INCOMPLETE;
1024		}
1025
1026		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
1027		if (n < 0) {
1028			warning("read");
1029			return -1;
1030		}
1031
1032		if (debug >= 4) {
1033			printf("Response packet:\n");
1034			dump_hex_printable(&rpkt, n);
1035		}
1036
1037		/*
1038		 * Check for format errors.  Bug proofing.
1039		 */
1040		if (n < (int)CTL_HEADER_LEN) {
1041			if (debug)
1042				printf("Short (%d byte) packet received\n", n);
1043			continue;
1044		}
1045		if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
1046		    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
1047			if (debug)
1048				printf("Packet received with version %d\n",
1049				       PKT_VERSION(rpkt.li_vn_mode));
1050			continue;
1051		}
1052		if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
1053			if (debug)
1054				printf("Packet received with mode %d\n",
1055				       PKT_MODE(rpkt.li_vn_mode));
1056			continue;
1057		}
1058		if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
1059			if (debug)
1060				printf("Received request packet, wanted response\n");
1061			continue;
1062		}
1063
1064		/*
1065		 * Check opcode and sequence number for a match.
1066		 * Could be old data getting to us.
1067		 */
1068		if (ntohs(rpkt.sequence) != sequence) {
1069			if (debug)
1070				printf("Received sequnce number %d, wanted %d\n",
1071				       ntohs(rpkt.sequence), sequence);
1072			continue;
1073		}
1074		if (CTL_OP(rpkt.r_m_e_op) != opcode) {
1075			if (debug)
1076			    printf(
1077				    "Received opcode %d, wanted %d (sequence number okay)\n",
1078				    CTL_OP(rpkt.r_m_e_op), opcode);
1079			continue;
1080		}
1081
1082		/*
1083		 * Check the error code.  If non-zero, return it.
1084		 */
1085		if (CTL_ISERROR(rpkt.r_m_e_op)) {
1086			errcode = (ntohs(rpkt.status) >> 8) & 0xff;
1087			if (CTL_ISMORE(rpkt.r_m_e_op))
1088				TRACE(1, ("Error code %d received on not-final packet\n",
1089					  errcode));
1090			if (errcode == CERR_UNSPEC)
1091				return ERR_UNSPEC;
1092			return errcode;
1093		}
1094
1095		/*
1096		 * Check the association ID to make sure it matches what
1097		 * we sent.
1098		 */
1099		if (ntohs(rpkt.associd) != associd) {
1100			TRACE(1, ("Association ID %d doesn't match expected %d\n",
1101				  ntohs(rpkt.associd), associd));
1102			/*
1103			 * Hack for silly fuzzballs which, at the time of writing,
1104			 * return an assID of sys.peer when queried for system variables.
1105			 */
1106#ifdef notdef
1107			continue;
1108#endif
1109		}
1110
1111		/*
1112		 * Collect offset and count.  Make sure they make sense.
1113		 */
1114		offset = ntohs(rpkt.offset);
1115		count = ntohs(rpkt.count);
1116
1117		/*
1118		 * validate received payload size is padded to next 32-bit
1119		 * boundary and no smaller than claimed by rpkt.count
1120		 */
1121		if (n & 0x3) {
1122			TRACE(1, ("Response packet not padded, size = %d\n",
1123				  n));
1124			continue;
1125		}
1126
1127		shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
1128
1129		if (n < shouldbesize) {
1130			printf("Response packet claims %u octets payload, above %ld received\n",
1131			       count, (long)(n - CTL_HEADER_LEN));
1132			return ERR_INCOMPLETE;
1133		}
1134
1135		if (debug >= 3 && shouldbesize > n) {
1136			u_int32 key;
1137			u_int32 *lpkt;
1138			int maclen;
1139
1140			/*
1141			 * Usually we ignore authentication, but for debugging purposes
1142			 * we watch it here.
1143			 */
1144			/* round to 8 octet boundary */
1145			shouldbesize = (shouldbesize + 7) & ~7;
1146
1147			maclen = n - shouldbesize;
1148			if (maclen >= (int)MIN_MAC_LEN) {
1149				printf(
1150					"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1151					n, shouldbesize, maclen);
1152				lpkt = (u_int32 *)&rpkt;
1153				printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1154				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1155				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1156				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1157				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1158				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1159				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1160				key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1161				printf("Authenticated with keyid %lu\n", (u_long)key);
1162				if (key != 0 && key != info_auth_keyid) {
1163					printf("We don't know that key\n");
1164				} else {
1165					if (authdecrypt(key, (u_int32 *)&rpkt,
1166					    n - maclen, maclen)) {
1167						printf("Auth okay!\n");
1168					} else {
1169						printf("Auth failed!\n");
1170					}
1171				}
1172			}
1173		}
1174
1175		TRACE(2, ("Got packet, size = %d\n", n));
1176		if (count > (n - CTL_HEADER_LEN)) {
1177			TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
1178				  count, (long)n - CTL_HEADER_LEN));
1179			continue;
1180		}
1181		if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1182			TRACE(1, ("Received count of 0 in non-final fragment\n"));
1183			continue;
1184		}
1185		if (offset + count > sizeof(pktdata)) {
1186			TRACE(1, ("Offset %u, count %u, too big for buffer\n",
1187				  offset, count));
1188			return ERR_TOOMUCH;
1189		}
1190		if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1191			TRACE(1, ("Received second last fragment packet\n"));
1192			continue;
1193		}
1194
1195		/*
1196		 * So far, so good.  Record this fragment, making sure it doesn't
1197		 * overlap anything.
1198		 */
1199		TRACE(2, ("Packet okay\n"));
1200
1201		if (numfrags > (MAXFRAGS - 1)) {
1202			TRACE(2, ("Number of fragments exceeds maximum %d\n",
1203				  MAXFRAGS - 1));
1204			return ERR_TOOMUCH;
1205		}
1206
1207		/*
1208		 * Find the position for the fragment relative to any
1209		 * previously received.
1210		 */
1211		for (f = 0;
1212		     f < numfrags && offsets[f] < offset;
1213		     f++) {
1214			/* empty body */ ;
1215		}
1216
1217		if (f < numfrags && offset == offsets[f]) {
1218			TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
1219				  count, offset, counts[f], offsets[f]));
1220			continue;
1221		}
1222
1223		if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1224			TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
1225				  offset, counts[f-1], offsets[f-1]));
1226			continue;
1227		}
1228
1229		if (f < numfrags && (offset + count) > offsets[f]) {
1230			TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
1231				  count, offset, offsets[f]));
1232			continue;
1233		}
1234
1235		for (ff = numfrags; ff > f; ff--) {
1236			offsets[ff] = offsets[ff-1];
1237			counts[ff] = counts[ff-1];
1238		}
1239		offsets[f] = offset;
1240		counts[f] = count;
1241		numfrags++;
1242
1243		/*
1244		 * Got that stuffed in right.  Figure out if this was the last.
1245		 * Record status info out of the last packet.
1246		 */
1247		if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1248			seenlastfrag = 1;
1249			if (rstatus != 0)
1250				*rstatus = ntohs(rpkt.status);
1251		}
1252
1253		/*
1254		 * Copy the data into the data buffer, and bump the
1255		 * timout base in case we need more.
1256		 */
1257		memcpy((char *)pktdata + offset, &rpkt.u, count);
1258		tobase = (uint32_t)time(NULL);
1259
1260		/*
1261		 * If we've seen the last fragment, look for holes in the sequence.
1262		 * If there aren't any, we're done.
1263		 */
1264#if !defined(SYS_WINNT) && defined(EINTR)
1265		maybe_final:
1266#endif
1267
1268		if (seenlastfrag && offsets[0] == 0) {
1269			for (f = 1; f < numfrags; f++)
1270				if (offsets[f-1] + counts[f-1] !=
1271				    offsets[f])
1272					break;
1273			if (f == numfrags) {
1274				*rsize = offsets[f-1] + counts[f-1];
1275				TRACE(1, ("%lu packets reassembled into response\n",
1276					  (u_long)numfrags));
1277				return 0;
1278			}
1279		}
1280	}  /* giant for (;;) collecting response packets */
1281}  /* getresponse() */
1282
1283
1284/*
1285 * sendrequest - format and send a request packet
1286 */
1287static int
1288sendrequest(
1289	int opcode,
1290	associd_t associd,
1291	int auth,
1292	size_t qsize,
1293	const char *qdata
1294	)
1295{
1296	struct ntp_control qpkt;
1297	size_t	pktsize;
1298	u_long	key_id;
1299	char *	pass;
1300	size_t	maclen;
1301
1302	/*
1303	 * Check to make sure the data will fit in one packet
1304	 */
1305	if (qsize > CTL_MAX_DATA_LEN) {
1306		fprintf(stderr,
1307			"***Internal error!  qsize (%zu) too large\n",
1308			qsize);
1309		return 1;
1310	}
1311
1312	/*
1313	 * Fill in the packet
1314	 */
1315	qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1316	qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1317	qpkt.sequence = htons(sequence);
1318	qpkt.status = 0;
1319	qpkt.associd = htons((u_short)associd);
1320	qpkt.offset = 0;
1321	qpkt.count = htons((u_short)qsize);
1322
1323	pktsize = CTL_HEADER_LEN;
1324
1325	/*
1326	 * If we have data, copy and pad it out to a 32-bit boundary.
1327	 */
1328	if (qsize > 0) {
1329		memcpy(&qpkt.u, qdata, (size_t)qsize);
1330		pktsize += qsize;
1331		while (pktsize & (sizeof(u_int32) - 1)) {
1332			qpkt.u.data[qsize++] = 0;
1333			pktsize++;
1334		}
1335	}
1336
1337	/*
1338	 * If it isn't authenticated we can just send it.  Otherwise
1339	 * we're going to have to think about it a little.
1340	 */
1341	if (!auth && !always_auth) {
1342		return sendpkt(&qpkt, pktsize);
1343	}
1344
1345	/*
1346	 * Pad out packet to a multiple of 8 octets to be sure
1347	 * receiver can handle it.
1348	 */
1349	while (pktsize & 7) {
1350		qpkt.u.data[qsize++] = 0;
1351		pktsize++;
1352	}
1353
1354	/*
1355	 * Get the keyid and the password if we don't have one.
1356	 */
1357	if (info_auth_keyid == 0) {
1358		key_id = getkeyid("Keyid: ");
1359		if (key_id == 0 || key_id > NTP_MAXKEY) {
1360			fprintf(stderr,
1361				"Invalid key identifier\n");
1362			return 1;
1363		}
1364		info_auth_keyid = key_id;
1365	}
1366	if (!authistrusted(info_auth_keyid)) {
1367		pass = getpass_keytype(info_auth_keytype);
1368		if ('\0' == pass[0]) {
1369			fprintf(stderr, "Invalid password\n");
1370			return 1;
1371		}
1372		authusekey(info_auth_keyid, info_auth_keytype,
1373			   (u_char *)pass);
1374		authtrust(info_auth_keyid, 1);
1375	}
1376
1377	/*
1378	 * Do the encryption.
1379	 */
1380	maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1381	if (!maclen) {
1382		fprintf(stderr, "Key not found\n");
1383		return 1;
1384	} else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1385		fprintf(stderr,
1386			"%zu octet MAC, %zu expected with %zu octet digest\n",
1387			maclen, (info_auth_hashlen + sizeof(keyid_t)),
1388			info_auth_hashlen);
1389		return 1;
1390	}
1391
1392	return sendpkt((char *)&qpkt, pktsize + maclen);
1393}
1394
1395
1396/*
1397 * show_error_msg - display the error text for a mode 6 error response.
1398 */
1399void
1400show_error_msg(
1401	int		m6resp,
1402	associd_t	associd
1403	)
1404{
1405	if (numhosts > 1)
1406		fprintf(stderr, "server=%s ", currenthost);
1407
1408	switch (m6resp) {
1409
1410	case CERR_BADFMT:
1411		fprintf(stderr,
1412		    "***Server reports a bad format request packet\n");
1413		break;
1414
1415	case CERR_PERMISSION:
1416		fprintf(stderr,
1417		    "***Server disallowed request (authentication?)\n");
1418		break;
1419
1420	case CERR_BADOP:
1421		fprintf(stderr,
1422		    "***Server reports a bad opcode in request\n");
1423		break;
1424
1425	case CERR_BADASSOC:
1426		fprintf(stderr,
1427		    "***Association ID %d unknown to server\n",
1428		    associd);
1429		break;
1430
1431	case CERR_UNKNOWNVAR:
1432		fprintf(stderr,
1433		    "***A request variable unknown to the server\n");
1434		break;
1435
1436	case CERR_BADVALUE:
1437		fprintf(stderr,
1438		    "***Server indicates a request variable was bad\n");
1439		break;
1440
1441	case ERR_UNSPEC:
1442		fprintf(stderr,
1443		    "***Server returned an unspecified error\n");
1444		break;
1445
1446	case ERR_TIMEOUT:
1447		fprintf(stderr, "***Request timed out\n");
1448		break;
1449
1450	case ERR_INCOMPLETE:
1451		fprintf(stderr,
1452		    "***Response from server was incomplete\n");
1453		break;
1454
1455	case ERR_TOOMUCH:
1456		fprintf(stderr,
1457		    "***Buffer size exceeded for returned data\n");
1458		break;
1459
1460	default:
1461		fprintf(stderr,
1462		    "***Server returns unknown error code %d\n",
1463		    m6resp);
1464	}
1465}
1466
1467/*
1468 * doquery - send a request and process the response, displaying
1469 *	     error messages for any error responses.
1470 */
1471int
1472doquery(
1473	int opcode,
1474	associd_t associd,
1475	int auth,
1476	size_t qsize,
1477	const char *qdata,
1478	u_short *rstatus,
1479	size_t *rsize,
1480	const char **rdata
1481	)
1482{
1483	return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
1484			 rsize, rdata, FALSE);
1485}
1486
1487
1488/*
1489 * doqueryex - send a request and process the response, optionally
1490 *	       displaying error messages for any error responses.
1491 */
1492int
1493doqueryex(
1494	int opcode,
1495	associd_t associd,
1496	int auth,
1497	size_t qsize,
1498	const char *qdata,
1499	u_short *rstatus,
1500	size_t *rsize,
1501	const char **rdata,
1502	int quiet
1503	)
1504{
1505	int res;
1506	int done;
1507
1508	/*
1509	 * Check to make sure host is open
1510	 */
1511	if (!havehost) {
1512		fprintf(stderr, "***No host open, use `host' command\n");
1513		return -1;
1514	}
1515
1516	done = 0;
1517	sequence++;
1518
1519    again:
1520	/*
1521	 * send a request
1522	 */
1523	res = sendrequest(opcode, associd, auth, qsize, qdata);
1524	if (res != 0)
1525		return res;
1526
1527	/*
1528	 * Get the response.  If we got a standard error, print a message
1529	 */
1530	res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1531
1532	if (res > 0) {
1533		if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1534			if (res == ERR_INCOMPLETE) {
1535				/*
1536				 * better bump the sequence so we don't
1537				 * get confused about differing fragments.
1538				 */
1539				sequence++;
1540			}
1541			done = 1;
1542			goto again;
1543		}
1544		if (!quiet)
1545			show_error_msg(res, associd);
1546
1547	}
1548	return res;
1549}
1550
1551
1552#ifndef BUILD_AS_LIB
1553/*
1554 * getcmds - read commands from the standard input and execute them
1555 */
1556static void
1557getcmds(void)
1558{
1559	char *	line;
1560	int	count;
1561
1562	ntp_readline_init(interactive ? prompt : NULL);
1563
1564	for (;;) {
1565		line = ntp_readline(&count);
1566		if (NULL == line)
1567			break;
1568		docmd(line);
1569		free(line);
1570	}
1571
1572	ntp_readline_uninit();
1573}
1574#endif /* !BUILD_AS_LIB */
1575
1576
1577#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1578/*
1579 * abortcmd - catch interrupts and abort the current command
1580 */
1581static int
1582abortcmd(void)
1583{
1584	if (current_output == stdout)
1585		(void) fflush(stdout);
1586	putc('\n', stderr);
1587	(void) fflush(stderr);
1588	if (jump) {
1589		jump = 0;
1590		LONGJMP(interrupt_buf, 1);
1591	}
1592	return TRUE;
1593}
1594#endif	/* !SYS_WINNT && !BUILD_AS_LIB */
1595
1596
1597#ifndef	BUILD_AS_LIB
1598/*
1599 * docmd - decode the command line and execute a command
1600 */
1601static void
1602docmd(
1603	const char *cmdline
1604	)
1605{
1606	char *tokens[1+MAXARGS+2];
1607	struct parse pcmd;
1608	int ntok;
1609	static int i;
1610	struct xcmd *xcmd;
1611
1612	/*
1613	 * Tokenize the command line.  If nothing on it, return.
1614	 */
1615	tokenize(cmdline, tokens, &ntok);
1616	if (ntok == 0)
1617	    return;
1618
1619	/*
1620	 * Find the appropriate command description.
1621	 */
1622	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1623	if (i == 0) {
1624		(void) fprintf(stderr, "***Command `%s' unknown\n",
1625			       tokens[0]);
1626		return;
1627	} else if (i >= 2) {
1628		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1629			       tokens[0]);
1630		return;
1631	}
1632
1633	/* Warn about ignored extra args */
1634	for (i = MAXARGS + 1; i < ntok ; ++i) {
1635		fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
1636	}
1637
1638	/*
1639	 * Save the keyword, then walk through the arguments, interpreting
1640	 * as we go.
1641	 */
1642	pcmd.keyword = tokens[0];
1643	pcmd.nargs = 0;
1644	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1645		if ((i+1) >= ntok) {
1646			if (!(xcmd->arg[i] & OPT)) {
1647				printusage(xcmd, stderr);
1648				return;
1649			}
1650			break;
1651		}
1652		if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1653			break;
1654		if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1655			return;
1656		pcmd.nargs++;
1657	}
1658
1659	i++;
1660	if (i < ntok && *tokens[i] == '>') {
1661		char *fname;
1662
1663		if (*(tokens[i]+1) != '\0')
1664			fname = tokens[i]+1;
1665		else if ((i+1) < ntok)
1666			fname = tokens[i+1];
1667		else {
1668			(void) fprintf(stderr, "***No file for redirect\n");
1669			return;
1670		}
1671
1672		current_output = fopen(fname, "w");
1673		if (current_output == NULL) {
1674			(void) fprintf(stderr, "***Error opening %s: ", fname);
1675			perror("");
1676			return;
1677		}
1678	} else {
1679		current_output = stdout;
1680	}
1681
1682	if (interactive) {
1683		if ( ! SETJMP(interrupt_buf)) {
1684			jump = 1;
1685			(xcmd->handler)(&pcmd, current_output);
1686			jump = 0;
1687		} else {
1688			fflush(current_output);
1689			fputs("\n >>> command aborted <<<\n", stderr);
1690			fflush(stderr);
1691		}
1692
1693	} else {
1694		jump = 0;
1695		(xcmd->handler)(&pcmd, current_output);
1696	}
1697	if ((NULL != current_output) && (stdout != current_output)) {
1698		(void)fclose(current_output);
1699		current_output = NULL;
1700	}
1701}
1702
1703
1704/*
1705 * tokenize - turn a command line into tokens
1706 *
1707 * SK: Modified to allow a quoted string
1708 *
1709 * HMS: If the first character of the first token is a ':' then (after
1710 * eating inter-token whitespace) the 2nd token is the rest of the line.
1711 */
1712
1713static void
1714tokenize(
1715	const char *line,
1716	char **tokens,
1717	int *ntok
1718	)
1719{
1720	register const char *cp;
1721	register char *sp;
1722	static char tspace[MAXLINE];
1723
1724	sp = tspace;
1725	cp = line;
1726	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1727		tokens[*ntok] = sp;
1728
1729		/* Skip inter-token whitespace */
1730		while (ISSPACE(*cp))
1731		    cp++;
1732
1733		/* If we're at EOL we're done */
1734		if (ISEOL(*cp))
1735		    break;
1736
1737		/* If this is the 2nd token and the first token begins
1738		 * with a ':', then just grab to EOL.
1739		 */
1740
1741		if (*ntok == 1 && tokens[0][0] == ':') {
1742			do {
1743				if (sp - tspace >= MAXLINE)
1744					goto toobig;
1745				*sp++ = *cp++;
1746			} while (!ISEOL(*cp));
1747		}
1748
1749		/* Check if this token begins with a double quote.
1750		 * If yes, continue reading till the next double quote
1751		 */
1752		else if (*cp == '\"') {
1753			++cp;
1754			do {
1755				if (sp - tspace >= MAXLINE)
1756					goto toobig;
1757				*sp++ = *cp++;
1758			} while ((*cp != '\"') && !ISEOL(*cp));
1759			/* HMS: a missing closing " should be an error */
1760		}
1761		else {
1762			do {
1763				if (sp - tspace >= MAXLINE)
1764					goto toobig;
1765				*sp++ = *cp++;
1766			} while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1767			/* HMS: Why check for a " in the previous line? */
1768		}
1769
1770		if (sp - tspace >= MAXLINE)
1771			goto toobig;
1772		*sp++ = '\0';
1773	}
1774	return;
1775
1776  toobig:
1777	*ntok = 0;
1778	fprintf(stderr,
1779		"***Line `%s' is too big\n",
1780		line);
1781	return;
1782}
1783
1784
1785/*
1786 * getarg - interpret an argument token
1787 */
1788static int
1789getarg(
1790	const char *str,
1791	int code,
1792	arg_v *argp
1793	)
1794{
1795	u_long ul;
1796
1797	switch (code & ~OPT) {
1798	case NTP_STR:
1799		argp->string = str;
1800		break;
1801
1802	case NTP_ADD:
1803		if (!getnetnum(str, &argp->netnum, NULL, 0))
1804			return 0;
1805		break;
1806
1807	case NTP_UINT:
1808		if ('&' == str[0]) {
1809			if (!atouint(&str[1], &ul)) {
1810				fprintf(stderr,
1811					"***Association index `%s' invalid/undecodable\n",
1812					str);
1813				return 0;
1814			}
1815			if (0 == numassoc) {
1816				dogetassoc(stdout);
1817				if (0 == numassoc) {
1818					fprintf(stderr,
1819						"***No associations found, `%s' unknown\n",
1820						str);
1821					return 0;
1822				}
1823			}
1824			ul = min(ul, numassoc);
1825			argp->uval = assoc_cache[ul - 1].assid;
1826			break;
1827		}
1828		if (!atouint(str, &argp->uval)) {
1829			fprintf(stderr, "***Illegal unsigned value %s\n",
1830				str);
1831			return 0;
1832		}
1833		break;
1834
1835	case NTP_INT:
1836		if (!atoint(str, &argp->ival)) {
1837			fprintf(stderr, "***Illegal integer value %s\n",
1838				str);
1839			return 0;
1840		}
1841		break;
1842
1843	case IP_VERSION:
1844		if (!strcmp("-6", str)) {
1845			argp->ival = 6;
1846		} else if (!strcmp("-4", str)) {
1847			argp->ival = 4;
1848		} else {
1849			fprintf(stderr, "***Version must be either 4 or 6\n");
1850			return 0;
1851		}
1852		break;
1853	}
1854
1855	return 1;
1856}
1857#endif	/* !BUILD_AS_LIB */
1858
1859
1860/*
1861 * findcmd - find a command in a command description table
1862 */
1863static int
1864findcmd(
1865	const char *	str,
1866	struct xcmd *	clist1,
1867	struct xcmd *	clist2,
1868	struct xcmd **	cmd
1869	)
1870{
1871	struct xcmd *cl;
1872	size_t clen;
1873	int nmatch;
1874	struct xcmd *nearmatch = NULL;
1875	struct xcmd *clist;
1876
1877	clen = strlen(str);
1878	nmatch = 0;
1879	if (clist1 != 0)
1880	    clist = clist1;
1881	else if (clist2 != 0)
1882	    clist = clist2;
1883	else
1884	    return 0;
1885
1886    again:
1887	for (cl = clist; cl->keyword != 0; cl++) {
1888		/* do a first character check, for efficiency */
1889		if (*str != *(cl->keyword))
1890		    continue;
1891		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1892			/*
1893			 * Could be extact match, could be approximate.
1894			 * Is exact if the length of the keyword is the
1895			 * same as the str.
1896			 */
1897			if (*((cl->keyword) + clen) == '\0') {
1898				*cmd = cl;
1899				return 1;
1900			}
1901			nmatch++;
1902			nearmatch = cl;
1903		}
1904	}
1905
1906	/*
1907	 * See if there is more to do.  If so, go again.  Sorry about the
1908	 * goto, too much looking at BSD sources...
1909	 */
1910	if (clist == clist1 && clist2 != 0) {
1911		clist = clist2;
1912		goto again;
1913	}
1914
1915	/*
1916	 * If we got extactly 1 near match, use it, else return number
1917	 * of matches.
1918	 */
1919	if (nmatch == 1) {
1920		*cmd = nearmatch;
1921		return 1;
1922	}
1923	return nmatch;
1924}
1925
1926
1927/*
1928 * getnetnum - given a host name, return its net number
1929 *	       and (optional) full name
1930 */
1931int
1932getnetnum(
1933	const char *hname,
1934	sockaddr_u *num,
1935	char *fullhost,
1936	int af
1937	)
1938{
1939	struct addrinfo hints, *ai = NULL;
1940
1941	ZERO(hints);
1942	hints.ai_flags = AI_CANONNAME;
1943#ifdef AI_ADDRCONFIG
1944	hints.ai_flags |= AI_ADDRCONFIG;
1945#endif
1946
1947	/*
1948	 * decodenetnum only works with addresses, but handles syntax
1949	 * that getaddrinfo doesn't:  [2001::1]:1234
1950	 */
1951	if (decodenetnum(hname, num)) {
1952		if (fullhost != NULL)
1953			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1954				    LENHOSTNAME, NULL, 0, 0);
1955		return 1;
1956	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1957		INSIST(sizeof(*num) >= ai->ai_addrlen);
1958		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1959		if (fullhost != NULL) {
1960			if (ai->ai_canonname != NULL)
1961				strlcpy(fullhost, ai->ai_canonname,
1962					LENHOSTNAME);
1963			else
1964				getnameinfo(&num->sa, SOCKLEN(num),
1965					    fullhost, LENHOSTNAME, NULL,
1966					    0, 0);
1967		}
1968		freeaddrinfo(ai);
1969		return 1;
1970	}
1971	fprintf(stderr, "***Can't find host %s\n", hname);
1972
1973	return 0;
1974}
1975
1976
1977/*
1978 * nntohost - convert network number to host name.  This routine enforces
1979 *	       the showhostnames setting.
1980 */
1981const char *
1982nntohost(
1983	sockaddr_u *netnum
1984	)
1985{
1986	return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
1987}
1988
1989
1990/*
1991 * nntohost_col - convert network number to host name in fixed width.
1992 *		  This routine enforces the showhostnames setting.
1993 *		  When displaying hostnames longer than the width,
1994 *		  the first part of the hostname is displayed.  When
1995 *		  displaying numeric addresses longer than the width,
1996 *		  Such as IPv6 addresses, the caller decides whether
1997 *		  the first or last of the numeric address is used.
1998 */
1999const char *
2000nntohost_col(
2001	sockaddr_u *	addr,
2002	size_t		width,
2003	int		preserve_lowaddrbits
2004	)
2005{
2006	const char *	out;
2007
2008	if (!showhostnames || SOCK_UNSPEC(addr)) {
2009		if (preserve_lowaddrbits)
2010			out = trunc_left(stoa(addr), width);
2011		else
2012			out = trunc_right(stoa(addr), width);
2013	} else if (ISREFCLOCKADR(addr)) {
2014		out = refnumtoa(addr);
2015	} else {
2016		out = trunc_right(socktohost(addr), width);
2017	}
2018	return out;
2019}
2020
2021
2022/*
2023 * nntohostp() is the same as nntohost() plus a :port suffix
2024 */
2025const char *
2026nntohostp(
2027	sockaddr_u *netnum
2028	)
2029{
2030	const char *	hostn;
2031	char *		buf;
2032
2033	if (!showhostnames || SOCK_UNSPEC(netnum))
2034		return sptoa(netnum);
2035	else if (ISREFCLOCKADR(netnum))
2036		return refnumtoa(netnum);
2037
2038	hostn = socktohost(netnum);
2039	LIB_GETBUF(buf);
2040	snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
2041
2042	return buf;
2043}
2044
2045/*
2046 * rtdatetolfp - decode an RT-11 date into an l_fp
2047 */
2048static int
2049rtdatetolfp(
2050	char *str,
2051	l_fp *lfp
2052	)
2053{
2054	register char *cp;
2055	register int i;
2056	struct calendar cal;
2057	char buf[4];
2058
2059	cal.yearday = 0;
2060
2061	/*
2062	 * An RT-11 date looks like:
2063	 *
2064	 * d[d]-Mth-y[y] hh:mm:ss
2065	 *
2066	 * (No docs, but assume 4-digit years are also legal...)
2067	 *
2068	 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
2069	 */
2070	cp = str;
2071	if (!isdigit(pgetc(cp))) {
2072		if (*cp == '-') {
2073			/*
2074			 * Catch special case
2075			 */
2076			L_CLR(lfp);
2077			return 1;
2078		}
2079		return 0;
2080	}
2081
2082	cal.monthday = (u_char) (*cp++ - '0');	/* ascii dependent */
2083	if (isdigit(pgetc(cp))) {
2084		cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
2085		cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
2086	}
2087
2088	if (*cp++ != '-')
2089	    return 0;
2090
2091	for (i = 0; i < 3; i++)
2092	    buf[i] = *cp++;
2093	buf[3] = '\0';
2094
2095	for (i = 0; i < 12; i++)
2096	    if (STREQ(buf, months[i]))
2097		break;
2098	if (i == 12)
2099	    return 0;
2100	cal.month = (u_char)(i + 1);
2101
2102	if (*cp++ != '-')
2103	    return 0;
2104
2105	if (!isdigit(pgetc(cp)))
2106	    return 0;
2107	cal.year = (u_short)(*cp++ - '0');
2108	if (isdigit(pgetc(cp))) {
2109		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2110		cal.year = (u_short)(*cp++ - '0');
2111	}
2112	if (isdigit(pgetc(cp))) {
2113		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2114		cal.year = (u_short)(cal.year + *cp++ - '0');
2115	}
2116	if (isdigit(pgetc(cp))) {
2117		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2118		cal.year = (u_short)(cal.year + *cp++ - '0');
2119	}
2120
2121	/*
2122	 * Catch special case.  If cal.year == 0 this is a zero timestamp.
2123	 */
2124	if (cal.year == 0) {
2125		L_CLR(lfp);
2126		return 1;
2127	}
2128
2129	if (*cp++ != ' ' || !isdigit(pgetc(cp)))
2130	    return 0;
2131	cal.hour = (u_char)(*cp++ - '0');
2132	if (isdigit(pgetc(cp))) {
2133		cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
2134		cal.hour = (u_char)(cal.hour + *cp++ - '0');
2135	}
2136
2137	if (*cp++ != ':' || !isdigit(pgetc(cp)))
2138	    return 0;
2139	cal.minute = (u_char)(*cp++ - '0');
2140	if (isdigit(pgetc(cp))) {
2141		cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
2142		cal.minute = (u_char)(cal.minute + *cp++ - '0');
2143	}
2144
2145	if (*cp++ != ':' || !isdigit(pgetc(cp)))
2146	    return 0;
2147	cal.second = (u_char)(*cp++ - '0');
2148	if (isdigit(pgetc(cp))) {
2149		cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
2150		cal.second = (u_char)(cal.second + *cp++ - '0');
2151	}
2152
2153	/*
2154	 * For RT-11, 1972 seems to be the pivot year
2155	 */
2156	if (cal.year < 72)
2157		cal.year += 2000;
2158	if (cal.year < 100)
2159		cal.year += 1900;
2160
2161	lfp->l_ui = caltontp(&cal);
2162	lfp->l_uf = 0;
2163	return 1;
2164}
2165
2166
2167/*
2168 * decodets - decode a timestamp into an l_fp format number, with
2169 *	      consideration of fuzzball formats.
2170 */
2171int
2172decodets(
2173	char *str,
2174	l_fp *lfp
2175	)
2176{
2177	char *cp;
2178	char buf[30];
2179	size_t b;
2180
2181	/*
2182	 * If it starts with a 0x, decode as hex.
2183	 */
2184	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2185		return hextolfp(str+2, lfp);
2186
2187	/*
2188	 * If it starts with a '"', try it as an RT-11 date.
2189	 */
2190	if (*str == '"') {
2191		cp = str + 1;
2192		b = 0;
2193		while ('"' != *cp && '\0' != *cp &&
2194		       b < COUNTOF(buf) - 1)
2195			buf[b++] = *cp++;
2196		buf[b] = '\0';
2197		return rtdatetolfp(buf, lfp);
2198	}
2199
2200	/*
2201	 * Might still be hex.  Check out the first character.  Talk
2202	 * about heuristics!
2203	 */
2204	if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2205		return hextolfp(str, lfp);
2206
2207	/*
2208	 * Try it as a decimal.  If this fails, try as an unquoted
2209	 * RT-11 date.  This code should go away eventually.
2210	 */
2211	if (atolfp(str, lfp))
2212		return 1;
2213
2214	return rtdatetolfp(str, lfp);
2215}
2216
2217
2218/*
2219 * decodetime - decode a time value.  It should be in milliseconds
2220 */
2221int
2222decodetime(
2223	char *str,
2224	l_fp *lfp
2225	)
2226{
2227	return mstolfp(str, lfp);
2228}
2229
2230
2231/*
2232 * decodeint - decode an integer
2233 */
2234int
2235decodeint(
2236	char *str,
2237	long *val
2238	)
2239{
2240	if (*str == '0') {
2241		if (*(str+1) == 'x' || *(str+1) == 'X')
2242		    return hextoint(str+2, (u_long *)val);
2243		return octtoint(str, (u_long *)val);
2244	}
2245	return atoint(str, val);
2246}
2247
2248
2249/*
2250 * decodeuint - decode an unsigned integer
2251 */
2252int
2253decodeuint(
2254	char *str,
2255	u_long *val
2256	)
2257{
2258	if (*str == '0') {
2259		if (*(str + 1) == 'x' || *(str + 1) == 'X')
2260			return (hextoint(str + 2, val));
2261		return (octtoint(str, val));
2262	}
2263	return (atouint(str, val));
2264}
2265
2266
2267/*
2268 * decodearr - decode an array of time values
2269 */
2270static int
2271decodearr(
2272	char *cp,
2273	int  *narr,
2274	l_fp *lfpa,
2275	int   amax
2276	)
2277{
2278	char *bp;
2279	char buf[60];
2280
2281	*narr = 0;
2282
2283	while (*narr < amax && *cp) {
2284		if (isspace(pgetc(cp))) {
2285			do
2286				++cp;
2287			while (*cp && isspace(pgetc(cp)));
2288		} else {
2289			bp = buf;
2290			do {
2291				if (bp != (buf + sizeof(buf) - 1))
2292					*bp++ = *cp;
2293				++cp;
2294			} while (*cp && !isspace(pgetc(cp)));
2295			*bp = '\0';
2296
2297			if (!decodetime(buf, lfpa))
2298				return 0;
2299			++(*narr);
2300			++lfpa;
2301		}
2302	}
2303	return 1;
2304}
2305
2306
2307/*
2308 * Finally, the built in command handlers
2309 */
2310
2311/*
2312 * help - tell about commands, or details of a particular command
2313 */
2314static void
2315help(
2316	struct parse *pcmd,
2317	FILE *fp
2318	)
2319{
2320	struct xcmd *xcp = NULL;	/* quiet warning */
2321	const char *cmd;
2322	const char *list[100];
2323	size_t word, words;
2324	size_t row, rows;
2325	size_t col, cols;
2326	size_t length;
2327
2328	if (pcmd->nargs == 0) {
2329		words = 0;
2330		for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2331			if (*(xcp->keyword) != '?' &&
2332			    words < COUNTOF(list))
2333				list[words++] = xcp->keyword;
2334		}
2335		for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2336			if (words < COUNTOF(list))
2337				list[words++] = xcp->keyword;
2338
2339		qsort((void *)list, words, sizeof(list[0]), helpsort);
2340		col = 0;
2341		for (word = 0; word < words; word++) {
2342			length = strlen(list[word]);
2343			col = max(col, length);
2344		}
2345
2346		cols = SCREENWIDTH / ++col;
2347		rows = (words + cols - 1) / cols;
2348
2349		fprintf(fp, "ntpq commands:\n");
2350
2351		for (row = 0; row < rows; row++) {
2352			for (word = row; word < words; word += rows)
2353				fprintf(fp, "%-*.*s", (int)col,
2354					(int)col - 1, list[word]);
2355			fprintf(fp, "\n");
2356		}
2357	} else {
2358		cmd = pcmd->argval[0].string;
2359		words = findcmd(cmd, builtins, opcmds, &xcp);
2360		if (words == 0) {
2361			fprintf(stderr,
2362				"Command `%s' is unknown\n", cmd);
2363			return;
2364		} else if (words >= 2) {
2365			fprintf(stderr,
2366				"Command `%s' is ambiguous\n", cmd);
2367			return;
2368		}
2369		fprintf(fp, "function: %s\n", xcp->comment);
2370		printusage(xcp, fp);
2371	}
2372}
2373
2374
2375/*
2376 * helpsort - do hostname qsort comparisons
2377 */
2378static int
2379helpsort(
2380	const void *t1,
2381	const void *t2
2382	)
2383{
2384	const char * const *	name1 = t1;
2385	const char * const *	name2 = t2;
2386
2387	return strcmp(*name1, *name2);
2388}
2389
2390
2391/*
2392 * printusage - print usage information for a command
2393 */
2394static void
2395printusage(
2396	struct xcmd *xcp,
2397	FILE *fp
2398	)
2399{
2400	register int i;
2401
2402	/* XXX: Do we need to warn about extra args here too? */
2403
2404	(void) fprintf(fp, "usage: %s", xcp->keyword);
2405	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2406		if (xcp->arg[i] & OPT)
2407		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2408		else
2409		    (void) fprintf(fp, " %s", xcp->desc[i]);
2410	}
2411	(void) fprintf(fp, "\n");
2412}
2413
2414
2415/*
2416 * timeout - set time out time
2417 */
2418static void
2419timeout(
2420	struct parse *pcmd,
2421	FILE *fp
2422	)
2423{
2424	int val;
2425
2426	if (pcmd->nargs == 0) {
2427		val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2428		(void) fprintf(fp, "primary timeout %d ms\n", val);
2429	} else {
2430		tvout.tv_sec = pcmd->argval[0].uval / 1000;
2431		tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2432			* 1000;
2433	}
2434}
2435
2436
2437/*
2438 * auth_delay - set delay for auth requests
2439 */
2440static void
2441auth_delay(
2442	struct parse *pcmd,
2443	FILE *fp
2444	)
2445{
2446	int isneg;
2447	u_long val;
2448
2449	if (pcmd->nargs == 0) {
2450		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2451		(void) fprintf(fp, "delay %lu ms\n", val);
2452	} else {
2453		if (pcmd->argval[0].ival < 0) {
2454			isneg = 1;
2455			val = (u_long)(-pcmd->argval[0].ival);
2456		} else {
2457			isneg = 0;
2458			val = (u_long)pcmd->argval[0].ival;
2459		}
2460
2461		delay_time.l_ui = val / 1000;
2462		val %= 1000;
2463		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
2464
2465		if (isneg)
2466		    L_NEG(&delay_time);
2467	}
2468}
2469
2470
2471/*
2472 * host - set the host we are dealing with.
2473 */
2474static void
2475host(
2476	struct parse *pcmd,
2477	FILE *fp
2478	)
2479{
2480	int i;
2481
2482	if (pcmd->nargs == 0) {
2483		if (havehost)
2484			(void) fprintf(fp, "current host is %s\n",
2485					   currenthost);
2486		else
2487			(void) fprintf(fp, "no current host\n");
2488		return;
2489	}
2490
2491	i = 0;
2492	ai_fam_templ = ai_fam_default;
2493	if (pcmd->nargs == 2) {
2494		if (!strcmp("-4", pcmd->argval[i].string))
2495			ai_fam_templ = AF_INET;
2496		else if (!strcmp("-6", pcmd->argval[i].string))
2497			ai_fam_templ = AF_INET6;
2498		else
2499			goto no_change;
2500		i = 1;
2501	}
2502	if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
2503		fprintf(fp, "current host set to %s\n", currenthost);
2504	} else {
2505    no_change:
2506		if (havehost)
2507			fprintf(fp, "current host remains %s\n",
2508				currenthost);
2509		else
2510			fprintf(fp, "still no current host\n");
2511	}
2512}
2513
2514
2515/*
2516 * poll - do one (or more) polls of the host via NTP
2517 */
2518/*ARGSUSED*/
2519static void
2520ntp_poll(
2521	struct parse *pcmd,
2522	FILE *fp
2523	)
2524{
2525	(void) fprintf(fp, "poll not implemented yet\n");
2526}
2527
2528
2529/*
2530 * showdrefid2str - return a string explanation of the value of drefid
2531 */
2532static const char *
2533showdrefid2str(void)
2534{
2535	switch (drefid) {
2536	    case REFID_HASH:
2537	    	return "hash";
2538	    case REFID_IPV4:
2539	    	return "ipv4";
2540	    default:
2541	    	return "Unknown";
2542	}
2543}
2544
2545
2546/*
2547 * drefid - display/change "display hash"
2548 */
2549static void
2550showdrefid(
2551	struct parse *pcmd,
2552	FILE *fp
2553	)
2554{
2555	if (pcmd->nargs == 0) {
2556		(void) fprintf(fp, "drefid value is %s\n", showdrefid2str());
2557		return;
2558	} else if (STREQ(pcmd->argval[0].string, "hash")) {
2559		drefid = REFID_HASH;
2560	} else if (STREQ(pcmd->argval[0].string, "ipv4")) {
2561		drefid = REFID_IPV4;
2562	} else {
2563		(void) fprintf(fp, "What?\n");
2564		return;
2565	}
2566	(void) fprintf(fp, "drefid value set to %s\n", showdrefid2str());
2567}
2568
2569
2570/*
2571 * keyid - get a keyid to use for authenticating requests
2572 */
2573static void
2574keyid(
2575	struct parse *pcmd,
2576	FILE *fp
2577	)
2578{
2579	if (pcmd->nargs == 0) {
2580		if (info_auth_keyid == 0)
2581		    (void) fprintf(fp, "no keyid defined\n");
2582		else
2583		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2584	} else {
2585		/* allow zero so that keyid can be cleared. */
2586		if(pcmd->argval[0].uval > NTP_MAXKEY)
2587		    (void) fprintf(fp, "Invalid key identifier\n");
2588		info_auth_keyid = pcmd->argval[0].uval;
2589	}
2590}
2591
2592/*
2593 * keytype - get type of key to use for authenticating requests
2594 */
2595static void
2596keytype(
2597	struct parse *pcmd,
2598	FILE *fp
2599	)
2600{
2601	const char *	digest_name;
2602	size_t		digest_len;
2603	int		key_type;
2604
2605	if (!pcmd->nargs) {
2606		fprintf(fp, "keytype is %s with %lu octet digests\n",
2607			keytype_name(info_auth_keytype),
2608			(u_long)info_auth_hashlen);
2609		return;
2610	}
2611
2612	digest_name = pcmd->argval[0].string;
2613	digest_len = 0;
2614	key_type = keytype_from_text(digest_name, &digest_len);
2615
2616	if (!key_type) {
2617		fprintf(fp, "keytype is not valid. "
2618#ifdef OPENSSL
2619			"Type \"help keytype\" for the available digest types.\n");
2620#else
2621			"Only \"md5\" is available.\n");
2622#endif
2623		return;
2624	}
2625
2626	info_auth_keytype = key_type;
2627	info_auth_hashlen = digest_len;
2628}
2629
2630
2631/*
2632 * passwd - get an authentication key
2633 */
2634/*ARGSUSED*/
2635static void
2636passwd(
2637	struct parse *pcmd,
2638	FILE *fp
2639	)
2640{
2641	const char *pass;
2642
2643	if (info_auth_keyid == 0) {
2644		info_auth_keyid = getkeyid("Keyid: ");
2645		if (info_auth_keyid == 0) {
2646			(void)fprintf(fp, "Keyid must be defined\n");
2647			return;
2648		}
2649	}
2650	if (pcmd->nargs >= 1)
2651		pass = pcmd->argval[0].string;
2652	else {
2653		pass = getpass_keytype(info_auth_keytype);
2654		if ('\0' == pass[0]) {
2655			fprintf(fp, "Password unchanged\n");
2656			return;
2657		}
2658	}
2659	authusekey(info_auth_keyid, info_auth_keytype,
2660		   (const u_char *)pass);
2661	authtrust(info_auth_keyid, 1);
2662}
2663
2664
2665/*
2666 * hostnames - set the showhostnames flag
2667 */
2668static void
2669hostnames(
2670	struct parse *pcmd,
2671	FILE *fp
2672	)
2673{
2674	if (pcmd->nargs == 0) {
2675		if (showhostnames)
2676		    (void) fprintf(fp, "hostnames being shown\n");
2677		else
2678		    (void) fprintf(fp, "hostnames not being shown\n");
2679	} else {
2680		if (STREQ(pcmd->argval[0].string, "yes"))
2681		    showhostnames = 1;
2682		else if (STREQ(pcmd->argval[0].string, "no"))
2683		    showhostnames = 0;
2684		else
2685		    (void)fprintf(stderr, "What?\n");
2686	}
2687}
2688
2689
2690
2691/*
2692 * setdebug - set/change debugging level
2693 */
2694static void
2695setdebug(
2696	struct parse *pcmd,
2697	FILE *fp
2698	)
2699{
2700	if (pcmd->nargs == 0) {
2701		(void) fprintf(fp, "debug level is %d\n", debug);
2702		return;
2703	} else if (STREQ(pcmd->argval[0].string, "no")) {
2704		debug = 0;
2705	} else if (STREQ(pcmd->argval[0].string, "more")) {
2706		debug++;
2707	} else if (STREQ(pcmd->argval[0].string, "less")) {
2708		debug--;
2709	} else {
2710		(void) fprintf(fp, "What?\n");
2711		return;
2712	}
2713	(void) fprintf(fp, "debug level set to %d\n", debug);
2714}
2715
2716
2717/*
2718 * quit - stop this nonsense
2719 */
2720/*ARGSUSED*/
2721static void
2722quit(
2723	struct parse *pcmd,
2724	FILE *fp
2725	)
2726{
2727	if (havehost)
2728	    closesocket(sockfd);	/* cleanliness next to godliness */
2729	exit(0);
2730}
2731
2732
2733/*
2734 * version - print the current version number
2735 */
2736/*ARGSUSED*/
2737static void
2738version(
2739	struct parse *pcmd,
2740	FILE *fp
2741	)
2742{
2743
2744	(void) fprintf(fp, "%s\n", Version);
2745	return;
2746}
2747
2748
2749/*
2750 * raw - set raw mode output
2751 */
2752/*ARGSUSED*/
2753static void
2754raw(
2755	struct parse *pcmd,
2756	FILE *fp
2757	)
2758{
2759	rawmode = 1;
2760	(void) fprintf(fp, "Output set to raw\n");
2761}
2762
2763
2764/*
2765 * cooked - set cooked mode output
2766 */
2767/*ARGSUSED*/
2768static void
2769cooked(
2770	struct parse *pcmd,
2771	FILE *fp
2772	)
2773{
2774	rawmode = 0;
2775	(void) fprintf(fp, "Output set to cooked\n");
2776	return;
2777}
2778
2779
2780/*
2781 * authenticate - always authenticate requests to this host
2782 */
2783static void
2784authenticate(
2785	struct parse *pcmd,
2786	FILE *fp
2787	)
2788{
2789	if (pcmd->nargs == 0) {
2790		if (always_auth) {
2791			(void) fprintf(fp,
2792				       "authenticated requests being sent\n");
2793		} else
2794		    (void) fprintf(fp,
2795				   "unauthenticated requests being sent\n");
2796	} else {
2797		if (STREQ(pcmd->argval[0].string, "yes")) {
2798			always_auth = 1;
2799		} else if (STREQ(pcmd->argval[0].string, "no")) {
2800			always_auth = 0;
2801		} else
2802		    (void)fprintf(stderr, "What?\n");
2803	}
2804}
2805
2806
2807/*
2808 * ntpversion - choose the NTP version to use
2809 */
2810static void
2811ntpversion(
2812	struct parse *pcmd,
2813	FILE *fp
2814	)
2815{
2816	if (pcmd->nargs == 0) {
2817		(void) fprintf(fp,
2818			       "NTP version being claimed is %d\n", pktversion);
2819	} else {
2820		if (pcmd->argval[0].uval < NTP_OLDVERSION
2821		    || pcmd->argval[0].uval > NTP_VERSION) {
2822			(void) fprintf(stderr, "versions %d to %d, please\n",
2823				       NTP_OLDVERSION, NTP_VERSION);
2824		} else {
2825			pktversion = (u_char) pcmd->argval[0].uval;
2826		}
2827	}
2828}
2829
2830
2831static void __attribute__((__format__(__printf__, 1, 0)))
2832vwarning(const char *fmt, va_list ap)
2833{
2834	int serrno = errno;
2835	(void) fprintf(stderr, "%s: ", progname);
2836	vfprintf(stderr, fmt, ap);
2837	(void) fprintf(stderr, ": %s\n", strerror(serrno));
2838}
2839
2840/*
2841 * warning - print a warning message
2842 */
2843static void __attribute__((__format__(__printf__, 1, 2)))
2844warning(
2845	const char *fmt,
2846	...
2847	)
2848{
2849	va_list ap;
2850	va_start(ap, fmt);
2851	vwarning(fmt, ap);
2852	va_end(ap);
2853}
2854
2855
2856/*
2857 * error - print a message and exit
2858 */
2859static void __attribute__((__format__(__printf__, 1, 2)))
2860error(
2861	const char *fmt,
2862	...
2863	)
2864{
2865	va_list ap;
2866	va_start(ap, fmt);
2867	vwarning(fmt, ap);
2868	va_end(ap);
2869	exit(1);
2870}
2871/*
2872 * getkeyid - prompt the user for a keyid to use
2873 */
2874static u_long
2875getkeyid(
2876	const char *keyprompt
2877	)
2878{
2879	int c;
2880	FILE *fi;
2881	char pbuf[20];
2882	size_t i;
2883	size_t ilim;
2884
2885#ifndef SYS_WINNT
2886	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2887#else
2888	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2889#endif /* SYS_WINNT */
2890		fi = stdin;
2891	else
2892		setbuf(fi, (char *)NULL);
2893	fprintf(stderr, "%s", keyprompt); fflush(stderr);
2894	for (i = 0, ilim = COUNTOF(pbuf) - 1;
2895	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
2896	     )
2897		pbuf[i++] = (char)c;
2898	pbuf[i] = '\0';
2899	if (fi != stdin)
2900		fclose(fi);
2901
2902	return (u_long) atoi(pbuf);
2903}
2904
2905
2906/*
2907 * atoascii - printable-ize possibly ascii data using the character
2908 *	      transformations cat -v uses.
2909 */
2910static void
2911atoascii(
2912	const char *in,
2913	size_t in_octets,
2914	char *out,
2915	size_t out_octets
2916	)
2917{
2918	const u_char *	pchIn;
2919	const u_char *	pchInLimit;
2920	u_char *	pchOut;
2921	u_char		c;
2922
2923	pchIn = (const u_char *)in;
2924	pchInLimit = pchIn + in_octets;
2925	pchOut = (u_char *)out;
2926
2927	if (NULL == pchIn) {
2928		if (0 < out_octets)
2929			*pchOut = '\0';
2930		return;
2931	}
2932
2933#define	ONEOUT(c)					\
2934do {							\
2935	if (0 == --out_octets) {			\
2936		*pchOut = '\0';				\
2937		return;					\
2938	}						\
2939	*pchOut++ = (c);				\
2940} while (0)
2941
2942	for (	; pchIn < pchInLimit; pchIn++) {
2943		c = *pchIn;
2944		if ('\0' == c)
2945			break;
2946		if (c & 0x80) {
2947			ONEOUT('M');
2948			ONEOUT('-');
2949			c &= 0x7f;
2950		}
2951		if (c < ' ') {
2952			ONEOUT('^');
2953			ONEOUT((u_char)(c + '@'));
2954		} else if (0x7f == c) {
2955			ONEOUT('^');
2956			ONEOUT('?');
2957		} else
2958			ONEOUT(c);
2959	}
2960	ONEOUT('\0');
2961
2962#undef ONEOUT
2963}
2964
2965
2966/*
2967 * makeascii - print possibly ascii data using the character
2968 *	       transformations that cat -v uses.
2969 */
2970void
2971makeascii(
2972	size_t length,
2973	const char *data,
2974	FILE *fp
2975	)
2976{
2977	const u_char *data_u_char;
2978	const u_char *cp;
2979	int c;
2980
2981	data_u_char = (const u_char *)data;
2982
2983	for (cp = data_u_char; cp < data_u_char + length; cp++) {
2984		c = (int)*cp;
2985		if (c & 0x80) {
2986			putc('M', fp);
2987			putc('-', fp);
2988			c &= 0x7f;
2989		}
2990
2991		if (c < ' ') {
2992			putc('^', fp);
2993			putc(c + '@', fp);
2994		} else if (0x7f == c) {
2995			putc('^', fp);
2996			putc('?', fp);
2997		} else
2998			putc(c, fp);
2999	}
3000}
3001
3002
3003/*
3004 * asciize - same thing as makeascii except add a newline
3005 */
3006void
3007asciize(
3008	int length,
3009	char *data,
3010	FILE *fp
3011	)
3012{
3013	makeascii(length, data, fp);
3014	putc('\n', fp);
3015}
3016
3017
3018/*
3019 * truncate string to fit clipping excess at end.
3020 *	"too long"	->	"too l"
3021 * Used for hostnames.
3022 */
3023const char *
3024trunc_right(
3025	const char *	src,
3026	size_t		width
3027	)
3028{
3029	size_t	sl;
3030	char *	out;
3031
3032
3033	sl = strlen(src);
3034	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
3035		LIB_GETBUF(out);
3036		memcpy(out, src, width);
3037		out[width] = '\0';
3038
3039		return out;
3040	}
3041
3042	return src;
3043}
3044
3045
3046/*
3047 * truncate string to fit by preserving right side and using '_' to hint
3048 *	"too long"	->	"_long"
3049 * Used for local IPv6 addresses, where low bits differentiate.
3050 */
3051const char *
3052trunc_left(
3053	const char *	src,
3054	size_t		width
3055	)
3056{
3057	size_t	sl;
3058	char *	out;
3059
3060
3061	sl = strlen(src);
3062	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
3063		LIB_GETBUF(out);
3064		out[0] = '_';
3065		memcpy(&out[1], &src[sl + 1 - width], width);
3066
3067		return out;
3068	}
3069
3070	return src;
3071}
3072
3073
3074/*
3075 * Some circular buffer space
3076 */
3077#define	CBLEN	80
3078#define	NUMCB	6
3079
3080char circ_buf[NUMCB][CBLEN];
3081int nextcb = 0;
3082
3083/* --------------------------------------------------------------------
3084 * Parsing a response value list
3085 *
3086 * This sounds simple (and it actually is not really hard) but it has
3087 * some pitfalls.
3088 *
3089 * Rule1: CR/LF is never embedded in an item
3090 * Rule2: An item is a name, optionally followed by a value
3091 * Rule3: The value is separated from the name by a '='
3092 * Rule4: Items are separated by a ','
3093 * Rule5: values can be quoted by '"', in which case they can contain
3094 *        arbitrary characters but *not* '"', CR and LF
3095 *
3096 * There are a few implementations out there that require a somewhat
3097 * relaxed attitude when parsing a value list, especially since we want
3098 * to copy names and values into local buffers. If these would overflow,
3099 * the item should be skipped without terminating the parsing sequence.
3100 *
3101 * Also, for empty values, there might be a '=' after the name or not;
3102 * we treat that equivalent.
3103 *
3104 * Parsing an item definitely breaks on a CR/LF. If an item is not
3105 * followed by a comma (','), parsing stops. In the middle of a quoted
3106 * character sequence CR/LF terminates the parsing finally without
3107 * returning a value.
3108 *
3109 * White space and other noise is ignored when parsing the data buffer;
3110 * only CR, LF, ',', '=' and '"' are characters with a special meaning.
3111 * White space is stripped from the names and values *after* working
3112 * through the buffer, before making the local copies. If whitespace
3113 * stripping results in an empty name, parsing resumes.
3114 */
3115
3116/*
3117 * nextvar parsing helpers
3118 */
3119
3120/* predicate: allowed chars inside a quoted string */
3121static int/*BOOL*/ cp_qschar(int ch)
3122{
3123	return ch && (ch != '"' && ch != '\r' && ch != '\n');
3124}
3125
3126/* predicate: allowed chars inside an unquoted string */
3127static int/*BOOL*/ cp_uqchar(int ch)
3128{
3129	return ch && (ch != ',' && ch != '"' && ch != '\r' && ch != '\n');
3130}
3131
3132/* predicate: allowed chars inside a value name */
3133static int/*BOOL*/ cp_namechar(int ch)
3134{
3135	return ch && (ch != ',' && ch != '=' && ch != '\r' && ch != '\n');
3136}
3137
3138/* predicate: characters *between* list items. We're relaxed here. */
3139static int/*BOOL*/ cp_ivspace(int ch)
3140{
3141	return (ch == ',' || (ch > 0 && ch <= ' '));
3142}
3143
3144/* get current character (or NUL when on end) */
3145static inline int
3146pf_getch(
3147	const char **	datap,
3148	const char *	endp
3149	)
3150{
3151	return (*datap != endp)
3152	    ? *(const unsigned char*)*datap
3153	    : '\0';
3154}
3155
3156/* get next character (or NUL when on end) */
3157static inline int
3158pf_nextch(
3159	const char **	datap,
3160	const char *	endp
3161	)
3162{
3163	return (*datap != endp && ++(*datap) != endp)
3164	    ? *(const unsigned char*)*datap
3165	    : '\0';
3166}
3167
3168static size_t
3169str_strip(
3170	const char ** 	datap,
3171	size_t		len
3172	)
3173{
3174	static const char empty[] = "";
3175
3176	if (*datap && len) {
3177		const char * cpl = *datap;
3178		const char * cpr = cpl + len;
3179
3180		while (cpl != cpr && *(const unsigned char*)cpl <= ' ')
3181			++cpl;
3182		while (cpl != cpr && *(const unsigned char*)(cpr - 1) <= ' ')
3183			--cpr;
3184		*datap = cpl;
3185		len = (size_t)(cpr - cpl);
3186	} else {
3187		*datap = empty;
3188		len = 0;
3189	}
3190	return len;
3191}
3192
3193static void
3194pf_error(
3195	const char *	what,
3196	const char *	where,
3197	const char *	whend
3198	)
3199{
3200#   ifndef BUILD_AS_LIB
3201
3202	FILE *	ofp = (debug > 0) ? stdout : stderr;
3203	size_t	len = (size_t)(whend - where);
3204
3205	if (len > 50) /* *must* fit into an 'int'! */
3206		len = 50;
3207	fprintf(ofp, "nextvar: %s: '%.*s'\n",
3208		what, (int)len, where);
3209
3210#   else  /*defined(BUILD_AS_LIB)*/
3211
3212	UNUSED_ARG(what);
3213	UNUSED_ARG(where);
3214	UNUSED_ARG(whend);
3215
3216#   endif /*defined(BUILD_AS_LIB)*/
3217}
3218
3219/*
3220 * nextvar - find the next variable in the buffer
3221 */
3222int/*BOOL*/
3223nextvar(
3224	size_t *datalen,
3225	const char **datap,
3226	char **vname,
3227	char **vvalue
3228	)
3229{
3230	enum PState 	{ sDone, sInit, sName, sValU, sValQ };
3231
3232	static char	name[MAXVARLEN], value[MAXVALLEN];
3233
3234	const char	*cp, *cpend;
3235	const char	*np, *vp;
3236	size_t		nlen, vlen;
3237	int		ch;
3238	enum PState	st;
3239
3240	cpend = *datap + *datalen;
3241
3242  again:
3243	np   = vp   = NULL;
3244	nlen = vlen = 0;
3245
3246	st = sInit;
3247	ch = pf_getch(datap, cpend);
3248
3249	while (st != sDone) {
3250		switch (st)
3251		{
3252		case sInit:	/* handle inter-item chars */
3253			while (cp_ivspace(ch))
3254				ch = pf_nextch(datap, cpend);
3255			if (cp_namechar(ch)) {
3256				np = *datap;
3257				cp = np;
3258				st = sName;
3259				ch = pf_nextch(datap, cpend);
3260			} else {
3261				goto final_done;
3262			}
3263			break;
3264
3265		case sName:	/* collect name */
3266			while (cp_namechar(ch))
3267				ch = pf_nextch(datap, cpend);
3268			nlen = (size_t)(*datap - np);
3269			if (ch == '=') {
3270				ch = pf_nextch(datap, cpend);
3271				vp = *datap;
3272				st = sValU;
3273			} else {
3274				if (ch != ',')
3275					*datap = cpend;
3276				st = sDone;
3277			}
3278			break;
3279
3280		case sValU:	/* collect unquoted part(s) of value */
3281			while (cp_uqchar(ch))
3282				ch = pf_nextch(datap, cpend);
3283			if (ch == '"') {
3284				ch = pf_nextch(datap, cpend);
3285				st = sValQ;
3286			} else {
3287				vlen = (size_t)(*datap - vp);
3288				if (ch != ',')
3289					*datap = cpend;
3290				st = sDone;
3291			}
3292			break;
3293
3294		case sValQ:	/* collect quoted part(s) of value */
3295			while (cp_qschar(ch))
3296				ch = pf_nextch(datap, cpend);
3297			if (ch == '"') {
3298				ch = pf_nextch(datap, cpend);
3299				st = sValU;
3300			} else {
3301				pf_error("no closing quote, stop", cp, cpend);
3302				goto final_done;
3303			}
3304			break;
3305
3306		default:
3307			pf_error("state machine error, stop", *datap, cpend);
3308			goto final_done;
3309		}
3310	}
3311
3312	/* If name or value do not fit their buffer, croak and start
3313	 * over. If there's no name at all after whitespace stripping,
3314	 * redo silently.
3315	 */
3316	nlen = str_strip(&np, nlen);
3317	vlen = str_strip(&vp, vlen);
3318
3319	if (nlen == 0) {
3320		goto again;
3321	}
3322	if (nlen >= sizeof(name)) {
3323		pf_error("runaway name", np, cpend);
3324		goto again;
3325	}
3326	if (vlen >= sizeof(value)) {
3327		pf_error("runaway value", vp, cpend);
3328		goto again;
3329	}
3330
3331	/* copy name and value into NUL-terminated buffers */
3332	memcpy(name, np, nlen);
3333	name[nlen] = '\0';
3334	*vname = name;
3335
3336	memcpy(value, vp, vlen);
3337	value[vlen] = '\0';
3338	*vvalue = value;
3339
3340	/* check if there's more to do or if we are finshed */
3341	*datalen = (size_t)(cpend - *datap);
3342	return TRUE;
3343
3344  final_done:
3345	*datap = cpend;
3346	*datalen = 0;
3347	return FALSE;
3348}
3349
3350
3351u_short
3352varfmt(const char * varname)
3353{
3354	u_int n;
3355
3356	for (n = 0; n < COUNTOF(cookedvars); n++)
3357		if (!strcmp(varname, cookedvars[n].varname))
3358			return cookedvars[n].fmt;
3359
3360	return PADDING;
3361}
3362
3363
3364/*
3365 * printvars - print variables returned in response packet
3366 */
3367void
3368printvars(
3369	size_t length,
3370	const char *data,
3371	int status,
3372	int sttype,
3373	int quiet,
3374	FILE *fp
3375	)
3376{
3377	if (rawmode)
3378	    rawprint(sttype, length, data, status, quiet, fp);
3379	else
3380	    cookedprint(sttype, length, data, status, quiet, fp);
3381}
3382
3383
3384/*
3385 * rawprint - do a printout of the data in raw mode
3386 */
3387static void
3388rawprint(
3389	int datatype,
3390	size_t length,
3391	const char *data,
3392	int status,
3393	int quiet,
3394	FILE *fp
3395	)
3396{
3397	const char *cp;
3398	const char *cpend;
3399
3400	/*
3401	 * Essentially print the data as is.  We reformat unprintables, though.
3402	 */
3403	cp = data;
3404	cpend = data + length;
3405
3406	if (!quiet)
3407		(void) fprintf(fp, "status=0x%04x,\n", status);
3408
3409	while (cp < cpend) {
3410		if (*cp == '\r') {
3411			/*
3412			 * If this is a \r and the next character is a
3413			 * \n, supress this, else pretty print it.  Otherwise
3414			 * just output the character.
3415			 */
3416			if (cp == (cpend - 1) || *(cp + 1) != '\n')
3417			    makeascii(1, cp, fp);
3418		} else if (isspace(pgetc(cp)) || isprint(pgetc(cp)))
3419			putc(*cp, fp);
3420		else
3421			makeascii(1, cp, fp);
3422		cp++;
3423	}
3424}
3425
3426
3427/*
3428 * Global data used by the cooked output routines
3429 */
3430int out_chars;		/* number of characters output */
3431int out_linecount;	/* number of characters output on this line */
3432
3433
3434/*
3435 * startoutput - get ready to do cooked output
3436 */
3437static void
3438startoutput(void)
3439{
3440	out_chars = 0;
3441	out_linecount = 0;
3442}
3443
3444
3445/*
3446 * output - output a variable=value combination
3447 */
3448static void
3449output(
3450	FILE *fp,
3451	const char *name,
3452	const char *value
3453	)
3454{
3455	int len;
3456
3457	/* strlen of "name=value" */
3458	len = size2int_sat(strlen(name) + 1 + strlen(value));
3459
3460	if (out_chars != 0) {
3461		out_chars += 2;
3462		if ((out_linecount + len + 2) > MAXOUTLINE) {
3463			fputs(",\n", fp);
3464			out_linecount = 0;
3465		} else {
3466			fputs(", ", fp);
3467			out_linecount += 2;
3468		}
3469	}
3470
3471	fputs(name, fp);
3472	putc('=', fp);
3473	fputs(value, fp);
3474	out_chars += len;
3475	out_linecount += len;
3476}
3477
3478
3479/*
3480 * endoutput - terminate a block of cooked output
3481 */
3482static void
3483endoutput(
3484	FILE *fp
3485	)
3486{
3487	if (out_chars != 0)
3488		putc('\n', fp);
3489}
3490
3491
3492/*
3493 * outputarr - output an array of values
3494 */
3495static void
3496outputarr(
3497	FILE *fp,
3498	char *name,
3499	int narr,
3500	l_fp *lfp,
3501	int issigned
3502	)
3503{
3504	char *bp;
3505	char *cp;
3506	size_t i;
3507	size_t len;
3508	char buf[256];
3509
3510	bp = buf;
3511	/*
3512	 * Hack to align delay and offset values
3513	 */
3514	for (i = (int)strlen(name); i < 11; i++)
3515		*bp++ = ' ';
3516
3517	for (i = narr; i > 0; i--) {
3518		if (i != (size_t)narr)
3519			*bp++ = ' ';
3520		cp = (issigned ? lfptoms(lfp, 2) : ulfptoms(lfp, 2));
3521		len = strlen(cp);
3522		if (len > 7) {
3523			cp[7] = '\0';
3524			len = 7;
3525		}
3526		while (len < 7) {
3527			*bp++ = ' ';
3528			len++;
3529		}
3530		while (*cp != '\0')
3531		    *bp++ = *cp++;
3532		lfp++;
3533	}
3534	*bp = '\0';
3535	output(fp, name, buf);
3536}
3537
3538static char *
3539tstflags(
3540	u_long val
3541	)
3542{
3543#	if CBLEN < 10
3544#	 error BLEN is too small -- increase!
3545#	endif
3546
3547	char *cp, *s;
3548	size_t cb, i;
3549	int l;
3550
3551	s = cp = circ_buf[nextcb];
3552	if (++nextcb >= NUMCB)
3553		nextcb = 0;
3554	cb = sizeof(circ_buf[0]);
3555
3556	l = snprintf(cp, cb, "%02lx", val);
3557	if (l < 0 || (size_t)l >= cb)
3558		goto fail;
3559	cp += l;
3560	cb -= l;
3561	if (!val) {
3562		l = strlcat(cp, " ok", cb);
3563		if ((size_t)l >= cb)
3564			goto fail;
3565		cp += l;
3566		cb -= l;
3567	} else {
3568		const char *sep;
3569
3570		sep = " ";
3571		for (i = 0; i < COUNTOF(tstflagnames); i++) {
3572			if (val & 0x1) {
3573				l = snprintf(cp, cb, "%s%s", sep,
3574					     tstflagnames[i]);
3575				if (l < 0)
3576					goto fail;
3577				if ((size_t)l >= cb) {
3578					cp += cb - 4;
3579					cb = 4;
3580					l = strlcpy (cp, "...", cb);
3581					cp += l;
3582					cb -= l;
3583					break;
3584				}
3585				sep = ", ";
3586				cp += l;
3587				cb -= l;
3588			}
3589			val >>= 1;
3590		}
3591	}
3592
3593	return s;
3594
3595  fail:
3596	*cp = '\0';
3597	return s;
3598}
3599
3600/*
3601 * cookedprint - output variables in cooked mode
3602 */
3603static void
3604cookedprint(
3605	int datatype,
3606	size_t length,
3607	const char *data,
3608	int status,
3609	int quiet,
3610	FILE *fp
3611	)
3612{
3613	char *name;
3614	char *value;
3615	char output_raw;
3616	int fmt;
3617	l_fp lfp;
3618	sockaddr_u hval;
3619	u_long uval;
3620	int narr;
3621	size_t len;
3622	l_fp lfparr[8];
3623	char b[12];
3624	char bn[2 * MAXVARLEN];
3625	char bv[2 * MAXVALLEN];
3626
3627	UNUSED_ARG(datatype);
3628
3629	if (!quiet)
3630		fprintf(fp, "status=%04x %s,\n", status,
3631			statustoa(datatype, status));
3632
3633	startoutput();
3634	while (nextvar(&length, &data, &name, &value)) {
3635		fmt = varfmt(name);
3636		output_raw = 0;
3637		switch (fmt) {
3638
3639		case PADDING:
3640			output_raw = '*';
3641			break;
3642
3643		case TS:
3644			if (!value || !decodets(value, &lfp))
3645				output_raw = '?';
3646			else
3647				output(fp, name, prettydate(&lfp));
3648			break;
3649
3650		case HA:	/* fallthru */
3651		case NA:
3652			if (!value || !decodenetnum(value, &hval)) {
3653				output_raw = '?';
3654			} else if (fmt == HA){
3655				output(fp, name, nntohost(&hval));
3656			} else {
3657				output(fp, name, stoa(&hval));
3658			}
3659			break;
3660
3661		case RF:
3662			if (!value) {
3663				output_raw = '?';
3664			} else if (decodenetnum(value, &hval)) {
3665				if (datatype == TYPE_CLOCK && IS_IPV4(&hval)) {
3666					/*
3667					 * Workaround to override numeric refid formats
3668					 * for refclocks received from faulty nptd servers
3669					 * and output them as text.
3670					 */
3671					int i;
3672					unsigned char *str = (unsigned char *)&(hval.sa4).sin_addr;
3673					char refid_buf[5];
3674					for (i=0; i<4 && str[i]; i++)
3675						refid_buf[i] = (isprint(str[i]) ? str[i] : '?');
3676					refid_buf[i] = 0; /* Null terminator */
3677					output(fp, name, refid_buf);
3678				} else if (ISREFCLOCKADR(&hval)) {
3679					output(fp, name, refnumtoa(&hval));
3680				} else {
3681					if (drefid == REFID_IPV4) {
3682						output(fp, name, stoa(&hval));
3683					} else {
3684						char refid_buf[12];
3685						snprintf (refid_buf, sizeof(refid_buf),
3686							  "0x%08x", ntohl(addr2refid(&hval)));
3687						output(fp, name, refid_buf);
3688					}
3689				}
3690			} else if (strlen(value) <= 4) {
3691				output(fp, name, value);
3692			} else {
3693				output_raw = '?';
3694			}
3695			break;
3696
3697		case LP:
3698			if (!value || !decodeuint(value, &uval) || uval > 3) {
3699				output_raw = '?';
3700			} else {
3701				b[0] = (0x2 & uval)
3702					   ? '1'
3703					   : '0';
3704				b[1] = (0x1 & uval)
3705					   ? '1'
3706					   : '0';
3707				b[2] = '\0';
3708				output(fp, name, b);
3709			}
3710			break;
3711
3712		case OC:
3713			if (!value || !decodeuint(value, &uval)) {
3714				output_raw = '?';
3715			} else {
3716				snprintf(b, sizeof(b), "%03lo", uval);
3717				output(fp, name, b);
3718			}
3719			break;
3720
3721		case AU:
3722		case AS:
3723			if (!value || !decodearr(value, &narr, lfparr, 8))
3724				output_raw = '?';
3725			else
3726				outputarr(fp, name, narr, lfparr, (fmt==AS));
3727			break;
3728
3729		case FX:
3730			if (!value || !decodeuint(value, &uval))
3731				output_raw = '?';
3732			else
3733				output(fp, name, tstflags(uval));
3734			break;
3735
3736		case SN:
3737			if (!value)
3738				output_raw = '?';
3739			else if (isdigit(*value)) {	/* number without sign */
3740				bv[0] = '+';
3741				atoascii (value, MAXVALLEN, bv+1, sizeof(bv)-1);
3742				output(fp, name, bv);
3743			} else
3744				output_raw = '*';		/* output as-is */
3745			break;
3746
3747		default:
3748			fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
3749				name, value, fmt);
3750			output_raw = '?';
3751			break;
3752		}
3753
3754		if (output_raw != 0) {
3755			/* TALOS-CAN-0063: avoid buffer overrun */
3756			atoascii(name, MAXVARLEN, bn, sizeof(bn));
3757			if (output_raw != '*') {
3758				atoascii(value, MAXVALLEN,
3759					 bv, sizeof(bv) - 1);
3760				len = strlen(bv);
3761				bv[len] = output_raw;
3762				bv[len+1] = '\0';
3763			} else {
3764				atoascii(value, MAXVALLEN,
3765					 bv, sizeof(bv));
3766			}
3767			output(fp, bn, bv);
3768		}
3769	}
3770	endoutput(fp);
3771}
3772
3773
3774/*
3775 * sortassoc - sort associations in the cache into ascending order
3776 */
3777void
3778sortassoc(void)
3779{
3780	if (numassoc > 1)
3781		qsort(assoc_cache, (size_t)numassoc,
3782		      sizeof(assoc_cache[0]), &assoccmp);
3783}
3784
3785
3786/*
3787 * assoccmp - compare two associations
3788 */
3789static int
3790assoccmp(
3791	const void *t1,
3792	const void *t2
3793	)
3794{
3795	const struct association *ass1 = t1;
3796	const struct association *ass2 = t2;
3797
3798	if (ass1->assid < ass2->assid)
3799		return -1;
3800	if (ass1->assid > ass2->assid)
3801		return 1;
3802	return 0;
3803}
3804
3805
3806/*
3807 * grow_assoc_cache() - enlarge dynamic assoc_cache array
3808 *
3809 * The strategy is to add an assumed 4k page size at a time, leaving
3810 * room for malloc() bookkeeping overhead equivalent to 4 pointers.
3811 */
3812void
3813grow_assoc_cache(void)
3814{
3815	static size_t	prior_sz;
3816	size_t		new_sz;
3817
3818	new_sz = prior_sz + 4 * 1024;
3819	if (0 == prior_sz) {
3820		new_sz -= 4 * sizeof(void *);
3821	}
3822	assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
3823	prior_sz = new_sz;
3824	assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0]));
3825}
3826
3827
3828/*
3829 * ntpq_custom_opt_handler - autoopts handler for -c and -p
3830 *
3831 * By default, autoopts loses the relative order of -c and -p options
3832 * on the command line.  This routine replaces the default handler for
3833 * those routines and builds a list of commands to execute preserving
3834 * the order.
3835 */
3836void
3837ntpq_custom_opt_handler(
3838	tOptions *pOptions,
3839	tOptDesc *pOptDesc
3840	)
3841{
3842	switch (pOptDesc->optValue) {
3843
3844	default:
3845		fprintf(stderr,
3846			"ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3847			pOptDesc->optValue, pOptDesc->optValue);
3848		exit(1);
3849
3850	case 'c':
3851		ADDCMD(pOptDesc->pzLastArg);
3852		break;
3853
3854	case 'p':
3855		ADDCMD("peers");
3856		break;
3857	}
3858}
3859/*
3860 * Obtain list of digest names
3861 */
3862
3863#if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED)
3864# if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
3865#  define HAVE_EVP_MD_DO_ALL_SORTED
3866# endif
3867#endif
3868
3869#ifdef OPENSSL
3870# ifdef HAVE_EVP_MD_DO_ALL_SORTED
3871#  define K_PER_LINE	8
3872#  define K_NL_PFX_STR	"\n    "
3873#  define K_DELIM_STR	", "
3874
3875struct hstate {
3876	char *list;
3877	const char **seen;
3878	int idx;
3879};
3880
3881
3882#  ifndef BUILD_AS_LIB
3883static void
3884list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg)
3885{
3886	size_t 	       len, n;
3887	const char    *name, **seen;
3888	struct hstate *hstate = arg;
3889	const char    *cp;
3890
3891	/* m is MD obj, from is name or alias, to is base name for alias */
3892	if (!m || !from || to)
3893		return; /* Ignore aliases */
3894
3895	/* Discard MACs that NTP won't accept. */
3896	/* Keep this consistent with keytype_from_text() in ssl_init.c. */
3897	if (EVP_MD_size(m) > (MAX_MAC_LEN - sizeof(keyid_t)))
3898		return;
3899
3900	name = EVP_MD_name(m);
3901
3902	/* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
3903
3904	for (cp = name; *cp; cp++)
3905		if (islower((unsigned char)*cp))
3906			return;
3907
3908	len = (cp - name) + 1;
3909
3910	/* There are duplicates.  Discard if name has been seen. */
3911
3912	for (seen = hstate->seen; *seen; seen++)
3913		if (!strcmp(*seen, name))
3914			return;
3915
3916	n = (seen - hstate->seen) + 2;
3917	hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
3918	hstate->seen[n-2] = name;
3919	hstate->seen[n-1] = NULL;
3920
3921	if (hstate->list != NULL)
3922		len += strlen(hstate->list);
3923
3924	len += (hstate->idx >= K_PER_LINE)
3925	    ? strlen(K_NL_PFX_STR)
3926	    : strlen(K_DELIM_STR);
3927
3928	if (hstate->list == NULL) {
3929		hstate->list = (char *)emalloc(len);
3930		hstate->list[0] = '\0';
3931	} else {
3932		hstate->list = (char *)erealloc(hstate->list, len);
3933	}
3934
3935	sprintf(hstate->list + strlen(hstate->list), "%s%s",
3936		((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR),
3937		name);
3938
3939	if (hstate->idx >= K_PER_LINE)
3940		hstate->idx = 1;
3941	else
3942		hstate->idx++;
3943}
3944#  endif /* !defined(BUILD_AS_LIB) */
3945
3946#  ifndef BUILD_AS_LIB
3947/* Insert CMAC into SSL digests list */
3948static char *
3949insert_cmac(char *list)
3950{
3951#ifdef ENABLE_CMAC
3952	int insert;
3953	size_t len;
3954
3955
3956	/* If list empty, we need to insert CMAC on new line */
3957	insert = (!list || !*list);
3958
3959	if (insert) {
3960		len = strlen(K_NL_PFX_STR) + strlen(CMAC);
3961		list = (char *)erealloc(list, len + 1);
3962		sprintf(list, "%s%s", K_NL_PFX_STR, CMAC);
3963	} else {	/* List not empty */
3964		/* Check if CMAC already in list - future proofing */
3965		const char *cmac_sn;
3966		char *cmac_p;
3967
3968		cmac_sn = OBJ_nid2sn(NID_cmac);
3969		cmac_p = list;
3970		insert = cmac_sn != NULL && *cmac_sn != '\0';
3971
3972		/* CMAC in list if found, followed by nul char or ',' */
3973		while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) {
3974			cmac_p += strlen(cmac_sn);
3975			/* Still need to insert if not nul and not ',' */
3976			insert = *cmac_p && ',' != *cmac_p;
3977		}
3978
3979		/* Find proper insertion point */
3980		if (insert) {
3981			char *last_nl;
3982			char *point;
3983			char *delim;
3984			int found;
3985
3986			/* Default to start if list empty */
3987			found = 0;
3988			delim = list;
3989			len = strlen(list);
3990
3991			/* While new lines */
3992			while (delim < list + len && *delim &&
3993			       !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) {
3994				point = delim + strlen(K_NL_PFX_STR);
3995
3996				/* While digest names on line */
3997				while (point < list + len && *point) {
3998					/* Another digest after on same or next line? */
3999					delim = strstr( point, K_DELIM_STR);
4000					last_nl = strstr( point, K_NL_PFX_STR);
4001
4002					/* No - end of list */
4003					if (!delim && !last_nl) {
4004						delim = list + len;
4005					} else
4006						/* New line and no delim or before delim? */
4007						if (last_nl && (!delim || last_nl < delim)) {
4008							delim = last_nl;
4009						}
4010
4011					/* Found insertion point where CMAC before entry? */
4012					if (strncmp(CMAC, point, delim - point) < 0) {
4013						found = 1;
4014						break;
4015					}
4016
4017					if (delim < list + len && *delim &&
4018					    !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) {
4019						point += strlen(K_DELIM_STR);
4020					} else {
4021						break;
4022					}
4023				} /* While digest names on line */
4024			} /* While new lines */
4025
4026			/* If found in list */
4027			if (found) {
4028				/* insert cmac and delim */
4029				/* Space for list could move - save offset */
4030				ptrdiff_t p_offset = point - list;
4031				len += strlen(CMAC) + strlen(K_DELIM_STR);
4032				list = (char *)erealloc(list, len + 1);
4033				point = list + p_offset;
4034				/* move to handle src/dest overlap */
4035				memmove(point + strlen(CMAC) + strlen(K_DELIM_STR),
4036					point, strlen(point) + 1);
4037				strncpy(point, CMAC, strlen(CMAC));
4038				strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR));
4039			} else {	/* End of list */
4040				/* append delim and cmac */
4041				len += strlen(K_DELIM_STR) + strlen(CMAC);
4042				list = (char *)erealloc(list, len + 1);
4043				strcpy(list + strlen(list), K_DELIM_STR);
4044				strcpy(list + strlen(list), CMAC);
4045			}
4046		} /* insert */
4047	} /* List not empty */
4048#endif /*ENABLE_CMAC*/
4049	return list;
4050}
4051#  endif /* !defined(BUILD_AS_LIB) */
4052# endif
4053#endif
4054
4055
4056#ifndef BUILD_AS_LIB
4057static char *
4058list_digest_names(void)
4059{
4060	char *list = NULL;
4061
4062#ifdef OPENSSL
4063# ifdef HAVE_EVP_MD_DO_ALL_SORTED
4064	struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
4065
4066	/* replace calloc(1, sizeof(const char *)) */
4067	hstate.seen = (const char **)emalloc_zero(sizeof(const char *));
4068
4069	INIT_SSL();
4070	EVP_MD_do_all_sorted(list_md_fn, &hstate);
4071	list = hstate.list;
4072	free(hstate.seen);
4073
4074	list = insert_cmac(list);	/* Insert CMAC into SSL digests list */
4075
4076# else
4077	list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
4078	strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
4079# endif
4080#else
4081	list = (char *)emalloc(sizeof("md5"));
4082	strcpy(list, "md5");
4083#endif
4084
4085	return list;
4086}
4087#endif /* !defined(BUILD_AS_LIB) */
4088
4089#define CTRLC_STACK_MAX 4
4090static volatile size_t		ctrlc_stack_len = 0;
4091static volatile Ctrl_C_Handler	ctrlc_stack[CTRLC_STACK_MAX];
4092
4093
4094
4095int/*BOOL*/
4096push_ctrl_c_handler(
4097	Ctrl_C_Handler func
4098	)
4099{
4100	size_t size = ctrlc_stack_len;
4101	if (func && (size < CTRLC_STACK_MAX)) {
4102		ctrlc_stack[size] = func;
4103		ctrlc_stack_len = size + 1;
4104		return TRUE;
4105	}
4106	return FALSE;
4107}
4108
4109int/*BOOL*/
4110pop_ctrl_c_handler(
4111	Ctrl_C_Handler func
4112	)
4113{
4114	size_t size = ctrlc_stack_len;
4115	if (size) {
4116		--size;
4117		if (func == NULL || func == ctrlc_stack[size]) {
4118			ctrlc_stack_len = size;
4119			return TRUE;
4120		}
4121	}
4122	return FALSE;
4123}
4124
4125#ifndef BUILD_AS_LIB
4126static void
4127on_ctrlc(void)
4128{
4129	size_t size = ctrlc_stack_len;
4130	while (size)
4131		if ((*ctrlc_stack[--size])())
4132			break;
4133}
4134#endif /* !defined(BUILD_AS_LIB) */
4135
4136#ifndef BUILD_AS_LIB
4137static int
4138my_easprintf(
4139	char ** 	ppinto,
4140	const char *	fmt   ,
4141	...
4142	)
4143{
4144	va_list	va;
4145	int	prc;
4146	size_t	len = 128;
4147	char *	buf = emalloc(len);
4148
4149  again:
4150	/* Note: we expect the memory allocation to fail long before the
4151	 * increment in buffer size actually overflows.
4152	 */
4153	buf = (buf) ? erealloc(buf, len) : emalloc(len);
4154
4155	va_start(va, fmt);
4156	prc = vsnprintf(buf, len, fmt, va);
4157	va_end(va);
4158
4159	if (prc < 0) {
4160		/* might be very old vsnprintf. Or actually MSVC... */
4161		len += len >> 1;
4162		goto again;
4163	}
4164	if ((size_t)prc >= len) {
4165		/* at least we have the proper size now... */
4166		len = (size_t)prc + 1;
4167		goto again;
4168	}
4169	if ((size_t)prc < (len - 32))
4170		buf = erealloc(buf, (size_t)prc + 1);
4171	*ppinto = buf;
4172	return prc;
4173}
4174#endif /* !defined(BUILD_AS_LIB) */
4175