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