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