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