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