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