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