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