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