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