xref: /netbsd/external/bsd/ntp/dist/ntpq/ntpq.c (revision f7d97a96)
1*f7d97a96Schristos /*	$NetBSD: ntpq.c,v 1.22 2020/05/27 23:52:19 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ntpq - query an NTP server using mode 6 commands
5abb0f93cSkardel  */
6b3d6264cSchristos #include <config.h>
7abb0f93cSkardel #include <ctype.h>
8abb0f93cSkardel #include <signal.h>
9abb0f93cSkardel #include <setjmp.h>
10169394abSchristos #include <stddef.h>
11169394abSchristos #include <stdio.h>
12abb0f93cSkardel #include <sys/types.h>
13abb0f93cSkardel #include <sys/time.h>
14b3d6264cSchristos #ifdef HAVE_UNISTD_H
15b3d6264cSchristos # include <unistd.h>
16b3d6264cSchristos #endif
17b3d6264cSchristos #ifdef HAVE_FCNTL_H
18b3d6264cSchristos # include <fcntl.h>
19b3d6264cSchristos #endif
20b3d6264cSchristos #ifdef SYS_WINNT
21b3d6264cSchristos # include <mswsock.h>
22b3d6264cSchristos #endif
23b3d6264cSchristos #include <isc/net.h>
24b3d6264cSchristos #include <isc/result.h>
25abb0f93cSkardel 
26abb0f93cSkardel #include "ntpq.h"
274e3b3909Schristos #include "ntp_assert.h"
28b3d6264cSchristos #include "ntp_stdlib.h"
29abb0f93cSkardel #include "ntp_unixtime.h"
30abb0f93cSkardel #include "ntp_calendar.h"
31abb0f93cSkardel #include "ntp_select.h"
32abb0f93cSkardel #include "ntp_assert.h"
33b3d6264cSchristos #include "lib_strbuf.h"
34abb0f93cSkardel #include "ntp_lineedit.h"
35abb0f93cSkardel #include "ntp_debug.h"
36b3d6264cSchristos #ifdef OPENSSL
37b3d6264cSchristos # include "openssl/evp.h"
38b3d6264cSchristos # include "openssl/objects.h"
394e3b3909Schristos # include "openssl/err.h"
40169394abSchristos # ifdef SYS_WINNT
41169394abSchristos #  include "openssl/opensslv.h"
42169394abSchristos #  if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L
43169394abSchristos #     define HAVE_EVP_MD_DO_ALL_SORTED	1
44169394abSchristos #  endif
45169394abSchristos # endif
46f6706026Schristos # include "libssl_compat.h"
479e1d19ccSchristos # ifdef HAVE_OPENSSL_CMAC_H
489e1d19ccSchristos #  include <openssl/cmac.h>
49169394abSchristos #  define CMAC "AES128CMAC"
50b3d6264cSchristos # endif
519e1d19ccSchristos #endif
52abb0f93cSkardel #include <ssl_applink.c>
53abb0f93cSkardel 
5445530cf1Skardel #include "ntp_libopts.h"
55bd25f4c4Schristos #include "safecast.h"
56abb0f93cSkardel 
57b3d6264cSchristos #ifdef SYS_VXWORKS		/* vxWorks needs mode flag -casey*/
58abb0f93cSkardel # define open(name, flags)   open(name, flags, 0777)
59abb0f93cSkardel # define SERVER_PORT_NUM     123
60abb0f93cSkardel #endif
61abb0f93cSkardel 
62abb0f93cSkardel /* we use COMMAND as an autogen keyword */
63abb0f93cSkardel #ifdef COMMAND
64abb0f93cSkardel # undef COMMAND
65abb0f93cSkardel #endif
66abb0f93cSkardel 
67abb0f93cSkardel /*
68abb0f93cSkardel  * Because we potentially understand a lot of commands we will run
69abb0f93cSkardel  * interactive if connected to a terminal.
70abb0f93cSkardel  */
71abb0f93cSkardel int interactive = 0;		/* set to 1 when we should prompt */
72abb0f93cSkardel const char *prompt = "ntpq> ";	/* prompt to ask him about */
73abb0f93cSkardel 
74abb0f93cSkardel /*
75abb0f93cSkardel  * use old readvars behavior?  --old-rv processing in ntpq resets
76abb0f93cSkardel  * this value based on the presence or absence of --old-rv.  It is
77abb0f93cSkardel  * initialized to 1 here to maintain backward compatibility with
78abb0f93cSkardel  * libntpq clients such as ntpsnmpd, which are free to reset it as
79abb0f93cSkardel  * desired.
80abb0f93cSkardel  */
81abb0f93cSkardel int	old_rv = 1;
82abb0f93cSkardel 
83335f7552Schristos /*
84335f7552Schristos  * How should we display the refid?
85335f7552Schristos  * REFID_HASH, REFID_IPV4
86335f7552Schristos  */
87335f7552Schristos te_Refid drefid = -1;
88abb0f93cSkardel 
89abb0f93cSkardel /*
90abb0f93cSkardel  * for get_systime()
91abb0f93cSkardel  */
92abb0f93cSkardel s_char	sys_precision;		/* local clock precision (log2 s) */
93abb0f93cSkardel 
94abb0f93cSkardel /*
95abb0f93cSkardel  * Keyid used for authenticated requests.  Obtained on the fly.
96abb0f93cSkardel  */
97abb0f93cSkardel u_long info_auth_keyid = 0;
98abb0f93cSkardel 
99abb0f93cSkardel static	int	info_auth_keytype = NID_md5;	/* MD5 */
100abb0f93cSkardel static	size_t	info_auth_hashlen = 16;		/* MD5 */
101abb0f93cSkardel u_long	current_time;		/* needed by authkeys; not used */
102abb0f93cSkardel 
103abb0f93cSkardel /*
104abb0f93cSkardel  * Flag which indicates we should always send authenticated requests
105abb0f93cSkardel  */
106abb0f93cSkardel int always_auth = 0;
107abb0f93cSkardel 
108abb0f93cSkardel /*
109abb0f93cSkardel  * Flag which indicates raw mode output.
110abb0f93cSkardel  */
111abb0f93cSkardel int rawmode = 0;
112abb0f93cSkardel 
113abb0f93cSkardel /*
114abb0f93cSkardel  * Packet version number we use
115abb0f93cSkardel  */
116abb0f93cSkardel u_char pktversion = NTP_OLDVERSION + 1;
117abb0f93cSkardel 
118abb0f93cSkardel 
119abb0f93cSkardel /*
120abb0f93cSkardel  * Format values
121abb0f93cSkardel  */
122abb0f93cSkardel #define	PADDING	0
123b3d6264cSchristos #define	HA	1	/* host address */
124b3d6264cSchristos #define	NA	2	/* network address */
125b3d6264cSchristos #define	LP	3	/* leap (print in binary) */
126b3d6264cSchristos #define	RF	4	/* refid (sometimes string, sometimes not) */
1279034ec65Schristos #define	AU	5	/* array of unsigned times */
128b3d6264cSchristos #define FX	6	/* test flags */
129b3d6264cSchristos #define TS	7	/* l_fp timestamp in hex */
130b3d6264cSchristos #define	OC	8	/* integer, print in octal */
1319034ec65Schristos #define	AS	9	/* array of signed times */
1329034ec65Schristos #define	SN	10	/* signed number: must display +/- sign */
133abb0f93cSkardel #define	EOV	255	/* end of table */
134abb0f93cSkardel 
135abb0f93cSkardel /*
136b3d6264cSchristos  * For the most part ntpq simply displays what ntpd provides in the
137b3d6264cSchristos  * mostly plain-text mode 6 responses.  A few variable names are by
138b3d6264cSchristos  * default "cooked" to provide more human-friendly output.
139abb0f93cSkardel  */
140b3d6264cSchristos const var_format cookedvars[] = {
141b3d6264cSchristos 	{ "leap",		LP },
142b3d6264cSchristos 	{ "reach",		OC },
143b3d6264cSchristos 	{ "refid",		RF },
144b3d6264cSchristos 	{ "reftime",		TS },
145b3d6264cSchristos 	{ "clock",		TS },
146b3d6264cSchristos 	{ "org",		TS },
147b3d6264cSchristos 	{ "rec",		TS },
148b3d6264cSchristos 	{ "xmt",		TS },
149b3d6264cSchristos 	{ "flash",		FX },
150b3d6264cSchristos 	{ "srcadr",		HA },
151b3d6264cSchristos 	{ "peeradr",		HA },	/* compat with others */
152b3d6264cSchristos 	{ "dstadr",		NA },
1539034ec65Schristos 	{ "filtdelay",		AU },
1549034ec65Schristos 	{ "filtoffset",		AS },
1559034ec65Schristos 	{ "filtdisp",		AU },
1569034ec65Schristos 	{ "filterror",		AU },	/* compat with others */
1579034ec65Schristos 	{ "offset",		SN },
1589034ec65Schristos 	{ "frequency",		SN }
159abb0f93cSkardel };
160abb0f93cSkardel 
161abb0f93cSkardel 
162abb0f93cSkardel 
163abb0f93cSkardel /*
164abb0f93cSkardel  * flasher bits
165abb0f93cSkardel  */
166abb0f93cSkardel static const char *tstflagnames[] = {
167abb0f93cSkardel 	"pkt_dup",		/* TEST1 */
168abb0f93cSkardel 	"pkt_bogus",		/* TEST2 */
169abb0f93cSkardel 	"pkt_unsync",		/* TEST3 */
170abb0f93cSkardel 	"pkt_denied",		/* TEST4 */
171abb0f93cSkardel 	"pkt_auth",		/* TEST5 */
172abb0f93cSkardel 	"pkt_stratum",		/* TEST6 */
173abb0f93cSkardel 	"pkt_header",		/* TEST7 */
174abb0f93cSkardel 	"pkt_autokey",		/* TEST8 */
175abb0f93cSkardel 	"pkt_crypto",		/* TEST9 */
176abb0f93cSkardel 	"peer_stratum",		/* TEST10 */
177abb0f93cSkardel 	"peer_dist",		/* TEST11 */
178abb0f93cSkardel 	"peer_loop",		/* TEST12 */
179abb0f93cSkardel 	"peer_unreach"		/* TEST13 */
180abb0f93cSkardel };
181abb0f93cSkardel 
182abb0f93cSkardel 
183abb0f93cSkardel int		ntpqmain	(int,	char **);
184abb0f93cSkardel /*
185abb0f93cSkardel  * Built in command handler declarations
186abb0f93cSkardel  */
187b3d6264cSchristos static	int	openhost	(const char *, int);
188b3d6264cSchristos static	void	dump_hex_printable(const void *, size_t);
189abb0f93cSkardel static	int	sendpkt		(void *, size_t);
190bd25f4c4Schristos static	int	getresponse	(int, int, u_short *, size_t *, const char **, int);
191bd25f4c4Schristos static	int	sendrequest	(int, associd_t, int, size_t, const char *);
192abb0f93cSkardel static	char *	tstflags	(u_long);
193abb0f93cSkardel #ifndef BUILD_AS_LIB
194abb0f93cSkardel static	void	getcmds		(void);
195abb0f93cSkardel #ifndef SYS_WINNT
196bd25f4c4Schristos static	int	abortcmd	(void);
197abb0f93cSkardel #endif	/* SYS_WINNT */
198abb0f93cSkardel static	void	docmd		(const char *);
199abb0f93cSkardel static	void	tokenize	(const char *, char **, int *);
200b3d6264cSchristos static	int	getarg		(const char *, int, arg_v *);
201abb0f93cSkardel #endif	/* BUILD_AS_LIB */
202b3d6264cSchristos static	int	findcmd		(const char *, struct xcmd *,
203b3d6264cSchristos 				 struct xcmd *, struct xcmd **);
204abb0f93cSkardel static	int	rtdatetolfp	(char *, l_fp *);
205169394abSchristos static	int	decodearr	(char *, int *, l_fp *, int);
206abb0f93cSkardel static	void	help		(struct parse *, FILE *);
207abb0f93cSkardel static	int	helpsort	(const void *, const void *);
208abb0f93cSkardel static	void	printusage	(struct xcmd *, FILE *);
209abb0f93cSkardel static	void	timeout		(struct parse *, FILE *);
210abb0f93cSkardel static	void	auth_delay	(struct parse *, FILE *);
211abb0f93cSkardel static	void	host		(struct parse *, FILE *);
212abb0f93cSkardel static	void	ntp_poll	(struct parse *, FILE *);
213abb0f93cSkardel static	void	keyid		(struct parse *, FILE *);
214abb0f93cSkardel static	void	keytype		(struct parse *, FILE *);
215abb0f93cSkardel static	void	passwd		(struct parse *, FILE *);
216abb0f93cSkardel static	void	hostnames	(struct parse *, FILE *);
217abb0f93cSkardel static	void	setdebug	(struct parse *, FILE *);
218abb0f93cSkardel static	void	quit		(struct parse *, FILE *);
219335f7552Schristos static	void	showdrefid	(struct parse *, FILE *);
220abb0f93cSkardel static	void	version		(struct parse *, FILE *);
221abb0f93cSkardel static	void	raw		(struct parse *, FILE *);
222abb0f93cSkardel static	void	cooked		(struct parse *, FILE *);
223abb0f93cSkardel static	void	authenticate	(struct parse *, FILE *);
224abb0f93cSkardel static	void	ntpversion	(struct parse *, FILE *);
2259e1d19ccSchristos static	void	warning		(const char *, ...) NTP_PRINTF(1, 2);
2269e1d19ccSchristos static	void	error		(const char *, ...) NTP_PRINTF(1, 2);
227abb0f93cSkardel static	u_long	getkeyid	(const char *);
228abb0f93cSkardel static	void	atoascii	(const char *, size_t, char *, size_t);
229bd25f4c4Schristos static	void	cookedprint	(int, size_t, const char *, int, int, FILE *);
230bd25f4c4Schristos static	void	rawprint	(int, size_t, const char *, int, int, FILE *);
231abb0f93cSkardel static	void	startoutput	(void);
232b3d6264cSchristos static	void	output		(FILE *, const char *, const char *);
233abb0f93cSkardel static	void	endoutput	(FILE *);
2349034ec65Schristos static	void	outputarr	(FILE *, char *, int, l_fp *, int);
235abb0f93cSkardel static	int	assoccmp	(const void *, const void *);
236b3d6264cSchristos 	u_short	varfmt		(const char *);
237abb0f93cSkardel 	void	ntpq_custom_opt_handler(tOptions *, tOptDesc *);
238abb0f93cSkardel 
2399e1d19ccSchristos #ifndef BUILD_AS_LIB
2409e1d19ccSchristos static	char   *list_digest_names(void);
2419e1d19ccSchristos static	char   *insert_cmac	(char *list);
2429e1d19ccSchristos static	void	on_ctrlc	(void);
2439e1d19ccSchristos static	int	my_easprintf	(char**, const char *, ...) NTP_PRINTF(2, 3);
2449e1d19ccSchristos # if defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED)
2459e1d19ccSchristos static	void	list_md_fn	(const EVP_MD *m, const char *from,
2469e1d19ccSchristos 				 const char *to, void *arg);
2479e1d19ccSchristos # endif /* defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED) */
2489e1d19ccSchristos #endif /* !defined(BUILD_AS_LIB) */
2499e1d19ccSchristos 
2509e1d19ccSchristos 
251169394abSchristos /* read a character from memory and expand to integer */
252169394abSchristos static inline int
pgetc(const char * cp)253169394abSchristos pgetc(
254169394abSchristos 	const char *cp
255169394abSchristos 	)
256169394abSchristos {
257169394abSchristos 	return (int)*(const unsigned char*)cp;
258169394abSchristos }
259169394abSchristos 
260169394abSchristos 
261abb0f93cSkardel 
262abb0f93cSkardel /*
263abb0f93cSkardel  * Built-in commands we understand
264abb0f93cSkardel  */
265abb0f93cSkardel struct xcmd builtins[] = {
266abb0f93cSkardel 	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
267abb0f93cSkardel 	  { "command", "", "", "" },
268abb0f93cSkardel 	  "tell the use and syntax of commands" },
269abb0f93cSkardel 	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
270abb0f93cSkardel 	  { "command", "", "", "" },
271abb0f93cSkardel 	  "tell the use and syntax of commands" },
272abb0f93cSkardel 	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
273abb0f93cSkardel 	  { "msec", "", "", "" },
274abb0f93cSkardel 	  "set the primary receive time out" },
275abb0f93cSkardel 	{ "delay",	auth_delay,	{ OPT|NTP_INT, NO, NO, NO },
276abb0f93cSkardel 	  { "msec", "", "", "" },
277abb0f93cSkardel 	  "set the delay added to encryption time stamps" },
278abb0f93cSkardel 	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
279abb0f93cSkardel 	  { "-4|-6", "hostname", "", "" },
280abb0f93cSkardel 	  "specify the host whose NTP server we talk to" },
281abb0f93cSkardel 	{ "poll",	ntp_poll,	{ OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
282abb0f93cSkardel 	  { "n", "verbose", "", "" },
283abb0f93cSkardel 	  "poll an NTP server in client mode `n' times" },
284b3d6264cSchristos 	{ "passwd",	passwd,		{ OPT|NTP_STR, NO, NO, NO },
285abb0f93cSkardel 	  { "", "", "", "" },
286abb0f93cSkardel 	  "specify a password to use for authenticated requests"},
287abb0f93cSkardel 	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
288abb0f93cSkardel 	  { "yes|no", "", "", "" },
289abb0f93cSkardel 	  "specify whether hostnames or net numbers are printed"},
290abb0f93cSkardel 	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
291abb0f93cSkardel 	  { "no|more|less", "", "", "" },
292abb0f93cSkardel 	  "set/change debugging level" },
293abb0f93cSkardel 	{ "quit",	quit,		{ NO, NO, NO, NO },
294abb0f93cSkardel 	  { "", "", "", "" },
295abb0f93cSkardel 	  "exit ntpq" },
296abb0f93cSkardel 	{ "exit",	quit,		{ NO, NO, NO, NO },
297abb0f93cSkardel 	  { "", "", "", "" },
298abb0f93cSkardel 	  "exit ntpq" },
299abb0f93cSkardel 	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
300abb0f93cSkardel 	  { "key#", "", "", "" },
301abb0f93cSkardel 	  "set keyid to use for authenticated requests" },
302335f7552Schristos 	{ "drefid",	showdrefid,	{ OPT|NTP_STR, NO, NO, NO },
303335f7552Schristos 	  { "hash|ipv4", "", "", "" },
304335f7552Schristos 	  "display refid's as IPv4 or hash" },
305abb0f93cSkardel 	{ "version",	version,	{ NO, NO, NO, NO },
306abb0f93cSkardel 	  { "", "", "", "" },
307abb0f93cSkardel 	  "print version number" },
308abb0f93cSkardel 	{ "raw",	raw,		{ NO, NO, NO, NO },
309abb0f93cSkardel 	  { "", "", "", "" },
310abb0f93cSkardel 	  "do raw mode variable output" },
311abb0f93cSkardel 	{ "cooked",	cooked,		{ NO, NO, NO, NO },
312abb0f93cSkardel 	  { "", "", "", "" },
313abb0f93cSkardel 	  "do cooked mode variable output" },
314abb0f93cSkardel 	{ "authenticate", authenticate,	{ OPT|NTP_STR, NO, NO, NO },
315abb0f93cSkardel 	  { "yes|no", "", "", "" },
316abb0f93cSkardel 	  "always authenticate requests to this server" },
317abb0f93cSkardel 	{ "ntpversion",	ntpversion,	{ OPT|NTP_UINT, NO, NO, NO },
318abb0f93cSkardel 	  { "version number", "", "", "" },
319abb0f93cSkardel 	  "set the NTP version number to use for requests" },
320abb0f93cSkardel 	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
3214e3b3909Schristos 	  { "key type %s", "", "", "" },
3224e3b3909Schristos 	  NULL },
323abb0f93cSkardel 	{ 0,		0,		{ NO, NO, NO, NO },
324abb0f93cSkardel 	  { "", "", "", "" }, "" }
325abb0f93cSkardel };
326abb0f93cSkardel 
327abb0f93cSkardel 
328abb0f93cSkardel /*
329abb0f93cSkardel  * Default values we use.
330abb0f93cSkardel  */
331abb0f93cSkardel #define	DEFHOST		"localhost"	/* default host name */
332b3d6264cSchristos #define	DEFTIMEOUT	5		/* wait 5 seconds for 1st pkt */
333b3d6264cSchristos #define	DEFSTIMEOUT	3		/* and 3 more for each additional */
334b3d6264cSchristos /*
335b3d6264cSchristos  * Requests are automatically retried once, so total timeout with no
336b3d6264cSchristos  * response is a bit over 2 * DEFTIMEOUT, or 10 seconds.  At the other
337b3d6264cSchristos  * extreme, a request eliciting 32 packets of responses each for some
338b3d6264cSchristos  * reason nearly DEFSTIMEOUT seconds after the prior in that series,
339b3d6264cSchristos  * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
340b3d6264cSchristos  * 93 seconds to fail each of two times, or 186 seconds.
341b3d6264cSchristos  * Some commands involve a series of requests, such as "peers" and
342b3d6264cSchristos  * "mrulist", so the cumulative timeouts are even longer for those.
343b3d6264cSchristos  */
344abb0f93cSkardel #define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
345abb0f93cSkardel #define	LENHOSTNAME	256		/* host name is 256 characters long */
346abb0f93cSkardel #define	MAXCMDS		100		/* maximum commands on cmd line */
347abb0f93cSkardel #define	MAXHOSTS	200		/* maximum hosts on cmd line */
348abb0f93cSkardel #define	MAXLINE		512		/* maximum line length */
349abb0f93cSkardel #define	MAXTOKENS	(1+MAXARGS+2)	/* maximum number of usable tokens */
350abb0f93cSkardel #define	MAXVARLEN	256		/* maximum length of a variable name */
351b3d6264cSchristos #define	MAXVALLEN	2048		/* maximum length of a variable value */
352abb0f93cSkardel #define	MAXOUTLINE	72		/* maximum length of an output line */
353abb0f93cSkardel #define SCREENWIDTH	76		/* nominal screen width in columns */
354abb0f93cSkardel 
355abb0f93cSkardel /*
356abb0f93cSkardel  * Some variables used and manipulated locally
357abb0f93cSkardel  */
358abb0f93cSkardel struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
359abb0f93cSkardel struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
360abb0f93cSkardel l_fp delay_time;				/* delay time */
361abb0f93cSkardel char currenthost[LENHOSTNAME];			/* current host name */
36245530cf1Skardel int currenthostisnum;				/* is prior text from IP? */
363f40817b7Skardel struct sockaddr_in hostaddr;			/* host address */
364abb0f93cSkardel int showhostnames = 1;				/* show host names by default */
365ad131110Schristos int wideremote = 0;				/* show wide remote names? */
366abb0f93cSkardel 
367abb0f93cSkardel int ai_fam_templ;				/* address family */
368abb0f93cSkardel int ai_fam_default;				/* default address family */
369abb0f93cSkardel SOCKET sockfd;					/* fd socket is opened on */
370abb0f93cSkardel int havehost = 0;				/* set to 1 when host open */
371abb0f93cSkardel int s_port = 0;
372abb0f93cSkardel struct servent *server_entry = NULL;		/* server entry for ntp */
373abb0f93cSkardel 
374abb0f93cSkardel 
375abb0f93cSkardel /*
376abb0f93cSkardel  * Sequence number used for requests.  It is incremented before
377abb0f93cSkardel  * it is used.
378abb0f93cSkardel  */
379abb0f93cSkardel u_short sequence;
380abb0f93cSkardel 
381abb0f93cSkardel /*
382abb0f93cSkardel  * Holds data returned from queries.  Declare buffer long to be sure of
383abb0f93cSkardel  * alignment.
384abb0f93cSkardel  */
385abb0f93cSkardel #define	DATASIZE	(MAXFRAGS*480)	/* maximum amount of data */
386abb0f93cSkardel long pktdata[DATASIZE/sizeof(long)];
387abb0f93cSkardel 
388abb0f93cSkardel /*
389b3d6264cSchristos  * assoc_cache[] is a dynamic array which allows references to
390b3d6264cSchristos  * associations using &1 ... &N for n associations, avoiding manual
391b3d6264cSchristos  * lookup of the current association IDs for a given ntpd.  It also
392b3d6264cSchristos  * caches the status word for each association, retrieved incidentally.
393abb0f93cSkardel  */
394b3d6264cSchristos struct association *	assoc_cache;
395b3d6264cSchristos u_int assoc_cache_slots;/* count of allocated array entries */
396b3d6264cSchristos u_int numassoc;		/* number of cached associations */
397abb0f93cSkardel 
398abb0f93cSkardel /*
399abb0f93cSkardel  * For commands typed on the command line (with the -c option)
400abb0f93cSkardel  */
4014e3b3909Schristos size_t numcmds = 0;
402abb0f93cSkardel const char *ccmds[MAXCMDS];
403abb0f93cSkardel #define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
404abb0f93cSkardel 
405abb0f93cSkardel /*
406abb0f93cSkardel  * When multiple hosts are specified.
407abb0f93cSkardel  */
408abb0f93cSkardel 
409b3d6264cSchristos u_int numhosts;
410b3d6264cSchristos 
411b3d6264cSchristos chost chosts[MAXHOSTS];
412b3d6264cSchristos #define	ADDHOST(cp)						\
413b3d6264cSchristos 	do {							\
414b3d6264cSchristos 		if (numhosts < MAXHOSTS) {			\
415b3d6264cSchristos 			chosts[numhosts].name = (cp);		\
416b3d6264cSchristos 			chosts[numhosts].fam = ai_fam_templ;	\
417b3d6264cSchristos 			numhosts++;				\
418b3d6264cSchristos 		}						\
419b3d6264cSchristos 	} while (0)
420abb0f93cSkardel 
421abb0f93cSkardel /*
422abb0f93cSkardel  * Macro definitions we use
423abb0f93cSkardel  */
424abb0f93cSkardel #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
425abb0f93cSkardel #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
426abb0f93cSkardel #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
427abb0f93cSkardel 
428abb0f93cSkardel /*
4299e1d19ccSchristos  * Jump buffer for longjumping back to the command level.
4309e1d19ccSchristos  *
4319e1d19ccSchristos  * Since we do this from a signal handler, we use 'sig{set,long}jmp()'
4329e1d19ccSchristos  * if available. The signal is blocked by default during the excution of
4339e1d19ccSchristos  * a signal handler, and it is unspecified if '{set,long}jmp()' save and
4349e1d19ccSchristos  * restore the signal mask. They do on BSD, it depends on the GLIBC
4359e1d19ccSchristos  * version on Linux, and the gods know what happens on other OSes...
4369e1d19ccSchristos  *
4379e1d19ccSchristos  * So we use the 'sig{set,long}jmp()' functions where available, because
4389e1d19ccSchristos  * for them the semantics are well-defined. If we have to fall back to
4399e1d19ccSchristos  * '{set,long}jmp()', the CTRL-C handling might be a bit erratic.
440abb0f93cSkardel  */
4419e1d19ccSchristos #if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP
4429e1d19ccSchristos # define JMP_BUF	sigjmp_buf
4439e1d19ccSchristos # define SETJMP(x)	sigsetjmp((x), 1)
4449e1d19ccSchristos # define LONGJMP(x, v)	siglongjmp((x),(v))
4459e1d19ccSchristos #else
4469e1d19ccSchristos # define JMP_BUF	jmp_buf
4479e1d19ccSchristos # define SETJMP(x)	setjmp((x))
4489e1d19ccSchristos # define LONGJMP(x, v)	longjmp((x),(v))
4499e1d19ccSchristos #endif
4509e1d19ccSchristos static	JMP_BUF		interrupt_buf;
4519e1d19ccSchristos static	volatile int	jump = 0;
452abb0f93cSkardel 
453abb0f93cSkardel /*
454abb0f93cSkardel  * Points at file being currently printed into
455abb0f93cSkardel  */
4569e1d19ccSchristos FILE *current_output = NULL;
457abb0f93cSkardel 
458abb0f93cSkardel /*
459abb0f93cSkardel  * Command table imported from ntpdc_ops.c
460abb0f93cSkardel  */
461abb0f93cSkardel extern struct xcmd opcmds[];
462abb0f93cSkardel 
46309f14f80Schristos char const *progname;
464abb0f93cSkardel 
465abb0f93cSkardel #ifdef NO_MAIN_ALLOWED
466abb0f93cSkardel #ifndef BUILD_AS_LIB
467abb0f93cSkardel CALL(ntpq,"ntpq",ntpqmain);
468abb0f93cSkardel 
clear_globals(void)469abb0f93cSkardel void clear_globals(void)
470abb0f93cSkardel {
471abb0f93cSkardel 	extern int ntp_optind;
472abb0f93cSkardel 	showhostnames = 0;	/* don'tshow host names by default */
473abb0f93cSkardel 	ntp_optind = 0;
474abb0f93cSkardel 	server_entry = NULL;	/* server entry for ntp */
475abb0f93cSkardel 	havehost = 0;		/* set to 1 when host open */
476abb0f93cSkardel 	numassoc = 0;		/* number of cached associations */
477abb0f93cSkardel 	numcmds = 0;
478abb0f93cSkardel 	numhosts = 0;
479abb0f93cSkardel }
480abb0f93cSkardel #endif /* !BUILD_AS_LIB */
481abb0f93cSkardel #endif /* NO_MAIN_ALLOWED */
482abb0f93cSkardel 
483abb0f93cSkardel /*
484abb0f93cSkardel  * main - parse arguments and handle options
485abb0f93cSkardel  */
486abb0f93cSkardel #ifndef NO_MAIN_ALLOWED
487abb0f93cSkardel int
main(int argc,char * argv[])488abb0f93cSkardel main(
489abb0f93cSkardel 	int argc,
490abb0f93cSkardel 	char *argv[]
491abb0f93cSkardel 	)
492abb0f93cSkardel {
493abb0f93cSkardel 	return ntpqmain(argc, argv);
494abb0f93cSkardel }
495abb0f93cSkardel #endif
496abb0f93cSkardel 
497169394abSchristos 
498abb0f93cSkardel #ifndef BUILD_AS_LIB
499abb0f93cSkardel int
ntpqmain(int argc,char * argv[])500abb0f93cSkardel ntpqmain(
501abb0f93cSkardel 	int argc,
502abb0f93cSkardel 	char *argv[]
503abb0f93cSkardel 	)
504abb0f93cSkardel {
505b3d6264cSchristos 	u_int ihost;
5064e3b3909Schristos 	size_t icmd;
507b3d6264cSchristos 
508abb0f93cSkardel 
509abb0f93cSkardel #ifdef SYS_VXWORKS
510abb0f93cSkardel 	clear_globals();
511abb0f93cSkardel 	taskPrioritySet(taskIdSelf(), 100 );
512abb0f93cSkardel #endif
513abb0f93cSkardel 
514abb0f93cSkardel 	delay_time.l_ui = 0;
515abb0f93cSkardel 	delay_time.l_uf = DEFDELAY;
516abb0f93cSkardel 
517abb0f93cSkardel 	init_lib();	/* sets up ipv4_works, ipv6_works */
518abb0f93cSkardel 	ssl_applink();
519b3d6264cSchristos 	init_auth();
520abb0f93cSkardel 
521abb0f93cSkardel 	/* Check to see if we have IPv6. Otherwise default to IPv4 */
522abb0f93cSkardel 	if (!ipv6_works)
523abb0f93cSkardel 		ai_fam_default = AF_INET;
524abb0f93cSkardel 
5254e3b3909Schristos 	/* Fixup keytype's help based on available digest names */
5264e3b3909Schristos 
5274e3b3909Schristos 	{
5284e3b3909Schristos 	    char *list;
5294e3b3909Schristos 	    char *msg;
5304e3b3909Schristos 
5314e3b3909Schristos 	    list = list_digest_names();
532169394abSchristos 
533169394abSchristos 	    for (icmd = 0; icmd < sizeof(builtins)/sizeof(*builtins); icmd++) {
534169394abSchristos 		if (strcmp("keytype", builtins[icmd].keyword) == 0) {
5354e3b3909Schristos 		    break;
5364e3b3909Schristos 		}
537169394abSchristos 	    }
5384e3b3909Schristos 
5394e3b3909Schristos 	    /* CID: 1295478 */
5404e3b3909Schristos 	    /* This should only "trip" if "keytype" is removed from builtins */
541169394abSchristos 	    INSIST(icmd < sizeof(builtins)/sizeof(*builtins));
5424e3b3909Schristos 
5434e3b3909Schristos #ifdef OPENSSL
5444e3b3909Schristos 	    builtins[icmd].desc[0] = "digest-name";
545335f7552Schristos 	    my_easprintf(&msg,
546335f7552Schristos 			 "set key type to use for authenticated requests, one of:%s",
547335f7552Schristos 			 list);
5484e3b3909Schristos #else
5494e3b3909Schristos 	    builtins[icmd].desc[0] = "md5";
550335f7552Schristos 	    my_easprintf(&msg,
551335f7552Schristos 			 "set key type to use for authenticated requests (%s)",
5524e3b3909Schristos 			 list);
553335f7552Schristos #endif
5544e3b3909Schristos 	    builtins[icmd].comment = msg;
5554e3b3909Schristos 	    free(list);
5564e3b3909Schristos 	}
5574e3b3909Schristos 
558abb0f93cSkardel 	progname = argv[0];
559abb0f93cSkardel 
560abb0f93cSkardel 	{
56145530cf1Skardel 		int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
562abb0f93cSkardel 		argc -= optct;
563abb0f93cSkardel 		argv += optct;
564abb0f93cSkardel 	}
565abb0f93cSkardel 
566abb0f93cSkardel 	/*
567abb0f93cSkardel 	 * Process options other than -c and -p, which are specially
568abb0f93cSkardel 	 * handled by ntpq_custom_opt_handler().
569abb0f93cSkardel 	 */
570abb0f93cSkardel 
571b3d6264cSchristos 	debug = OPT_VALUE_SET_DEBUG_LEVEL;
572abb0f93cSkardel 
573abb0f93cSkardel 	if (HAVE_OPT(IPV4))
574abb0f93cSkardel 		ai_fam_templ = AF_INET;
575abb0f93cSkardel 	else if (HAVE_OPT(IPV6))
576abb0f93cSkardel 		ai_fam_templ = AF_INET6;
577abb0f93cSkardel 	else
578abb0f93cSkardel 		ai_fam_templ = ai_fam_default;
579abb0f93cSkardel 
580abb0f93cSkardel 	if (HAVE_OPT(INTERACTIVE))
581abb0f93cSkardel 		interactive = 1;
582abb0f93cSkardel 
583abb0f93cSkardel 	if (HAVE_OPT(NUMERIC))
584abb0f93cSkardel 		showhostnames = 0;
585abb0f93cSkardel 
586ad131110Schristos 	if (HAVE_OPT(WIDE))
587ad131110Schristos 		wideremote = 1;
588ad131110Schristos 
589abb0f93cSkardel 	old_rv = HAVE_OPT(OLD_RV);
590abb0f93cSkardel 
591335f7552Schristos 	drefid = OPT_VALUE_REFID;
592335f7552Schristos 
593b3d6264cSchristos 	if (0 == argc) {
594abb0f93cSkardel 		ADDHOST(DEFHOST);
595abb0f93cSkardel 	} else {
596b3d6264cSchristos 		for (ihost = 0; ihost < (u_int)argc; ihost++) {
597b3d6264cSchristos 			if ('-' == *argv[ihost]) {
598b3d6264cSchristos 				//
599b3d6264cSchristos 				// If I really cared I'd also check:
600b3d6264cSchristos 				// 0 == argv[ihost][2]
601b3d6264cSchristos 				//
602b3d6264cSchristos 				// and there are other cases as well...
603b3d6264cSchristos 				//
604b3d6264cSchristos 				if ('4' == argv[ihost][1]) {
605b3d6264cSchristos 					ai_fam_templ = AF_INET;
606b3d6264cSchristos 					continue;
607b3d6264cSchristos 				} else if ('6' == argv[ihost][1]) {
608b3d6264cSchristos 					ai_fam_templ = AF_INET6;
609b3d6264cSchristos 					continue;
610b3d6264cSchristos 				} else {
611b3d6264cSchristos 					// XXX Throw a usage error
612b3d6264cSchristos 				}
613b3d6264cSchristos 			}
614b3d6264cSchristos 			ADDHOST(argv[ihost]);
615b3d6264cSchristos 		}
616abb0f93cSkardel 	}
617abb0f93cSkardel 
618abb0f93cSkardel 	if (numcmds == 0 && interactive == 0
619abb0f93cSkardel 	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
620abb0f93cSkardel 		interactive = 1;
621abb0f93cSkardel 	}
622abb0f93cSkardel 
623bd25f4c4Schristos 	set_ctrl_c_hook(on_ctrlc);
624abb0f93cSkardel #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
625abb0f93cSkardel 	if (interactive)
626bd25f4c4Schristos 		push_ctrl_c_handler(abortcmd);
627abb0f93cSkardel #endif /* SYS_WINNT */
628abb0f93cSkardel 
629abb0f93cSkardel 	if (numcmds == 0) {
630b3d6264cSchristos 		(void) openhost(chosts[0].name, chosts[0].fam);
631abb0f93cSkardel 		getcmds();
632abb0f93cSkardel 	} else {
633abb0f93cSkardel 		for (ihost = 0; ihost < numhosts; ihost++) {
634169394abSchristos 			if (openhost(chosts[ihost].name, chosts[ihost].fam)) {
6359e1d19ccSchristos 				if (ihost && current_output)
636169394abSchristos 					fputc('\n', current_output);
637169394abSchristos 				for (icmd = 0; icmd < numcmds; icmd++) {
6389e1d19ccSchristos 					if (icmd && current_output)
639169394abSchristos 						fputc('\n', current_output);
640abb0f93cSkardel 					docmd(ccmds[icmd]);
641abb0f93cSkardel 				}
642abb0f93cSkardel 			}
643169394abSchristos 		}
644169394abSchristos 	}
645abb0f93cSkardel #ifdef SYS_WINNT
646abb0f93cSkardel 	WSACleanup();
647abb0f93cSkardel #endif /* SYS_WINNT */
648abb0f93cSkardel 	return 0;
649abb0f93cSkardel }
650abb0f93cSkardel #endif /* !BUILD_AS_LIB */
651abb0f93cSkardel 
652abb0f93cSkardel /*
653abb0f93cSkardel  * openhost - open a socket to a host
654abb0f93cSkardel  */
655abb0f93cSkardel static	int
openhost(const char * hname,int fam)656abb0f93cSkardel openhost(
657b3d6264cSchristos 	const char *hname,
658b3d6264cSchristos 	int	    fam
659abb0f93cSkardel 	)
660abb0f93cSkardel {
661b3d6264cSchristos 	const char svc[] = "ntp";
662abb0f93cSkardel 	char temphost[LENHOSTNAME];
6639e1d19ccSchristos 	int a_info;
664b3d6264cSchristos 	struct addrinfo hints, *ai;
665b3d6264cSchristos 	sockaddr_u addr;
666b3d6264cSchristos 	size_t octets;
6679e1d19ccSchristos 	const char *cp;
668abb0f93cSkardel 	char name[LENHOSTNAME];
669abb0f93cSkardel 
670abb0f93cSkardel 	/*
671abb0f93cSkardel 	 * We need to get by the [] if they were entered
672abb0f93cSkardel 	 */
6739e1d19ccSchristos 	if (*hname == '[') {
6749e1d19ccSchristos 		cp = strchr(hname + 1, ']');
6759e1d19ccSchristos 		if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) {
6769e1d19ccSchristos 			errno = EINVAL;
6779e1d19ccSchristos 			warning("%s", "bad hostname/address");
678abb0f93cSkardel 			return 0;
679abb0f93cSkardel 		}
6809e1d19ccSchristos 		memcpy(name, hname + 1, octets);
6819e1d19ccSchristos 		name[octets] = '\0';
6829e1d19ccSchristos 		hname = name;
683abb0f93cSkardel 	}
684abb0f93cSkardel 
685abb0f93cSkardel 	/*
686abb0f93cSkardel 	 * First try to resolve it as an ip address and if that fails,
687abb0f93cSkardel 	 * do a fullblown (dns) lookup. That way we only use the dns
688abb0f93cSkardel 	 * when it is needed and work around some implementations that
689abb0f93cSkardel 	 * will return an "IPv4-mapped IPv6 address" address if you
690abb0f93cSkardel 	 * give it an IPv4 address to lookup.
691abb0f93cSkardel 	 */
69245530cf1Skardel 	ZERO(hints);
693b3d6264cSchristos 	hints.ai_family = fam;
694abb0f93cSkardel 	hints.ai_protocol = IPPROTO_UDP;
695abb0f93cSkardel 	hints.ai_socktype = SOCK_DGRAM;
69645530cf1Skardel 	hints.ai_flags = Z_AI_NUMERICHOST;
697b3d6264cSchristos 	ai = NULL;
698abb0f93cSkardel 
699b3d6264cSchristos 	a_info = getaddrinfo(hname, svc, &hints, &ai);
700abb0f93cSkardel 	if (a_info == EAI_NONAME
701abb0f93cSkardel #ifdef EAI_NODATA
702abb0f93cSkardel 	    || a_info == EAI_NODATA
703abb0f93cSkardel #endif
704abb0f93cSkardel 	   ) {
705abb0f93cSkardel 		hints.ai_flags = AI_CANONNAME;
706abb0f93cSkardel #ifdef AI_ADDRCONFIG
707abb0f93cSkardel 		hints.ai_flags |= AI_ADDRCONFIG;
708abb0f93cSkardel #endif
709b3d6264cSchristos 		a_info = getaddrinfo(hname, svc, &hints, &ai);
710abb0f93cSkardel 	}
711abb0f93cSkardel #ifdef AI_ADDRCONFIG
712abb0f93cSkardel 	/* Some older implementations don't like AI_ADDRCONFIG. */
713abb0f93cSkardel 	if (a_info == EAI_BADFLAGS) {
714b3d6264cSchristos 		hints.ai_flags &= ~AI_ADDRCONFIG;
715b3d6264cSchristos 		a_info = getaddrinfo(hname, svc, &hints, &ai);
716abb0f93cSkardel 	}
717abb0f93cSkardel #endif
718abb0f93cSkardel 	if (a_info != 0) {
719b3d6264cSchristos 		fprintf(stderr, "%s\n", gai_strerror(a_info));
720abb0f93cSkardel 		return 0;
721abb0f93cSkardel 	}
722abb0f93cSkardel 
723b3d6264cSchristos 	INSIST(ai != NULL);
724b3d6264cSchristos 	ZERO(addr);
725b3d6264cSchristos 	octets = min(sizeof(addr), ai->ai_addrlen);
726b3d6264cSchristos 	memcpy(&addr, ai->ai_addr, octets);
727b3d6264cSchristos 
728b3d6264cSchristos 	if (ai->ai_canonname == NULL) {
729b3d6264cSchristos 		strlcpy(temphost, stoa(&addr), sizeof(temphost));
73045530cf1Skardel 		currenthostisnum = TRUE;
731abb0f93cSkardel 	} else {
732b3d6264cSchristos 		strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
73345530cf1Skardel 		currenthostisnum = FALSE;
734abb0f93cSkardel 	}
735abb0f93cSkardel 
736abb0f93cSkardel 	if (debug > 2)
737b3d6264cSchristos 		printf("Opening host %s (%s)\n",
738b3d6264cSchristos 			temphost,
739b3d6264cSchristos 			(ai->ai_family == AF_INET)
740b3d6264cSchristos 			? "AF_INET"
741b3d6264cSchristos 			: (ai->ai_family == AF_INET6)
742b3d6264cSchristos 			  ? "AF_INET6"
743b3d6264cSchristos 			  : "AF-???"
744b3d6264cSchristos 			);
745abb0f93cSkardel 
746abb0f93cSkardel 	if (havehost == 1) {
747abb0f93cSkardel 		if (debug > 2)
748abb0f93cSkardel 			printf("Closing old host %s\n", currenthost);
749b3d6264cSchristos 		closesocket(sockfd);
750abb0f93cSkardel 		havehost = 0;
751abb0f93cSkardel 	}
752b3d6264cSchristos 	strlcpy(currenthost, temphost, sizeof(currenthost));
753abb0f93cSkardel 
754abb0f93cSkardel 	/* port maps to the same location in both families */
755b3d6264cSchristos 	s_port = NSRCPORT(&addr);
756abb0f93cSkardel #ifdef SYS_VXWORKS
757abb0f93cSkardel 	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
758abb0f93cSkardel 	if (ai->ai_family == AF_INET)
759abb0f93cSkardel 		*(struct sockaddr_in *)&hostaddr=
760abb0f93cSkardel 			*((struct sockaddr_in *)ai->ai_addr);
761abb0f93cSkardel 	else
762abb0f93cSkardel 		*(struct sockaddr_in6 *)&hostaddr=
763abb0f93cSkardel 			*((struct sockaddr_in6 *)ai->ai_addr);
764abb0f93cSkardel #endif /* SYS_VXWORKS */
765abb0f93cSkardel 
766abb0f93cSkardel #ifdef SYS_WINNT
767abb0f93cSkardel 	{
768abb0f93cSkardel 		int optionValue = SO_SYNCHRONOUS_NONALERT;
769abb0f93cSkardel 		int err;
770abb0f93cSkardel 
771abb0f93cSkardel 		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
772169394abSchristos 				 (void *)&optionValue, sizeof(optionValue));
773abb0f93cSkardel 		if (err) {
774b3d6264cSchristos 			mfprintf(stderr,
775abb0f93cSkardel 				 "setsockopt(SO_SYNCHRONOUS_NONALERT)"
776b3d6264cSchristos 				 " error: %m\n");
777b3d6264cSchristos 			freeaddrinfo(ai);
778abb0f93cSkardel 			exit(1);
779abb0f93cSkardel 		}
780abb0f93cSkardel 	}
781abb0f93cSkardel #endif /* SYS_WINNT */
782abb0f93cSkardel 
783b3d6264cSchristos 	sockfd = socket(ai->ai_family, ai->ai_socktype,
784b3d6264cSchristos 			ai->ai_protocol);
785abb0f93cSkardel 	if (sockfd == INVALID_SOCKET) {
7869ae3808cSchristos 		error("socket");
787b3d6264cSchristos 		freeaddrinfo(ai);
788b3d6264cSchristos 		return 0;
789abb0f93cSkardel 	}
790abb0f93cSkardel 
791abb0f93cSkardel 
792abb0f93cSkardel #ifdef NEED_RCVBUF_SLOP
793abb0f93cSkardel # ifdef SO_RCVBUF
794abb0f93cSkardel 	{ int rbufsize = DATASIZE + 2048;	/* 2K for slop */
795abb0f93cSkardel 	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
796169394abSchristos 		       (void *)&rbufsize, sizeof(int)) == -1)
7979ae3808cSchristos 		error("setsockopt");
798abb0f93cSkardel 	}
799abb0f93cSkardel # endif
800abb0f93cSkardel #endif
801abb0f93cSkardel 
802b3d6264cSchristos 	if
803abb0f93cSkardel #ifdef SYS_VXWORKS
804b3d6264cSchristos 	   (connect(sockfd, (struct sockaddr *)&hostaddr,
805abb0f93cSkardel 		    sizeof(hostaddr)) == -1)
806abb0f93cSkardel #else
807b3d6264cSchristos 	   (connect(sockfd, (struct sockaddr *)ai->ai_addr,
808abb0f93cSkardel 		ai->ai_addrlen) == -1)
809abb0f93cSkardel #endif /* SYS_VXWORKS */
810b3d6264cSchristos 	{
8119ae3808cSchristos 		error("connect");
812b3d6264cSchristos 		freeaddrinfo(ai);
813b3d6264cSchristos 		return 0;
814b3d6264cSchristos 	}
815abb0f93cSkardel 	freeaddrinfo(ai);
816abb0f93cSkardel 	havehost = 1;
817b3d6264cSchristos 	numassoc = 0;
818b3d6264cSchristos 
819abb0f93cSkardel 	return 1;
820abb0f93cSkardel }
821abb0f93cSkardel 
822abb0f93cSkardel 
823b3d6264cSchristos static void
dump_hex_printable(const void * data,size_t len)824b3d6264cSchristos dump_hex_printable(
825b3d6264cSchristos 	const void *	data,
826b3d6264cSchristos 	size_t		len
827b3d6264cSchristos 	)
828b3d6264cSchristos {
8291c24ec91Schristos 	/* every line shows at most 16 bytes, so we need a buffer of
8301c24ec91Schristos 	 *   4 * 16 (2 xdigits, 1 char, one sep for xdigits)
8311c24ec91Schristos 	 * + 2 * 1  (block separators)
8321c24ec91Schristos 	 * + <LF> + <NUL>
8331c24ec91Schristos 	 *---------------
8341c24ec91Schristos 	 *  68 bytes
8351c24ec91Schristos 	 */
8361c24ec91Schristos 	static const char s_xdig[16] = "0123456789ABCDEF";
837b3d6264cSchristos 
8381c24ec91Schristos 	char lbuf[68];
8391c24ec91Schristos 	int  ch, rowlen;
8401c24ec91Schristos 	const u_char * cdata = data;
8411c24ec91Schristos 	char *xptr, *pptr;
8421c24ec91Schristos 
8431c24ec91Schristos 	while (len) {
8441c24ec91Schristos 		memset(lbuf, ' ', sizeof(lbuf));
8451c24ec91Schristos 		xptr = lbuf;
8461c24ec91Schristos 		pptr = lbuf + 3*16 + 2;
8471c24ec91Schristos 
8481c24ec91Schristos 		rowlen = (len > 16) ? 16 : (int)len;
849b3d6264cSchristos 		len -= rowlen;
8501c24ec91Schristos 
8511c24ec91Schristos 		do {
8521c24ec91Schristos 			ch = *cdata++;
8531c24ec91Schristos 
8541c24ec91Schristos 			*xptr++ = s_xdig[ch >> 4  ];
8551c24ec91Schristos 			*xptr++ = s_xdig[ch & 0x0F];
8561c24ec91Schristos 			if (++xptr == lbuf + 3*8)
8571c24ec91Schristos 				++xptr;
8581c24ec91Schristos 
8591c24ec91Schristos 			*pptr++ = isprint(ch) ? (char)ch : '.';
8601c24ec91Schristos 		} while (--rowlen);
8611c24ec91Schristos 
8621c24ec91Schristos 		*pptr++ = '\n';
8631c24ec91Schristos 		*pptr   = '\0';
8641c24ec91Schristos 		fputs(lbuf, stdout);
865b3d6264cSchristos 	}
866b3d6264cSchristos }
867b3d6264cSchristos 
868b3d6264cSchristos 
869abb0f93cSkardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
870abb0f93cSkardel /*
871abb0f93cSkardel  * sendpkt - send a packet to the remote host
872abb0f93cSkardel  */
873abb0f93cSkardel static int
sendpkt(void * xdata,size_t xdatalen)874abb0f93cSkardel sendpkt(
875abb0f93cSkardel 	void *	xdata,
876abb0f93cSkardel 	size_t	xdatalen
877abb0f93cSkardel 	)
878abb0f93cSkardel {
879abb0f93cSkardel 	if (debug >= 3)
880e19314b7Schristos 		printf("Sending %zu octets\n", xdatalen);
881abb0f93cSkardel 
882bd25f4c4Schristos 	if (send(sockfd, xdata, xdatalen, 0) == -1) {
8839ae3808cSchristos 		warning("write to %s failed", currenthost);
884abb0f93cSkardel 		return -1;
885abb0f93cSkardel 	}
886abb0f93cSkardel 
887abb0f93cSkardel 	if (debug >= 4) {
888b3d6264cSchristos 		printf("Request packet:\n");
889b3d6264cSchristos 		dump_hex_printable(xdata, xdatalen);
890abb0f93cSkardel 	}
891abb0f93cSkardel 	return 0;
892abb0f93cSkardel }
893abb0f93cSkardel 
894abb0f93cSkardel /*
895abb0f93cSkardel  * getresponse - get a (series of) response packet(s) and return the data
896abb0f93cSkardel  */
897abb0f93cSkardel static int
getresponse(int opcode,int associd,u_short * rstatus,size_t * rsize,const char ** rdata,int timeo)898abb0f93cSkardel getresponse(
899abb0f93cSkardel 	int opcode,
900abb0f93cSkardel 	int associd,
901abb0f93cSkardel 	u_short *rstatus,
902bd25f4c4Schristos 	size_t *rsize,
90345530cf1Skardel 	const char **rdata,
904abb0f93cSkardel 	int timeo
905abb0f93cSkardel 	)
906abb0f93cSkardel {
907abb0f93cSkardel 	struct ntp_control rpkt;
908abb0f93cSkardel 	struct sock_timeval tvo;
909abb0f93cSkardel 	u_short offsets[MAXFRAGS+1];
910abb0f93cSkardel 	u_short counts[MAXFRAGS+1];
911abb0f93cSkardel 	u_short offset;
912abb0f93cSkardel 	u_short count;
91345530cf1Skardel 	size_t numfrags;
91445530cf1Skardel 	size_t f;
91545530cf1Skardel 	size_t ff;
916abb0f93cSkardel 	int seenlastfrag;
917abb0f93cSkardel 	int shouldbesize;
918abb0f93cSkardel 	fd_set fds;
919abb0f93cSkardel 	int n;
920b3d6264cSchristos 	int errcode;
921335f7552Schristos 	/* absolute timeout checks. Not 'time_t' by intention! */
922335f7552Schristos 	uint32_t tobase;	/* base value for timeout */
923335f7552Schristos 	uint32_t tospan;	/* timeout span (max delay) */
924335f7552Schristos 	uint32_t todiff;	/* current delay */
925abb0f93cSkardel 
9261c24ec91Schristos 	memset(offsets, 0, sizeof(offsets));
9271c24ec91Schristos 	memset(counts , 0, sizeof(counts ));
9281c24ec91Schristos 
929abb0f93cSkardel 	/*
930abb0f93cSkardel 	 * This is pretty tricky.  We may get between 1 and MAXFRAG packets
931abb0f93cSkardel 	 * back in response to the request.  We peel the data out of
932abb0f93cSkardel 	 * each packet and collect it in one long block.  When the last
933abb0f93cSkardel 	 * packet in the sequence is received we'll know how much data we
934abb0f93cSkardel 	 * should have had.  Note we use one long time out, should reconsider.
935abb0f93cSkardel 	 */
936abb0f93cSkardel 	*rsize = 0;
937abb0f93cSkardel 	if (rstatus)
938abb0f93cSkardel 		*rstatus = 0;
939abb0f93cSkardel 	*rdata = (char *)pktdata;
940abb0f93cSkardel 
941abb0f93cSkardel 	numfrags = 0;
942abb0f93cSkardel 	seenlastfrag = 0;
943abb0f93cSkardel 
944335f7552Schristos 	tobase = (uint32_t)time(NULL);
945335f7552Schristos 
946abb0f93cSkardel 	FD_ZERO(&fds);
947abb0f93cSkardel 
948abb0f93cSkardel 	/*
949abb0f93cSkardel 	 * Loop until we have an error or a complete response.  Nearly all
95045530cf1Skardel 	 * code paths to loop again use continue.
951abb0f93cSkardel 	 */
952abb0f93cSkardel 	for (;;) {
953abb0f93cSkardel 
954abb0f93cSkardel 		if (numfrags == 0)
955abb0f93cSkardel 			tvo = tvout;
956abb0f93cSkardel 		else
957abb0f93cSkardel 			tvo = tvsout;
958335f7552Schristos 		tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0);
959abb0f93cSkardel 
960abb0f93cSkardel 		FD_SET(sockfd, &fds);
96145530cf1Skardel 		n = select(sockfd+1, &fds, NULL, NULL, &tvo);
962abb0f93cSkardel 		if (n == -1) {
963335f7552Schristos #if !defined(SYS_WINNT) && defined(EINTR)
964335f7552Schristos 			/* Windows does not know about EINTR (until very
965335f7552Schristos 			 * recently) and the handling of console events
966335f7552Schristos 			 * is *very* different from POSIX/UNIX signal
967335f7552Schristos 			 * handling anyway.
968335f7552Schristos 			 *
969335f7552Schristos 			 * Under non-windows targets we map EINTR as
970335f7552Schristos 			 * 'last packet was received' and try to exit
971335f7552Schristos 			 * the receive sequence.
972335f7552Schristos 			 */
973335f7552Schristos 			if (errno == EINTR) {
974335f7552Schristos 				seenlastfrag = 1;
975335f7552Schristos 				goto maybe_final;
976335f7552Schristos 			}
977335f7552Schristos #endif
9789ae3808cSchristos 			warning("select fails");
979abb0f93cSkardel 			return -1;
980abb0f93cSkardel 		}
981335f7552Schristos 
982335f7552Schristos 		/*
983335f7552Schristos 		 * Check if this is already too late. Trash the data and
984335f7552Schristos 		 * fake a timeout if this is so.
985335f7552Schristos 		 */
986335f7552Schristos 		todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu;
987335f7552Schristos 		if ((n > 0) && (todiff > tospan)) {
988335f7552Schristos 			n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
9891c24ec91Schristos 			n -= n; /* faked timeout return from 'select()',
9901c24ec91Schristos 				 * execute RMW cycle on 'n'
9911c24ec91Schristos 				 */
992335f7552Schristos 		}
993335f7552Schristos 
9941c24ec91Schristos 		if (n <= 0) {
995abb0f93cSkardel 			/*
996abb0f93cSkardel 			 * Timed out.  Return what we have
997abb0f93cSkardel 			 */
998abb0f93cSkardel 			if (numfrags == 0) {
999abb0f93cSkardel 				if (timeo)
100045530cf1Skardel 					fprintf(stderr,
1001abb0f93cSkardel 						"%s: timed out, nothing received\n",
1002abb0f93cSkardel 						currenthost);
1003abb0f93cSkardel 				return ERR_TIMEOUT;
100445530cf1Skardel 			}
1005abb0f93cSkardel 			if (timeo)
100645530cf1Skardel 				fprintf(stderr,
1007abb0f93cSkardel 					"%s: timed out with incomplete data\n",
1008abb0f93cSkardel 					currenthost);
1009abb0f93cSkardel 			if (debug) {
101045530cf1Skardel 				fprintf(stderr,
101145530cf1Skardel 					"ERR_INCOMPLETE: Received fragments:\n");
101245530cf1Skardel 				for (f = 0; f < numfrags; f++)
101345530cf1Skardel 					fprintf(stderr,
1014b3d6264cSchristos 						"%2u: %5d %5d\t%3d octets\n",
1015b3d6264cSchristos 						(u_int)f, offsets[f],
101645530cf1Skardel 						offsets[f] +
101745530cf1Skardel 						counts[f],
101845530cf1Skardel 						counts[f]);
101945530cf1Skardel 				fprintf(stderr,
102045530cf1Skardel 					"last fragment %sreceived\n",
102145530cf1Skardel 					(seenlastfrag)
102245530cf1Skardel 					    ? ""
102345530cf1Skardel 					    : "not ");
1024abb0f93cSkardel 			}
1025abb0f93cSkardel 			return ERR_INCOMPLETE;
1026abb0f93cSkardel 		}
1027abb0f93cSkardel 
1028abb0f93cSkardel 		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
10291c24ec91Schristos 		if (n < 0) {
10309ae3808cSchristos 			warning("read");
1031abb0f93cSkardel 			return -1;
1032abb0f93cSkardel 		}
1033abb0f93cSkardel 
1034abb0f93cSkardel 		if (debug >= 4) {
1035b3d6264cSchristos 			printf("Response packet:\n");
1036b3d6264cSchristos 			dump_hex_printable(&rpkt, n);
1037abb0f93cSkardel 		}
1038abb0f93cSkardel 
1039abb0f93cSkardel 		/*
1040abb0f93cSkardel 		 * Check for format errors.  Bug proofing.
1041abb0f93cSkardel 		 */
1042f40817b7Skardel 		if (n < (int)CTL_HEADER_LEN) {
1043abb0f93cSkardel 			if (debug)
1044abb0f93cSkardel 				printf("Short (%d byte) packet received\n", n);
1045abb0f93cSkardel 			continue;
1046abb0f93cSkardel 		}
1047abb0f93cSkardel 		if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
1048abb0f93cSkardel 		    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
1049abb0f93cSkardel 			if (debug)
1050abb0f93cSkardel 				printf("Packet received with version %d\n",
1051abb0f93cSkardel 				       PKT_VERSION(rpkt.li_vn_mode));
1052abb0f93cSkardel 			continue;
1053abb0f93cSkardel 		}
1054abb0f93cSkardel 		if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
1055abb0f93cSkardel 			if (debug)
1056abb0f93cSkardel 				printf("Packet received with mode %d\n",
1057abb0f93cSkardel 				       PKT_MODE(rpkt.li_vn_mode));
1058abb0f93cSkardel 			continue;
1059abb0f93cSkardel 		}
1060abb0f93cSkardel 		if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
1061abb0f93cSkardel 			if (debug)
1062abb0f93cSkardel 				printf("Received request packet, wanted response\n");
1063abb0f93cSkardel 			continue;
1064abb0f93cSkardel 		}
1065abb0f93cSkardel 
1066abb0f93cSkardel 		/*
1067abb0f93cSkardel 		 * Check opcode and sequence number for a match.
1068abb0f93cSkardel 		 * Could be old data getting to us.
1069abb0f93cSkardel 		 */
1070abb0f93cSkardel 		if (ntohs(rpkt.sequence) != sequence) {
1071abb0f93cSkardel 			if (debug)
107245530cf1Skardel 				printf("Received sequnce number %d, wanted %d\n",
1073abb0f93cSkardel 				       ntohs(rpkt.sequence), sequence);
1074abb0f93cSkardel 			continue;
1075abb0f93cSkardel 		}
1076abb0f93cSkardel 		if (CTL_OP(rpkt.r_m_e_op) != opcode) {
1077abb0f93cSkardel 			if (debug)
1078abb0f93cSkardel 			    printf(
1079abb0f93cSkardel 				    "Received opcode %d, wanted %d (sequence number okay)\n",
1080abb0f93cSkardel 				    CTL_OP(rpkt.r_m_e_op), opcode);
1081abb0f93cSkardel 			continue;
1082abb0f93cSkardel 		}
1083abb0f93cSkardel 
1084abb0f93cSkardel 		/*
1085abb0f93cSkardel 		 * Check the error code.  If non-zero, return it.
1086abb0f93cSkardel 		 */
1087abb0f93cSkardel 		if (CTL_ISERROR(rpkt.r_m_e_op)) {
1088abb0f93cSkardel 			errcode = (ntohs(rpkt.status) >> 8) & 0xff;
1089b3d6264cSchristos 			if (CTL_ISMORE(rpkt.r_m_e_op))
1090b3d6264cSchristos 				TRACE(1, ("Error code %d received on not-final packet\n",
1091b3d6264cSchristos 					  errcode));
1092abb0f93cSkardel 			if (errcode == CERR_UNSPEC)
1093abb0f93cSkardel 				return ERR_UNSPEC;
1094abb0f93cSkardel 			return errcode;
1095abb0f93cSkardel 		}
1096abb0f93cSkardel 
1097abb0f93cSkardel 		/*
1098abb0f93cSkardel 		 * Check the association ID to make sure it matches what
1099abb0f93cSkardel 		 * we sent.
1100abb0f93cSkardel 		 */
1101abb0f93cSkardel 		if (ntohs(rpkt.associd) != associd) {
1102b3d6264cSchristos 			TRACE(1, ("Association ID %d doesn't match expected %d\n",
1103b3d6264cSchristos 				  ntohs(rpkt.associd), associd));
1104abb0f93cSkardel 			/*
1105abb0f93cSkardel 			 * Hack for silly fuzzballs which, at the time of writing,
1106abb0f93cSkardel 			 * return an assID of sys.peer when queried for system variables.
1107abb0f93cSkardel 			 */
1108abb0f93cSkardel #ifdef notdef
1109abb0f93cSkardel 			continue;
1110abb0f93cSkardel #endif
1111abb0f93cSkardel 		}
1112abb0f93cSkardel 
1113abb0f93cSkardel 		/*
1114abb0f93cSkardel 		 * Collect offset and count.  Make sure they make sense.
1115abb0f93cSkardel 		 */
1116abb0f93cSkardel 		offset = ntohs(rpkt.offset);
1117abb0f93cSkardel 		count = ntohs(rpkt.count);
1118abb0f93cSkardel 
1119abb0f93cSkardel 		/*
1120abb0f93cSkardel 		 * validate received payload size is padded to next 32-bit
1121abb0f93cSkardel 		 * boundary and no smaller than claimed by rpkt.count
1122abb0f93cSkardel 		 */
1123abb0f93cSkardel 		if (n & 0x3) {
1124b3d6264cSchristos 			TRACE(1, ("Response packet not padded, size = %d\n",
1125b3d6264cSchristos 				  n));
1126abb0f93cSkardel 			continue;
1127abb0f93cSkardel 		}
1128abb0f93cSkardel 
1129abb0f93cSkardel 		shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
1130abb0f93cSkardel 
1131abb0f93cSkardel 		if (n < shouldbesize) {
1132b3d6264cSchristos 			printf("Response packet claims %u octets payload, above %ld received\n",
113366fcc386Schristos 			       count, (long)(n - CTL_HEADER_LEN));
1134abb0f93cSkardel 			return ERR_INCOMPLETE;
1135abb0f93cSkardel 		}
1136abb0f93cSkardel 
1137abb0f93cSkardel 		if (debug >= 3 && shouldbesize > n) {
1138abb0f93cSkardel 			u_int32 key;
1139abb0f93cSkardel 			u_int32 *lpkt;
1140abb0f93cSkardel 			int maclen;
1141abb0f93cSkardel 
1142abb0f93cSkardel 			/*
1143abb0f93cSkardel 			 * Usually we ignore authentication, but for debugging purposes
1144abb0f93cSkardel 			 * we watch it here.
1145abb0f93cSkardel 			 */
1146abb0f93cSkardel 			/* round to 8 octet boundary */
1147abb0f93cSkardel 			shouldbesize = (shouldbesize + 7) & ~7;
1148abb0f93cSkardel 
1149abb0f93cSkardel 			maclen = n - shouldbesize;
1150e19314b7Schristos 			if (maclen >= (int)MIN_MAC_LEN) {
1151abb0f93cSkardel 				printf(
1152abb0f93cSkardel 					"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1153abb0f93cSkardel 					n, shouldbesize, maclen);
1154abb0f93cSkardel 				lpkt = (u_int32 *)&rpkt;
1155abb0f93cSkardel 				printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1156abb0f93cSkardel 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1157abb0f93cSkardel 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1158abb0f93cSkardel 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1159abb0f93cSkardel 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1160abb0f93cSkardel 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1161abb0f93cSkardel 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1162abb0f93cSkardel 				key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1163abb0f93cSkardel 				printf("Authenticated with keyid %lu\n", (u_long)key);
1164abb0f93cSkardel 				if (key != 0 && key != info_auth_keyid) {
1165abb0f93cSkardel 					printf("We don't know that key\n");
1166abb0f93cSkardel 				} else {
1167abb0f93cSkardel 					if (authdecrypt(key, (u_int32 *)&rpkt,
1168abb0f93cSkardel 					    n - maclen, maclen)) {
1169abb0f93cSkardel 						printf("Auth okay!\n");
1170abb0f93cSkardel 					} else {
1171abb0f93cSkardel 						printf("Auth failed!\n");
1172abb0f93cSkardel 					}
1173abb0f93cSkardel 				}
1174abb0f93cSkardel 			}
1175abb0f93cSkardel 		}
1176abb0f93cSkardel 
1177b3d6264cSchristos 		TRACE(2, ("Got packet, size = %d\n", n));
1178b3d6264cSchristos 		if (count > (n - CTL_HEADER_LEN)) {
1179b3d6264cSchristos 			TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
1180b3d6264cSchristos 				  count, (long)n - CTL_HEADER_LEN));
1181abb0f93cSkardel 			continue;
1182abb0f93cSkardel 		}
1183abb0f93cSkardel 		if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1184b3d6264cSchristos 			TRACE(1, ("Received count of 0 in non-final fragment\n"));
1185abb0f93cSkardel 			continue;
1186abb0f93cSkardel 		}
1187abb0f93cSkardel 		if (offset + count > sizeof(pktdata)) {
1188b3d6264cSchristos 			TRACE(1, ("Offset %u, count %u, too big for buffer\n",
1189b3d6264cSchristos 				  offset, count));
1190abb0f93cSkardel 			return ERR_TOOMUCH;
1191abb0f93cSkardel 		}
1192abb0f93cSkardel 		if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1193b3d6264cSchristos 			TRACE(1, ("Received second last fragment packet\n"));
1194abb0f93cSkardel 			continue;
1195abb0f93cSkardel 		}
1196abb0f93cSkardel 
1197abb0f93cSkardel 		/*
1198abb0f93cSkardel 		 * So far, so good.  Record this fragment, making sure it doesn't
1199abb0f93cSkardel 		 * overlap anything.
1200abb0f93cSkardel 		 */
1201b3d6264cSchristos 		TRACE(2, ("Packet okay\n"));
1202abb0f93cSkardel 
1203abb0f93cSkardel 		if (numfrags > (MAXFRAGS - 1)) {
1204b3d6264cSchristos 			TRACE(2, ("Number of fragments exceeds maximum %d\n",
1205b3d6264cSchristos 				  MAXFRAGS - 1));
1206abb0f93cSkardel 			return ERR_TOOMUCH;
1207abb0f93cSkardel 		}
1208abb0f93cSkardel 
1209abb0f93cSkardel 		/*
1210abb0f93cSkardel 		 * Find the position for the fragment relative to any
1211abb0f93cSkardel 		 * previously received.
1212abb0f93cSkardel 		 */
121345530cf1Skardel 		for (f = 0;
121445530cf1Skardel 		     f < numfrags && offsets[f] < offset;
121545530cf1Skardel 		     f++) {
1216abb0f93cSkardel 			/* empty body */ ;
1217abb0f93cSkardel 		}
1218abb0f93cSkardel 
121945530cf1Skardel 		if (f < numfrags && offset == offsets[f]) {
1220b3d6264cSchristos 			TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
1221b3d6264cSchristos 				  count, offset, counts[f], offsets[f]));
1222abb0f93cSkardel 			continue;
1223abb0f93cSkardel 		}
1224abb0f93cSkardel 
122545530cf1Skardel 		if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1226b3d6264cSchristos 			TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
1227b3d6264cSchristos 				  offset, counts[f-1], offsets[f-1]));
1228abb0f93cSkardel 			continue;
1229abb0f93cSkardel 		}
1230abb0f93cSkardel 
123145530cf1Skardel 		if (f < numfrags && (offset + count) > offsets[f]) {
1232b3d6264cSchristos 			TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
1233b3d6264cSchristos 				  count, offset, offsets[f]));
1234abb0f93cSkardel 			continue;
1235abb0f93cSkardel 		}
1236abb0f93cSkardel 
123745530cf1Skardel 		for (ff = numfrags; ff > f; ff--) {
123845530cf1Skardel 			offsets[ff] = offsets[ff-1];
123945530cf1Skardel 			counts[ff] = counts[ff-1];
1240abb0f93cSkardel 		}
124145530cf1Skardel 		offsets[f] = offset;
124245530cf1Skardel 		counts[f] = count;
1243abb0f93cSkardel 		numfrags++;
1244abb0f93cSkardel 
1245abb0f93cSkardel 		/*
1246abb0f93cSkardel 		 * Got that stuffed in right.  Figure out if this was the last.
1247abb0f93cSkardel 		 * Record status info out of the last packet.
1248abb0f93cSkardel 		 */
1249abb0f93cSkardel 		if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1250abb0f93cSkardel 			seenlastfrag = 1;
1251abb0f93cSkardel 			if (rstatus != 0)
1252abb0f93cSkardel 				*rstatus = ntohs(rpkt.status);
1253abb0f93cSkardel 		}
1254abb0f93cSkardel 
1255abb0f93cSkardel 		/*
1256335f7552Schristos 		 * Copy the data into the data buffer, and bump the
1257335f7552Schristos 		 * timout base in case we need more.
1258abb0f93cSkardel 		 */
1259b3d6264cSchristos 		memcpy((char *)pktdata + offset, &rpkt.u, count);
1260335f7552Schristos 		tobase = (uint32_t)time(NULL);
1261abb0f93cSkardel 
1262abb0f93cSkardel 		/*
1263abb0f93cSkardel 		 * If we've seen the last fragment, look for holes in the sequence.
1264abb0f93cSkardel 		 * If there aren't any, we're done.
1265abb0f93cSkardel 		 */
126666fcc386Schristos #if !defined(SYS_WINNT) && defined(EINTR)
1267335f7552Schristos 		maybe_final:
126866fcc386Schristos #endif
126966fcc386Schristos 
1270abb0f93cSkardel 		if (seenlastfrag && offsets[0] == 0) {
127145530cf1Skardel 			for (f = 1; f < numfrags; f++)
127245530cf1Skardel 				if (offsets[f-1] + counts[f-1] !=
127345530cf1Skardel 				    offsets[f])
1274abb0f93cSkardel 					break;
127545530cf1Skardel 			if (f == numfrags) {
127645530cf1Skardel 				*rsize = offsets[f-1] + counts[f-1];
1277b3d6264cSchristos 				TRACE(1, ("%lu packets reassembled into response\n",
1278b3d6264cSchristos 					  (u_long)numfrags));
1279abb0f93cSkardel 				return 0;
1280abb0f93cSkardel 			}
1281abb0f93cSkardel 		}
1282abb0f93cSkardel 	}  /* giant for (;;) collecting response packets */
1283abb0f93cSkardel }  /* getresponse() */
1284abb0f93cSkardel 
1285abb0f93cSkardel 
1286abb0f93cSkardel /*
1287abb0f93cSkardel  * sendrequest - format and send a request packet
1288abb0f93cSkardel  */
1289abb0f93cSkardel static int
sendrequest(int opcode,associd_t associd,int auth,size_t qsize,const char * qdata)1290abb0f93cSkardel sendrequest(
1291abb0f93cSkardel 	int opcode,
1292b3d6264cSchristos 	associd_t associd,
1293abb0f93cSkardel 	int auth,
1294bd25f4c4Schristos 	size_t qsize,
1295b3d6264cSchristos 	const char *qdata
1296abb0f93cSkardel 	)
1297abb0f93cSkardel {
1298abb0f93cSkardel 	struct ntp_control qpkt;
1299bd25f4c4Schristos 	size_t	pktsize;
1300abb0f93cSkardel 	u_long	key_id;
1301abb0f93cSkardel 	char *	pass;
1302bd25f4c4Schristos 	size_t	maclen;
1303abb0f93cSkardel 
1304abb0f93cSkardel 	/*
1305abb0f93cSkardel 	 * Check to make sure the data will fit in one packet
1306abb0f93cSkardel 	 */
1307abb0f93cSkardel 	if (qsize > CTL_MAX_DATA_LEN) {
1308abb0f93cSkardel 		fprintf(stderr,
1309bd25f4c4Schristos 			"***Internal error!  qsize (%zu) too large\n",
1310abb0f93cSkardel 			qsize);
1311abb0f93cSkardel 		return 1;
1312abb0f93cSkardel 	}
1313abb0f93cSkardel 
1314abb0f93cSkardel 	/*
1315abb0f93cSkardel 	 * Fill in the packet
1316abb0f93cSkardel 	 */
1317abb0f93cSkardel 	qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1318abb0f93cSkardel 	qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1319abb0f93cSkardel 	qpkt.sequence = htons(sequence);
1320abb0f93cSkardel 	qpkt.status = 0;
1321abb0f93cSkardel 	qpkt.associd = htons((u_short)associd);
1322abb0f93cSkardel 	qpkt.offset = 0;
1323abb0f93cSkardel 	qpkt.count = htons((u_short)qsize);
1324abb0f93cSkardel 
1325abb0f93cSkardel 	pktsize = CTL_HEADER_LEN;
1326abb0f93cSkardel 
1327abb0f93cSkardel 	/*
1328abb0f93cSkardel 	 * If we have data, copy and pad it out to a 32-bit boundary.
1329abb0f93cSkardel 	 */
1330abb0f93cSkardel 	if (qsize > 0) {
1331b3d6264cSchristos 		memcpy(&qpkt.u, qdata, (size_t)qsize);
1332abb0f93cSkardel 		pktsize += qsize;
1333abb0f93cSkardel 		while (pktsize & (sizeof(u_int32) - 1)) {
1334b3d6264cSchristos 			qpkt.u.data[qsize++] = 0;
1335abb0f93cSkardel 			pktsize++;
1336abb0f93cSkardel 		}
1337abb0f93cSkardel 	}
1338abb0f93cSkardel 
1339abb0f93cSkardel 	/*
1340abb0f93cSkardel 	 * If it isn't authenticated we can just send it.  Otherwise
1341abb0f93cSkardel 	 * we're going to have to think about it a little.
1342abb0f93cSkardel 	 */
1343abb0f93cSkardel 	if (!auth && !always_auth) {
1344abb0f93cSkardel 		return sendpkt(&qpkt, pktsize);
1345abb0f93cSkardel 	}
1346abb0f93cSkardel 
1347abb0f93cSkardel 	/*
1348abb0f93cSkardel 	 * Pad out packet to a multiple of 8 octets to be sure
1349abb0f93cSkardel 	 * receiver can handle it.
1350abb0f93cSkardel 	 */
1351abb0f93cSkardel 	while (pktsize & 7) {
1352b3d6264cSchristos 		qpkt.u.data[qsize++] = 0;
1353abb0f93cSkardel 		pktsize++;
1354abb0f93cSkardel 	}
1355abb0f93cSkardel 
1356abb0f93cSkardel 	/*
1357abb0f93cSkardel 	 * Get the keyid and the password if we don't have one.
1358abb0f93cSkardel 	 */
1359abb0f93cSkardel 	if (info_auth_keyid == 0) {
1360abb0f93cSkardel 		key_id = getkeyid("Keyid: ");
1361abb0f93cSkardel 		if (key_id == 0 || key_id > NTP_MAXKEY) {
1362abb0f93cSkardel 			fprintf(stderr,
1363abb0f93cSkardel 				"Invalid key identifier\n");
1364abb0f93cSkardel 			return 1;
1365abb0f93cSkardel 		}
1366abb0f93cSkardel 		info_auth_keyid = key_id;
1367abb0f93cSkardel 	}
1368abb0f93cSkardel 	if (!authistrusted(info_auth_keyid)) {
136945530cf1Skardel 		pass = getpass_keytype(info_auth_keytype);
1370abb0f93cSkardel 		if ('\0' == pass[0]) {
1371abb0f93cSkardel 			fprintf(stderr, "Invalid password\n");
1372abb0f93cSkardel 			return 1;
1373abb0f93cSkardel 		}
1374abb0f93cSkardel 		authusekey(info_auth_keyid, info_auth_keytype,
1375abb0f93cSkardel 			   (u_char *)pass);
1376abb0f93cSkardel 		authtrust(info_auth_keyid, 1);
1377abb0f93cSkardel 	}
1378abb0f93cSkardel 
1379abb0f93cSkardel 	/*
1380abb0f93cSkardel 	 * Do the encryption.
1381abb0f93cSkardel 	 */
1382abb0f93cSkardel 	maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1383abb0f93cSkardel 	if (!maclen) {
1384abb0f93cSkardel 		fprintf(stderr, "Key not found\n");
1385abb0f93cSkardel 		return 1;
1386abb0f93cSkardel 	} else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1387abb0f93cSkardel 		fprintf(stderr,
1388bd25f4c4Schristos 			"%zu octet MAC, %zu expected with %zu octet digest\n",
1389abb0f93cSkardel 			maclen, (info_auth_hashlen + sizeof(keyid_t)),
1390abb0f93cSkardel 			info_auth_hashlen);
1391abb0f93cSkardel 		return 1;
1392abb0f93cSkardel 	}
1393abb0f93cSkardel 
1394abb0f93cSkardel 	return sendpkt((char *)&qpkt, pktsize + maclen);
1395abb0f93cSkardel }
1396abb0f93cSkardel 
1397abb0f93cSkardel 
1398abb0f93cSkardel /*
139945530cf1Skardel  * show_error_msg - display the error text for a mode 6 error response.
140045530cf1Skardel  */
140145530cf1Skardel void
show_error_msg(int m6resp,associd_t associd)140245530cf1Skardel show_error_msg(
140345530cf1Skardel 	int		m6resp,
140445530cf1Skardel 	associd_t	associd
140545530cf1Skardel 	)
140645530cf1Skardel {
140745530cf1Skardel 	if (numhosts > 1)
140845530cf1Skardel 		fprintf(stderr, "server=%s ", currenthost);
140945530cf1Skardel 
141045530cf1Skardel 	switch (m6resp) {
141145530cf1Skardel 
141245530cf1Skardel 	case CERR_BADFMT:
141345530cf1Skardel 		fprintf(stderr,
141445530cf1Skardel 		    "***Server reports a bad format request packet\n");
141545530cf1Skardel 		break;
141645530cf1Skardel 
141745530cf1Skardel 	case CERR_PERMISSION:
141845530cf1Skardel 		fprintf(stderr,
141945530cf1Skardel 		    "***Server disallowed request (authentication?)\n");
142045530cf1Skardel 		break;
142145530cf1Skardel 
142245530cf1Skardel 	case CERR_BADOP:
142345530cf1Skardel 		fprintf(stderr,
142445530cf1Skardel 		    "***Server reports a bad opcode in request\n");
142545530cf1Skardel 		break;
142645530cf1Skardel 
142745530cf1Skardel 	case CERR_BADASSOC:
142845530cf1Skardel 		fprintf(stderr,
142945530cf1Skardel 		    "***Association ID %d unknown to server\n",
143045530cf1Skardel 		    associd);
143145530cf1Skardel 		break;
143245530cf1Skardel 
143345530cf1Skardel 	case CERR_UNKNOWNVAR:
143445530cf1Skardel 		fprintf(stderr,
143545530cf1Skardel 		    "***A request variable unknown to the server\n");
143645530cf1Skardel 		break;
143745530cf1Skardel 
143845530cf1Skardel 	case CERR_BADVALUE:
143945530cf1Skardel 		fprintf(stderr,
144045530cf1Skardel 		    "***Server indicates a request variable was bad\n");
144145530cf1Skardel 		break;
144245530cf1Skardel 
144345530cf1Skardel 	case ERR_UNSPEC:
144445530cf1Skardel 		fprintf(stderr,
144545530cf1Skardel 		    "***Server returned an unspecified error\n");
144645530cf1Skardel 		break;
144745530cf1Skardel 
144845530cf1Skardel 	case ERR_TIMEOUT:
144945530cf1Skardel 		fprintf(stderr, "***Request timed out\n");
145045530cf1Skardel 		break;
145145530cf1Skardel 
145245530cf1Skardel 	case ERR_INCOMPLETE:
145345530cf1Skardel 		fprintf(stderr,
145445530cf1Skardel 		    "***Response from server was incomplete\n");
145545530cf1Skardel 		break;
145645530cf1Skardel 
145745530cf1Skardel 	case ERR_TOOMUCH:
145845530cf1Skardel 		fprintf(stderr,
145945530cf1Skardel 		    "***Buffer size exceeded for returned data\n");
146045530cf1Skardel 		break;
146145530cf1Skardel 
146245530cf1Skardel 	default:
146345530cf1Skardel 		fprintf(stderr,
146445530cf1Skardel 		    "***Server returns unknown error code %d\n",
146545530cf1Skardel 		    m6resp);
146645530cf1Skardel 	}
146745530cf1Skardel }
146845530cf1Skardel 
146945530cf1Skardel /*
147045530cf1Skardel  * doquery - send a request and process the response, displaying
147145530cf1Skardel  *	     error messages for any error responses.
1472abb0f93cSkardel  */
1473abb0f93cSkardel int
doquery(int opcode,associd_t associd,int auth,size_t qsize,const char * qdata,u_short * rstatus,size_t * rsize,const char ** rdata)1474abb0f93cSkardel doquery(
1475abb0f93cSkardel 	int opcode,
147645530cf1Skardel 	associd_t associd,
1477abb0f93cSkardel 	int auth,
1478bd25f4c4Schristos 	size_t qsize,
1479b3d6264cSchristos 	const char *qdata,
1480abb0f93cSkardel 	u_short *rstatus,
1481bd25f4c4Schristos 	size_t *rsize,
148245530cf1Skardel 	const char **rdata
148345530cf1Skardel 	)
148445530cf1Skardel {
148545530cf1Skardel 	return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
148645530cf1Skardel 			 rsize, rdata, FALSE);
148745530cf1Skardel }
148845530cf1Skardel 
148945530cf1Skardel 
149045530cf1Skardel /*
149145530cf1Skardel  * doqueryex - send a request and process the response, optionally
149245530cf1Skardel  *	       displaying error messages for any error responses.
149345530cf1Skardel  */
149445530cf1Skardel int
doqueryex(int opcode,associd_t associd,int auth,size_t qsize,const char * qdata,u_short * rstatus,size_t * rsize,const char ** rdata,int quiet)149545530cf1Skardel doqueryex(
149645530cf1Skardel 	int opcode,
149745530cf1Skardel 	associd_t associd,
149845530cf1Skardel 	int auth,
1499bd25f4c4Schristos 	size_t qsize,
1500b3d6264cSchristos 	const char *qdata,
150145530cf1Skardel 	u_short *rstatus,
1502bd25f4c4Schristos 	size_t *rsize,
150345530cf1Skardel 	const char **rdata,
150445530cf1Skardel 	int quiet
1505abb0f93cSkardel 	)
1506abb0f93cSkardel {
1507abb0f93cSkardel 	int res;
1508abb0f93cSkardel 	int done;
1509abb0f93cSkardel 
1510abb0f93cSkardel 	/*
1511abb0f93cSkardel 	 * Check to make sure host is open
1512abb0f93cSkardel 	 */
1513abb0f93cSkardel 	if (!havehost) {
151445530cf1Skardel 		fprintf(stderr, "***No host open, use `host' command\n");
1515abb0f93cSkardel 		return -1;
1516abb0f93cSkardel 	}
1517abb0f93cSkardel 
1518abb0f93cSkardel 	done = 0;
1519abb0f93cSkardel 	sequence++;
1520abb0f93cSkardel 
1521abb0f93cSkardel     again:
1522abb0f93cSkardel 	/*
1523abb0f93cSkardel 	 * send a request
1524abb0f93cSkardel 	 */
1525abb0f93cSkardel 	res = sendrequest(opcode, associd, auth, qsize, qdata);
1526abb0f93cSkardel 	if (res != 0)
1527abb0f93cSkardel 		return res;
1528abb0f93cSkardel 
1529abb0f93cSkardel 	/*
1530abb0f93cSkardel 	 * Get the response.  If we got a standard error, print a message
1531abb0f93cSkardel 	 */
1532abb0f93cSkardel 	res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1533abb0f93cSkardel 
1534abb0f93cSkardel 	if (res > 0) {
1535abb0f93cSkardel 		if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1536abb0f93cSkardel 			if (res == ERR_INCOMPLETE) {
1537abb0f93cSkardel 				/*
1538abb0f93cSkardel 				 * better bump the sequence so we don't
1539abb0f93cSkardel 				 * get confused about differing fragments.
1540abb0f93cSkardel 				 */
1541abb0f93cSkardel 				sequence++;
1542abb0f93cSkardel 			}
1543abb0f93cSkardel 			done = 1;
1544abb0f93cSkardel 			goto again;
1545abb0f93cSkardel 		}
154645530cf1Skardel 		if (!quiet)
154745530cf1Skardel 			show_error_msg(res, associd);
154845530cf1Skardel 
1549abb0f93cSkardel 	}
1550abb0f93cSkardel 	return res;
1551abb0f93cSkardel }
1552abb0f93cSkardel 
1553abb0f93cSkardel 
1554abb0f93cSkardel #ifndef BUILD_AS_LIB
1555abb0f93cSkardel /*
1556abb0f93cSkardel  * getcmds - read commands from the standard input and execute them
1557abb0f93cSkardel  */
1558abb0f93cSkardel static void
getcmds(void)1559abb0f93cSkardel getcmds(void)
1560abb0f93cSkardel {
1561abb0f93cSkardel 	char *	line;
1562abb0f93cSkardel 	int	count;
1563abb0f93cSkardel 
1564abb0f93cSkardel 	ntp_readline_init(interactive ? prompt : NULL);
1565abb0f93cSkardel 
1566abb0f93cSkardel 	for (;;) {
1567abb0f93cSkardel 		line = ntp_readline(&count);
1568abb0f93cSkardel 		if (NULL == line)
1569abb0f93cSkardel 			break;
1570abb0f93cSkardel 		docmd(line);
1571abb0f93cSkardel 		free(line);
1572abb0f93cSkardel 	}
1573abb0f93cSkardel 
1574abb0f93cSkardel 	ntp_readline_uninit();
1575abb0f93cSkardel }
1576abb0f93cSkardel #endif /* !BUILD_AS_LIB */
1577abb0f93cSkardel 
1578abb0f93cSkardel 
1579abb0f93cSkardel #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1580abb0f93cSkardel /*
1581abb0f93cSkardel  * abortcmd - catch interrupts and abort the current command
1582abb0f93cSkardel  */
1583bd25f4c4Schristos static int
abortcmd(void)1584bd25f4c4Schristos abortcmd(void)
1585abb0f93cSkardel {
1586abb0f93cSkardel 	if (current_output == stdout)
1587abb0f93cSkardel 		(void) fflush(stdout);
1588abb0f93cSkardel 	putc('\n', stderr);
1589abb0f93cSkardel 	(void) fflush(stderr);
1590bd25f4c4Schristos 	if (jump) {
1591bd25f4c4Schristos 		jump = 0;
15929e1d19ccSchristos 		LONGJMP(interrupt_buf, 1);
1593bd25f4c4Schristos 	}
1594bd25f4c4Schristos 	return TRUE;
1595abb0f93cSkardel }
1596abb0f93cSkardel #endif	/* !SYS_WINNT && !BUILD_AS_LIB */
1597abb0f93cSkardel 
1598abb0f93cSkardel 
1599abb0f93cSkardel #ifndef	BUILD_AS_LIB
1600abb0f93cSkardel /*
1601abb0f93cSkardel  * docmd - decode the command line and execute a command
1602abb0f93cSkardel  */
1603abb0f93cSkardel static void
docmd(const char * cmdline)1604abb0f93cSkardel docmd(
1605abb0f93cSkardel 	const char *cmdline
1606abb0f93cSkardel 	)
1607abb0f93cSkardel {
1608abb0f93cSkardel 	char *tokens[1+MAXARGS+2];
1609abb0f93cSkardel 	struct parse pcmd;
1610abb0f93cSkardel 	int ntok;
1611abb0f93cSkardel 	static int i;
1612abb0f93cSkardel 	struct xcmd *xcmd;
1613abb0f93cSkardel 
1614abb0f93cSkardel 	/*
1615abb0f93cSkardel 	 * Tokenize the command line.  If nothing on it, return.
1616abb0f93cSkardel 	 */
1617abb0f93cSkardel 	tokenize(cmdline, tokens, &ntok);
1618abb0f93cSkardel 	if (ntok == 0)
1619abb0f93cSkardel 	    return;
1620abb0f93cSkardel 
1621abb0f93cSkardel 	/*
1622abb0f93cSkardel 	 * Find the appropriate command description.
1623abb0f93cSkardel 	 */
1624abb0f93cSkardel 	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1625abb0f93cSkardel 	if (i == 0) {
1626abb0f93cSkardel 		(void) fprintf(stderr, "***Command `%s' unknown\n",
1627abb0f93cSkardel 			       tokens[0]);
1628abb0f93cSkardel 		return;
1629abb0f93cSkardel 	} else if (i >= 2) {
1630abb0f93cSkardel 		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
1631abb0f93cSkardel 			       tokens[0]);
1632abb0f93cSkardel 		return;
1633abb0f93cSkardel 	}
1634abb0f93cSkardel 
1635b3d6264cSchristos 	/* Warn about ignored extra args */
1636b3d6264cSchristos 	for (i = MAXARGS + 1; i < ntok ; ++i) {
1637b3d6264cSchristos 		fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
1638b3d6264cSchristos 	}
1639b3d6264cSchristos 
1640abb0f93cSkardel 	/*
1641abb0f93cSkardel 	 * Save the keyword, then walk through the arguments, interpreting
1642abb0f93cSkardel 	 * as we go.
1643abb0f93cSkardel 	 */
1644abb0f93cSkardel 	pcmd.keyword = tokens[0];
1645abb0f93cSkardel 	pcmd.nargs = 0;
1646abb0f93cSkardel 	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1647abb0f93cSkardel 		if ((i+1) >= ntok) {
1648abb0f93cSkardel 			if (!(xcmd->arg[i] & OPT)) {
1649abb0f93cSkardel 				printusage(xcmd, stderr);
1650abb0f93cSkardel 				return;
1651abb0f93cSkardel 			}
1652abb0f93cSkardel 			break;
1653abb0f93cSkardel 		}
1654abb0f93cSkardel 		if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1655abb0f93cSkardel 			break;
1656abb0f93cSkardel 		if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1657abb0f93cSkardel 			return;
1658abb0f93cSkardel 		pcmd.nargs++;
1659abb0f93cSkardel 	}
1660abb0f93cSkardel 
1661abb0f93cSkardel 	i++;
1662abb0f93cSkardel 	if (i < ntok && *tokens[i] == '>') {
1663abb0f93cSkardel 		char *fname;
1664abb0f93cSkardel 
1665abb0f93cSkardel 		if (*(tokens[i]+1) != '\0')
1666abb0f93cSkardel 			fname = tokens[i]+1;
1667abb0f93cSkardel 		else if ((i+1) < ntok)
1668abb0f93cSkardel 			fname = tokens[i+1];
1669abb0f93cSkardel 		else {
1670abb0f93cSkardel 			(void) fprintf(stderr, "***No file for redirect\n");
1671abb0f93cSkardel 			return;
1672abb0f93cSkardel 		}
1673abb0f93cSkardel 
1674abb0f93cSkardel 		current_output = fopen(fname, "w");
1675abb0f93cSkardel 		if (current_output == NULL) {
1676abb0f93cSkardel 			(void) fprintf(stderr, "***Error opening %s: ", fname);
1677abb0f93cSkardel 			perror("");
1678abb0f93cSkardel 			return;
1679abb0f93cSkardel 		}
1680abb0f93cSkardel 	} else {
1681abb0f93cSkardel 		current_output = stdout;
1682abb0f93cSkardel 	}
1683abb0f93cSkardel 
16849e1d19ccSchristos 	if (interactive) {
16859e1d19ccSchristos 		if ( ! SETJMP(interrupt_buf)) {
16869e1d19ccSchristos 			jump = 1;
1687abb0f93cSkardel 			(xcmd->handler)(&pcmd, current_output);
16889e1d19ccSchristos 			jump = 0;
16899e1d19ccSchristos 		} else {
16909e1d19ccSchristos 			fflush(current_output);
16919e1d19ccSchristos 			fputs("\n >>> command aborted <<<\n", stderr);
16929e1d19ccSchristos 			fflush(stderr);
1693abb0f93cSkardel 		}
1694b3d6264cSchristos 
16959e1d19ccSchristos 	} else {
16969e1d19ccSchristos 		jump = 0;
16979e1d19ccSchristos 		(xcmd->handler)(&pcmd, current_output);
16989e1d19ccSchristos 	}
16999e1d19ccSchristos 	if ((NULL != current_output) && (stdout != current_output)) {
17009e1d19ccSchristos 		(void)fclose(current_output);
17019e1d19ccSchristos 		current_output = NULL;
17029e1d19ccSchristos 	}
1703abb0f93cSkardel }
1704abb0f93cSkardel 
1705abb0f93cSkardel 
1706abb0f93cSkardel /*
1707abb0f93cSkardel  * tokenize - turn a command line into tokens
1708abb0f93cSkardel  *
1709abb0f93cSkardel  * SK: Modified to allow a quoted string
1710abb0f93cSkardel  *
1711abb0f93cSkardel  * HMS: If the first character of the first token is a ':' then (after
1712abb0f93cSkardel  * eating inter-token whitespace) the 2nd token is the rest of the line.
1713abb0f93cSkardel  */
1714abb0f93cSkardel 
1715abb0f93cSkardel static void
tokenize(const char * line,char ** tokens,int * ntok)1716abb0f93cSkardel tokenize(
1717abb0f93cSkardel 	const char *line,
1718abb0f93cSkardel 	char **tokens,
1719abb0f93cSkardel 	int *ntok
1720abb0f93cSkardel 	)
1721abb0f93cSkardel {
1722abb0f93cSkardel 	register const char *cp;
1723abb0f93cSkardel 	register char *sp;
1724abb0f93cSkardel 	static char tspace[MAXLINE];
1725abb0f93cSkardel 
1726abb0f93cSkardel 	sp = tspace;
1727abb0f93cSkardel 	cp = line;
1728abb0f93cSkardel 	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1729abb0f93cSkardel 		tokens[*ntok] = sp;
1730abb0f93cSkardel 
1731abb0f93cSkardel 		/* Skip inter-token whitespace */
1732abb0f93cSkardel 		while (ISSPACE(*cp))
1733abb0f93cSkardel 		    cp++;
1734abb0f93cSkardel 
1735abb0f93cSkardel 		/* If we're at EOL we're done */
1736abb0f93cSkardel 		if (ISEOL(*cp))
1737abb0f93cSkardel 		    break;
1738abb0f93cSkardel 
1739abb0f93cSkardel 		/* If this is the 2nd token and the first token begins
1740abb0f93cSkardel 		 * with a ':', then just grab to EOL.
1741abb0f93cSkardel 		 */
1742abb0f93cSkardel 
1743abb0f93cSkardel 		if (*ntok == 1 && tokens[0][0] == ':') {
1744abb0f93cSkardel 			do {
1745ad131110Schristos 				if (sp - tspace >= MAXLINE)
1746ad131110Schristos 					goto toobig;
1747abb0f93cSkardel 				*sp++ = *cp++;
1748abb0f93cSkardel 			} while (!ISEOL(*cp));
1749abb0f93cSkardel 		}
1750abb0f93cSkardel 
1751abb0f93cSkardel 		/* Check if this token begins with a double quote.
1752abb0f93cSkardel 		 * If yes, continue reading till the next double quote
1753abb0f93cSkardel 		 */
1754abb0f93cSkardel 		else if (*cp == '\"') {
1755abb0f93cSkardel 			++cp;
1756abb0f93cSkardel 			do {
1757ad131110Schristos 				if (sp - tspace >= MAXLINE)
1758ad131110Schristos 					goto toobig;
1759abb0f93cSkardel 				*sp++ = *cp++;
1760abb0f93cSkardel 			} while ((*cp != '\"') && !ISEOL(*cp));
1761abb0f93cSkardel 			/* HMS: a missing closing " should be an error */
1762abb0f93cSkardel 		}
1763abb0f93cSkardel 		else {
1764abb0f93cSkardel 			do {
1765ad131110Schristos 				if (sp - tspace >= MAXLINE)
1766ad131110Schristos 					goto toobig;
1767abb0f93cSkardel 				*sp++ = *cp++;
1768abb0f93cSkardel 			} while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1769abb0f93cSkardel 			/* HMS: Why check for a " in the previous line? */
1770abb0f93cSkardel 		}
1771abb0f93cSkardel 
1772ad131110Schristos 		if (sp - tspace >= MAXLINE)
1773ad131110Schristos 			goto toobig;
1774abb0f93cSkardel 		*sp++ = '\0';
1775abb0f93cSkardel 	}
1776ad131110Schristos 	return;
1777ad131110Schristos 
1778ad131110Schristos   toobig:
1779ad131110Schristos 	*ntok = 0;
1780ad131110Schristos 	fprintf(stderr,
1781ad131110Schristos 		"***Line `%s' is too big\n",
1782ad131110Schristos 		line);
1783ad131110Schristos 	return;
1784abb0f93cSkardel }
1785abb0f93cSkardel 
1786abb0f93cSkardel 
1787abb0f93cSkardel /*
1788abb0f93cSkardel  * getarg - interpret an argument token
1789abb0f93cSkardel  */
1790abb0f93cSkardel static int
getarg(const char * str,int code,arg_v * argp)1791abb0f93cSkardel getarg(
1792b3d6264cSchristos 	const char *str,
1793abb0f93cSkardel 	int code,
1794abb0f93cSkardel 	arg_v *argp
1795abb0f93cSkardel 	)
1796abb0f93cSkardel {
1797b3d6264cSchristos 	u_long ul;
1798abb0f93cSkardel 
1799abb0f93cSkardel 	switch (code & ~OPT) {
1800abb0f93cSkardel 	case NTP_STR:
1801abb0f93cSkardel 		argp->string = str;
1802abb0f93cSkardel 		break;
1803b3d6264cSchristos 
1804abb0f93cSkardel 	case NTP_ADD:
1805b3d6264cSchristos 		if (!getnetnum(str, &argp->netnum, NULL, 0))
1806abb0f93cSkardel 			return 0;
1807abb0f93cSkardel 		break;
1808b3d6264cSchristos 
1809abb0f93cSkardel 	case NTP_UINT:
1810b3d6264cSchristos 		if ('&' == str[0]) {
1811b3d6264cSchristos 			if (!atouint(&str[1], &ul)) {
1812b3d6264cSchristos 				fprintf(stderr,
1813b3d6264cSchristos 					"***Association index `%s' invalid/undecodable\n",
1814b3d6264cSchristos 					str);
1815abb0f93cSkardel 				return 0;
1816abb0f93cSkardel 			}
1817b3d6264cSchristos 			if (0 == numassoc) {
1818b3d6264cSchristos 				dogetassoc(stdout);
1819b3d6264cSchristos 				if (0 == numassoc) {
1820b3d6264cSchristos 					fprintf(stderr,
1821b3d6264cSchristos 						"***No associations found, `%s' unknown\n",
1822b3d6264cSchristos 						str);
1823abb0f93cSkardel 					return 0;
1824abb0f93cSkardel 				}
1825abb0f93cSkardel 			}
1826b3d6264cSchristos 			ul = min(ul, numassoc);
1827b3d6264cSchristos 			argp->uval = assoc_cache[ul - 1].assid;
1828abb0f93cSkardel 			break;
1829abb0f93cSkardel 		}
1830b3d6264cSchristos 		if (!atouint(str, &argp->uval)) {
1831b3d6264cSchristos 			fprintf(stderr, "***Illegal unsigned value %s\n",
1832b3d6264cSchristos 				str);
1833abb0f93cSkardel 			return 0;
1834abb0f93cSkardel 		}
1835abb0f93cSkardel 		break;
1836b3d6264cSchristos 
1837b3d6264cSchristos 	case NTP_INT:
1838b3d6264cSchristos 		if (!atoint(str, &argp->ival)) {
1839b3d6264cSchristos 			fprintf(stderr, "***Illegal integer value %s\n",
1840b3d6264cSchristos 				str);
1841b3d6264cSchristos 			return 0;
1842b3d6264cSchristos 		}
1843b3d6264cSchristos 		break;
1844b3d6264cSchristos 
1845abb0f93cSkardel 	case IP_VERSION:
1846b3d6264cSchristos 		if (!strcmp("-6", str)) {
1847abb0f93cSkardel 			argp->ival = 6;
1848b3d6264cSchristos 		} else if (!strcmp("-4", str)) {
1849abb0f93cSkardel 			argp->ival = 4;
1850b3d6264cSchristos 		} else {
1851b3d6264cSchristos 			fprintf(stderr, "***Version must be either 4 or 6\n");
1852abb0f93cSkardel 			return 0;
1853abb0f93cSkardel 		}
1854abb0f93cSkardel 		break;
1855abb0f93cSkardel 	}
1856abb0f93cSkardel 
1857abb0f93cSkardel 	return 1;
1858abb0f93cSkardel }
1859abb0f93cSkardel #endif	/* !BUILD_AS_LIB */
1860abb0f93cSkardel 
1861abb0f93cSkardel 
1862abb0f93cSkardel /*
1863abb0f93cSkardel  * findcmd - find a command in a command description table
1864abb0f93cSkardel  */
1865abb0f93cSkardel static int
findcmd(const char * str,struct xcmd * clist1,struct xcmd * clist2,struct xcmd ** cmd)1866abb0f93cSkardel findcmd(
1867b3d6264cSchristos 	const char *	str,
1868abb0f93cSkardel 	struct xcmd *	clist1,
1869abb0f93cSkardel 	struct xcmd *	clist2,
1870abb0f93cSkardel 	struct xcmd **	cmd
1871abb0f93cSkardel 	)
1872abb0f93cSkardel {
1873b3d6264cSchristos 	struct xcmd *cl;
1874bd25f4c4Schristos 	size_t clen;
1875abb0f93cSkardel 	int nmatch;
1876abb0f93cSkardel 	struct xcmd *nearmatch = NULL;
1877abb0f93cSkardel 	struct xcmd *clist;
1878abb0f93cSkardel 
1879abb0f93cSkardel 	clen = strlen(str);
1880abb0f93cSkardel 	nmatch = 0;
1881abb0f93cSkardel 	if (clist1 != 0)
1882abb0f93cSkardel 	    clist = clist1;
1883abb0f93cSkardel 	else if (clist2 != 0)
1884abb0f93cSkardel 	    clist = clist2;
1885abb0f93cSkardel 	else
1886abb0f93cSkardel 	    return 0;
1887abb0f93cSkardel 
1888abb0f93cSkardel     again:
1889abb0f93cSkardel 	for (cl = clist; cl->keyword != 0; cl++) {
1890abb0f93cSkardel 		/* do a first character check, for efficiency */
1891abb0f93cSkardel 		if (*str != *(cl->keyword))
1892abb0f93cSkardel 		    continue;
1893abb0f93cSkardel 		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1894abb0f93cSkardel 			/*
1895abb0f93cSkardel 			 * Could be extact match, could be approximate.
1896abb0f93cSkardel 			 * Is exact if the length of the keyword is the
1897abb0f93cSkardel 			 * same as the str.
1898abb0f93cSkardel 			 */
1899abb0f93cSkardel 			if (*((cl->keyword) + clen) == '\0') {
1900abb0f93cSkardel 				*cmd = cl;
1901abb0f93cSkardel 				return 1;
1902abb0f93cSkardel 			}
1903abb0f93cSkardel 			nmatch++;
1904abb0f93cSkardel 			nearmatch = cl;
1905abb0f93cSkardel 		}
1906abb0f93cSkardel 	}
1907abb0f93cSkardel 
1908abb0f93cSkardel 	/*
1909abb0f93cSkardel 	 * See if there is more to do.  If so, go again.  Sorry about the
1910abb0f93cSkardel 	 * goto, too much looking at BSD sources...
1911abb0f93cSkardel 	 */
1912abb0f93cSkardel 	if (clist == clist1 && clist2 != 0) {
1913abb0f93cSkardel 		clist = clist2;
1914abb0f93cSkardel 		goto again;
1915abb0f93cSkardel 	}
1916abb0f93cSkardel 
1917abb0f93cSkardel 	/*
1918abb0f93cSkardel 	 * If we got extactly 1 near match, use it, else return number
1919abb0f93cSkardel 	 * of matches.
1920abb0f93cSkardel 	 */
1921abb0f93cSkardel 	if (nmatch == 1) {
1922abb0f93cSkardel 		*cmd = nearmatch;
1923abb0f93cSkardel 		return 1;
1924abb0f93cSkardel 	}
1925abb0f93cSkardel 	return nmatch;
1926abb0f93cSkardel }
1927abb0f93cSkardel 
1928abb0f93cSkardel 
1929abb0f93cSkardel /*
1930abb0f93cSkardel  * getnetnum - given a host name, return its net number
1931abb0f93cSkardel  *	       and (optional) full name
1932abb0f93cSkardel  */
1933abb0f93cSkardel int
getnetnum(const char * hname,sockaddr_u * num,char * fullhost,int af)1934abb0f93cSkardel getnetnum(
1935abb0f93cSkardel 	const char *hname,
1936abb0f93cSkardel 	sockaddr_u *num,
1937abb0f93cSkardel 	char *fullhost,
1938abb0f93cSkardel 	int af
1939abb0f93cSkardel 	)
1940abb0f93cSkardel {
1941abb0f93cSkardel 	struct addrinfo hints, *ai = NULL;
1942abb0f93cSkardel 
194345530cf1Skardel 	ZERO(hints);
1944abb0f93cSkardel 	hints.ai_flags = AI_CANONNAME;
1945abb0f93cSkardel #ifdef AI_ADDRCONFIG
1946abb0f93cSkardel 	hints.ai_flags |= AI_ADDRCONFIG;
1947abb0f93cSkardel #endif
1948abb0f93cSkardel 
194945530cf1Skardel 	/*
195045530cf1Skardel 	 * decodenetnum only works with addresses, but handles syntax
195145530cf1Skardel 	 * that getaddrinfo doesn't:  [2001::1]:1234
195245530cf1Skardel 	 */
1953abb0f93cSkardel 	if (decodenetnum(hname, num)) {
195445530cf1Skardel 		if (fullhost != NULL)
195545530cf1Skardel 			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
195645530cf1Skardel 				    LENHOSTNAME, NULL, 0, 0);
1957abb0f93cSkardel 		return 1;
1958abb0f93cSkardel 	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1959b3d6264cSchristos 		INSIST(sizeof(*num) >= ai->ai_addrlen);
196045530cf1Skardel 		memcpy(num, ai->ai_addr, ai->ai_addrlen);
196145530cf1Skardel 		if (fullhost != NULL) {
1962b3d6264cSchristos 			if (ai->ai_canonname != NULL)
1963b3d6264cSchristos 				strlcpy(fullhost, ai->ai_canonname,
196445530cf1Skardel 					LENHOSTNAME);
1965b3d6264cSchristos 			else
196645530cf1Skardel 				getnameinfo(&num->sa, SOCKLEN(num),
196745530cf1Skardel 					    fullhost, LENHOSTNAME, NULL,
196845530cf1Skardel 					    0, 0);
1969abb0f93cSkardel 		}
1970b3d6264cSchristos 		freeaddrinfo(ai);
197145530cf1Skardel 		return 1;
197245530cf1Skardel 	}
197345530cf1Skardel 	fprintf(stderr, "***Can't find host %s\n", hname);
197445530cf1Skardel 
197545530cf1Skardel 	return 0;
1976abb0f93cSkardel }
1977abb0f93cSkardel 
1978b3d6264cSchristos 
1979abb0f93cSkardel /*
1980abb0f93cSkardel  * nntohost - convert network number to host name.  This routine enforces
1981abb0f93cSkardel  *	       the showhostnames setting.
1982abb0f93cSkardel  */
198345530cf1Skardel const char *
nntohost(sockaddr_u * netnum)1984abb0f93cSkardel nntohost(
1985abb0f93cSkardel 	sockaddr_u *netnum
1986abb0f93cSkardel 	)
1987abb0f93cSkardel {
198845530cf1Skardel 	return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
198945530cf1Skardel }
199045530cf1Skardel 
199145530cf1Skardel 
199245530cf1Skardel /*
199345530cf1Skardel  * nntohost_col - convert network number to host name in fixed width.
199445530cf1Skardel  *		  This routine enforces the showhostnames setting.
199545530cf1Skardel  *		  When displaying hostnames longer than the width,
199645530cf1Skardel  *		  the first part of the hostname is displayed.  When
199745530cf1Skardel  *		  displaying numeric addresses longer than the width,
199845530cf1Skardel  *		  Such as IPv6 addresses, the caller decides whether
199945530cf1Skardel  *		  the first or last of the numeric address is used.
200045530cf1Skardel  */
200145530cf1Skardel const char *
nntohost_col(sockaddr_u * addr,size_t width,int preserve_lowaddrbits)200245530cf1Skardel nntohost_col(
200345530cf1Skardel 	sockaddr_u *	addr,
200445530cf1Skardel 	size_t		width,
200545530cf1Skardel 	int		preserve_lowaddrbits
200645530cf1Skardel 	)
200745530cf1Skardel {
200845530cf1Skardel 	const char *	out;
200945530cf1Skardel 
2010b3d6264cSchristos 	if (!showhostnames || SOCK_UNSPEC(addr)) {
201145530cf1Skardel 		if (preserve_lowaddrbits)
201245530cf1Skardel 			out = trunc_left(stoa(addr), width);
2013abb0f93cSkardel 		else
201445530cf1Skardel 			out = trunc_right(stoa(addr), width);
201545530cf1Skardel 	} else if (ISREFCLOCKADR(addr)) {
201645530cf1Skardel 		out = refnumtoa(addr);
201745530cf1Skardel 	} else {
201845530cf1Skardel 		out = trunc_right(socktohost(addr), width);
201945530cf1Skardel 	}
202045530cf1Skardel 	return out;
2021abb0f93cSkardel }
2022abb0f93cSkardel 
2023abb0f93cSkardel 
2024abb0f93cSkardel /*
2025b3d6264cSchristos  * nntohostp() is the same as nntohost() plus a :port suffix
2026b3d6264cSchristos  */
2027b3d6264cSchristos const char *
nntohostp(sockaddr_u * netnum)2028b3d6264cSchristos nntohostp(
2029b3d6264cSchristos 	sockaddr_u *netnum
2030b3d6264cSchristos 	)
2031b3d6264cSchristos {
2032b3d6264cSchristos 	const char *	hostn;
2033b3d6264cSchristos 	char *		buf;
2034b3d6264cSchristos 
2035b3d6264cSchristos 	if (!showhostnames || SOCK_UNSPEC(netnum))
2036b3d6264cSchristos 		return sptoa(netnum);
2037b3d6264cSchristos 	else if (ISREFCLOCKADR(netnum))
2038b3d6264cSchristos 		return refnumtoa(netnum);
2039b3d6264cSchristos 
2040b3d6264cSchristos 	hostn = socktohost(netnum);
2041b3d6264cSchristos 	LIB_GETBUF(buf);
2042b3d6264cSchristos 	snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
2043b3d6264cSchristos 
2044b3d6264cSchristos 	return buf;
2045b3d6264cSchristos }
2046b3d6264cSchristos 
2047b3d6264cSchristos /*
2048abb0f93cSkardel  * rtdatetolfp - decode an RT-11 date into an l_fp
2049abb0f93cSkardel  */
2050abb0f93cSkardel static int
rtdatetolfp(char * str,l_fp * lfp)2051abb0f93cSkardel rtdatetolfp(
2052abb0f93cSkardel 	char *str,
2053abb0f93cSkardel 	l_fp *lfp
2054abb0f93cSkardel 	)
2055abb0f93cSkardel {
2056abb0f93cSkardel 	register char *cp;
2057abb0f93cSkardel 	register int i;
2058abb0f93cSkardel 	struct calendar cal;
2059abb0f93cSkardel 	char buf[4];
2060abb0f93cSkardel 
2061abb0f93cSkardel 	cal.yearday = 0;
2062abb0f93cSkardel 
2063abb0f93cSkardel 	/*
2064abb0f93cSkardel 	 * An RT-11 date looks like:
2065abb0f93cSkardel 	 *
2066abb0f93cSkardel 	 * d[d]-Mth-y[y] hh:mm:ss
2067abb0f93cSkardel 	 *
2068abb0f93cSkardel 	 * (No docs, but assume 4-digit years are also legal...)
2069abb0f93cSkardel 	 *
2070abb0f93cSkardel 	 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
2071abb0f93cSkardel 	 */
2072abb0f93cSkardel 	cp = str;
2073169394abSchristos 	if (!isdigit(pgetc(cp))) {
2074abb0f93cSkardel 		if (*cp == '-') {
2075abb0f93cSkardel 			/*
2076abb0f93cSkardel 			 * Catch special case
2077abb0f93cSkardel 			 */
2078abb0f93cSkardel 			L_CLR(lfp);
2079abb0f93cSkardel 			return 1;
2080abb0f93cSkardel 		}
2081abb0f93cSkardel 		return 0;
2082abb0f93cSkardel 	}
2083abb0f93cSkardel 
2084abb0f93cSkardel 	cal.monthday = (u_char) (*cp++ - '0');	/* ascii dependent */
2085169394abSchristos 	if (isdigit(pgetc(cp))) {
2086abb0f93cSkardel 		cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
2087abb0f93cSkardel 		cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
2088abb0f93cSkardel 	}
2089abb0f93cSkardel 
2090abb0f93cSkardel 	if (*cp++ != '-')
2091abb0f93cSkardel 	    return 0;
2092abb0f93cSkardel 
2093abb0f93cSkardel 	for (i = 0; i < 3; i++)
2094abb0f93cSkardel 	    buf[i] = *cp++;
2095abb0f93cSkardel 	buf[3] = '\0';
2096abb0f93cSkardel 
2097abb0f93cSkardel 	for (i = 0; i < 12; i++)
2098abb0f93cSkardel 	    if (STREQ(buf, months[i]))
2099abb0f93cSkardel 		break;
2100abb0f93cSkardel 	if (i == 12)
2101abb0f93cSkardel 	    return 0;
2102abb0f93cSkardel 	cal.month = (u_char)(i + 1);
2103abb0f93cSkardel 
2104abb0f93cSkardel 	if (*cp++ != '-')
2105abb0f93cSkardel 	    return 0;
2106abb0f93cSkardel 
2107169394abSchristos 	if (!isdigit(pgetc(cp)))
2108abb0f93cSkardel 	    return 0;
2109abb0f93cSkardel 	cal.year = (u_short)(*cp++ - '0');
2110169394abSchristos 	if (isdigit(pgetc(cp))) {
2111abb0f93cSkardel 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2112abb0f93cSkardel 		cal.year = (u_short)(*cp++ - '0');
2113abb0f93cSkardel 	}
2114169394abSchristos 	if (isdigit(pgetc(cp))) {
2115abb0f93cSkardel 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2116abb0f93cSkardel 		cal.year = (u_short)(cal.year + *cp++ - '0');
2117abb0f93cSkardel 	}
2118169394abSchristos 	if (isdigit(pgetc(cp))) {
2119abb0f93cSkardel 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
2120abb0f93cSkardel 		cal.year = (u_short)(cal.year + *cp++ - '0');
2121abb0f93cSkardel 	}
2122abb0f93cSkardel 
2123abb0f93cSkardel 	/*
2124abb0f93cSkardel 	 * Catch special case.  If cal.year == 0 this is a zero timestamp.
2125abb0f93cSkardel 	 */
2126abb0f93cSkardel 	if (cal.year == 0) {
2127abb0f93cSkardel 		L_CLR(lfp);
2128abb0f93cSkardel 		return 1;
2129abb0f93cSkardel 	}
2130abb0f93cSkardel 
2131169394abSchristos 	if (*cp++ != ' ' || !isdigit(pgetc(cp)))
2132abb0f93cSkardel 	    return 0;
2133abb0f93cSkardel 	cal.hour = (u_char)(*cp++ - '0');
2134169394abSchristos 	if (isdigit(pgetc(cp))) {
2135abb0f93cSkardel 		cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
2136abb0f93cSkardel 		cal.hour = (u_char)(cal.hour + *cp++ - '0');
2137abb0f93cSkardel 	}
2138abb0f93cSkardel 
2139169394abSchristos 	if (*cp++ != ':' || !isdigit(pgetc(cp)))
2140abb0f93cSkardel 	    return 0;
2141abb0f93cSkardel 	cal.minute = (u_char)(*cp++ - '0');
2142169394abSchristos 	if (isdigit(pgetc(cp))) {
2143abb0f93cSkardel 		cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
2144abb0f93cSkardel 		cal.minute = (u_char)(cal.minute + *cp++ - '0');
2145abb0f93cSkardel 	}
2146abb0f93cSkardel 
2147169394abSchristos 	if (*cp++ != ':' || !isdigit(pgetc(cp)))
2148abb0f93cSkardel 	    return 0;
2149abb0f93cSkardel 	cal.second = (u_char)(*cp++ - '0');
2150169394abSchristos 	if (isdigit(pgetc(cp))) {
2151abb0f93cSkardel 		cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
2152abb0f93cSkardel 		cal.second = (u_char)(cal.second + *cp++ - '0');
2153abb0f93cSkardel 	}
2154abb0f93cSkardel 
2155abb0f93cSkardel 	/*
2156abb0f93cSkardel 	 * For RT-11, 1972 seems to be the pivot year
2157abb0f93cSkardel 	 */
2158abb0f93cSkardel 	if (cal.year < 72)
2159abb0f93cSkardel 		cal.year += 2000;
2160abb0f93cSkardel 	if (cal.year < 100)
2161abb0f93cSkardel 		cal.year += 1900;
2162abb0f93cSkardel 
2163abb0f93cSkardel 	lfp->l_ui = caltontp(&cal);
2164abb0f93cSkardel 	lfp->l_uf = 0;
2165abb0f93cSkardel 	return 1;
2166abb0f93cSkardel }
2167abb0f93cSkardel 
2168abb0f93cSkardel 
2169abb0f93cSkardel /*
2170abb0f93cSkardel  * decodets - decode a timestamp into an l_fp format number, with
2171abb0f93cSkardel  *	      consideration of fuzzball formats.
2172abb0f93cSkardel  */
2173abb0f93cSkardel int
decodets(char * str,l_fp * lfp)2174abb0f93cSkardel decodets(
2175abb0f93cSkardel 	char *str,
2176abb0f93cSkardel 	l_fp *lfp
2177abb0f93cSkardel 	)
2178abb0f93cSkardel {
217945530cf1Skardel 	char *cp;
218045530cf1Skardel 	char buf[30];
218145530cf1Skardel 	size_t b;
218245530cf1Skardel 
2183abb0f93cSkardel 	/*
2184abb0f93cSkardel 	 * If it starts with a 0x, decode as hex.
2185abb0f93cSkardel 	 */
2186abb0f93cSkardel 	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2187abb0f93cSkardel 		return hextolfp(str+2, lfp);
2188abb0f93cSkardel 
2189abb0f93cSkardel 	/*
2190abb0f93cSkardel 	 * If it starts with a '"', try it as an RT-11 date.
2191abb0f93cSkardel 	 */
2192abb0f93cSkardel 	if (*str == '"') {
219345530cf1Skardel 		cp = str + 1;
219445530cf1Skardel 		b = 0;
219545530cf1Skardel 		while ('"' != *cp && '\0' != *cp &&
219645530cf1Skardel 		       b < COUNTOF(buf) - 1)
219745530cf1Skardel 			buf[b++] = *cp++;
219845530cf1Skardel 		buf[b] = '\0';
2199abb0f93cSkardel 		return rtdatetolfp(buf, lfp);
2200abb0f93cSkardel 	}
2201abb0f93cSkardel 
2202abb0f93cSkardel 	/*
2203abb0f93cSkardel 	 * Might still be hex.  Check out the first character.  Talk
2204abb0f93cSkardel 	 * about heuristics!
2205abb0f93cSkardel 	 */
2206abb0f93cSkardel 	if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2207abb0f93cSkardel 		return hextolfp(str, lfp);
2208abb0f93cSkardel 
2209abb0f93cSkardel 	/*
2210abb0f93cSkardel 	 * Try it as a decimal.  If this fails, try as an unquoted
2211abb0f93cSkardel 	 * RT-11 date.  This code should go away eventually.
2212abb0f93cSkardel 	 */
2213abb0f93cSkardel 	if (atolfp(str, lfp))
2214abb0f93cSkardel 		return 1;
2215abb0f93cSkardel 
2216abb0f93cSkardel 	return rtdatetolfp(str, lfp);
2217abb0f93cSkardel }
2218abb0f93cSkardel 
2219abb0f93cSkardel 
2220abb0f93cSkardel /*
2221abb0f93cSkardel  * decodetime - decode a time value.  It should be in milliseconds
2222abb0f93cSkardel  */
2223abb0f93cSkardel int
decodetime(char * str,l_fp * lfp)2224abb0f93cSkardel decodetime(
2225abb0f93cSkardel 	char *str,
2226abb0f93cSkardel 	l_fp *lfp
2227abb0f93cSkardel 	)
2228abb0f93cSkardel {
2229abb0f93cSkardel 	return mstolfp(str, lfp);
2230abb0f93cSkardel }
2231abb0f93cSkardel 
2232abb0f93cSkardel 
2233abb0f93cSkardel /*
2234abb0f93cSkardel  * decodeint - decode an integer
2235abb0f93cSkardel  */
2236abb0f93cSkardel int
decodeint(char * str,long * val)2237abb0f93cSkardel decodeint(
2238abb0f93cSkardel 	char *str,
2239abb0f93cSkardel 	long *val
2240abb0f93cSkardel 	)
2241abb0f93cSkardel {
2242abb0f93cSkardel 	if (*str == '0') {
2243abb0f93cSkardel 		if (*(str+1) == 'x' || *(str+1) == 'X')
2244abb0f93cSkardel 		    return hextoint(str+2, (u_long *)val);
2245abb0f93cSkardel 		return octtoint(str, (u_long *)val);
2246abb0f93cSkardel 	}
2247abb0f93cSkardel 	return atoint(str, val);
2248abb0f93cSkardel }
2249abb0f93cSkardel 
2250abb0f93cSkardel 
2251abb0f93cSkardel /*
2252abb0f93cSkardel  * decodeuint - decode an unsigned integer
2253abb0f93cSkardel  */
2254abb0f93cSkardel int
decodeuint(char * str,u_long * val)2255abb0f93cSkardel decodeuint(
2256abb0f93cSkardel 	char *str,
2257abb0f93cSkardel 	u_long *val
2258abb0f93cSkardel 	)
2259abb0f93cSkardel {
2260abb0f93cSkardel 	if (*str == '0') {
2261abb0f93cSkardel 		if (*(str + 1) == 'x' || *(str + 1) == 'X')
2262abb0f93cSkardel 			return (hextoint(str + 2, val));
2263abb0f93cSkardel 		return (octtoint(str, val));
2264abb0f93cSkardel 	}
2265abb0f93cSkardel 	return (atouint(str, val));
2266abb0f93cSkardel }
2267abb0f93cSkardel 
2268abb0f93cSkardel 
2269abb0f93cSkardel /*
2270abb0f93cSkardel  * decodearr - decode an array of time values
2271abb0f93cSkardel  */
2272abb0f93cSkardel static int
decodearr(char * cp,int * narr,l_fp * lfpa,int amax)2273abb0f93cSkardel decodearr(
2274169394abSchristos 	char *cp,
2275abb0f93cSkardel 	int  *narr,
2276169394abSchristos 	l_fp *lfpa,
2277169394abSchristos 	int   amax
2278abb0f93cSkardel 	)
2279abb0f93cSkardel {
2280169394abSchristos 	char *bp;
2281abb0f93cSkardel 	char buf[60];
2282abb0f93cSkardel 
2283abb0f93cSkardel 	*narr = 0;
2284abb0f93cSkardel 
2285169394abSchristos 	while (*narr < amax && *cp) {
2286169394abSchristos 		if (isspace(pgetc(cp))) {
2287169394abSchristos 			do
2288169394abSchristos 				++cp;
2289169394abSchristos 			while (*cp && isspace(pgetc(cp)));
2290169394abSchristos 		} else {
2291abb0f93cSkardel 			bp = buf;
2292169394abSchristos 			do {
2293169394abSchristos 				if (bp != (buf + sizeof(buf) - 1))
2294169394abSchristos 					*bp++ = *cp;
2295169394abSchristos 				++cp;
2296169394abSchristos 			} while (*cp && !isspace(pgetc(cp)));
2297169394abSchristos 			*bp = '\0';
2298abb0f93cSkardel 
2299169394abSchristos 			if (!decodetime(buf, lfpa))
2300abb0f93cSkardel 				return 0;
2301169394abSchristos 			++(*narr);
2302169394abSchristos 			++lfpa;
2303169394abSchristos 		}
2304abb0f93cSkardel 	}
2305abb0f93cSkardel 	return 1;
2306abb0f93cSkardel }
2307abb0f93cSkardel 
2308abb0f93cSkardel 
2309abb0f93cSkardel /*
2310abb0f93cSkardel  * Finally, the built in command handlers
2311abb0f93cSkardel  */
2312abb0f93cSkardel 
2313abb0f93cSkardel /*
2314abb0f93cSkardel  * help - tell about commands, or details of a particular command
2315abb0f93cSkardel  */
2316abb0f93cSkardel static void
help(struct parse * pcmd,FILE * fp)2317abb0f93cSkardel help(
2318abb0f93cSkardel 	struct parse *pcmd,
2319abb0f93cSkardel 	FILE *fp
2320abb0f93cSkardel 	)
2321abb0f93cSkardel {
2322abb0f93cSkardel 	struct xcmd *xcp = NULL;	/* quiet warning */
2323b3d6264cSchristos 	const char *cmd;
2324abb0f93cSkardel 	const char *list[100];
232545530cf1Skardel 	size_t word, words;
232645530cf1Skardel 	size_t row, rows;
232745530cf1Skardel 	size_t col, cols;
232845530cf1Skardel 	size_t length;
2329abb0f93cSkardel 
2330abb0f93cSkardel 	if (pcmd->nargs == 0) {
2331abb0f93cSkardel 		words = 0;
233245530cf1Skardel 		for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2333b3d6264cSchristos 			if (*(xcp->keyword) != '?' &&
2334b3d6264cSchristos 			    words < COUNTOF(list))
2335abb0f93cSkardel 				list[words++] = xcp->keyword;
2336abb0f93cSkardel 		}
233745530cf1Skardel 		for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2338b3d6264cSchristos 			if (words < COUNTOF(list))
2339abb0f93cSkardel 				list[words++] = xcp->keyword;
2340abb0f93cSkardel 
2341b3d6264cSchristos 		qsort((void *)list, words, sizeof(list[0]), helpsort);
2342abb0f93cSkardel 		col = 0;
2343abb0f93cSkardel 		for (word = 0; word < words; word++) {
234445530cf1Skardel 			length = strlen(list[word]);
234545530cf1Skardel 			col = max(col, length);
2346abb0f93cSkardel 		}
2347abb0f93cSkardel 
2348abb0f93cSkardel 		cols = SCREENWIDTH / ++col;
2349abb0f93cSkardel 		rows = (words + cols - 1) / cols;
2350abb0f93cSkardel 
235145530cf1Skardel 		fprintf(fp, "ntpq commands:\n");
2352abb0f93cSkardel 
2353abb0f93cSkardel 		for (row = 0; row < rows; row++) {
235445530cf1Skardel 			for (word = row; word < words; word += rows)
2355b3d6264cSchristos 				fprintf(fp, "%-*.*s", (int)col,
2356b3d6264cSchristos 					(int)col - 1, list[word]);
235745530cf1Skardel 			fprintf(fp, "\n");
2358abb0f93cSkardel 		}
2359abb0f93cSkardel 	} else {
2360abb0f93cSkardel 		cmd = pcmd->argval[0].string;
2361abb0f93cSkardel 		words = findcmd(cmd, builtins, opcmds, &xcp);
2362abb0f93cSkardel 		if (words == 0) {
236345530cf1Skardel 			fprintf(stderr,
2364abb0f93cSkardel 				"Command `%s' is unknown\n", cmd);
2365abb0f93cSkardel 			return;
2366abb0f93cSkardel 		} else if (words >= 2) {
236745530cf1Skardel 			fprintf(stderr,
2368abb0f93cSkardel 				"Command `%s' is ambiguous\n", cmd);
2369abb0f93cSkardel 			return;
2370abb0f93cSkardel 		}
237145530cf1Skardel 		fprintf(fp, "function: %s\n", xcp->comment);
2372abb0f93cSkardel 		printusage(xcp, fp);
2373abb0f93cSkardel 	}
2374abb0f93cSkardel }
2375abb0f93cSkardel 
2376abb0f93cSkardel 
2377abb0f93cSkardel /*
2378abb0f93cSkardel  * helpsort - do hostname qsort comparisons
2379abb0f93cSkardel  */
2380abb0f93cSkardel static int
helpsort(const void * t1,const void * t2)2381abb0f93cSkardel helpsort(
2382abb0f93cSkardel 	const void *t1,
2383abb0f93cSkardel 	const void *t2
2384abb0f93cSkardel 	)
2385abb0f93cSkardel {
238645530cf1Skardel 	const char * const *	name1 = t1;
238745530cf1Skardel 	const char * const *	name2 = t2;
2388abb0f93cSkardel 
2389abb0f93cSkardel 	return strcmp(*name1, *name2);
2390abb0f93cSkardel }
2391abb0f93cSkardel 
2392abb0f93cSkardel 
2393abb0f93cSkardel /*
2394abb0f93cSkardel  * printusage - print usage information for a command
2395abb0f93cSkardel  */
2396abb0f93cSkardel static void
printusage(struct xcmd * xcp,FILE * fp)2397abb0f93cSkardel printusage(
2398abb0f93cSkardel 	struct xcmd *xcp,
2399abb0f93cSkardel 	FILE *fp
2400abb0f93cSkardel 	)
2401abb0f93cSkardel {
2402abb0f93cSkardel 	register int i;
2403abb0f93cSkardel 
2404b3d6264cSchristos 	/* XXX: Do we need to warn about extra args here too? */
2405b3d6264cSchristos 
2406abb0f93cSkardel 	(void) fprintf(fp, "usage: %s", xcp->keyword);
2407abb0f93cSkardel 	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2408abb0f93cSkardel 		if (xcp->arg[i] & OPT)
2409abb0f93cSkardel 		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2410abb0f93cSkardel 		else
2411abb0f93cSkardel 		    (void) fprintf(fp, " %s", xcp->desc[i]);
2412abb0f93cSkardel 	}
2413abb0f93cSkardel 	(void) fprintf(fp, "\n");
2414abb0f93cSkardel }
2415abb0f93cSkardel 
2416abb0f93cSkardel 
2417abb0f93cSkardel /*
2418abb0f93cSkardel  * timeout - set time out time
2419abb0f93cSkardel  */
2420abb0f93cSkardel static void
timeout(struct parse * pcmd,FILE * fp)2421abb0f93cSkardel timeout(
2422abb0f93cSkardel 	struct parse *pcmd,
2423abb0f93cSkardel 	FILE *fp
2424abb0f93cSkardel 	)
2425abb0f93cSkardel {
2426abb0f93cSkardel 	int val;
2427abb0f93cSkardel 
2428abb0f93cSkardel 	if (pcmd->nargs == 0) {
2429abb0f93cSkardel 		val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2430abb0f93cSkardel 		(void) fprintf(fp, "primary timeout %d ms\n", val);
2431abb0f93cSkardel 	} else {
2432abb0f93cSkardel 		tvout.tv_sec = pcmd->argval[0].uval / 1000;
2433abb0f93cSkardel 		tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2434abb0f93cSkardel 			* 1000;
2435abb0f93cSkardel 	}
2436abb0f93cSkardel }
2437abb0f93cSkardel 
2438abb0f93cSkardel 
2439abb0f93cSkardel /*
2440abb0f93cSkardel  * auth_delay - set delay for auth requests
2441abb0f93cSkardel  */
2442abb0f93cSkardel static void
auth_delay(struct parse * pcmd,FILE * fp)2443abb0f93cSkardel auth_delay(
2444abb0f93cSkardel 	struct parse *pcmd,
2445abb0f93cSkardel 	FILE *fp
2446abb0f93cSkardel 	)
2447abb0f93cSkardel {
2448abb0f93cSkardel 	int isneg;
2449abb0f93cSkardel 	u_long val;
2450abb0f93cSkardel 
2451abb0f93cSkardel 	if (pcmd->nargs == 0) {
2452abb0f93cSkardel 		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2453abb0f93cSkardel 		(void) fprintf(fp, "delay %lu ms\n", val);
2454abb0f93cSkardel 	} else {
2455abb0f93cSkardel 		if (pcmd->argval[0].ival < 0) {
2456abb0f93cSkardel 			isneg = 1;
2457abb0f93cSkardel 			val = (u_long)(-pcmd->argval[0].ival);
2458abb0f93cSkardel 		} else {
2459abb0f93cSkardel 			isneg = 0;
2460abb0f93cSkardel 			val = (u_long)pcmd->argval[0].ival;
2461abb0f93cSkardel 		}
2462abb0f93cSkardel 
2463abb0f93cSkardel 		delay_time.l_ui = val / 1000;
2464abb0f93cSkardel 		val %= 1000;
2465abb0f93cSkardel 		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
2466abb0f93cSkardel 
2467abb0f93cSkardel 		if (isneg)
2468abb0f93cSkardel 		    L_NEG(&delay_time);
2469abb0f93cSkardel 	}
2470abb0f93cSkardel }
2471abb0f93cSkardel 
2472abb0f93cSkardel 
2473abb0f93cSkardel /*
2474abb0f93cSkardel  * host - set the host we are dealing with.
2475abb0f93cSkardel  */
2476abb0f93cSkardel static void
host(struct parse * pcmd,FILE * fp)2477abb0f93cSkardel host(
2478abb0f93cSkardel 	struct parse *pcmd,
2479abb0f93cSkardel 	FILE *fp
2480abb0f93cSkardel 	)
2481abb0f93cSkardel {
2482abb0f93cSkardel 	int i;
2483abb0f93cSkardel 
2484abb0f93cSkardel 	if (pcmd->nargs == 0) {
2485abb0f93cSkardel 		if (havehost)
2486abb0f93cSkardel 			(void) fprintf(fp, "current host is %s\n",
2487abb0f93cSkardel 					   currenthost);
2488abb0f93cSkardel 		else
2489abb0f93cSkardel 			(void) fprintf(fp, "no current host\n");
2490abb0f93cSkardel 		return;
2491abb0f93cSkardel 	}
2492abb0f93cSkardel 
2493abb0f93cSkardel 	i = 0;
2494abb0f93cSkardel 	ai_fam_templ = ai_fam_default;
2495abb0f93cSkardel 	if (pcmd->nargs == 2) {
2496abb0f93cSkardel 		if (!strcmp("-4", pcmd->argval[i].string))
2497abb0f93cSkardel 			ai_fam_templ = AF_INET;
2498abb0f93cSkardel 		else if (!strcmp("-6", pcmd->argval[i].string))
2499abb0f93cSkardel 			ai_fam_templ = AF_INET6;
2500abb0f93cSkardel 		else
2501b3d6264cSchristos 			goto no_change;
2502abb0f93cSkardel 		i = 1;
2503abb0f93cSkardel 	}
2504b3d6264cSchristos 	if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
2505b3d6264cSchristos 		fprintf(fp, "current host set to %s\n", currenthost);
2506abb0f93cSkardel 	} else {
2507b3d6264cSchristos     no_change:
2508abb0f93cSkardel 		if (havehost)
2509b3d6264cSchristos 			fprintf(fp, "current host remains %s\n",
2510abb0f93cSkardel 				currenthost);
2511abb0f93cSkardel 		else
2512b3d6264cSchristos 			fprintf(fp, "still no current host\n");
2513abb0f93cSkardel 	}
2514abb0f93cSkardel }
2515abb0f93cSkardel 
2516abb0f93cSkardel 
2517abb0f93cSkardel /*
2518abb0f93cSkardel  * poll - do one (or more) polls of the host via NTP
2519abb0f93cSkardel  */
2520abb0f93cSkardel /*ARGSUSED*/
2521abb0f93cSkardel static void
ntp_poll(struct parse * pcmd,FILE * fp)2522abb0f93cSkardel ntp_poll(
2523abb0f93cSkardel 	struct parse *pcmd,
2524abb0f93cSkardel 	FILE *fp
2525abb0f93cSkardel 	)
2526abb0f93cSkardel {
2527abb0f93cSkardel 	(void) fprintf(fp, "poll not implemented yet\n");
2528abb0f93cSkardel }
2529abb0f93cSkardel 
2530abb0f93cSkardel 
2531abb0f93cSkardel /*
2532335f7552Schristos  * showdrefid2str - return a string explanation of the value of drefid
2533335f7552Schristos  */
2534335f7552Schristos static const char *
showdrefid2str(void)2535335f7552Schristos showdrefid2str(void)
2536335f7552Schristos {
2537335f7552Schristos 	switch (drefid) {
2538335f7552Schristos 	    case REFID_HASH:
2539335f7552Schristos 	    	return "hash";
2540335f7552Schristos 	    case REFID_IPV4:
2541335f7552Schristos 	    	return "ipv4";
2542335f7552Schristos 	    default:
2543335f7552Schristos 	    	return "Unknown";
2544335f7552Schristos 	}
2545335f7552Schristos }
2546335f7552Schristos 
2547335f7552Schristos 
2548335f7552Schristos /*
2549335f7552Schristos  * drefid - display/change "display hash"
2550335f7552Schristos  */
2551335f7552Schristos static void
showdrefid(struct parse * pcmd,FILE * fp)2552335f7552Schristos showdrefid(
2553335f7552Schristos 	struct parse *pcmd,
2554335f7552Schristos 	FILE *fp
2555335f7552Schristos 	)
2556335f7552Schristos {
2557335f7552Schristos 	if (pcmd->nargs == 0) {
2558335f7552Schristos 		(void) fprintf(fp, "drefid value is %s\n", showdrefid2str());
2559335f7552Schristos 		return;
2560335f7552Schristos 	} else if (STREQ(pcmd->argval[0].string, "hash")) {
2561335f7552Schristos 		drefid = REFID_HASH;
2562335f7552Schristos 	} else if (STREQ(pcmd->argval[0].string, "ipv4")) {
2563335f7552Schristos 		drefid = REFID_IPV4;
2564335f7552Schristos 	} else {
2565335f7552Schristos 		(void) fprintf(fp, "What?\n");
2566335f7552Schristos 		return;
2567335f7552Schristos 	}
2568335f7552Schristos 	(void) fprintf(fp, "drefid value set to %s\n", showdrefid2str());
2569335f7552Schristos }
2570335f7552Schristos 
2571335f7552Schristos 
2572335f7552Schristos /*
2573abb0f93cSkardel  * keyid - get a keyid to use for authenticating requests
2574abb0f93cSkardel  */
2575abb0f93cSkardel static void
keyid(struct parse * pcmd,FILE * fp)2576abb0f93cSkardel keyid(
2577abb0f93cSkardel 	struct parse *pcmd,
2578abb0f93cSkardel 	FILE *fp
2579abb0f93cSkardel 	)
2580abb0f93cSkardel {
2581abb0f93cSkardel 	if (pcmd->nargs == 0) {
2582abb0f93cSkardel 		if (info_auth_keyid == 0)
2583abb0f93cSkardel 		    (void) fprintf(fp, "no keyid defined\n");
2584abb0f93cSkardel 		else
2585abb0f93cSkardel 		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2586abb0f93cSkardel 	} else {
2587abb0f93cSkardel 		/* allow zero so that keyid can be cleared. */
2588abb0f93cSkardel 		if(pcmd->argval[0].uval > NTP_MAXKEY)
2589abb0f93cSkardel 		    (void) fprintf(fp, "Invalid key identifier\n");
2590abb0f93cSkardel 		info_auth_keyid = pcmd->argval[0].uval;
2591abb0f93cSkardel 	}
2592abb0f93cSkardel }
2593abb0f93cSkardel 
2594abb0f93cSkardel /*
2595abb0f93cSkardel  * keytype - get type of key to use for authenticating requests
2596abb0f93cSkardel  */
2597abb0f93cSkardel static void
keytype(struct parse * pcmd,FILE * fp)2598abb0f93cSkardel keytype(
2599abb0f93cSkardel 	struct parse *pcmd,
2600abb0f93cSkardel 	FILE *fp
2601abb0f93cSkardel 	)
2602abb0f93cSkardel {
2603abb0f93cSkardel 	const char *	digest_name;
2604abb0f93cSkardel 	size_t		digest_len;
2605abb0f93cSkardel 	int		key_type;
2606abb0f93cSkardel 
2607abb0f93cSkardel 	if (!pcmd->nargs) {
2608c9a8249bSkardel 		fprintf(fp, "keytype is %s with %lu octet digests\n",
2609abb0f93cSkardel 			keytype_name(info_auth_keytype),
261045530cf1Skardel 			(u_long)info_auth_hashlen);
2611abb0f93cSkardel 		return;
2612abb0f93cSkardel 	}
2613abb0f93cSkardel 
2614abb0f93cSkardel 	digest_name = pcmd->argval[0].string;
2615abb0f93cSkardel 	digest_len = 0;
2616abb0f93cSkardel 	key_type = keytype_from_text(digest_name, &digest_len);
2617abb0f93cSkardel 
2618abb0f93cSkardel 	if (!key_type) {
26194e3b3909Schristos 		fprintf(fp, "keytype is not valid. "
2620abb0f93cSkardel #ifdef OPENSSL
26214e3b3909Schristos 			"Type \"help keytype\" for the available digest types.\n");
2622abb0f93cSkardel #else
26234e3b3909Schristos 			"Only \"md5\" is available.\n");
2624abb0f93cSkardel #endif
2625abb0f93cSkardel 		return;
2626abb0f93cSkardel 	}
2627abb0f93cSkardel 
2628abb0f93cSkardel 	info_auth_keytype = key_type;
2629abb0f93cSkardel 	info_auth_hashlen = digest_len;
2630abb0f93cSkardel }
2631abb0f93cSkardel 
2632abb0f93cSkardel 
2633abb0f93cSkardel /*
2634abb0f93cSkardel  * passwd - get an authentication key
2635abb0f93cSkardel  */
2636abb0f93cSkardel /*ARGSUSED*/
2637abb0f93cSkardel static void
passwd(struct parse * pcmd,FILE * fp)2638abb0f93cSkardel passwd(
2639abb0f93cSkardel 	struct parse *pcmd,
2640abb0f93cSkardel 	FILE *fp
2641abb0f93cSkardel 	)
2642abb0f93cSkardel {
2643b3d6264cSchristos 	const char *pass;
2644abb0f93cSkardel 
2645abb0f93cSkardel 	if (info_auth_keyid == 0) {
2646b3d6264cSchristos 		info_auth_keyid = getkeyid("Keyid: ");
2647b3d6264cSchristos 		if (info_auth_keyid == 0) {
2648b3d6264cSchristos 			(void)fprintf(fp, "Keyid must be defined\n");
2649abb0f93cSkardel 			return;
2650abb0f93cSkardel 		}
2651abb0f93cSkardel 	}
265245530cf1Skardel 	if (pcmd->nargs >= 1)
265345530cf1Skardel 		pass = pcmd->argval[0].string;
2654abb0f93cSkardel 	else {
265545530cf1Skardel 		pass = getpass_keytype(info_auth_keytype);
265645530cf1Skardel 		if ('\0' == pass[0]) {
265745530cf1Skardel 			fprintf(fp, "Password unchanged\n");
265845530cf1Skardel 			return;
265945530cf1Skardel 		}
266045530cf1Skardel 	}
2661b3d6264cSchristos 	authusekey(info_auth_keyid, info_auth_keytype,
2662b3d6264cSchristos 		   (const u_char *)pass);
2663abb0f93cSkardel 	authtrust(info_auth_keyid, 1);
2664abb0f93cSkardel }
2665abb0f93cSkardel 
2666abb0f93cSkardel 
2667abb0f93cSkardel /*
2668abb0f93cSkardel  * hostnames - set the showhostnames flag
2669abb0f93cSkardel  */
2670abb0f93cSkardel static void
hostnames(struct parse * pcmd,FILE * fp)2671abb0f93cSkardel hostnames(
2672abb0f93cSkardel 	struct parse *pcmd,
2673abb0f93cSkardel 	FILE *fp
2674abb0f93cSkardel 	)
2675abb0f93cSkardel {
2676abb0f93cSkardel 	if (pcmd->nargs == 0) {
2677abb0f93cSkardel 		if (showhostnames)
2678abb0f93cSkardel 		    (void) fprintf(fp, "hostnames being shown\n");
2679abb0f93cSkardel 		else
2680abb0f93cSkardel 		    (void) fprintf(fp, "hostnames not being shown\n");
2681abb0f93cSkardel 	} else {
2682abb0f93cSkardel 		if (STREQ(pcmd->argval[0].string, "yes"))
2683abb0f93cSkardel 		    showhostnames = 1;
2684abb0f93cSkardel 		else if (STREQ(pcmd->argval[0].string, "no"))
2685abb0f93cSkardel 		    showhostnames = 0;
2686abb0f93cSkardel 		else
2687abb0f93cSkardel 		    (void)fprintf(stderr, "What?\n");
2688abb0f93cSkardel 	}
2689abb0f93cSkardel }
2690abb0f93cSkardel 
2691abb0f93cSkardel 
2692abb0f93cSkardel 
2693abb0f93cSkardel /*
2694abb0f93cSkardel  * setdebug - set/change debugging level
2695abb0f93cSkardel  */
2696abb0f93cSkardel static void
setdebug(struct parse * pcmd,FILE * fp)2697abb0f93cSkardel setdebug(
2698abb0f93cSkardel 	struct parse *pcmd,
2699abb0f93cSkardel 	FILE *fp
2700abb0f93cSkardel 	)
2701abb0f93cSkardel {
2702abb0f93cSkardel 	if (pcmd->nargs == 0) {
2703abb0f93cSkardel 		(void) fprintf(fp, "debug level is %d\n", debug);
2704abb0f93cSkardel 		return;
2705abb0f93cSkardel 	} else if (STREQ(pcmd->argval[0].string, "no")) {
2706abb0f93cSkardel 		debug = 0;
2707abb0f93cSkardel 	} else if (STREQ(pcmd->argval[0].string, "more")) {
2708abb0f93cSkardel 		debug++;
2709abb0f93cSkardel 	} else if (STREQ(pcmd->argval[0].string, "less")) {
2710abb0f93cSkardel 		debug--;
2711abb0f93cSkardel 	} else {
2712abb0f93cSkardel 		(void) fprintf(fp, "What?\n");
2713abb0f93cSkardel 		return;
2714abb0f93cSkardel 	}
2715abb0f93cSkardel 	(void) fprintf(fp, "debug level set to %d\n", debug);
2716abb0f93cSkardel }
2717abb0f93cSkardel 
2718abb0f93cSkardel 
2719abb0f93cSkardel /*
2720abb0f93cSkardel  * quit - stop this nonsense
2721abb0f93cSkardel  */
2722abb0f93cSkardel /*ARGSUSED*/
2723abb0f93cSkardel static void
quit(struct parse * pcmd,FILE * fp)2724abb0f93cSkardel quit(
2725abb0f93cSkardel 	struct parse *pcmd,
2726abb0f93cSkardel 	FILE *fp
2727abb0f93cSkardel 	)
2728abb0f93cSkardel {
2729abb0f93cSkardel 	if (havehost)
2730abb0f93cSkardel 	    closesocket(sockfd);	/* cleanliness next to godliness */
2731abb0f93cSkardel 	exit(0);
2732abb0f93cSkardel }
2733abb0f93cSkardel 
2734abb0f93cSkardel 
2735abb0f93cSkardel /*
2736abb0f93cSkardel  * version - print the current version number
2737abb0f93cSkardel  */
2738abb0f93cSkardel /*ARGSUSED*/
2739abb0f93cSkardel static void
version(struct parse * pcmd,FILE * fp)2740abb0f93cSkardel version(
2741abb0f93cSkardel 	struct parse *pcmd,
2742abb0f93cSkardel 	FILE *fp
2743abb0f93cSkardel 	)
2744abb0f93cSkardel {
2745abb0f93cSkardel 
2746abb0f93cSkardel 	(void) fprintf(fp, "%s\n", Version);
2747abb0f93cSkardel 	return;
2748abb0f93cSkardel }
2749abb0f93cSkardel 
2750abb0f93cSkardel 
2751abb0f93cSkardel /*
2752abb0f93cSkardel  * raw - set raw mode output
2753abb0f93cSkardel  */
2754abb0f93cSkardel /*ARGSUSED*/
2755abb0f93cSkardel static void
raw(struct parse * pcmd,FILE * fp)2756abb0f93cSkardel raw(
2757abb0f93cSkardel 	struct parse *pcmd,
2758abb0f93cSkardel 	FILE *fp
2759abb0f93cSkardel 	)
2760abb0f93cSkardel {
2761abb0f93cSkardel 	rawmode = 1;
2762abb0f93cSkardel 	(void) fprintf(fp, "Output set to raw\n");
2763abb0f93cSkardel }
2764abb0f93cSkardel 
2765abb0f93cSkardel 
2766abb0f93cSkardel /*
2767abb0f93cSkardel  * cooked - set cooked mode output
2768abb0f93cSkardel  */
2769abb0f93cSkardel /*ARGSUSED*/
2770abb0f93cSkardel static void
cooked(struct parse * pcmd,FILE * fp)2771abb0f93cSkardel cooked(
2772abb0f93cSkardel 	struct parse *pcmd,
2773abb0f93cSkardel 	FILE *fp
2774abb0f93cSkardel 	)
2775abb0f93cSkardel {
2776abb0f93cSkardel 	rawmode = 0;
2777abb0f93cSkardel 	(void) fprintf(fp, "Output set to cooked\n");
2778abb0f93cSkardel 	return;
2779abb0f93cSkardel }
2780abb0f93cSkardel 
2781abb0f93cSkardel 
2782abb0f93cSkardel /*
2783abb0f93cSkardel  * authenticate - always authenticate requests to this host
2784abb0f93cSkardel  */
2785abb0f93cSkardel static void
authenticate(struct parse * pcmd,FILE * fp)2786abb0f93cSkardel authenticate(
2787abb0f93cSkardel 	struct parse *pcmd,
2788abb0f93cSkardel 	FILE *fp
2789abb0f93cSkardel 	)
2790abb0f93cSkardel {
2791abb0f93cSkardel 	if (pcmd->nargs == 0) {
2792abb0f93cSkardel 		if (always_auth) {
2793abb0f93cSkardel 			(void) fprintf(fp,
2794abb0f93cSkardel 				       "authenticated requests being sent\n");
2795abb0f93cSkardel 		} else
2796abb0f93cSkardel 		    (void) fprintf(fp,
2797abb0f93cSkardel 				   "unauthenticated requests being sent\n");
2798abb0f93cSkardel 	} else {
2799abb0f93cSkardel 		if (STREQ(pcmd->argval[0].string, "yes")) {
2800abb0f93cSkardel 			always_auth = 1;
2801abb0f93cSkardel 		} else if (STREQ(pcmd->argval[0].string, "no")) {
2802abb0f93cSkardel 			always_auth = 0;
2803abb0f93cSkardel 		} else
2804abb0f93cSkardel 		    (void)fprintf(stderr, "What?\n");
2805abb0f93cSkardel 	}
2806abb0f93cSkardel }
2807abb0f93cSkardel 
2808abb0f93cSkardel 
2809abb0f93cSkardel /*
2810abb0f93cSkardel  * ntpversion - choose the NTP version to use
2811abb0f93cSkardel  */
2812abb0f93cSkardel static void
ntpversion(struct parse * pcmd,FILE * fp)2813abb0f93cSkardel ntpversion(
2814abb0f93cSkardel 	struct parse *pcmd,
2815abb0f93cSkardel 	FILE *fp
2816abb0f93cSkardel 	)
2817abb0f93cSkardel {
2818abb0f93cSkardel 	if (pcmd->nargs == 0) {
2819abb0f93cSkardel 		(void) fprintf(fp,
2820abb0f93cSkardel 			       "NTP version being claimed is %d\n", pktversion);
2821abb0f93cSkardel 	} else {
2822abb0f93cSkardel 		if (pcmd->argval[0].uval < NTP_OLDVERSION
2823abb0f93cSkardel 		    || pcmd->argval[0].uval > NTP_VERSION) {
2824abb0f93cSkardel 			(void) fprintf(stderr, "versions %d to %d, please\n",
2825abb0f93cSkardel 				       NTP_OLDVERSION, NTP_VERSION);
2826abb0f93cSkardel 		} else {
2827abb0f93cSkardel 			pktversion = (u_char) pcmd->argval[0].uval;
2828abb0f93cSkardel 		}
2829abb0f93cSkardel 	}
2830abb0f93cSkardel }
2831abb0f93cSkardel 
2832abb0f93cSkardel 
28339ae3808cSchristos static void __attribute__((__format__(__printf__, 1, 0)))
vwarning(const char * fmt,va_list ap)28349ae3808cSchristos vwarning(const char *fmt, va_list ap)
28359ae3808cSchristos {
28369ae3808cSchristos 	int serrno = errno;
28379ae3808cSchristos 	(void) fprintf(stderr, "%s: ", progname);
28389ae3808cSchristos 	vfprintf(stderr, fmt, ap);
2839bd25f4c4Schristos 	(void) fprintf(stderr, ": %s\n", strerror(serrno));
28409ae3808cSchristos }
28419ae3808cSchristos 
2842abb0f93cSkardel /*
2843abb0f93cSkardel  * warning - print a warning message
2844abb0f93cSkardel  */
28459ae3808cSchristos static void __attribute__((__format__(__printf__, 1, 2)))
warning(const char * fmt,...)2846abb0f93cSkardel warning(
2847abb0f93cSkardel 	const char *fmt,
28489ae3808cSchristos 	...
2849abb0f93cSkardel 	)
2850abb0f93cSkardel {
28519ae3808cSchristos 	va_list ap;
28529ae3808cSchristos 	va_start(ap, fmt);
28539ae3808cSchristos 	vwarning(fmt, ap);
28549ae3808cSchristos 	va_end(ap);
2855abb0f93cSkardel }
2856abb0f93cSkardel 
2857abb0f93cSkardel 
2858abb0f93cSkardel /*
2859abb0f93cSkardel  * error - print a message and exit
2860abb0f93cSkardel  */
28619ae3808cSchristos static void __attribute__((__format__(__printf__, 1, 2)))
error(const char * fmt,...)2862abb0f93cSkardel error(
2863abb0f93cSkardel 	const char *fmt,
28649ae3808cSchristos 	...
2865abb0f93cSkardel 	)
2866abb0f93cSkardel {
28679ae3808cSchristos 	va_list ap;
28689ae3808cSchristos 	va_start(ap, fmt);
28699ae3808cSchristos 	vwarning(fmt, ap);
28709ae3808cSchristos 	va_end(ap);
2871abb0f93cSkardel 	exit(1);
2872abb0f93cSkardel }
2873abb0f93cSkardel /*
2874abb0f93cSkardel  * getkeyid - prompt the user for a keyid to use
2875abb0f93cSkardel  */
2876abb0f93cSkardel static u_long
getkeyid(const char * keyprompt)2877abb0f93cSkardel getkeyid(
2878abb0f93cSkardel 	const char *keyprompt
2879abb0f93cSkardel 	)
2880abb0f93cSkardel {
288145530cf1Skardel 	int c;
2882abb0f93cSkardel 	FILE *fi;
2883abb0f93cSkardel 	char pbuf[20];
288445530cf1Skardel 	size_t i;
288545530cf1Skardel 	size_t ilim;
2886abb0f93cSkardel 
2887abb0f93cSkardel #ifndef SYS_WINNT
2888abb0f93cSkardel 	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2889abb0f93cSkardel #else
2890abb0f93cSkardel 	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2891abb0f93cSkardel #endif /* SYS_WINNT */
2892abb0f93cSkardel 		fi = stdin;
2893abb0f93cSkardel 	else
2894abb0f93cSkardel 		setbuf(fi, (char *)NULL);
2895abb0f93cSkardel 	fprintf(stderr, "%s", keyprompt); fflush(stderr);
289645530cf1Skardel 	for (i = 0, ilim = COUNTOF(pbuf) - 1;
289745530cf1Skardel 	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
289845530cf1Skardel 	     )
289945530cf1Skardel 		pbuf[i++] = (char)c;
290045530cf1Skardel 	pbuf[i] = '\0';
2901abb0f93cSkardel 	if (fi != stdin)
2902abb0f93cSkardel 		fclose(fi);
2903abb0f93cSkardel 
2904abb0f93cSkardel 	return (u_long) atoi(pbuf);
2905abb0f93cSkardel }
2906abb0f93cSkardel 
2907abb0f93cSkardel 
2908abb0f93cSkardel /*
2909abb0f93cSkardel  * atoascii - printable-ize possibly ascii data using the character
2910abb0f93cSkardel  *	      transformations cat -v uses.
2911abb0f93cSkardel  */
2912abb0f93cSkardel static void
atoascii(const char * in,size_t in_octets,char * out,size_t out_octets)2913abb0f93cSkardel atoascii(
2914abb0f93cSkardel 	const char *in,
2915abb0f93cSkardel 	size_t in_octets,
2916abb0f93cSkardel 	char *out,
2917abb0f93cSkardel 	size_t out_octets
2918abb0f93cSkardel 	)
2919abb0f93cSkardel {
2920b3d6264cSchristos 	const u_char *	pchIn;
2921abb0f93cSkardel 	const u_char *	pchInLimit;
2922b3d6264cSchristos 	u_char *	pchOut;
2923b3d6264cSchristos 	u_char		c;
2924abb0f93cSkardel 
2925abb0f93cSkardel 	pchIn = (const u_char *)in;
2926abb0f93cSkardel 	pchInLimit = pchIn + in_octets;
2927abb0f93cSkardel 	pchOut = (u_char *)out;
2928abb0f93cSkardel 
2929abb0f93cSkardel 	if (NULL == pchIn) {
2930abb0f93cSkardel 		if (0 < out_octets)
2931abb0f93cSkardel 			*pchOut = '\0';
2932abb0f93cSkardel 		return;
2933abb0f93cSkardel 	}
2934abb0f93cSkardel 
2935abb0f93cSkardel #define	ONEOUT(c)					\
2936abb0f93cSkardel do {							\
2937abb0f93cSkardel 	if (0 == --out_octets) {			\
2938abb0f93cSkardel 		*pchOut = '\0';				\
2939abb0f93cSkardel 		return;					\
2940abb0f93cSkardel 	}						\
2941abb0f93cSkardel 	*pchOut++ = (c);				\
2942abb0f93cSkardel } while (0)
2943abb0f93cSkardel 
2944abb0f93cSkardel 	for (	; pchIn < pchInLimit; pchIn++) {
2945abb0f93cSkardel 		c = *pchIn;
2946abb0f93cSkardel 		if ('\0' == c)
2947abb0f93cSkardel 			break;
2948abb0f93cSkardel 		if (c & 0x80) {
2949abb0f93cSkardel 			ONEOUT('M');
2950abb0f93cSkardel 			ONEOUT('-');
2951abb0f93cSkardel 			c &= 0x7f;
2952abb0f93cSkardel 		}
2953abb0f93cSkardel 		if (c < ' ') {
2954abb0f93cSkardel 			ONEOUT('^');
2955abb0f93cSkardel 			ONEOUT((u_char)(c + '@'));
2956abb0f93cSkardel 		} else if (0x7f == c) {
2957abb0f93cSkardel 			ONEOUT('^');
2958abb0f93cSkardel 			ONEOUT('?');
2959abb0f93cSkardel 		} else
2960abb0f93cSkardel 			ONEOUT(c);
2961abb0f93cSkardel 	}
2962abb0f93cSkardel 	ONEOUT('\0');
2963abb0f93cSkardel 
2964abb0f93cSkardel #undef ONEOUT
2965abb0f93cSkardel }
2966abb0f93cSkardel 
2967abb0f93cSkardel 
2968abb0f93cSkardel /*
2969abb0f93cSkardel  * makeascii - print possibly ascii data using the character
2970abb0f93cSkardel  *	       transformations that cat -v uses.
2971abb0f93cSkardel  */
297245530cf1Skardel void
makeascii(size_t length,const char * data,FILE * fp)2973abb0f93cSkardel makeascii(
2974bd25f4c4Schristos 	size_t length,
297545530cf1Skardel 	const char *data,
2976abb0f93cSkardel 	FILE *fp
2977abb0f93cSkardel 	)
2978abb0f93cSkardel {
297945530cf1Skardel 	const u_char *data_u_char;
298045530cf1Skardel 	const u_char *cp;
298145530cf1Skardel 	int c;
2982abb0f93cSkardel 
298345530cf1Skardel 	data_u_char = (const u_char *)data;
298445530cf1Skardel 
298545530cf1Skardel 	for (cp = data_u_char; cp < data_u_char + length; cp++) {
2986abb0f93cSkardel 		c = (int)*cp;
2987abb0f93cSkardel 		if (c & 0x80) {
2988abb0f93cSkardel 			putc('M', fp);
2989abb0f93cSkardel 			putc('-', fp);
2990abb0f93cSkardel 			c &= 0x7f;
2991abb0f93cSkardel 		}
2992abb0f93cSkardel 
2993abb0f93cSkardel 		if (c < ' ') {
2994abb0f93cSkardel 			putc('^', fp);
2995abb0f93cSkardel 			putc(c + '@', fp);
2996abb0f93cSkardel 		} else if (0x7f == c) {
2997abb0f93cSkardel 			putc('^', fp);
2998abb0f93cSkardel 			putc('?', fp);
2999abb0f93cSkardel 		} else
3000abb0f93cSkardel 			putc(c, fp);
3001abb0f93cSkardel 	}
3002abb0f93cSkardel }
3003abb0f93cSkardel 
3004abb0f93cSkardel 
3005abb0f93cSkardel /*
3006abb0f93cSkardel  * asciize - same thing as makeascii except add a newline
3007abb0f93cSkardel  */
3008abb0f93cSkardel void
asciize(int length,char * data,FILE * fp)3009abb0f93cSkardel asciize(
3010abb0f93cSkardel 	int length,
3011abb0f93cSkardel 	char *data,
3012abb0f93cSkardel 	FILE *fp
3013abb0f93cSkardel 	)
3014abb0f93cSkardel {
3015abb0f93cSkardel 	makeascii(length, data, fp);
3016abb0f93cSkardel 	putc('\n', fp);
3017abb0f93cSkardel }
3018abb0f93cSkardel 
3019abb0f93cSkardel 
3020abb0f93cSkardel /*
302145530cf1Skardel  * truncate string to fit clipping excess at end.
302245530cf1Skardel  *	"too long"	->	"too l"
302345530cf1Skardel  * Used for hostnames.
302445530cf1Skardel  */
302545530cf1Skardel const char *
trunc_right(const char * src,size_t width)302645530cf1Skardel trunc_right(
302745530cf1Skardel 	const char *	src,
302845530cf1Skardel 	size_t		width
302945530cf1Skardel 	)
303045530cf1Skardel {
303145530cf1Skardel 	size_t	sl;
303245530cf1Skardel 	char *	out;
303345530cf1Skardel 
303445530cf1Skardel 
303545530cf1Skardel 	sl = strlen(src);
303645530cf1Skardel 	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
303745530cf1Skardel 		LIB_GETBUF(out);
303845530cf1Skardel 		memcpy(out, src, width);
303945530cf1Skardel 		out[width] = '\0';
304045530cf1Skardel 
304145530cf1Skardel 		return out;
304245530cf1Skardel 	}
304345530cf1Skardel 
304445530cf1Skardel 	return src;
304545530cf1Skardel }
304645530cf1Skardel 
304745530cf1Skardel 
304845530cf1Skardel /*
304945530cf1Skardel  * truncate string to fit by preserving right side and using '_' to hint
305045530cf1Skardel  *	"too long"	->	"_long"
305145530cf1Skardel  * Used for local IPv6 addresses, where low bits differentiate.
305245530cf1Skardel  */
305345530cf1Skardel const char *
trunc_left(const char * src,size_t width)305445530cf1Skardel trunc_left(
305545530cf1Skardel 	const char *	src,
305645530cf1Skardel 	size_t		width
305745530cf1Skardel 	)
305845530cf1Skardel {
305945530cf1Skardel 	size_t	sl;
306045530cf1Skardel 	char *	out;
306145530cf1Skardel 
306245530cf1Skardel 
306345530cf1Skardel 	sl = strlen(src);
306445530cf1Skardel 	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
306545530cf1Skardel 		LIB_GETBUF(out);
306645530cf1Skardel 		out[0] = '_';
306745530cf1Skardel 		memcpy(&out[1], &src[sl + 1 - width], width);
306845530cf1Skardel 
306945530cf1Skardel 		return out;
307045530cf1Skardel 	}
307145530cf1Skardel 
307245530cf1Skardel 	return src;
307345530cf1Skardel }
307445530cf1Skardel 
307545530cf1Skardel 
307645530cf1Skardel /*
3077abb0f93cSkardel  * Some circular buffer space
3078abb0f93cSkardel  */
3079abb0f93cSkardel #define	CBLEN	80
3080abb0f93cSkardel #define	NUMCB	6
3081abb0f93cSkardel 
3082abb0f93cSkardel char circ_buf[NUMCB][CBLEN];
3083abb0f93cSkardel int nextcb = 0;
3084abb0f93cSkardel 
30859e1d19ccSchristos /* --------------------------------------------------------------------
30869e1d19ccSchristos  * Parsing a response value list
30879e1d19ccSchristos  *
30889e1d19ccSchristos  * This sounds simple (and it actually is not really hard) but it has
30899e1d19ccSchristos  * some pitfalls.
30909e1d19ccSchristos  *
30919e1d19ccSchristos  * Rule1: CR/LF is never embedded in an item
30929e1d19ccSchristos  * Rule2: An item is a name, optionally followed by a value
30939e1d19ccSchristos  * Rule3: The value is separated from the name by a '='
30949e1d19ccSchristos  * Rule4: Items are separated by a ','
30959e1d19ccSchristos  * Rule5: values can be quoted by '"', in which case they can contain
30969e1d19ccSchristos  *        arbitrary characters but *not* '"', CR and LF
30979e1d19ccSchristos  *
30989e1d19ccSchristos  * There are a few implementations out there that require a somewhat
30999e1d19ccSchristos  * relaxed attitude when parsing a value list, especially since we want
31009e1d19ccSchristos  * to copy names and values into local buffers. If these would overflow,
31019e1d19ccSchristos  * the item should be skipped without terminating the parsing sequence.
31029e1d19ccSchristos  *
31039e1d19ccSchristos  * Also, for empty values, there might be a '=' after the name or not;
31049e1d19ccSchristos  * we treat that equivalent.
31059e1d19ccSchristos  *
31069e1d19ccSchristos  * Parsing an item definitely breaks on a CR/LF. If an item is not
31079e1d19ccSchristos  * followed by a comma (','), parsing stops. In the middle of a quoted
31089e1d19ccSchristos  * character sequence CR/LF terminates the parsing finally without
31099e1d19ccSchristos  * returning a value.
31109e1d19ccSchristos  *
31119e1d19ccSchristos  * White space and other noise is ignored when parsing the data buffer;
31129e1d19ccSchristos  * only CR, LF, ',', '=' and '"' are characters with a special meaning.
31139e1d19ccSchristos  * White space is stripped from the names and values *after* working
31149e1d19ccSchristos  * through the buffer, before making the local copies. If whitespace
31159e1d19ccSchristos  * stripping results in an empty name, parsing resumes.
31169e1d19ccSchristos  */
31179e1d19ccSchristos 
31189e1d19ccSchristos /*
31199e1d19ccSchristos  * nextvar parsing helpers
31209e1d19ccSchristos  */
31219e1d19ccSchristos 
31229e1d19ccSchristos /* predicate: allowed chars inside a quoted string */
cp_qschar(int ch)31239e1d19ccSchristos static int/*BOOL*/ cp_qschar(int ch)
31249e1d19ccSchristos {
31259e1d19ccSchristos 	return ch && (ch != '"' && ch != '\r' && ch != '\n');
31269e1d19ccSchristos }
31279e1d19ccSchristos 
31289e1d19ccSchristos /* predicate: allowed chars inside an unquoted string */
cp_uqchar(int ch)31299e1d19ccSchristos static int/*BOOL*/ cp_uqchar(int ch)
31309e1d19ccSchristos {
31319e1d19ccSchristos 	return ch && (ch != ',' && ch != '"' && ch != '\r' && ch != '\n');
31329e1d19ccSchristos }
31339e1d19ccSchristos 
31349e1d19ccSchristos /* predicate: allowed chars inside a value name */
cp_namechar(int ch)31359e1d19ccSchristos static int/*BOOL*/ cp_namechar(int ch)
31369e1d19ccSchristos {
31379e1d19ccSchristos 	return ch && (ch != ',' && ch != '=' && ch != '\r' && ch != '\n');
31389e1d19ccSchristos }
31399e1d19ccSchristos 
31409e1d19ccSchristos /* predicate: characters *between* list items. We're relaxed here. */
cp_ivspace(int ch)31419e1d19ccSchristos static int/*BOOL*/ cp_ivspace(int ch)
31429e1d19ccSchristos {
31439e1d19ccSchristos 	return (ch == ',' || (ch > 0 && ch <= ' '));
31449e1d19ccSchristos }
31459e1d19ccSchristos 
31469e1d19ccSchristos /* get current character (or NUL when on end) */
31479e1d19ccSchristos static inline int
pf_getch(const char ** datap,const char * endp)31489e1d19ccSchristos pf_getch(
31499e1d19ccSchristos 	const char **	datap,
31509e1d19ccSchristos 	const char *	endp
31519e1d19ccSchristos 	)
31529e1d19ccSchristos {
31539e1d19ccSchristos 	return (*datap != endp)
31549e1d19ccSchristos 	    ? *(const unsigned char*)*datap
31559e1d19ccSchristos 	    : '\0';
31569e1d19ccSchristos }
31579e1d19ccSchristos 
31589e1d19ccSchristos /* get next character (or NUL when on end) */
31599e1d19ccSchristos static inline int
pf_nextch(const char ** datap,const char * endp)31609e1d19ccSchristos pf_nextch(
31619e1d19ccSchristos 	const char **	datap,
31629e1d19ccSchristos 	const char *	endp
31639e1d19ccSchristos 	)
31649e1d19ccSchristos {
31659e1d19ccSchristos 	return (*datap != endp && ++(*datap) != endp)
31669e1d19ccSchristos 	    ? *(const unsigned char*)*datap
31679e1d19ccSchristos 	    : '\0';
31689e1d19ccSchristos }
31699e1d19ccSchristos 
31709e1d19ccSchristos static size_t
str_strip(const char ** datap,size_t len)31719e1d19ccSchristos str_strip(
31729e1d19ccSchristos 	const char ** 	datap,
31739e1d19ccSchristos 	size_t		len
31749e1d19ccSchristos 	)
31759e1d19ccSchristos {
31769e1d19ccSchristos 	static const char empty[] = "";
31779e1d19ccSchristos 
31789e1d19ccSchristos 	if (*datap && len) {
31799e1d19ccSchristos 		const char * cpl = *datap;
31809e1d19ccSchristos 		const char * cpr = cpl + len;
31819e1d19ccSchristos 
31829e1d19ccSchristos 		while (cpl != cpr && *(const unsigned char*)cpl <= ' ')
31839e1d19ccSchristos 			++cpl;
31849e1d19ccSchristos 		while (cpl != cpr && *(const unsigned char*)(cpr - 1) <= ' ')
31859e1d19ccSchristos 			--cpr;
31869e1d19ccSchristos 		*datap = cpl;
31879e1d19ccSchristos 		len = (size_t)(cpr - cpl);
31889e1d19ccSchristos 	} else {
31899e1d19ccSchristos 		*datap = empty;
31909e1d19ccSchristos 		len = 0;
31919e1d19ccSchristos 	}
31929e1d19ccSchristos 	return len;
31939e1d19ccSchristos }
31949e1d19ccSchristos 
31959e1d19ccSchristos static void
pf_error(const char * what,const char * where,const char * whend)31969e1d19ccSchristos pf_error(
31979e1d19ccSchristos 	const char *	what,
31989e1d19ccSchristos 	const char *	where,
31999e1d19ccSchristos 	const char *	whend
32009e1d19ccSchristos 	)
32019e1d19ccSchristos {
32029e1d19ccSchristos #   ifndef BUILD_AS_LIB
32039e1d19ccSchristos 
32049e1d19ccSchristos 	FILE *	ofp = (debug > 0) ? stdout : stderr;
32059e1d19ccSchristos 	size_t	len = (size_t)(whend - where);
32069e1d19ccSchristos 
32079e1d19ccSchristos 	if (len > 50) /* *must* fit into an 'int'! */
32089e1d19ccSchristos 		len = 50;
32099e1d19ccSchristos 	fprintf(ofp, "nextvar: %s: '%.*s'\n",
32109e1d19ccSchristos 		what, (int)len, where);
32119e1d19ccSchristos 
32129e1d19ccSchristos #   else  /*defined(BUILD_AS_LIB)*/
32139e1d19ccSchristos 
32149e1d19ccSchristos 	UNUSED_ARG(what);
32159e1d19ccSchristos 	UNUSED_ARG(where);
32169e1d19ccSchristos 	UNUSED_ARG(whend);
32179e1d19ccSchristos 
32189e1d19ccSchristos #   endif /*defined(BUILD_AS_LIB)*/
32199e1d19ccSchristos }
32209e1d19ccSchristos 
3221abb0f93cSkardel /*
3222abb0f93cSkardel  * nextvar - find the next variable in the buffer
3223abb0f93cSkardel  */
32249e1d19ccSchristos int/*BOOL*/
nextvar(size_t * datalen,const char ** datap,char ** vname,char ** vvalue)3225abb0f93cSkardel nextvar(
3226bd25f4c4Schristos 	size_t *datalen,
322745530cf1Skardel 	const char **datap,
3228abb0f93cSkardel 	char **vname,
3229abb0f93cSkardel 	char **vvalue
3230abb0f93cSkardel 	)
3231abb0f93cSkardel {
32329e1d19ccSchristos 	enum PState 	{ sDone, sInit, sName, sValU, sValQ };
3233abb0f93cSkardel 
32349e1d19ccSchristos 	static char	name[MAXVARLEN], value[MAXVALLEN];
3235abb0f93cSkardel 
32369e1d19ccSchristos 	const char	*cp, *cpend;
32379e1d19ccSchristos 	const char	*np, *vp;
32389e1d19ccSchristos 	size_t		nlen, vlen;
32399e1d19ccSchristos 	int		ch;
32409e1d19ccSchristos 	enum PState	st;
3241abb0f93cSkardel 
32429e1d19ccSchristos 	cpend = *datap + *datalen;
3243abb0f93cSkardel 
32449e1d19ccSchristos   again:
32459e1d19ccSchristos 	np   = vp   = NULL;
32469e1d19ccSchristos 	nlen = vlen = 0;
3247abb0f93cSkardel 
32489e1d19ccSchristos 	st = sInit;
32499e1d19ccSchristos 	ch = pf_getch(datap, cpend);
32509e1d19ccSchristos 
32519e1d19ccSchristos 	while (st != sDone) {
32529e1d19ccSchristos 		switch (st)
32539e1d19ccSchristos 		{
32549e1d19ccSchristos 		case sInit:	/* handle inter-item chars */
32559e1d19ccSchristos 			while (cp_ivspace(ch))
32569e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
32579e1d19ccSchristos 			if (cp_namechar(ch)) {
32589e1d19ccSchristos 				np = *datap;
32599e1d19ccSchristos 				cp = np;
32609e1d19ccSchristos 				st = sName;
32619e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
3262b3d6264cSchristos 			} else {
32639e1d19ccSchristos 				goto final_done;
3264abb0f93cSkardel 			}
32659e1d19ccSchristos 			break;
3266abb0f93cSkardel 
32679e1d19ccSchristos 		case sName:	/* collect name */
32689e1d19ccSchristos 			while (cp_namechar(ch))
32699e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
32709e1d19ccSchristos 			nlen = (size_t)(*datap - np);
32719e1d19ccSchristos 			if (ch == '=') {
32729e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
32739e1d19ccSchristos 				vp = *datap;
32749e1d19ccSchristos 				st = sValU;
32759e1d19ccSchristos 			} else {
32769e1d19ccSchristos 				if (ch != ',')
32779e1d19ccSchristos 					*datap = cpend;
32789e1d19ccSchristos 				st = sDone;
32799e1d19ccSchristos 			}
32809e1d19ccSchristos 			break;
32819e1d19ccSchristos 
32829e1d19ccSchristos 		case sValU:	/* collect unquoted part(s) of value */
32839e1d19ccSchristos 			while (cp_uqchar(ch))
32849e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
32859e1d19ccSchristos 			if (ch == '"') {
32869e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
32879e1d19ccSchristos 				st = sValQ;
32889e1d19ccSchristos 			} else {
32899e1d19ccSchristos 				vlen = (size_t)(*datap - vp);
32909e1d19ccSchristos 				if (ch != ',')
32919e1d19ccSchristos 					*datap = cpend;
32929e1d19ccSchristos 				st = sDone;
32939e1d19ccSchristos 			}
32949e1d19ccSchristos 			break;
32959e1d19ccSchristos 
32969e1d19ccSchristos 		case sValQ:	/* collect quoted part(s) of value */
32979e1d19ccSchristos 			while (cp_qschar(ch))
32989e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
32999e1d19ccSchristos 			if (ch == '"') {
33009e1d19ccSchristos 				ch = pf_nextch(datap, cpend);
33019e1d19ccSchristos 				st = sValU;
33029e1d19ccSchristos 			} else {
33039e1d19ccSchristos 				pf_error("no closing quote, stop", cp, cpend);
33049e1d19ccSchristos 				goto final_done;
33059e1d19ccSchristos 			}
33069e1d19ccSchristos 			break;
33079e1d19ccSchristos 
33089e1d19ccSchristos 		default:
33099e1d19ccSchristos 			pf_error("state machine error, stop", *datap, cpend);
33109e1d19ccSchristos 			goto final_done;
33119e1d19ccSchristos 		}
33129e1d19ccSchristos 	}
33139e1d19ccSchristos 
33149e1d19ccSchristos 	/* If name or value do not fit their buffer, croak and start
33159e1d19ccSchristos 	 * over. If there's no name at all after whitespace stripping,
33169e1d19ccSchristos 	 * redo silently.
3317abb0f93cSkardel 	 */
33189e1d19ccSchristos 	nlen = str_strip(&np, nlen);
33199e1d19ccSchristos 	vlen = str_strip(&vp, vlen);
33209e1d19ccSchristos 
33219e1d19ccSchristos 	if (nlen == 0) {
33229e1d19ccSchristos 		goto again;
33239e1d19ccSchristos 	}
33249e1d19ccSchristos 	if (nlen >= sizeof(name)) {
33259e1d19ccSchristos 		pf_error("runaway name", np, cpend);
33269e1d19ccSchristos 		goto again;
33279e1d19ccSchristos 	}
33289e1d19ccSchristos 	if (vlen >= sizeof(value)) {
33299e1d19ccSchristos 		pf_error("runaway value", vp, cpend);
33309e1d19ccSchristos 		goto again;
33319e1d19ccSchristos 	}
33329e1d19ccSchristos 
33339e1d19ccSchristos 	/* copy name and value into NUL-terminated buffers */
33349e1d19ccSchristos 	memcpy(name, np, nlen);
33359e1d19ccSchristos 	name[nlen] = '\0';
33369e1d19ccSchristos 	*vname = name;
33379e1d19ccSchristos 
33389e1d19ccSchristos 	memcpy(value, vp, vlen);
33399e1d19ccSchristos 	value[vlen] = '\0';
3340abb0f93cSkardel 	*vvalue = value;
33419e1d19ccSchristos 
33429e1d19ccSchristos 	/* check if there's more to do or if we are finshed */
33439e1d19ccSchristos 	*datalen = (size_t)(cpend - *datap);
33449e1d19ccSchristos 	return TRUE;
33459e1d19ccSchristos 
33469e1d19ccSchristos   final_done:
33479e1d19ccSchristos 	*datap = cpend;
33489e1d19ccSchristos 	*datalen = 0;
33499e1d19ccSchristos 	return FALSE;
3350abb0f93cSkardel }
3351abb0f93cSkardel 
3352abb0f93cSkardel 
3353b3d6264cSchristos u_short
varfmt(const char * varname)3354b3d6264cSchristos varfmt(const char * varname)
3355abb0f93cSkardel {
3356b3d6264cSchristos 	u_int n;
3357abb0f93cSkardel 
3358b3d6264cSchristos 	for (n = 0; n < COUNTOF(cookedvars); n++)
3359b3d6264cSchristos 		if (!strcmp(varname, cookedvars[n].varname))
3360b3d6264cSchristos 			return cookedvars[n].fmt;
3361abb0f93cSkardel 
3362b3d6264cSchristos 	return PADDING;
3363b3d6264cSchristos }
3364abb0f93cSkardel 
3365abb0f93cSkardel 
3366abb0f93cSkardel /*
3367abb0f93cSkardel  * printvars - print variables returned in response packet
3368abb0f93cSkardel  */
3369abb0f93cSkardel void
printvars(size_t length,const char * data,int status,int sttype,int quiet,FILE * fp)3370abb0f93cSkardel printvars(
3371bd25f4c4Schristos 	size_t length,
337245530cf1Skardel 	const char *data,
3373abb0f93cSkardel 	int status,
3374abb0f93cSkardel 	int sttype,
3375abb0f93cSkardel 	int quiet,
3376abb0f93cSkardel 	FILE *fp
3377abb0f93cSkardel 	)
3378abb0f93cSkardel {
3379abb0f93cSkardel 	if (rawmode)
3380abb0f93cSkardel 	    rawprint(sttype, length, data, status, quiet, fp);
3381abb0f93cSkardel 	else
3382abb0f93cSkardel 	    cookedprint(sttype, length, data, status, quiet, fp);
3383abb0f93cSkardel }
3384abb0f93cSkardel 
3385abb0f93cSkardel 
3386abb0f93cSkardel /*
3387abb0f93cSkardel  * rawprint - do a printout of the data in raw mode
3388abb0f93cSkardel  */
3389abb0f93cSkardel static void
rawprint(int datatype,size_t length,const char * data,int status,int quiet,FILE * fp)3390abb0f93cSkardel rawprint(
3391abb0f93cSkardel 	int datatype,
3392bd25f4c4Schristos 	size_t length,
339345530cf1Skardel 	const char *data,
3394abb0f93cSkardel 	int status,
3395abb0f93cSkardel 	int quiet,
3396abb0f93cSkardel 	FILE *fp
3397abb0f93cSkardel 	)
3398abb0f93cSkardel {
339945530cf1Skardel 	const char *cp;
340045530cf1Skardel 	const char *cpend;
3401abb0f93cSkardel 
3402abb0f93cSkardel 	/*
3403abb0f93cSkardel 	 * Essentially print the data as is.  We reformat unprintables, though.
3404abb0f93cSkardel 	 */
3405abb0f93cSkardel 	cp = data;
3406abb0f93cSkardel 	cpend = data + length;
3407abb0f93cSkardel 
3408abb0f93cSkardel 	if (!quiet)
3409abb0f93cSkardel 		(void) fprintf(fp, "status=0x%04x,\n", status);
3410abb0f93cSkardel 
3411abb0f93cSkardel 	while (cp < cpend) {
3412abb0f93cSkardel 		if (*cp == '\r') {
3413abb0f93cSkardel 			/*
3414abb0f93cSkardel 			 * If this is a \r and the next character is a
3415abb0f93cSkardel 			 * \n, supress this, else pretty print it.  Otherwise
3416abb0f93cSkardel 			 * just output the character.
3417abb0f93cSkardel 			 */
3418abb0f93cSkardel 			if (cp == (cpend - 1) || *(cp + 1) != '\n')
3419abb0f93cSkardel 			    makeascii(1, cp, fp);
3420169394abSchristos 		} else if (isspace(pgetc(cp)) || isprint(pgetc(cp)))
3421abb0f93cSkardel 			putc(*cp, fp);
3422abb0f93cSkardel 		else
3423abb0f93cSkardel 			makeascii(1, cp, fp);
3424abb0f93cSkardel 		cp++;
3425abb0f93cSkardel 	}
3426abb0f93cSkardel }
3427abb0f93cSkardel 
3428abb0f93cSkardel 
3429abb0f93cSkardel /*
3430abb0f93cSkardel  * Global data used by the cooked output routines
3431abb0f93cSkardel  */
3432abb0f93cSkardel int out_chars;		/* number of characters output */
3433abb0f93cSkardel int out_linecount;	/* number of characters output on this line */
3434abb0f93cSkardel 
3435abb0f93cSkardel 
3436abb0f93cSkardel /*
3437abb0f93cSkardel  * startoutput - get ready to do cooked output
3438abb0f93cSkardel  */
3439abb0f93cSkardel static void
startoutput(void)3440abb0f93cSkardel startoutput(void)
3441abb0f93cSkardel {
3442abb0f93cSkardel 	out_chars = 0;
3443abb0f93cSkardel 	out_linecount = 0;
3444abb0f93cSkardel }
3445abb0f93cSkardel 
3446abb0f93cSkardel 
3447abb0f93cSkardel /*
3448abb0f93cSkardel  * output - output a variable=value combination
3449abb0f93cSkardel  */
3450abb0f93cSkardel static void
output(FILE * fp,const char * name,const char * value)3451abb0f93cSkardel output(
3452abb0f93cSkardel 	FILE *fp,
3453b3d6264cSchristos 	const char *name,
345445530cf1Skardel 	const char *value
3455abb0f93cSkardel 	)
3456abb0f93cSkardel {
3457bd25f4c4Schristos 	int len;
3458abb0f93cSkardel 
3459abb0f93cSkardel 	/* strlen of "name=value" */
3460bd25f4c4Schristos 	len = size2int_sat(strlen(name) + 1 + strlen(value));
3461abb0f93cSkardel 
3462abb0f93cSkardel 	if (out_chars != 0) {
3463abb0f93cSkardel 		out_chars += 2;
3464abb0f93cSkardel 		if ((out_linecount + len + 2) > MAXOUTLINE) {
3465abb0f93cSkardel 			fputs(",\n", fp);
3466abb0f93cSkardel 			out_linecount = 0;
3467abb0f93cSkardel 		} else {
3468abb0f93cSkardel 			fputs(", ", fp);
3469abb0f93cSkardel 			out_linecount += 2;
3470abb0f93cSkardel 		}
3471abb0f93cSkardel 	}
3472abb0f93cSkardel 
3473abb0f93cSkardel 	fputs(name, fp);
3474abb0f93cSkardel 	putc('=', fp);
3475abb0f93cSkardel 	fputs(value, fp);
3476abb0f93cSkardel 	out_chars += len;
3477abb0f93cSkardel 	out_linecount += len;
3478abb0f93cSkardel }
3479abb0f93cSkardel 
3480abb0f93cSkardel 
3481abb0f93cSkardel /*
3482abb0f93cSkardel  * endoutput - terminate a block of cooked output
3483abb0f93cSkardel  */
3484abb0f93cSkardel static void
endoutput(FILE * fp)3485abb0f93cSkardel endoutput(
3486abb0f93cSkardel 	FILE *fp
3487abb0f93cSkardel 	)
3488abb0f93cSkardel {
3489abb0f93cSkardel 	if (out_chars != 0)
3490abb0f93cSkardel 		putc('\n', fp);
3491abb0f93cSkardel }
3492abb0f93cSkardel 
3493abb0f93cSkardel 
3494abb0f93cSkardel /*
3495abb0f93cSkardel  * outputarr - output an array of values
3496abb0f93cSkardel  */
3497abb0f93cSkardel static void
outputarr(FILE * fp,char * name,int narr,l_fp * lfp,int issigned)3498abb0f93cSkardel outputarr(
3499abb0f93cSkardel 	FILE *fp,
3500abb0f93cSkardel 	char *name,
3501abb0f93cSkardel 	int narr,
35029034ec65Schristos 	l_fp *lfp,
35039034ec65Schristos 	int issigned
3504abb0f93cSkardel 	)
3505abb0f93cSkardel {
3506bd25f4c4Schristos 	char *bp;
3507bd25f4c4Schristos 	char *cp;
3508bd25f4c4Schristos 	size_t i;
3509bd25f4c4Schristos 	size_t len;
3510abb0f93cSkardel 	char buf[256];
3511abb0f93cSkardel 
3512abb0f93cSkardel 	bp = buf;
3513abb0f93cSkardel 	/*
3514abb0f93cSkardel 	 * Hack to align delay and offset values
3515abb0f93cSkardel 	 */
3516abb0f93cSkardel 	for (i = (int)strlen(name); i < 11; i++)
3517abb0f93cSkardel 		*bp++ = ' ';
3518abb0f93cSkardel 
3519abb0f93cSkardel 	for (i = narr; i > 0; i--) {
3520bd25f4c4Schristos 		if (i != (size_t)narr)
3521abb0f93cSkardel 			*bp++ = ' ';
35229034ec65Schristos 		cp = (issigned ? lfptoms(lfp, 2) : ulfptoms(lfp, 2));
3523abb0f93cSkardel 		len = strlen(cp);
3524abb0f93cSkardel 		if (len > 7) {
3525abb0f93cSkardel 			cp[7] = '\0';
3526abb0f93cSkardel 			len = 7;
3527abb0f93cSkardel 		}
3528abb0f93cSkardel 		while (len < 7) {
3529abb0f93cSkardel 			*bp++ = ' ';
3530abb0f93cSkardel 			len++;
3531abb0f93cSkardel 		}
3532abb0f93cSkardel 		while (*cp != '\0')
3533abb0f93cSkardel 		    *bp++ = *cp++;
3534abb0f93cSkardel 		lfp++;
3535abb0f93cSkardel 	}
3536abb0f93cSkardel 	*bp = '\0';
3537abb0f93cSkardel 	output(fp, name, buf);
3538abb0f93cSkardel }
3539abb0f93cSkardel 
3540abb0f93cSkardel static char *
tstflags(u_long val)3541abb0f93cSkardel tstflags(
3542abb0f93cSkardel 	u_long val
3543abb0f93cSkardel 	)
3544abb0f93cSkardel {
35459e1d19ccSchristos #	if CBLEN < 10
35469e1d19ccSchristos #	 error BLEN is too small -- increase!
35479e1d19ccSchristos #	endif
3548abb0f93cSkardel 
35499e1d19ccSchristos 	char *cp, *s;
35509e1d19ccSchristos 	size_t cb, i;
35519e1d19ccSchristos 	int l;
35529e1d19ccSchristos 
355345530cf1Skardel 	s = cp = circ_buf[nextcb];
3554abb0f93cSkardel 	if (++nextcb >= NUMCB)
3555abb0f93cSkardel 		nextcb = 0;
355645530cf1Skardel 	cb = sizeof(circ_buf[0]);
3557abb0f93cSkardel 
35589e1d19ccSchristos 	l = snprintf(cp, cb, "%02lx", val);
35599e1d19ccSchristos 	if (l < 0 || (size_t)l >= cb)
35609e1d19ccSchristos 		goto fail;
35619e1d19ccSchristos 	cp += l;
35629e1d19ccSchristos 	cb -= l;
3563abb0f93cSkardel 	if (!val) {
35649e1d19ccSchristos 		l = strlcat(cp, " ok", cb);
35659e1d19ccSchristos 		if ((size_t)l >= cb)
35669e1d19ccSchristos 			goto fail;
35679e1d19ccSchristos 		cp += l;
35689e1d19ccSchristos 		cb -= l;
3569abb0f93cSkardel 	} else {
35709e1d19ccSchristos 		const char *sep;
35719e1d19ccSchristos 
35729e1d19ccSchristos 		sep = " ";
35739e1d19ccSchristos 		for (i = 0; i < COUNTOF(tstflagnames); i++) {
3574abb0f93cSkardel 			if (val & 0x1) {
35759e1d19ccSchristos 				l = snprintf(cp, cb, "%s%s", sep,
357645530cf1Skardel 					     tstflagnames[i]);
35779e1d19ccSchristos 				if (l < 0)
35789e1d19ccSchristos 					goto fail;
35799e1d19ccSchristos 				if ((size_t)l >= cb) {
35809e1d19ccSchristos 					cp += cb - 4;
35819e1d19ccSchristos 					cb = 4;
35829e1d19ccSchristos 					l = strlcpy (cp, "...", cb);
35839e1d19ccSchristos 					cp += l;
35849e1d19ccSchristos 					cb -= l;
35859e1d19ccSchristos 					break;
35869e1d19ccSchristos 				}
3587abb0f93cSkardel 				sep = ", ";
35889e1d19ccSchristos 				cp += l;
35899e1d19ccSchristos 				cb -= l;
3590abb0f93cSkardel 			}
3591abb0f93cSkardel 			val >>= 1;
3592abb0f93cSkardel 		}
3593abb0f93cSkardel 	}
359445530cf1Skardel 
3595abb0f93cSkardel 	return s;
35969e1d19ccSchristos 
35979e1d19ccSchristos   fail:
35989e1d19ccSchristos 	*cp = '\0';
35999e1d19ccSchristos 	return s;
3600abb0f93cSkardel }
3601abb0f93cSkardel 
3602abb0f93cSkardel /*
3603abb0f93cSkardel  * cookedprint - output variables in cooked mode
3604abb0f93cSkardel  */
3605abb0f93cSkardel static void
cookedprint(int datatype,size_t length,const char * data,int status,int quiet,FILE * fp)3606abb0f93cSkardel cookedprint(
3607abb0f93cSkardel 	int datatype,
3608bd25f4c4Schristos 	size_t length,
360945530cf1Skardel 	const char *data,
3610abb0f93cSkardel 	int status,
3611abb0f93cSkardel 	int quiet,
3612abb0f93cSkardel 	FILE *fp
3613abb0f93cSkardel 	)
3614abb0f93cSkardel {
3615abb0f93cSkardel 	char *name;
3616abb0f93cSkardel 	char *value;
3617abb0f93cSkardel 	char output_raw;
3618abb0f93cSkardel 	int fmt;
3619abb0f93cSkardel 	l_fp lfp;
3620abb0f93cSkardel 	sockaddr_u hval;
3621abb0f93cSkardel 	u_long uval;
3622abb0f93cSkardel 	int narr;
3623b3d6264cSchristos 	size_t len;
3624b3d6264cSchristos 	l_fp lfparr[8];
3625b3d6264cSchristos 	char b[12];
3626b3d6264cSchristos 	char bn[2 * MAXVARLEN];
3627b3d6264cSchristos 	char bv[2 * MAXVALLEN];
3628abb0f93cSkardel 
3629b3d6264cSchristos 	UNUSED_ARG(datatype);
3630abb0f93cSkardel 
3631abb0f93cSkardel 	if (!quiet)
3632abb0f93cSkardel 		fprintf(fp, "status=%04x %s,\n", status,
3633abb0f93cSkardel 			statustoa(datatype, status));
3634abb0f93cSkardel 
3635abb0f93cSkardel 	startoutput();
3636abb0f93cSkardel 	while (nextvar(&length, &data, &name, &value)) {
3637b3d6264cSchristos 		fmt = varfmt(name);
3638abb0f93cSkardel 		output_raw = 0;
3639abb0f93cSkardel 		switch (fmt) {
3640b3d6264cSchristos 
3641b3d6264cSchristos 		case PADDING:
3642b3d6264cSchristos 			output_raw = '*';
3643b3d6264cSchristos 			break;
3644b3d6264cSchristos 
3645abb0f93cSkardel 		case TS:
3646169394abSchristos 			if (!value || !decodets(value, &lfp))
3647abb0f93cSkardel 				output_raw = '?';
3648abb0f93cSkardel 			else
3649abb0f93cSkardel 				output(fp, name, prettydate(&lfp));
3650abb0f93cSkardel 			break;
3651abb0f93cSkardel 
3652b3d6264cSchristos 		case HA:	/* fallthru */
3653abb0f93cSkardel 		case NA:
3654169394abSchristos 			if (!value || !decodenetnum(value, &hval)) {
3655abb0f93cSkardel 				output_raw = '?';
3656b3d6264cSchristos 			} else if (fmt == HA){
3657abb0f93cSkardel 				output(fp, name, nntohost(&hval));
3658abb0f93cSkardel 			} else {
3659abb0f93cSkardel 				output(fp, name, stoa(&hval));
3660abb0f93cSkardel 			}
3661abb0f93cSkardel 			break;
3662abb0f93cSkardel 
3663abb0f93cSkardel 		case RF:
3664169394abSchristos 			if (!value) {
3665169394abSchristos 				output_raw = '?';
3666169394abSchristos 			} else if (decodenetnum(value, &hval)) {
36679034ec65Schristos 				if (datatype == TYPE_CLOCK && IS_IPV4(&hval)) {
36689034ec65Schristos 					/*
36699034ec65Schristos 					 * Workaround to override numeric refid formats
36709034ec65Schristos 					 * for refclocks received from faulty nptd servers
36719034ec65Schristos 					 * and output them as text.
36729034ec65Schristos 					 */
36739034ec65Schristos 					int i;
36749034ec65Schristos 					unsigned char *str = (unsigned char *)&(hval.sa4).sin_addr;
36759034ec65Schristos 					char refid_buf[5];
36769034ec65Schristos 					for (i=0; i<4 && str[i]; i++)
36779034ec65Schristos 						refid_buf[i] = (isprint(str[i]) ? str[i] : '?');
36789034ec65Schristos 					refid_buf[i] = 0; /* Null terminator */
36799034ec65Schristos 					output(fp, name, refid_buf);
36809034ec65Schristos 				} else if (ISREFCLOCKADR(&hval)) {
36819034ec65Schristos 					output(fp, name, refnumtoa(&hval));
36829034ec65Schristos 				} else {
36839034ec65Schristos 					if (drefid == REFID_IPV4) {
3684abb0f93cSkardel 						output(fp, name, stoa(&hval));
36859034ec65Schristos 					} else {
36869034ec65Schristos 						char refid_buf[12];
36879034ec65Schristos 						snprintf (refid_buf, sizeof(refid_buf),
36889034ec65Schristos 							  "0x%08x", ntohl(addr2refid(&hval)));
36899034ec65Schristos 						output(fp, name, refid_buf);
36909034ec65Schristos 					}
36919034ec65Schristos 				}
3692b3d6264cSchristos 			} else if (strlen(value) <= 4) {
3693abb0f93cSkardel 				output(fp, name, value);
3694b3d6264cSchristos 			} else {
3695abb0f93cSkardel 				output_raw = '?';
3696b3d6264cSchristos 			}
3697abb0f93cSkardel 			break;
3698abb0f93cSkardel 
3699abb0f93cSkardel 		case LP:
3700169394abSchristos 			if (!value || !decodeuint(value, &uval) || uval > 3) {
3701abb0f93cSkardel 				output_raw = '?';
3702b3d6264cSchristos 			} else {
3703b3d6264cSchristos 				b[0] = (0x2 & uval)
3704b3d6264cSchristos 					   ? '1'
3705b3d6264cSchristos 					   : '0';
3706b3d6264cSchristos 				b[1] = (0x1 & uval)
3707b3d6264cSchristos 					   ? '1'
3708b3d6264cSchristos 					   : '0';
3709abb0f93cSkardel 				b[2] = '\0';
3710abb0f93cSkardel 				output(fp, name, b);
3711abb0f93cSkardel 			}
3712abb0f93cSkardel 			break;
3713abb0f93cSkardel 
3714abb0f93cSkardel 		case OC:
3715169394abSchristos 			if (!value || !decodeuint(value, &uval)) {
3716abb0f93cSkardel 				output_raw = '?';
3717b3d6264cSchristos 			} else {
3718b3d6264cSchristos 				snprintf(b, sizeof(b), "%03lo", uval);
3719abb0f93cSkardel 				output(fp, name, b);
3720abb0f93cSkardel 			}
3721abb0f93cSkardel 			break;
3722abb0f93cSkardel 
37239034ec65Schristos 		case AU:
37249034ec65Schristos 		case AS:
3725169394abSchristos 			if (!value || !decodearr(value, &narr, lfparr, 8))
3726abb0f93cSkardel 				output_raw = '?';
3727abb0f93cSkardel 			else
37289034ec65Schristos 				outputarr(fp, name, narr, lfparr, (fmt==AS));
3729abb0f93cSkardel 			break;
3730abb0f93cSkardel 
3731abb0f93cSkardel 		case FX:
3732169394abSchristos 			if (!value || !decodeuint(value, &uval))
3733abb0f93cSkardel 				output_raw = '?';
3734abb0f93cSkardel 			else
3735abb0f93cSkardel 				output(fp, name, tstflags(uval));
3736abb0f93cSkardel 			break;
3737abb0f93cSkardel 
37389034ec65Schristos 		case SN:
37399034ec65Schristos 			if (!value)
37409034ec65Schristos 				output_raw = '?';
3741*f7d97a96Schristos 			else if (isdigit(*(const unsigned char *)value)) {	/* number without sign */
37429034ec65Schristos 				bv[0] = '+';
37439034ec65Schristos 				atoascii (value, MAXVALLEN, bv+1, sizeof(bv)-1);
37449034ec65Schristos 				output(fp, name, bv);
37459034ec65Schristos 			} else
37469034ec65Schristos 				output_raw = '*';		/* output as-is */
37479034ec65Schristos 			break;
37489034ec65Schristos 
3749abb0f93cSkardel 		default:
3750b3d6264cSchristos 			fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
3751abb0f93cSkardel 				name, value, fmt);
3752b3d6264cSchristos 			output_raw = '?';
3753abb0f93cSkardel 			break;
3754abb0f93cSkardel 		}
3755abb0f93cSkardel 
3756abb0f93cSkardel 		if (output_raw != 0) {
375709f14f80Schristos 			/* TALOS-CAN-0063: avoid buffer overrun */
3758abb0f93cSkardel 			atoascii(name, MAXVARLEN, bn, sizeof(bn));
3759abb0f93cSkardel 			if (output_raw != '*') {
376009f14f80Schristos 				atoascii(value, MAXVALLEN,
376109f14f80Schristos 					 bv, sizeof(bv) - 1);
3762abb0f93cSkardel 				len = strlen(bv);
3763abb0f93cSkardel 				bv[len] = output_raw;
3764abb0f93cSkardel 				bv[len+1] = '\0';
376509f14f80Schristos 			} else {
376609f14f80Schristos 				atoascii(value, MAXVALLEN,
376709f14f80Schristos 					 bv, sizeof(bv));
3768abb0f93cSkardel 			}
3769abb0f93cSkardel 			output(fp, bn, bv);
3770abb0f93cSkardel 		}
3771abb0f93cSkardel 	}
3772abb0f93cSkardel 	endoutput(fp);
3773abb0f93cSkardel }
3774abb0f93cSkardel 
3775abb0f93cSkardel 
3776abb0f93cSkardel /*
3777abb0f93cSkardel  * sortassoc - sort associations in the cache into ascending order
3778abb0f93cSkardel  */
3779abb0f93cSkardel void
sortassoc(void)3780abb0f93cSkardel sortassoc(void)
3781abb0f93cSkardel {
3782abb0f93cSkardel 	if (numassoc > 1)
3783b3d6264cSchristos 		qsort(assoc_cache, (size_t)numassoc,
3784b3d6264cSchristos 		      sizeof(assoc_cache[0]), &assoccmp);
3785abb0f93cSkardel }
3786abb0f93cSkardel 
3787abb0f93cSkardel 
3788abb0f93cSkardel /*
3789abb0f93cSkardel  * assoccmp - compare two associations
3790abb0f93cSkardel  */
3791abb0f93cSkardel static int
assoccmp(const void * t1,const void * t2)3792abb0f93cSkardel assoccmp(
3793abb0f93cSkardel 	const void *t1,
3794abb0f93cSkardel 	const void *t2
3795abb0f93cSkardel 	)
3796abb0f93cSkardel {
379745530cf1Skardel 	const struct association *ass1 = t1;
379845530cf1Skardel 	const struct association *ass2 = t2;
3799abb0f93cSkardel 
3800abb0f93cSkardel 	if (ass1->assid < ass2->assid)
3801abb0f93cSkardel 		return -1;
3802abb0f93cSkardel 	if (ass1->assid > ass2->assid)
3803abb0f93cSkardel 		return 1;
3804abb0f93cSkardel 	return 0;
3805abb0f93cSkardel }
380645530cf1Skardel 
3807abb0f93cSkardel 
3808abb0f93cSkardel /*
3809b3d6264cSchristos  * grow_assoc_cache() - enlarge dynamic assoc_cache array
3810b3d6264cSchristos  *
3811b3d6264cSchristos  * The strategy is to add an assumed 4k page size at a time, leaving
3812b3d6264cSchristos  * room for malloc() bookkeeping overhead equivalent to 4 pointers.
3813b3d6264cSchristos  */
3814b3d6264cSchristos void
grow_assoc_cache(void)3815b3d6264cSchristos grow_assoc_cache(void)
3816b3d6264cSchristos {
3817b3d6264cSchristos 	static size_t	prior_sz;
3818b3d6264cSchristos 	size_t		new_sz;
3819b3d6264cSchristos 
3820b3d6264cSchristos 	new_sz = prior_sz + 4 * 1024;
3821b3d6264cSchristos 	if (0 == prior_sz) {
3822b3d6264cSchristos 		new_sz -= 4 * sizeof(void *);
3823b3d6264cSchristos 	}
3824b3d6264cSchristos 	assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
3825b3d6264cSchristos 	prior_sz = new_sz;
3826bd25f4c4Schristos 	assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0]));
3827b3d6264cSchristos }
3828b3d6264cSchristos 
3829b3d6264cSchristos 
3830b3d6264cSchristos /*
3831abb0f93cSkardel  * ntpq_custom_opt_handler - autoopts handler for -c and -p
3832abb0f93cSkardel  *
3833abb0f93cSkardel  * By default, autoopts loses the relative order of -c and -p options
3834abb0f93cSkardel  * on the command line.  This routine replaces the default handler for
3835abb0f93cSkardel  * those routines and builds a list of commands to execute preserving
3836abb0f93cSkardel  * the order.
3837abb0f93cSkardel  */
3838abb0f93cSkardel void
ntpq_custom_opt_handler(tOptions * pOptions,tOptDesc * pOptDesc)3839abb0f93cSkardel ntpq_custom_opt_handler(
3840abb0f93cSkardel 	tOptions *pOptions,
3841abb0f93cSkardel 	tOptDesc *pOptDesc
3842abb0f93cSkardel 	)
3843abb0f93cSkardel {
3844abb0f93cSkardel 	switch (pOptDesc->optValue) {
3845abb0f93cSkardel 
3846abb0f93cSkardel 	default:
3847abb0f93cSkardel 		fprintf(stderr,
3848abb0f93cSkardel 			"ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3849abb0f93cSkardel 			pOptDesc->optValue, pOptDesc->optValue);
3850b3d6264cSchristos 		exit(1);
3851abb0f93cSkardel 
3852abb0f93cSkardel 	case 'c':
3853abb0f93cSkardel 		ADDCMD(pOptDesc->pzLastArg);
3854abb0f93cSkardel 		break;
3855abb0f93cSkardel 
3856abb0f93cSkardel 	case 'p':
3857abb0f93cSkardel 		ADDCMD("peers");
3858abb0f93cSkardel 		break;
3859abb0f93cSkardel 	}
3860abb0f93cSkardel }
38614e3b3909Schristos /*
38624e3b3909Schristos  * Obtain list of digest names
38634e3b3909Schristos  */
38644e3b3909Schristos 
3865169394abSchristos #if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED)
3866169394abSchristos # if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
3867169394abSchristos #  define HAVE_EVP_MD_DO_ALL_SORTED
3868169394abSchristos # endif
3869169394abSchristos #endif
3870169394abSchristos 
38714e3b3909Schristos #ifdef OPENSSL
38724e3b3909Schristos # ifdef HAVE_EVP_MD_DO_ALL_SORTED
3873169394abSchristos #  define K_PER_LINE	8
3874169394abSchristos #  define K_NL_PFX_STR	"\n    "
3875169394abSchristos #  define K_DELIM_STR	", "
3876169394abSchristos 
38774e3b3909Schristos struct hstate {
38784e3b3909Schristos 	char *list;
38794e3b3909Schristos 	const char **seen;
38804e3b3909Schristos 	int idx;
38814e3b3909Schristos };
3882169394abSchristos 
3883169394abSchristos 
38849e1d19ccSchristos #  ifndef BUILD_AS_LIB
3885169394abSchristos static void
list_md_fn(const EVP_MD * m,const char * from,const char * to,void * arg)3886169394abSchristos list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg)
38874e3b3909Schristos {
38884e3b3909Schristos 	size_t 	       len, n;
3889169394abSchristos 	const char    *name, **seen;
38904e3b3909Schristos 	struct hstate *hstate = arg;
3891169394abSchristos 	const char    *cp;
38924e3b3909Schristos 
3893169394abSchristos 	/* m is MD obj, from is name or alias, to is base name for alias */
38949e1d19ccSchristos 	if (!m || !from || to)
38954e3b3909Schristos 		return; /* Ignore aliases */
3896169394abSchristos 
3897169394abSchristos 	/* Discard MACs that NTP won't accept. */
3898169394abSchristos 	/* Keep this consistent with keytype_from_text() in ssl_init.c. */
38999e1d19ccSchristos 	if (EVP_MD_size(m) > (int)(MAX_MAC_LEN - sizeof(keyid_t)))
3900169394abSchristos 		return;
39014e3b3909Schristos 
39024e3b3909Schristos 	name = EVP_MD_name(m);
39034e3b3909Schristos 
39044e3b3909Schristos 	/* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
39054e3b3909Schristos 
39069e1d19ccSchristos 	for (cp = name; *cp; cp++)
39079e1d19ccSchristos 		if (islower((unsigned char)*cp))
39084e3b3909Schristos 			return;
3909169394abSchristos 
39104e3b3909Schristos 	len = (cp - name) + 1;
39114e3b3909Schristos 
39124e3b3909Schristos 	/* There are duplicates.  Discard if name has been seen. */
39134e3b3909Schristos 
39149e1d19ccSchristos 	for (seen = hstate->seen; *seen; seen++)
39159e1d19ccSchristos 		if (!strcmp(*seen, name))
39164e3b3909Schristos 			return;
3917169394abSchristos 
39184e3b3909Schristos 	n = (seen - hstate->seen) + 2;
391909f14f80Schristos 	hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
39204e3b3909Schristos 	hstate->seen[n-2] = name;
39214e3b3909Schristos 	hstate->seen[n-1] = NULL;
39224e3b3909Schristos 
39239e1d19ccSchristos 	if (hstate->list != NULL)
39244e3b3909Schristos 		len += strlen(hstate->list);
3925169394abSchristos 
3926169394abSchristos 	len += (hstate->idx >= K_PER_LINE)
3927169394abSchristos 	    ? strlen(K_NL_PFX_STR)
3928169394abSchristos 	    : strlen(K_DELIM_STR);
39294e3b3909Schristos 
39304e3b3909Schristos 	if (hstate->list == NULL) {
393109f14f80Schristos 		hstate->list = (char *)emalloc(len);
39324e3b3909Schristos 		hstate->list[0] = '\0';
3933169394abSchristos 	} else {
393409f14f80Schristos 		hstate->list = (char *)erealloc(hstate->list, len);
3935169394abSchristos 	}
39364e3b3909Schristos 
39374e3b3909Schristos 	sprintf(hstate->list + strlen(hstate->list), "%s%s",
39384e3b3909Schristos 		((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR),
39394e3b3909Schristos 		name);
3940169394abSchristos 
39419e1d19ccSchristos 	if (hstate->idx >= K_PER_LINE)
39424e3b3909Schristos 		hstate->idx = 1;
39439e1d19ccSchristos 	else
39444e3b3909Schristos 		hstate->idx++;
39454e3b3909Schristos }
39469e1d19ccSchristos #  endif /* !defined(BUILD_AS_LIB) */
3947169394abSchristos 
39489e1d19ccSchristos #  ifndef BUILD_AS_LIB
3949169394abSchristos /* Insert CMAC into SSL digests list */
3950169394abSchristos static char *
insert_cmac(char * list)3951169394abSchristos insert_cmac(char *list)
3952169394abSchristos {
39539e1d19ccSchristos #ifdef ENABLE_CMAC
3954169394abSchristos 	int insert;
3955169394abSchristos 	size_t len;
3956169394abSchristos 
3957169394abSchristos 
3958169394abSchristos 	/* If list empty, we need to insert CMAC on new line */
3959169394abSchristos 	insert = (!list || !*list);
3960169394abSchristos 
3961169394abSchristos 	if (insert) {
3962169394abSchristos 		len = strlen(K_NL_PFX_STR) + strlen(CMAC);
3963169394abSchristos 		list = (char *)erealloc(list, len + 1);
3964169394abSchristos 		sprintf(list, "%s%s", K_NL_PFX_STR, CMAC);
3965169394abSchristos 	} else {	/* List not empty */
3966169394abSchristos 		/* Check if CMAC already in list - future proofing */
3967169394abSchristos 		const char *cmac_sn;
3968169394abSchristos 		char *cmac_p;
3969169394abSchristos 
3970169394abSchristos 		cmac_sn = OBJ_nid2sn(NID_cmac);
3971169394abSchristos 		cmac_p = list;
3972169394abSchristos 		insert = cmac_sn != NULL && *cmac_sn != '\0';
3973169394abSchristos 
3974169394abSchristos 		/* CMAC in list if found, followed by nul char or ',' */
3975169394abSchristos 		while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) {
3976169394abSchristos 			cmac_p += strlen(cmac_sn);
3977169394abSchristos 			/* Still need to insert if not nul and not ',' */
3978169394abSchristos 			insert = *cmac_p && ',' != *cmac_p;
3979169394abSchristos 		}
3980169394abSchristos 
3981169394abSchristos 		/* Find proper insertion point */
3982169394abSchristos 		if (insert) {
3983169394abSchristos 			char *last_nl;
3984169394abSchristos 			char *point;
3985169394abSchristos 			char *delim;
3986169394abSchristos 			int found;
3987169394abSchristos 
3988169394abSchristos 			/* Default to start if list empty */
3989169394abSchristos 			found = 0;
3990169394abSchristos 			delim = list;
3991169394abSchristos 			len = strlen(list);
3992169394abSchristos 
3993169394abSchristos 			/* While new lines */
3994169394abSchristos 			while (delim < list + len && *delim &&
3995169394abSchristos 			       !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) {
3996169394abSchristos 				point = delim + strlen(K_NL_PFX_STR);
3997169394abSchristos 
3998169394abSchristos 				/* While digest names on line */
3999169394abSchristos 				while (point < list + len && *point) {
4000169394abSchristos 					/* Another digest after on same or next line? */
4001169394abSchristos 					delim = strstr( point, K_DELIM_STR);
4002169394abSchristos 					last_nl = strstr( point, K_NL_PFX_STR);
4003169394abSchristos 
4004169394abSchristos 					/* No - end of list */
4005169394abSchristos 					if (!delim && !last_nl) {
4006169394abSchristos 						delim = list + len;
4007169394abSchristos 					} else
4008169394abSchristos 						/* New line and no delim or before delim? */
4009169394abSchristos 						if (last_nl && (!delim || last_nl < delim)) {
4010169394abSchristos 							delim = last_nl;
4011169394abSchristos 						}
4012169394abSchristos 
4013169394abSchristos 					/* Found insertion point where CMAC before entry? */
4014169394abSchristos 					if (strncmp(CMAC, point, delim - point) < 0) {
4015169394abSchristos 						found = 1;
4016169394abSchristos 						break;
4017169394abSchristos 					}
4018169394abSchristos 
4019169394abSchristos 					if (delim < list + len && *delim &&
4020169394abSchristos 					    !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) {
4021169394abSchristos 						point += strlen(K_DELIM_STR);
4022169394abSchristos 					} else {
4023169394abSchristos 						break;
4024169394abSchristos 					}
4025169394abSchristos 				} /* While digest names on line */
4026169394abSchristos 			} /* While new lines */
4027169394abSchristos 
4028169394abSchristos 			/* If found in list */
4029169394abSchristos 			if (found) {
4030169394abSchristos 				/* insert cmac and delim */
4031169394abSchristos 				/* Space for list could move - save offset */
4032169394abSchristos 				ptrdiff_t p_offset = point - list;
4033169394abSchristos 				len += strlen(CMAC) + strlen(K_DELIM_STR);
4034169394abSchristos 				list = (char *)erealloc(list, len + 1);
4035169394abSchristos 				point = list + p_offset;
4036169394abSchristos 				/* move to handle src/dest overlap */
4037169394abSchristos 				memmove(point + strlen(CMAC) + strlen(K_DELIM_STR),
4038169394abSchristos 					point, strlen(point) + 1);
4039169394abSchristos 				strncpy(point, CMAC, strlen(CMAC));
4040169394abSchristos 				strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR));
4041169394abSchristos 			} else {	/* End of list */
4042169394abSchristos 				/* append delim and cmac */
4043169394abSchristos 				len += strlen(K_DELIM_STR) + strlen(CMAC);
4044169394abSchristos 				list = (char *)erealloc(list, len + 1);
4045169394abSchristos 				strcpy(list + strlen(list), K_DELIM_STR);
4046169394abSchristos 				strcpy(list + strlen(list), CMAC);
4047169394abSchristos 			}
4048169394abSchristos 		} /* insert */
4049169394abSchristos 	} /* List not empty */
40509e1d19ccSchristos #endif /*ENABLE_CMAC*/
4051169394abSchristos 	return list;
4052169394abSchristos }
40539e1d19ccSchristos #  endif /* !defined(BUILD_AS_LIB) */
40544e3b3909Schristos # endif
40554e3b3909Schristos #endif
40564e3b3909Schristos 
4057169394abSchristos 
40589e1d19ccSchristos #ifndef BUILD_AS_LIB
4059169394abSchristos static char *
list_digest_names(void)4060169394abSchristos list_digest_names(void)
40614e3b3909Schristos {
40624e3b3909Schristos 	char *list = NULL;
40634e3b3909Schristos 
40644e3b3909Schristos #ifdef OPENSSL
40654e3b3909Schristos # ifdef HAVE_EVP_MD_DO_ALL_SORTED
40664e3b3909Schristos 	struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
40674e3b3909Schristos 
4068169394abSchristos 	/* replace calloc(1, sizeof(const char *)) */
4069169394abSchristos 	hstate.seen = (const char **)emalloc_zero(sizeof(const char *));
40704e3b3909Schristos 
40714e3b3909Schristos 	INIT_SSL();
40724e3b3909Schristos 	EVP_MD_do_all_sorted(list_md_fn, &hstate);
40734e3b3909Schristos 	list = hstate.list;
40744e3b3909Schristos 	free(hstate.seen);
4075169394abSchristos 
4076169394abSchristos 	list = insert_cmac(list);	/* Insert CMAC into SSL digests list */
4077169394abSchristos 
40784e3b3909Schristos # else
407909f14f80Schristos 	list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
40804e3b3909Schristos 	strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
40814e3b3909Schristos # endif
40824e3b3909Schristos #else
408309f14f80Schristos 	list = (char *)emalloc(sizeof("md5"));
40844e3b3909Schristos 	strcpy(list, "md5");
40854e3b3909Schristos #endif
40864e3b3909Schristos 
40874e3b3909Schristos 	return list;
40884e3b3909Schristos }
40899e1d19ccSchristos #endif /* !defined(BUILD_AS_LIB) */
4090bd25f4c4Schristos 
4091bd25f4c4Schristos #define CTRLC_STACK_MAX 4
4092bd25f4c4Schristos static volatile size_t		ctrlc_stack_len = 0;
4093bd25f4c4Schristos static volatile Ctrl_C_Handler	ctrlc_stack[CTRLC_STACK_MAX];
4094bd25f4c4Schristos 
4095bd25f4c4Schristos 
4096bd25f4c4Schristos 
4097bd25f4c4Schristos int/*BOOL*/
push_ctrl_c_handler(Ctrl_C_Handler func)4098bd25f4c4Schristos push_ctrl_c_handler(
4099bd25f4c4Schristos 	Ctrl_C_Handler func
4100bd25f4c4Schristos 	)
4101bd25f4c4Schristos {
4102bd25f4c4Schristos 	size_t size = ctrlc_stack_len;
4103bd25f4c4Schristos 	if (func && (size < CTRLC_STACK_MAX)) {
4104bd25f4c4Schristos 		ctrlc_stack[size] = func;
4105bd25f4c4Schristos 		ctrlc_stack_len = size + 1;
4106bd25f4c4Schristos 		return TRUE;
4107bd25f4c4Schristos 	}
4108bd25f4c4Schristos 	return FALSE;
4109bd25f4c4Schristos }
4110bd25f4c4Schristos 
4111bd25f4c4Schristos int/*BOOL*/
pop_ctrl_c_handler(Ctrl_C_Handler func)4112bd25f4c4Schristos pop_ctrl_c_handler(
4113bd25f4c4Schristos 	Ctrl_C_Handler func
4114bd25f4c4Schristos 	)
4115bd25f4c4Schristos {
4116bd25f4c4Schristos 	size_t size = ctrlc_stack_len;
4117bd25f4c4Schristos 	if (size) {
4118bd25f4c4Schristos 		--size;
4119bd25f4c4Schristos 		if (func == NULL || func == ctrlc_stack[size]) {
4120bd25f4c4Schristos 			ctrlc_stack_len = size;
4121bd25f4c4Schristos 			return TRUE;
4122bd25f4c4Schristos 		}
4123bd25f4c4Schristos 	}
4124bd25f4c4Schristos 	return FALSE;
4125bd25f4c4Schristos }
4126bd25f4c4Schristos 
41279e1d19ccSchristos #ifndef BUILD_AS_LIB
4128bd25f4c4Schristos static void
on_ctrlc(void)4129bd25f4c4Schristos on_ctrlc(void)
4130bd25f4c4Schristos {
4131bd25f4c4Schristos 	size_t size = ctrlc_stack_len;
4132bd25f4c4Schristos 	while (size)
4133bd25f4c4Schristos 		if ((*ctrlc_stack[--size])())
4134bd25f4c4Schristos 			break;
4135bd25f4c4Schristos }
41369e1d19ccSchristos #endif /* !defined(BUILD_AS_LIB) */
4137335f7552Schristos 
41389e1d19ccSchristos #ifndef BUILD_AS_LIB
4139335f7552Schristos static int
my_easprintf(char ** ppinto,const char * fmt,...)4140335f7552Schristos my_easprintf(
4141335f7552Schristos 	char ** 	ppinto,
4142335f7552Schristos 	const char *	fmt   ,
4143335f7552Schristos 	...
4144335f7552Schristos 	)
4145335f7552Schristos {
4146335f7552Schristos 	va_list	va;
4147335f7552Schristos 	int	prc;
4148335f7552Schristos 	size_t	len = 128;
4149335f7552Schristos 	char *	buf = emalloc(len);
4150335f7552Schristos 
4151335f7552Schristos   again:
4152335f7552Schristos 	/* Note: we expect the memory allocation to fail long before the
4153335f7552Schristos 	 * increment in buffer size actually overflows.
4154335f7552Schristos 	 */
4155335f7552Schristos 	buf = (buf) ? erealloc(buf, len) : emalloc(len);
4156335f7552Schristos 
4157335f7552Schristos 	va_start(va, fmt);
4158335f7552Schristos 	prc = vsnprintf(buf, len, fmt, va);
4159335f7552Schristos 	va_end(va);
4160335f7552Schristos 
4161335f7552Schristos 	if (prc < 0) {
4162335f7552Schristos 		/* might be very old vsnprintf. Or actually MSVC... */
4163335f7552Schristos 		len += len >> 1;
4164335f7552Schristos 		goto again;
4165335f7552Schristos 	}
4166335f7552Schristos 	if ((size_t)prc >= len) {
4167335f7552Schristos 		/* at least we have the proper size now... */
4168335f7552Schristos 		len = (size_t)prc + 1;
4169335f7552Schristos 		goto again;
4170335f7552Schristos 	}
4171335f7552Schristos 	if ((size_t)prc < (len - 32))
4172335f7552Schristos 		buf = erealloc(buf, (size_t)prc + 1);
4173335f7552Schristos 	*ppinto = buf;
4174335f7552Schristos 	return prc;
4175335f7552Schristos }
41769e1d19ccSchristos #endif /* !defined(BUILD_AS_LIB) */
4177