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