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