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