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