ntpq.c revision 298770
152400Sbillf/*
252400Sbillf * ntpq - query an NTP server using mode 6 commands
352400Sbillf */
452400Sbillf#include <config.h>
552400Sbillf#include <stdio.h>
652400Sbillf#include <ctype.h>
752400Sbillf#include <signal.h>
873651Sdougb#include <setjmp.h>
973651Sdougb#include <sys/types.h>
1052400Sbillf#include <sys/time.h>
1152495Sbillf#ifdef HAVE_UNISTD_H
1252400Sbillf# include <unistd.h>
1368507Sdougb#endif
1452400Sbillf#ifdef HAVE_FCNTL_H
1552400Sbillf# include <fcntl.h>
1652533Sbillf#endif
1752400Sbillf#ifdef SYS_WINNT
1867949Sdougb# include <mswsock.h>
1967949Sdougb#endif
2052400Sbillf#include <isc/net.h>
2152400Sbillf#include <isc/result.h>
2252400Sbillf
2352400Sbillf#include "ntpq.h"
2452400Sbillf#include "ntp_assert.h"
2552400Sbillf#include "ntp_stdlib.h"
2652400Sbillf#include "ntp_unixtime.h"
2767949Sdougb#include "ntp_calendar.h"
2852400Sbillf#include "ntp_select.h"
2952400Sbillf#include "ntp_assert.h"
3052400Sbillf#include "lib_strbuf.h"
3152400Sbillf#include "ntp_lineedit.h"
3252400Sbillf#include "ntp_debug.h"
3367949Sdougb#ifdef OPENSSL
3452400Sbillf#include "openssl/evp.h"
3552400Sbillf#include "openssl/objects.h"
3652400Sbillf#include "openssl/err.h"
3752400Sbillf#endif
3852400Sbillf#include <ssl_applink.c>
3952400Sbillf
4052400Sbillf#include "ntp_libopts.h"
4167859Sdougb#include "safecast.h"
4267949Sdougb
4352400Sbillf#ifdef SYS_VXWORKS		/* vxWorks needs mode flag -casey*/
4452400Sbillf# define open(name, flags)   open(name, flags, 0777)
4558910Salfred# define SERVER_PORT_NUM     123
4658910Salfred#endif
4758910Salfred
4867850Sdougb/* we use COMMAND as an autogen keyword */
4967850Sdougb#ifdef COMMAND
5067850Sdougb# undef COMMAND
5167850Sdougb#endif
5267850Sdougb
5367850Sdougb/*
5467850Sdougb * Because we potentially understand a lot of commands we will run
5567850Sdougb * interactive if connected to a terminal.
5667850Sdougb */
5767850Sdougbint interactive = 0;		/* set to 1 when we should prompt */
5867850Sdougbconst char *prompt = "ntpq> ";	/* prompt to ask him about */
5967850Sdougb
6067949Sdougb/*
6167850Sdougb * use old readvars behavior?  --old-rv processing in ntpq resets
6267850Sdougb * this value based on the presence or absence of --old-rv.  It is
6367850Sdougb * initialized to 1 here to maintain backward compatibility with
6467850Sdougb * libntpq clients such as ntpsnmpd, which are free to reset it as
6567850Sdougb * desired.
6667850Sdougb */
6767850Sdougbint	old_rv = 1;
6867850Sdougb
6967859Sdougb/*
7067859Sdougb * How should we display the refid?
7158910Salfred * REFID_HASH, REFID_IPV4
7267850Sdougb */
7367850Sdougbte_Refid drefid = -1;
7467850Sdougb
7567850Sdougb/*
7667850Sdougb * for get_systime()
7767850Sdougb */
7867859Sdougbs_char	sys_precision;		/* local clock precision (log2 s) */
7967850Sdougb
8067859Sdougb/*
8167850Sdougb * Keyid used for authenticated requests.  Obtained on the fly.
8267850Sdougb */
8367850Sdougbu_long info_auth_keyid = 0;
8467850Sdougb
8567859Sdougbstatic	int	info_auth_keytype = NID_md5;	/* MD5 */
8667850Sdougbstatic	size_t	info_auth_hashlen = 16;		/* MD5 */
8767850Sdougbu_long	current_time;		/* needed by authkeys; not used */
8867850Sdougb
8967850Sdougb/*
9067850Sdougb * Flag which indicates we should always send authenticated requests
9167850Sdougb */
9267850Sdougbint always_auth = 0;
9367850Sdougb
9467850Sdougb/*
9567850Sdougb * Flag which indicates raw mode output.
9667850Sdougb */
9767850Sdougbint rawmode = 0;
9867850Sdougb
9967850Sdougb/*
10058910Salfred * Packet version number we use
10158910Salfred */
10258910Salfredu_char pktversion = NTP_OLDVERSION + 1;
10358910Salfred
10458910Salfred/*
10558910Salfred * Don't jump if no set jmp.
10667850Sdougb */
10758910Salfredvolatile int jump = 0;
10877323Sdougb
10977323Sdougb/*
11067949Sdougb * Format values
11167850Sdougb */
11267850Sdougb#define	PADDING	0
11367949Sdougb#define	HA	1	/* host address */
11467850Sdougb#define	NA	2	/* network address */
11567850Sdougb#define	LP	3	/* leap (print in binary) */
11667949Sdougb#define	RF	4	/* refid (sometimes string, sometimes not) */
11767850Sdougb#define	AR	5	/* array of times */
11867850Sdougb#define FX	6	/* test flags */
11967850Sdougb#define TS	7	/* l_fp timestamp in hex */
12067850Sdougb#define	OC	8	/* integer, print in octal */
12167949Sdougb#define	EOV	255	/* end of table */
12267850Sdougb
12367949Sdougb/*
12467949Sdougb * For the most part ntpq simply displays what ntpd provides in the
12567949Sdougb * mostly plain-text mode 6 responses.  A few variable names are by
12667949Sdougb * default "cooked" to provide more human-friendly output.
12767949Sdougb */
12868507Sdougbconst var_format cookedvars[] = {
12967949Sdougb	{ "leap",		LP },
13067949Sdougb	{ "reach",		OC },
13167949Sdougb	{ "refid",		RF },
13267949Sdougb	{ "reftime",		TS },
13367949Sdougb	{ "clock",		TS },
13467949Sdougb	{ "org",		TS },
13567949Sdougb	{ "rec",		TS },
13667949Sdougb	{ "xmt",		TS },
13767949Sdougb	{ "flash",		FX },
13867949Sdougb	{ "srcadr",		HA },
13967949Sdougb	{ "peeradr",		HA },	/* compat with others */
14067949Sdougb	{ "dstadr",		NA },
14167850Sdougb	{ "filtdelay",		AR },
14267859Sdougb	{ "filtoffset",		AR },
14367850Sdougb	{ "filtdisp",		AR },
14467850Sdougb	{ "filterror",		AR },	/* compat with others */
14567850Sdougb};
14667850Sdougb
14777326Sdougb
14877326Sdougb
14967850Sdougb/*
15067850Sdougb * flasher bits
15167850Sdougb */
15267850Sdougbstatic const char *tstflagnames[] = {
15367850Sdougb	"pkt_dup",		/* TEST1 */
15467859Sdougb	"pkt_bogus",		/* TEST2 */
15567859Sdougb	"pkt_unsync",		/* TEST3 */
15667859Sdougb	"pkt_denied",		/* TEST4 */
15767850Sdougb	"pkt_auth",		/* TEST5 */
15867850Sdougb	"pkt_stratum",		/* TEST6 */
15967850Sdougb	"pkt_header",		/* TEST7 */
16067850Sdougb	"pkt_autokey",		/* TEST8 */
16167850Sdougb	"pkt_crypto",		/* TEST9 */
16267850Sdougb	"peer_stratum",		/* TEST10 */
16367850Sdougb	"peer_dist",		/* TEST11 */
16467850Sdougb	"peer_loop",		/* TEST12 */
16567850Sdougb	"peer_unreach"		/* TEST13 */
16667850Sdougb};
16767850Sdougb
16867850Sdougb
16967850Sdougbint		ntpqmain	(int,	char **);
17067850Sdougb/*
17167850Sdougb * Built in command handler declarations
17267850Sdougb */
17367850Sdougbstatic	int	openhost	(const char *, int);
17467850Sdougbstatic	void	dump_hex_printable(const void *, size_t);
17567850Sdougbstatic	int	sendpkt		(void *, size_t);
17667850Sdougbstatic	int	getresponse	(int, int, u_short *, size_t *, const char **, int);
17767850Sdougbstatic	int	sendrequest	(int, associd_t, int, size_t, const char *);
17867850Sdougbstatic	char *	tstflags	(u_long);
17967850Sdougb#ifndef BUILD_AS_LIB
18067850Sdougbstatic	void	getcmds		(void);
18167850Sdougb#ifndef SYS_WINNT
18267850Sdougbstatic	int	abortcmd	(void);
18367850Sdougb#endif	/* SYS_WINNT */
18467850Sdougbstatic	void	docmd		(const char *);
18567850Sdougbstatic	void	tokenize	(const char *, char **, int *);
18667850Sdougbstatic	int	getarg		(const char *, int, arg_v *);
18767850Sdougb#endif	/* BUILD_AS_LIB */
18867850Sdougbstatic	int	findcmd		(const char *, struct xcmd *,
18967850Sdougb				 struct xcmd *, struct xcmd **);
19067850Sdougbstatic	int	rtdatetolfp	(char *, l_fp *);
19167850Sdougbstatic	int	decodearr	(char *, int *, l_fp *);
19267850Sdougbstatic	void	help		(struct parse *, FILE *);
19367850Sdougbstatic	int	helpsort	(const void *, const void *);
19467850Sdougbstatic	void	printusage	(struct xcmd *, FILE *);
19567850Sdougbstatic	void	timeout		(struct parse *, FILE *);
19667850Sdougbstatic	void	auth_delay	(struct parse *, FILE *);
19767850Sdougbstatic	void	host		(struct parse *, FILE *);
19867850Sdougbstatic	void	ntp_poll	(struct parse *, FILE *);
19967850Sdougbstatic	void	keyid		(struct parse *, FILE *);
20067859Sdougbstatic	void	keytype		(struct parse *, FILE *);
20167850Sdougbstatic	void	passwd		(struct parse *, FILE *);
20267850Sdougbstatic	void	hostnames	(struct parse *, FILE *);
20367850Sdougbstatic	void	setdebug	(struct parse *, FILE *);
20467850Sdougbstatic	void	quit		(struct parse *, FILE *);
20567850Sdougbstatic	void	showdrefid	(struct parse *, FILE *);
20667850Sdougbstatic	void	version		(struct parse *, FILE *);
20767850Sdougbstatic	void	raw		(struct parse *, FILE *);
20867850Sdougbstatic	void	cooked		(struct parse *, FILE *);
20958910Salfredstatic	void	authenticate	(struct parse *, FILE *);
21058910Salfredstatic	void	ntpversion	(struct parse *, FILE *);
21152400Sbillfstatic	void	warning		(const char *, ...)
21252400Sbillf    __attribute__((__format__(__printf__, 1, 2)));
21352400Sbillfstatic	void	error		(const char *, ...)
21452400Sbillf    __attribute__((__format__(__printf__, 1, 2)));
21573651Sdougbstatic	u_long	getkeyid	(const char *);
21673651Sdougbstatic	void	atoascii	(const char *, size_t, char *, size_t);
21773651Sdougbstatic	void	cookedprint	(int, size_t, const char *, int, int, FILE *);
21873651Sdougbstatic	void	rawprint	(int, size_t, const char *, int, int, FILE *);
21973651Sdougbstatic	void	startoutput	(void);
22073651Sdougbstatic	void	output		(FILE *, const char *, const char *);
22152400Sbillfstatic	void	endoutput	(FILE *);
22252400Sbillfstatic	void	outputarr	(FILE *, char *, int, l_fp *);
22367949Sdougbstatic	int	assoccmp	(const void *, const void *);
22452400Sbillfstatic	void	on_ctrlc	(void);
22552400Sbillf	u_short	varfmt		(const char *);
22652400Sbillfstatic	int	my_easprintf	(char**, const char *, ...) NTP_PRINTF(2, 3);
22752400Sbillfvoid	ntpq_custom_opt_handler	(tOptions *, tOptDesc *);
22852400Sbillf
22967949Sdougb#ifdef OPENSSL
23052400Sbillf# ifdef HAVE_EVP_MD_DO_ALL_SORTED
23152400Sbillfstatic void list_md_fn(const EVP_MD *m, const char *from,
23252400Sbillf		       const char *to, void *arg );
23352400Sbillf# endif
23452400Sbillf#endif
23552400Sbillfstatic char *list_digest_names(void);
23652400Sbillf
23752400Sbillf/*
23852400Sbillf * Built-in commands we understand
23952400Sbillf */
24052400Sbillfstruct xcmd builtins[] = {
24152400Sbillf	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
24252400Sbillf	  { "command", "", "", "" },
24352400Sbillf	  "tell the use and syntax of commands" },
24452400Sbillf	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
24552400Sbillf	  { "command", "", "", "" },
24652400Sbillf	  "tell the use and syntax of commands" },
24752400Sbillf	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
24852400Sbillf	  { "msec", "", "", "" },
24952400Sbillf	  "set the primary receive time out" },
25052400Sbillf	{ "delay",	auth_delay,	{ OPT|NTP_INT, NO, NO, NO },
25152400Sbillf	  { "msec", "", "", "" },
25252400Sbillf	  "set the delay added to encryption time stamps" },
25352400Sbillf	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
25467949Sdougb	  { "-4|-6", "hostname", "", "" },
25567949Sdougb	  "specify the host whose NTP server we talk to" },
25667949Sdougb	{ "poll",	ntp_poll,	{ OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
25752400Sbillf	  { "n", "verbose", "", "" },
25852400Sbillf	  "poll an NTP server in client mode `n' times" },
25952400Sbillf	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
26052400Sbillf	  { "", "", "", "" },
26152400Sbillf	  "specify a password to use for authenticated requests"},
26252400Sbillf	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
26352400Sbillf	  { "yes|no", "", "", "" },
26452400Sbillf	  "specify whether hostnames or net numbers are printed"},
26552400Sbillf	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
26652400Sbillf	  { "no|more|less", "", "", "" },
26752400Sbillf	  "set/change debugging level" },
26852400Sbillf	{ "quit",	quit,		{ NO, NO, NO, NO },
26952400Sbillf	  { "", "", "", "" },
27052400Sbillf	  "exit ntpq" },
27152400Sbillf	{ "exit",	quit,		{ NO, NO, NO, NO },
27267949Sdougb	  { "", "", "", "" },
27367949Sdougb	  "exit ntpq" },
27467949Sdougb	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
27552400Sbillf	  { "key#", "", "", "" },
27652400Sbillf	  "set keyid to use for authenticated requests" },
27752400Sbillf	{ "drefid",	showdrefid,	{ OPT|NTP_STR, NO, NO, NO },
27852400Sbillf	  { "hash|ipv4", "", "", "" },
27952400Sbillf	  "display refid's as IPv4 or hash" },
28052400Sbillf	{ "version",	version,	{ NO, NO, NO, NO },
28152400Sbillf	  { "", "", "", "" },
28252400Sbillf	  "print version number" },
28352400Sbillf	{ "raw",	raw,		{ NO, NO, NO, NO },
28452400Sbillf	  { "", "", "", "" },
28552400Sbillf	  "do raw mode variable output" },
28652400Sbillf	{ "cooked",	cooked,		{ NO, NO, NO, NO },
28752400Sbillf	  { "", "", "", "" },
28864467Sbrian	  "do cooked mode variable output" },
28952400Sbillf	{ "authenticate", authenticate,	{ OPT|NTP_STR, NO, NO, NO },
29064467Sbrian	  { "yes|no", "", "", "" },
29167859Sdougb	  "always authenticate requests to this server" },
29252400Sbillf	{ "ntpversion",	ntpversion,	{ OPT|NTP_UINT, NO, NO, NO },
29352400Sbillf	  { "version number", "", "", "" },
29464467Sbrian	  "set the NTP version number to use for requests" },
29564467Sbrian	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
29652400Sbillf	  { "key type %s", "", "", "" },
29752400Sbillf	  NULL },
29852400Sbillf	{ 0,		0,		{ NO, NO, NO, NO },
29952400Sbillf	  { "", "", "", "" }, "" }
30052400Sbillf};
30167859Sdougb
30267859Sdougb
30367859Sdougb/*
30452400Sbillf * Default values we use.
30558910Salfred */
30652400Sbillf#define	DEFHOST		"localhost"	/* default host name */
30752400Sbillf#define	DEFTIMEOUT	5		/* wait 5 seconds for 1st pkt */
30858910Salfred#define	DEFSTIMEOUT	3		/* and 3 more for each additional */
30964467Sbrian/*
31064467Sbrian * Requests are automatically retried once, so total timeout with no
31164467Sbrian * response is a bit over 2 * DEFTIMEOUT, or 10 seconds.  At the other
31258910Salfred * extreme, a request eliciting 32 packets of responses each for some
31364467Sbrian * reason nearly DEFSTIMEOUT seconds after the prior in that series,
31464467Sbrian * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
31564467Sbrian * 93 seconds to fail each of two times, or 186 seconds.
31664467Sbrian * Some commands involve a series of requests, such as "peers" and
31764467Sbrian * "mrulist", so the cumulative timeouts are even longer for those.
31864467Sbrian */
31958910Salfred#define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
32052400Sbillf#define	LENHOSTNAME	256		/* host name is 256 characters long */
32160420Sbsd#define	MAXCMDS		100		/* maximum commands on cmd line */
32252400Sbillf#define	MAXHOSTS	200		/* maximum hosts on cmd line */
32352400Sbillf#define	MAXLINE		512		/* maximum line length */
32458910Salfred#define	MAXTOKENS	(1+MAXARGS+2)	/* maximum number of usable tokens */
32558910Salfred#define	MAXVARLEN	256		/* maximum length of a variable name */
32658910Salfred#define	MAXVALLEN	2048		/* maximum length of a variable value */
32752400Sbillf#define	MAXOUTLINE	72		/* maximum length of an output line */
32852400Sbillf#define SCREENWIDTH	76		/* nominal screen width in columns */
32958910Salfred
33052400Sbillf/*
33152400Sbillf * Some variables used and manipulated locally
33252400Sbillf */
33352400Sbillfstruct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
33452400Sbillfstruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
33552400Sbillfl_fp delay_time;				/* delay time */
33652400Sbillfchar currenthost[LENHOSTNAME];			/* current host name */
33752400Sbillfint currenthostisnum;				/* is prior text from IP? */
33852400Sbillfstruct sockaddr_in hostaddr;			/* host address */
33952400Sbillfint showhostnames = 1;				/* show host names by default */
34052400Sbillfint wideremote = 0;				/* show wide remote names? */
34152400Sbillf
34252400Sbillfint ai_fam_templ;				/* address family */
34352400Sbillfint ai_fam_default;				/* default address family */
34452400SbillfSOCKET sockfd;					/* fd socket is opened on */
34552400Sbillfint havehost = 0;				/* set to 1 when host open */
34652400Sbillfint s_port = 0;
34752400Sbillfstruct servent *server_entry = NULL;		/* server entry for ntp */
34852400Sbillf
34952400Sbillf
35052400Sbillf/*
35152400Sbillf * Sequence number used for requests.  It is incremented before
35273651Sdougb * it is used.
35373651Sdougb */
35473651Sdougbu_short sequence;
35573651Sdougb
35652400Sbillf/*
35752400Sbillf * Holds data returned from queries.  Declare buffer long to be sure of
35852400Sbillf * alignment.
35952400Sbillf */
36052400Sbillf#define	DATASIZE	(MAXFRAGS*480)	/* maximum amount of data */
36152400Sbillflong pktdata[DATASIZE/sizeof(long)];
36252400Sbillf
36352400Sbillf/*
36452400Sbillf * assoc_cache[] is a dynamic array which allows references to
36567859Sdougb * associations using &1 ... &N for n associations, avoiding manual
36652400Sbillf * lookup of the current association IDs for a given ntpd.  It also
36752400Sbillf * caches the status word for each association, retrieved incidentally.
36852400Sbillf */
36952400Sbillfstruct association *	assoc_cache;
37052400Sbillfu_int assoc_cache_slots;/* count of allocated array entries */
37152400Sbillfu_int numassoc;		/* number of cached associations */
37252400Sbillf
37352400Sbillf/*
37452400Sbillf * For commands typed on the command line (with the -c option)
37552400Sbillf */
37667859Sdougbint numcmds = 0;
37767859Sdougbconst char *ccmds[MAXCMDS];
37867859Sdougb#define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
37967859Sdougb
38067859Sdougb/*
38167859Sdougb * When multiple hosts are specified.
38267859Sdougb */
38367859Sdougb
38467859Sdougbu_int numhosts;
38567859Sdougb
38652400Sbillfchost chosts[MAXHOSTS];
38767859Sdougb#define	ADDHOST(cp)						\
38867859Sdougb	do {							\
38967859Sdougb		if (numhosts < MAXHOSTS) {			\
39067859Sdougb			chosts[numhosts].name = (cp);		\
39167859Sdougb			chosts[numhosts].fam = ai_fam_templ;	\
39267859Sdougb			numhosts++;				\
39367859Sdougb		}						\
39467859Sdougb	} while (0)
39567859Sdougb
39667859Sdougb/*
39767859Sdougb * Macro definitions we use
39867859Sdougb */
39967859Sdougb#define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
40067859Sdougb#define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
40167859Sdougb#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
40267859Sdougb
40367859Sdougb/*
40467859Sdougb * Jump buffer for longjumping back to the command level
40567859Sdougb */
40667859Sdougbjmp_buf interrupt_buf;
40752400Sbillf
40877323Sdougb/*
40977323Sdougb * Points at file being currently printed into
41052400Sbillf */
41152400SbillfFILE *current_output;
41252400Sbillf
41352400Sbillf/*
41452400Sbillf * Command table imported from ntpdc_ops.c
41552400Sbillf */
41652400Sbillfextern struct xcmd opcmds[];
41752400Sbillf
41852400Sbillfchar const *progname;
41952400Sbillf
42052400Sbillf#ifdef NO_MAIN_ALLOWED
42152400Sbillf#ifndef BUILD_AS_LIB
42252400SbillfCALL(ntpq,"ntpq",ntpqmain);
42352400Sbillf
42452400Sbillfvoid clear_globals(void)
42552400Sbillf{
42652400Sbillf	extern int ntp_optind;
42752400Sbillf	showhostnames = 0;	/* don'tshow host names by default */
42852400Sbillf	ntp_optind = 0;
42952400Sbillf	server_entry = NULL;	/* server entry for ntp */
43052400Sbillf	havehost = 0;		/* set to 1 when host open */
43152400Sbillf	numassoc = 0;		/* number of cached associations */
43252400Sbillf	numcmds = 0;
43352400Sbillf	numhosts = 0;
43452400Sbillf}
43552400Sbillf#endif /* !BUILD_AS_LIB */
43652400Sbillf#endif /* NO_MAIN_ALLOWED */
43752400Sbillf
43852400Sbillf/*
43952400Sbillf * main - parse arguments and handle options
44052400Sbillf */
44152400Sbillf#ifndef NO_MAIN_ALLOWED
44252400Sbillfint
44352400Sbillfmain(
44468507Sdougb	int argc,
44568507Sdougb	char *argv[]
44668507Sdougb	)
44768507Sdougb{
44868507Sdougb	return ntpqmain(argc, argv);
44968507Sdougb}
45052400Sbillf#endif
45174992Sasmodai
45252400Sbillf#ifndef BUILD_AS_LIB
45377323Sdougbint
45477323Sdougbntpqmain(
45552400Sbillf	int argc,
45652400Sbillf	char *argv[]
45752400Sbillf	)
45877323Sdougb{
45977323Sdougb	u_int ihost;
46077323Sdougb	int icmd;
46167949Sdougb
46267949Sdougb
46367949Sdougb#ifdef SYS_VXWORKS
46467949Sdougb	clear_globals();
46567949Sdougb	taskPrioritySet(taskIdSelf(), 100 );
46667949Sdougb#endif
46767949Sdougb
46867949Sdougb	delay_time.l_ui = 0;
46967949Sdougb	delay_time.l_uf = DEFDELAY;
47067949Sdougb
47167949Sdougb	init_lib();	/* sets up ipv4_works, ipv6_works */
47267949Sdougb	ssl_applink();
47367949Sdougb	init_auth();
47467949Sdougb
47567949Sdougb	/* Check to see if we have IPv6. Otherwise default to IPv4 */
47667949Sdougb	if (!ipv6_works)
47767949Sdougb		ai_fam_default = AF_INET;
47867949Sdougb
47967949Sdougb	/* Fixup keytype's help based on available digest names */
48067949Sdougb
48167949Sdougb	{
48252534Sbillf	    char *list;
48352534Sbillf	    char *msg;
48452534Sbillf
48552534Sbillf	    list = list_digest_names();
48652534Sbillf	    for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) {
48752534Sbillf		if (strcmp("keytype", builtins[icmd].keyword) == 0)
48852534Sbillf		    break;
48965115Sben	    }
49068507Sdougb
49165115Sben	    /* CID: 1295478 */
49265115Sben	    /* This should only "trip" if "keytype" is removed from builtins */
49365115Sben	    INSIST(icmd < sizeof(builtins)/sizeof(builtins[0]));
49452400Sbillf
49552400Sbillf#ifdef OPENSSL
49652400Sbillf	    builtins[icmd].desc[0] = "digest-name";
49777478Sdougb	    my_easprintf(&msg,
49877478Sdougb			 "set key type to use for authenticated requests, one of:%s",
49977478Sdougb			 list);
50077478Sdougb#else
50177478Sdougb	    builtins[icmd].desc[0] = "md5";
50277478Sdougb	    my_easprintf(&msg,
50377478Sdougb			 "set key type to use for authenticated requests (%s)",
50477478Sdougb			 list);
50552400Sbillf#endif
50652400Sbillf	    builtins[icmd].comment = msg;
50752400Sbillf	    free(list);
50852400Sbillf	}
50952400Sbillf
51052400Sbillf	progname = argv[0];
51152400Sbillf
51252400Sbillf	{
51377335Sdougb		int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
51452400Sbillf		argc -= optct;
51552400Sbillf		argv += optct;
51667859Sdougb	}
51752400Sbillf
51852400Sbillf	/*
51967859Sdougb	 * Process options other than -c and -p, which are specially
52052400Sbillf	 * handled by ntpq_custom_opt_handler().
52167859Sdougb	 */
52252400Sbillf
52367859Sdougb	debug = OPT_VALUE_SET_DEBUG_LEVEL;
52452400Sbillf
52552400Sbillf	if (HAVE_OPT(IPV4))
52667859Sdougb		ai_fam_templ = AF_INET;
52767859Sdougb	else if (HAVE_OPT(IPV6))
52867859Sdougb		ai_fam_templ = AF_INET6;
52952400Sbillf	else
53052400Sbillf		ai_fam_templ = ai_fam_default;
53152400Sbillf
53252400Sbillf	if (HAVE_OPT(INTERACTIVE))
53352400Sbillf		interactive = 1;
53452400Sbillf
53552400Sbillf	if (HAVE_OPT(NUMERIC))
53652400Sbillf		showhostnames = 0;
53767949Sdougb
53852400Sbillf	if (HAVE_OPT(WIDE))
53967949Sdougb		wideremote = 1;
54052400Sbillf
54167949Sdougb	old_rv = HAVE_OPT(OLD_RV);
54267949Sdougb
54367949Sdougb	drefid = OPT_VALUE_REFID;
54467949Sdougb
54567949Sdougb	if (0 == argc) {
54667949Sdougb		ADDHOST(DEFHOST);
54767949Sdougb	} else {
54867949Sdougb		for (ihost = 0; ihost < (u_int)argc; ihost++) {
54967949Sdougb			if ('-' == *argv[ihost]) {
55052400Sbillf				//
55152400Sbillf				// If I really cared I'd also check:
55267859Sdougb				// 0 == argv[ihost][2]
55367859Sdougb				//
55467859Sdougb				// and there are other cases as well...
55552400Sbillf				//
55652400Sbillf				if ('4' == argv[ihost][1]) {
55752400Sbillf					ai_fam_templ = AF_INET;
55852400Sbillf					continue;
55952400Sbillf				} else if ('6' == argv[ihost][1]) {
56052400Sbillf					ai_fam_templ = AF_INET6;
56152400Sbillf					continue;
56252400Sbillf				} else {
56352400Sbillf					// XXX Throw a usage error
56452400Sbillf				}
56552400Sbillf			}
56652400Sbillf			ADDHOST(argv[ihost]);
56752400Sbillf		}
56852400Sbillf	}
56952400Sbillf
57052400Sbillf	if (numcmds == 0 && interactive == 0
57152400Sbillf	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
57278490Sdougb		interactive = 1;
57378490Sdougb	}
57478490Sdougb
57578490Sdougb	set_ctrl_c_hook(on_ctrlc);
57678490Sdougb#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
57778490Sdougb	if (interactive)
57878490Sdougb		push_ctrl_c_handler(abortcmd);
57978490Sdougb#endif /* SYS_WINNT */
58078490Sdougb
58152400Sbillf	if (numcmds == 0) {
58252400Sbillf		(void) openhost(chosts[0].name, chosts[0].fam);
58352400Sbillf		getcmds();
58452400Sbillf	} else {
58567949Sdougb		for (ihost = 0; ihost < numhosts; ihost++) {
58652400Sbillf			if (openhost(chosts[ihost].name, chosts[ihost].fam))
58752400Sbillf				for (icmd = 0; icmd < numcmds; icmd++)
58852400Sbillf					docmd(ccmds[icmd]);
58952400Sbillf		}
59052400Sbillf	}
59152400Sbillf#ifdef SYS_WINNT
59267949Sdougb	WSACleanup();
59377323Sdougb#endif /* SYS_WINNT */
59477323Sdougb	return 0;
59567949Sdougb}
59652400Sbillf#endif /* !BUILD_AS_LIB */
59752400Sbillf
59877323Sdougb/*
59977323Sdougb * openhost - open a socket to a host
60052400Sbillf */
60152400Sbillfstatic	int
60252400Sbillfopenhost(
60364625Sgshapiro	const char *hname,
60452400Sbillf	int	    fam
60552400Sbillf	)
60652400Sbillf{
60752400Sbillf	const char svc[] = "ntp";
60852400Sbillf	char temphost[LENHOSTNAME];
60952400Sbillf	int a_info, i;
61078490Sdougb	struct addrinfo hints, *ai;
61152400Sbillf	sockaddr_u addr;
61252400Sbillf	size_t octets;
61352400Sbillf	register const char *cp;
61452400Sbillf	char name[LENHOSTNAME];
61577335Sdougb
61677335Sdougb	/*
61752400Sbillf	 * We need to get by the [] if they were entered
61852400Sbillf	 */
61967859Sdougb
62067859Sdougb	cp = hname;
62167859Sdougb
62267859Sdougb	if (*cp == '[') {
62367859Sdougb		cp++;
62452400Sbillf		for (i = 0; *cp && *cp != ']'; cp++, i++)
62552400Sbillf			name[i] = *cp;
62652400Sbillf		if (*cp == ']') {
62752400Sbillf			name[i] = '\0';
62852400Sbillf			hname = name;
62952400Sbillf		} else {
63067949Sdougb			return 0;
63152400Sbillf		}
63252400Sbillf	}
63352400Sbillf
63467859Sdougb	/*
63567859Sdougb	 * First try to resolve it as an ip address and if that fails,
63677335Sdougb	 * do a fullblown (dns) lookup. That way we only use the dns
63777335Sdougb	 * when it is needed and work around some implementations that
63877335Sdougb	 * will return an "IPv4-mapped IPv6 address" address if you
63977335Sdougb	 * give it an IPv4 address to lookup.
64077335Sdougb	 */
64167859Sdougb	ZERO(hints);
64252400Sbillf	hints.ai_family = fam;
64352400Sbillf	hints.ai_protocol = IPPROTO_UDP;
64452400Sbillf	hints.ai_socktype = SOCK_DGRAM;
64552400Sbillf	hints.ai_flags = Z_AI_NUMERICHOST;
64652400Sbillf	ai = NULL;
64752400Sbillf
64852400Sbillf	a_info = getaddrinfo(hname, svc, &hints, &ai);
64952400Sbillf	if (a_info == EAI_NONAME
65067949Sdougb#ifdef EAI_NODATA
65167949Sdougb	    || a_info == EAI_NODATA
65267949Sdougb#endif
65352400Sbillf	   ) {
65452400Sbillf		hints.ai_flags = AI_CANONNAME;
65567949Sdougb#ifdef AI_ADDRCONFIG
65652400Sbillf		hints.ai_flags |= AI_ADDRCONFIG;
65752400Sbillf#endif
65852400Sbillf		a_info = getaddrinfo(hname, svc, &hints, &ai);
65952400Sbillf	}
66052400Sbillf#ifdef AI_ADDRCONFIG
66152400Sbillf	/* Some older implementations don't like AI_ADDRCONFIG. */
66252400Sbillf	if (a_info == EAI_BADFLAGS) {
66352400Sbillf		hints.ai_flags &= ~AI_ADDRCONFIG;
66452400Sbillf		a_info = getaddrinfo(hname, svc, &hints, &ai);
66552400Sbillf	}
66652400Sbillf#endif
66752400Sbillf	if (a_info != 0) {
66878490Sdougb		fprintf(stderr, "%s\n", gai_strerror(a_info));
66952400Sbillf		return 0;
67052400Sbillf	}
67152400Sbillf
67252400Sbillf	INSIST(ai != NULL);
67352400Sbillf	ZERO(addr);
67478490Sdougb	octets = min(sizeof(addr), ai->ai_addrlen);
67567949Sdougb	memcpy(&addr, ai->ai_addr, octets);
67667949Sdougb
67767949Sdougb	if (ai->ai_canonname == NULL) {
67867949Sdougb		strlcpy(temphost, stoa(&addr), sizeof(temphost));
67967949Sdougb		currenthostisnum = TRUE;
68078490Sdougb	} else {
68152400Sbillf		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
68252400Sbillf		currenthostisnum = FALSE;
68352400Sbillf	}
68452400Sbillf
68567949Sdougb	if (debug > 2)
68667949Sdougb		printf("Opening host %s (%s)\n",
68767949Sdougb			temphost,
68852400Sbillf			(ai->ai_family == AF_INET)
68967949Sdougb			? "AF_INET"
69067949Sdougb			: (ai->ai_family == AF_INET6)
69167949Sdougb			  ? "AF_INET6"
69267949Sdougb			  : "AF-???"
69367949Sdougb			);
69467949Sdougb
69552400Sbillf	if (havehost == 1) {
69652400Sbillf		if (debug > 2)
69767949Sdougb			printf("Closing old host %s\n", currenthost);
69852400Sbillf		closesocket(sockfd);
69952400Sbillf		havehost = 0;
70067949Sdougb	}
70167949Sdougb	strlcpy(currenthost, temphost, sizeof(currenthost));
70267949Sdougb
70367949Sdougb	/* port maps to the same location in both families */
70467949Sdougb	s_port = NSRCPORT(&addr);
70577325Sdougb#ifdef SYS_VXWORKS
70677325Sdougb	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
70777325Sdougb	if (ai->ai_family == AF_INET)
70877325Sdougb		*(struct sockaddr_in *)&hostaddr=
70977325Sdougb			*((struct sockaddr_in *)ai->ai_addr);
71077325Sdougb	else
71177325Sdougb		*(struct sockaddr_in6 *)&hostaddr=
71277325Sdougb			*((struct sockaddr_in6 *)ai->ai_addr);
71377325Sdougb#endif /* SYS_VXWORKS */
71477325Sdougb
71577325Sdougb#ifdef SYS_WINNT
71677325Sdougb	{
71777325Sdougb		int optionValue = SO_SYNCHRONOUS_NONALERT;
71877325Sdougb		int err;
71977325Sdougb
72077325Sdougb		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
72167949Sdougb				 (char *)&optionValue, sizeof(optionValue));
72267949Sdougb		if (err) {
72367949Sdougb			mfprintf(stderr,
72452400Sbillf				 "setsockopt(SO_SYNCHRONOUS_NONALERT)"
72552400Sbillf				 " error: %m\n");
72652400Sbillf			freeaddrinfo(ai);
72752400Sbillf			exit(1);
72852400Sbillf		}
72952400Sbillf	}
73052400Sbillf#endif /* SYS_WINNT */
73173651Sdougb
73273651Sdougb	sockfd = socket(ai->ai_family, ai->ai_socktype,
73352400Sbillf			ai->ai_protocol);
73467949Sdougb	if (sockfd == INVALID_SOCKET) {
73573651Sdougb		error("socket");
73667949Sdougb		freeaddrinfo(ai);
73767949Sdougb		return 0;
73867949Sdougb	}
73967949Sdougb
74052400Sbillf
74152400Sbillf#ifdef NEED_RCVBUF_SLOP
74252400Sbillf# ifdef SO_RCVBUF
74352400Sbillf	{ int rbufsize = DATASIZE + 2048;	/* 2K for slop */
74452400Sbillf	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
74552400Sbillf		       &rbufsize, sizeof(int)) == -1)
74652400Sbillf		error("setsockopt");
74752400Sbillf	}
74852400Sbillf# endif
74952400Sbillf#endif
75052400Sbillf
75167949Sdougb	if
75252400Sbillf#ifdef SYS_VXWORKS
75352400Sbillf	   (connect(sockfd, (struct sockaddr *)&hostaddr,
75452400Sbillf		    sizeof(hostaddr)) == -1)
75577323Sdougb#else
75677323Sdougb	   (connect(sockfd, (struct sockaddr *)ai->ai_addr,
75777323Sdougb		ai->ai_addrlen) == -1)
75867859Sdougb#endif /* SYS_VXWORKS */
75952400Sbillf	{
76052400Sbillf		error("connect");
76152400Sbillf		freeaddrinfo(ai);
76258910Salfred		return 0;
76358910Salfred	}
76452400Sbillf	freeaddrinfo(ai);
76552400Sbillf	havehost = 1;
76652400Sbillf	numassoc = 0;
76752400Sbillf
76852400Sbillf	return 1;
76952400Sbillf}
77052400Sbillf
77152400Sbillf
77252400Sbillfstatic void
77352400Sbillfdump_hex_printable(
77452534Sbillf	const void *	data,
77552400Sbillf	size_t		len
77652400Sbillf	)
77752400Sbillf{
77852400Sbillf	const char *	cdata;
77952400Sbillf	const char *	rowstart;
78052400Sbillf	size_t		idx;
78152400Sbillf	size_t		rowlen;
78277335Sdougb	u_char		uch;
78352400Sbillf
78452400Sbillf	cdata = data;
78552400Sbillf	while (len > 0) {
78652400Sbillf		rowstart = cdata;
78767859Sdougb		rowlen = min(16, len);
78867859Sdougb		for (idx = 0; idx < rowlen; idx++) {
78967859Sdougb			uch = *(cdata++);
79052400Sbillf			printf("%02x ", uch);
79152400Sbillf		}
79252400Sbillf		for ( ; idx < 16 ; idx++)
79352400Sbillf			printf("   ");
79452400Sbillf		cdata = rowstart;
79552400Sbillf		for (idx = 0; idx < rowlen; idx++) {
79652400Sbillf			uch = *(cdata++);
79752400Sbillf			printf("%c", (isprint(uch))
79852400Sbillf					 ? uch
79952400Sbillf					 : '.');
80052400Sbillf		}
80152400Sbillf		printf("\n");
80252400Sbillf		len -= rowlen;
80352400Sbillf	}
80452400Sbillf}
80552400Sbillf
80668153Sdougb
80768153Sdougb/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
80868153Sdougb/*
80973651Sdougb * sendpkt - send a packet to the remote host
81073651Sdougb */
81173651Sdougbstatic int
81273651Sdougbsendpkt(
81377323Sdougb	void *	xdata,
81477323Sdougb	size_t	xdatalen
81573651Sdougb	)
81673651Sdougb{
81773651Sdougb	if (debug >= 3)
81873651Sdougb		printf("Sending %zu octets\n", xdatalen);
81968153Sdougb
82077323Sdougb	if (send(sockfd, xdata, xdatalen, 0) == -1) {
82177323Sdougb		warning("write to %s failed", currenthost);
82268153Sdougb		return -1;
82373651Sdougb	}
82473651Sdougb
82568153Sdougb	if (debug >= 4) {
82668153Sdougb		printf("Request packet:\n");
82768153Sdougb		dump_hex_printable(xdata, xdatalen);
82873651Sdougb	}
82973651Sdougb	return 0;
83073651Sdougb}
83173651Sdougb
83273651Sdougb/*
83377335Sdougb * getresponse - get a (series of) response packet(s) and return the data
83473651Sdougb */
83573651Sdougbstatic int
83673651Sdougbgetresponse(
83773651Sdougb	int opcode,
83877335Sdougb	int associd,
83977335Sdougb	u_short *rstatus,
84073651Sdougb	size_t *rsize,
84173651Sdougb	const char **rdata,
84277335Sdougb	int timeo
84377335Sdougb	)
84477335Sdougb{
84577335Sdougb	struct ntp_control rpkt;
84677335Sdougb	struct sock_timeval tvo;
84777335Sdougb	u_short offsets[MAXFRAGS+1];
84873651Sdougb	u_short counts[MAXFRAGS+1];
84977335Sdougb	u_short offset;
85077335Sdougb	u_short count;
85177335Sdougb	size_t numfrags;
85277335Sdougb	size_t f;
85373651Sdougb	size_t ff;
85473651Sdougb	int seenlastfrag;
85573651Sdougb	int shouldbesize;
85673651Sdougb	fd_set fds;
85773651Sdougb	int n;
85873651Sdougb	int errcode;
85952400Sbillf	/* absolute timeout checks. Not 'time_t' by intention! */
86052400Sbillf	uint32_t tobase;	/* base value for timeout */
86152400Sbillf	uint32_t tospan;	/* timeout span (max delay) */
86252400Sbillf	uint32_t todiff;	/* current delay */
86377335Sdougb
86477335Sdougb	/*
86577335Sdougb	 * This is pretty tricky.  We may get between 1 and MAXFRAG packets
86652400Sbillf	 * back in response to the request.  We peel the data out of
86752400Sbillf	 * each packet and collect it in one long block.  When the last
86852400Sbillf	 * packet in the sequence is received we'll know how much data we
86952400Sbillf	 * should have had.  Note we use one long time out, should reconsider.
87052400Sbillf	 */
87152400Sbillf	*rsize = 0;
87252400Sbillf	if (rstatus)
87377335Sdougb		*rstatus = 0;
87477335Sdougb	*rdata = (char *)pktdata;
87577335Sdougb
87677335Sdougb	numfrags = 0;
87777335Sdougb	seenlastfrag = 0;
87877335Sdougb
87977335Sdougb	tobase = (uint32_t)time(NULL);
88077335Sdougb
88177335Sdougb	FD_ZERO(&fds);
88277335Sdougb
88352400Sbillf	/*
88452400Sbillf	 * Loop until we have an error or a complete response.  Nearly all
88552400Sbillf	 * code paths to loop again use continue.
88652400Sbillf	 */
88752400Sbillf	for (;;) {
88852400Sbillf
88952400Sbillf		if (numfrags == 0)
89052400Sbillf			tvo = tvout;
89177335Sdougb		else
89277335Sdougb			tvo = tvsout;
89377335Sdougb		tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0);
89452400Sbillf
89552400Sbillf		FD_SET(sockfd, &fds);
89652400Sbillf		n = select(sockfd+1, &fds, NULL, NULL, &tvo);
89752400Sbillf		if (n == -1) {
89852400Sbillf#if !defined(SYS_WINNT) && defined(EINTR)
89952400Sbillf			/* Windows does not know about EINTR (until very
90052400Sbillf			 * recently) and the handling of console events
90152400Sbillf			 * is *very* different from POSIX/UNIX signal
90277335Sdougb			 * handling anyway.
90377335Sdougb			 *
90477335Sdougb			 * Under non-windows targets we map EINTR as
90577335Sdougb			 * 'last packet was received' and try to exit
90677335Sdougb			 * the receive sequence.
90777335Sdougb			 */
90877335Sdougb			if (errno == EINTR) {
90977335Sdougb				seenlastfrag = 1;
91077335Sdougb				goto maybe_final;
91152400Sbillf			}
91252400Sbillf#endif
91352400Sbillf			warning("select fails");
91452400Sbillf			return -1;
91552400Sbillf		}
91667949Sdougb
91767949Sdougb		/*
91867949Sdougb		 * Check if this is already too late. Trash the data and
91967949Sdougb		 * fake a timeout if this is so.
92052400Sbillf		 */
92167850Sdougb		todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu;
922		if ((n > 0) && (todiff > tospan)) {
923			n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
924			n = 0; /* faked timeout return from 'select()'*/
925		}
926
927		if (n == 0) {
928			/*
929			 * Timed out.  Return what we have
930			 */
931			if (numfrags == 0) {
932				if (timeo)
933					fprintf(stderr,
934						"%s: timed out, nothing received\n",
935						currenthost);
936				return ERR_TIMEOUT;
937			}
938			if (timeo)
939				fprintf(stderr,
940					"%s: timed out with incomplete data\n",
941					currenthost);
942			if (debug) {
943				fprintf(stderr,
944					"ERR_INCOMPLETE: Received fragments:\n");
945				for (f = 0; f < numfrags; f++)
946					fprintf(stderr,
947						"%2u: %5d %5d\t%3d octets\n",
948						(u_int)f, offsets[f],
949						offsets[f] +
950						counts[f],
951						counts[f]);
952				fprintf(stderr,
953					"last fragment %sreceived\n",
954					(seenlastfrag)
955					    ? ""
956					    : "not ");
957			}
958			return ERR_INCOMPLETE;
959		}
960
961		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
962		if (n == -1) {
963			warning("read");
964			return -1;
965		}
966
967		if (debug >= 4) {
968			printf("Response packet:\n");
969			dump_hex_printable(&rpkt, n);
970		}
971
972		/*
973		 * Check for format errors.  Bug proofing.
974		 */
975		if (n < (int)CTL_HEADER_LEN) {
976			if (debug)
977				printf("Short (%d byte) packet received\n", n);
978			continue;
979		}
980		if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
981		    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
982			if (debug)
983				printf("Packet received with version %d\n",
984				       PKT_VERSION(rpkt.li_vn_mode));
985			continue;
986		}
987		if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
988			if (debug)
989				printf("Packet received with mode %d\n",
990				       PKT_MODE(rpkt.li_vn_mode));
991			continue;
992		}
993		if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
994			if (debug)
995				printf("Received request packet, wanted response\n");
996			continue;
997		}
998
999		/*
1000		 * Check opcode and sequence number for a match.
1001		 * Could be old data getting to us.
1002		 */
1003		if (ntohs(rpkt.sequence) != sequence) {
1004			if (debug)
1005				printf("Received sequnce number %d, wanted %d\n",
1006				       ntohs(rpkt.sequence), sequence);
1007			continue;
1008		}
1009		if (CTL_OP(rpkt.r_m_e_op) != opcode) {
1010			if (debug)
1011			    printf(
1012				    "Received opcode %d, wanted %d (sequence number okay)\n",
1013				    CTL_OP(rpkt.r_m_e_op), opcode);
1014			continue;
1015		}
1016
1017		/*
1018		 * Check the error code.  If non-zero, return it.
1019		 */
1020		if (CTL_ISERROR(rpkt.r_m_e_op)) {
1021			errcode = (ntohs(rpkt.status) >> 8) & 0xff;
1022			if (CTL_ISMORE(rpkt.r_m_e_op))
1023				TRACE(1, ("Error code %d received on not-final packet\n",
1024					  errcode));
1025			if (errcode == CERR_UNSPEC)
1026				return ERR_UNSPEC;
1027			return errcode;
1028		}
1029
1030		/*
1031		 * Check the association ID to make sure it matches what
1032		 * we sent.
1033		 */
1034		if (ntohs(rpkt.associd) != associd) {
1035			TRACE(1, ("Association ID %d doesn't match expected %d\n",
1036				  ntohs(rpkt.associd), associd));
1037			/*
1038			 * Hack for silly fuzzballs which, at the time of writing,
1039			 * return an assID of sys.peer when queried for system variables.
1040			 */
1041#ifdef notdef
1042			continue;
1043#endif
1044		}
1045
1046		/*
1047		 * Collect offset and count.  Make sure they make sense.
1048		 */
1049		offset = ntohs(rpkt.offset);
1050		count = ntohs(rpkt.count);
1051
1052		/*
1053		 * validate received payload size is padded to next 32-bit
1054		 * boundary and no smaller than claimed by rpkt.count
1055		 */
1056		if (n & 0x3) {
1057			TRACE(1, ("Response packet not padded, size = %d\n",
1058				  n));
1059			continue;
1060		}
1061
1062		shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
1063
1064		if (n < shouldbesize) {
1065			printf("Response packet claims %u octets payload, above %ld received\n",
1066			       count, (long)n - CTL_HEADER_LEN);
1067			return ERR_INCOMPLETE;
1068		}
1069
1070		if (debug >= 3 && shouldbesize > n) {
1071			u_int32 key;
1072			u_int32 *lpkt;
1073			int maclen;
1074
1075			/*
1076			 * Usually we ignore authentication, but for debugging purposes
1077			 * we watch it here.
1078			 */
1079			/* round to 8 octet boundary */
1080			shouldbesize = (shouldbesize + 7) & ~7;
1081
1082			maclen = n - shouldbesize;
1083			if (maclen >= (int)MIN_MAC_LEN) {
1084				printf(
1085					"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1086					n, shouldbesize, maclen);
1087				lpkt = (u_int32 *)&rpkt;
1088				printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1089				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1090				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1091				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1092				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1093				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1094				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1095				key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1096				printf("Authenticated with keyid %lu\n", (u_long)key);
1097				if (key != 0 && key != info_auth_keyid) {
1098					printf("We don't know that key\n");
1099				} else {
1100					if (authdecrypt(key, (u_int32 *)&rpkt,
1101					    n - maclen, maclen)) {
1102						printf("Auth okay!\n");
1103					} else {
1104						printf("Auth failed!\n");
1105					}
1106				}
1107			}
1108		}
1109
1110		TRACE(2, ("Got packet, size = %d\n", n));
1111		if (count > (n - CTL_HEADER_LEN)) {
1112			TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
1113				  count, (long)n - CTL_HEADER_LEN));
1114			continue;
1115		}
1116		if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1117			TRACE(1, ("Received count of 0 in non-final fragment\n"));
1118			continue;
1119		}
1120		if (offset + count > sizeof(pktdata)) {
1121			TRACE(1, ("Offset %u, count %u, too big for buffer\n",
1122				  offset, count));
1123			return ERR_TOOMUCH;
1124		}
1125		if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1126			TRACE(1, ("Received second last fragment packet\n"));
1127			continue;
1128		}
1129
1130		/*
1131		 * So far, so good.  Record this fragment, making sure it doesn't
1132		 * overlap anything.
1133		 */
1134		TRACE(2, ("Packet okay\n"));
1135
1136		if (numfrags > (MAXFRAGS - 1)) {
1137			TRACE(2, ("Number of fragments exceeds maximum %d\n",
1138				  MAXFRAGS - 1));
1139			return ERR_TOOMUCH;
1140		}
1141
1142		/*
1143		 * Find the position for the fragment relative to any
1144		 * previously received.
1145		 */
1146		for (f = 0;
1147		     f < numfrags && offsets[f] < offset;
1148		     f++) {
1149			/* empty body */ ;
1150		}
1151
1152		if (f < numfrags && offset == offsets[f]) {
1153			TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
1154				  count, offset, counts[f], offsets[f]));
1155			continue;
1156		}
1157
1158		if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1159			TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
1160				  offset, counts[f-1], offsets[f-1]));
1161			continue;
1162		}
1163
1164		if (f < numfrags && (offset + count) > offsets[f]) {
1165			TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
1166				  count, offset, offsets[f]));
1167			continue;
1168		}
1169
1170		for (ff = numfrags; ff > f; ff--) {
1171			offsets[ff] = offsets[ff-1];
1172			counts[ff] = counts[ff-1];
1173		}
1174		offsets[f] = offset;
1175		counts[f] = count;
1176		numfrags++;
1177
1178		/*
1179		 * Got that stuffed in right.  Figure out if this was the last.
1180		 * Record status info out of the last packet.
1181		 */
1182		if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1183			seenlastfrag = 1;
1184			if (rstatus != 0)
1185				*rstatus = ntohs(rpkt.status);
1186		}
1187
1188		/*
1189		 * Copy the data into the data buffer, and bump the
1190		 * timout base in case we need more.
1191		 */
1192		memcpy((char *)pktdata + offset, &rpkt.u, count);
1193		tobase = (uint32_t)time(NULL);
1194
1195		/*
1196		 * If we've seen the last fragment, look for holes in the sequence.
1197		 * If there aren't any, we're done.
1198		 */
1199	  maybe_final:
1200		if (seenlastfrag && offsets[0] == 0) {
1201			for (f = 1; f < numfrags; f++)
1202				if (offsets[f-1] + counts[f-1] !=
1203				    offsets[f])
1204					break;
1205			if (f == numfrags) {
1206				*rsize = offsets[f-1] + counts[f-1];
1207				TRACE(1, ("%lu packets reassembled into response\n",
1208					  (u_long)numfrags));
1209				return 0;
1210			}
1211		}
1212	}  /* giant for (;;) collecting response packets */
1213}  /* getresponse() */
1214
1215
1216/*
1217 * sendrequest - format and send a request packet
1218 */
1219static int
1220sendrequest(
1221	int opcode,
1222	associd_t associd,
1223	int auth,
1224	size_t qsize,
1225	const char *qdata
1226	)
1227{
1228	struct ntp_control qpkt;
1229	size_t	pktsize;
1230	u_long	key_id;
1231	char *	pass;
1232	size_t	maclen;
1233
1234	/*
1235	 * Check to make sure the data will fit in one packet
1236	 */
1237	if (qsize > CTL_MAX_DATA_LEN) {
1238		fprintf(stderr,
1239			"***Internal error!  qsize (%zu) too large\n",
1240			qsize);
1241		return 1;
1242	}
1243
1244	/*
1245	 * Fill in the packet
1246	 */
1247	qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1248	qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1249	qpkt.sequence = htons(sequence);
1250	qpkt.status = 0;
1251	qpkt.associd = htons((u_short)associd);
1252	qpkt.offset = 0;
1253	qpkt.count = htons((u_short)qsize);
1254
1255	pktsize = CTL_HEADER_LEN;
1256
1257	/*
1258	 * If we have data, copy and pad it out to a 32-bit boundary.
1259	 */
1260	if (qsize > 0) {
1261		memcpy(&qpkt.u, qdata, (size_t)qsize);
1262		pktsize += qsize;
1263		while (pktsize & (sizeof(u_int32) - 1)) {
1264			qpkt.u.data[qsize++] = 0;
1265			pktsize++;
1266		}
1267	}
1268
1269	/*
1270	 * If it isn't authenticated we can just send it.  Otherwise
1271	 * we're going to have to think about it a little.
1272	 */
1273	if (!auth && !always_auth) {
1274		return sendpkt(&qpkt, pktsize);
1275	}
1276
1277	/*
1278	 * Pad out packet to a multiple of 8 octets to be sure
1279	 * receiver can handle it.
1280	 */
1281	while (pktsize & 7) {
1282		qpkt.u.data[qsize++] = 0;
1283		pktsize++;
1284	}
1285
1286	/*
1287	 * Get the keyid and the password if we don't have one.
1288	 */
1289	if (info_auth_keyid == 0) {
1290		key_id = getkeyid("Keyid: ");
1291		if (key_id == 0 || key_id > NTP_MAXKEY) {
1292			fprintf(stderr,
1293				"Invalid key identifier\n");
1294			return 1;
1295		}
1296		info_auth_keyid = key_id;
1297	}
1298	if (!authistrusted(info_auth_keyid)) {
1299		pass = getpass_keytype(info_auth_keytype);
1300		if ('\0' == pass[0]) {
1301			fprintf(stderr, "Invalid password\n");
1302			return 1;
1303		}
1304		authusekey(info_auth_keyid, info_auth_keytype,
1305			   (u_char *)pass);
1306		authtrust(info_auth_keyid, 1);
1307	}
1308
1309	/*
1310	 * Do the encryption.
1311	 */
1312	maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1313	if (!maclen) {
1314		fprintf(stderr, "Key not found\n");
1315		return 1;
1316	} else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1317		fprintf(stderr,
1318			"%zu octet MAC, %zu expected with %zu octet digest\n",
1319			maclen, (info_auth_hashlen + sizeof(keyid_t)),
1320			info_auth_hashlen);
1321		return 1;
1322	}
1323
1324	return sendpkt((char *)&qpkt, pktsize + maclen);
1325}
1326
1327
1328/*
1329 * show_error_msg - display the error text for a mode 6 error response.
1330 */
1331void
1332show_error_msg(
1333	int		m6resp,
1334	associd_t	associd
1335	)
1336{
1337	if (numhosts > 1)
1338		fprintf(stderr, "server=%s ", currenthost);
1339
1340	switch (m6resp) {
1341
1342	case CERR_BADFMT:
1343		fprintf(stderr,
1344		    "***Server reports a bad format request packet\n");
1345		break;
1346
1347	case CERR_PERMISSION:
1348		fprintf(stderr,
1349		    "***Server disallowed request (authentication?)\n");
1350		break;
1351
1352	case CERR_BADOP:
1353		fprintf(stderr,
1354		    "***Server reports a bad opcode in request\n");
1355		break;
1356
1357	case CERR_BADASSOC:
1358		fprintf(stderr,
1359		    "***Association ID %d unknown to server\n",
1360		    associd);
1361		break;
1362
1363	case CERR_UNKNOWNVAR:
1364		fprintf(stderr,
1365		    "***A request variable unknown to the server\n");
1366		break;
1367
1368	case CERR_BADVALUE:
1369		fprintf(stderr,
1370		    "***Server indicates a request variable was bad\n");
1371		break;
1372
1373	case ERR_UNSPEC:
1374		fprintf(stderr,
1375		    "***Server returned an unspecified error\n");
1376		break;
1377
1378	case ERR_TIMEOUT:
1379		fprintf(stderr, "***Request timed out\n");
1380		break;
1381
1382	case ERR_INCOMPLETE:
1383		fprintf(stderr,
1384		    "***Response from server was incomplete\n");
1385		break;
1386
1387	case ERR_TOOMUCH:
1388		fprintf(stderr,
1389		    "***Buffer size exceeded for returned data\n");
1390		break;
1391
1392	default:
1393		fprintf(stderr,
1394		    "***Server returns unknown error code %d\n",
1395		    m6resp);
1396	}
1397}
1398
1399/*
1400 * doquery - send a request and process the response, displaying
1401 *	     error messages for any error responses.
1402 */
1403int
1404doquery(
1405	int opcode,
1406	associd_t associd,
1407	int auth,
1408	size_t qsize,
1409	const char *qdata,
1410	u_short *rstatus,
1411	size_t *rsize,
1412	const char **rdata
1413	)
1414{
1415	return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
1416			 rsize, rdata, FALSE);
1417}
1418
1419
1420/*
1421 * doqueryex - send a request and process the response, optionally
1422 *	       displaying error messages for any error responses.
1423 */
1424int
1425doqueryex(
1426	int opcode,
1427	associd_t associd,
1428	int auth,
1429	size_t qsize,
1430	const char *qdata,
1431	u_short *rstatus,
1432	size_t *rsize,
1433	const char **rdata,
1434	int quiet
1435	)
1436{
1437	int res;
1438	int done;
1439
1440	/*
1441	 * Check to make sure host is open
1442	 */
1443	if (!havehost) {
1444		fprintf(stderr, "***No host open, use `host' command\n");
1445		return -1;
1446	}
1447
1448	done = 0;
1449	sequence++;
1450
1451    again:
1452	/*
1453	 * send a request
1454	 */
1455	res = sendrequest(opcode, associd, auth, qsize, qdata);
1456	if (res != 0)
1457		return res;
1458
1459	/*
1460	 * Get the response.  If we got a standard error, print a message
1461	 */
1462	res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1463
1464	if (res > 0) {
1465		if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1466			if (res == ERR_INCOMPLETE) {
1467				/*
1468				 * better bump the sequence so we don't
1469				 * get confused about differing fragments.
1470				 */
1471				sequence++;
1472			}
1473			done = 1;
1474			goto again;
1475		}
1476		if (!quiet)
1477			show_error_msg(res, associd);
1478
1479	}
1480	return res;
1481}
1482
1483
1484#ifndef BUILD_AS_LIB
1485/*
1486 * getcmds - read commands from the standard input and execute them
1487 */
1488static void
1489getcmds(void)
1490{
1491	char *	line;
1492	int	count;
1493
1494	ntp_readline_init(interactive ? prompt : NULL);
1495
1496	for (;;) {
1497		line = ntp_readline(&count);
1498		if (NULL == line)
1499			break;
1500		docmd(line);
1501		free(line);
1502	}
1503
1504	ntp_readline_uninit();
1505}
1506#endif /* !BUILD_AS_LIB */
1507
1508
1509#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1510/*
1511 * abortcmd - catch interrupts and abort the current command
1512 */
1513static int
1514abortcmd(void)
1515{
1516	if (current_output == stdout)
1517		(void) fflush(stdout);
1518	putc('\n', stderr);
1519	(void) fflush(stderr);
1520	if (jump) {
1521		jump = 0;
1522		longjmp(interrupt_buf, 1);
1523	}
1524	return TRUE;
1525}
1526#endif	/* !SYS_WINNT && !BUILD_AS_LIB */
1527
1528
1529#ifndef	BUILD_AS_LIB
1530/*
1531 * docmd - decode the command line and execute a command
1532 */
1533static void
1534docmd(
1535	const char *cmdline
1536	)
1537{
1538	char *tokens[1+MAXARGS+2];
1539	struct parse pcmd;
1540	int ntok;
1541	static int i;
1542	struct xcmd *xcmd;
1543
1544	/*
1545	 * Tokenize the command line.  If nothing on it, return.
1546	 */
1547	tokenize(cmdline, tokens, &ntok);
1548	if (ntok == 0)
1549	    return;
1550
1551	/*
1552	 * Find the appropriate command description.
1553	 */
1554	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1555	if (i == 0) {
1556		(void) fprintf(stderr, "***Command `%s' unknown\n",
1557			       tokens[0]);
1558		return;
1559	} else if (i >= 2) {
1560		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1561			       tokens[0]);
1562		return;
1563	}
1564
1565	/* Warn about ignored extra args */
1566	for (i = MAXARGS + 1; i < ntok ; ++i) {
1567		fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
1568	}
1569
1570	/*
1571	 * Save the keyword, then walk through the arguments, interpreting
1572	 * as we go.
1573	 */
1574	pcmd.keyword = tokens[0];
1575	pcmd.nargs = 0;
1576	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1577		if ((i+1) >= ntok) {
1578			if (!(xcmd->arg[i] & OPT)) {
1579				printusage(xcmd, stderr);
1580				return;
1581			}
1582			break;
1583		}
1584		if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1585			break;
1586		if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1587			return;
1588		pcmd.nargs++;
1589	}
1590
1591	i++;
1592	if (i < ntok && *tokens[i] == '>') {
1593		char *fname;
1594
1595		if (*(tokens[i]+1) != '\0')
1596			fname = tokens[i]+1;
1597		else if ((i+1) < ntok)
1598			fname = tokens[i+1];
1599		else {
1600			(void) fprintf(stderr, "***No file for redirect\n");
1601			return;
1602		}
1603
1604		current_output = fopen(fname, "w");
1605		if (current_output == NULL) {
1606			(void) fprintf(stderr, "***Error opening %s: ", fname);
1607			perror("");
1608			return;
1609		}
1610		i = 1;		/* flag we need a close */
1611	} else {
1612		current_output = stdout;
1613		i = 0;		/* flag no close */
1614	}
1615
1616	if (interactive && setjmp(interrupt_buf)) {
1617		jump = 0;
1618		return;
1619	} else {
1620		jump++;
1621		(xcmd->handler)(&pcmd, current_output);
1622		jump = 0;	/* HMS: 961106: was after fclose() */
1623		if (i) (void) fclose(current_output);
1624	}
1625
1626	return;
1627}
1628
1629
1630/*
1631 * tokenize - turn a command line into tokens
1632 *
1633 * SK: Modified to allow a quoted string
1634 *
1635 * HMS: If the first character of the first token is a ':' then (after
1636 * eating inter-token whitespace) the 2nd token is the rest of the line.
1637 */
1638
1639static void
1640tokenize(
1641	const char *line,
1642	char **tokens,
1643	int *ntok
1644	)
1645{
1646	register const char *cp;
1647	register char *sp;
1648	static char tspace[MAXLINE];
1649
1650	sp = tspace;
1651	cp = line;
1652	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1653		tokens[*ntok] = sp;
1654
1655		/* Skip inter-token whitespace */
1656		while (ISSPACE(*cp))
1657		    cp++;
1658
1659		/* If we're at EOL we're done */
1660		if (ISEOL(*cp))
1661		    break;
1662
1663		/* If this is the 2nd token and the first token begins
1664		 * with a ':', then just grab to EOL.
1665		 */
1666
1667		if (*ntok == 1 && tokens[0][0] == ':') {
1668			do {
1669				if (sp - tspace >= MAXLINE)
1670					goto toobig;
1671				*sp++ = *cp++;
1672			} while (!ISEOL(*cp));
1673		}
1674
1675		/* Check if this token begins with a double quote.
1676		 * If yes, continue reading till the next double quote
1677		 */
1678		else if (*cp == '\"') {
1679			++cp;
1680			do {
1681				if (sp - tspace >= MAXLINE)
1682					goto toobig;
1683				*sp++ = *cp++;
1684			} while ((*cp != '\"') && !ISEOL(*cp));
1685			/* HMS: a missing closing " should be an error */
1686		}
1687		else {
1688			do {
1689				if (sp - tspace >= MAXLINE)
1690					goto toobig;
1691				*sp++ = *cp++;
1692			} while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1693			/* HMS: Why check for a " in the previous line? */
1694		}
1695
1696		if (sp - tspace >= MAXLINE)
1697			goto toobig;
1698		*sp++ = '\0';
1699	}
1700	return;
1701
1702  toobig:
1703	*ntok = 0;
1704	fprintf(stderr,
1705		"***Line `%s' is too big\n",
1706		line);
1707	return;
1708}
1709
1710
1711/*
1712 * getarg - interpret an argument token
1713 */
1714static int
1715getarg(
1716	const char *str,
1717	int code,
1718	arg_v *argp
1719	)
1720{
1721	u_long ul;
1722
1723	switch (code & ~OPT) {
1724	case NTP_STR:
1725		argp->string = str;
1726		break;
1727
1728	case NTP_ADD:
1729		if (!getnetnum(str, &argp->netnum, NULL, 0))
1730			return 0;
1731		break;
1732
1733	case NTP_UINT:
1734		if ('&' == str[0]) {
1735			if (!atouint(&str[1], &ul)) {
1736				fprintf(stderr,
1737					"***Association index `%s' invalid/undecodable\n",
1738					str);
1739				return 0;
1740			}
1741			if (0 == numassoc) {
1742				dogetassoc(stdout);
1743				if (0 == numassoc) {
1744					fprintf(stderr,
1745						"***No associations found, `%s' unknown\n",
1746						str);
1747					return 0;
1748				}
1749			}
1750			ul = min(ul, numassoc);
1751			argp->uval = assoc_cache[ul - 1].assid;
1752			break;
1753		}
1754		if (!atouint(str, &argp->uval)) {
1755			fprintf(stderr, "***Illegal unsigned value %s\n",
1756				str);
1757			return 0;
1758		}
1759		break;
1760
1761	case NTP_INT:
1762		if (!atoint(str, &argp->ival)) {
1763			fprintf(stderr, "***Illegal integer value %s\n",
1764				str);
1765			return 0;
1766		}
1767		break;
1768
1769	case IP_VERSION:
1770		if (!strcmp("-6", str)) {
1771			argp->ival = 6;
1772		} else if (!strcmp("-4", str)) {
1773			argp->ival = 4;
1774		} else {
1775			fprintf(stderr, "***Version must be either 4 or 6\n");
1776			return 0;
1777		}
1778		break;
1779	}
1780
1781	return 1;
1782}
1783#endif	/* !BUILD_AS_LIB */
1784
1785
1786/*
1787 * findcmd - find a command in a command description table
1788 */
1789static int
1790findcmd(
1791	const char *	str,
1792	struct xcmd *	clist1,
1793	struct xcmd *	clist2,
1794	struct xcmd **	cmd
1795	)
1796{
1797	struct xcmd *cl;
1798	size_t clen;
1799	int nmatch;
1800	struct xcmd *nearmatch = NULL;
1801	struct xcmd *clist;
1802
1803	clen = strlen(str);
1804	nmatch = 0;
1805	if (clist1 != 0)
1806	    clist = clist1;
1807	else if (clist2 != 0)
1808	    clist = clist2;
1809	else
1810	    return 0;
1811
1812    again:
1813	for (cl = clist; cl->keyword != 0; cl++) {
1814		/* do a first character check, for efficiency */
1815		if (*str != *(cl->keyword))
1816		    continue;
1817		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1818			/*
1819			 * Could be extact match, could be approximate.
1820			 * Is exact if the length of the keyword is the
1821			 * same as the str.
1822			 */
1823			if (*((cl->keyword) + clen) == '\0') {
1824				*cmd = cl;
1825				return 1;
1826			}
1827			nmatch++;
1828			nearmatch = cl;
1829		}
1830	}
1831
1832	/*
1833	 * See if there is more to do.  If so, go again.  Sorry about the
1834	 * goto, too much looking at BSD sources...
1835	 */
1836	if (clist == clist1 && clist2 != 0) {
1837		clist = clist2;
1838		goto again;
1839	}
1840
1841	/*
1842	 * If we got extactly 1 near match, use it, else return number
1843	 * of matches.
1844	 */
1845	if (nmatch == 1) {
1846		*cmd = nearmatch;
1847		return 1;
1848	}
1849	return nmatch;
1850}
1851
1852
1853/*
1854 * getnetnum - given a host name, return its net number
1855 *	       and (optional) full name
1856 */
1857int
1858getnetnum(
1859	const char *hname,
1860	sockaddr_u *num,
1861	char *fullhost,
1862	int af
1863	)
1864{
1865	struct addrinfo hints, *ai = NULL;
1866
1867	ZERO(hints);
1868	hints.ai_flags = AI_CANONNAME;
1869#ifdef AI_ADDRCONFIG
1870	hints.ai_flags |= AI_ADDRCONFIG;
1871#endif
1872
1873	/*
1874	 * decodenetnum only works with addresses, but handles syntax
1875	 * that getaddrinfo doesn't:  [2001::1]:1234
1876	 */
1877	if (decodenetnum(hname, num)) {
1878		if (fullhost != NULL)
1879			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1880				    LENHOSTNAME, NULL, 0, 0);
1881		return 1;
1882	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1883		INSIST(sizeof(*num) >= ai->ai_addrlen);
1884		memcpy(num, ai->ai_addr, ai->ai_addrlen);
1885		if (fullhost != NULL) {
1886			if (ai->ai_canonname != NULL)
1887				strlcpy(fullhost, ai->ai_canonname,
1888					LENHOSTNAME);
1889			else
1890				getnameinfo(&num->sa, SOCKLEN(num),
1891					    fullhost, LENHOSTNAME, NULL,
1892					    0, 0);
1893		}
1894		freeaddrinfo(ai);
1895		return 1;
1896	}
1897	fprintf(stderr, "***Can't find host %s\n", hname);
1898
1899	return 0;
1900}
1901
1902
1903/*
1904 * nntohost - convert network number to host name.  This routine enforces
1905 *	       the showhostnames setting.
1906 */
1907const char *
1908nntohost(
1909	sockaddr_u *netnum
1910	)
1911{
1912	return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
1913}
1914
1915
1916/*
1917 * nntohost_col - convert network number to host name in fixed width.
1918 *		  This routine enforces the showhostnames setting.
1919 *		  When displaying hostnames longer than the width,
1920 *		  the first part of the hostname is displayed.  When
1921 *		  displaying numeric addresses longer than the width,
1922 *		  Such as IPv6 addresses, the caller decides whether
1923 *		  the first or last of the numeric address is used.
1924 */
1925const char *
1926nntohost_col(
1927	sockaddr_u *	addr,
1928	size_t		width,
1929	int		preserve_lowaddrbits
1930	)
1931{
1932	const char *	out;
1933
1934	if (!showhostnames || SOCK_UNSPEC(addr)) {
1935		if (preserve_lowaddrbits)
1936			out = trunc_left(stoa(addr), width);
1937		else
1938			out = trunc_right(stoa(addr), width);
1939	} else if (ISREFCLOCKADR(addr)) {
1940		out = refnumtoa(addr);
1941	} else {
1942		out = trunc_right(socktohost(addr), width);
1943	}
1944	return out;
1945}
1946
1947
1948/*
1949 * nntohostp() is the same as nntohost() plus a :port suffix
1950 */
1951const char *
1952nntohostp(
1953	sockaddr_u *netnum
1954	)
1955{
1956	const char *	hostn;
1957	char *		buf;
1958
1959	if (!showhostnames || SOCK_UNSPEC(netnum))
1960		return sptoa(netnum);
1961	else if (ISREFCLOCKADR(netnum))
1962		return refnumtoa(netnum);
1963
1964	hostn = socktohost(netnum);
1965	LIB_GETBUF(buf);
1966	snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
1967
1968	return buf;
1969}
1970
1971/*
1972 * rtdatetolfp - decode an RT-11 date into an l_fp
1973 */
1974static int
1975rtdatetolfp(
1976	char *str,
1977	l_fp *lfp
1978	)
1979{
1980	register char *cp;
1981	register int i;
1982	struct calendar cal;
1983	char buf[4];
1984
1985	cal.yearday = 0;
1986
1987	/*
1988	 * An RT-11 date looks like:
1989	 *
1990	 * d[d]-Mth-y[y] hh:mm:ss
1991	 *
1992	 * (No docs, but assume 4-digit years are also legal...)
1993	 *
1994	 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1995	 */
1996	cp = str;
1997	if (!isdigit((int)*cp)) {
1998		if (*cp == '-') {
1999			/*
2000			 * Catch special case
2001			 */
2002			L_CLR(lfp);
2003			return 1;
2004		}
2005		return 0;
2006	}
2007
2008	cal.monthday = (u_char) (*cp++ - '0');	/* ascii dependent */
2009	if (isdigit((int)*cp)) {
2010		cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
2011		cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
2012	}
2013
2014	if (*cp++ != '-')
2015	    return 0;
2016
2017	for (i = 0; i < 3; i++)
2018	    buf[i] = *cp++;
2019	buf[3] = '\0';
2020
2021	for (i = 0; i < 12; i++)
2022	    if (STREQ(buf, months[i]))
2023		break;
2024	if (i == 12)
2025	    return 0;
2026	cal.month = (u_char)(i + 1);
2027
2028	if (*cp++ != '-')
2029	    return 0;
2030
2031	if (!isdigit((int)*cp))
2032	    return 0;
2033	cal.year = (u_short)(*cp++ - '0');
2034	if (isdigit((int)*cp)) {
2035		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2036		cal.year = (u_short)(*cp++ - '0');
2037	}
2038	if (isdigit((int)*cp)) {
2039		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2040		cal.year = (u_short)(cal.year + *cp++ - '0');
2041	}
2042	if (isdigit((int)*cp)) {
2043		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2044		cal.year = (u_short)(cal.year + *cp++ - '0');
2045	}
2046
2047	/*
2048	 * Catch special case.  If cal.year == 0 this is a zero timestamp.
2049	 */
2050	if (cal.year == 0) {
2051		L_CLR(lfp);
2052		return 1;
2053	}
2054
2055	if (*cp++ != ' ' || !isdigit((int)*cp))
2056	    return 0;
2057	cal.hour = (u_char)(*cp++ - '0');
2058	if (isdigit((int)*cp)) {
2059		cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
2060		cal.hour = (u_char)(cal.hour + *cp++ - '0');
2061	}
2062
2063	if (*cp++ != ':' || !isdigit((int)*cp))
2064	    return 0;
2065	cal.minute = (u_char)(*cp++ - '0');
2066	if (isdigit((int)*cp)) {
2067		cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
2068		cal.minute = (u_char)(cal.minute + *cp++ - '0');
2069	}
2070
2071	if (*cp++ != ':' || !isdigit((int)*cp))
2072	    return 0;
2073	cal.second = (u_char)(*cp++ - '0');
2074	if (isdigit((int)*cp)) {
2075		cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
2076		cal.second = (u_char)(cal.second + *cp++ - '0');
2077	}
2078
2079	/*
2080	 * For RT-11, 1972 seems to be the pivot year
2081	 */
2082	if (cal.year < 72)
2083		cal.year += 2000;
2084	if (cal.year < 100)
2085		cal.year += 1900;
2086
2087	lfp->l_ui = caltontp(&cal);
2088	lfp->l_uf = 0;
2089	return 1;
2090}
2091
2092
2093/*
2094 * decodets - decode a timestamp into an l_fp format number, with
2095 *	      consideration of fuzzball formats.
2096 */
2097int
2098decodets(
2099	char *str,
2100	l_fp *lfp
2101	)
2102{
2103	char *cp;
2104	char buf[30];
2105	size_t b;
2106
2107	/*
2108	 * If it starts with a 0x, decode as hex.
2109	 */
2110	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2111		return hextolfp(str+2, lfp);
2112
2113	/*
2114	 * If it starts with a '"', try it as an RT-11 date.
2115	 */
2116	if (*str == '"') {
2117		cp = str + 1;
2118		b = 0;
2119		while ('"' != *cp && '\0' != *cp &&
2120		       b < COUNTOF(buf) - 1)
2121			buf[b++] = *cp++;
2122		buf[b] = '\0';
2123		return rtdatetolfp(buf, lfp);
2124	}
2125
2126	/*
2127	 * Might still be hex.  Check out the first character.  Talk
2128	 * about heuristics!
2129	 */
2130	if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2131		return hextolfp(str, lfp);
2132
2133	/*
2134	 * Try it as a decimal.  If this fails, try as an unquoted
2135	 * RT-11 date.  This code should go away eventually.
2136	 */
2137	if (atolfp(str, lfp))
2138		return 1;
2139
2140	return rtdatetolfp(str, lfp);
2141}
2142
2143
2144/*
2145 * decodetime - decode a time value.  It should be in milliseconds
2146 */
2147int
2148decodetime(
2149	char *str,
2150	l_fp *lfp
2151	)
2152{
2153	return mstolfp(str, lfp);
2154}
2155
2156
2157/*
2158 * decodeint - decode an integer
2159 */
2160int
2161decodeint(
2162	char *str,
2163	long *val
2164	)
2165{
2166	if (*str == '0') {
2167		if (*(str+1) == 'x' || *(str+1) == 'X')
2168		    return hextoint(str+2, (u_long *)val);
2169		return octtoint(str, (u_long *)val);
2170	}
2171	return atoint(str, val);
2172}
2173
2174
2175/*
2176 * decodeuint - decode an unsigned integer
2177 */
2178int
2179decodeuint(
2180	char *str,
2181	u_long *val
2182	)
2183{
2184	if (*str == '0') {
2185		if (*(str + 1) == 'x' || *(str + 1) == 'X')
2186			return (hextoint(str + 2, val));
2187		return (octtoint(str, val));
2188	}
2189	return (atouint(str, val));
2190}
2191
2192
2193/*
2194 * decodearr - decode an array of time values
2195 */
2196static int
2197decodearr(
2198	char *str,
2199	int *narr,
2200	l_fp *lfparr
2201	)
2202{
2203	register char *cp, *bp;
2204	register l_fp *lfp;
2205	char buf[60];
2206
2207	lfp = lfparr;
2208	cp = str;
2209	*narr = 0;
2210
2211	while (*narr < 8) {
2212		while (isspace((int)*cp))
2213		    cp++;
2214		if (*cp == '\0')
2215		    break;
2216
2217		bp = buf;
2218		while (!isspace((int)*cp) && *cp != '\0')
2219		    *bp++ = *cp++;
2220		*bp++ = '\0';
2221
2222		if (!decodetime(buf, lfp))
2223		    return 0;
2224		(*narr)++;
2225		lfp++;
2226	}
2227	return 1;
2228}
2229
2230
2231/*
2232 * Finally, the built in command handlers
2233 */
2234
2235/*
2236 * help - tell about commands, or details of a particular command
2237 */
2238static void
2239help(
2240	struct parse *pcmd,
2241	FILE *fp
2242	)
2243{
2244	struct xcmd *xcp = NULL;	/* quiet warning */
2245	const char *cmd;
2246	const char *list[100];
2247	size_t word, words;
2248	size_t row, rows;
2249	size_t col, cols;
2250	size_t length;
2251
2252	if (pcmd->nargs == 0) {
2253		words = 0;
2254		for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2255			if (*(xcp->keyword) != '?' &&
2256			    words < COUNTOF(list))
2257				list[words++] = xcp->keyword;
2258		}
2259		for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2260			if (words < COUNTOF(list))
2261				list[words++] = xcp->keyword;
2262
2263		qsort((void *)list, words, sizeof(list[0]), helpsort);
2264		col = 0;
2265		for (word = 0; word < words; word++) {
2266			length = strlen(list[word]);
2267			col = max(col, length);
2268		}
2269
2270		cols = SCREENWIDTH / ++col;
2271		rows = (words + cols - 1) / cols;
2272
2273		fprintf(fp, "ntpq commands:\n");
2274
2275		for (row = 0; row < rows; row++) {
2276			for (word = row; word < words; word += rows)
2277				fprintf(fp, "%-*.*s", (int)col,
2278					(int)col - 1, list[word]);
2279			fprintf(fp, "\n");
2280		}
2281	} else {
2282		cmd = pcmd->argval[0].string;
2283		words = findcmd(cmd, builtins, opcmds, &xcp);
2284		if (words == 0) {
2285			fprintf(stderr,
2286				"Command `%s' is unknown\n", cmd);
2287			return;
2288		} else if (words >= 2) {
2289			fprintf(stderr,
2290				"Command `%s' is ambiguous\n", cmd);
2291			return;
2292		}
2293		fprintf(fp, "function: %s\n", xcp->comment);
2294		printusage(xcp, fp);
2295	}
2296}
2297
2298
2299/*
2300 * helpsort - do hostname qsort comparisons
2301 */
2302static int
2303helpsort(
2304	const void *t1,
2305	const void *t2
2306	)
2307{
2308	const char * const *	name1 = t1;
2309	const char * const *	name2 = t2;
2310
2311	return strcmp(*name1, *name2);
2312}
2313
2314
2315/*
2316 * printusage - print usage information for a command
2317 */
2318static void
2319printusage(
2320	struct xcmd *xcp,
2321	FILE *fp
2322	)
2323{
2324	register int i;
2325
2326	/* XXX: Do we need to warn about extra args here too? */
2327
2328	(void) fprintf(fp, "usage: %s", xcp->keyword);
2329	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2330		if (xcp->arg[i] & OPT)
2331		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2332		else
2333		    (void) fprintf(fp, " %s", xcp->desc[i]);
2334	}
2335	(void) fprintf(fp, "\n");
2336}
2337
2338
2339/*
2340 * timeout - set time out time
2341 */
2342static void
2343timeout(
2344	struct parse *pcmd,
2345	FILE *fp
2346	)
2347{
2348	int val;
2349
2350	if (pcmd->nargs == 0) {
2351		val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2352		(void) fprintf(fp, "primary timeout %d ms\n", val);
2353	} else {
2354		tvout.tv_sec = pcmd->argval[0].uval / 1000;
2355		tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2356			* 1000;
2357	}
2358}
2359
2360
2361/*
2362 * auth_delay - set delay for auth requests
2363 */
2364static void
2365auth_delay(
2366	struct parse *pcmd,
2367	FILE *fp
2368	)
2369{
2370	int isneg;
2371	u_long val;
2372
2373	if (pcmd->nargs == 0) {
2374		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2375		(void) fprintf(fp, "delay %lu ms\n", val);
2376	} else {
2377		if (pcmd->argval[0].ival < 0) {
2378			isneg = 1;
2379			val = (u_long)(-pcmd->argval[0].ival);
2380		} else {
2381			isneg = 0;
2382			val = (u_long)pcmd->argval[0].ival;
2383		}
2384
2385		delay_time.l_ui = val / 1000;
2386		val %= 1000;
2387		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
2388
2389		if (isneg)
2390		    L_NEG(&delay_time);
2391	}
2392}
2393
2394
2395/*
2396 * host - set the host we are dealing with.
2397 */
2398static void
2399host(
2400	struct parse *pcmd,
2401	FILE *fp
2402	)
2403{
2404	int i;
2405
2406	if (pcmd->nargs == 0) {
2407		if (havehost)
2408			(void) fprintf(fp, "current host is %s\n",
2409					   currenthost);
2410		else
2411			(void) fprintf(fp, "no current host\n");
2412		return;
2413	}
2414
2415	i = 0;
2416	ai_fam_templ = ai_fam_default;
2417	if (pcmd->nargs == 2) {
2418		if (!strcmp("-4", pcmd->argval[i].string))
2419			ai_fam_templ = AF_INET;
2420		else if (!strcmp("-6", pcmd->argval[i].string))
2421			ai_fam_templ = AF_INET6;
2422		else
2423			goto no_change;
2424		i = 1;
2425	}
2426	if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
2427		fprintf(fp, "current host set to %s\n", currenthost);
2428	} else {
2429    no_change:
2430		if (havehost)
2431			fprintf(fp, "current host remains %s\n",
2432				currenthost);
2433		else
2434			fprintf(fp, "still no current host\n");
2435	}
2436}
2437
2438
2439/*
2440 * poll - do one (or more) polls of the host via NTP
2441 */
2442/*ARGSUSED*/
2443static void
2444ntp_poll(
2445	struct parse *pcmd,
2446	FILE *fp
2447	)
2448{
2449	(void) fprintf(fp, "poll not implemented yet\n");
2450}
2451
2452
2453/*
2454 * showdrefid2str - return a string explanation of the value of drefid
2455 */
2456static char *
2457showdrefid2str(void)
2458{
2459	switch (drefid) {
2460	    case REFID_HASH:
2461	    	return "hash";
2462	    case REFID_IPV4:
2463	    	return "ipv4";
2464	    default:
2465	    	return "Unknown";
2466	}
2467}
2468
2469
2470/*
2471 * drefid - display/change "display hash"
2472 */
2473static void
2474showdrefid(
2475	struct parse *pcmd,
2476	FILE *fp
2477	)
2478{
2479	if (pcmd->nargs == 0) {
2480		(void) fprintf(fp, "drefid value is %s\n", showdrefid2str());
2481		return;
2482	} else if (STREQ(pcmd->argval[0].string, "hash")) {
2483		drefid = REFID_HASH;
2484	} else if (STREQ(pcmd->argval[0].string, "ipv4")) {
2485		drefid = REFID_IPV4;
2486	} else {
2487		(void) fprintf(fp, "What?\n");
2488		return;
2489	}
2490	(void) fprintf(fp, "drefid value set to %s\n", showdrefid2str());
2491}
2492
2493
2494/*
2495 * keyid - get a keyid to use for authenticating requests
2496 */
2497static void
2498keyid(
2499	struct parse *pcmd,
2500	FILE *fp
2501	)
2502{
2503	if (pcmd->nargs == 0) {
2504		if (info_auth_keyid == 0)
2505		    (void) fprintf(fp, "no keyid defined\n");
2506		else
2507		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2508	} else {
2509		/* allow zero so that keyid can be cleared. */
2510		if(pcmd->argval[0].uval > NTP_MAXKEY)
2511		    (void) fprintf(fp, "Invalid key identifier\n");
2512		info_auth_keyid = pcmd->argval[0].uval;
2513	}
2514}
2515
2516/*
2517 * keytype - get type of key to use for authenticating requests
2518 */
2519static void
2520keytype(
2521	struct parse *pcmd,
2522	FILE *fp
2523	)
2524{
2525	const char *	digest_name;
2526	size_t		digest_len;
2527	int		key_type;
2528
2529	if (!pcmd->nargs) {
2530		fprintf(fp, "keytype is %s with %lu octet digests\n",
2531			keytype_name(info_auth_keytype),
2532			(u_long)info_auth_hashlen);
2533		return;
2534	}
2535
2536	digest_name = pcmd->argval[0].string;
2537	digest_len = 0;
2538	key_type = keytype_from_text(digest_name, &digest_len);
2539
2540	if (!key_type) {
2541		fprintf(fp, "keytype is not valid. "
2542#ifdef OPENSSL
2543			"Type \"help keytype\" for the available digest types.\n");
2544#else
2545			"Only \"md5\" is available.\n");
2546#endif
2547		return;
2548	}
2549
2550	info_auth_keytype = key_type;
2551	info_auth_hashlen = digest_len;
2552}
2553
2554
2555/*
2556 * passwd - get an authentication key
2557 */
2558/*ARGSUSED*/
2559static void
2560passwd(
2561	struct parse *pcmd,
2562	FILE *fp
2563	)
2564{
2565	const char *pass;
2566
2567	if (info_auth_keyid == 0) {
2568		info_auth_keyid = getkeyid("Keyid: ");
2569		if (info_auth_keyid == 0) {
2570			(void)fprintf(fp, "Keyid must be defined\n");
2571			return;
2572		}
2573	}
2574	if (pcmd->nargs >= 1)
2575		pass = pcmd->argval[0].string;
2576	else {
2577		pass = getpass_keytype(info_auth_keytype);
2578		if ('\0' == pass[0]) {
2579			fprintf(fp, "Password unchanged\n");
2580			return;
2581		}
2582	}
2583	authusekey(info_auth_keyid, info_auth_keytype,
2584		   (const u_char *)pass);
2585	authtrust(info_auth_keyid, 1);
2586}
2587
2588
2589/*
2590 * hostnames - set the showhostnames flag
2591 */
2592static void
2593hostnames(
2594	struct parse *pcmd,
2595	FILE *fp
2596	)
2597{
2598	if (pcmd->nargs == 0) {
2599		if (showhostnames)
2600		    (void) fprintf(fp, "hostnames being shown\n");
2601		else
2602		    (void) fprintf(fp, "hostnames not being shown\n");
2603	} else {
2604		if (STREQ(pcmd->argval[0].string, "yes"))
2605		    showhostnames = 1;
2606		else if (STREQ(pcmd->argval[0].string, "no"))
2607		    showhostnames = 0;
2608		else
2609		    (void)fprintf(stderr, "What?\n");
2610	}
2611}
2612
2613
2614
2615/*
2616 * setdebug - set/change debugging level
2617 */
2618static void
2619setdebug(
2620	struct parse *pcmd,
2621	FILE *fp
2622	)
2623{
2624	if (pcmd->nargs == 0) {
2625		(void) fprintf(fp, "debug level is %d\n", debug);
2626		return;
2627	} else if (STREQ(pcmd->argval[0].string, "no")) {
2628		debug = 0;
2629	} else if (STREQ(pcmd->argval[0].string, "more")) {
2630		debug++;
2631	} else if (STREQ(pcmd->argval[0].string, "less")) {
2632		debug--;
2633	} else {
2634		(void) fprintf(fp, "What?\n");
2635		return;
2636	}
2637	(void) fprintf(fp, "debug level set to %d\n", debug);
2638}
2639
2640
2641/*
2642 * quit - stop this nonsense
2643 */
2644/*ARGSUSED*/
2645static void
2646quit(
2647	struct parse *pcmd,
2648	FILE *fp
2649	)
2650{
2651	if (havehost)
2652	    closesocket(sockfd);	/* cleanliness next to godliness */
2653	exit(0);
2654}
2655
2656
2657/*
2658 * version - print the current version number
2659 */
2660/*ARGSUSED*/
2661static void
2662version(
2663	struct parse *pcmd,
2664	FILE *fp
2665	)
2666{
2667
2668	(void) fprintf(fp, "%s\n", Version);
2669	return;
2670}
2671
2672
2673/*
2674 * raw - set raw mode output
2675 */
2676/*ARGSUSED*/
2677static void
2678raw(
2679	struct parse *pcmd,
2680	FILE *fp
2681	)
2682{
2683	rawmode = 1;
2684	(void) fprintf(fp, "Output set to raw\n");
2685}
2686
2687
2688/*
2689 * cooked - set cooked mode output
2690 */
2691/*ARGSUSED*/
2692static void
2693cooked(
2694	struct parse *pcmd,
2695	FILE *fp
2696	)
2697{
2698	rawmode = 0;
2699	(void) fprintf(fp, "Output set to cooked\n");
2700	return;
2701}
2702
2703
2704/*
2705 * authenticate - always authenticate requests to this host
2706 */
2707static void
2708authenticate(
2709	struct parse *pcmd,
2710	FILE *fp
2711	)
2712{
2713	if (pcmd->nargs == 0) {
2714		if (always_auth) {
2715			(void) fprintf(fp,
2716				       "authenticated requests being sent\n");
2717		} else
2718		    (void) fprintf(fp,
2719				   "unauthenticated requests being sent\n");
2720	} else {
2721		if (STREQ(pcmd->argval[0].string, "yes")) {
2722			always_auth = 1;
2723		} else if (STREQ(pcmd->argval[0].string, "no")) {
2724			always_auth = 0;
2725		} else
2726		    (void)fprintf(stderr, "What?\n");
2727	}
2728}
2729
2730
2731/*
2732 * ntpversion - choose the NTP version to use
2733 */
2734static void
2735ntpversion(
2736	struct parse *pcmd,
2737	FILE *fp
2738	)
2739{
2740	if (pcmd->nargs == 0) {
2741		(void) fprintf(fp,
2742			       "NTP version being claimed is %d\n", pktversion);
2743	} else {
2744		if (pcmd->argval[0].uval < NTP_OLDVERSION
2745		    || pcmd->argval[0].uval > NTP_VERSION) {
2746			(void) fprintf(stderr, "versions %d to %d, please\n",
2747				       NTP_OLDVERSION, NTP_VERSION);
2748		} else {
2749			pktversion = (u_char) pcmd->argval[0].uval;
2750		}
2751	}
2752}
2753
2754
2755static void __attribute__((__format__(__printf__, 1, 0)))
2756vwarning(const char *fmt, va_list ap)
2757{
2758	int serrno = errno;
2759	(void) fprintf(stderr, "%s: ", progname);
2760	vfprintf(stderr, fmt, ap);
2761	(void) fprintf(stderr, ": %s\n", strerror(serrno));
2762}
2763
2764/*
2765 * warning - print a warning message
2766 */
2767static void __attribute__((__format__(__printf__, 1, 2)))
2768warning(
2769	const char *fmt,
2770	...
2771	)
2772{
2773	va_list ap;
2774	va_start(ap, fmt);
2775	vwarning(fmt, ap);
2776	va_end(ap);
2777}
2778
2779
2780/*
2781 * error - print a message and exit
2782 */
2783static void __attribute__((__format__(__printf__, 1, 2)))
2784error(
2785	const char *fmt,
2786	...
2787	)
2788{
2789	va_list ap;
2790	va_start(ap, fmt);
2791	vwarning(fmt, ap);
2792	va_end(ap);
2793	exit(1);
2794}
2795/*
2796 * getkeyid - prompt the user for a keyid to use
2797 */
2798static u_long
2799getkeyid(
2800	const char *keyprompt
2801	)
2802{
2803	int c;
2804	FILE *fi;
2805	char pbuf[20];
2806	size_t i;
2807	size_t ilim;
2808
2809#ifndef SYS_WINNT
2810	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2811#else
2812	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2813#endif /* SYS_WINNT */
2814		fi = stdin;
2815	else
2816		setbuf(fi, (char *)NULL);
2817	fprintf(stderr, "%s", keyprompt); fflush(stderr);
2818	for (i = 0, ilim = COUNTOF(pbuf) - 1;
2819	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
2820	     )
2821		pbuf[i++] = (char)c;
2822	pbuf[i] = '\0';
2823	if (fi != stdin)
2824		fclose(fi);
2825
2826	return (u_long) atoi(pbuf);
2827}
2828
2829
2830/*
2831 * atoascii - printable-ize possibly ascii data using the character
2832 *	      transformations cat -v uses.
2833 */
2834static void
2835atoascii(
2836	const char *in,
2837	size_t in_octets,
2838	char *out,
2839	size_t out_octets
2840	)
2841{
2842	const u_char *	pchIn;
2843	const u_char *	pchInLimit;
2844	u_char *	pchOut;
2845	u_char		c;
2846
2847	pchIn = (const u_char *)in;
2848	pchInLimit = pchIn + in_octets;
2849	pchOut = (u_char *)out;
2850
2851	if (NULL == pchIn) {
2852		if (0 < out_octets)
2853			*pchOut = '\0';
2854		return;
2855	}
2856
2857#define	ONEOUT(c)					\
2858do {							\
2859	if (0 == --out_octets) {			\
2860		*pchOut = '\0';				\
2861		return;					\
2862	}						\
2863	*pchOut++ = (c);				\
2864} while (0)
2865
2866	for (	; pchIn < pchInLimit; pchIn++) {
2867		c = *pchIn;
2868		if ('\0' == c)
2869			break;
2870		if (c & 0x80) {
2871			ONEOUT('M');
2872			ONEOUT('-');
2873			c &= 0x7f;
2874		}
2875		if (c < ' ') {
2876			ONEOUT('^');
2877			ONEOUT((u_char)(c + '@'));
2878		} else if (0x7f == c) {
2879			ONEOUT('^');
2880			ONEOUT('?');
2881		} else
2882			ONEOUT(c);
2883	}
2884	ONEOUT('\0');
2885
2886#undef ONEOUT
2887}
2888
2889
2890/*
2891 * makeascii - print possibly ascii data using the character
2892 *	       transformations that cat -v uses.
2893 */
2894void
2895makeascii(
2896	size_t length,
2897	const char *data,
2898	FILE *fp
2899	)
2900{
2901	const u_char *data_u_char;
2902	const u_char *cp;
2903	int c;
2904
2905	data_u_char = (const u_char *)data;
2906
2907	for (cp = data_u_char; cp < data_u_char + length; cp++) {
2908		c = (int)*cp;
2909		if (c & 0x80) {
2910			putc('M', fp);
2911			putc('-', fp);
2912			c &= 0x7f;
2913		}
2914
2915		if (c < ' ') {
2916			putc('^', fp);
2917			putc(c + '@', fp);
2918		} else if (0x7f == c) {
2919			putc('^', fp);
2920			putc('?', fp);
2921		} else
2922			putc(c, fp);
2923	}
2924}
2925
2926
2927/*
2928 * asciize - same thing as makeascii except add a newline
2929 */
2930void
2931asciize(
2932	int length,
2933	char *data,
2934	FILE *fp
2935	)
2936{
2937	makeascii(length, data, fp);
2938	putc('\n', fp);
2939}
2940
2941
2942/*
2943 * truncate string to fit clipping excess at end.
2944 *	"too long"	->	"too l"
2945 * Used for hostnames.
2946 */
2947const char *
2948trunc_right(
2949	const char *	src,
2950	size_t		width
2951	)
2952{
2953	size_t	sl;
2954	char *	out;
2955
2956
2957	sl = strlen(src);
2958	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
2959		LIB_GETBUF(out);
2960		memcpy(out, src, width);
2961		out[width] = '\0';
2962
2963		return out;
2964	}
2965
2966	return src;
2967}
2968
2969
2970/*
2971 * truncate string to fit by preserving right side and using '_' to hint
2972 *	"too long"	->	"_long"
2973 * Used for local IPv6 addresses, where low bits differentiate.
2974 */
2975const char *
2976trunc_left(
2977	const char *	src,
2978	size_t		width
2979	)
2980{
2981	size_t	sl;
2982	char *	out;
2983
2984
2985	sl = strlen(src);
2986	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
2987		LIB_GETBUF(out);
2988		out[0] = '_';
2989		memcpy(&out[1], &src[sl + 1 - width], width);
2990
2991		return out;
2992	}
2993
2994	return src;
2995}
2996
2997
2998/*
2999 * Some circular buffer space
3000 */
3001#define	CBLEN	80
3002#define	NUMCB	6
3003
3004char circ_buf[NUMCB][CBLEN];
3005int nextcb = 0;
3006
3007/*
3008 * nextvar - find the next variable in the buffer
3009 */
3010int
3011nextvar(
3012	size_t *datalen,
3013	const char **datap,
3014	char **vname,
3015	char **vvalue
3016	)
3017{
3018	const char *cp;
3019	const char *np;
3020	const char *cpend;
3021	size_t srclen;
3022	size_t len;
3023	static char name[MAXVARLEN];
3024	static char value[MAXVALLEN];
3025
3026	cp = *datap;
3027	cpend = cp + *datalen;
3028
3029	/*
3030	 * Space past commas and white space
3031	 */
3032	while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
3033		cp++;
3034	if (cp >= cpend)
3035		return 0;
3036
3037	/*
3038	 * Copy name until we hit a ',', an '=', a '\r' or a '\n'.  Backspace
3039	 * over any white space and terminate it.
3040	 */
3041	srclen = strcspn(cp, ",=\r\n");
3042	srclen = min(srclen, (size_t)(cpend - cp));
3043	len = srclen;
3044	while (len > 0 && isspace((unsigned char)cp[len - 1]))
3045		len--;
3046	if (len >= sizeof(name))
3047	    return 0;
3048	if (len > 0)
3049		memcpy(name, cp, len);
3050	name[len] = '\0';
3051	*vname = name;
3052	cp += srclen;
3053
3054	/*
3055	 * Check if we hit the end of the buffer or a ','.  If so we are done.
3056	 */
3057	if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
3058		if (cp < cpend)
3059			cp++;
3060		*datap = cp;
3061		*datalen = size2int_sat(cpend - cp);
3062		*vvalue = NULL;
3063		return 1;
3064	}
3065
3066	/*
3067	 * So far, so good.  Copy out the value
3068	 */
3069	cp++;	/* past '=' */
3070	while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n'))
3071		cp++;
3072	np = cp;
3073	if ('"' == *np) {
3074		do {
3075			np++;
3076		} while (np < cpend && '"' != *np);
3077		if (np < cpend && '"' == *np)
3078			np++;
3079	} else {
3080		while (np < cpend && ',' != *np && '\r' != *np)
3081			np++;
3082	}
3083	len = np - cp;
3084	if (np > cpend || len >= sizeof(value) ||
3085	    (np < cpend && ',' != *np && '\r' != *np))
3086		return 0;
3087	memcpy(value, cp, len);
3088	/*
3089	 * Trim off any trailing whitespace
3090	 */
3091	while (len > 0 && isspace((unsigned char)value[len - 1]))
3092		len--;
3093	value[len] = '\0';
3094
3095	/*
3096	 * Return this.  All done.
3097	 */
3098	if (np < cpend && ',' == *np)
3099		np++;
3100	*datap = np;
3101	*datalen = size2int_sat(cpend - np);
3102	*vvalue = value;
3103	return 1;
3104}
3105
3106
3107u_short
3108varfmt(const char * varname)
3109{
3110	u_int n;
3111
3112	for (n = 0; n < COUNTOF(cookedvars); n++)
3113		if (!strcmp(varname, cookedvars[n].varname))
3114			return cookedvars[n].fmt;
3115
3116	return PADDING;
3117}
3118
3119
3120/*
3121 * printvars - print variables returned in response packet
3122 */
3123void
3124printvars(
3125	size_t length,
3126	const char *data,
3127	int status,
3128	int sttype,
3129	int quiet,
3130	FILE *fp
3131	)
3132{
3133	if (rawmode)
3134	    rawprint(sttype, length, data, status, quiet, fp);
3135	else
3136	    cookedprint(sttype, length, data, status, quiet, fp);
3137}
3138
3139
3140/*
3141 * rawprint - do a printout of the data in raw mode
3142 */
3143static void
3144rawprint(
3145	int datatype,
3146	size_t length,
3147	const char *data,
3148	int status,
3149	int quiet,
3150	FILE *fp
3151	)
3152{
3153	const char *cp;
3154	const char *cpend;
3155
3156	/*
3157	 * Essentially print the data as is.  We reformat unprintables, though.
3158	 */
3159	cp = data;
3160	cpend = data + length;
3161
3162	if (!quiet)
3163		(void) fprintf(fp, "status=0x%04x,\n", status);
3164
3165	while (cp < cpend) {
3166		if (*cp == '\r') {
3167			/*
3168			 * If this is a \r and the next character is a
3169			 * \n, supress this, else pretty print it.  Otherwise
3170			 * just output the character.
3171			 */
3172			if (cp == (cpend - 1) || *(cp + 1) != '\n')
3173			    makeascii(1, cp, fp);
3174		} else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp))
3175			putc(*cp, fp);
3176		else
3177			makeascii(1, cp, fp);
3178		cp++;
3179	}
3180}
3181
3182
3183/*
3184 * Global data used by the cooked output routines
3185 */
3186int out_chars;		/* number of characters output */
3187int out_linecount;	/* number of characters output on this line */
3188
3189
3190/*
3191 * startoutput - get ready to do cooked output
3192 */
3193static void
3194startoutput(void)
3195{
3196	out_chars = 0;
3197	out_linecount = 0;
3198}
3199
3200
3201/*
3202 * output - output a variable=value combination
3203 */
3204static void
3205output(
3206	FILE *fp,
3207	const char *name,
3208	const char *value
3209	)
3210{
3211	int len;
3212
3213	/* strlen of "name=value" */
3214	len = size2int_sat(strlen(name) + 1 + strlen(value));
3215
3216	if (out_chars != 0) {
3217		out_chars += 2;
3218		if ((out_linecount + len + 2) > MAXOUTLINE) {
3219			fputs(",\n", fp);
3220			out_linecount = 0;
3221		} else {
3222			fputs(", ", fp);
3223			out_linecount += 2;
3224		}
3225	}
3226
3227	fputs(name, fp);
3228	putc('=', fp);
3229	fputs(value, fp);
3230	out_chars += len;
3231	out_linecount += len;
3232}
3233
3234
3235/*
3236 * endoutput - terminate a block of cooked output
3237 */
3238static void
3239endoutput(
3240	FILE *fp
3241	)
3242{
3243	if (out_chars != 0)
3244		putc('\n', fp);
3245}
3246
3247
3248/*
3249 * outputarr - output an array of values
3250 */
3251static void
3252outputarr(
3253	FILE *fp,
3254	char *name,
3255	int narr,
3256	l_fp *lfp
3257	)
3258{
3259	char *bp;
3260	char *cp;
3261	size_t i;
3262	size_t len;
3263	char buf[256];
3264
3265	bp = buf;
3266	/*
3267	 * Hack to align delay and offset values
3268	 */
3269	for (i = (int)strlen(name); i < 11; i++)
3270	    *bp++ = ' ';
3271
3272	for (i = narr; i > 0; i--) {
3273		if (i != narr)
3274		    *bp++ = ' ';
3275		cp = lfptoms(lfp, 2);
3276		len = strlen(cp);
3277		if (len > 7) {
3278			cp[7] = '\0';
3279			len = 7;
3280		}
3281		while (len < 7) {
3282			*bp++ = ' ';
3283			len++;
3284		}
3285		while (*cp != '\0')
3286		    *bp++ = *cp++;
3287		lfp++;
3288	}
3289	*bp = '\0';
3290	output(fp, name, buf);
3291}
3292
3293static char *
3294tstflags(
3295	u_long val
3296	)
3297{
3298	register char *cp, *s;
3299	size_t cb;
3300	register int i;
3301	register const char *sep;
3302
3303	sep = "";
3304	s = cp = circ_buf[nextcb];
3305	if (++nextcb >= NUMCB)
3306		nextcb = 0;
3307	cb = sizeof(circ_buf[0]);
3308
3309	snprintf(cp, cb, "%02lx", val);
3310	cp += strlen(cp);
3311	cb -= strlen(cp);
3312	if (!val) {
3313		strlcat(cp, " ok", cb);
3314		cp += strlen(cp);
3315		cb -= strlen(cp);
3316	} else {
3317		if (cb) {
3318			*cp++ = ' ';
3319			cb--;
3320		}
3321		for (i = 0; i < (int)COUNTOF(tstflagnames); i++) {
3322			if (val & 0x1) {
3323				snprintf(cp, cb, "%s%s", sep,
3324					 tstflagnames[i]);
3325				sep = ", ";
3326				cp += strlen(cp);
3327				cb -= strlen(cp);
3328			}
3329			val >>= 1;
3330		}
3331	}
3332	if (cb)
3333		*cp = '\0';
3334
3335	return s;
3336}
3337
3338/*
3339 * cookedprint - output variables in cooked mode
3340 */
3341static void
3342cookedprint(
3343	int datatype,
3344	size_t length,
3345	const char *data,
3346	int status,
3347	int quiet,
3348	FILE *fp
3349	)
3350{
3351	char *name;
3352	char *value;
3353	char output_raw;
3354	int fmt;
3355	l_fp lfp;
3356	sockaddr_u hval;
3357	u_long uval;
3358	int narr;
3359	size_t len;
3360	l_fp lfparr[8];
3361	char b[12];
3362	char bn[2 * MAXVARLEN];
3363	char bv[2 * MAXVALLEN];
3364
3365	UNUSED_ARG(datatype);
3366
3367	if (!quiet)
3368		fprintf(fp, "status=%04x %s,\n", status,
3369			statustoa(datatype, status));
3370
3371	startoutput();
3372	while (nextvar(&length, &data, &name, &value)) {
3373		fmt = varfmt(name);
3374		output_raw = 0;
3375		switch (fmt) {
3376
3377		case PADDING:
3378			output_raw = '*';
3379			break;
3380
3381		case TS:
3382			if (!decodets(value, &lfp))
3383				output_raw = '?';
3384			else
3385				output(fp, name, prettydate(&lfp));
3386			break;
3387
3388		case HA:	/* fallthru */
3389		case NA:
3390			if (!decodenetnum(value, &hval)) {
3391				output_raw = '?';
3392			} else if (fmt == HA){
3393				output(fp, name, nntohost(&hval));
3394			} else {
3395				output(fp, name, stoa(&hval));
3396			}
3397			break;
3398
3399		case RF:
3400			if (decodenetnum(value, &hval)) {
3401				if (ISREFCLOCKADR(&hval))
3402					output(fp, name,
3403					       refnumtoa(&hval));
3404				else
3405					output(fp, name, stoa(&hval));
3406			} else if (strlen(value) <= 4) {
3407				output(fp, name, value);
3408			} else {
3409				output_raw = '?';
3410			}
3411			break;
3412
3413		case LP:
3414			if (!decodeuint(value, &uval) || uval > 3) {
3415				output_raw = '?';
3416			} else {
3417				b[0] = (0x2 & uval)
3418					   ? '1'
3419					   : '0';
3420				b[1] = (0x1 & uval)
3421					   ? '1'
3422					   : '0';
3423				b[2] = '\0';
3424				output(fp, name, b);
3425			}
3426			break;
3427
3428		case OC:
3429			if (!decodeuint(value, &uval)) {
3430				output_raw = '?';
3431			} else {
3432				snprintf(b, sizeof(b), "%03lo", uval);
3433				output(fp, name, b);
3434			}
3435			break;
3436
3437		case AR:
3438			if (!decodearr(value, &narr, lfparr))
3439				output_raw = '?';
3440			else
3441				outputarr(fp, name, narr, lfparr);
3442			break;
3443
3444		case FX:
3445			if (!decodeuint(value, &uval))
3446				output_raw = '?';
3447			else
3448				output(fp, name, tstflags(uval));
3449			break;
3450
3451		default:
3452			fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
3453				name, value, fmt);
3454			output_raw = '?';
3455			break;
3456		}
3457
3458		if (output_raw != 0) {
3459			/* TALOS-CAN-0063: avoid buffer overrun */
3460			atoascii(name, MAXVARLEN, bn, sizeof(bn));
3461			if (output_raw != '*') {
3462				atoascii(value, MAXVALLEN,
3463					 bv, sizeof(bv) - 1);
3464				len = strlen(bv);
3465				bv[len] = output_raw;
3466				bv[len+1] = '\0';
3467			} else {
3468				atoascii(value, MAXVALLEN,
3469					 bv, sizeof(bv));
3470			}
3471			output(fp, bn, bv);
3472		}
3473	}
3474	endoutput(fp);
3475}
3476
3477
3478/*
3479 * sortassoc - sort associations in the cache into ascending order
3480 */
3481void
3482sortassoc(void)
3483{
3484	if (numassoc > 1)
3485		qsort(assoc_cache, (size_t)numassoc,
3486		      sizeof(assoc_cache[0]), &assoccmp);
3487}
3488
3489
3490/*
3491 * assoccmp - compare two associations
3492 */
3493static int
3494assoccmp(
3495	const void *t1,
3496	const void *t2
3497	)
3498{
3499	const struct association *ass1 = t1;
3500	const struct association *ass2 = t2;
3501
3502	if (ass1->assid < ass2->assid)
3503		return -1;
3504	if (ass1->assid > ass2->assid)
3505		return 1;
3506	return 0;
3507}
3508
3509
3510/*
3511 * grow_assoc_cache() - enlarge dynamic assoc_cache array
3512 *
3513 * The strategy is to add an assumed 4k page size at a time, leaving
3514 * room for malloc() bookkeeping overhead equivalent to 4 pointers.
3515 */
3516void
3517grow_assoc_cache(void)
3518{
3519	static size_t	prior_sz;
3520	size_t		new_sz;
3521
3522	new_sz = prior_sz + 4 * 1024;
3523	if (0 == prior_sz) {
3524		new_sz -= 4 * sizeof(void *);
3525	}
3526	assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
3527	prior_sz = new_sz;
3528	assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0]));
3529}
3530
3531
3532/*
3533 * ntpq_custom_opt_handler - autoopts handler for -c and -p
3534 *
3535 * By default, autoopts loses the relative order of -c and -p options
3536 * on the command line.  This routine replaces the default handler for
3537 * those routines and builds a list of commands to execute preserving
3538 * the order.
3539 */
3540void
3541ntpq_custom_opt_handler(
3542	tOptions *pOptions,
3543	tOptDesc *pOptDesc
3544	)
3545{
3546	switch (pOptDesc->optValue) {
3547
3548	default:
3549		fprintf(stderr,
3550			"ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3551			pOptDesc->optValue, pOptDesc->optValue);
3552		exit(1);
3553
3554	case 'c':
3555		ADDCMD(pOptDesc->pzLastArg);
3556		break;
3557
3558	case 'p':
3559		ADDCMD("peers");
3560		break;
3561	}
3562}
3563/*
3564 * Obtain list of digest names
3565 */
3566
3567#ifdef OPENSSL
3568# ifdef HAVE_EVP_MD_DO_ALL_SORTED
3569struct hstate {
3570   char *list;
3571   const char **seen;
3572   int idx;
3573};
3574#define K_PER_LINE 8
3575#define K_NL_PFX_STR "\n    "
3576#define K_DELIM_STR ", "
3577static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg )
3578{
3579    size_t len, n;
3580    const char *name, *cp, **seen;
3581    struct hstate *hstate = arg;
3582    EVP_MD_CTX ctx;
3583    u_int digest_len;
3584    u_char digest[EVP_MAX_MD_SIZE];
3585
3586    if (!m)
3587        return; /* Ignore aliases */
3588
3589    name = EVP_MD_name(m);
3590
3591    /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
3592
3593    for( cp = name; *cp; cp++ ) {
3594	if( islower(*cp) )
3595	    return;
3596    }
3597    len = (cp - name) + 1;
3598
3599    /* There are duplicates.  Discard if name has been seen. */
3600
3601    for (seen = hstate->seen; *seen; seen++)
3602        if (!strcmp(*seen, name))
3603	    return;
3604    n = (seen - hstate->seen) + 2;
3605    hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
3606    hstate->seen[n-2] = name;
3607    hstate->seen[n-1] = NULL;
3608
3609    /* Discard MACs that NTP won't accept.
3610     * Keep this consistent with keytype_from_text() in ssl_init.c.
3611     */
3612
3613    EVP_DigestInit(&ctx, EVP_get_digestbyname(name));
3614    EVP_DigestFinal(&ctx, digest, &digest_len);
3615    if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t)))
3616        return;
3617
3618    if (hstate->list != NULL)
3619	len += strlen(hstate->list);
3620    len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR);
3621
3622    if (hstate->list == NULL) {
3623	hstate->list = (char *)emalloc(len);
3624	hstate->list[0] = '\0';
3625    } else
3626	hstate->list = (char *)erealloc(hstate->list, len);
3627
3628    sprintf(hstate->list + strlen(hstate->list), "%s%s",
3629	    ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR),
3630	    name);
3631    if (hstate->idx >= K_PER_LINE)
3632	hstate->idx = 1;
3633    else
3634	hstate->idx++;
3635}
3636# endif
3637#endif
3638
3639static char *list_digest_names(void)
3640{
3641    char *list = NULL;
3642
3643#ifdef OPENSSL
3644# ifdef HAVE_EVP_MD_DO_ALL_SORTED
3645    struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
3646
3647    hstate.seen = (const char **) emalloc_zero(1*sizeof( const char * )); // replaces -> calloc(1, sizeof( const char * ));
3648
3649    INIT_SSL();
3650    EVP_MD_do_all_sorted(list_md_fn, &hstate);
3651    list = hstate.list;
3652    free(hstate.seen);
3653# else
3654    list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
3655    strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
3656# endif
3657#else
3658    list = (char *)emalloc(sizeof("md5"));
3659    strcpy(list, "md5");
3660#endif
3661
3662    return list;
3663}
3664
3665#define CTRLC_STACK_MAX 4
3666static volatile size_t		ctrlc_stack_len = 0;
3667static volatile Ctrl_C_Handler	ctrlc_stack[CTRLC_STACK_MAX];
3668
3669
3670
3671int/*BOOL*/
3672push_ctrl_c_handler(
3673	Ctrl_C_Handler func
3674	)
3675{
3676	size_t size = ctrlc_stack_len;
3677	if (func && (size < CTRLC_STACK_MAX)) {
3678		ctrlc_stack[size] = func;
3679		ctrlc_stack_len = size + 1;
3680		return TRUE;
3681	}
3682	return FALSE;
3683}
3684
3685int/*BOOL*/
3686pop_ctrl_c_handler(
3687	Ctrl_C_Handler func
3688	)
3689{
3690	size_t size = ctrlc_stack_len;
3691	if (size) {
3692		--size;
3693		if (func == NULL || func == ctrlc_stack[size]) {
3694			ctrlc_stack_len = size;
3695			return TRUE;
3696		}
3697	}
3698	return FALSE;
3699}
3700
3701static void
3702on_ctrlc(void)
3703{
3704	size_t size = ctrlc_stack_len;
3705	while (size)
3706		if ((*ctrlc_stack[--size])())
3707			break;
3708}
3709
3710static int
3711my_easprintf(
3712	char ** 	ppinto,
3713	const char *	fmt   ,
3714	...
3715	)
3716{
3717	va_list	va;
3718	int	prc;
3719	size_t	len = 128;
3720	char *	buf = emalloc(len);
3721
3722  again:
3723	/* Note: we expect the memory allocation to fail long before the
3724	 * increment in buffer size actually overflows.
3725	 */
3726	buf = (buf) ? erealloc(buf, len) : emalloc(len);
3727
3728	va_start(va, fmt);
3729	prc = vsnprintf(buf, len, fmt, va);
3730	va_end(va);
3731
3732	if (prc < 0) {
3733		/* might be very old vsnprintf. Or actually MSVC... */
3734		len += len >> 1;
3735		goto again;
3736	}
3737	if ((size_t)prc >= len) {
3738		/* at least we have the proper size now... */
3739		len = (size_t)prc + 1;
3740		goto again;
3741	}
3742	if ((size_t)prc < (len - 32))
3743		buf = erealloc(buf, (size_t)prc + 1);
3744	*ppinto = buf;
3745	return prc;
3746}
3747