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