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