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