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