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