154359Sroberto/* 254359Sroberto * ntpdc - control and monitor your ntpd daemon 354359Sroberto */ 4290000Sglebius#include <config.h> 554359Sroberto#include <stdio.h> 6290000Sglebius#include <stddef.h> 7182007Sroberto#include <ctype.h> 8182007Sroberto#include <signal.h> 9182007Sroberto#include <setjmp.h> 10290000Sglebius#ifdef HAVE_UNISTD_H 11290000Sglebius# include <unistd.h> 12290000Sglebius#endif 13290000Sglebius#ifdef HAVE_FCNTL_H 14290000Sglebius# include <fcntl.h> 15290000Sglebius#endif 16290000Sglebius#ifdef SYS_WINNT 17290000Sglebius# include <mswsock.h> 18290000Sglebius#endif 19290000Sglebius#include <isc/net.h> 20290000Sglebius#include <isc/result.h> 21182007Sroberto 2282498Sroberto#include "ntpdc.h" 2382498Sroberto#include "ntp_select.h" 2482498Sroberto#include "ntp_stdlib.h" 25290000Sglebius#include "ntp_assert.h" 26290000Sglebius#include "ntp_lineedit.h" 27290000Sglebius#ifdef OPENSSL 28290000Sglebius#include "openssl/evp.h" 29290000Sglebius#include "openssl/objects.h" 30290000Sglebius#endif 31290000Sglebius#include <ssl_applink.c> 3282498Sroberto 33290000Sglebius#include "ntp_libopts.h" 34182007Sroberto#include "ntpdc-opts.h" 35293894Sglebius#include "safecast.h" 3654359Sroberto 3754359Sroberto#ifdef SYS_VXWORKS 38182007Sroberto /* vxWorks needs mode flag -casey*/ 39182007Sroberto# define open(name, flags) open(name, flags, 0777) 40182007Sroberto# define SERVER_PORT_NUM 123 4154359Sroberto#endif 4254359Sroberto 43182007Sroberto/* We use COMMAND as an autogen keyword */ 44182007Sroberto#ifdef COMMAND 45182007Sroberto# undef COMMAND 46182007Sroberto#endif 47182007Sroberto 4854359Sroberto/* 4954359Sroberto * Because we now potentially understand a lot of commands (and 5054359Sroberto * it requires a lot of commands to talk to ntpd) we will run 5154359Sroberto * interactive if connected to a terminal. 5254359Sroberto */ 5354359Srobertostatic int interactive = 0; /* set to 1 when we should prompt */ 5454359Srobertostatic const char * prompt = "ntpdc> "; /* prompt to ask him about */ 5554359Sroberto 5654359Sroberto/* 5754359Sroberto * Keyid used for authenticated requests. Obtained on the fly. 5854359Sroberto */ 5954359Srobertostatic u_long info_auth_keyid; 60182007Srobertostatic int keyid_entered = 0; 6154359Sroberto 62290000Sglebiusstatic int info_auth_keytype = NID_md5; /* MD5 */ 63290000Sglebiusstatic size_t info_auth_hashlen = 16; /* MD5 */ 6454359Srobertou_long current_time; /* needed by authkeys; not used */ 6554359Sroberto 66182007Sroberto/* 67182007Sroberto * for get_systime() 68182007Sroberto */ 69182007Srobertos_char sys_precision; /* local clock precision (log2 s) */ 70182007Sroberto 71290000Sglebiusint ntpdcmain (int, char **); 7254359Sroberto/* 7354359Sroberto * Built in command handler declarations 7454359Sroberto */ 75290000Sglebiusstatic int openhost (const char *); 76290000Sglebiusstatic int sendpkt (void *, size_t); 77290000Sglebiusstatic void growpktdata (void); 78293894Sglebiusstatic int getresponse (int, int, size_t *, size_t *, const char **, size_t); 79293894Sglebiusstatic int sendrequest (int, int, int, size_t, size_t, const char *); 80290000Sglebiusstatic void getcmds (void); 81290000Sglebiusstatic RETSIGTYPE abortcmd (int); 82290000Sglebiusstatic void docmd (const char *); 83290000Sglebiusstatic void tokenize (const char *, char **, int *); 84290000Sglebiusstatic int findcmd (char *, struct xcmd *, struct xcmd *, struct xcmd **); 85290000Sglebiusstatic int getarg (char *, int, arg_v *); 86290000Sglebiusstatic int getnetnum (const char *, sockaddr_u *, char *, int); 87290000Sglebiusstatic void help (struct parse *, FILE *); 88290000Sglebiusstatic int helpsort (const void *, const void *); 89290000Sglebiusstatic void printusage (struct xcmd *, FILE *); 90290000Sglebiusstatic void timeout (struct parse *, FILE *); 91290000Sglebiusstatic void my_delay (struct parse *, FILE *); 92290000Sglebiusstatic void host (struct parse *, FILE *); 93290000Sglebiusstatic void keyid (struct parse *, FILE *); 94290000Sglebiusstatic void keytype (struct parse *, FILE *); 95290000Sglebiusstatic void passwd (struct parse *, FILE *); 96290000Sglebiusstatic void hostnames (struct parse *, FILE *); 97290000Sglebiusstatic void setdebug (struct parse *, FILE *); 98290000Sglebiusstatic void quit (struct parse *, FILE *); 99290000Sglebiusstatic void version (struct parse *, FILE *); 100290000Sglebiusstatic void warning (const char *, ...) 101290000Sglebius __attribute__((__format__(__printf__, 1, 2))); 102290000Sglebiusstatic void error (const char *, ...) 103290000Sglebius __attribute__((__format__(__printf__, 1, 2))); 104290000Sglebiusstatic u_long getkeyid (const char *); 10554359Sroberto 10654359Sroberto 10754359Sroberto 10854359Sroberto/* 10954359Sroberto * Built-in commands we understand 11054359Sroberto */ 11154359Srobertostatic struct xcmd builtins[] = { 11254359Sroberto { "?", help, { OPT|NTP_STR, NO, NO, NO }, 11354359Sroberto { "command", "", "", "" }, 11454359Sroberto "tell the use and syntax of commands" }, 11554359Sroberto { "help", help, { OPT|NTP_STR, NO, NO, NO }, 11654359Sroberto { "command", "", "", "" }, 11754359Sroberto "tell the use and syntax of commands" }, 118182007Sroberto { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 11954359Sroberto { "msec", "", "", "" }, 12054359Sroberto "set the primary receive time out" }, 121182007Sroberto { "delay", my_delay, { OPT|NTP_INT, NO, NO, NO }, 12254359Sroberto { "msec", "", "", "" }, 12354359Sroberto "set the delay added to encryption time stamps" }, 124132451Sroberto { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 125132451Sroberto { "-4|-6", "hostname", "", "" }, 12654359Sroberto "specify the host whose NTP server we talk to" }, 12754359Sroberto { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 12854359Sroberto { "", "", "", "" }, 12954359Sroberto "specify a password to use for authenticated requests"}, 13054359Sroberto { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 13154359Sroberto { "yes|no", "", "", "" }, 13254359Sroberto "specify whether hostnames or net numbers are printed"}, 13354359Sroberto { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 13454359Sroberto { "no|more|less", "", "", "" }, 13554359Sroberto "set/change debugging level" }, 13654359Sroberto { "quit", quit, { NO, NO, NO, NO }, 13754359Sroberto { "", "", "", "" }, 13854359Sroberto "exit ntpdc" }, 13954359Sroberto { "exit", quit, { NO, NO, NO, NO }, 14054359Sroberto { "", "", "", "" }, 14154359Sroberto "exit ntpdc" }, 142182007Sroberto { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 14354359Sroberto { "key#", "", "", "" }, 14454359Sroberto "set/show keyid to use for authenticated requests" }, 14554359Sroberto { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 14654359Sroberto { "(md5|des)", "", "", "" }, 14754359Sroberto "set/show key authentication type for authenticated requests (des|md5)" }, 14854359Sroberto { "version", version, { NO, NO, NO, NO }, 14954359Sroberto { "", "", "", "" }, 15054359Sroberto "print version number" }, 15154359Sroberto { 0, 0, { NO, NO, NO, NO }, 15254359Sroberto { "", "", "", "" }, "" } 15354359Sroberto}; 15454359Sroberto 15554359Sroberto 15654359Sroberto/* 15754359Sroberto * Default values we use. 15854359Sroberto */ 159290000Sglebius#define DEFHOST "localhost" /* default host name */ 16054359Sroberto#define DEFTIMEOUT (5) /* 5 second time out */ 16154359Sroberto#define DEFSTIMEOUT (2) /* 2 second time out after first */ 16254359Sroberto#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 16354359Sroberto#define LENHOSTNAME 256 /* host name is 256 characters long */ 16454359Sroberto#define MAXCMDS 100 /* maximum commands on cmd line */ 16554359Sroberto#define MAXHOSTS 200 /* maximum hosts on cmd line */ 16654359Sroberto#define MAXLINE 512 /* maximum line length */ 167182007Sroberto#define MAXTOKENS (1+1+MAXARGS+MOREARGS+2) /* maximum number of usable tokens */ 168182007Sroberto#define SCREENWIDTH 78 /* nominal screen width in columns */ 16954359Sroberto 17054359Sroberto/* 17154359Sroberto * Some variables used and manipulated locally 17254359Sroberto */ 173290000Sglebiusstatic struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 174290000Sglebiusstatic struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 17554359Srobertostatic l_fp delay_time; /* delay time */ 17654359Srobertostatic char currenthost[LENHOSTNAME]; /* current host name */ 177132451Srobertoint showhostnames = 1; /* show host names by default */ 17854359Sroberto 179132451Srobertostatic int ai_fam_templ; /* address family */ 180132451Srobertostatic int ai_fam_default; /* default address family */ 181132451Srobertostatic SOCKET sockfd; /* fd socket is opened on */ 18254359Srobertostatic int havehost = 0; /* set to 1 when host open */ 183132451Srobertoint s_port = 0; 18454359Sroberto 18554359Sroberto/* 18654359Sroberto * Holds data returned from queries. We allocate INITDATASIZE 18754359Sroberto * octets to begin with, increasing this as we need to. 18854359Sroberto */ 18954359Sroberto#define INITDATASIZE (sizeof(struct resp_pkt) * 16) 19054359Sroberto#define INCDATASIZE (sizeof(struct resp_pkt) * 8) 19154359Sroberto 19254359Srobertostatic char *pktdata; 19354359Srobertostatic int pktdatasize; 19454359Sroberto 19554359Sroberto/* 196106163Sroberto * These are used to help the magic with old and new versions of ntpd. 197106163Sroberto */ 198132451Srobertoint impl_ver = IMPL_XNTPD; 199106163Srobertostatic int req_pkt_size = REQ_LEN_NOMAC; 200106163Sroberto 201106163Sroberto/* 20254359Sroberto * For commands typed on the command line (with the -c option) 20354359Sroberto */ 20454359Srobertostatic int numcmds = 0; 20554359Srobertostatic const char *ccmds[MAXCMDS]; 20654359Sroberto#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 20754359Sroberto 20854359Sroberto/* 20954359Sroberto * When multiple hosts are specified. 21054359Sroberto */ 21154359Srobertostatic int numhosts = 0; 21254359Srobertostatic const char *chosts[MAXHOSTS]; 21354359Sroberto#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp) 21454359Sroberto 21554359Sroberto/* 21654359Sroberto * Error codes for internal use 21754359Sroberto */ 21854359Sroberto#define ERR_INCOMPLETE 16 21954359Sroberto#define ERR_TIMEOUT 17 22054359Sroberto 22154359Sroberto/* 22254359Sroberto * Macro definitions we use 22354359Sroberto */ 22454359Sroberto#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 22554359Sroberto#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 22654359Sroberto#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 22754359Sroberto 22854359Sroberto/* 22954359Sroberto * Jump buffer for longjumping back to the command level 23054359Sroberto */ 23154359Srobertostatic jmp_buf interrupt_buf; 23254359Srobertostatic volatile int jump = 0; 23354359Sroberto 23454359Sroberto/* 23554359Sroberto * Pointer to current output unit 23654359Sroberto */ 23754359Srobertostatic FILE *current_output; 23854359Sroberto 23954359Sroberto/* 24054359Sroberto * Command table imported from ntpdc_ops.c 24154359Sroberto */ 24254359Srobertoextern struct xcmd opcmds[]; 24354359Sroberto 244290000Sglebiuschar const *progname; 24554359Sroberto 24654359Sroberto#ifdef NO_MAIN_ALLOWED 24754359SrobertoCALL(ntpdc,"ntpdc",ntpdcmain); 24854359Sroberto#else 24954359Srobertoint 25054359Srobertomain( 25154359Sroberto int argc, 25254359Sroberto char *argv[] 25354359Sroberto ) 25454359Sroberto{ 25554359Sroberto return ntpdcmain(argc, argv); 25654359Sroberto} 25754359Sroberto#endif 25854359Sroberto 25954359Sroberto#ifdef SYS_VXWORKS 26054359Srobertovoid clear_globals(void) 26154359Sroberto{ 26254359Sroberto showhostnames = 0; /* show host names by default */ 26354359Sroberto havehost = 0; /* set to 1 when host open */ 26454359Sroberto numcmds = 0; 26554359Sroberto numhosts = 0; 26654359Sroberto} 26754359Sroberto#endif 26854359Sroberto 26954359Sroberto/* 27054359Sroberto * main - parse arguments and handle options 27154359Sroberto */ 27254359Srobertoint 27354359Srobertontpdcmain( 27454359Sroberto int argc, 27554359Sroberto char *argv[] 27654359Sroberto ) 27754359Sroberto{ 27854359Sroberto 27954359Sroberto delay_time.l_ui = 0; 28054359Sroberto delay_time.l_uf = DEFDELAY; 28154359Sroberto 28254359Sroberto#ifdef SYS_VXWORKS 28354359Sroberto clear_globals(); 28454359Sroberto taskPrioritySet(taskIdSelf(), 100 ); 28554359Sroberto#endif 28654359Sroberto 287290000Sglebius init_lib(); /* sets up ipv4_works, ipv6_works */ 288290000Sglebius ssl_applink(); 289290000Sglebius init_auth(); 290132451Sroberto 291290000Sglebius /* Check to see if we have IPv6. Otherwise default to IPv4 */ 292290000Sglebius if (!ipv6_works) 293132451Sroberto ai_fam_default = AF_INET; 294132451Sroberto 29554359Sroberto progname = argv[0]; 296182007Sroberto 297182007Sroberto { 298290000Sglebius int optct = ntpOptionProcess(&ntpdcOptions, argc, argv); 299182007Sroberto argc -= optct; 300182007Sroberto argv += optct; 301182007Sroberto } 302182007Sroberto 303290000Sglebius if (HAVE_OPT(IPV4)) 304182007Sroberto ai_fam_templ = AF_INET; 305290000Sglebius else if (HAVE_OPT(IPV6)) 306182007Sroberto ai_fam_templ = AF_INET6; 307290000Sglebius else 308182007Sroberto ai_fam_templ = ai_fam_default; 309182007Sroberto 310182007Sroberto if (HAVE_OPT(COMMAND)) { 311182007Sroberto int cmdct = STACKCT_OPT( COMMAND ); 312182007Sroberto const char** cmds = STACKLST_OPT( COMMAND ); 313182007Sroberto 314182007Sroberto while (cmdct-- > 0) { 315182007Sroberto ADDCMD(*cmds++); 316182007Sroberto } 317182007Sroberto } 318182007Sroberto 319290000Sglebius debug = OPT_VALUE_SET_DEBUG_LEVEL; 320182007Sroberto 321182007Sroberto if (HAVE_OPT(INTERACTIVE)) { 322182007Sroberto interactive = 1; 323182007Sroberto } 324182007Sroberto 325182007Sroberto if (HAVE_OPT(NUMERIC)) { 326182007Sroberto showhostnames = 0; 327182007Sroberto } 328182007Sroberto 329182007Sroberto if (HAVE_OPT(LISTPEERS)) { 330182007Sroberto ADDCMD("listpeers"); 331182007Sroberto } 332182007Sroberto 333182007Sroberto if (HAVE_OPT(PEERS)) { 334182007Sroberto ADDCMD("peers"); 335182007Sroberto } 336182007Sroberto 337182007Sroberto if (HAVE_OPT(SHOWPEERS)) { 338182007Sroberto ADDCMD("dmpeers"); 339182007Sroberto } 340182007Sroberto 341182007Sroberto if (ntp_optind == argc) { 342182007Sroberto ADDHOST(DEFHOST); 343182007Sroberto } else { 344182007Sroberto for (; ntp_optind < argc; ntp_optind++) 345182007Sroberto ADDHOST(argv[ntp_optind]); 346182007Sroberto } 347182007Sroberto 348182007Sroberto if (numcmds == 0 && interactive == 0 349182007Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 350182007Sroberto interactive = 1; 351182007Sroberto } 352182007Sroberto 35354359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 35454359Sroberto if (interactive) 35554359Sroberto (void) signal_no_reset(SIGINT, abortcmd); 35654359Sroberto#endif /* SYS_WINNT */ 35754359Sroberto 35854359Sroberto /* 35954359Sroberto * Initialize the packet data buffer 36054359Sroberto */ 36154359Sroberto pktdatasize = INITDATASIZE; 362290000Sglebius pktdata = emalloc(INITDATASIZE); 36354359Sroberto 36454359Sroberto if (numcmds == 0) { 36554359Sroberto (void) openhost(chosts[0]); 36654359Sroberto getcmds(); 36754359Sroberto } else { 36854359Sroberto int ihost; 36954359Sroberto int icmd; 37054359Sroberto 37154359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 37254359Sroberto if (openhost(chosts[ihost])) 37354359Sroberto for (icmd = 0; icmd < numcmds; icmd++) { 37454359Sroberto if (numhosts > 1) 37554359Sroberto printf ("--- %s ---\n",chosts[ihost]); 37654359Sroberto docmd(ccmds[icmd]); 37754359Sroberto } 37854359Sroberto } 37954359Sroberto } 38054359Sroberto#ifdef SYS_WINNT 38154359Sroberto WSACleanup(); 38254359Sroberto#endif 38354359Sroberto return(0); 38454359Sroberto} /* main end */ 38554359Sroberto 38654359Sroberto 38754359Sroberto/* 38854359Sroberto * openhost - open a socket to a host 38954359Sroberto */ 39054359Srobertostatic int 39154359Srobertoopenhost( 39254359Sroberto const char *hname 39354359Sroberto ) 39454359Sroberto{ 39554359Sroberto char temphost[LENHOSTNAME]; 396132451Sroberto int a_info, i; 397132451Sroberto struct addrinfo hints, *ai = NULL; 398290000Sglebius sockaddr_u addr; 399290000Sglebius size_t octets; 400132451Sroberto register const char *cp; 401132451Sroberto char name[LENHOSTNAME]; 402132451Sroberto char service[5]; 40354359Sroberto 404132451Sroberto /* 405132451Sroberto * We need to get by the [] if they were entered 406132451Sroberto */ 407132451Sroberto 408132451Sroberto cp = hname; 409132451Sroberto 410132451Sroberto if (*cp == '[') { 411132451Sroberto cp++; 412290000Sglebius for (i = 0; *cp && *cp != ']'; cp++, i++) 413290000Sglebius name[i] = *cp; 414290000Sglebius if (*cp == ']') { 415290000Sglebius name[i] = '\0'; 416290000Sglebius hname = name; 417290000Sglebius } else { 418290000Sglebius return 0; 419290000Sglebius } 420132451Sroberto } 421132451Sroberto 422132451Sroberto /* 423132451Sroberto * First try to resolve it as an ip address and if that fails, 424132451Sroberto * do a fullblown (dns) lookup. That way we only use the dns 425132451Sroberto * when it is needed and work around some implementations that 426132451Sroberto * will return an "IPv4-mapped IPv6 address" address if you 427132451Sroberto * give it an IPv4 address to lookup. 428132451Sroberto */ 429290000Sglebius strlcpy(service, "ntp", sizeof(service)); 430290000Sglebius ZERO(hints); 431132451Sroberto hints.ai_family = ai_fam_templ; 432132451Sroberto hints.ai_protocol = IPPROTO_UDP; 433132451Sroberto hints.ai_socktype = SOCK_DGRAM; 434290000Sglebius hints.ai_flags = Z_AI_NUMERICHOST; 435132451Sroberto 436132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 437182007Sroberto if (a_info == EAI_NONAME 438182007Sroberto#ifdef EAI_NODATA 439182007Sroberto || a_info == EAI_NODATA 440182007Sroberto#endif 441182007Sroberto ) { 442132451Sroberto hints.ai_flags = AI_CANONNAME; 443132451Sroberto#ifdef AI_ADDRCONFIG 444132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 445132451Sroberto#endif 446132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 44754359Sroberto } 448132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 449132451Sroberto if (a_info == EAI_BADFLAGS) { 450132451Sroberto hints.ai_flags = AI_CANONNAME; 451132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 452132451Sroberto } 453132451Sroberto if (a_info != 0) { 454290000Sglebius fprintf(stderr, "%s\n", gai_strerror(a_info)); 455182007Sroberto if (ai != NULL) 456182007Sroberto freeaddrinfo(ai); 457132451Sroberto return 0; 458132451Sroberto } 45954359Sroberto 460290000Sglebius /* 461290000Sglebius * getaddrinfo() has returned without error so ai should not 462290000Sglebius * be NULL. 463290000Sglebius */ 464290000Sglebius INSIST(ai != NULL); 465290000Sglebius ZERO(addr); 466290000Sglebius octets = min(sizeof(addr), ai->ai_addrlen); 467290000Sglebius memcpy(&addr, ai->ai_addr, octets); 468132451Sroberto 469290000Sglebius if (ai->ai_canonname == NULL) 470290000Sglebius strlcpy(temphost, stoa(&addr), sizeof(temphost)); 471290000Sglebius else 472290000Sglebius strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 473290000Sglebius 47454359Sroberto if (debug > 2) 475290000Sglebius printf("Opening host %s\n", temphost); 47654359Sroberto 47754359Sroberto if (havehost == 1) { 47854359Sroberto if (debug > 2) 479290000Sglebius printf("Closing old host %s\n", currenthost); 480290000Sglebius closesocket(sockfd); 48154359Sroberto havehost = 0; 48254359Sroberto } 483290000Sglebius strlcpy(currenthost, temphost, sizeof(currenthost)); 484132451Sroberto 485132451Sroberto /* port maps to the same in both families */ 486290000Sglebius s_port = NSRCPORT(&addr);; 487132451Sroberto#ifdef SYS_VXWORKS 488132451Sroberto ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 489132451Sroberto if (ai->ai_family == AF_INET) 490132451Sroberto *(struct sockaddr_in *)&hostaddr= 491132451Sroberto *((struct sockaddr_in *)ai->ai_addr); 492132451Sroberto else 493132451Sroberto *(struct sockaddr_in6 *)&hostaddr= 494132451Sroberto *((struct sockaddr_in6 *)ai->ai_addr); 495132451Sroberto#endif /* SYS_VXWORKS */ 49654359Sroberto 49754359Sroberto#ifdef SYS_WINNT 49854359Sroberto { 49954359Sroberto int optionValue = SO_SYNCHRONOUS_NONALERT; 50054359Sroberto int err; 501182007Sroberto 50254359Sroberto err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); 50354359Sroberto if (err != NO_ERROR) { 50454359Sroberto (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); 50554359Sroberto exit(1); 50654359Sroberto } 50754359Sroberto } 508290000Sglebius#endif /* SYS_WINNT */ 509132451Sroberto 510132451Sroberto sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); 51154359Sroberto if (sockfd == INVALID_SOCKET) { 512290000Sglebius error("socket"); 51354359Sroberto exit(-1); 51454359Sroberto } 51554359Sroberto 51654359Sroberto#ifdef NEED_RCVBUF_SLOP 51754359Sroberto# ifdef SO_RCVBUF 51854359Sroberto { 51954359Sroberto int rbufsize = INITDATASIZE + 2048; /* 2K for slop */ 52054359Sroberto 52154359Sroberto if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 52254359Sroberto &rbufsize, sizeof(int)) == -1) 523290000Sglebius error("setsockopt"); 52454359Sroberto } 52554359Sroberto# endif 52654359Sroberto#endif 52754359Sroberto 528132451Sroberto#ifdef SYS_VXWORKS 529132451Sroberto if (connect(sockfd, (struct sockaddr *)&hostaddr, 530293894Sglebius sizeof(hostaddr)) == -1) 531132451Sroberto#else 532293894Sglebius if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) 533132451Sroberto#endif /* SYS_VXWORKS */ 534293894Sglebius { 535290000Sglebius error("connect"); 536290000Sglebius exit(-1); 537290000Sglebius } 538290000Sglebius 539290000Sglebius freeaddrinfo(ai); 54054359Sroberto havehost = 1; 541106163Sroberto req_pkt_size = REQ_LEN_NOMAC; 542132451Sroberto impl_ver = IMPL_XNTPD; 54354359Sroberto return 1; 54454359Sroberto} 54554359Sroberto 54654359Sroberto 54754359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 54854359Sroberto/* 54954359Sroberto * sendpkt - send a packet to the remote host 55054359Sroberto */ 55154359Srobertostatic int 55254359Srobertosendpkt( 553290000Sglebius void * xdata, 554290000Sglebius size_t xdatalen 55554359Sroberto ) 55654359Sroberto{ 557290000Sglebius if (send(sockfd, xdata, xdatalen, 0) == -1) { 558290000Sglebius warning("write to %s failed", currenthost); 55954359Sroberto return -1; 56054359Sroberto } 56154359Sroberto 56254359Sroberto return 0; 56354359Sroberto} 56454359Sroberto 56554359Sroberto 56654359Sroberto/* 56754359Sroberto * growpktdata - grow the packet data area 56854359Sroberto */ 56954359Srobertostatic void 57054359Srobertogrowpktdata(void) 57154359Sroberto{ 572290000Sglebius size_t priorsz; 573290000Sglebius 574290000Sglebius priorsz = (size_t)pktdatasize; 57554359Sroberto pktdatasize += INCDATASIZE; 576290000Sglebius pktdata = erealloc_zero(pktdata, (size_t)pktdatasize, priorsz); 57754359Sroberto} 57854359Sroberto 57954359Sroberto 58054359Sroberto/* 58154359Sroberto * getresponse - get a (series of) response packet(s) and return the data 58254359Sroberto */ 58354359Srobertostatic int 58454359Srobertogetresponse( 58554359Sroberto int implcode, 58654359Sroberto int reqcode, 587293894Sglebius size_t *ritems, 588293894Sglebius size_t *rsize, 589293894Sglebius const char **rdata, 590293894Sglebius size_t esize 59154359Sroberto ) 59254359Sroberto{ 59354359Sroberto struct resp_pkt rpkt; 594290000Sglebius struct sock_timeval tvo; 595293894Sglebius size_t items; 596293894Sglebius size_t i; 597293894Sglebius size_t size; 598293894Sglebius size_t datasize; 59954359Sroberto char *datap; 600132451Sroberto char *tmp_data; 60154359Sroberto char haveseq[MAXSEQ+1]; 60254359Sroberto int firstpkt; 60354359Sroberto int lastseq; 60454359Sroberto int numrecv; 60554359Sroberto int seq; 60654359Sroberto fd_set fds; 607290000Sglebius ssize_t n; 608294904Sdelphij int pad; 609294904Sdelphij /* absolute timeout checks. Not 'time_t' by intention! */ 610294904Sdelphij uint32_t tobase; /* base value for timeout */ 611294904Sdelphij uint32_t tospan; /* timeout span (max delay) */ 612294904Sdelphij uint32_t todiff; /* current delay */ 61354359Sroberto 61454359Sroberto /* 61554359Sroberto * This is pretty tricky. We may get between 1 and many packets 61654359Sroberto * back in response to the request. We peel the data out of 61754359Sroberto * each packet and collect it in one long block. When the last 61854359Sroberto * packet in the sequence is received we'll know how many we 61954359Sroberto * should have had. Note we use one long time out, should reconsider. 62054359Sroberto */ 62154359Sroberto *ritems = 0; 62254359Sroberto *rsize = 0; 62354359Sroberto firstpkt = 1; 62454359Sroberto numrecv = 0; 62554359Sroberto *rdata = datap = pktdata; 62654359Sroberto lastseq = 999; /* too big to be a sequence number */ 627290000Sglebius ZERO(haveseq); 62854359Sroberto FD_ZERO(&fds); 629294904Sdelphij tobase = (uint32_t)time(NULL); 63054359Sroberto 63154359Sroberto again: 63254359Sroberto if (firstpkt) 633290000Sglebius tvo = tvout; 63454359Sroberto else 635290000Sglebius tvo = tvsout; 636294904Sdelphij tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 63754359Sroberto 63854359Sroberto FD_SET(sockfd, &fds); 639293894Sglebius n = select(sockfd+1, &fds, NULL, NULL, &tvo); 64054359Sroberto if (n == -1) { 641290000Sglebius warning("select fails"); 64254359Sroberto return -1; 64354359Sroberto } 644294904Sdelphij 645294904Sdelphij /* 646294904Sdelphij * Check if this is already too late. Trash the data and fake a 647294904Sdelphij * timeout if this is so. 648294904Sdelphij */ 649294904Sdelphij todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 650294904Sdelphij if ((n > 0) && (todiff > tospan)) { 651294904Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 652294904Sdelphij n = 0; /* faked timeout return from 'select()'*/ 653294904Sdelphij } 654294904Sdelphij 65554359Sroberto if (n == 0) { 65654359Sroberto /* 65754359Sroberto * Timed out. Return what we have 65854359Sroberto */ 65954359Sroberto if (firstpkt) { 66054359Sroberto (void) fprintf(stderr, 661293894Sglebius "%s: timed out, nothing received\n", 662293894Sglebius currenthost); 66354359Sroberto return ERR_TIMEOUT; 66454359Sroberto } else { 66554359Sroberto (void) fprintf(stderr, 66654359Sroberto "%s: timed out with incomplete data\n", 66754359Sroberto currenthost); 66854359Sroberto if (debug) { 66954359Sroberto printf("Received sequence numbers"); 67054359Sroberto for (n = 0; n <= MAXSEQ; n++) 67154359Sroberto if (haveseq[n]) 672301301Sdelphij printf(" %zd,", (size_t)n); 67354359Sroberto if (lastseq != 999) 67454359Sroberto printf(" last frame received\n"); 67554359Sroberto else 67654359Sroberto printf(" last frame not received\n"); 67754359Sroberto } 67854359Sroberto return ERR_INCOMPLETE; 67954359Sroberto } 68054359Sroberto } 68154359Sroberto 68254359Sroberto n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 68354359Sroberto if (n == -1) { 684290000Sglebius warning("read"); 68554359Sroberto return -1; 68654359Sroberto } 68754359Sroberto 68854359Sroberto 68954359Sroberto /* 69054359Sroberto * Check for format errors. Bug proofing. 69154359Sroberto */ 692290000Sglebius if (n < (ssize_t)RESP_HEADER_SIZE) { 69354359Sroberto if (debug) 694301301Sdelphij printf("Short (%zd byte) packet received\n", (size_t)n); 69554359Sroberto goto again; 69654359Sroberto } 69754359Sroberto if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION || 69854359Sroberto INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) { 69954359Sroberto if (debug) 700290000Sglebius printf("Packet received with version %d\n", 701290000Sglebius INFO_VERSION(rpkt.rm_vn_mode)); 70254359Sroberto goto again; 70354359Sroberto } 70454359Sroberto if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) { 70554359Sroberto if (debug) 706290000Sglebius printf("Packet received with mode %d\n", 707290000Sglebius INFO_MODE(rpkt.rm_vn_mode)); 70854359Sroberto goto again; 70954359Sroberto } 71054359Sroberto if (INFO_IS_AUTH(rpkt.auth_seq)) { 71154359Sroberto if (debug) 712290000Sglebius printf("Encrypted packet received\n"); 71354359Sroberto goto again; 71454359Sroberto } 71554359Sroberto if (!ISRESPONSE(rpkt.rm_vn_mode)) { 71654359Sroberto if (debug) 717290000Sglebius printf("Received request packet, wanted response\n"); 71854359Sroberto goto again; 71954359Sroberto } 72054359Sroberto if (INFO_MBZ(rpkt.mbz_itemsize) != 0) { 72154359Sroberto if (debug) 722290000Sglebius printf("Received packet with nonzero MBZ field!\n"); 72354359Sroberto goto again; 72454359Sroberto } 72554359Sroberto 72654359Sroberto /* 72754359Sroberto * Check implementation/request. Could be old data getting to us. 72854359Sroberto */ 72954359Sroberto if (rpkt.implementation != implcode || rpkt.request != reqcode) { 73054359Sroberto if (debug) 731290000Sglebius printf( 73254359Sroberto "Received implementation/request of %d/%d, wanted %d/%d", 73354359Sroberto rpkt.implementation, rpkt.request, 73454359Sroberto implcode, reqcode); 73554359Sroberto goto again; 73654359Sroberto } 73754359Sroberto 73854359Sroberto /* 73954359Sroberto * Check the error code. If non-zero, return it. 74054359Sroberto */ 74154359Sroberto if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) { 74254359Sroberto if (debug && ISMORE(rpkt.rm_vn_mode)) { 74354359Sroberto printf("Error code %d received on not-final packet\n", 74454359Sroberto INFO_ERR(rpkt.err_nitems)); 74554359Sroberto } 74654359Sroberto return (int)INFO_ERR(rpkt.err_nitems); 74754359Sroberto } 74854359Sroberto 74954359Sroberto /* 75054359Sroberto * Collect items and size. Make sure they make sense. 75154359Sroberto */ 75254359Sroberto items = INFO_NITEMS(rpkt.err_nitems); 75354359Sroberto size = INFO_ITEMSIZE(rpkt.mbz_itemsize); 754132451Sroberto if (esize > size) 755132451Sroberto pad = esize - size; 756132451Sroberto else 757132451Sroberto pad = 0; 758290000Sglebius datasize = items * size; 759290000Sglebius if ((size_t)datasize > (n-RESP_HEADER_SIZE)) { 76054359Sroberto if (debug) 76154359Sroberto printf( 762293894Sglebius "Received items %zu, size %zu (total %zu), data in packet is %zu\n", 76354359Sroberto items, size, datasize, n-RESP_HEADER_SIZE); 76454359Sroberto goto again; 76554359Sroberto } 76654359Sroberto 76754359Sroberto /* 76854359Sroberto * If this isn't our first packet, make sure the size matches 76954359Sroberto * the other ones. 77054359Sroberto */ 771290000Sglebius if (!firstpkt && size != *rsize) { 77254359Sroberto if (debug) 773293894Sglebius printf("Received itemsize %zu, previous %zu\n", 77454359Sroberto size, *rsize); 77554359Sroberto goto again; 77654359Sroberto } 77754359Sroberto /* 778132451Sroberto * If we've received this before, +toss it 77954359Sroberto */ 78054359Sroberto seq = INFO_SEQ(rpkt.auth_seq); 78154359Sroberto if (haveseq[seq]) { 78254359Sroberto if (debug) 78354359Sroberto printf("Received duplicate sequence number %d\n", seq); 78454359Sroberto goto again; 78554359Sroberto } 78654359Sroberto haveseq[seq] = 1; 78754359Sroberto 78854359Sroberto /* 78954359Sroberto * If this is the last in the sequence, record that. 79054359Sroberto */ 79154359Sroberto if (!ISMORE(rpkt.rm_vn_mode)) { 79254359Sroberto if (lastseq != 999) { 79354359Sroberto printf("Received second end sequence packet\n"); 79454359Sroberto goto again; 79554359Sroberto } 79654359Sroberto lastseq = seq; 79754359Sroberto } 79854359Sroberto 79954359Sroberto /* 800294904Sdelphij * So far, so good. Copy this data into the output array. Bump 801294904Sdelphij * the timeout base, in case we expect more data. 80254359Sroberto */ 803294904Sdelphij tobase = (uint32_t)time(NULL); 804132451Sroberto if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) { 805293894Sglebius size_t offset = datap - pktdata; 80654359Sroberto growpktdata(); 807290000Sglebius *rdata = pktdata; /* might have been realloced ! */ 80854359Sroberto datap = pktdata + offset; 80954359Sroberto } 810132451Sroberto /* 811132451Sroberto * We now move the pointer along according to size and number of 812132451Sroberto * items. This is so we can play nice with older implementations 813132451Sroberto */ 814132451Sroberto 815290000Sglebius tmp_data = rpkt.u.data; 816290000Sglebius for (i = 0; i < items; i++) { 817290000Sglebius memcpy(datap, tmp_data, (unsigned)size); 818132451Sroberto tmp_data += size; 819290000Sglebius zero_mem(datap + size, pad); 820132451Sroberto datap += size + pad; 821132451Sroberto } 822132451Sroberto 82354359Sroberto if (firstpkt) { 82454359Sroberto firstpkt = 0; 825132451Sroberto *rsize = size + pad; 82654359Sroberto } 82754359Sroberto *ritems += items; 82854359Sroberto 82954359Sroberto /* 83054359Sroberto * Finally, check the count of received packets. If we've got them 83154359Sroberto * all, return 83254359Sroberto */ 83354359Sroberto ++numrecv; 83454359Sroberto if (numrecv <= lastseq) 835290000Sglebius goto again; 83654359Sroberto return INFO_OKAY; 83754359Sroberto} 83854359Sroberto 83954359Sroberto 84054359Sroberto/* 84154359Sroberto * sendrequest - format and send a request packet 842290000Sglebius * 843290000Sglebius * Historically, ntpdc has used a fixed-size request packet regardless 844290000Sglebius * of the actual payload size. When authenticating, the timestamp, key 845290000Sglebius * ID, and digest have been placed just before the end of the packet. 846290000Sglebius * With the introduction in late 2009 of support for authenticated 847290000Sglebius * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we 848290000Sglebius * come up four bytes short. 849290000Sglebius * 850290000Sglebius * To maintain interop while allowing for larger digests, the behavior 851290000Sglebius * is unchanged when using 16-octet digests. For larger digests, the 852290000Sglebius * timestamp, key ID, and digest are placed immediately following the 853290000Sglebius * request payload, with the overall packet size variable. ntpd can 854290000Sglebius * distinguish 16-octet digests by the overall request size being 855290000Sglebius * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled. When using a 856290000Sglebius * longer digest, that request size should be avoided. 857290000Sglebius * 858290000Sglebius * With the form used with 20-octet and larger digests, the timestamp, 859290000Sglebius * key ID, and digest are located by ntpd relative to the start of the 860290000Sglebius * packet, and the size of the digest is then implied by the packet 861290000Sglebius * size. 86254359Sroberto */ 86354359Srobertostatic int 86454359Srobertosendrequest( 86554359Sroberto int implcode, 86654359Sroberto int reqcode, 86754359Sroberto int auth, 868293894Sglebius size_t qitems, 869290000Sglebius size_t qsize, 870293894Sglebius const char *qdata 87154359Sroberto ) 87254359Sroberto{ 87354359Sroberto struct req_pkt qpkt; 874290000Sglebius size_t datasize; 875290000Sglebius size_t reqsize; 876290000Sglebius u_long key_id; 877290000Sglebius l_fp ts; 878290000Sglebius l_fp * ptstamp; 879293894Sglebius size_t maclen; 880290000Sglebius char * pass; 88154359Sroberto 882290000Sglebius ZERO(qpkt); 88354359Sroberto qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); 88454359Sroberto qpkt.implementation = (u_char)implcode; 88554359Sroberto qpkt.request = (u_char)reqcode; 88654359Sroberto 88754359Sroberto datasize = qitems * qsize; 888290000Sglebius if (datasize && qdata != NULL) { 889290000Sglebius memcpy(qpkt.u.data, qdata, datasize); 89054359Sroberto qpkt.err_nitems = ERR_NITEMS(0, qitems); 89154359Sroberto qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); 89254359Sroberto } else { 89354359Sroberto qpkt.err_nitems = ERR_NITEMS(0, 0); 894182007Sroberto qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); /* allow for optional first item */ 89554359Sroberto } 89654359Sroberto 897182007Sroberto if (!auth || (keyid_entered && info_auth_keyid == 0)) { 89854359Sroberto qpkt.auth_seq = AUTH_SEQ(0, 0); 899290000Sglebius return sendpkt(&qpkt, req_pkt_size); 900290000Sglebius } 90154359Sroberto 902290000Sglebius if (info_auth_keyid == 0) { 903290000Sglebius key_id = getkeyid("Keyid: "); 904290000Sglebius if (!key_id) { 905290000Sglebius fprintf(stderr, "Invalid key identifier\n"); 906290000Sglebius return 1; 90754359Sroberto } 908290000Sglebius info_auth_keyid = key_id; 909290000Sglebius } 910290000Sglebius if (!authistrusted(info_auth_keyid)) { 911290000Sglebius pass = getpass_keytype(info_auth_keytype); 912290000Sglebius if ('\0' == pass[0]) { 913290000Sglebius fprintf(stderr, "Invalid password\n"); 914290000Sglebius return 1; 91554359Sroberto } 916290000Sglebius authusekey(info_auth_keyid, info_auth_keytype, 917290000Sglebius (u_char *)pass); 91854359Sroberto authtrust(info_auth_keyid, 1); 91954359Sroberto } 920290000Sglebius qpkt.auth_seq = AUTH_SEQ(1, 0); 921290000Sglebius if (info_auth_hashlen > 16) { 922290000Sglebius /* 923290000Sglebius * Only ntpd which expects REQ_LEN_NOMAC plus maclen 924290000Sglebius * octets in an authenticated request using a 16 octet 925290000Sglebius * digest (that is, a newer ntpd) will handle digests 926290000Sglebius * larger than 16 octets, so for longer digests, do 927290000Sglebius * not attempt to shorten the requests for downlevel 928290000Sglebius * ntpd compatibility. 929290000Sglebius */ 930290000Sglebius if (REQ_LEN_NOMAC != req_pkt_size) 931290000Sglebius return 1; 932290000Sglebius reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp); 933290000Sglebius /* align to 32 bits */ 934290000Sglebius reqsize = (reqsize + 3) & ~3; 935290000Sglebius } else 936290000Sglebius reqsize = req_pkt_size; 937290000Sglebius ptstamp = (void *)((char *)&qpkt + reqsize); 938290000Sglebius ptstamp--; 939290000Sglebius get_systime(&ts); 940290000Sglebius L_ADD(&ts, &delay_time); 941290000Sglebius HTONL_FP(&ts, ptstamp); 942293894Sglebius maclen = authencrypt( 943293894Sglebius info_auth_keyid, (void *)&qpkt, size2int_chk(reqsize)); 944290000Sglebius if (!maclen) { 945290000Sglebius fprintf(stderr, "Key not found\n"); 946290000Sglebius return 1; 947290000Sglebius } else if (maclen != (int)(info_auth_hashlen + sizeof(keyid_t))) { 948290000Sglebius fprintf(stderr, 949293894Sglebius "%zu octet MAC, %zu expected with %zu octet digest\n", 950290000Sglebius maclen, (info_auth_hashlen + sizeof(keyid_t)), 951290000Sglebius info_auth_hashlen); 952290000Sglebius return 1; 953290000Sglebius } 954290000Sglebius return sendpkt(&qpkt, reqsize + maclen); 95554359Sroberto} 95654359Sroberto 95754359Sroberto 95854359Sroberto/* 95954359Sroberto * doquery - send a request and process the response 96054359Sroberto */ 96154359Srobertoint 96254359Srobertodoquery( 96354359Sroberto int implcode, 96454359Sroberto int reqcode, 96554359Sroberto int auth, 966293894Sglebius size_t qitems, 967293894Sglebius size_t qsize, 968293894Sglebius const char *qdata, 969293894Sglebius size_t *ritems, 970293894Sglebius size_t *rsize, 971293894Sglebius const char **rdata, 972132451Sroberto int quiet_mask, 973132451Sroberto int esize 97454359Sroberto ) 97554359Sroberto{ 97654359Sroberto int res; 97754359Sroberto char junk[512]; 97854359Sroberto fd_set fds; 979290000Sglebius struct sock_timeval tvzero; 98054359Sroberto 98154359Sroberto /* 98254359Sroberto * Check to make sure host is open 98354359Sroberto */ 98454359Sroberto if (!havehost) { 98554359Sroberto (void) fprintf(stderr, "***No host open, use `host' command\n"); 98654359Sroberto return -1; 98754359Sroberto } 98854359Sroberto 98954359Sroberto /* 99054359Sroberto * Poll the socket and clear out any pending data 99154359Sroberto */ 992106163Srobertoagain: 99354359Sroberto do { 99454359Sroberto tvzero.tv_sec = tvzero.tv_usec = 0; 99554359Sroberto FD_ZERO(&fds); 99654359Sroberto FD_SET(sockfd, &fds); 997293894Sglebius res = select(sockfd+1, &fds, NULL, NULL, &tvzero); 99854359Sroberto if (res == -1) { 999290000Sglebius warning("polling select"); 100054359Sroberto return -1; 100154359Sroberto } else if (res > 0) 100254359Sroberto 100354359Sroberto (void) recv(sockfd, junk, sizeof junk, 0); 100454359Sroberto } while (res > 0); 100554359Sroberto 100654359Sroberto 100754359Sroberto /* 100854359Sroberto * send a request 100954359Sroberto */ 101054359Sroberto res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata); 101154359Sroberto if (res != 0) 1012290000Sglebius return res; 101354359Sroberto 101454359Sroberto /* 101554359Sroberto * Get the response. If we got a standard error, print a message 101654359Sroberto */ 1017132451Sroberto res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize); 101854359Sroberto 1019106163Sroberto /* 1020106163Sroberto * Try to be compatible with older implementations of ntpd. 1021106163Sroberto */ 1022106163Sroberto if (res == INFO_ERR_FMT && req_pkt_size != 48) { 1023106163Sroberto int oldsize; 1024106163Sroberto 1025106163Sroberto oldsize = req_pkt_size; 1026106163Sroberto 1027106163Sroberto switch(req_pkt_size) { 1028106163Sroberto case REQ_LEN_NOMAC: 1029132451Sroberto req_pkt_size = 160; 1030132451Sroberto break; 1031132451Sroberto case 160: 1032106163Sroberto req_pkt_size = 48; 1033106163Sroberto break; 1034106163Sroberto } 1035132451Sroberto if (impl_ver == IMPL_XNTPD) { 1036132451Sroberto fprintf(stderr, 1037132451Sroberto "***Warning changing to older implementation\n"); 1038132451Sroberto return INFO_ERR_IMPL; 1039132451Sroberto } 1040106163Sroberto 1041106163Sroberto fprintf(stderr, 1042106163Sroberto "***Warning changing the request packet size from %d to %d\n", 1043106163Sroberto oldsize, req_pkt_size); 1044106163Sroberto goto again; 1045106163Sroberto } 1046106163Sroberto 104754359Sroberto /* log error message if not told to be quiet */ 104854359Sroberto if ((res > 0) && (((1 << res) & quiet_mask) == 0)) { 104954359Sroberto switch(res) { 1050290000Sglebius case INFO_ERR_IMPL: 1051132451Sroberto /* Give us a chance to try the older implementation. */ 1052132451Sroberto if (implcode == IMPL_XNTPD) 1053132451Sroberto break; 105454359Sroberto (void) fprintf(stderr, 1055290000Sglebius "***Server implementation incompatible with our own\n"); 105654359Sroberto break; 1057290000Sglebius case INFO_ERR_REQ: 105854359Sroberto (void) fprintf(stderr, 105954359Sroberto "***Server doesn't implement this request\n"); 106054359Sroberto break; 1061290000Sglebius case INFO_ERR_FMT: 106254359Sroberto (void) fprintf(stderr, 106354359Sroberto "***Server reports a format error in the received packet (shouldn't happen)\n"); 106454359Sroberto break; 1065290000Sglebius case INFO_ERR_NODATA: 106654359Sroberto (void) fprintf(stderr, 106754359Sroberto "***Server reports data not found\n"); 106854359Sroberto break; 1069290000Sglebius case INFO_ERR_AUTH: 107054359Sroberto (void) fprintf(stderr, "***Permission denied\n"); 107154359Sroberto break; 1072290000Sglebius case ERR_TIMEOUT: 107354359Sroberto (void) fprintf(stderr, "***Request timed out\n"); 107454359Sroberto break; 1075290000Sglebius case ERR_INCOMPLETE: 107654359Sroberto (void) fprintf(stderr, 107754359Sroberto "***Response from server was incomplete\n"); 107854359Sroberto break; 1079290000Sglebius default: 108054359Sroberto (void) fprintf(stderr, 108154359Sroberto "***Server returns unknown error code %d\n", res); 108254359Sroberto break; 108354359Sroberto } 108454359Sroberto } 108554359Sroberto return res; 108654359Sroberto} 108754359Sroberto 108854359Sroberto 108954359Sroberto/* 109054359Sroberto * getcmds - read commands from the standard input and execute them 109154359Sroberto */ 109254359Srobertostatic void 109354359Srobertogetcmds(void) 109454359Sroberto{ 1095290000Sglebius char * line; 1096290000Sglebius int count; 109782498Sroberto 1098290000Sglebius ntp_readline_init(interactive ? prompt : NULL); 1099290000Sglebius 110082498Sroberto for (;;) { 1101290000Sglebius line = ntp_readline(&count); 1102290000Sglebius if (NULL == line) 1103290000Sglebius break; 110482498Sroberto docmd(line); 110582498Sroberto free(line); 110682498Sroberto } 110754359Sroberto 1108290000Sglebius ntp_readline_uninit(); 110954359Sroberto} 111054359Sroberto 111154359Sroberto 1112132451Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 111354359Sroberto/* 111454359Sroberto * abortcmd - catch interrupts and abort the current command 111554359Sroberto */ 111654359Srobertostatic RETSIGTYPE 111754359Srobertoabortcmd( 111854359Sroberto int sig 111954359Sroberto ) 112054359Sroberto{ 112154359Sroberto 112254359Sroberto if (current_output == stdout) 112354359Sroberto (void) fflush(stdout); 112454359Sroberto putc('\n', stderr); 112554359Sroberto (void) fflush(stderr); 112654359Sroberto if (jump) longjmp(interrupt_buf, 1); 112754359Sroberto} 1128132451Sroberto#endif /* SYS_WINNT */ 112954359Sroberto 113054359Sroberto/* 113154359Sroberto * docmd - decode the command line and execute a command 113254359Sroberto */ 113354359Srobertostatic void 113454359Srobertodocmd( 113554359Sroberto const char *cmdline 113654359Sroberto ) 113754359Sroberto{ 1138182007Sroberto char *tokens[1+MAXARGS+MOREARGS+2]; 113954359Sroberto struct parse pcmd; 114054359Sroberto int ntok; 1141132451Sroberto int i, ti; 1142132451Sroberto int rval; 114354359Sroberto struct xcmd *xcmd; 114454359Sroberto 1145132451Sroberto ai_fam_templ = ai_fam_default; 114654359Sroberto /* 114754359Sroberto * Tokenize the command line. If nothing on it, return. 114854359Sroberto */ 1149290000Sglebius if (strlen(cmdline) >= MAXLINE) { 1150290000Sglebius fprintf(stderr, "***Command ignored, more than %d characters:\n%s\n", 1151290000Sglebius MAXLINE - 1, cmdline); 1152290000Sglebius return; 1153290000Sglebius } 115454359Sroberto tokenize(cmdline, tokens, &ntok); 115554359Sroberto if (ntok == 0) 115654359Sroberto return; 115754359Sroberto 115854359Sroberto /* 115954359Sroberto * Find the appropriate command description. 116054359Sroberto */ 116154359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 116254359Sroberto if (i == 0) { 116354359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 116454359Sroberto tokens[0]); 116554359Sroberto return; 116654359Sroberto } else if (i >= 2) { 116754359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 116854359Sroberto tokens[0]); 116954359Sroberto return; 117054359Sroberto } 117154359Sroberto 117254359Sroberto /* 117354359Sroberto * Save the keyword, then walk through the arguments, interpreting 117454359Sroberto * as we go. 117554359Sroberto */ 117654359Sroberto pcmd.keyword = tokens[0]; 117754359Sroberto pcmd.nargs = 0; 1178132451Sroberto ti = 1; 1179132451Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) { 1180132451Sroberto if ((i+ti) >= ntok) { 118154359Sroberto if (!(xcmd->arg[i] & OPT)) { 118254359Sroberto printusage(xcmd, stderr); 118354359Sroberto return; 118454359Sroberto } 118554359Sroberto break; 118654359Sroberto } 1187132451Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>')) 1188132451Sroberto break; 1189132451Sroberto rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]); 1190132451Sroberto if (rval == -1) { 1191132451Sroberto ti++; 1192132451Sroberto continue; 1193132451Sroberto } 1194132451Sroberto if (rval == 0) 1195132451Sroberto return; 119654359Sroberto pcmd.nargs++; 1197132451Sroberto i++; 119854359Sroberto } 119954359Sroberto 1200182007Sroberto /* Any extra args are assumed to be "OPT|NTP_STR". */ 1201182007Sroberto for ( ; i < MAXARGS + MOREARGS;) { 1202182007Sroberto if ((i+ti) >= ntok) 1203182007Sroberto break; 1204182007Sroberto rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]); 1205182007Sroberto if (rval == -1) { 1206182007Sroberto ti++; 1207182007Sroberto continue; 1208182007Sroberto } 1209182007Sroberto if (rval == 0) 1210182007Sroberto return; 1211182007Sroberto pcmd.nargs++; 1212182007Sroberto i++; 1213182007Sroberto } 1214182007Sroberto 1215132451Sroberto i += ti; 121654359Sroberto if (i < ntok && *tokens[i] == '>') { 121754359Sroberto char *fname; 121854359Sroberto 121954359Sroberto if (*(tokens[i]+1) != '\0') 122054359Sroberto fname = tokens[i]+1; 122154359Sroberto else if ((i+1) < ntok) 122254359Sroberto fname = tokens[i+1]; 122354359Sroberto else { 122454359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 122554359Sroberto return; 122654359Sroberto } 122754359Sroberto 122854359Sroberto current_output = fopen(fname, "w"); 122954359Sroberto if (current_output == NULL) { 123054359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 123154359Sroberto perror(""); 123254359Sroberto return; 123354359Sroberto } 123454359Sroberto } else { 123554359Sroberto current_output = stdout; 123654359Sroberto } 123754359Sroberto 123854359Sroberto if (interactive && setjmp(interrupt_buf)) { 123954359Sroberto return; 124054359Sroberto } else { 124154359Sroberto jump = 1; 124254359Sroberto (xcmd->handler)(&pcmd, current_output); 124354359Sroberto jump = 0; 1244132451Sroberto if (current_output != stdout) 1245132451Sroberto (void) fclose(current_output); 1246132451Sroberto current_output = NULL; 124754359Sroberto } 124854359Sroberto} 124954359Sroberto 125054359Sroberto 125154359Sroberto/* 125254359Sroberto * tokenize - turn a command line into tokens 125354359Sroberto */ 125454359Srobertostatic void 125554359Srobertotokenize( 125654359Sroberto const char *line, 125754359Sroberto char **tokens, 125854359Sroberto int *ntok 125954359Sroberto ) 126054359Sroberto{ 126154359Sroberto register const char *cp; 126254359Sroberto register char *sp; 126354359Sroberto static char tspace[MAXLINE]; 126454359Sroberto 126554359Sroberto sp = tspace; 126654359Sroberto cp = line; 126754359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 126854359Sroberto tokens[*ntok] = sp; 126954359Sroberto while (ISSPACE(*cp)) 127054359Sroberto cp++; 127154359Sroberto if (ISEOL(*cp)) 127254359Sroberto break; 127354359Sroberto do { 127454359Sroberto *sp++ = *cp++; 127554359Sroberto } while (!ISSPACE(*cp) && !ISEOL(*cp)); 127654359Sroberto 127754359Sroberto *sp++ = '\0'; 127854359Sroberto } 127954359Sroberto} 128054359Sroberto 128154359Sroberto 128254359Sroberto 128354359Sroberto/* 128454359Sroberto * findcmd - find a command in a command description table 128554359Sroberto */ 128654359Srobertostatic int 128754359Srobertofindcmd( 128854359Sroberto register char *str, 128954359Sroberto struct xcmd *clist1, 129054359Sroberto struct xcmd *clist2, 129154359Sroberto struct xcmd **cmd 129254359Sroberto ) 129354359Sroberto{ 129454359Sroberto register struct xcmd *cl; 1295293894Sglebius size_t clen; 129654359Sroberto int nmatch; 129754359Sroberto struct xcmd *nearmatch = NULL; 129854359Sroberto struct xcmd *clist; 129954359Sroberto 130054359Sroberto clen = strlen(str); 130154359Sroberto nmatch = 0; 130254359Sroberto if (clist1 != 0) 130354359Sroberto clist = clist1; 130454359Sroberto else if (clist2 != 0) 130554359Sroberto clist = clist2; 130654359Sroberto else 130754359Sroberto return 0; 130854359Sroberto 130954359Sroberto again: 131054359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 131154359Sroberto /* do a first character check, for efficiency */ 131254359Sroberto if (*str != *(cl->keyword)) 131354359Sroberto continue; 131454359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 131554359Sroberto /* 131654359Sroberto * Could be extact match, could be approximate. 131754359Sroberto * Is exact if the length of the keyword is the 131854359Sroberto * same as the str. 131954359Sroberto */ 132054359Sroberto if (*((cl->keyword) + clen) == '\0') { 132154359Sroberto *cmd = cl; 132254359Sroberto return 1; 132354359Sroberto } 132454359Sroberto nmatch++; 132554359Sroberto nearmatch = cl; 132654359Sroberto } 132754359Sroberto } 132854359Sroberto 132954359Sroberto /* 133054359Sroberto * See if there is more to do. If so, go again. Sorry about the 133154359Sroberto * goto, too much looking at BSD sources... 133254359Sroberto */ 133354359Sroberto if (clist == clist1 && clist2 != 0) { 133454359Sroberto clist = clist2; 133554359Sroberto goto again; 133654359Sroberto } 133754359Sroberto 133854359Sroberto /* 133954359Sroberto * If we got extactly 1 near match, use it, else return number 134054359Sroberto * of matches. 134154359Sroberto */ 134254359Sroberto if (nmatch == 1) { 134354359Sroberto *cmd = nearmatch; 134454359Sroberto return 1; 134554359Sroberto } 134654359Sroberto return nmatch; 134754359Sroberto} 134854359Sroberto 134954359Sroberto 1350132451Sroberto/* 135154359Sroberto * getarg - interpret an argument token 1352132451Sroberto * 1353182007Sroberto * string is always set. 1354182007Sroberto * type is set to the decoded type. 1355182007Sroberto * 1356132451Sroberto * return: 0 - failure 1357132451Sroberto * 1 - success 1358132451Sroberto * -1 - skip to next token 135954359Sroberto */ 136054359Srobertostatic int 136154359Srobertogetarg( 136254359Sroberto char *str, 136354359Sroberto int code, 136454359Sroberto arg_v *argp 136554359Sroberto ) 136654359Sroberto{ 136754359Sroberto int isneg; 136854359Sroberto char *cp, *np; 136954359Sroberto static const char *digits = "0123456789"; 137054359Sroberto 1371290000Sglebius ZERO(*argp); 1372182007Sroberto argp->string = str; 1373182007Sroberto argp->type = code & ~OPT; 1374182007Sroberto 1375182007Sroberto switch (argp->type) { 137654359Sroberto case NTP_STR: 137754359Sroberto break; 1378182007Sroberto case NTP_ADD: 1379132451Sroberto if (!strcmp("-6", str)) { 1380132451Sroberto ai_fam_templ = AF_INET6; 1381132451Sroberto return -1; 1382132451Sroberto } else if (!strcmp("-4", str)) { 1383132451Sroberto ai_fam_templ = AF_INET; 1384132451Sroberto return -1; 1385132451Sroberto } 1386132451Sroberto if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) { 138754359Sroberto return 0; 138854359Sroberto } 138954359Sroberto break; 1390182007Sroberto case NTP_INT: 1391182007Sroberto case NTP_UINT: 139254359Sroberto isneg = 0; 139354359Sroberto np = str; 139454359Sroberto if (*np == '-') { 139554359Sroberto np++; 139654359Sroberto isneg = 1; 139754359Sroberto } 139854359Sroberto 139954359Sroberto argp->uval = 0; 140054359Sroberto do { 140154359Sroberto cp = strchr(digits, *np); 140254359Sroberto if (cp == NULL) { 140354359Sroberto (void) fprintf(stderr, 140454359Sroberto "***Illegal integer value %s\n", str); 140554359Sroberto return 0; 140654359Sroberto } 140754359Sroberto argp->uval *= 10; 1408293894Sglebius argp->uval += (u_long)(cp - digits); 140954359Sroberto } while (*(++np) != '\0'); 141054359Sroberto 141154359Sroberto if (isneg) { 1412182007Sroberto if ((code & ~OPT) == NTP_UINT) { 141354359Sroberto (void) fprintf(stderr, 141454359Sroberto "***Value %s should be unsigned\n", str); 141554359Sroberto return 0; 141654359Sroberto } 141754359Sroberto argp->ival = -argp->ival; 141854359Sroberto } 141954359Sroberto break; 1420132451Sroberto case IP_VERSION: 1421132451Sroberto if (!strcmp("-6", str)) 1422132451Sroberto argp->ival = 6 ; 1423132451Sroberto else if (!strcmp("-4", str)) 1424132451Sroberto argp->ival = 4 ; 1425132451Sroberto else { 1426132451Sroberto (void) fprintf(stderr, 1427132451Sroberto "***Version must be either 4 or 6\n"); 1428132451Sroberto return 0; 1429132451Sroberto } 1430132451Sroberto break; 143154359Sroberto } 143254359Sroberto 143354359Sroberto return 1; 143454359Sroberto} 143554359Sroberto 143654359Sroberto 143754359Sroberto/* 143854359Sroberto * getnetnum - given a host name, return its net number 143954359Sroberto * and (optional) full name 144054359Sroberto */ 144154359Srobertostatic int 144254359Srobertogetnetnum( 144354359Sroberto const char *hname, 1444290000Sglebius sockaddr_u *num, 1445132451Sroberto char *fullhost, 1446132451Sroberto int af 144754359Sroberto ) 144854359Sroberto{ 1449132451Sroberto struct addrinfo hints, *ai = NULL; 145054359Sroberto 1451290000Sglebius ZERO(hints); 1452132451Sroberto hints.ai_flags = AI_CANONNAME; 1453132451Sroberto#ifdef AI_ADDRCONFIG 1454132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1455132451Sroberto#endif 1456132451Sroberto 1457290000Sglebius /* 1458290000Sglebius * decodenetnum only works with addresses, but handles syntax 1459290000Sglebius * that getaddrinfo doesn't: [2001::1]:1234 1460290000Sglebius */ 146154359Sroberto if (decodenetnum(hname, num)) { 1462290000Sglebius if (fullhost != NULL) 1463290000Sglebius getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1464290000Sglebius LENHOSTNAME, NULL, 0, 0); 146554359Sroberto return 1; 1466182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1467290000Sglebius INSIST(sizeof(*num) >= ai->ai_addrlen); 1468290000Sglebius memcpy(num, ai->ai_addr, ai->ai_addrlen); 1469290000Sglebius if (fullhost != NULL) { 1470290000Sglebius if (ai->ai_canonname != NULL) 1471290000Sglebius strlcpy(fullhost, ai->ai_canonname, 1472290000Sglebius LENHOSTNAME); 1473290000Sglebius else 1474290000Sglebius getnameinfo(&num->sa, SOCKLEN(num), 1475290000Sglebius fullhost, LENHOSTNAME, NULL, 1476290000Sglebius 0, 0); 1477290000Sglebius } 147854359Sroberto return 1; 147954359Sroberto } 1480290000Sglebius fprintf(stderr, "***Can't find host %s\n", hname); 1481290000Sglebius 1482290000Sglebius return 0; 148354359Sroberto} 148454359Sroberto 1485290000Sglebius 148654359Sroberto/* 148754359Sroberto * nntohost - convert network number to host name. This routine enforces 148854359Sroberto * the showhostnames setting. 148954359Sroberto */ 1490290000Sglebiusconst char * 149154359Srobertonntohost( 1492290000Sglebius sockaddr_u *netnum 149354359Sroberto ) 149454359Sroberto{ 1495290000Sglebius if (!showhostnames || SOCK_UNSPEC(netnum)) 1496290000Sglebius return stoa(netnum); 1497290000Sglebius else if (ISREFCLOCKADR(netnum)) 1498132451Sroberto return refnumtoa(netnum); 1499290000Sglebius else 1500290000Sglebius return socktohost(netnum); 150154359Sroberto} 150254359Sroberto 150354359Sroberto 150454359Sroberto/* 150554359Sroberto * Finally, the built in command handlers 150654359Sroberto */ 150754359Sroberto 150854359Sroberto/* 150954359Sroberto * help - tell about commands, or details of a particular command 151054359Sroberto */ 151154359Srobertostatic void 151254359Srobertohelp( 151354359Sroberto struct parse *pcmd, 151454359Sroberto FILE *fp 151554359Sroberto ) 151654359Sroberto{ 151754359Sroberto struct xcmd *xcp; 151854359Sroberto char *cmd; 1519182007Sroberto const char *list[100]; 1520290000Sglebius size_t word, words; 1521290000Sglebius size_t row, rows; 1522290000Sglebius size_t col, cols; 1523290000Sglebius size_t length; 152454359Sroberto 152554359Sroberto if (pcmd->nargs == 0) { 1526182007Sroberto words = 0; 152754359Sroberto for (xcp = builtins; xcp->keyword != 0; xcp++) { 152854359Sroberto if (*(xcp->keyword) != '?') 1529290000Sglebius list[words++] = xcp->keyword; 153054359Sroberto } 1531290000Sglebius for (xcp = opcmds; xcp->keyword != 0; xcp++) 1532290000Sglebius list[words++] = xcp->keyword; 153354359Sroberto 1534290000Sglebius qsort((void *)list, words, sizeof(list[0]), helpsort); 1535182007Sroberto col = 0; 1536182007Sroberto for (word = 0; word < words; word++) { 1537290000Sglebius length = strlen(list[word]); 1538290000Sglebius col = max(col, length); 153954359Sroberto } 154054359Sroberto 1541182007Sroberto cols = SCREENWIDTH / ++col; 1542290000Sglebius rows = (words + cols - 1) / cols; 1543182007Sroberto 1544290000Sglebius fprintf(fp, "ntpdc commands:\n"); 1545182007Sroberto 1546182007Sroberto for (row = 0; row < rows; row++) { 1547290000Sglebius for (word = row; word < words; word += rows) 1548290000Sglebius fprintf(fp, "%-*.*s", (int)col, 1549290000Sglebius (int)col - 1, list[word]); 1550290000Sglebius fprintf(fp, "\n"); 155154359Sroberto } 155254359Sroberto } else { 155354359Sroberto cmd = pcmd->argval[0].string; 1554182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 1555182007Sroberto if (words == 0) { 1556290000Sglebius fprintf(stderr, 1557290000Sglebius "Command `%s' is unknown\n", cmd); 155854359Sroberto return; 1559182007Sroberto } else if (words >= 2) { 1560290000Sglebius fprintf(stderr, 1561290000Sglebius "Command `%s' is ambiguous\n", cmd); 156254359Sroberto return; 156354359Sroberto } 1564290000Sglebius fprintf(fp, "function: %s\n", xcp->comment); 156554359Sroberto printusage(xcp, fp); 156654359Sroberto } 156754359Sroberto} 156854359Sroberto 156954359Sroberto 157054359Sroberto/* 157154359Sroberto * helpsort - do hostname qsort comparisons 157254359Sroberto */ 157354359Srobertostatic int 157454359Srobertohelpsort( 157554359Sroberto const void *t1, 157654359Sroberto const void *t2 157754359Sroberto ) 157854359Sroberto{ 1579290000Sglebius const char * const * name1 = t1; 1580290000Sglebius const char * const * name2 = t2; 158154359Sroberto 158254359Sroberto return strcmp(*name1, *name2); 158354359Sroberto} 158454359Sroberto 158554359Sroberto 158654359Sroberto/* 158754359Sroberto * printusage - print usage information for a command 158854359Sroberto */ 158954359Srobertostatic void 159054359Srobertoprintusage( 159154359Sroberto struct xcmd *xcp, 159254359Sroberto FILE *fp 159354359Sroberto ) 159454359Sroberto{ 1595132451Sroberto int i, opt46; 159654359Sroberto 1597132451Sroberto opt46 = 0; 159854359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 159954359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 1600182007Sroberto if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) { 1601132451Sroberto (void) fprintf(fp, " [ -4|-6 ]"); 1602132451Sroberto opt46 = 1; 1603132451Sroberto } 160454359Sroberto if (xcp->arg[i] & OPT) 160554359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 160654359Sroberto else 160754359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 160854359Sroberto } 160954359Sroberto (void) fprintf(fp, "\n"); 161054359Sroberto} 161154359Sroberto 161254359Sroberto 161354359Sroberto/* 161454359Sroberto * timeout - set time out time 161554359Sroberto */ 161654359Srobertostatic void 161754359Srobertotimeout( 161854359Sroberto struct parse *pcmd, 161954359Sroberto FILE *fp 162054359Sroberto ) 162154359Sroberto{ 162254359Sroberto int val; 162354359Sroberto 162454359Sroberto if (pcmd->nargs == 0) { 162554359Sroberto val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 162654359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 162754359Sroberto } else { 162854359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 162954359Sroberto tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) 163054359Sroberto * 1000; 163154359Sroberto } 163254359Sroberto} 163354359Sroberto 163454359Sroberto 163554359Sroberto/* 163654359Sroberto * my_delay - set delay for auth requests 163754359Sroberto */ 163854359Srobertostatic void 163954359Srobertomy_delay( 164054359Sroberto struct parse *pcmd, 164154359Sroberto FILE *fp 164254359Sroberto ) 164354359Sroberto{ 164454359Sroberto int isneg; 164554359Sroberto u_long val; 164654359Sroberto 164754359Sroberto if (pcmd->nargs == 0) { 164854359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 164954359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 165054359Sroberto } else { 165154359Sroberto if (pcmd->argval[0].ival < 0) { 165254359Sroberto isneg = 1; 165354359Sroberto val = (u_long)(-pcmd->argval[0].ival); 165454359Sroberto } else { 165554359Sroberto isneg = 0; 165654359Sroberto val = (u_long)pcmd->argval[0].ival; 165754359Sroberto } 165854359Sroberto 165954359Sroberto delay_time.l_ui = val / 1000; 166054359Sroberto val %= 1000; 166154359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 166254359Sroberto 166354359Sroberto if (isneg) 166454359Sroberto L_NEG(&delay_time); 166554359Sroberto } 166654359Sroberto} 166754359Sroberto 166854359Sroberto 166954359Sroberto/* 167054359Sroberto * host - set the host we are dealing with. 167154359Sroberto */ 167254359Srobertostatic void 167354359Srobertohost( 167454359Sroberto struct parse *pcmd, 167554359Sroberto FILE *fp 167654359Sroberto ) 167754359Sroberto{ 1678132451Sroberto int i; 1679132451Sroberto 168054359Sroberto if (pcmd->nargs == 0) { 168154359Sroberto if (havehost) 168254359Sroberto (void) fprintf(fp, "current host is %s\n", currenthost); 168354359Sroberto else 168454359Sroberto (void) fprintf(fp, "no current host\n"); 1685132451Sroberto return; 1686132451Sroberto } 1687132451Sroberto 1688132451Sroberto i = 0; 1689132451Sroberto if (pcmd->nargs == 2) { 1690132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 1691132451Sroberto ai_fam_templ = AF_INET; 1692132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 1693132451Sroberto ai_fam_templ = AF_INET6; 1694132451Sroberto else { 1695132451Sroberto if (havehost) 1696132451Sroberto (void) fprintf(fp, 1697132451Sroberto "current host remains %s\n", currenthost); 1698132451Sroberto else 1699132451Sroberto (void) fprintf(fp, "still no current host\n"); 1700132451Sroberto return; 1701132451Sroberto } 1702132451Sroberto i = 1; 1703132451Sroberto } 1704132451Sroberto if (openhost(pcmd->argval[i].string)) { 170554359Sroberto (void) fprintf(fp, "current host set to %s\n", currenthost); 170654359Sroberto } else { 170754359Sroberto if (havehost) 170854359Sroberto (void) fprintf(fp, 170954359Sroberto "current host remains %s\n", currenthost); 171054359Sroberto else 171154359Sroberto (void) fprintf(fp, "still no current host\n"); 171254359Sroberto } 171354359Sroberto} 171454359Sroberto 171554359Sroberto 171654359Sroberto/* 171754359Sroberto * keyid - get a keyid to use for authenticating requests 171854359Sroberto */ 171954359Srobertostatic void 172054359Srobertokeyid( 172154359Sroberto struct parse *pcmd, 172254359Sroberto FILE *fp 172354359Sroberto ) 172454359Sroberto{ 172554359Sroberto if (pcmd->nargs == 0) { 1726182007Sroberto if (info_auth_keyid == 0 && !keyid_entered) 172754359Sroberto (void) fprintf(fp, "no keyid defined\n"); 1728182007Sroberto else if (info_auth_keyid == 0 && keyid_entered) 1729182007Sroberto (void) fprintf(fp, "no keyid will be sent\n"); 173054359Sroberto else 173154359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 173254359Sroberto } else { 173354359Sroberto info_auth_keyid = pcmd->argval[0].uval; 1734182007Sroberto keyid_entered = 1; 173554359Sroberto } 173654359Sroberto} 173754359Sroberto 173854359Sroberto 173954359Sroberto/* 174054359Sroberto * keytype - get type of key to use for authenticating requests 174154359Sroberto */ 174254359Srobertostatic void 174354359Srobertokeytype( 174454359Sroberto struct parse *pcmd, 174554359Sroberto FILE *fp 174654359Sroberto ) 174754359Sroberto{ 1748290000Sglebius const char * digest_name; 1749290000Sglebius size_t digest_len; 1750290000Sglebius int key_type; 175154359Sroberto 1752290000Sglebius if (!pcmd->nargs) { 1753290000Sglebius fprintf(fp, "keytype is %s with %lu octet digests\n", 1754290000Sglebius keytype_name(info_auth_keytype), 1755290000Sglebius (u_long)info_auth_hashlen); 1756290000Sglebius return; 1757290000Sglebius } 1758290000Sglebius 1759290000Sglebius digest_name = pcmd->argval[0].string; 1760290000Sglebius digest_len = 0; 1761290000Sglebius key_type = keytype_from_text(digest_name, &digest_len); 1762290000Sglebius 1763290000Sglebius if (!key_type) { 1764290000Sglebius fprintf(fp, "keytype must be 'md5'%s\n", 1765290000Sglebius#ifdef OPENSSL 1766290000Sglebius " or a digest type provided by OpenSSL"); 1767290000Sglebius#else 1768290000Sglebius ""); 1769290000Sglebius#endif 1770290000Sglebius return; 1771290000Sglebius } 1772290000Sglebius 1773290000Sglebius info_auth_keytype = key_type; 1774290000Sglebius info_auth_hashlen = digest_len; 177554359Sroberto} 177654359Sroberto 177754359Sroberto 177854359Sroberto/* 177954359Sroberto * passwd - get an authentication key 178054359Sroberto */ 178154359Sroberto/*ARGSUSED*/ 178254359Srobertostatic void 178354359Srobertopasswd( 178454359Sroberto struct parse *pcmd, 178554359Sroberto FILE *fp 178654359Sroberto ) 178754359Sroberto{ 178854359Sroberto char *pass; 178954359Sroberto 179054359Sroberto if (info_auth_keyid == 0) { 179154359Sroberto info_auth_keyid = getkeyid("Keyid: "); 179254359Sroberto if (info_auth_keyid == 0) { 179354359Sroberto (void)fprintf(fp, "Keyid must be defined\n"); 179454359Sroberto return; 179554359Sroberto } 179654359Sroberto } 1797290000Sglebius if (pcmd->nargs >= 1) 1798290000Sglebius pass = pcmd->argval[0].string; 1799290000Sglebius else { 1800290000Sglebius pass = getpass_keytype(info_auth_keytype); 1801290000Sglebius if ('\0' == *pass) { 1802290000Sglebius fprintf(fp, "Password unchanged\n"); 1803290000Sglebius return; 180482498Sroberto } 180554359Sroberto } 1806290000Sglebius authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); 1807290000Sglebius authtrust(info_auth_keyid, 1); 180854359Sroberto} 180954359Sroberto 181054359Sroberto 181154359Sroberto/* 181254359Sroberto * hostnames - set the showhostnames flag 181354359Sroberto */ 181454359Srobertostatic void 181554359Srobertohostnames( 181654359Sroberto struct parse *pcmd, 181754359Sroberto FILE *fp 181854359Sroberto ) 181954359Sroberto{ 182054359Sroberto if (pcmd->nargs == 0) { 182154359Sroberto if (showhostnames) 182254359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 182354359Sroberto else 182454359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 182554359Sroberto } else { 182654359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 182754359Sroberto showhostnames = 1; 182854359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 182954359Sroberto showhostnames = 0; 183054359Sroberto else 183154359Sroberto (void)fprintf(stderr, "What?\n"); 183254359Sroberto } 183354359Sroberto} 183454359Sroberto 183554359Sroberto 183654359Sroberto/* 183754359Sroberto * setdebug - set/change debugging level 183854359Sroberto */ 183954359Srobertostatic void 184054359Srobertosetdebug( 184154359Sroberto struct parse *pcmd, 184254359Sroberto FILE *fp 184354359Sroberto ) 184454359Sroberto{ 184554359Sroberto if (pcmd->nargs == 0) { 184654359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 184754359Sroberto return; 184854359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 184954359Sroberto debug = 0; 185054359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 185154359Sroberto debug++; 185254359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 185354359Sroberto debug--; 185454359Sroberto } else { 185554359Sroberto (void) fprintf(fp, "What?\n"); 185654359Sroberto return; 185754359Sroberto } 185854359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 185954359Sroberto} 186054359Sroberto 186154359Sroberto 186254359Sroberto/* 186354359Sroberto * quit - stop this nonsense 186454359Sroberto */ 186554359Sroberto/*ARGSUSED*/ 186654359Srobertostatic void 186754359Srobertoquit( 186854359Sroberto struct parse *pcmd, 186954359Sroberto FILE *fp 187054359Sroberto ) 187154359Sroberto{ 187254359Sroberto if (havehost) 187354359Sroberto closesocket(sockfd); 187454359Sroberto exit(0); 187554359Sroberto} 187654359Sroberto 187754359Sroberto 187854359Sroberto/* 187954359Sroberto * version - print the current version number 188054359Sroberto */ 188154359Sroberto/*ARGSUSED*/ 188254359Srobertostatic void 188354359Srobertoversion( 188454359Sroberto struct parse *pcmd, 188554359Sroberto FILE *fp 188654359Sroberto ) 188754359Sroberto{ 188854359Sroberto 188954359Sroberto (void) fprintf(fp, "%s\n", Version); 189054359Sroberto return; 189154359Sroberto} 189254359Sroberto 189354359Sroberto 1894290000Sglebiusstatic void __attribute__((__format__(__printf__, 1, 0))) 1895290000Sglebiusvwarning(const char *fmt, va_list ap) 1896290000Sglebius{ 1897290000Sglebius int serrno = errno; 1898290000Sglebius (void) fprintf(stderr, "%s: ", progname); 1899290000Sglebius vfprintf(stderr, fmt, ap); 1900290000Sglebius (void) fprintf(stderr, ": %s\n", strerror(serrno)); 1901290000Sglebius} 1902290000Sglebius 190354359Sroberto/* 190454359Sroberto * warning - print a warning message 190554359Sroberto */ 1906290000Sglebiusstatic void __attribute__((__format__(__printf__, 1, 2))) 190754359Srobertowarning( 190854359Sroberto const char *fmt, 1909290000Sglebius ... 191054359Sroberto ) 191154359Sroberto{ 1912290000Sglebius va_list ap; 1913290000Sglebius va_start(ap, fmt); 1914290000Sglebius vwarning(fmt, ap); 1915290000Sglebius va_end(ap); 191654359Sroberto} 191754359Sroberto 191854359Sroberto 191954359Sroberto/* 192054359Sroberto * error - print a message and exit 192154359Sroberto */ 1922290000Sglebiusstatic void __attribute__((__format__(__printf__, 1, 2))) 192354359Srobertoerror( 192454359Sroberto const char *fmt, 1925290000Sglebius ... 192654359Sroberto ) 192754359Sroberto{ 1928290000Sglebius va_list ap; 1929290000Sglebius va_start(ap, fmt); 1930290000Sglebius vwarning(fmt, ap); 1931290000Sglebius va_end(ap); 193254359Sroberto exit(1); 193354359Sroberto} 193454359Sroberto 193554359Sroberto/* 193654359Sroberto * getkeyid - prompt the user for a keyid to use 193754359Sroberto */ 193854359Srobertostatic u_long 193954359Srobertogetkeyid( 194054359Sroberto const char *keyprompt 194154359Sroberto ) 194254359Sroberto{ 1943290000Sglebius int c; 194454359Sroberto FILE *fi; 194554359Sroberto char pbuf[20]; 1946290000Sglebius size_t i; 1947290000Sglebius size_t ilim; 194854359Sroberto 194954359Sroberto#ifndef SYS_WINNT 195054359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 195154359Sroberto#else 1952290000Sglebius if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 195354359Sroberto#endif /* SYS_WINNT */ 195454359Sroberto fi = stdin; 1955290000Sglebius else 195654359Sroberto setbuf(fi, (char *)NULL); 195754359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 1958290000Sglebius for (i = 0, ilim = COUNTOF(pbuf) - 1; 1959290000Sglebius i < ilim && (c = getc(fi)) != '\n' && c != EOF; 1960290000Sglebius ) 1961290000Sglebius pbuf[i++] = (char)c; 1962290000Sglebius pbuf[i] = '\0'; 196354359Sroberto if (fi != stdin) 1964290000Sglebius fclose(fi); 1965290000Sglebius 1966290000Sglebius return (u_long) atoi(pbuf); 196754359Sroberto} 1968