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