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