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