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