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