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