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