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