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