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