154359Sroberto/* 254359Sroberto * ntpdc - control and monitor your ntpd daemon 354359Sroberto */ 4285612Sdelphij#include <config.h> 554359Sroberto#include <stdio.h> 6285612Sdelphij#include <stddef.h> 7182007Sroberto#include <ctype.h> 8182007Sroberto#include <signal.h> 9182007Sroberto#include <setjmp.h> 10285612Sdelphij#ifdef HAVE_UNISTD_H 11285612Sdelphij# include <unistd.h> 12285612Sdelphij#endif 13285612Sdelphij#ifdef HAVE_FCNTL_H 14285612Sdelphij# include <fcntl.h> 15285612Sdelphij#endif 16285612Sdelphij#ifdef SYS_WINNT 17285612Sdelphij# include <mswsock.h> 18285612Sdelphij#endif 19285612Sdelphij#include <isc/net.h> 20285612Sdelphij#include <isc/result.h> 21182007Sroberto 2282498Sroberto#include "ntpdc.h" 2382498Sroberto#include "ntp_select.h" 2482498Sroberto#include "ntp_stdlib.h" 25285612Sdelphij#include "ntp_assert.h" 26285612Sdelphij#include "ntp_lineedit.h" 27285612Sdelphij#ifdef OPENSSL 28285612Sdelphij#include "openssl/evp.h" 29285612Sdelphij#include "openssl/objects.h" 30285612Sdelphij#endif 31285612Sdelphij#include <ssl_applink.c> 3282498Sroberto 33285612Sdelphij#include "ntp_libopts.h" 34182007Sroberto#include "ntpdc-opts.h" 35293650Sglebius#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 62285612Sdelphijstatic int info_auth_keytype = NID_md5; /* MD5 */ 63285612Sdelphijstatic 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 71285612Sdelphijint ntpdcmain (int, char **); 7254359Sroberto/* 7354359Sroberto * Built in command handler declarations 7454359Sroberto */ 75285612Sdelphijstatic int openhost (const char *); 76285612Sdelphijstatic int sendpkt (void *, size_t); 77285612Sdelphijstatic void growpktdata (void); 78293650Sglebiusstatic int getresponse (int, int, size_t *, size_t *, const char **, size_t); 79293650Sglebiusstatic int sendrequest (int, int, int, size_t, size_t, const char *); 80285612Sdelphijstatic void getcmds (void); 81285612Sdelphijstatic RETSIGTYPE abortcmd (int); 82285612Sdelphijstatic void docmd (const char *); 83285612Sdelphijstatic void tokenize (const char *, char **, int *); 84285612Sdelphijstatic int findcmd (char *, struct xcmd *, struct xcmd *, struct xcmd **); 85285612Sdelphijstatic int getarg (char *, int, arg_v *); 86285612Sdelphijstatic int getnetnum (const char *, sockaddr_u *, char *, int); 87285612Sdelphijstatic void help (struct parse *, FILE *); 88285612Sdelphijstatic int helpsort (const void *, const void *); 89285612Sdelphijstatic void printusage (struct xcmd *, FILE *); 90285612Sdelphijstatic void timeout (struct parse *, FILE *); 91285612Sdelphijstatic void my_delay (struct parse *, FILE *); 92285612Sdelphijstatic void host (struct parse *, FILE *); 93285612Sdelphijstatic void keyid (struct parse *, FILE *); 94285612Sdelphijstatic void keytype (struct parse *, FILE *); 95285612Sdelphijstatic void passwd (struct parse *, FILE *); 96285612Sdelphijstatic void hostnames (struct parse *, FILE *); 97285612Sdelphijstatic void setdebug (struct parse *, FILE *); 98285612Sdelphijstatic void quit (struct parse *, FILE *); 99285612Sdelphijstatic void version (struct parse *, FILE *); 100285612Sdelphijstatic void warning (const char *, ...) 101285612Sdelphij __attribute__((__format__(__printf__, 1, 2))); 102285612Sdelphijstatic void error (const char *, ...) 103285612Sdelphij __attribute__((__format__(__printf__, 1, 2))); 104285612Sdelphijstatic 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 */ 159285612Sdelphij#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 */ 173285612Sdelphijstatic struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 174285612Sdelphijstatic 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/* 229338531Sdelphij * Jump buffer for longjumping back to the command level. 230338531Sdelphij * 231338531Sdelphij * See ntpq/ntpq.c for an explanation why 'sig{set,long}jmp()' is used 232338531Sdelphij * when available. 23354359Sroberto */ 234338531Sdelphij#if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP 235338531Sdelphij# define JMP_BUF sigjmp_buf 236338531Sdelphij# define SETJMP(x) sigsetjmp((x), 1) 237338531Sdelphij# define LONGJMP(x, v) siglongjmp((x),(v)) 238338531Sdelphij#else 239338531Sdelphij# define JMP_BUF jmp_buf 240338531Sdelphij# define SETJMP(x) setjmp((x)) 241338531Sdelphij# define LONGJMP(x, v) longjmp((x),(v)) 242338531Sdelphij#endif 243338531Sdelphijstatic JMP_BUF interrupt_buf; 244338531Sdelphijstatic volatile int jump = 0; 24554359Sroberto 24654359Sroberto/* 24754359Sroberto * Pointer to current output unit 24854359Sroberto */ 249338531Sdelphijstatic FILE *current_output = NULL; 25054359Sroberto 25154359Sroberto/* 25254359Sroberto * Command table imported from ntpdc_ops.c 25354359Sroberto */ 25454359Srobertoextern struct xcmd opcmds[]; 25554359Sroberto 256289997Sglebiuschar const *progname; 25754359Sroberto 25854359Sroberto#ifdef NO_MAIN_ALLOWED 25954359SrobertoCALL(ntpdc,"ntpdc",ntpdcmain); 26054359Sroberto#else 26154359Srobertoint 26254359Srobertomain( 26354359Sroberto int argc, 26454359Sroberto char *argv[] 26554359Sroberto ) 26654359Sroberto{ 26754359Sroberto return ntpdcmain(argc, argv); 26854359Sroberto} 26954359Sroberto#endif 27054359Sroberto 27154359Sroberto#ifdef SYS_VXWORKS 27254359Srobertovoid clear_globals(void) 27354359Sroberto{ 27454359Sroberto showhostnames = 0; /* show host names by default */ 27554359Sroberto havehost = 0; /* set to 1 when host open */ 27654359Sroberto numcmds = 0; 27754359Sroberto numhosts = 0; 27854359Sroberto} 27954359Sroberto#endif 28054359Sroberto 28154359Sroberto/* 28254359Sroberto * main - parse arguments and handle options 28354359Sroberto */ 28454359Srobertoint 28554359Srobertontpdcmain( 28654359Sroberto int argc, 28754359Sroberto char *argv[] 28854359Sroberto ) 28954359Sroberto{ 29054359Sroberto delay_time.l_ui = 0; 29154359Sroberto delay_time.l_uf = DEFDELAY; 29254359Sroberto 29354359Sroberto#ifdef SYS_VXWORKS 29454359Sroberto clear_globals(); 29554359Sroberto taskPrioritySet(taskIdSelf(), 100 ); 29654359Sroberto#endif 29754359Sroberto 298285612Sdelphij init_lib(); /* sets up ipv4_works, ipv6_works */ 299285612Sdelphij ssl_applink(); 300285612Sdelphij init_auth(); 301132451Sroberto 302285612Sdelphij /* Check to see if we have IPv6. Otherwise default to IPv4 */ 303285612Sdelphij if (!ipv6_works) 304132451Sroberto ai_fam_default = AF_INET; 305132451Sroberto 30654359Sroberto progname = argv[0]; 307182007Sroberto 308182007Sroberto { 309285612Sdelphij int optct = ntpOptionProcess(&ntpdcOptions, argc, argv); 310182007Sroberto argc -= optct; 311182007Sroberto argv += optct; 312182007Sroberto } 313182007Sroberto 314285612Sdelphij if (HAVE_OPT(IPV4)) 315182007Sroberto ai_fam_templ = AF_INET; 316285612Sdelphij else if (HAVE_OPT(IPV6)) 317182007Sroberto ai_fam_templ = AF_INET6; 318285612Sdelphij else 319182007Sroberto ai_fam_templ = ai_fam_default; 320182007Sroberto 321182007Sroberto if (HAVE_OPT(COMMAND)) { 322182007Sroberto int cmdct = STACKCT_OPT( COMMAND ); 323182007Sroberto const char** cmds = STACKLST_OPT( COMMAND ); 324182007Sroberto 325182007Sroberto while (cmdct-- > 0) { 326182007Sroberto ADDCMD(*cmds++); 327182007Sroberto } 328182007Sroberto } 329182007Sroberto 330285612Sdelphij debug = OPT_VALUE_SET_DEBUG_LEVEL; 331182007Sroberto 332182007Sroberto if (HAVE_OPT(INTERACTIVE)) { 333182007Sroberto interactive = 1; 334182007Sroberto } 335182007Sroberto 336182007Sroberto if (HAVE_OPT(NUMERIC)) { 337182007Sroberto showhostnames = 0; 338182007Sroberto } 339182007Sroberto 340182007Sroberto if (HAVE_OPT(LISTPEERS)) { 341182007Sroberto ADDCMD("listpeers"); 342182007Sroberto } 343182007Sroberto 344182007Sroberto if (HAVE_OPT(PEERS)) { 345182007Sroberto ADDCMD("peers"); 346182007Sroberto } 347182007Sroberto 348182007Sroberto if (HAVE_OPT(SHOWPEERS)) { 349182007Sroberto ADDCMD("dmpeers"); 350182007Sroberto } 351182007Sroberto 352182007Sroberto if (ntp_optind == argc) { 353182007Sroberto ADDHOST(DEFHOST); 354182007Sroberto } else { 355182007Sroberto for (; ntp_optind < argc; ntp_optind++) 356182007Sroberto ADDHOST(argv[ntp_optind]); 357182007Sroberto } 358182007Sroberto 359182007Sroberto if (numcmds == 0 && interactive == 0 360182007Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 361182007Sroberto interactive = 1; 362182007Sroberto } 363182007Sroberto 36454359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 36554359Sroberto if (interactive) 366338531Sdelphij (void) signal_no_reset(SIGINT, abortcmd); 36754359Sroberto#endif /* SYS_WINNT */ 36854359Sroberto 36954359Sroberto /* 37054359Sroberto * Initialize the packet data buffer 37154359Sroberto */ 37254359Sroberto pktdatasize = INITDATASIZE; 373285612Sdelphij pktdata = emalloc(INITDATASIZE); 37454359Sroberto 37554359Sroberto if (numcmds == 0) { 37654359Sroberto (void) openhost(chosts[0]); 37754359Sroberto getcmds(); 37854359Sroberto } else { 37954359Sroberto int ihost; 38054359Sroberto int icmd; 38154359Sroberto 38254359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 38354359Sroberto if (openhost(chosts[ihost])) 38454359Sroberto for (icmd = 0; icmd < numcmds; icmd++) { 38554359Sroberto if (numhosts > 1) 38654359Sroberto printf ("--- %s ---\n",chosts[ihost]); 38754359Sroberto docmd(ccmds[icmd]); 38854359Sroberto } 38954359Sroberto } 39054359Sroberto } 39154359Sroberto#ifdef SYS_WINNT 39254359Sroberto WSACleanup(); 39354359Sroberto#endif 39454359Sroberto return(0); 39554359Sroberto} /* main end */ 39654359Sroberto 39754359Sroberto 39854359Sroberto/* 39954359Sroberto * openhost - open a socket to a host 40054359Sroberto */ 40154359Srobertostatic int 40254359Srobertoopenhost( 40354359Sroberto const char *hname 40454359Sroberto ) 40554359Sroberto{ 40654359Sroberto char temphost[LENHOSTNAME]; 407338531Sdelphij int a_info; 408132451Sroberto struct addrinfo hints, *ai = NULL; 409285612Sdelphij sockaddr_u addr; 410285612Sdelphij size_t octets; 411338531Sdelphij const char *cp; 412132451Sroberto char name[LENHOSTNAME]; 413132451Sroberto char service[5]; 41454359Sroberto 415132451Sroberto /* 416132451Sroberto * We need to get by the [] if they were entered 417132451Sroberto */ 418338531Sdelphij if (*hname == '[') { 419338531Sdelphij cp = strchr(hname + 1, ']'); 420338531Sdelphij if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) { 421338531Sdelphij errno = EINVAL; 422338531Sdelphij warning("%s", "bad hostname/address"); 423285612Sdelphij return 0; 424285612Sdelphij } 425338531Sdelphij memcpy(name, hname + 1, octets); 426338531Sdelphij name[octets] = '\0'; 427338531Sdelphij hname = name; 428338531Sdelphij } 429132451Sroberto 430132451Sroberto /* 431132451Sroberto * First try to resolve it as an ip address and if that fails, 432132451Sroberto * do a fullblown (dns) lookup. That way we only use the dns 433132451Sroberto * when it is needed and work around some implementations that 434132451Sroberto * will return an "IPv4-mapped IPv6 address" address if you 435132451Sroberto * give it an IPv4 address to lookup. 436132451Sroberto */ 437285612Sdelphij strlcpy(service, "ntp", sizeof(service)); 438285612Sdelphij ZERO(hints); 439132451Sroberto hints.ai_family = ai_fam_templ; 440132451Sroberto hints.ai_protocol = IPPROTO_UDP; 441132451Sroberto hints.ai_socktype = SOCK_DGRAM; 442285612Sdelphij hints.ai_flags = Z_AI_NUMERICHOST; 443132451Sroberto 444132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 445182007Sroberto if (a_info == EAI_NONAME 446182007Sroberto#ifdef EAI_NODATA 447182007Sroberto || a_info == EAI_NODATA 448182007Sroberto#endif 449182007Sroberto ) { 450132451Sroberto hints.ai_flags = AI_CANONNAME; 451132451Sroberto#ifdef AI_ADDRCONFIG 452132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 453132451Sroberto#endif 454132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 45554359Sroberto } 456132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 457132451Sroberto if (a_info == EAI_BADFLAGS) { 458132451Sroberto hints.ai_flags = AI_CANONNAME; 459132451Sroberto a_info = getaddrinfo(hname, service, &hints, &ai); 460132451Sroberto } 461132451Sroberto if (a_info != 0) { 462285612Sdelphij fprintf(stderr, "%s\n", gai_strerror(a_info)); 463182007Sroberto if (ai != NULL) 464182007Sroberto freeaddrinfo(ai); 465132451Sroberto return 0; 466132451Sroberto } 46754359Sroberto 468285612Sdelphij /* 469285612Sdelphij * getaddrinfo() has returned without error so ai should not 470285612Sdelphij * be NULL. 471285612Sdelphij */ 472285612Sdelphij INSIST(ai != NULL); 473285612Sdelphij ZERO(addr); 474285612Sdelphij octets = min(sizeof(addr), ai->ai_addrlen); 475285612Sdelphij memcpy(&addr, ai->ai_addr, octets); 476132451Sroberto 477285612Sdelphij if (ai->ai_canonname == NULL) 478285612Sdelphij strlcpy(temphost, stoa(&addr), sizeof(temphost)); 479285612Sdelphij else 480285612Sdelphij strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 481285612Sdelphij 48254359Sroberto if (debug > 2) 483285612Sdelphij printf("Opening host %s\n", temphost); 48454359Sroberto 48554359Sroberto if (havehost == 1) { 48654359Sroberto if (debug > 2) 487285612Sdelphij printf("Closing old host %s\n", currenthost); 488285612Sdelphij closesocket(sockfd); 48954359Sroberto havehost = 0; 49054359Sroberto } 491285612Sdelphij strlcpy(currenthost, temphost, sizeof(currenthost)); 492132451Sroberto 493132451Sroberto /* port maps to the same in both families */ 494285612Sdelphij s_port = NSRCPORT(&addr);; 495132451Sroberto#ifdef SYS_VXWORKS 496132451Sroberto ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 497132451Sroberto if (ai->ai_family == AF_INET) 498132451Sroberto *(struct sockaddr_in *)&hostaddr= 499132451Sroberto *((struct sockaddr_in *)ai->ai_addr); 500132451Sroberto else 501132451Sroberto *(struct sockaddr_in6 *)&hostaddr= 502132451Sroberto *((struct sockaddr_in6 *)ai->ai_addr); 503132451Sroberto#endif /* SYS_VXWORKS */ 50454359Sroberto 50554359Sroberto#ifdef SYS_WINNT 50654359Sroberto { 50754359Sroberto int optionValue = SO_SYNCHRONOUS_NONALERT; 50854359Sroberto int err; 509182007Sroberto 510330141Sdelphij err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (void *)&optionValue, sizeof(optionValue)); 51154359Sroberto if (err != NO_ERROR) { 51254359Sroberto (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); 51354359Sroberto exit(1); 51454359Sroberto } 51554359Sroberto } 516285612Sdelphij#endif /* SYS_WINNT */ 517132451Sroberto 518132451Sroberto sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); 51954359Sroberto if (sockfd == INVALID_SOCKET) { 520285612Sdelphij error("socket"); 52154359Sroberto exit(-1); 52254359Sroberto } 52354359Sroberto 52454359Sroberto#ifdef NEED_RCVBUF_SLOP 52554359Sroberto# ifdef SO_RCVBUF 52654359Sroberto { 52754359Sroberto int rbufsize = INITDATASIZE + 2048; /* 2K for slop */ 52854359Sroberto 52954359Sroberto if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 530330141Sdelphij (void *)&rbufsize, sizeof(int)) == -1) 531285612Sdelphij error("setsockopt"); 53254359Sroberto } 53354359Sroberto# endif 53454359Sroberto#endif 53554359Sroberto 536132451Sroberto#ifdef SYS_VXWORKS 537132451Sroberto if (connect(sockfd, (struct sockaddr *)&hostaddr, 538293650Sglebius sizeof(hostaddr)) == -1) 539132451Sroberto#else 540293650Sglebius if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == -1) 541132451Sroberto#endif /* SYS_VXWORKS */ 542293650Sglebius { 543285612Sdelphij error("connect"); 544285612Sdelphij exit(-1); 545285612Sdelphij } 546285612Sdelphij 547285612Sdelphij freeaddrinfo(ai); 54854359Sroberto havehost = 1; 549106163Sroberto req_pkt_size = REQ_LEN_NOMAC; 550132451Sroberto impl_ver = IMPL_XNTPD; 55154359Sroberto return 1; 55254359Sroberto} 55354359Sroberto 55454359Sroberto 55554359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 55654359Sroberto/* 55754359Sroberto * sendpkt - send a packet to the remote host 55854359Sroberto */ 55954359Srobertostatic int 56054359Srobertosendpkt( 561285612Sdelphij void * xdata, 562285612Sdelphij size_t xdatalen 56354359Sroberto ) 56454359Sroberto{ 565285612Sdelphij if (send(sockfd, xdata, xdatalen, 0) == -1) { 566285612Sdelphij warning("write to %s failed", currenthost); 56754359Sroberto return -1; 56854359Sroberto } 56954359Sroberto 57054359Sroberto return 0; 57154359Sroberto} 57254359Sroberto 57354359Sroberto 57454359Sroberto/* 57554359Sroberto * growpktdata - grow the packet data area 57654359Sroberto */ 57754359Srobertostatic void 57854359Srobertogrowpktdata(void) 57954359Sroberto{ 580285612Sdelphij size_t priorsz; 581285612Sdelphij 582285612Sdelphij priorsz = (size_t)pktdatasize; 58354359Sroberto pktdatasize += INCDATASIZE; 584285612Sdelphij pktdata = erealloc_zero(pktdata, (size_t)pktdatasize, priorsz); 58554359Sroberto} 58654359Sroberto 58754359Sroberto 58854359Sroberto/* 58954359Sroberto * getresponse - get a (series of) response packet(s) and return the data 59054359Sroberto */ 59154359Srobertostatic int 59254359Srobertogetresponse( 59354359Sroberto int implcode, 59454359Sroberto int reqcode, 595293650Sglebius size_t *ritems, 596293650Sglebius size_t *rsize, 597293650Sglebius const char **rdata, 598293650Sglebius size_t esize 59954359Sroberto ) 60054359Sroberto{ 60154359Sroberto struct resp_pkt rpkt; 602285612Sdelphij struct sock_timeval tvo; 603293650Sglebius size_t items; 604293650Sglebius size_t i; 605293650Sglebius size_t size; 606293650Sglebius size_t datasize; 60754359Sroberto char *datap; 608132451Sroberto char *tmp_data; 60954359Sroberto char haveseq[MAXSEQ+1]; 61054359Sroberto int firstpkt; 61154359Sroberto int lastseq; 61254359Sroberto int numrecv; 61354359Sroberto int seq; 61454359Sroberto fd_set fds; 615285612Sdelphij ssize_t n; 616294569Sdelphij int pad; 617294569Sdelphij /* absolute timeout checks. Not 'time_t' by intention! */ 618294569Sdelphij uint32_t tobase; /* base value for timeout */ 619294569Sdelphij uint32_t tospan; /* timeout span (max delay) */ 620294569Sdelphij uint32_t todiff; /* current delay */ 62154359Sroberto 62254359Sroberto /* 62354359Sroberto * This is pretty tricky. We may get between 1 and many packets 62454359Sroberto * back in response to the request. We peel the data out of 62554359Sroberto * each packet and collect it in one long block. When the last 62654359Sroberto * packet in the sequence is received we'll know how many we 62754359Sroberto * should have had. Note we use one long time out, should reconsider. 62854359Sroberto */ 62954359Sroberto *ritems = 0; 63054359Sroberto *rsize = 0; 63154359Sroberto firstpkt = 1; 63254359Sroberto numrecv = 0; 63354359Sroberto *rdata = datap = pktdata; 63454359Sroberto lastseq = 999; /* too big to be a sequence number */ 635285612Sdelphij ZERO(haveseq); 63654359Sroberto FD_ZERO(&fds); 637294569Sdelphij tobase = (uint32_t)time(NULL); 63854359Sroberto 63954359Sroberto again: 64054359Sroberto if (firstpkt) 641285612Sdelphij tvo = tvout; 64254359Sroberto else 643285612Sdelphij tvo = tvsout; 644294569Sdelphij tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 64554359Sroberto 64654359Sroberto FD_SET(sockfd, &fds); 647293650Sglebius n = select(sockfd+1, &fds, NULL, NULL, &tvo); 64854359Sroberto if (n == -1) { 649285612Sdelphij warning("select fails"); 65054359Sroberto return -1; 65154359Sroberto } 652294569Sdelphij 653294569Sdelphij /* 654294569Sdelphij * Check if this is already too late. Trash the data and fake a 655294569Sdelphij * timeout if this is so. 656294569Sdelphij */ 657294569Sdelphij todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 658294569Sdelphij if ((n > 0) && (todiff > tospan)) { 659294569Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 660316069Sdelphij n -= n; /* faked timeout return from 'select()'*/ 661294569Sdelphij } 662294569Sdelphij 66354359Sroberto if (n == 0) { 66454359Sroberto /* 66554359Sroberto * Timed out. Return what we have 66654359Sroberto */ 66754359Sroberto if (firstpkt) { 66854359Sroberto (void) fprintf(stderr, 669293650Sglebius "%s: timed out, nothing received\n", 670293650Sglebius currenthost); 67154359Sroberto return ERR_TIMEOUT; 67254359Sroberto } else { 67354359Sroberto (void) fprintf(stderr, 67454359Sroberto "%s: timed out with incomplete data\n", 67554359Sroberto currenthost); 67654359Sroberto if (debug) { 67754359Sroberto printf("Received sequence numbers"); 67854359Sroberto for (n = 0; n <= MAXSEQ; n++) 67954359Sroberto if (haveseq[n]) 680301256Sdelphij printf(" %zd,", (size_t)n); 68154359Sroberto if (lastseq != 999) 68254359Sroberto printf(" last frame received\n"); 68354359Sroberto else 68454359Sroberto printf(" last frame not received\n"); 68554359Sroberto } 68654359Sroberto return ERR_INCOMPLETE; 68754359Sroberto } 68854359Sroberto } 68954359Sroberto 69054359Sroberto n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 69154359Sroberto if (n == -1) { 692285612Sdelphij warning("read"); 69354359Sroberto return -1; 69454359Sroberto } 69554359Sroberto 69654359Sroberto 69754359Sroberto /* 69854359Sroberto * Check for format errors. Bug proofing. 69954359Sroberto */ 700285612Sdelphij if (n < (ssize_t)RESP_HEADER_SIZE) { 70154359Sroberto if (debug) 702301256Sdelphij printf("Short (%zd byte) packet received\n", (size_t)n); 70354359Sroberto goto again; 70454359Sroberto } 70554359Sroberto if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION || 70654359Sroberto INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) { 70754359Sroberto if (debug) 708285612Sdelphij printf("Packet received with version %d\n", 709285612Sdelphij INFO_VERSION(rpkt.rm_vn_mode)); 71054359Sroberto goto again; 71154359Sroberto } 71254359Sroberto if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) { 71354359Sroberto if (debug) 714285612Sdelphij printf("Packet received with mode %d\n", 715285612Sdelphij INFO_MODE(rpkt.rm_vn_mode)); 71654359Sroberto goto again; 71754359Sroberto } 71854359Sroberto if (INFO_IS_AUTH(rpkt.auth_seq)) { 71954359Sroberto if (debug) 720285612Sdelphij printf("Encrypted packet received\n"); 72154359Sroberto goto again; 72254359Sroberto } 72354359Sroberto if (!ISRESPONSE(rpkt.rm_vn_mode)) { 72454359Sroberto if (debug) 725285612Sdelphij printf("Received request packet, wanted response\n"); 72654359Sroberto goto again; 72754359Sroberto } 72854359Sroberto if (INFO_MBZ(rpkt.mbz_itemsize) != 0) { 72954359Sroberto if (debug) 730285612Sdelphij printf("Received packet with nonzero MBZ field!\n"); 73154359Sroberto goto again; 73254359Sroberto } 73354359Sroberto 73454359Sroberto /* 73554359Sroberto * Check implementation/request. Could be old data getting to us. 73654359Sroberto */ 73754359Sroberto if (rpkt.implementation != implcode || rpkt.request != reqcode) { 73854359Sroberto if (debug) 739285612Sdelphij printf( 74054359Sroberto "Received implementation/request of %d/%d, wanted %d/%d", 74154359Sroberto rpkt.implementation, rpkt.request, 74254359Sroberto implcode, reqcode); 74354359Sroberto goto again; 74454359Sroberto } 74554359Sroberto 74654359Sroberto /* 74754359Sroberto * Check the error code. If non-zero, return it. 74854359Sroberto */ 74954359Sroberto if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) { 75054359Sroberto if (debug && ISMORE(rpkt.rm_vn_mode)) { 75154359Sroberto printf("Error code %d received on not-final packet\n", 75254359Sroberto INFO_ERR(rpkt.err_nitems)); 75354359Sroberto } 75454359Sroberto return (int)INFO_ERR(rpkt.err_nitems); 75554359Sroberto } 75654359Sroberto 75754359Sroberto /* 75854359Sroberto * Collect items and size. Make sure they make sense. 75954359Sroberto */ 76054359Sroberto items = INFO_NITEMS(rpkt.err_nitems); 76154359Sroberto size = INFO_ITEMSIZE(rpkt.mbz_itemsize); 762132451Sroberto if (esize > size) 763132451Sroberto pad = esize - size; 764132451Sroberto else 765132451Sroberto pad = 0; 766285612Sdelphij datasize = items * size; 767285612Sdelphij if ((size_t)datasize > (n-RESP_HEADER_SIZE)) { 76854359Sroberto if (debug) 76954359Sroberto printf( 770293650Sglebius "Received items %zu, size %zu (total %zu), data in packet is %zu\n", 77154359Sroberto items, size, datasize, n-RESP_HEADER_SIZE); 77254359Sroberto goto again; 77354359Sroberto } 77454359Sroberto 77554359Sroberto /* 77654359Sroberto * If this isn't our first packet, make sure the size matches 77754359Sroberto * the other ones. 77854359Sroberto */ 779285612Sdelphij if (!firstpkt && size != *rsize) { 78054359Sroberto if (debug) 781293650Sglebius printf("Received itemsize %zu, previous %zu\n", 78254359Sroberto size, *rsize); 78354359Sroberto goto again; 78454359Sroberto } 78554359Sroberto /* 786132451Sroberto * If we've received this before, +toss it 78754359Sroberto */ 78854359Sroberto seq = INFO_SEQ(rpkt.auth_seq); 78954359Sroberto if (haveseq[seq]) { 79054359Sroberto if (debug) 79154359Sroberto printf("Received duplicate sequence number %d\n", seq); 79254359Sroberto goto again; 79354359Sroberto } 79454359Sroberto haveseq[seq] = 1; 79554359Sroberto 79654359Sroberto /* 79754359Sroberto * If this is the last in the sequence, record that. 79854359Sroberto */ 79954359Sroberto if (!ISMORE(rpkt.rm_vn_mode)) { 80054359Sroberto if (lastseq != 999) { 80154359Sroberto printf("Received second end sequence packet\n"); 80254359Sroberto goto again; 80354359Sroberto } 80454359Sroberto lastseq = seq; 80554359Sroberto } 80654359Sroberto 80754359Sroberto /* 808294569Sdelphij * So far, so good. Copy this data into the output array. Bump 809294569Sdelphij * the timeout base, in case we expect more data. 81054359Sroberto */ 811294569Sdelphij tobase = (uint32_t)time(NULL); 812132451Sroberto if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) { 813293650Sglebius size_t offset = datap - pktdata; 81454359Sroberto growpktdata(); 815285612Sdelphij *rdata = pktdata; /* might have been realloced ! */ 81654359Sroberto datap = pktdata + offset; 81754359Sroberto } 818132451Sroberto /* 819132451Sroberto * We now move the pointer along according to size and number of 820132451Sroberto * items. This is so we can play nice with older implementations 821132451Sroberto */ 822132451Sroberto 823285612Sdelphij tmp_data = rpkt.u.data; 824285612Sdelphij for (i = 0; i < items; i++) { 825285612Sdelphij memcpy(datap, tmp_data, (unsigned)size); 826132451Sroberto tmp_data += size; 827285612Sdelphij zero_mem(datap + size, pad); 828132451Sroberto datap += size + pad; 829132451Sroberto } 830132451Sroberto 83154359Sroberto if (firstpkt) { 83254359Sroberto firstpkt = 0; 833132451Sroberto *rsize = size + pad; 83454359Sroberto } 83554359Sroberto *ritems += items; 83654359Sroberto 83754359Sroberto /* 83854359Sroberto * Finally, check the count of received packets. If we've got them 83954359Sroberto * all, return 84054359Sroberto */ 84154359Sroberto ++numrecv; 84254359Sroberto if (numrecv <= lastseq) 843285612Sdelphij goto again; 84454359Sroberto return INFO_OKAY; 84554359Sroberto} 84654359Sroberto 84754359Sroberto 84854359Sroberto/* 84954359Sroberto * sendrequest - format and send a request packet 850285612Sdelphij * 851285612Sdelphij * Historically, ntpdc has used a fixed-size request packet regardless 852285612Sdelphij * of the actual payload size. When authenticating, the timestamp, key 853285612Sdelphij * ID, and digest have been placed just before the end of the packet. 854285612Sdelphij * With the introduction in late 2009 of support for authenticated 855285612Sdelphij * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we 856285612Sdelphij * come up four bytes short. 857285612Sdelphij * 858285612Sdelphij * To maintain interop while allowing for larger digests, the behavior 859285612Sdelphij * is unchanged when using 16-octet digests. For larger digests, the 860285612Sdelphij * timestamp, key ID, and digest are placed immediately following the 861285612Sdelphij * request payload, with the overall packet size variable. ntpd can 862285612Sdelphij * distinguish 16-octet digests by the overall request size being 863285612Sdelphij * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled. When using a 864285612Sdelphij * longer digest, that request size should be avoided. 865285612Sdelphij * 866285612Sdelphij * With the form used with 20-octet and larger digests, the timestamp, 867285612Sdelphij * key ID, and digest are located by ntpd relative to the start of the 868285612Sdelphij * packet, and the size of the digest is then implied by the packet 869285612Sdelphij * size. 87054359Sroberto */ 87154359Srobertostatic int 87254359Srobertosendrequest( 87354359Sroberto int implcode, 87454359Sroberto int reqcode, 87554359Sroberto int auth, 876293650Sglebius size_t qitems, 877285612Sdelphij size_t qsize, 878293650Sglebius const char *qdata 87954359Sroberto ) 88054359Sroberto{ 88154359Sroberto struct req_pkt qpkt; 882285612Sdelphij size_t datasize; 883285612Sdelphij size_t reqsize; 884285612Sdelphij u_long key_id; 885285612Sdelphij l_fp ts; 886285612Sdelphij l_fp * ptstamp; 887293650Sglebius size_t maclen; 888285612Sdelphij char * pass; 88954359Sroberto 890285612Sdelphij ZERO(qpkt); 89154359Sroberto qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); 89254359Sroberto qpkt.implementation = (u_char)implcode; 89354359Sroberto qpkt.request = (u_char)reqcode; 89454359Sroberto 89554359Sroberto datasize = qitems * qsize; 896285612Sdelphij if (datasize && qdata != NULL) { 897285612Sdelphij memcpy(qpkt.u.data, qdata, datasize); 89854359Sroberto qpkt.err_nitems = ERR_NITEMS(0, qitems); 89954359Sroberto qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); 90054359Sroberto } else { 90154359Sroberto qpkt.err_nitems = ERR_NITEMS(0, 0); 902182007Sroberto qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); /* allow for optional first item */ 90354359Sroberto } 90454359Sroberto 905182007Sroberto if (!auth || (keyid_entered && info_auth_keyid == 0)) { 90654359Sroberto qpkt.auth_seq = AUTH_SEQ(0, 0); 907285612Sdelphij return sendpkt(&qpkt, req_pkt_size); 908285612Sdelphij } 90954359Sroberto 910285612Sdelphij if (info_auth_keyid == 0) { 911285612Sdelphij key_id = getkeyid("Keyid: "); 912285612Sdelphij if (!key_id) { 913285612Sdelphij fprintf(stderr, "Invalid key identifier\n"); 914285612Sdelphij return 1; 91554359Sroberto } 916285612Sdelphij info_auth_keyid = key_id; 917285612Sdelphij } 918285612Sdelphij if (!authistrusted(info_auth_keyid)) { 919285612Sdelphij pass = getpass_keytype(info_auth_keytype); 920285612Sdelphij if ('\0' == pass[0]) { 921285612Sdelphij fprintf(stderr, "Invalid password\n"); 922285612Sdelphij return 1; 92354359Sroberto } 924285612Sdelphij authusekey(info_auth_keyid, info_auth_keytype, 925285612Sdelphij (u_char *)pass); 92654359Sroberto authtrust(info_auth_keyid, 1); 92754359Sroberto } 928285612Sdelphij qpkt.auth_seq = AUTH_SEQ(1, 0); 929285612Sdelphij if (info_auth_hashlen > 16) { 930285612Sdelphij /* 931285612Sdelphij * Only ntpd which expects REQ_LEN_NOMAC plus maclen 932285612Sdelphij * octets in an authenticated request using a 16 octet 933285612Sdelphij * digest (that is, a newer ntpd) will handle digests 934285612Sdelphij * larger than 16 octets, so for longer digests, do 935285612Sdelphij * not attempt to shorten the requests for downlevel 936285612Sdelphij * ntpd compatibility. 937285612Sdelphij */ 938285612Sdelphij if (REQ_LEN_NOMAC != req_pkt_size) 939285612Sdelphij return 1; 940285612Sdelphij reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp); 941285612Sdelphij /* align to 32 bits */ 942285612Sdelphij reqsize = (reqsize + 3) & ~3; 943285612Sdelphij } else 944285612Sdelphij reqsize = req_pkt_size; 945285612Sdelphij ptstamp = (void *)((char *)&qpkt + reqsize); 946285612Sdelphij ptstamp--; 947285612Sdelphij get_systime(&ts); 948285612Sdelphij L_ADD(&ts, &delay_time); 949285612Sdelphij HTONL_FP(&ts, ptstamp); 950293650Sglebius maclen = authencrypt( 951293650Sglebius info_auth_keyid, (void *)&qpkt, size2int_chk(reqsize)); 952285612Sdelphij if (!maclen) { 953285612Sdelphij fprintf(stderr, "Key not found\n"); 954285612Sdelphij return 1; 955338531Sdelphij } else if (maclen != (size_t)(info_auth_hashlen + sizeof(keyid_t))) { 956285612Sdelphij fprintf(stderr, 957293650Sglebius "%zu octet MAC, %zu expected with %zu octet digest\n", 958285612Sdelphij maclen, (info_auth_hashlen + sizeof(keyid_t)), 959285612Sdelphij info_auth_hashlen); 960285612Sdelphij return 1; 961285612Sdelphij } 962285612Sdelphij return sendpkt(&qpkt, reqsize + maclen); 96354359Sroberto} 96454359Sroberto 96554359Sroberto 96654359Sroberto/* 96754359Sroberto * doquery - send a request and process the response 96854359Sroberto */ 96954359Srobertoint 97054359Srobertodoquery( 97154359Sroberto int implcode, 97254359Sroberto int reqcode, 97354359Sroberto int auth, 974293650Sglebius size_t qitems, 975293650Sglebius size_t qsize, 976293650Sglebius const char *qdata, 977293650Sglebius size_t *ritems, 978293650Sglebius size_t *rsize, 979293650Sglebius const char **rdata, 980132451Sroberto int quiet_mask, 981132451Sroberto int esize 98254359Sroberto ) 98354359Sroberto{ 98454359Sroberto int res; 98554359Sroberto char junk[512]; 98654359Sroberto fd_set fds; 987285612Sdelphij struct sock_timeval tvzero; 98854359Sroberto 98954359Sroberto /* 99054359Sroberto * Check to make sure host is open 99154359Sroberto */ 99254359Sroberto if (!havehost) { 99354359Sroberto (void) fprintf(stderr, "***No host open, use `host' command\n"); 99454359Sroberto return -1; 99554359Sroberto } 99654359Sroberto 99754359Sroberto /* 99854359Sroberto * Poll the socket and clear out any pending data 99954359Sroberto */ 1000106163Srobertoagain: 100154359Sroberto do { 100254359Sroberto tvzero.tv_sec = tvzero.tv_usec = 0; 100354359Sroberto FD_ZERO(&fds); 100454359Sroberto FD_SET(sockfd, &fds); 1005293650Sglebius res = select(sockfd+1, &fds, NULL, NULL, &tvzero); 100654359Sroberto if (res == -1) { 1007285612Sdelphij warning("polling select"); 100854359Sroberto return -1; 100954359Sroberto } else if (res > 0) 101054359Sroberto 101154359Sroberto (void) recv(sockfd, junk, sizeof junk, 0); 101254359Sroberto } while (res > 0); 101354359Sroberto 101454359Sroberto 101554359Sroberto /* 101654359Sroberto * send a request 101754359Sroberto */ 101854359Sroberto res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata); 101954359Sroberto if (res != 0) 1020285612Sdelphij return res; 102154359Sroberto 102254359Sroberto /* 102354359Sroberto * Get the response. If we got a standard error, print a message 102454359Sroberto */ 1025132451Sroberto res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize); 102654359Sroberto 1027106163Sroberto /* 1028106163Sroberto * Try to be compatible with older implementations of ntpd. 1029106163Sroberto */ 1030106163Sroberto if (res == INFO_ERR_FMT && req_pkt_size != 48) { 1031106163Sroberto int oldsize; 1032106163Sroberto 1033106163Sroberto oldsize = req_pkt_size; 1034106163Sroberto 1035106163Sroberto switch(req_pkt_size) { 1036106163Sroberto case REQ_LEN_NOMAC: 1037132451Sroberto req_pkt_size = 160; 1038132451Sroberto break; 1039132451Sroberto case 160: 1040106163Sroberto req_pkt_size = 48; 1041106163Sroberto break; 1042106163Sroberto } 1043132451Sroberto if (impl_ver == IMPL_XNTPD) { 1044132451Sroberto fprintf(stderr, 1045132451Sroberto "***Warning changing to older implementation\n"); 1046132451Sroberto return INFO_ERR_IMPL; 1047132451Sroberto } 1048106163Sroberto 1049106163Sroberto fprintf(stderr, 1050106163Sroberto "***Warning changing the request packet size from %d to %d\n", 1051106163Sroberto oldsize, req_pkt_size); 1052106163Sroberto goto again; 1053106163Sroberto } 1054106163Sroberto 105554359Sroberto /* log error message if not told to be quiet */ 105654359Sroberto if ((res > 0) && (((1 << res) & quiet_mask) == 0)) { 105754359Sroberto switch(res) { 1058285612Sdelphij case INFO_ERR_IMPL: 1059132451Sroberto /* Give us a chance to try the older implementation. */ 1060132451Sroberto if (implcode == IMPL_XNTPD) 1061132451Sroberto break; 106254359Sroberto (void) fprintf(stderr, 1063285612Sdelphij "***Server implementation incompatible with our own\n"); 106454359Sroberto break; 1065285612Sdelphij case INFO_ERR_REQ: 106654359Sroberto (void) fprintf(stderr, 106754359Sroberto "***Server doesn't implement this request\n"); 106854359Sroberto break; 1069285612Sdelphij case INFO_ERR_FMT: 107054359Sroberto (void) fprintf(stderr, 107154359Sroberto "***Server reports a format error in the received packet (shouldn't happen)\n"); 107254359Sroberto break; 1073285612Sdelphij case INFO_ERR_NODATA: 107454359Sroberto (void) fprintf(stderr, 107554359Sroberto "***Server reports data not found\n"); 107654359Sroberto break; 1077285612Sdelphij case INFO_ERR_AUTH: 107854359Sroberto (void) fprintf(stderr, "***Permission denied\n"); 107954359Sroberto break; 1080285612Sdelphij case ERR_TIMEOUT: 108154359Sroberto (void) fprintf(stderr, "***Request timed out\n"); 108254359Sroberto break; 1083285612Sdelphij case ERR_INCOMPLETE: 108454359Sroberto (void) fprintf(stderr, 108554359Sroberto "***Response from server was incomplete\n"); 108654359Sroberto break; 1087285612Sdelphij default: 108854359Sroberto (void) fprintf(stderr, 108954359Sroberto "***Server returns unknown error code %d\n", res); 109054359Sroberto break; 109154359Sroberto } 109254359Sroberto } 109354359Sroberto return res; 109454359Sroberto} 109554359Sroberto 109654359Sroberto 109754359Sroberto/* 109854359Sroberto * getcmds - read commands from the standard input and execute them 109954359Sroberto */ 110054359Srobertostatic void 110154359Srobertogetcmds(void) 110254359Sroberto{ 1103285612Sdelphij char * line; 1104285612Sdelphij int count; 110582498Sroberto 1106285612Sdelphij ntp_readline_init(interactive ? prompt : NULL); 1107285612Sdelphij 110882498Sroberto for (;;) { 1109285612Sdelphij line = ntp_readline(&count); 1110285612Sdelphij if (NULL == line) 1111285612Sdelphij break; 111282498Sroberto docmd(line); 111382498Sroberto free(line); 111482498Sroberto } 111554359Sroberto 1116285612Sdelphij ntp_readline_uninit(); 111754359Sroberto} 111854359Sroberto 111954359Sroberto 1120132451Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 112154359Sroberto/* 112254359Sroberto * abortcmd - catch interrupts and abort the current command 112354359Sroberto */ 112454359Srobertostatic RETSIGTYPE 112554359Srobertoabortcmd( 112654359Sroberto int sig 112754359Sroberto ) 112854359Sroberto{ 112954359Sroberto if (current_output == stdout) 1130338531Sdelphij (void)fflush(stdout); 113154359Sroberto putc('\n', stderr); 1132338531Sdelphij (void)fflush(stderr); 1133338531Sdelphij if (jump) { 1134338531Sdelphij jump = 0; 1135338531Sdelphij LONGJMP(interrupt_buf, 1); 1136338531Sdelphij } 113754359Sroberto} 1138132451Sroberto#endif /* SYS_WINNT */ 113954359Sroberto 114054359Sroberto/* 114154359Sroberto * docmd - decode the command line and execute a command 114254359Sroberto */ 114354359Srobertostatic void 114454359Srobertodocmd( 114554359Sroberto const char *cmdline 114654359Sroberto ) 114754359Sroberto{ 1148182007Sroberto char *tokens[1+MAXARGS+MOREARGS+2]; 114954359Sroberto struct parse pcmd; 115054359Sroberto int ntok; 1151132451Sroberto int i, ti; 1152132451Sroberto int rval; 115354359Sroberto struct xcmd *xcmd; 115454359Sroberto 1155132451Sroberto ai_fam_templ = ai_fam_default; 115654359Sroberto /* 115754359Sroberto * Tokenize the command line. If nothing on it, return. 115854359Sroberto */ 1159285612Sdelphij if (strlen(cmdline) >= MAXLINE) { 1160285612Sdelphij fprintf(stderr, "***Command ignored, more than %d characters:\n%s\n", 1161285612Sdelphij MAXLINE - 1, cmdline); 1162285612Sdelphij return; 1163285612Sdelphij } 116454359Sroberto tokenize(cmdline, tokens, &ntok); 116554359Sroberto if (ntok == 0) 116654359Sroberto return; 116754359Sroberto 116854359Sroberto /* 116954359Sroberto * Find the appropriate command description. 117054359Sroberto */ 117154359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 117254359Sroberto if (i == 0) { 117354359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 117454359Sroberto tokens[0]); 117554359Sroberto return; 117654359Sroberto } else if (i >= 2) { 117754359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 117854359Sroberto tokens[0]); 117954359Sroberto return; 118054359Sroberto } 118154359Sroberto 118254359Sroberto /* 118354359Sroberto * Save the keyword, then walk through the arguments, interpreting 118454359Sroberto * as we go. 118554359Sroberto */ 118654359Sroberto pcmd.keyword = tokens[0]; 118754359Sroberto pcmd.nargs = 0; 1188132451Sroberto ti = 1; 1189132451Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) { 1190132451Sroberto if ((i+ti) >= ntok) { 119154359Sroberto if (!(xcmd->arg[i] & OPT)) { 119254359Sroberto printusage(xcmd, stderr); 119354359Sroberto return; 119454359Sroberto } 119554359Sroberto break; 119654359Sroberto } 1197132451Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>')) 1198132451Sroberto break; 1199132451Sroberto rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]); 1200132451Sroberto if (rval == -1) { 1201132451Sroberto ti++; 1202132451Sroberto continue; 1203132451Sroberto } 1204132451Sroberto if (rval == 0) 1205132451Sroberto return; 120654359Sroberto pcmd.nargs++; 1207132451Sroberto i++; 120854359Sroberto } 120954359Sroberto 1210182007Sroberto /* Any extra args are assumed to be "OPT|NTP_STR". */ 1211182007Sroberto for ( ; i < MAXARGS + MOREARGS;) { 1212182007Sroberto if ((i+ti) >= ntok) 1213182007Sroberto break; 1214182007Sroberto rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]); 1215182007Sroberto if (rval == -1) { 1216182007Sroberto ti++; 1217182007Sroberto continue; 1218182007Sroberto } 1219182007Sroberto if (rval == 0) 1220182007Sroberto return; 1221182007Sroberto pcmd.nargs++; 1222182007Sroberto i++; 1223182007Sroberto } 1224182007Sroberto 1225132451Sroberto i += ti; 122654359Sroberto if (i < ntok && *tokens[i] == '>') { 122754359Sroberto char *fname; 122854359Sroberto 122954359Sroberto if (*(tokens[i]+1) != '\0') 123054359Sroberto fname = tokens[i]+1; 123154359Sroberto else if ((i+1) < ntok) 123254359Sroberto fname = tokens[i+1]; 123354359Sroberto else { 123454359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 123554359Sroberto return; 123654359Sroberto } 123754359Sroberto 123854359Sroberto current_output = fopen(fname, "w"); 123954359Sroberto if (current_output == NULL) { 124054359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 124154359Sroberto perror(""); 124254359Sroberto return; 124354359Sroberto } 124454359Sroberto } else { 124554359Sroberto current_output = stdout; 124654359Sroberto } 124754359Sroberto 1248338531Sdelphij if (interactive) { 1249338531Sdelphij if ( ! SETJMP(interrupt_buf)) { 1250338531Sdelphij jump = 1; 1251338531Sdelphij (xcmd->handler)(&pcmd, current_output); 1252338531Sdelphij jump = 0; 1253338531Sdelphij } else { 1254338531Sdelphij fflush(current_output); 1255338531Sdelphij fputs("\n >>> command aborted <<<\n", stderr); 1256338531Sdelphij fflush(stderr); 1257338531Sdelphij } 125854359Sroberto } else { 1259338531Sdelphij jump = 0; 126054359Sroberto (xcmd->handler)(&pcmd, current_output); 1261338531Sdelphij } 1262338531Sdelphij if ((NULL != current_output) && (stdout != current_output)) { 1263338531Sdelphij (void)fclose(current_output); 1264132451Sroberto current_output = NULL; 126554359Sroberto } 126654359Sroberto} 126754359Sroberto 126854359Sroberto 126954359Sroberto/* 127054359Sroberto * tokenize - turn a command line into tokens 127154359Sroberto */ 127254359Srobertostatic void 127354359Srobertotokenize( 127454359Sroberto const char *line, 127554359Sroberto char **tokens, 127654359Sroberto int *ntok 127754359Sroberto ) 127854359Sroberto{ 127954359Sroberto register const char *cp; 128054359Sroberto register char *sp; 128154359Sroberto static char tspace[MAXLINE]; 128254359Sroberto 128354359Sroberto sp = tspace; 128454359Sroberto cp = line; 128554359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 128654359Sroberto tokens[*ntok] = sp; 128754359Sroberto while (ISSPACE(*cp)) 128854359Sroberto cp++; 128954359Sroberto if (ISEOL(*cp)) 129054359Sroberto break; 129154359Sroberto do { 129254359Sroberto *sp++ = *cp++; 129354359Sroberto } while (!ISSPACE(*cp) && !ISEOL(*cp)); 129454359Sroberto 129554359Sroberto *sp++ = '\0'; 129654359Sroberto } 129754359Sroberto} 129854359Sroberto 129954359Sroberto 130054359Sroberto 130154359Sroberto/* 130254359Sroberto * findcmd - find a command in a command description table 130354359Sroberto */ 130454359Srobertostatic int 130554359Srobertofindcmd( 130654359Sroberto register char *str, 130754359Sroberto struct xcmd *clist1, 130854359Sroberto struct xcmd *clist2, 130954359Sroberto struct xcmd **cmd 131054359Sroberto ) 131154359Sroberto{ 131254359Sroberto register struct xcmd *cl; 1313293650Sglebius size_t clen; 131454359Sroberto int nmatch; 131554359Sroberto struct xcmd *nearmatch = NULL; 131654359Sroberto struct xcmd *clist; 131754359Sroberto 131854359Sroberto clen = strlen(str); 131954359Sroberto nmatch = 0; 132054359Sroberto if (clist1 != 0) 132154359Sroberto clist = clist1; 132254359Sroberto else if (clist2 != 0) 132354359Sroberto clist = clist2; 132454359Sroberto else 132554359Sroberto return 0; 132654359Sroberto 132754359Sroberto again: 132854359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 132954359Sroberto /* do a first character check, for efficiency */ 133054359Sroberto if (*str != *(cl->keyword)) 133154359Sroberto continue; 133254359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 133354359Sroberto /* 133454359Sroberto * Could be extact match, could be approximate. 133554359Sroberto * Is exact if the length of the keyword is the 133654359Sroberto * same as the str. 133754359Sroberto */ 133854359Sroberto if (*((cl->keyword) + clen) == '\0') { 133954359Sroberto *cmd = cl; 134054359Sroberto return 1; 134154359Sroberto } 134254359Sroberto nmatch++; 134354359Sroberto nearmatch = cl; 134454359Sroberto } 134554359Sroberto } 134654359Sroberto 134754359Sroberto /* 134854359Sroberto * See if there is more to do. If so, go again. Sorry about the 134954359Sroberto * goto, too much looking at BSD sources... 135054359Sroberto */ 135154359Sroberto if (clist == clist1 && clist2 != 0) { 135254359Sroberto clist = clist2; 135354359Sroberto goto again; 135454359Sroberto } 135554359Sroberto 135654359Sroberto /* 135754359Sroberto * If we got extactly 1 near match, use it, else return number 135854359Sroberto * of matches. 135954359Sroberto */ 136054359Sroberto if (nmatch == 1) { 136154359Sroberto *cmd = nearmatch; 136254359Sroberto return 1; 136354359Sroberto } 136454359Sroberto return nmatch; 136554359Sroberto} 136654359Sroberto 136754359Sroberto 1368132451Sroberto/* 136954359Sroberto * getarg - interpret an argument token 1370132451Sroberto * 1371182007Sroberto * string is always set. 1372182007Sroberto * type is set to the decoded type. 1373182007Sroberto * 1374132451Sroberto * return: 0 - failure 1375132451Sroberto * 1 - success 1376132451Sroberto * -1 - skip to next token 137754359Sroberto */ 137854359Srobertostatic int 137954359Srobertogetarg( 138054359Sroberto char *str, 138154359Sroberto int code, 138254359Sroberto arg_v *argp 138354359Sroberto ) 138454359Sroberto{ 138554359Sroberto int isneg; 138654359Sroberto char *cp, *np; 138754359Sroberto static const char *digits = "0123456789"; 138854359Sroberto 1389285612Sdelphij ZERO(*argp); 1390182007Sroberto argp->string = str; 1391182007Sroberto argp->type = code & ~OPT; 1392182007Sroberto 1393182007Sroberto switch (argp->type) { 139454359Sroberto case NTP_STR: 139554359Sroberto break; 1396182007Sroberto case NTP_ADD: 1397132451Sroberto if (!strcmp("-6", str)) { 1398132451Sroberto ai_fam_templ = AF_INET6; 1399132451Sroberto return -1; 1400132451Sroberto } else if (!strcmp("-4", str)) { 1401132451Sroberto ai_fam_templ = AF_INET; 1402132451Sroberto return -1; 1403132451Sroberto } 1404132451Sroberto if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) { 140554359Sroberto return 0; 140654359Sroberto } 140754359Sroberto break; 1408182007Sroberto case NTP_INT: 1409182007Sroberto case NTP_UINT: 141054359Sroberto isneg = 0; 141154359Sroberto np = str; 141254359Sroberto if (*np == '-') { 141354359Sroberto np++; 141454359Sroberto isneg = 1; 141554359Sroberto } 141654359Sroberto 141754359Sroberto argp->uval = 0; 141854359Sroberto do { 141954359Sroberto cp = strchr(digits, *np); 142054359Sroberto if (cp == NULL) { 142154359Sroberto (void) fprintf(stderr, 142254359Sroberto "***Illegal integer value %s\n", str); 142354359Sroberto return 0; 142454359Sroberto } 142554359Sroberto argp->uval *= 10; 1426293650Sglebius argp->uval += (u_long)(cp - digits); 142754359Sroberto } while (*(++np) != '\0'); 142854359Sroberto 142954359Sroberto if (isneg) { 1430182007Sroberto if ((code & ~OPT) == NTP_UINT) { 143154359Sroberto (void) fprintf(stderr, 143254359Sroberto "***Value %s should be unsigned\n", str); 143354359Sroberto return 0; 143454359Sroberto } 143554359Sroberto argp->ival = -argp->ival; 143654359Sroberto } 143754359Sroberto break; 1438132451Sroberto case IP_VERSION: 1439132451Sroberto if (!strcmp("-6", str)) 1440132451Sroberto argp->ival = 6 ; 1441132451Sroberto else if (!strcmp("-4", str)) 1442132451Sroberto argp->ival = 4 ; 1443132451Sroberto else { 1444132451Sroberto (void) fprintf(stderr, 1445132451Sroberto "***Version must be either 4 or 6\n"); 1446132451Sroberto return 0; 1447132451Sroberto } 1448132451Sroberto break; 144954359Sroberto } 145054359Sroberto 145154359Sroberto return 1; 145254359Sroberto} 145354359Sroberto 145454359Sroberto 145554359Sroberto/* 145654359Sroberto * getnetnum - given a host name, return its net number 145754359Sroberto * and (optional) full name 145854359Sroberto */ 145954359Srobertostatic int 146054359Srobertogetnetnum( 146154359Sroberto const char *hname, 1462285612Sdelphij sockaddr_u *num, 1463132451Sroberto char *fullhost, 1464132451Sroberto int af 146554359Sroberto ) 146654359Sroberto{ 1467132451Sroberto struct addrinfo hints, *ai = NULL; 146854359Sroberto 1469285612Sdelphij ZERO(hints); 1470132451Sroberto hints.ai_flags = AI_CANONNAME; 1471132451Sroberto#ifdef AI_ADDRCONFIG 1472132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1473132451Sroberto#endif 1474132451Sroberto 1475285612Sdelphij /* 1476285612Sdelphij * decodenetnum only works with addresses, but handles syntax 1477285612Sdelphij * that getaddrinfo doesn't: [2001::1]:1234 1478285612Sdelphij */ 147954359Sroberto if (decodenetnum(hname, num)) { 1480285612Sdelphij if (fullhost != NULL) 1481285612Sdelphij getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1482285612Sdelphij LENHOSTNAME, NULL, 0, 0); 148354359Sroberto return 1; 1484182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1485289997Sglebius INSIST(sizeof(*num) >= ai->ai_addrlen); 1486285612Sdelphij memcpy(num, ai->ai_addr, ai->ai_addrlen); 1487285612Sdelphij if (fullhost != NULL) { 1488285612Sdelphij if (ai->ai_canonname != NULL) 1489285612Sdelphij strlcpy(fullhost, ai->ai_canonname, 1490285612Sdelphij LENHOSTNAME); 1491285612Sdelphij else 1492285612Sdelphij getnameinfo(&num->sa, SOCKLEN(num), 1493285612Sdelphij fullhost, LENHOSTNAME, NULL, 1494285612Sdelphij 0, 0); 1495285612Sdelphij } 149654359Sroberto return 1; 149754359Sroberto } 1498285612Sdelphij fprintf(stderr, "***Can't find host %s\n", hname); 1499285612Sdelphij 1500285612Sdelphij return 0; 150154359Sroberto} 150254359Sroberto 1503285612Sdelphij 150454359Sroberto/* 150554359Sroberto * nntohost - convert network number to host name. This routine enforces 150654359Sroberto * the showhostnames setting. 150754359Sroberto */ 1508285612Sdelphijconst char * 150954359Srobertonntohost( 1510285612Sdelphij sockaddr_u *netnum 151154359Sroberto ) 151254359Sroberto{ 1513285612Sdelphij if (!showhostnames || SOCK_UNSPEC(netnum)) 1514285612Sdelphij return stoa(netnum); 1515285612Sdelphij else if (ISREFCLOCKADR(netnum)) 1516132451Sroberto return refnumtoa(netnum); 1517285612Sdelphij else 1518285612Sdelphij return socktohost(netnum); 151954359Sroberto} 152054359Sroberto 152154359Sroberto 152254359Sroberto/* 152354359Sroberto * Finally, the built in command handlers 152454359Sroberto */ 152554359Sroberto 152654359Sroberto/* 152754359Sroberto * help - tell about commands, or details of a particular command 152854359Sroberto */ 152954359Srobertostatic void 153054359Srobertohelp( 153154359Sroberto struct parse *pcmd, 153254359Sroberto FILE *fp 153354359Sroberto ) 153454359Sroberto{ 153554359Sroberto struct xcmd *xcp; 153654359Sroberto char *cmd; 1537182007Sroberto const char *list[100]; 1538285612Sdelphij size_t word, words; 1539285612Sdelphij size_t row, rows; 1540285612Sdelphij size_t col, cols; 1541285612Sdelphij size_t length; 154254359Sroberto 154354359Sroberto if (pcmd->nargs == 0) { 1544182007Sroberto words = 0; 154554359Sroberto for (xcp = builtins; xcp->keyword != 0; xcp++) { 154654359Sroberto if (*(xcp->keyword) != '?') 1547285612Sdelphij list[words++] = xcp->keyword; 154854359Sroberto } 1549285612Sdelphij for (xcp = opcmds; xcp->keyword != 0; xcp++) 1550285612Sdelphij list[words++] = xcp->keyword; 155154359Sroberto 1552285612Sdelphij qsort((void *)list, words, sizeof(list[0]), helpsort); 1553182007Sroberto col = 0; 1554182007Sroberto for (word = 0; word < words; word++) { 1555285612Sdelphij length = strlen(list[word]); 1556285612Sdelphij col = max(col, length); 155754359Sroberto } 155854359Sroberto 1559182007Sroberto cols = SCREENWIDTH / ++col; 1560285612Sdelphij rows = (words + cols - 1) / cols; 1561182007Sroberto 1562285612Sdelphij fprintf(fp, "ntpdc commands:\n"); 1563182007Sroberto 1564182007Sroberto for (row = 0; row < rows; row++) { 1565285612Sdelphij for (word = row; word < words; word += rows) 1566285612Sdelphij fprintf(fp, "%-*.*s", (int)col, 1567285612Sdelphij (int)col - 1, list[word]); 1568285612Sdelphij fprintf(fp, "\n"); 156954359Sroberto } 157054359Sroberto } else { 157154359Sroberto cmd = pcmd->argval[0].string; 1572182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 1573182007Sroberto if (words == 0) { 1574285612Sdelphij fprintf(stderr, 1575285612Sdelphij "Command `%s' is unknown\n", cmd); 157654359Sroberto return; 1577182007Sroberto } else if (words >= 2) { 1578285612Sdelphij fprintf(stderr, 1579285612Sdelphij "Command `%s' is ambiguous\n", cmd); 158054359Sroberto return; 158154359Sroberto } 1582285612Sdelphij fprintf(fp, "function: %s\n", xcp->comment); 158354359Sroberto printusage(xcp, fp); 158454359Sroberto } 158554359Sroberto} 158654359Sroberto 158754359Sroberto 158854359Sroberto/* 158954359Sroberto * helpsort - do hostname qsort comparisons 159054359Sroberto */ 159154359Srobertostatic int 159254359Srobertohelpsort( 159354359Sroberto const void *t1, 159454359Sroberto const void *t2 159554359Sroberto ) 159654359Sroberto{ 1597285612Sdelphij const char * const * name1 = t1; 1598285612Sdelphij const char * const * name2 = t2; 159954359Sroberto 160054359Sroberto return strcmp(*name1, *name2); 160154359Sroberto} 160254359Sroberto 160354359Sroberto 160454359Sroberto/* 160554359Sroberto * printusage - print usage information for a command 160654359Sroberto */ 160754359Srobertostatic void 160854359Srobertoprintusage( 160954359Sroberto struct xcmd *xcp, 161054359Sroberto FILE *fp 161154359Sroberto ) 161254359Sroberto{ 1613132451Sroberto int i, opt46; 161454359Sroberto 1615132451Sroberto opt46 = 0; 161654359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 161754359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 1618182007Sroberto if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) { 1619132451Sroberto (void) fprintf(fp, " [ -4|-6 ]"); 1620132451Sroberto opt46 = 1; 1621132451Sroberto } 162254359Sroberto if (xcp->arg[i] & OPT) 162354359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 162454359Sroberto else 162554359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 162654359Sroberto } 162754359Sroberto (void) fprintf(fp, "\n"); 162854359Sroberto} 162954359Sroberto 163054359Sroberto 163154359Sroberto/* 163254359Sroberto * timeout - set time out time 163354359Sroberto */ 163454359Srobertostatic void 163554359Srobertotimeout( 163654359Sroberto struct parse *pcmd, 163754359Sroberto FILE *fp 163854359Sroberto ) 163954359Sroberto{ 164054359Sroberto int val; 164154359Sroberto 164254359Sroberto if (pcmd->nargs == 0) { 164354359Sroberto val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 164454359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 164554359Sroberto } else { 164654359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 164754359Sroberto tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000)) 164854359Sroberto * 1000; 164954359Sroberto } 165054359Sroberto} 165154359Sroberto 165254359Sroberto 165354359Sroberto/* 165454359Sroberto * my_delay - set delay for auth requests 165554359Sroberto */ 165654359Srobertostatic void 165754359Srobertomy_delay( 165854359Sroberto struct parse *pcmd, 165954359Sroberto FILE *fp 166054359Sroberto ) 166154359Sroberto{ 166254359Sroberto int isneg; 166354359Sroberto u_long val; 166454359Sroberto 166554359Sroberto if (pcmd->nargs == 0) { 166654359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 166754359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 166854359Sroberto } else { 166954359Sroberto if (pcmd->argval[0].ival < 0) { 167054359Sroberto isneg = 1; 167154359Sroberto val = (u_long)(-pcmd->argval[0].ival); 167254359Sroberto } else { 167354359Sroberto isneg = 0; 167454359Sroberto val = (u_long)pcmd->argval[0].ival; 167554359Sroberto } 167654359Sroberto 167754359Sroberto delay_time.l_ui = val / 1000; 167854359Sroberto val %= 1000; 167954359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 168054359Sroberto 168154359Sroberto if (isneg) 168254359Sroberto L_NEG(&delay_time); 168354359Sroberto } 168454359Sroberto} 168554359Sroberto 168654359Sroberto 168754359Sroberto/* 168854359Sroberto * host - set the host we are dealing with. 168954359Sroberto */ 169054359Srobertostatic void 169154359Srobertohost( 169254359Sroberto struct parse *pcmd, 169354359Sroberto FILE *fp 169454359Sroberto ) 169554359Sroberto{ 1696132451Sroberto int i; 1697132451Sroberto 169854359Sroberto if (pcmd->nargs == 0) { 169954359Sroberto if (havehost) 170054359Sroberto (void) fprintf(fp, "current host is %s\n", currenthost); 170154359Sroberto else 170254359Sroberto (void) fprintf(fp, "no current host\n"); 1703132451Sroberto return; 1704132451Sroberto } 1705132451Sroberto 1706132451Sroberto i = 0; 1707132451Sroberto if (pcmd->nargs == 2) { 1708132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 1709132451Sroberto ai_fam_templ = AF_INET; 1710132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 1711132451Sroberto ai_fam_templ = AF_INET6; 1712132451Sroberto else { 1713132451Sroberto if (havehost) 1714132451Sroberto (void) fprintf(fp, 1715132451Sroberto "current host remains %s\n", currenthost); 1716132451Sroberto else 1717132451Sroberto (void) fprintf(fp, "still no current host\n"); 1718132451Sroberto return; 1719132451Sroberto } 1720132451Sroberto i = 1; 1721132451Sroberto } 1722132451Sroberto if (openhost(pcmd->argval[i].string)) { 172354359Sroberto (void) fprintf(fp, "current host set to %s\n", currenthost); 172454359Sroberto } else { 172554359Sroberto if (havehost) 172654359Sroberto (void) fprintf(fp, 172754359Sroberto "current host remains %s\n", currenthost); 172854359Sroberto else 172954359Sroberto (void) fprintf(fp, "still no current host\n"); 173054359Sroberto } 173154359Sroberto} 173254359Sroberto 173354359Sroberto 173454359Sroberto/* 173554359Sroberto * keyid - get a keyid to use for authenticating requests 173654359Sroberto */ 173754359Srobertostatic void 173854359Srobertokeyid( 173954359Sroberto struct parse *pcmd, 174054359Sroberto FILE *fp 174154359Sroberto ) 174254359Sroberto{ 174354359Sroberto if (pcmd->nargs == 0) { 1744182007Sroberto if (info_auth_keyid == 0 && !keyid_entered) 174554359Sroberto (void) fprintf(fp, "no keyid defined\n"); 1746182007Sroberto else if (info_auth_keyid == 0 && keyid_entered) 1747182007Sroberto (void) fprintf(fp, "no keyid will be sent\n"); 174854359Sroberto else 174954359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 175054359Sroberto } else { 175154359Sroberto info_auth_keyid = pcmd->argval[0].uval; 1752182007Sroberto keyid_entered = 1; 175354359Sroberto } 175454359Sroberto} 175554359Sroberto 175654359Sroberto 175754359Sroberto/* 175854359Sroberto * keytype - get type of key to use for authenticating requests 175954359Sroberto */ 176054359Srobertostatic void 176154359Srobertokeytype( 176254359Sroberto struct parse *pcmd, 176354359Sroberto FILE *fp 176454359Sroberto ) 176554359Sroberto{ 1766285612Sdelphij const char * digest_name; 1767285612Sdelphij size_t digest_len; 1768285612Sdelphij int key_type; 176954359Sroberto 1770285612Sdelphij if (!pcmd->nargs) { 1771285612Sdelphij fprintf(fp, "keytype is %s with %lu octet digests\n", 1772285612Sdelphij keytype_name(info_auth_keytype), 1773285612Sdelphij (u_long)info_auth_hashlen); 1774285612Sdelphij return; 1775285612Sdelphij } 1776285612Sdelphij 1777285612Sdelphij digest_name = pcmd->argval[0].string; 1778285612Sdelphij digest_len = 0; 1779285612Sdelphij key_type = keytype_from_text(digest_name, &digest_len); 1780285612Sdelphij 1781285612Sdelphij if (!key_type) { 1782285612Sdelphij fprintf(fp, "keytype must be 'md5'%s\n", 1783285612Sdelphij#ifdef OPENSSL 1784285612Sdelphij " or a digest type provided by OpenSSL"); 1785285612Sdelphij#else 1786285612Sdelphij ""); 1787285612Sdelphij#endif 1788285612Sdelphij return; 1789285612Sdelphij } 1790285612Sdelphij 1791285612Sdelphij info_auth_keytype = key_type; 1792285612Sdelphij info_auth_hashlen = digest_len; 179354359Sroberto} 179454359Sroberto 179554359Sroberto 179654359Sroberto/* 179754359Sroberto * passwd - get an authentication key 179854359Sroberto */ 179954359Sroberto/*ARGSUSED*/ 180054359Srobertostatic void 180154359Srobertopasswd( 180254359Sroberto struct parse *pcmd, 180354359Sroberto FILE *fp 180454359Sroberto ) 180554359Sroberto{ 180654359Sroberto char *pass; 180754359Sroberto 180854359Sroberto if (info_auth_keyid == 0) { 180954359Sroberto info_auth_keyid = getkeyid("Keyid: "); 181054359Sroberto if (info_auth_keyid == 0) { 181154359Sroberto (void)fprintf(fp, "Keyid must be defined\n"); 181254359Sroberto return; 181354359Sroberto } 181454359Sroberto } 1815285612Sdelphij if (pcmd->nargs >= 1) 1816285612Sdelphij pass = pcmd->argval[0].string; 1817285612Sdelphij else { 1818285612Sdelphij pass = getpass_keytype(info_auth_keytype); 1819285612Sdelphij if ('\0' == *pass) { 1820285612Sdelphij fprintf(fp, "Password unchanged\n"); 1821285612Sdelphij return; 182282498Sroberto } 182354359Sroberto } 1824285612Sdelphij authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); 1825285612Sdelphij authtrust(info_auth_keyid, 1); 182654359Sroberto} 182754359Sroberto 182854359Sroberto 182954359Sroberto/* 183054359Sroberto * hostnames - set the showhostnames flag 183154359Sroberto */ 183254359Srobertostatic void 183354359Srobertohostnames( 183454359Sroberto struct parse *pcmd, 183554359Sroberto FILE *fp 183654359Sroberto ) 183754359Sroberto{ 183854359Sroberto if (pcmd->nargs == 0) { 183954359Sroberto if (showhostnames) 184054359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 184154359Sroberto else 184254359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 184354359Sroberto } else { 184454359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 184554359Sroberto showhostnames = 1; 184654359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 184754359Sroberto showhostnames = 0; 184854359Sroberto else 184954359Sroberto (void)fprintf(stderr, "What?\n"); 185054359Sroberto } 185154359Sroberto} 185254359Sroberto 185354359Sroberto 185454359Sroberto/* 185554359Sroberto * setdebug - set/change debugging level 185654359Sroberto */ 185754359Srobertostatic void 185854359Srobertosetdebug( 185954359Sroberto struct parse *pcmd, 186054359Sroberto FILE *fp 186154359Sroberto ) 186254359Sroberto{ 186354359Sroberto if (pcmd->nargs == 0) { 186454359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 186554359Sroberto return; 186654359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 186754359Sroberto debug = 0; 186854359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 186954359Sroberto debug++; 187054359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 187154359Sroberto debug--; 187254359Sroberto } else { 187354359Sroberto (void) fprintf(fp, "What?\n"); 187454359Sroberto return; 187554359Sroberto } 187654359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 187754359Sroberto} 187854359Sroberto 187954359Sroberto 188054359Sroberto/* 188154359Sroberto * quit - stop this nonsense 188254359Sroberto */ 188354359Sroberto/*ARGSUSED*/ 188454359Srobertostatic void 188554359Srobertoquit( 188654359Sroberto struct parse *pcmd, 188754359Sroberto FILE *fp 188854359Sroberto ) 188954359Sroberto{ 189054359Sroberto if (havehost) 189154359Sroberto closesocket(sockfd); 189254359Sroberto exit(0); 189354359Sroberto} 189454359Sroberto 189554359Sroberto 189654359Sroberto/* 189754359Sroberto * version - print the current version number 189854359Sroberto */ 189954359Sroberto/*ARGSUSED*/ 190054359Srobertostatic void 190154359Srobertoversion( 190254359Sroberto struct parse *pcmd, 190354359Sroberto FILE *fp 190454359Sroberto ) 190554359Sroberto{ 190654359Sroberto 190754359Sroberto (void) fprintf(fp, "%s\n", Version); 190854359Sroberto return; 190954359Sroberto} 191054359Sroberto 191154359Sroberto 1912285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 0))) 1913285612Sdelphijvwarning(const char *fmt, va_list ap) 1914285612Sdelphij{ 1915285612Sdelphij int serrno = errno; 1916285612Sdelphij (void) fprintf(stderr, "%s: ", progname); 1917285612Sdelphij vfprintf(stderr, fmt, ap); 1918285612Sdelphij (void) fprintf(stderr, ": %s\n", strerror(serrno)); 1919285612Sdelphij} 1920285612Sdelphij 192154359Sroberto/* 192254359Sroberto * warning - print a warning message 192354359Sroberto */ 1924285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 2))) 192554359Srobertowarning( 192654359Sroberto const char *fmt, 1927285612Sdelphij ... 192854359Sroberto ) 192954359Sroberto{ 1930285612Sdelphij va_list ap; 1931285612Sdelphij va_start(ap, fmt); 1932285612Sdelphij vwarning(fmt, ap); 1933285612Sdelphij va_end(ap); 193454359Sroberto} 193554359Sroberto 193654359Sroberto 193754359Sroberto/* 193854359Sroberto * error - print a message and exit 193954359Sroberto */ 1940285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 2))) 194154359Srobertoerror( 194254359Sroberto const char *fmt, 1943285612Sdelphij ... 194454359Sroberto ) 194554359Sroberto{ 1946285612Sdelphij va_list ap; 1947285612Sdelphij va_start(ap, fmt); 1948285612Sdelphij vwarning(fmt, ap); 1949285612Sdelphij va_end(ap); 195054359Sroberto exit(1); 195154359Sroberto} 195254359Sroberto 195354359Sroberto/* 195454359Sroberto * getkeyid - prompt the user for a keyid to use 195554359Sroberto */ 195654359Srobertostatic u_long 195754359Srobertogetkeyid( 195854359Sroberto const char *keyprompt 195954359Sroberto ) 196054359Sroberto{ 1961285612Sdelphij int c; 196254359Sroberto FILE *fi; 196354359Sroberto char pbuf[20]; 1964285612Sdelphij size_t i; 1965285612Sdelphij size_t ilim; 196654359Sroberto 196754359Sroberto#ifndef SYS_WINNT 196854359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 196954359Sroberto#else 1970285612Sdelphij if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 197154359Sroberto#endif /* SYS_WINNT */ 197254359Sroberto fi = stdin; 1973285612Sdelphij else 197454359Sroberto setbuf(fi, (char *)NULL); 197554359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 1976285612Sdelphij for (i = 0, ilim = COUNTOF(pbuf) - 1; 1977285612Sdelphij i < ilim && (c = getc(fi)) != '\n' && c != EOF; 1978285612Sdelphij ) 1979285612Sdelphij pbuf[i++] = (char)c; 1980285612Sdelphij pbuf[i] = '\0'; 198154359Sroberto if (fi != stdin) 1982285612Sdelphij fclose(fi); 1983285612Sdelphij 1984285612Sdelphij return (u_long) atoi(pbuf); 198554359Sroberto} 1986