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