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