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