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