ntpq.c revision 298770
152400Sbillf/* 252400Sbillf * ntpq - query an NTP server using mode 6 commands 352400Sbillf */ 452400Sbillf#include <config.h> 552400Sbillf#include <stdio.h> 652400Sbillf#include <ctype.h> 752400Sbillf#include <signal.h> 873651Sdougb#include <setjmp.h> 973651Sdougb#include <sys/types.h> 1052400Sbillf#include <sys/time.h> 1152495Sbillf#ifdef HAVE_UNISTD_H 1252400Sbillf# include <unistd.h> 1368507Sdougb#endif 1452400Sbillf#ifdef HAVE_FCNTL_H 1552400Sbillf# include <fcntl.h> 1652533Sbillf#endif 1752400Sbillf#ifdef SYS_WINNT 1867949Sdougb# include <mswsock.h> 1967949Sdougb#endif 2052400Sbillf#include <isc/net.h> 2152400Sbillf#include <isc/result.h> 2252400Sbillf 2352400Sbillf#include "ntpq.h" 2452400Sbillf#include "ntp_assert.h" 2552400Sbillf#include "ntp_stdlib.h" 2652400Sbillf#include "ntp_unixtime.h" 2767949Sdougb#include "ntp_calendar.h" 2852400Sbillf#include "ntp_select.h" 2952400Sbillf#include "ntp_assert.h" 3052400Sbillf#include "lib_strbuf.h" 3152400Sbillf#include "ntp_lineedit.h" 3252400Sbillf#include "ntp_debug.h" 3367949Sdougb#ifdef OPENSSL 3452400Sbillf#include "openssl/evp.h" 3552400Sbillf#include "openssl/objects.h" 3652400Sbillf#include "openssl/err.h" 3752400Sbillf#endif 3852400Sbillf#include <ssl_applink.c> 3952400Sbillf 4052400Sbillf#include "ntp_libopts.h" 4167859Sdougb#include "safecast.h" 4267949Sdougb 4352400Sbillf#ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 4452400Sbillf# define open(name, flags) open(name, flags, 0777) 4558910Salfred# define SERVER_PORT_NUM 123 4658910Salfred#endif 4758910Salfred 4867850Sdougb/* we use COMMAND as an autogen keyword */ 4967850Sdougb#ifdef COMMAND 5067850Sdougb# undef COMMAND 5167850Sdougb#endif 5267850Sdougb 5367850Sdougb/* 5467850Sdougb * Because we potentially understand a lot of commands we will run 5567850Sdougb * interactive if connected to a terminal. 5667850Sdougb */ 5767850Sdougbint interactive = 0; /* set to 1 when we should prompt */ 5867850Sdougbconst char *prompt = "ntpq> "; /* prompt to ask him about */ 5967850Sdougb 6067949Sdougb/* 6167850Sdougb * use old readvars behavior? --old-rv processing in ntpq resets 6267850Sdougb * this value based on the presence or absence of --old-rv. It is 6367850Sdougb * initialized to 1 here to maintain backward compatibility with 6467850Sdougb * libntpq clients such as ntpsnmpd, which are free to reset it as 6567850Sdougb * desired. 6667850Sdougb */ 6767850Sdougbint old_rv = 1; 6867850Sdougb 6967859Sdougb/* 7067859Sdougb * How should we display the refid? 7158910Salfred * REFID_HASH, REFID_IPV4 7267850Sdougb */ 7367850Sdougbte_Refid drefid = -1; 7467850Sdougb 7567850Sdougb/* 7667850Sdougb * for get_systime() 7767850Sdougb */ 7867859Sdougbs_char sys_precision; /* local clock precision (log2 s) */ 7967850Sdougb 8067859Sdougb/* 8167850Sdougb * Keyid used for authenticated requests. Obtained on the fly. 8267850Sdougb */ 8367850Sdougbu_long info_auth_keyid = 0; 8467850Sdougb 8567859Sdougbstatic int info_auth_keytype = NID_md5; /* MD5 */ 8667850Sdougbstatic size_t info_auth_hashlen = 16; /* MD5 */ 8767850Sdougbu_long current_time; /* needed by authkeys; not used */ 8867850Sdougb 8967850Sdougb/* 9067850Sdougb * Flag which indicates we should always send authenticated requests 9167850Sdougb */ 9267850Sdougbint always_auth = 0; 9367850Sdougb 9467850Sdougb/* 9567850Sdougb * Flag which indicates raw mode output. 9667850Sdougb */ 9767850Sdougbint rawmode = 0; 9867850Sdougb 9967850Sdougb/* 10058910Salfred * Packet version number we use 10158910Salfred */ 10258910Salfredu_char pktversion = NTP_OLDVERSION + 1; 10358910Salfred 10458910Salfred/* 10558910Salfred * Don't jump if no set jmp. 10667850Sdougb */ 10758910Salfredvolatile int jump = 0; 10877323Sdougb 10977323Sdougb/* 11067949Sdougb * Format values 11167850Sdougb */ 11267850Sdougb#define PADDING 0 11367949Sdougb#define HA 1 /* host address */ 11467850Sdougb#define NA 2 /* network address */ 11567850Sdougb#define LP 3 /* leap (print in binary) */ 11667949Sdougb#define RF 4 /* refid (sometimes string, sometimes not) */ 11767850Sdougb#define AR 5 /* array of times */ 11867850Sdougb#define FX 6 /* test flags */ 11967850Sdougb#define TS 7 /* l_fp timestamp in hex */ 12067850Sdougb#define OC 8 /* integer, print in octal */ 12167949Sdougb#define EOV 255 /* end of table */ 12267850Sdougb 12367949Sdougb/* 12467949Sdougb * For the most part ntpq simply displays what ntpd provides in the 12567949Sdougb * mostly plain-text mode 6 responses. A few variable names are by 12667949Sdougb * default "cooked" to provide more human-friendly output. 12767949Sdougb */ 12868507Sdougbconst var_format cookedvars[] = { 12967949Sdougb { "leap", LP }, 13067949Sdougb { "reach", OC }, 13167949Sdougb { "refid", RF }, 13267949Sdougb { "reftime", TS }, 13367949Sdougb { "clock", TS }, 13467949Sdougb { "org", TS }, 13567949Sdougb { "rec", TS }, 13667949Sdougb { "xmt", TS }, 13767949Sdougb { "flash", FX }, 13867949Sdougb { "srcadr", HA }, 13967949Sdougb { "peeradr", HA }, /* compat with others */ 14067949Sdougb { "dstadr", NA }, 14167850Sdougb { "filtdelay", AR }, 14267859Sdougb { "filtoffset", AR }, 14367850Sdougb { "filtdisp", AR }, 14467850Sdougb { "filterror", AR }, /* compat with others */ 14567850Sdougb}; 14667850Sdougb 14777326Sdougb 14877326Sdougb 14967850Sdougb/* 15067850Sdougb * flasher bits 15167850Sdougb */ 15267850Sdougbstatic const char *tstflagnames[] = { 15367850Sdougb "pkt_dup", /* TEST1 */ 15467859Sdougb "pkt_bogus", /* TEST2 */ 15567859Sdougb "pkt_unsync", /* TEST3 */ 15667859Sdougb "pkt_denied", /* TEST4 */ 15767850Sdougb "pkt_auth", /* TEST5 */ 15867850Sdougb "pkt_stratum", /* TEST6 */ 15967850Sdougb "pkt_header", /* TEST7 */ 16067850Sdougb "pkt_autokey", /* TEST8 */ 16167850Sdougb "pkt_crypto", /* TEST9 */ 16267850Sdougb "peer_stratum", /* TEST10 */ 16367850Sdougb "peer_dist", /* TEST11 */ 16467850Sdougb "peer_loop", /* TEST12 */ 16567850Sdougb "peer_unreach" /* TEST13 */ 16667850Sdougb}; 16767850Sdougb 16867850Sdougb 16967850Sdougbint ntpqmain (int, char **); 17067850Sdougb/* 17167850Sdougb * Built in command handler declarations 17267850Sdougb */ 17367850Sdougbstatic int openhost (const char *, int); 17467850Sdougbstatic void dump_hex_printable(const void *, size_t); 17567850Sdougbstatic int sendpkt (void *, size_t); 17667850Sdougbstatic int getresponse (int, int, u_short *, size_t *, const char **, int); 17767850Sdougbstatic int sendrequest (int, associd_t, int, size_t, const char *); 17867850Sdougbstatic char * tstflags (u_long); 17967850Sdougb#ifndef BUILD_AS_LIB 18067850Sdougbstatic void getcmds (void); 18167850Sdougb#ifndef SYS_WINNT 18267850Sdougbstatic int abortcmd (void); 18367850Sdougb#endif /* SYS_WINNT */ 18467850Sdougbstatic void docmd (const char *); 18567850Sdougbstatic void tokenize (const char *, char **, int *); 18667850Sdougbstatic int getarg (const char *, int, arg_v *); 18767850Sdougb#endif /* BUILD_AS_LIB */ 18867850Sdougbstatic int findcmd (const char *, struct xcmd *, 18967850Sdougb struct xcmd *, struct xcmd **); 19067850Sdougbstatic int rtdatetolfp (char *, l_fp *); 19167850Sdougbstatic int decodearr (char *, int *, l_fp *); 19267850Sdougbstatic void help (struct parse *, FILE *); 19367850Sdougbstatic int helpsort (const void *, const void *); 19467850Sdougbstatic void printusage (struct xcmd *, FILE *); 19567850Sdougbstatic void timeout (struct parse *, FILE *); 19667850Sdougbstatic void auth_delay (struct parse *, FILE *); 19767850Sdougbstatic void host (struct parse *, FILE *); 19867850Sdougbstatic void ntp_poll (struct parse *, FILE *); 19967850Sdougbstatic void keyid (struct parse *, FILE *); 20067859Sdougbstatic void keytype (struct parse *, FILE *); 20167850Sdougbstatic void passwd (struct parse *, FILE *); 20267850Sdougbstatic void hostnames (struct parse *, FILE *); 20367850Sdougbstatic void setdebug (struct parse *, FILE *); 20467850Sdougbstatic void quit (struct parse *, FILE *); 20567850Sdougbstatic void showdrefid (struct parse *, FILE *); 20667850Sdougbstatic void version (struct parse *, FILE *); 20767850Sdougbstatic void raw (struct parse *, FILE *); 20867850Sdougbstatic void cooked (struct parse *, FILE *); 20958910Salfredstatic void authenticate (struct parse *, FILE *); 21058910Salfredstatic void ntpversion (struct parse *, FILE *); 21152400Sbillfstatic void warning (const char *, ...) 21252400Sbillf __attribute__((__format__(__printf__, 1, 2))); 21352400Sbillfstatic void error (const char *, ...) 21452400Sbillf __attribute__((__format__(__printf__, 1, 2))); 21573651Sdougbstatic u_long getkeyid (const char *); 21673651Sdougbstatic void atoascii (const char *, size_t, char *, size_t); 21773651Sdougbstatic void cookedprint (int, size_t, const char *, int, int, FILE *); 21873651Sdougbstatic void rawprint (int, size_t, const char *, int, int, FILE *); 21973651Sdougbstatic void startoutput (void); 22073651Sdougbstatic void output (FILE *, const char *, const char *); 22152400Sbillfstatic void endoutput (FILE *); 22252400Sbillfstatic void outputarr (FILE *, char *, int, l_fp *); 22367949Sdougbstatic int assoccmp (const void *, const void *); 22452400Sbillfstatic void on_ctrlc (void); 22552400Sbillf u_short varfmt (const char *); 22652400Sbillfstatic int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 22752400Sbillfvoid ntpq_custom_opt_handler (tOptions *, tOptDesc *); 22852400Sbillf 22967949Sdougb#ifdef OPENSSL 23052400Sbillf# ifdef HAVE_EVP_MD_DO_ALL_SORTED 23152400Sbillfstatic void list_md_fn(const EVP_MD *m, const char *from, 23252400Sbillf const char *to, void *arg ); 23352400Sbillf# endif 23452400Sbillf#endif 23552400Sbillfstatic char *list_digest_names(void); 23652400Sbillf 23752400Sbillf/* 23852400Sbillf * Built-in commands we understand 23952400Sbillf */ 24052400Sbillfstruct xcmd builtins[] = { 24152400Sbillf { "?", help, { OPT|NTP_STR, NO, NO, NO }, 24252400Sbillf { "command", "", "", "" }, 24352400Sbillf "tell the use and syntax of commands" }, 24452400Sbillf { "help", help, { OPT|NTP_STR, NO, NO, NO }, 24552400Sbillf { "command", "", "", "" }, 24652400Sbillf "tell the use and syntax of commands" }, 24752400Sbillf { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 24852400Sbillf { "msec", "", "", "" }, 24952400Sbillf "set the primary receive time out" }, 25052400Sbillf { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 25152400Sbillf { "msec", "", "", "" }, 25252400Sbillf "set the delay added to encryption time stamps" }, 25352400Sbillf { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 25467949Sdougb { "-4|-6", "hostname", "", "" }, 25567949Sdougb "specify the host whose NTP server we talk to" }, 25667949Sdougb { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 25752400Sbillf { "n", "verbose", "", "" }, 25852400Sbillf "poll an NTP server in client mode `n' times" }, 25952400Sbillf { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 26052400Sbillf { "", "", "", "" }, 26152400Sbillf "specify a password to use for authenticated requests"}, 26252400Sbillf { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 26352400Sbillf { "yes|no", "", "", "" }, 26452400Sbillf "specify whether hostnames or net numbers are printed"}, 26552400Sbillf { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 26652400Sbillf { "no|more|less", "", "", "" }, 26752400Sbillf "set/change debugging level" }, 26852400Sbillf { "quit", quit, { NO, NO, NO, NO }, 26952400Sbillf { "", "", "", "" }, 27052400Sbillf "exit ntpq" }, 27152400Sbillf { "exit", quit, { NO, NO, NO, NO }, 27267949Sdougb { "", "", "", "" }, 27367949Sdougb "exit ntpq" }, 27467949Sdougb { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 27552400Sbillf { "key#", "", "", "" }, 27652400Sbillf "set keyid to use for authenticated requests" }, 27752400Sbillf { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 27852400Sbillf { "hash|ipv4", "", "", "" }, 27952400Sbillf "display refid's as IPv4 or hash" }, 28052400Sbillf { "version", version, { NO, NO, NO, NO }, 28152400Sbillf { "", "", "", "" }, 28252400Sbillf "print version number" }, 28352400Sbillf { "raw", raw, { NO, NO, NO, NO }, 28452400Sbillf { "", "", "", "" }, 28552400Sbillf "do raw mode variable output" }, 28652400Sbillf { "cooked", cooked, { NO, NO, NO, NO }, 28752400Sbillf { "", "", "", "" }, 28864467Sbrian "do cooked mode variable output" }, 28952400Sbillf { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 29064467Sbrian { "yes|no", "", "", "" }, 29167859Sdougb "always authenticate requests to this server" }, 29252400Sbillf { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 29352400Sbillf { "version number", "", "", "" }, 29464467Sbrian "set the NTP version number to use for requests" }, 29564467Sbrian { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 29652400Sbillf { "key type %s", "", "", "" }, 29752400Sbillf NULL }, 29852400Sbillf { 0, 0, { NO, NO, NO, NO }, 29952400Sbillf { "", "", "", "" }, "" } 30052400Sbillf}; 30167859Sdougb 30267859Sdougb 30367859Sdougb/* 30452400Sbillf * Default values we use. 30558910Salfred */ 30652400Sbillf#define DEFHOST "localhost" /* default host name */ 30752400Sbillf#define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 30858910Salfred#define DEFSTIMEOUT 3 /* and 3 more for each additional */ 30964467Sbrian/* 31064467Sbrian * Requests are automatically retried once, so total timeout with no 31164467Sbrian * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 31258910Salfred * extreme, a request eliciting 32 packets of responses each for some 31364467Sbrian * reason nearly DEFSTIMEOUT seconds after the prior in that series, 31464467Sbrian * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 31564467Sbrian * 93 seconds to fail each of two times, or 186 seconds. 31664467Sbrian * Some commands involve a series of requests, such as "peers" and 31764467Sbrian * "mrulist", so the cumulative timeouts are even longer for those. 31864467Sbrian */ 31958910Salfred#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 32052400Sbillf#define LENHOSTNAME 256 /* host name is 256 characters long */ 32160420Sbsd#define MAXCMDS 100 /* maximum commands on cmd line */ 32252400Sbillf#define MAXHOSTS 200 /* maximum hosts on cmd line */ 32352400Sbillf#define MAXLINE 512 /* maximum line length */ 32458910Salfred#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 32558910Salfred#define MAXVARLEN 256 /* maximum length of a variable name */ 32658910Salfred#define MAXVALLEN 2048 /* maximum length of a variable value */ 32752400Sbillf#define MAXOUTLINE 72 /* maximum length of an output line */ 32852400Sbillf#define SCREENWIDTH 76 /* nominal screen width in columns */ 32958910Salfred 33052400Sbillf/* 33152400Sbillf * Some variables used and manipulated locally 33252400Sbillf */ 33352400Sbillfstruct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 33452400Sbillfstruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 33552400Sbillfl_fp delay_time; /* delay time */ 33652400Sbillfchar currenthost[LENHOSTNAME]; /* current host name */ 33752400Sbillfint currenthostisnum; /* is prior text from IP? */ 33852400Sbillfstruct sockaddr_in hostaddr; /* host address */ 33952400Sbillfint showhostnames = 1; /* show host names by default */ 34052400Sbillfint wideremote = 0; /* show wide remote names? */ 34152400Sbillf 34252400Sbillfint ai_fam_templ; /* address family */ 34352400Sbillfint ai_fam_default; /* default address family */ 34452400SbillfSOCKET sockfd; /* fd socket is opened on */ 34552400Sbillfint havehost = 0; /* set to 1 when host open */ 34652400Sbillfint s_port = 0; 34752400Sbillfstruct servent *server_entry = NULL; /* server entry for ntp */ 34852400Sbillf 34952400Sbillf 35052400Sbillf/* 35152400Sbillf * Sequence number used for requests. It is incremented before 35273651Sdougb * it is used. 35373651Sdougb */ 35473651Sdougbu_short sequence; 35573651Sdougb 35652400Sbillf/* 35752400Sbillf * Holds data returned from queries. Declare buffer long to be sure of 35852400Sbillf * alignment. 35952400Sbillf */ 36052400Sbillf#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 36152400Sbillflong pktdata[DATASIZE/sizeof(long)]; 36252400Sbillf 36352400Sbillf/* 36452400Sbillf * assoc_cache[] is a dynamic array which allows references to 36567859Sdougb * associations using &1 ... &N for n associations, avoiding manual 36652400Sbillf * lookup of the current association IDs for a given ntpd. It also 36752400Sbillf * caches the status word for each association, retrieved incidentally. 36852400Sbillf */ 36952400Sbillfstruct association * assoc_cache; 37052400Sbillfu_int assoc_cache_slots;/* count of allocated array entries */ 37152400Sbillfu_int numassoc; /* number of cached associations */ 37252400Sbillf 37352400Sbillf/* 37452400Sbillf * For commands typed on the command line (with the -c option) 37552400Sbillf */ 37667859Sdougbint numcmds = 0; 37767859Sdougbconst char *ccmds[MAXCMDS]; 37867859Sdougb#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 37967859Sdougb 38067859Sdougb/* 38167859Sdougb * When multiple hosts are specified. 38267859Sdougb */ 38367859Sdougb 38467859Sdougbu_int numhosts; 38567859Sdougb 38652400Sbillfchost chosts[MAXHOSTS]; 38767859Sdougb#define ADDHOST(cp) \ 38867859Sdougb do { \ 38967859Sdougb if (numhosts < MAXHOSTS) { \ 39067859Sdougb chosts[numhosts].name = (cp); \ 39167859Sdougb chosts[numhosts].fam = ai_fam_templ; \ 39267859Sdougb numhosts++; \ 39367859Sdougb } \ 39467859Sdougb } while (0) 39567859Sdougb 39667859Sdougb/* 39767859Sdougb * Macro definitions we use 39867859Sdougb */ 39967859Sdougb#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 40067859Sdougb#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 40167859Sdougb#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 40267859Sdougb 40367859Sdougb/* 40467859Sdougb * Jump buffer for longjumping back to the command level 40567859Sdougb */ 40667859Sdougbjmp_buf interrupt_buf; 40752400Sbillf 40877323Sdougb/* 40977323Sdougb * Points at file being currently printed into 41052400Sbillf */ 41152400SbillfFILE *current_output; 41252400Sbillf 41352400Sbillf/* 41452400Sbillf * Command table imported from ntpdc_ops.c 41552400Sbillf */ 41652400Sbillfextern struct xcmd opcmds[]; 41752400Sbillf 41852400Sbillfchar const *progname; 41952400Sbillf 42052400Sbillf#ifdef NO_MAIN_ALLOWED 42152400Sbillf#ifndef BUILD_AS_LIB 42252400SbillfCALL(ntpq,"ntpq",ntpqmain); 42352400Sbillf 42452400Sbillfvoid clear_globals(void) 42552400Sbillf{ 42652400Sbillf extern int ntp_optind; 42752400Sbillf showhostnames = 0; /* don'tshow host names by default */ 42852400Sbillf ntp_optind = 0; 42952400Sbillf server_entry = NULL; /* server entry for ntp */ 43052400Sbillf havehost = 0; /* set to 1 when host open */ 43152400Sbillf numassoc = 0; /* number of cached associations */ 43252400Sbillf numcmds = 0; 43352400Sbillf numhosts = 0; 43452400Sbillf} 43552400Sbillf#endif /* !BUILD_AS_LIB */ 43652400Sbillf#endif /* NO_MAIN_ALLOWED */ 43752400Sbillf 43852400Sbillf/* 43952400Sbillf * main - parse arguments and handle options 44052400Sbillf */ 44152400Sbillf#ifndef NO_MAIN_ALLOWED 44252400Sbillfint 44352400Sbillfmain( 44468507Sdougb int argc, 44568507Sdougb char *argv[] 44668507Sdougb ) 44768507Sdougb{ 44868507Sdougb return ntpqmain(argc, argv); 44968507Sdougb} 45052400Sbillf#endif 45174992Sasmodai 45252400Sbillf#ifndef BUILD_AS_LIB 45377323Sdougbint 45477323Sdougbntpqmain( 45552400Sbillf int argc, 45652400Sbillf char *argv[] 45752400Sbillf ) 45877323Sdougb{ 45977323Sdougb u_int ihost; 46077323Sdougb int icmd; 46167949Sdougb 46267949Sdougb 46367949Sdougb#ifdef SYS_VXWORKS 46467949Sdougb clear_globals(); 46567949Sdougb taskPrioritySet(taskIdSelf(), 100 ); 46667949Sdougb#endif 46767949Sdougb 46867949Sdougb delay_time.l_ui = 0; 46967949Sdougb delay_time.l_uf = DEFDELAY; 47067949Sdougb 47167949Sdougb init_lib(); /* sets up ipv4_works, ipv6_works */ 47267949Sdougb ssl_applink(); 47367949Sdougb init_auth(); 47467949Sdougb 47567949Sdougb /* Check to see if we have IPv6. Otherwise default to IPv4 */ 47667949Sdougb if (!ipv6_works) 47767949Sdougb ai_fam_default = AF_INET; 47867949Sdougb 47967949Sdougb /* Fixup keytype's help based on available digest names */ 48067949Sdougb 48167949Sdougb { 48252534Sbillf char *list; 48352534Sbillf char *msg; 48452534Sbillf 48552534Sbillf list = list_digest_names(); 48652534Sbillf for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) { 48752534Sbillf if (strcmp("keytype", builtins[icmd].keyword) == 0) 48852534Sbillf break; 48965115Sben } 49068507Sdougb 49165115Sben /* CID: 1295478 */ 49265115Sben /* This should only "trip" if "keytype" is removed from builtins */ 49365115Sben INSIST(icmd < sizeof(builtins)/sizeof(builtins[0])); 49452400Sbillf 49552400Sbillf#ifdef OPENSSL 49652400Sbillf builtins[icmd].desc[0] = "digest-name"; 49777478Sdougb my_easprintf(&msg, 49877478Sdougb "set key type to use for authenticated requests, one of:%s", 49977478Sdougb list); 50077478Sdougb#else 50177478Sdougb builtins[icmd].desc[0] = "md5"; 50277478Sdougb my_easprintf(&msg, 50377478Sdougb "set key type to use for authenticated requests (%s)", 50477478Sdougb list); 50552400Sbillf#endif 50652400Sbillf builtins[icmd].comment = msg; 50752400Sbillf free(list); 50852400Sbillf } 50952400Sbillf 51052400Sbillf progname = argv[0]; 51152400Sbillf 51252400Sbillf { 51377335Sdougb int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 51452400Sbillf argc -= optct; 51552400Sbillf argv += optct; 51667859Sdougb } 51752400Sbillf 51852400Sbillf /* 51967859Sdougb * Process options other than -c and -p, which are specially 52052400Sbillf * handled by ntpq_custom_opt_handler(). 52167859Sdougb */ 52252400Sbillf 52367859Sdougb debug = OPT_VALUE_SET_DEBUG_LEVEL; 52452400Sbillf 52552400Sbillf if (HAVE_OPT(IPV4)) 52667859Sdougb ai_fam_templ = AF_INET; 52767859Sdougb else if (HAVE_OPT(IPV6)) 52867859Sdougb ai_fam_templ = AF_INET6; 52952400Sbillf else 53052400Sbillf ai_fam_templ = ai_fam_default; 53152400Sbillf 53252400Sbillf if (HAVE_OPT(INTERACTIVE)) 53352400Sbillf interactive = 1; 53452400Sbillf 53552400Sbillf if (HAVE_OPT(NUMERIC)) 53652400Sbillf showhostnames = 0; 53767949Sdougb 53852400Sbillf if (HAVE_OPT(WIDE)) 53967949Sdougb wideremote = 1; 54052400Sbillf 54167949Sdougb old_rv = HAVE_OPT(OLD_RV); 54267949Sdougb 54367949Sdougb drefid = OPT_VALUE_REFID; 54467949Sdougb 54567949Sdougb if (0 == argc) { 54667949Sdougb ADDHOST(DEFHOST); 54767949Sdougb } else { 54867949Sdougb for (ihost = 0; ihost < (u_int)argc; ihost++) { 54967949Sdougb if ('-' == *argv[ihost]) { 55052400Sbillf // 55152400Sbillf // If I really cared I'd also check: 55267859Sdougb // 0 == argv[ihost][2] 55367859Sdougb // 55467859Sdougb // and there are other cases as well... 55552400Sbillf // 55652400Sbillf if ('4' == argv[ihost][1]) { 55752400Sbillf ai_fam_templ = AF_INET; 55852400Sbillf continue; 55952400Sbillf } else if ('6' == argv[ihost][1]) { 56052400Sbillf ai_fam_templ = AF_INET6; 56152400Sbillf continue; 56252400Sbillf } else { 56352400Sbillf // XXX Throw a usage error 56452400Sbillf } 56552400Sbillf } 56652400Sbillf ADDHOST(argv[ihost]); 56752400Sbillf } 56852400Sbillf } 56952400Sbillf 57052400Sbillf if (numcmds == 0 && interactive == 0 57152400Sbillf && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 57278490Sdougb interactive = 1; 57378490Sdougb } 57478490Sdougb 57578490Sdougb set_ctrl_c_hook(on_ctrlc); 57678490Sdougb#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 57778490Sdougb if (interactive) 57878490Sdougb push_ctrl_c_handler(abortcmd); 57978490Sdougb#endif /* SYS_WINNT */ 58078490Sdougb 58152400Sbillf if (numcmds == 0) { 58252400Sbillf (void) openhost(chosts[0].name, chosts[0].fam); 58352400Sbillf getcmds(); 58452400Sbillf } else { 58567949Sdougb for (ihost = 0; ihost < numhosts; ihost++) { 58652400Sbillf if (openhost(chosts[ihost].name, chosts[ihost].fam)) 58752400Sbillf for (icmd = 0; icmd < numcmds; icmd++) 58852400Sbillf docmd(ccmds[icmd]); 58952400Sbillf } 59052400Sbillf } 59152400Sbillf#ifdef SYS_WINNT 59267949Sdougb WSACleanup(); 59377323Sdougb#endif /* SYS_WINNT */ 59477323Sdougb return 0; 59567949Sdougb} 59652400Sbillf#endif /* !BUILD_AS_LIB */ 59752400Sbillf 59877323Sdougb/* 59977323Sdougb * openhost - open a socket to a host 60052400Sbillf */ 60152400Sbillfstatic int 60252400Sbillfopenhost( 60364625Sgshapiro const char *hname, 60452400Sbillf int fam 60552400Sbillf ) 60652400Sbillf{ 60752400Sbillf const char svc[] = "ntp"; 60852400Sbillf char temphost[LENHOSTNAME]; 60952400Sbillf int a_info, i; 61078490Sdougb struct addrinfo hints, *ai; 61152400Sbillf sockaddr_u addr; 61252400Sbillf size_t octets; 61352400Sbillf register const char *cp; 61452400Sbillf char name[LENHOSTNAME]; 61577335Sdougb 61677335Sdougb /* 61752400Sbillf * We need to get by the [] if they were entered 61852400Sbillf */ 61967859Sdougb 62067859Sdougb cp = hname; 62167859Sdougb 62267859Sdougb if (*cp == '[') { 62367859Sdougb cp++; 62452400Sbillf for (i = 0; *cp && *cp != ']'; cp++, i++) 62552400Sbillf name[i] = *cp; 62652400Sbillf if (*cp == ']') { 62752400Sbillf name[i] = '\0'; 62852400Sbillf hname = name; 62952400Sbillf } else { 63067949Sdougb return 0; 63152400Sbillf } 63252400Sbillf } 63352400Sbillf 63467859Sdougb /* 63567859Sdougb * First try to resolve it as an ip address and if that fails, 63677335Sdougb * do a fullblown (dns) lookup. That way we only use the dns 63777335Sdougb * when it is needed and work around some implementations that 63877335Sdougb * will return an "IPv4-mapped IPv6 address" address if you 63977335Sdougb * give it an IPv4 address to lookup. 64077335Sdougb */ 64167859Sdougb ZERO(hints); 64252400Sbillf hints.ai_family = fam; 64352400Sbillf hints.ai_protocol = IPPROTO_UDP; 64452400Sbillf hints.ai_socktype = SOCK_DGRAM; 64552400Sbillf hints.ai_flags = Z_AI_NUMERICHOST; 64652400Sbillf ai = NULL; 64752400Sbillf 64852400Sbillf a_info = getaddrinfo(hname, svc, &hints, &ai); 64952400Sbillf if (a_info == EAI_NONAME 65067949Sdougb#ifdef EAI_NODATA 65167949Sdougb || a_info == EAI_NODATA 65267949Sdougb#endif 65352400Sbillf ) { 65452400Sbillf hints.ai_flags = AI_CANONNAME; 65567949Sdougb#ifdef AI_ADDRCONFIG 65652400Sbillf hints.ai_flags |= AI_ADDRCONFIG; 65752400Sbillf#endif 65852400Sbillf a_info = getaddrinfo(hname, svc, &hints, &ai); 65952400Sbillf } 66052400Sbillf#ifdef AI_ADDRCONFIG 66152400Sbillf /* Some older implementations don't like AI_ADDRCONFIG. */ 66252400Sbillf if (a_info == EAI_BADFLAGS) { 66352400Sbillf hints.ai_flags &= ~AI_ADDRCONFIG; 66452400Sbillf a_info = getaddrinfo(hname, svc, &hints, &ai); 66552400Sbillf } 66652400Sbillf#endif 66752400Sbillf if (a_info != 0) { 66878490Sdougb fprintf(stderr, "%s\n", gai_strerror(a_info)); 66952400Sbillf return 0; 67052400Sbillf } 67152400Sbillf 67252400Sbillf INSIST(ai != NULL); 67352400Sbillf ZERO(addr); 67478490Sdougb octets = min(sizeof(addr), ai->ai_addrlen); 67567949Sdougb memcpy(&addr, ai->ai_addr, octets); 67667949Sdougb 67767949Sdougb if (ai->ai_canonname == NULL) { 67867949Sdougb strlcpy(temphost, stoa(&addr), sizeof(temphost)); 67967949Sdougb currenthostisnum = TRUE; 68078490Sdougb } else { 68152400Sbillf strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 68252400Sbillf currenthostisnum = FALSE; 68352400Sbillf } 68452400Sbillf 68567949Sdougb if (debug > 2) 68667949Sdougb printf("Opening host %s (%s)\n", 68767949Sdougb temphost, 68852400Sbillf (ai->ai_family == AF_INET) 68967949Sdougb ? "AF_INET" 69067949Sdougb : (ai->ai_family == AF_INET6) 69167949Sdougb ? "AF_INET6" 69267949Sdougb : "AF-???" 69367949Sdougb ); 69467949Sdougb 69552400Sbillf if (havehost == 1) { 69652400Sbillf if (debug > 2) 69767949Sdougb printf("Closing old host %s\n", currenthost); 69852400Sbillf closesocket(sockfd); 69952400Sbillf havehost = 0; 70067949Sdougb } 70167949Sdougb strlcpy(currenthost, temphost, sizeof(currenthost)); 70267949Sdougb 70367949Sdougb /* port maps to the same location in both families */ 70467949Sdougb s_port = NSRCPORT(&addr); 70577325Sdougb#ifdef SYS_VXWORKS 70677325Sdougb ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 70777325Sdougb if (ai->ai_family == AF_INET) 70877325Sdougb *(struct sockaddr_in *)&hostaddr= 70977325Sdougb *((struct sockaddr_in *)ai->ai_addr); 71077325Sdougb else 71177325Sdougb *(struct sockaddr_in6 *)&hostaddr= 71277325Sdougb *((struct sockaddr_in6 *)ai->ai_addr); 71377325Sdougb#endif /* SYS_VXWORKS */ 71477325Sdougb 71577325Sdougb#ifdef SYS_WINNT 71677325Sdougb { 71777325Sdougb int optionValue = SO_SYNCHRONOUS_NONALERT; 71877325Sdougb int err; 71977325Sdougb 72077325Sdougb err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 72167949Sdougb (char *)&optionValue, sizeof(optionValue)); 72267949Sdougb if (err) { 72367949Sdougb mfprintf(stderr, 72452400Sbillf "setsockopt(SO_SYNCHRONOUS_NONALERT)" 72552400Sbillf " error: %m\n"); 72652400Sbillf freeaddrinfo(ai); 72752400Sbillf exit(1); 72852400Sbillf } 72952400Sbillf } 73052400Sbillf#endif /* SYS_WINNT */ 73173651Sdougb 73273651Sdougb sockfd = socket(ai->ai_family, ai->ai_socktype, 73352400Sbillf ai->ai_protocol); 73467949Sdougb if (sockfd == INVALID_SOCKET) { 73573651Sdougb error("socket"); 73667949Sdougb freeaddrinfo(ai); 73767949Sdougb return 0; 73867949Sdougb } 73967949Sdougb 74052400Sbillf 74152400Sbillf#ifdef NEED_RCVBUF_SLOP 74252400Sbillf# ifdef SO_RCVBUF 74352400Sbillf { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 74452400Sbillf if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 74552400Sbillf &rbufsize, sizeof(int)) == -1) 74652400Sbillf error("setsockopt"); 74752400Sbillf } 74852400Sbillf# endif 74952400Sbillf#endif 75052400Sbillf 75167949Sdougb if 75252400Sbillf#ifdef SYS_VXWORKS 75352400Sbillf (connect(sockfd, (struct sockaddr *)&hostaddr, 75452400Sbillf sizeof(hostaddr)) == -1) 75577323Sdougb#else 75677323Sdougb (connect(sockfd, (struct sockaddr *)ai->ai_addr, 75777323Sdougb ai->ai_addrlen) == -1) 75867859Sdougb#endif /* SYS_VXWORKS */ 75952400Sbillf { 76052400Sbillf error("connect"); 76152400Sbillf freeaddrinfo(ai); 76258910Salfred return 0; 76358910Salfred } 76452400Sbillf freeaddrinfo(ai); 76552400Sbillf havehost = 1; 76652400Sbillf numassoc = 0; 76752400Sbillf 76852400Sbillf return 1; 76952400Sbillf} 77052400Sbillf 77152400Sbillf 77252400Sbillfstatic void 77352400Sbillfdump_hex_printable( 77452534Sbillf const void * data, 77552400Sbillf size_t len 77652400Sbillf ) 77752400Sbillf{ 77852400Sbillf const char * cdata; 77952400Sbillf const char * rowstart; 78052400Sbillf size_t idx; 78152400Sbillf size_t rowlen; 78277335Sdougb u_char uch; 78352400Sbillf 78452400Sbillf cdata = data; 78552400Sbillf while (len > 0) { 78652400Sbillf rowstart = cdata; 78767859Sdougb rowlen = min(16, len); 78867859Sdougb for (idx = 0; idx < rowlen; idx++) { 78967859Sdougb uch = *(cdata++); 79052400Sbillf printf("%02x ", uch); 79152400Sbillf } 79252400Sbillf for ( ; idx < 16 ; idx++) 79352400Sbillf printf(" "); 79452400Sbillf cdata = rowstart; 79552400Sbillf for (idx = 0; idx < rowlen; idx++) { 79652400Sbillf uch = *(cdata++); 79752400Sbillf printf("%c", (isprint(uch)) 79852400Sbillf ? uch 79952400Sbillf : '.'); 80052400Sbillf } 80152400Sbillf printf("\n"); 80252400Sbillf len -= rowlen; 80352400Sbillf } 80452400Sbillf} 80552400Sbillf 80668153Sdougb 80768153Sdougb/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 80868153Sdougb/* 80973651Sdougb * sendpkt - send a packet to the remote host 81073651Sdougb */ 81173651Sdougbstatic int 81273651Sdougbsendpkt( 81377323Sdougb void * xdata, 81477323Sdougb size_t xdatalen 81573651Sdougb ) 81673651Sdougb{ 81773651Sdougb if (debug >= 3) 81873651Sdougb printf("Sending %zu octets\n", xdatalen); 81968153Sdougb 82077323Sdougb if (send(sockfd, xdata, xdatalen, 0) == -1) { 82177323Sdougb warning("write to %s failed", currenthost); 82268153Sdougb return -1; 82373651Sdougb } 82473651Sdougb 82568153Sdougb if (debug >= 4) { 82668153Sdougb printf("Request packet:\n"); 82768153Sdougb dump_hex_printable(xdata, xdatalen); 82873651Sdougb } 82973651Sdougb return 0; 83073651Sdougb} 83173651Sdougb 83273651Sdougb/* 83377335Sdougb * getresponse - get a (series of) response packet(s) and return the data 83473651Sdougb */ 83573651Sdougbstatic int 83673651Sdougbgetresponse( 83773651Sdougb int opcode, 83877335Sdougb int associd, 83977335Sdougb u_short *rstatus, 84073651Sdougb size_t *rsize, 84173651Sdougb const char **rdata, 84277335Sdougb int timeo 84377335Sdougb ) 84477335Sdougb{ 84577335Sdougb struct ntp_control rpkt; 84677335Sdougb struct sock_timeval tvo; 84777335Sdougb u_short offsets[MAXFRAGS+1]; 84873651Sdougb u_short counts[MAXFRAGS+1]; 84977335Sdougb u_short offset; 85077335Sdougb u_short count; 85177335Sdougb size_t numfrags; 85277335Sdougb size_t f; 85373651Sdougb size_t ff; 85473651Sdougb int seenlastfrag; 85573651Sdougb int shouldbesize; 85673651Sdougb fd_set fds; 85773651Sdougb int n; 85873651Sdougb int errcode; 85952400Sbillf /* absolute timeout checks. Not 'time_t' by intention! */ 86052400Sbillf uint32_t tobase; /* base value for timeout */ 86152400Sbillf uint32_t tospan; /* timeout span (max delay) */ 86252400Sbillf uint32_t todiff; /* current delay */ 86377335Sdougb 86477335Sdougb /* 86577335Sdougb * This is pretty tricky. We may get between 1 and MAXFRAG packets 86652400Sbillf * back in response to the request. We peel the data out of 86752400Sbillf * each packet and collect it in one long block. When the last 86852400Sbillf * packet in the sequence is received we'll know how much data we 86952400Sbillf * should have had. Note we use one long time out, should reconsider. 87052400Sbillf */ 87152400Sbillf *rsize = 0; 87252400Sbillf if (rstatus) 87377335Sdougb *rstatus = 0; 87477335Sdougb *rdata = (char *)pktdata; 87577335Sdougb 87677335Sdougb numfrags = 0; 87777335Sdougb seenlastfrag = 0; 87877335Sdougb 87977335Sdougb tobase = (uint32_t)time(NULL); 88077335Sdougb 88177335Sdougb FD_ZERO(&fds); 88277335Sdougb 88352400Sbillf /* 88452400Sbillf * Loop until we have an error or a complete response. Nearly all 88552400Sbillf * code paths to loop again use continue. 88652400Sbillf */ 88752400Sbillf for (;;) { 88852400Sbillf 88952400Sbillf if (numfrags == 0) 89052400Sbillf tvo = tvout; 89177335Sdougb else 89277335Sdougb tvo = tvsout; 89377335Sdougb tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 89452400Sbillf 89552400Sbillf FD_SET(sockfd, &fds); 89652400Sbillf n = select(sockfd+1, &fds, NULL, NULL, &tvo); 89752400Sbillf if (n == -1) { 89852400Sbillf#if !defined(SYS_WINNT) && defined(EINTR) 89952400Sbillf /* Windows does not know about EINTR (until very 90052400Sbillf * recently) and the handling of console events 90152400Sbillf * is *very* different from POSIX/UNIX signal 90277335Sdougb * handling anyway. 90377335Sdougb * 90477335Sdougb * Under non-windows targets we map EINTR as 90577335Sdougb * 'last packet was received' and try to exit 90677335Sdougb * the receive sequence. 90777335Sdougb */ 90877335Sdougb if (errno == EINTR) { 90977335Sdougb seenlastfrag = 1; 91077335Sdougb goto maybe_final; 91152400Sbillf } 91252400Sbillf#endif 91352400Sbillf warning("select fails"); 91452400Sbillf return -1; 91552400Sbillf } 91667949Sdougb 91767949Sdougb /* 91867949Sdougb * Check if this is already too late. Trash the data and 91967949Sdougb * fake a timeout if this is so. 92052400Sbillf */ 92167850Sdougb todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 922 if ((n > 0) && (todiff > tospan)) { 923 n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 924 n = 0; /* faked timeout return from 'select()'*/ 925 } 926 927 if (n == 0) { 928 /* 929 * Timed out. Return what we have 930 */ 931 if (numfrags == 0) { 932 if (timeo) 933 fprintf(stderr, 934 "%s: timed out, nothing received\n", 935 currenthost); 936 return ERR_TIMEOUT; 937 } 938 if (timeo) 939 fprintf(stderr, 940 "%s: timed out with incomplete data\n", 941 currenthost); 942 if (debug) { 943 fprintf(stderr, 944 "ERR_INCOMPLETE: Received fragments:\n"); 945 for (f = 0; f < numfrags; f++) 946 fprintf(stderr, 947 "%2u: %5d %5d\t%3d octets\n", 948 (u_int)f, offsets[f], 949 offsets[f] + 950 counts[f], 951 counts[f]); 952 fprintf(stderr, 953 "last fragment %sreceived\n", 954 (seenlastfrag) 955 ? "" 956 : "not "); 957 } 958 return ERR_INCOMPLETE; 959 } 960 961 n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 962 if (n == -1) { 963 warning("read"); 964 return -1; 965 } 966 967 if (debug >= 4) { 968 printf("Response packet:\n"); 969 dump_hex_printable(&rpkt, n); 970 } 971 972 /* 973 * Check for format errors. Bug proofing. 974 */ 975 if (n < (int)CTL_HEADER_LEN) { 976 if (debug) 977 printf("Short (%d byte) packet received\n", n); 978 continue; 979 } 980 if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 981 || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 982 if (debug) 983 printf("Packet received with version %d\n", 984 PKT_VERSION(rpkt.li_vn_mode)); 985 continue; 986 } 987 if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 988 if (debug) 989 printf("Packet received with mode %d\n", 990 PKT_MODE(rpkt.li_vn_mode)); 991 continue; 992 } 993 if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 994 if (debug) 995 printf("Received request packet, wanted response\n"); 996 continue; 997 } 998 999 /* 1000 * Check opcode and sequence number for a match. 1001 * Could be old data getting to us. 1002 */ 1003 if (ntohs(rpkt.sequence) != sequence) { 1004 if (debug) 1005 printf("Received sequnce number %d, wanted %d\n", 1006 ntohs(rpkt.sequence), sequence); 1007 continue; 1008 } 1009 if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1010 if (debug) 1011 printf( 1012 "Received opcode %d, wanted %d (sequence number okay)\n", 1013 CTL_OP(rpkt.r_m_e_op), opcode); 1014 continue; 1015 } 1016 1017 /* 1018 * Check the error code. If non-zero, return it. 1019 */ 1020 if (CTL_ISERROR(rpkt.r_m_e_op)) { 1021 errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1022 if (CTL_ISMORE(rpkt.r_m_e_op)) 1023 TRACE(1, ("Error code %d received on not-final packet\n", 1024 errcode)); 1025 if (errcode == CERR_UNSPEC) 1026 return ERR_UNSPEC; 1027 return errcode; 1028 } 1029 1030 /* 1031 * Check the association ID to make sure it matches what 1032 * we sent. 1033 */ 1034 if (ntohs(rpkt.associd) != associd) { 1035 TRACE(1, ("Association ID %d doesn't match expected %d\n", 1036 ntohs(rpkt.associd), associd)); 1037 /* 1038 * Hack for silly fuzzballs which, at the time of writing, 1039 * return an assID of sys.peer when queried for system variables. 1040 */ 1041#ifdef notdef 1042 continue; 1043#endif 1044 } 1045 1046 /* 1047 * Collect offset and count. Make sure they make sense. 1048 */ 1049 offset = ntohs(rpkt.offset); 1050 count = ntohs(rpkt.count); 1051 1052 /* 1053 * validate received payload size is padded to next 32-bit 1054 * boundary and no smaller than claimed by rpkt.count 1055 */ 1056 if (n & 0x3) { 1057 TRACE(1, ("Response packet not padded, size = %d\n", 1058 n)); 1059 continue; 1060 } 1061 1062 shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 1063 1064 if (n < shouldbesize) { 1065 printf("Response packet claims %u octets payload, above %ld received\n", 1066 count, (long)n - CTL_HEADER_LEN); 1067 return ERR_INCOMPLETE; 1068 } 1069 1070 if (debug >= 3 && shouldbesize > n) { 1071 u_int32 key; 1072 u_int32 *lpkt; 1073 int maclen; 1074 1075 /* 1076 * Usually we ignore authentication, but for debugging purposes 1077 * we watch it here. 1078 */ 1079 /* round to 8 octet boundary */ 1080 shouldbesize = (shouldbesize + 7) & ~7; 1081 1082 maclen = n - shouldbesize; 1083 if (maclen >= (int)MIN_MAC_LEN) { 1084 printf( 1085 "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1086 n, shouldbesize, maclen); 1087 lpkt = (u_int32 *)&rpkt; 1088 printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1089 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1090 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1091 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1092 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1093 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1094 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1095 key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1096 printf("Authenticated with keyid %lu\n", (u_long)key); 1097 if (key != 0 && key != info_auth_keyid) { 1098 printf("We don't know that key\n"); 1099 } else { 1100 if (authdecrypt(key, (u_int32 *)&rpkt, 1101 n - maclen, maclen)) { 1102 printf("Auth okay!\n"); 1103 } else { 1104 printf("Auth failed!\n"); 1105 } 1106 } 1107 } 1108 } 1109 1110 TRACE(2, ("Got packet, size = %d\n", n)); 1111 if (count > (n - CTL_HEADER_LEN)) { 1112 TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1113 count, (long)n - CTL_HEADER_LEN)); 1114 continue; 1115 } 1116 if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1117 TRACE(1, ("Received count of 0 in non-final fragment\n")); 1118 continue; 1119 } 1120 if (offset + count > sizeof(pktdata)) { 1121 TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1122 offset, count)); 1123 return ERR_TOOMUCH; 1124 } 1125 if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1126 TRACE(1, ("Received second last fragment packet\n")); 1127 continue; 1128 } 1129 1130 /* 1131 * So far, so good. Record this fragment, making sure it doesn't 1132 * overlap anything. 1133 */ 1134 TRACE(2, ("Packet okay\n")); 1135 1136 if (numfrags > (MAXFRAGS - 1)) { 1137 TRACE(2, ("Number of fragments exceeds maximum %d\n", 1138 MAXFRAGS - 1)); 1139 return ERR_TOOMUCH; 1140 } 1141 1142 /* 1143 * Find the position for the fragment relative to any 1144 * previously received. 1145 */ 1146 for (f = 0; 1147 f < numfrags && offsets[f] < offset; 1148 f++) { 1149 /* empty body */ ; 1150 } 1151 1152 if (f < numfrags && offset == offsets[f]) { 1153 TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1154 count, offset, counts[f], offsets[f])); 1155 continue; 1156 } 1157 1158 if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1159 TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1160 offset, counts[f-1], offsets[f-1])); 1161 continue; 1162 } 1163 1164 if (f < numfrags && (offset + count) > offsets[f]) { 1165 TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1166 count, offset, offsets[f])); 1167 continue; 1168 } 1169 1170 for (ff = numfrags; ff > f; ff--) { 1171 offsets[ff] = offsets[ff-1]; 1172 counts[ff] = counts[ff-1]; 1173 } 1174 offsets[f] = offset; 1175 counts[f] = count; 1176 numfrags++; 1177 1178 /* 1179 * Got that stuffed in right. Figure out if this was the last. 1180 * Record status info out of the last packet. 1181 */ 1182 if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1183 seenlastfrag = 1; 1184 if (rstatus != 0) 1185 *rstatus = ntohs(rpkt.status); 1186 } 1187 1188 /* 1189 * Copy the data into the data buffer, and bump the 1190 * timout base in case we need more. 1191 */ 1192 memcpy((char *)pktdata + offset, &rpkt.u, count); 1193 tobase = (uint32_t)time(NULL); 1194 1195 /* 1196 * If we've seen the last fragment, look for holes in the sequence. 1197 * If there aren't any, we're done. 1198 */ 1199 maybe_final: 1200 if (seenlastfrag && offsets[0] == 0) { 1201 for (f = 1; f < numfrags; f++) 1202 if (offsets[f-1] + counts[f-1] != 1203 offsets[f]) 1204 break; 1205 if (f == numfrags) { 1206 *rsize = offsets[f-1] + counts[f-1]; 1207 TRACE(1, ("%lu packets reassembled into response\n", 1208 (u_long)numfrags)); 1209 return 0; 1210 } 1211 } 1212 } /* giant for (;;) collecting response packets */ 1213} /* getresponse() */ 1214 1215 1216/* 1217 * sendrequest - format and send a request packet 1218 */ 1219static int 1220sendrequest( 1221 int opcode, 1222 associd_t associd, 1223 int auth, 1224 size_t qsize, 1225 const char *qdata 1226 ) 1227{ 1228 struct ntp_control qpkt; 1229 size_t pktsize; 1230 u_long key_id; 1231 char * pass; 1232 size_t maclen; 1233 1234 /* 1235 * Check to make sure the data will fit in one packet 1236 */ 1237 if (qsize > CTL_MAX_DATA_LEN) { 1238 fprintf(stderr, 1239 "***Internal error! qsize (%zu) too large\n", 1240 qsize); 1241 return 1; 1242 } 1243 1244 /* 1245 * Fill in the packet 1246 */ 1247 qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1248 qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 1249 qpkt.sequence = htons(sequence); 1250 qpkt.status = 0; 1251 qpkt.associd = htons((u_short)associd); 1252 qpkt.offset = 0; 1253 qpkt.count = htons((u_short)qsize); 1254 1255 pktsize = CTL_HEADER_LEN; 1256 1257 /* 1258 * If we have data, copy and pad it out to a 32-bit boundary. 1259 */ 1260 if (qsize > 0) { 1261 memcpy(&qpkt.u, qdata, (size_t)qsize); 1262 pktsize += qsize; 1263 while (pktsize & (sizeof(u_int32) - 1)) { 1264 qpkt.u.data[qsize++] = 0; 1265 pktsize++; 1266 } 1267 } 1268 1269 /* 1270 * If it isn't authenticated we can just send it. Otherwise 1271 * we're going to have to think about it a little. 1272 */ 1273 if (!auth && !always_auth) { 1274 return sendpkt(&qpkt, pktsize); 1275 } 1276 1277 /* 1278 * Pad out packet to a multiple of 8 octets to be sure 1279 * receiver can handle it. 1280 */ 1281 while (pktsize & 7) { 1282 qpkt.u.data[qsize++] = 0; 1283 pktsize++; 1284 } 1285 1286 /* 1287 * Get the keyid and the password if we don't have one. 1288 */ 1289 if (info_auth_keyid == 0) { 1290 key_id = getkeyid("Keyid: "); 1291 if (key_id == 0 || key_id > NTP_MAXKEY) { 1292 fprintf(stderr, 1293 "Invalid key identifier\n"); 1294 return 1; 1295 } 1296 info_auth_keyid = key_id; 1297 } 1298 if (!authistrusted(info_auth_keyid)) { 1299 pass = getpass_keytype(info_auth_keytype); 1300 if ('\0' == pass[0]) { 1301 fprintf(stderr, "Invalid password\n"); 1302 return 1; 1303 } 1304 authusekey(info_auth_keyid, info_auth_keytype, 1305 (u_char *)pass); 1306 authtrust(info_auth_keyid, 1); 1307 } 1308 1309 /* 1310 * Do the encryption. 1311 */ 1312 maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1313 if (!maclen) { 1314 fprintf(stderr, "Key not found\n"); 1315 return 1; 1316 } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1317 fprintf(stderr, 1318 "%zu octet MAC, %zu expected with %zu octet digest\n", 1319 maclen, (info_auth_hashlen + sizeof(keyid_t)), 1320 info_auth_hashlen); 1321 return 1; 1322 } 1323 1324 return sendpkt((char *)&qpkt, pktsize + maclen); 1325} 1326 1327 1328/* 1329 * show_error_msg - display the error text for a mode 6 error response. 1330 */ 1331void 1332show_error_msg( 1333 int m6resp, 1334 associd_t associd 1335 ) 1336{ 1337 if (numhosts > 1) 1338 fprintf(stderr, "server=%s ", currenthost); 1339 1340 switch (m6resp) { 1341 1342 case CERR_BADFMT: 1343 fprintf(stderr, 1344 "***Server reports a bad format request packet\n"); 1345 break; 1346 1347 case CERR_PERMISSION: 1348 fprintf(stderr, 1349 "***Server disallowed request (authentication?)\n"); 1350 break; 1351 1352 case CERR_BADOP: 1353 fprintf(stderr, 1354 "***Server reports a bad opcode in request\n"); 1355 break; 1356 1357 case CERR_BADASSOC: 1358 fprintf(stderr, 1359 "***Association ID %d unknown to server\n", 1360 associd); 1361 break; 1362 1363 case CERR_UNKNOWNVAR: 1364 fprintf(stderr, 1365 "***A request variable unknown to the server\n"); 1366 break; 1367 1368 case CERR_BADVALUE: 1369 fprintf(stderr, 1370 "***Server indicates a request variable was bad\n"); 1371 break; 1372 1373 case ERR_UNSPEC: 1374 fprintf(stderr, 1375 "***Server returned an unspecified error\n"); 1376 break; 1377 1378 case ERR_TIMEOUT: 1379 fprintf(stderr, "***Request timed out\n"); 1380 break; 1381 1382 case ERR_INCOMPLETE: 1383 fprintf(stderr, 1384 "***Response from server was incomplete\n"); 1385 break; 1386 1387 case ERR_TOOMUCH: 1388 fprintf(stderr, 1389 "***Buffer size exceeded for returned data\n"); 1390 break; 1391 1392 default: 1393 fprintf(stderr, 1394 "***Server returns unknown error code %d\n", 1395 m6resp); 1396 } 1397} 1398 1399/* 1400 * doquery - send a request and process the response, displaying 1401 * error messages for any error responses. 1402 */ 1403int 1404doquery( 1405 int opcode, 1406 associd_t associd, 1407 int auth, 1408 size_t qsize, 1409 const char *qdata, 1410 u_short *rstatus, 1411 size_t *rsize, 1412 const char **rdata 1413 ) 1414{ 1415 return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1416 rsize, rdata, FALSE); 1417} 1418 1419 1420/* 1421 * doqueryex - send a request and process the response, optionally 1422 * displaying error messages for any error responses. 1423 */ 1424int 1425doqueryex( 1426 int opcode, 1427 associd_t associd, 1428 int auth, 1429 size_t qsize, 1430 const char *qdata, 1431 u_short *rstatus, 1432 size_t *rsize, 1433 const char **rdata, 1434 int quiet 1435 ) 1436{ 1437 int res; 1438 int done; 1439 1440 /* 1441 * Check to make sure host is open 1442 */ 1443 if (!havehost) { 1444 fprintf(stderr, "***No host open, use `host' command\n"); 1445 return -1; 1446 } 1447 1448 done = 0; 1449 sequence++; 1450 1451 again: 1452 /* 1453 * send a request 1454 */ 1455 res = sendrequest(opcode, associd, auth, qsize, qdata); 1456 if (res != 0) 1457 return res; 1458 1459 /* 1460 * Get the response. If we got a standard error, print a message 1461 */ 1462 res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 1463 1464 if (res > 0) { 1465 if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 1466 if (res == ERR_INCOMPLETE) { 1467 /* 1468 * better bump the sequence so we don't 1469 * get confused about differing fragments. 1470 */ 1471 sequence++; 1472 } 1473 done = 1; 1474 goto again; 1475 } 1476 if (!quiet) 1477 show_error_msg(res, associd); 1478 1479 } 1480 return res; 1481} 1482 1483 1484#ifndef BUILD_AS_LIB 1485/* 1486 * getcmds - read commands from the standard input and execute them 1487 */ 1488static void 1489getcmds(void) 1490{ 1491 char * line; 1492 int count; 1493 1494 ntp_readline_init(interactive ? prompt : NULL); 1495 1496 for (;;) { 1497 line = ntp_readline(&count); 1498 if (NULL == line) 1499 break; 1500 docmd(line); 1501 free(line); 1502 } 1503 1504 ntp_readline_uninit(); 1505} 1506#endif /* !BUILD_AS_LIB */ 1507 1508 1509#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 1510/* 1511 * abortcmd - catch interrupts and abort the current command 1512 */ 1513static int 1514abortcmd(void) 1515{ 1516 if (current_output == stdout) 1517 (void) fflush(stdout); 1518 putc('\n', stderr); 1519 (void) fflush(stderr); 1520 if (jump) { 1521 jump = 0; 1522 longjmp(interrupt_buf, 1); 1523 } 1524 return TRUE; 1525} 1526#endif /* !SYS_WINNT && !BUILD_AS_LIB */ 1527 1528 1529#ifndef BUILD_AS_LIB 1530/* 1531 * docmd - decode the command line and execute a command 1532 */ 1533static void 1534docmd( 1535 const char *cmdline 1536 ) 1537{ 1538 char *tokens[1+MAXARGS+2]; 1539 struct parse pcmd; 1540 int ntok; 1541 static int i; 1542 struct xcmd *xcmd; 1543 1544 /* 1545 * Tokenize the command line. If nothing on it, return. 1546 */ 1547 tokenize(cmdline, tokens, &ntok); 1548 if (ntok == 0) 1549 return; 1550 1551 /* 1552 * Find the appropriate command description. 1553 */ 1554 i = findcmd(tokens[0], builtins, opcmds, &xcmd); 1555 if (i == 0) { 1556 (void) fprintf(stderr, "***Command `%s' unknown\n", 1557 tokens[0]); 1558 return; 1559 } else if (i >= 2) { 1560 (void) fprintf(stderr, "***Command `%s' ambiguous\n", 1561 tokens[0]); 1562 return; 1563 } 1564 1565 /* Warn about ignored extra args */ 1566 for (i = MAXARGS + 1; i < ntok ; ++i) { 1567 fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1568 } 1569 1570 /* 1571 * Save the keyword, then walk through the arguments, interpreting 1572 * as we go. 1573 */ 1574 pcmd.keyword = tokens[0]; 1575 pcmd.nargs = 0; 1576 for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 1577 if ((i+1) >= ntok) { 1578 if (!(xcmd->arg[i] & OPT)) { 1579 printusage(xcmd, stderr); 1580 return; 1581 } 1582 break; 1583 } 1584 if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1585 break; 1586 if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1587 return; 1588 pcmd.nargs++; 1589 } 1590 1591 i++; 1592 if (i < ntok && *tokens[i] == '>') { 1593 char *fname; 1594 1595 if (*(tokens[i]+1) != '\0') 1596 fname = tokens[i]+1; 1597 else if ((i+1) < ntok) 1598 fname = tokens[i+1]; 1599 else { 1600 (void) fprintf(stderr, "***No file for redirect\n"); 1601 return; 1602 } 1603 1604 current_output = fopen(fname, "w"); 1605 if (current_output == NULL) { 1606 (void) fprintf(stderr, "***Error opening %s: ", fname); 1607 perror(""); 1608 return; 1609 } 1610 i = 1; /* flag we need a close */ 1611 } else { 1612 current_output = stdout; 1613 i = 0; /* flag no close */ 1614 } 1615 1616 if (interactive && setjmp(interrupt_buf)) { 1617 jump = 0; 1618 return; 1619 } else { 1620 jump++; 1621 (xcmd->handler)(&pcmd, current_output); 1622 jump = 0; /* HMS: 961106: was after fclose() */ 1623 if (i) (void) fclose(current_output); 1624 } 1625 1626 return; 1627} 1628 1629 1630/* 1631 * tokenize - turn a command line into tokens 1632 * 1633 * SK: Modified to allow a quoted string 1634 * 1635 * HMS: If the first character of the first token is a ':' then (after 1636 * eating inter-token whitespace) the 2nd token is the rest of the line. 1637 */ 1638 1639static void 1640tokenize( 1641 const char *line, 1642 char **tokens, 1643 int *ntok 1644 ) 1645{ 1646 register const char *cp; 1647 register char *sp; 1648 static char tspace[MAXLINE]; 1649 1650 sp = tspace; 1651 cp = line; 1652 for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 1653 tokens[*ntok] = sp; 1654 1655 /* Skip inter-token whitespace */ 1656 while (ISSPACE(*cp)) 1657 cp++; 1658 1659 /* If we're at EOL we're done */ 1660 if (ISEOL(*cp)) 1661 break; 1662 1663 /* If this is the 2nd token and the first token begins 1664 * with a ':', then just grab to EOL. 1665 */ 1666 1667 if (*ntok == 1 && tokens[0][0] == ':') { 1668 do { 1669 if (sp - tspace >= MAXLINE) 1670 goto toobig; 1671 *sp++ = *cp++; 1672 } while (!ISEOL(*cp)); 1673 } 1674 1675 /* Check if this token begins with a double quote. 1676 * If yes, continue reading till the next double quote 1677 */ 1678 else if (*cp == '\"') { 1679 ++cp; 1680 do { 1681 if (sp - tspace >= MAXLINE) 1682 goto toobig; 1683 *sp++ = *cp++; 1684 } while ((*cp != '\"') && !ISEOL(*cp)); 1685 /* HMS: a missing closing " should be an error */ 1686 } 1687 else { 1688 do { 1689 if (sp - tspace >= MAXLINE) 1690 goto toobig; 1691 *sp++ = *cp++; 1692 } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1693 /* HMS: Why check for a " in the previous line? */ 1694 } 1695 1696 if (sp - tspace >= MAXLINE) 1697 goto toobig; 1698 *sp++ = '\0'; 1699 } 1700 return; 1701 1702 toobig: 1703 *ntok = 0; 1704 fprintf(stderr, 1705 "***Line `%s' is too big\n", 1706 line); 1707 return; 1708} 1709 1710 1711/* 1712 * getarg - interpret an argument token 1713 */ 1714static int 1715getarg( 1716 const char *str, 1717 int code, 1718 arg_v *argp 1719 ) 1720{ 1721 u_long ul; 1722 1723 switch (code & ~OPT) { 1724 case NTP_STR: 1725 argp->string = str; 1726 break; 1727 1728 case NTP_ADD: 1729 if (!getnetnum(str, &argp->netnum, NULL, 0)) 1730 return 0; 1731 break; 1732 1733 case NTP_UINT: 1734 if ('&' == str[0]) { 1735 if (!atouint(&str[1], &ul)) { 1736 fprintf(stderr, 1737 "***Association index `%s' invalid/undecodable\n", 1738 str); 1739 return 0; 1740 } 1741 if (0 == numassoc) { 1742 dogetassoc(stdout); 1743 if (0 == numassoc) { 1744 fprintf(stderr, 1745 "***No associations found, `%s' unknown\n", 1746 str); 1747 return 0; 1748 } 1749 } 1750 ul = min(ul, numassoc); 1751 argp->uval = assoc_cache[ul - 1].assid; 1752 break; 1753 } 1754 if (!atouint(str, &argp->uval)) { 1755 fprintf(stderr, "***Illegal unsigned value %s\n", 1756 str); 1757 return 0; 1758 } 1759 break; 1760 1761 case NTP_INT: 1762 if (!atoint(str, &argp->ival)) { 1763 fprintf(stderr, "***Illegal integer value %s\n", 1764 str); 1765 return 0; 1766 } 1767 break; 1768 1769 case IP_VERSION: 1770 if (!strcmp("-6", str)) { 1771 argp->ival = 6; 1772 } else if (!strcmp("-4", str)) { 1773 argp->ival = 4; 1774 } else { 1775 fprintf(stderr, "***Version must be either 4 or 6\n"); 1776 return 0; 1777 } 1778 break; 1779 } 1780 1781 return 1; 1782} 1783#endif /* !BUILD_AS_LIB */ 1784 1785 1786/* 1787 * findcmd - find a command in a command description table 1788 */ 1789static int 1790findcmd( 1791 const char * str, 1792 struct xcmd * clist1, 1793 struct xcmd * clist2, 1794 struct xcmd ** cmd 1795 ) 1796{ 1797 struct xcmd *cl; 1798 size_t clen; 1799 int nmatch; 1800 struct xcmd *nearmatch = NULL; 1801 struct xcmd *clist; 1802 1803 clen = strlen(str); 1804 nmatch = 0; 1805 if (clist1 != 0) 1806 clist = clist1; 1807 else if (clist2 != 0) 1808 clist = clist2; 1809 else 1810 return 0; 1811 1812 again: 1813 for (cl = clist; cl->keyword != 0; cl++) { 1814 /* do a first character check, for efficiency */ 1815 if (*str != *(cl->keyword)) 1816 continue; 1817 if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 1818 /* 1819 * Could be extact match, could be approximate. 1820 * Is exact if the length of the keyword is the 1821 * same as the str. 1822 */ 1823 if (*((cl->keyword) + clen) == '\0') { 1824 *cmd = cl; 1825 return 1; 1826 } 1827 nmatch++; 1828 nearmatch = cl; 1829 } 1830 } 1831 1832 /* 1833 * See if there is more to do. If so, go again. Sorry about the 1834 * goto, too much looking at BSD sources... 1835 */ 1836 if (clist == clist1 && clist2 != 0) { 1837 clist = clist2; 1838 goto again; 1839 } 1840 1841 /* 1842 * If we got extactly 1 near match, use it, else return number 1843 * of matches. 1844 */ 1845 if (nmatch == 1) { 1846 *cmd = nearmatch; 1847 return 1; 1848 } 1849 return nmatch; 1850} 1851 1852 1853/* 1854 * getnetnum - given a host name, return its net number 1855 * and (optional) full name 1856 */ 1857int 1858getnetnum( 1859 const char *hname, 1860 sockaddr_u *num, 1861 char *fullhost, 1862 int af 1863 ) 1864{ 1865 struct addrinfo hints, *ai = NULL; 1866 1867 ZERO(hints); 1868 hints.ai_flags = AI_CANONNAME; 1869#ifdef AI_ADDRCONFIG 1870 hints.ai_flags |= AI_ADDRCONFIG; 1871#endif 1872 1873 /* 1874 * decodenetnum only works with addresses, but handles syntax 1875 * that getaddrinfo doesn't: [2001::1]:1234 1876 */ 1877 if (decodenetnum(hname, num)) { 1878 if (fullhost != NULL) 1879 getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1880 LENHOSTNAME, NULL, 0, 0); 1881 return 1; 1882 } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1883 INSIST(sizeof(*num) >= ai->ai_addrlen); 1884 memcpy(num, ai->ai_addr, ai->ai_addrlen); 1885 if (fullhost != NULL) { 1886 if (ai->ai_canonname != NULL) 1887 strlcpy(fullhost, ai->ai_canonname, 1888 LENHOSTNAME); 1889 else 1890 getnameinfo(&num->sa, SOCKLEN(num), 1891 fullhost, LENHOSTNAME, NULL, 1892 0, 0); 1893 } 1894 freeaddrinfo(ai); 1895 return 1; 1896 } 1897 fprintf(stderr, "***Can't find host %s\n", hname); 1898 1899 return 0; 1900} 1901 1902 1903/* 1904 * nntohost - convert network number to host name. This routine enforces 1905 * the showhostnames setting. 1906 */ 1907const char * 1908nntohost( 1909 sockaddr_u *netnum 1910 ) 1911{ 1912 return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 1913} 1914 1915 1916/* 1917 * nntohost_col - convert network number to host name in fixed width. 1918 * This routine enforces the showhostnames setting. 1919 * When displaying hostnames longer than the width, 1920 * the first part of the hostname is displayed. When 1921 * displaying numeric addresses longer than the width, 1922 * Such as IPv6 addresses, the caller decides whether 1923 * the first or last of the numeric address is used. 1924 */ 1925const char * 1926nntohost_col( 1927 sockaddr_u * addr, 1928 size_t width, 1929 int preserve_lowaddrbits 1930 ) 1931{ 1932 const char * out; 1933 1934 if (!showhostnames || SOCK_UNSPEC(addr)) { 1935 if (preserve_lowaddrbits) 1936 out = trunc_left(stoa(addr), width); 1937 else 1938 out = trunc_right(stoa(addr), width); 1939 } else if (ISREFCLOCKADR(addr)) { 1940 out = refnumtoa(addr); 1941 } else { 1942 out = trunc_right(socktohost(addr), width); 1943 } 1944 return out; 1945} 1946 1947 1948/* 1949 * nntohostp() is the same as nntohost() plus a :port suffix 1950 */ 1951const char * 1952nntohostp( 1953 sockaddr_u *netnum 1954 ) 1955{ 1956 const char * hostn; 1957 char * buf; 1958 1959 if (!showhostnames || SOCK_UNSPEC(netnum)) 1960 return sptoa(netnum); 1961 else if (ISREFCLOCKADR(netnum)) 1962 return refnumtoa(netnum); 1963 1964 hostn = socktohost(netnum); 1965 LIB_GETBUF(buf); 1966 snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 1967 1968 return buf; 1969} 1970 1971/* 1972 * rtdatetolfp - decode an RT-11 date into an l_fp 1973 */ 1974static int 1975rtdatetolfp( 1976 char *str, 1977 l_fp *lfp 1978 ) 1979{ 1980 register char *cp; 1981 register int i; 1982 struct calendar cal; 1983 char buf[4]; 1984 1985 cal.yearday = 0; 1986 1987 /* 1988 * An RT-11 date looks like: 1989 * 1990 * d[d]-Mth-y[y] hh:mm:ss 1991 * 1992 * (No docs, but assume 4-digit years are also legal...) 1993 * 1994 * d[d]-Mth-y[y[y[y]]] hh:mm:ss 1995 */ 1996 cp = str; 1997 if (!isdigit((int)*cp)) { 1998 if (*cp == '-') { 1999 /* 2000 * Catch special case 2001 */ 2002 L_CLR(lfp); 2003 return 1; 2004 } 2005 return 0; 2006 } 2007 2008 cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 2009 if (isdigit((int)*cp)) { 2010 cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2011 cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 2012 } 2013 2014 if (*cp++ != '-') 2015 return 0; 2016 2017 for (i = 0; i < 3; i++) 2018 buf[i] = *cp++; 2019 buf[3] = '\0'; 2020 2021 for (i = 0; i < 12; i++) 2022 if (STREQ(buf, months[i])) 2023 break; 2024 if (i == 12) 2025 return 0; 2026 cal.month = (u_char)(i + 1); 2027 2028 if (*cp++ != '-') 2029 return 0; 2030 2031 if (!isdigit((int)*cp)) 2032 return 0; 2033 cal.year = (u_short)(*cp++ - '0'); 2034 if (isdigit((int)*cp)) { 2035 cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2036 cal.year = (u_short)(*cp++ - '0'); 2037 } 2038 if (isdigit((int)*cp)) { 2039 cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2040 cal.year = (u_short)(cal.year + *cp++ - '0'); 2041 } 2042 if (isdigit((int)*cp)) { 2043 cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2044 cal.year = (u_short)(cal.year + *cp++ - '0'); 2045 } 2046 2047 /* 2048 * Catch special case. If cal.year == 0 this is a zero timestamp. 2049 */ 2050 if (cal.year == 0) { 2051 L_CLR(lfp); 2052 return 1; 2053 } 2054 2055 if (*cp++ != ' ' || !isdigit((int)*cp)) 2056 return 0; 2057 cal.hour = (u_char)(*cp++ - '0'); 2058 if (isdigit((int)*cp)) { 2059 cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2060 cal.hour = (u_char)(cal.hour + *cp++ - '0'); 2061 } 2062 2063 if (*cp++ != ':' || !isdigit((int)*cp)) 2064 return 0; 2065 cal.minute = (u_char)(*cp++ - '0'); 2066 if (isdigit((int)*cp)) { 2067 cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2068 cal.minute = (u_char)(cal.minute + *cp++ - '0'); 2069 } 2070 2071 if (*cp++ != ':' || !isdigit((int)*cp)) 2072 return 0; 2073 cal.second = (u_char)(*cp++ - '0'); 2074 if (isdigit((int)*cp)) { 2075 cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2076 cal.second = (u_char)(cal.second + *cp++ - '0'); 2077 } 2078 2079 /* 2080 * For RT-11, 1972 seems to be the pivot year 2081 */ 2082 if (cal.year < 72) 2083 cal.year += 2000; 2084 if (cal.year < 100) 2085 cal.year += 1900; 2086 2087 lfp->l_ui = caltontp(&cal); 2088 lfp->l_uf = 0; 2089 return 1; 2090} 2091 2092 2093/* 2094 * decodets - decode a timestamp into an l_fp format number, with 2095 * consideration of fuzzball formats. 2096 */ 2097int 2098decodets( 2099 char *str, 2100 l_fp *lfp 2101 ) 2102{ 2103 char *cp; 2104 char buf[30]; 2105 size_t b; 2106 2107 /* 2108 * If it starts with a 0x, decode as hex. 2109 */ 2110 if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2111 return hextolfp(str+2, lfp); 2112 2113 /* 2114 * If it starts with a '"', try it as an RT-11 date. 2115 */ 2116 if (*str == '"') { 2117 cp = str + 1; 2118 b = 0; 2119 while ('"' != *cp && '\0' != *cp && 2120 b < COUNTOF(buf) - 1) 2121 buf[b++] = *cp++; 2122 buf[b] = '\0'; 2123 return rtdatetolfp(buf, lfp); 2124 } 2125 2126 /* 2127 * Might still be hex. Check out the first character. Talk 2128 * about heuristics! 2129 */ 2130 if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2131 return hextolfp(str, lfp); 2132 2133 /* 2134 * Try it as a decimal. If this fails, try as an unquoted 2135 * RT-11 date. This code should go away eventually. 2136 */ 2137 if (atolfp(str, lfp)) 2138 return 1; 2139 2140 return rtdatetolfp(str, lfp); 2141} 2142 2143 2144/* 2145 * decodetime - decode a time value. It should be in milliseconds 2146 */ 2147int 2148decodetime( 2149 char *str, 2150 l_fp *lfp 2151 ) 2152{ 2153 return mstolfp(str, lfp); 2154} 2155 2156 2157/* 2158 * decodeint - decode an integer 2159 */ 2160int 2161decodeint( 2162 char *str, 2163 long *val 2164 ) 2165{ 2166 if (*str == '0') { 2167 if (*(str+1) == 'x' || *(str+1) == 'X') 2168 return hextoint(str+2, (u_long *)val); 2169 return octtoint(str, (u_long *)val); 2170 } 2171 return atoint(str, val); 2172} 2173 2174 2175/* 2176 * decodeuint - decode an unsigned integer 2177 */ 2178int 2179decodeuint( 2180 char *str, 2181 u_long *val 2182 ) 2183{ 2184 if (*str == '0') { 2185 if (*(str + 1) == 'x' || *(str + 1) == 'X') 2186 return (hextoint(str + 2, val)); 2187 return (octtoint(str, val)); 2188 } 2189 return (atouint(str, val)); 2190} 2191 2192 2193/* 2194 * decodearr - decode an array of time values 2195 */ 2196static int 2197decodearr( 2198 char *str, 2199 int *narr, 2200 l_fp *lfparr 2201 ) 2202{ 2203 register char *cp, *bp; 2204 register l_fp *lfp; 2205 char buf[60]; 2206 2207 lfp = lfparr; 2208 cp = str; 2209 *narr = 0; 2210 2211 while (*narr < 8) { 2212 while (isspace((int)*cp)) 2213 cp++; 2214 if (*cp == '\0') 2215 break; 2216 2217 bp = buf; 2218 while (!isspace((int)*cp) && *cp != '\0') 2219 *bp++ = *cp++; 2220 *bp++ = '\0'; 2221 2222 if (!decodetime(buf, lfp)) 2223 return 0; 2224 (*narr)++; 2225 lfp++; 2226 } 2227 return 1; 2228} 2229 2230 2231/* 2232 * Finally, the built in command handlers 2233 */ 2234 2235/* 2236 * help - tell about commands, or details of a particular command 2237 */ 2238static void 2239help( 2240 struct parse *pcmd, 2241 FILE *fp 2242 ) 2243{ 2244 struct xcmd *xcp = NULL; /* quiet warning */ 2245 const char *cmd; 2246 const char *list[100]; 2247 size_t word, words; 2248 size_t row, rows; 2249 size_t col, cols; 2250 size_t length; 2251 2252 if (pcmd->nargs == 0) { 2253 words = 0; 2254 for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2255 if (*(xcp->keyword) != '?' && 2256 words < COUNTOF(list)) 2257 list[words++] = xcp->keyword; 2258 } 2259 for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2260 if (words < COUNTOF(list)) 2261 list[words++] = xcp->keyword; 2262 2263 qsort((void *)list, words, sizeof(list[0]), helpsort); 2264 col = 0; 2265 for (word = 0; word < words; word++) { 2266 length = strlen(list[word]); 2267 col = max(col, length); 2268 } 2269 2270 cols = SCREENWIDTH / ++col; 2271 rows = (words + cols - 1) / cols; 2272 2273 fprintf(fp, "ntpq commands:\n"); 2274 2275 for (row = 0; row < rows; row++) { 2276 for (word = row; word < words; word += rows) 2277 fprintf(fp, "%-*.*s", (int)col, 2278 (int)col - 1, list[word]); 2279 fprintf(fp, "\n"); 2280 } 2281 } else { 2282 cmd = pcmd->argval[0].string; 2283 words = findcmd(cmd, builtins, opcmds, &xcp); 2284 if (words == 0) { 2285 fprintf(stderr, 2286 "Command `%s' is unknown\n", cmd); 2287 return; 2288 } else if (words >= 2) { 2289 fprintf(stderr, 2290 "Command `%s' is ambiguous\n", cmd); 2291 return; 2292 } 2293 fprintf(fp, "function: %s\n", xcp->comment); 2294 printusage(xcp, fp); 2295 } 2296} 2297 2298 2299/* 2300 * helpsort - do hostname qsort comparisons 2301 */ 2302static int 2303helpsort( 2304 const void *t1, 2305 const void *t2 2306 ) 2307{ 2308 const char * const * name1 = t1; 2309 const char * const * name2 = t2; 2310 2311 return strcmp(*name1, *name2); 2312} 2313 2314 2315/* 2316 * printusage - print usage information for a command 2317 */ 2318static void 2319printusage( 2320 struct xcmd *xcp, 2321 FILE *fp 2322 ) 2323{ 2324 register int i; 2325 2326 /* XXX: Do we need to warn about extra args here too? */ 2327 2328 (void) fprintf(fp, "usage: %s", xcp->keyword); 2329 for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 2330 if (xcp->arg[i] & OPT) 2331 (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 2332 else 2333 (void) fprintf(fp, " %s", xcp->desc[i]); 2334 } 2335 (void) fprintf(fp, "\n"); 2336} 2337 2338 2339/* 2340 * timeout - set time out time 2341 */ 2342static void 2343timeout( 2344 struct parse *pcmd, 2345 FILE *fp 2346 ) 2347{ 2348 int val; 2349 2350 if (pcmd->nargs == 0) { 2351 val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 2352 (void) fprintf(fp, "primary timeout %d ms\n", val); 2353 } else { 2354 tvout.tv_sec = pcmd->argval[0].uval / 1000; 2355 tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 2356 * 1000; 2357 } 2358} 2359 2360 2361/* 2362 * auth_delay - set delay for auth requests 2363 */ 2364static void 2365auth_delay( 2366 struct parse *pcmd, 2367 FILE *fp 2368 ) 2369{ 2370 int isneg; 2371 u_long val; 2372 2373 if (pcmd->nargs == 0) { 2374 val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 2375 (void) fprintf(fp, "delay %lu ms\n", val); 2376 } else { 2377 if (pcmd->argval[0].ival < 0) { 2378 isneg = 1; 2379 val = (u_long)(-pcmd->argval[0].ival); 2380 } else { 2381 isneg = 0; 2382 val = (u_long)pcmd->argval[0].ival; 2383 } 2384 2385 delay_time.l_ui = val / 1000; 2386 val %= 1000; 2387 delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 2388 2389 if (isneg) 2390 L_NEG(&delay_time); 2391 } 2392} 2393 2394 2395/* 2396 * host - set the host we are dealing with. 2397 */ 2398static void 2399host( 2400 struct parse *pcmd, 2401 FILE *fp 2402 ) 2403{ 2404 int i; 2405 2406 if (pcmd->nargs == 0) { 2407 if (havehost) 2408 (void) fprintf(fp, "current host is %s\n", 2409 currenthost); 2410 else 2411 (void) fprintf(fp, "no current host\n"); 2412 return; 2413 } 2414 2415 i = 0; 2416 ai_fam_templ = ai_fam_default; 2417 if (pcmd->nargs == 2) { 2418 if (!strcmp("-4", pcmd->argval[i].string)) 2419 ai_fam_templ = AF_INET; 2420 else if (!strcmp("-6", pcmd->argval[i].string)) 2421 ai_fam_templ = AF_INET6; 2422 else 2423 goto no_change; 2424 i = 1; 2425 } 2426 if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2427 fprintf(fp, "current host set to %s\n", currenthost); 2428 } else { 2429 no_change: 2430 if (havehost) 2431 fprintf(fp, "current host remains %s\n", 2432 currenthost); 2433 else 2434 fprintf(fp, "still no current host\n"); 2435 } 2436} 2437 2438 2439/* 2440 * poll - do one (or more) polls of the host via NTP 2441 */ 2442/*ARGSUSED*/ 2443static void 2444ntp_poll( 2445 struct parse *pcmd, 2446 FILE *fp 2447 ) 2448{ 2449 (void) fprintf(fp, "poll not implemented yet\n"); 2450} 2451 2452 2453/* 2454 * showdrefid2str - return a string explanation of the value of drefid 2455 */ 2456static char * 2457showdrefid2str(void) 2458{ 2459 switch (drefid) { 2460 case REFID_HASH: 2461 return "hash"; 2462 case REFID_IPV4: 2463 return "ipv4"; 2464 default: 2465 return "Unknown"; 2466 } 2467} 2468 2469 2470/* 2471 * drefid - display/change "display hash" 2472 */ 2473static void 2474showdrefid( 2475 struct parse *pcmd, 2476 FILE *fp 2477 ) 2478{ 2479 if (pcmd->nargs == 0) { 2480 (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2481 return; 2482 } else if (STREQ(pcmd->argval[0].string, "hash")) { 2483 drefid = REFID_HASH; 2484 } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2485 drefid = REFID_IPV4; 2486 } else { 2487 (void) fprintf(fp, "What?\n"); 2488 return; 2489 } 2490 (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2491} 2492 2493 2494/* 2495 * keyid - get a keyid to use for authenticating requests 2496 */ 2497static void 2498keyid( 2499 struct parse *pcmd, 2500 FILE *fp 2501 ) 2502{ 2503 if (pcmd->nargs == 0) { 2504 if (info_auth_keyid == 0) 2505 (void) fprintf(fp, "no keyid defined\n"); 2506 else 2507 (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 2508 } else { 2509 /* allow zero so that keyid can be cleared. */ 2510 if(pcmd->argval[0].uval > NTP_MAXKEY) 2511 (void) fprintf(fp, "Invalid key identifier\n"); 2512 info_auth_keyid = pcmd->argval[0].uval; 2513 } 2514} 2515 2516/* 2517 * keytype - get type of key to use for authenticating requests 2518 */ 2519static void 2520keytype( 2521 struct parse *pcmd, 2522 FILE *fp 2523 ) 2524{ 2525 const char * digest_name; 2526 size_t digest_len; 2527 int key_type; 2528 2529 if (!pcmd->nargs) { 2530 fprintf(fp, "keytype is %s with %lu octet digests\n", 2531 keytype_name(info_auth_keytype), 2532 (u_long)info_auth_hashlen); 2533 return; 2534 } 2535 2536 digest_name = pcmd->argval[0].string; 2537 digest_len = 0; 2538 key_type = keytype_from_text(digest_name, &digest_len); 2539 2540 if (!key_type) { 2541 fprintf(fp, "keytype is not valid. " 2542#ifdef OPENSSL 2543 "Type \"help keytype\" for the available digest types.\n"); 2544#else 2545 "Only \"md5\" is available.\n"); 2546#endif 2547 return; 2548 } 2549 2550 info_auth_keytype = key_type; 2551 info_auth_hashlen = digest_len; 2552} 2553 2554 2555/* 2556 * passwd - get an authentication key 2557 */ 2558/*ARGSUSED*/ 2559static void 2560passwd( 2561 struct parse *pcmd, 2562 FILE *fp 2563 ) 2564{ 2565 const char *pass; 2566 2567 if (info_auth_keyid == 0) { 2568 info_auth_keyid = getkeyid("Keyid: "); 2569 if (info_auth_keyid == 0) { 2570 (void)fprintf(fp, "Keyid must be defined\n"); 2571 return; 2572 } 2573 } 2574 if (pcmd->nargs >= 1) 2575 pass = pcmd->argval[0].string; 2576 else { 2577 pass = getpass_keytype(info_auth_keytype); 2578 if ('\0' == pass[0]) { 2579 fprintf(fp, "Password unchanged\n"); 2580 return; 2581 } 2582 } 2583 authusekey(info_auth_keyid, info_auth_keytype, 2584 (const u_char *)pass); 2585 authtrust(info_auth_keyid, 1); 2586} 2587 2588 2589/* 2590 * hostnames - set the showhostnames flag 2591 */ 2592static void 2593hostnames( 2594 struct parse *pcmd, 2595 FILE *fp 2596 ) 2597{ 2598 if (pcmd->nargs == 0) { 2599 if (showhostnames) 2600 (void) fprintf(fp, "hostnames being shown\n"); 2601 else 2602 (void) fprintf(fp, "hostnames not being shown\n"); 2603 } else { 2604 if (STREQ(pcmd->argval[0].string, "yes")) 2605 showhostnames = 1; 2606 else if (STREQ(pcmd->argval[0].string, "no")) 2607 showhostnames = 0; 2608 else 2609 (void)fprintf(stderr, "What?\n"); 2610 } 2611} 2612 2613 2614 2615/* 2616 * setdebug - set/change debugging level 2617 */ 2618static void 2619setdebug( 2620 struct parse *pcmd, 2621 FILE *fp 2622 ) 2623{ 2624 if (pcmd->nargs == 0) { 2625 (void) fprintf(fp, "debug level is %d\n", debug); 2626 return; 2627 } else if (STREQ(pcmd->argval[0].string, "no")) { 2628 debug = 0; 2629 } else if (STREQ(pcmd->argval[0].string, "more")) { 2630 debug++; 2631 } else if (STREQ(pcmd->argval[0].string, "less")) { 2632 debug--; 2633 } else { 2634 (void) fprintf(fp, "What?\n"); 2635 return; 2636 } 2637 (void) fprintf(fp, "debug level set to %d\n", debug); 2638} 2639 2640 2641/* 2642 * quit - stop this nonsense 2643 */ 2644/*ARGSUSED*/ 2645static void 2646quit( 2647 struct parse *pcmd, 2648 FILE *fp 2649 ) 2650{ 2651 if (havehost) 2652 closesocket(sockfd); /* cleanliness next to godliness */ 2653 exit(0); 2654} 2655 2656 2657/* 2658 * version - print the current version number 2659 */ 2660/*ARGSUSED*/ 2661static void 2662version( 2663 struct parse *pcmd, 2664 FILE *fp 2665 ) 2666{ 2667 2668 (void) fprintf(fp, "%s\n", Version); 2669 return; 2670} 2671 2672 2673/* 2674 * raw - set raw mode output 2675 */ 2676/*ARGSUSED*/ 2677static void 2678raw( 2679 struct parse *pcmd, 2680 FILE *fp 2681 ) 2682{ 2683 rawmode = 1; 2684 (void) fprintf(fp, "Output set to raw\n"); 2685} 2686 2687 2688/* 2689 * cooked - set cooked mode output 2690 */ 2691/*ARGSUSED*/ 2692static void 2693cooked( 2694 struct parse *pcmd, 2695 FILE *fp 2696 ) 2697{ 2698 rawmode = 0; 2699 (void) fprintf(fp, "Output set to cooked\n"); 2700 return; 2701} 2702 2703 2704/* 2705 * authenticate - always authenticate requests to this host 2706 */ 2707static void 2708authenticate( 2709 struct parse *pcmd, 2710 FILE *fp 2711 ) 2712{ 2713 if (pcmd->nargs == 0) { 2714 if (always_auth) { 2715 (void) fprintf(fp, 2716 "authenticated requests being sent\n"); 2717 } else 2718 (void) fprintf(fp, 2719 "unauthenticated requests being sent\n"); 2720 } else { 2721 if (STREQ(pcmd->argval[0].string, "yes")) { 2722 always_auth = 1; 2723 } else if (STREQ(pcmd->argval[0].string, "no")) { 2724 always_auth = 0; 2725 } else 2726 (void)fprintf(stderr, "What?\n"); 2727 } 2728} 2729 2730 2731/* 2732 * ntpversion - choose the NTP version to use 2733 */ 2734static void 2735ntpversion( 2736 struct parse *pcmd, 2737 FILE *fp 2738 ) 2739{ 2740 if (pcmd->nargs == 0) { 2741 (void) fprintf(fp, 2742 "NTP version being claimed is %d\n", pktversion); 2743 } else { 2744 if (pcmd->argval[0].uval < NTP_OLDVERSION 2745 || pcmd->argval[0].uval > NTP_VERSION) { 2746 (void) fprintf(stderr, "versions %d to %d, please\n", 2747 NTP_OLDVERSION, NTP_VERSION); 2748 } else { 2749 pktversion = (u_char) pcmd->argval[0].uval; 2750 } 2751 } 2752} 2753 2754 2755static void __attribute__((__format__(__printf__, 1, 0))) 2756vwarning(const char *fmt, va_list ap) 2757{ 2758 int serrno = errno; 2759 (void) fprintf(stderr, "%s: ", progname); 2760 vfprintf(stderr, fmt, ap); 2761 (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2762} 2763 2764/* 2765 * warning - print a warning message 2766 */ 2767static void __attribute__((__format__(__printf__, 1, 2))) 2768warning( 2769 const char *fmt, 2770 ... 2771 ) 2772{ 2773 va_list ap; 2774 va_start(ap, fmt); 2775 vwarning(fmt, ap); 2776 va_end(ap); 2777} 2778 2779 2780/* 2781 * error - print a message and exit 2782 */ 2783static void __attribute__((__format__(__printf__, 1, 2))) 2784error( 2785 const char *fmt, 2786 ... 2787 ) 2788{ 2789 va_list ap; 2790 va_start(ap, fmt); 2791 vwarning(fmt, ap); 2792 va_end(ap); 2793 exit(1); 2794} 2795/* 2796 * getkeyid - prompt the user for a keyid to use 2797 */ 2798static u_long 2799getkeyid( 2800 const char *keyprompt 2801 ) 2802{ 2803 int c; 2804 FILE *fi; 2805 char pbuf[20]; 2806 size_t i; 2807 size_t ilim; 2808 2809#ifndef SYS_WINNT 2810 if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 2811#else 2812 if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 2813#endif /* SYS_WINNT */ 2814 fi = stdin; 2815 else 2816 setbuf(fi, (char *)NULL); 2817 fprintf(stderr, "%s", keyprompt); fflush(stderr); 2818 for (i = 0, ilim = COUNTOF(pbuf) - 1; 2819 i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2820 ) 2821 pbuf[i++] = (char)c; 2822 pbuf[i] = '\0'; 2823 if (fi != stdin) 2824 fclose(fi); 2825 2826 return (u_long) atoi(pbuf); 2827} 2828 2829 2830/* 2831 * atoascii - printable-ize possibly ascii data using the character 2832 * transformations cat -v uses. 2833 */ 2834static void 2835atoascii( 2836 const char *in, 2837 size_t in_octets, 2838 char *out, 2839 size_t out_octets 2840 ) 2841{ 2842 const u_char * pchIn; 2843 const u_char * pchInLimit; 2844 u_char * pchOut; 2845 u_char c; 2846 2847 pchIn = (const u_char *)in; 2848 pchInLimit = pchIn + in_octets; 2849 pchOut = (u_char *)out; 2850 2851 if (NULL == pchIn) { 2852 if (0 < out_octets) 2853 *pchOut = '\0'; 2854 return; 2855 } 2856 2857#define ONEOUT(c) \ 2858do { \ 2859 if (0 == --out_octets) { \ 2860 *pchOut = '\0'; \ 2861 return; \ 2862 } \ 2863 *pchOut++ = (c); \ 2864} while (0) 2865 2866 for ( ; pchIn < pchInLimit; pchIn++) { 2867 c = *pchIn; 2868 if ('\0' == c) 2869 break; 2870 if (c & 0x80) { 2871 ONEOUT('M'); 2872 ONEOUT('-'); 2873 c &= 0x7f; 2874 } 2875 if (c < ' ') { 2876 ONEOUT('^'); 2877 ONEOUT((u_char)(c + '@')); 2878 } else if (0x7f == c) { 2879 ONEOUT('^'); 2880 ONEOUT('?'); 2881 } else 2882 ONEOUT(c); 2883 } 2884 ONEOUT('\0'); 2885 2886#undef ONEOUT 2887} 2888 2889 2890/* 2891 * makeascii - print possibly ascii data using the character 2892 * transformations that cat -v uses. 2893 */ 2894void 2895makeascii( 2896 size_t length, 2897 const char *data, 2898 FILE *fp 2899 ) 2900{ 2901 const u_char *data_u_char; 2902 const u_char *cp; 2903 int c; 2904 2905 data_u_char = (const u_char *)data; 2906 2907 for (cp = data_u_char; cp < data_u_char + length; cp++) { 2908 c = (int)*cp; 2909 if (c & 0x80) { 2910 putc('M', fp); 2911 putc('-', fp); 2912 c &= 0x7f; 2913 } 2914 2915 if (c < ' ') { 2916 putc('^', fp); 2917 putc(c + '@', fp); 2918 } else if (0x7f == c) { 2919 putc('^', fp); 2920 putc('?', fp); 2921 } else 2922 putc(c, fp); 2923 } 2924} 2925 2926 2927/* 2928 * asciize - same thing as makeascii except add a newline 2929 */ 2930void 2931asciize( 2932 int length, 2933 char *data, 2934 FILE *fp 2935 ) 2936{ 2937 makeascii(length, data, fp); 2938 putc('\n', fp); 2939} 2940 2941 2942/* 2943 * truncate string to fit clipping excess at end. 2944 * "too long" -> "too l" 2945 * Used for hostnames. 2946 */ 2947const char * 2948trunc_right( 2949 const char * src, 2950 size_t width 2951 ) 2952{ 2953 size_t sl; 2954 char * out; 2955 2956 2957 sl = strlen(src); 2958 if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 2959 LIB_GETBUF(out); 2960 memcpy(out, src, width); 2961 out[width] = '\0'; 2962 2963 return out; 2964 } 2965 2966 return src; 2967} 2968 2969 2970/* 2971 * truncate string to fit by preserving right side and using '_' to hint 2972 * "too long" -> "_long" 2973 * Used for local IPv6 addresses, where low bits differentiate. 2974 */ 2975const char * 2976trunc_left( 2977 const char * src, 2978 size_t width 2979 ) 2980{ 2981 size_t sl; 2982 char * out; 2983 2984 2985 sl = strlen(src); 2986 if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 2987 LIB_GETBUF(out); 2988 out[0] = '_'; 2989 memcpy(&out[1], &src[sl + 1 - width], width); 2990 2991 return out; 2992 } 2993 2994 return src; 2995} 2996 2997 2998/* 2999 * Some circular buffer space 3000 */ 3001#define CBLEN 80 3002#define NUMCB 6 3003 3004char circ_buf[NUMCB][CBLEN]; 3005int nextcb = 0; 3006 3007/* 3008 * nextvar - find the next variable in the buffer 3009 */ 3010int 3011nextvar( 3012 size_t *datalen, 3013 const char **datap, 3014 char **vname, 3015 char **vvalue 3016 ) 3017{ 3018 const char *cp; 3019 const char *np; 3020 const char *cpend; 3021 size_t srclen; 3022 size_t len; 3023 static char name[MAXVARLEN]; 3024 static char value[MAXVALLEN]; 3025 3026 cp = *datap; 3027 cpend = cp + *datalen; 3028 3029 /* 3030 * Space past commas and white space 3031 */ 3032 while (cp < cpend && (*cp == ',' || isspace((int)*cp))) 3033 cp++; 3034 if (cp >= cpend) 3035 return 0; 3036 3037 /* 3038 * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace 3039 * over any white space and terminate it. 3040 */ 3041 srclen = strcspn(cp, ",=\r\n"); 3042 srclen = min(srclen, (size_t)(cpend - cp)); 3043 len = srclen; 3044 while (len > 0 && isspace((unsigned char)cp[len - 1])) 3045 len--; 3046 if (len >= sizeof(name)) 3047 return 0; 3048 if (len > 0) 3049 memcpy(name, cp, len); 3050 name[len] = '\0'; 3051 *vname = name; 3052 cp += srclen; 3053 3054 /* 3055 * Check if we hit the end of the buffer or a ','. If so we are done. 3056 */ 3057 if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { 3058 if (cp < cpend) 3059 cp++; 3060 *datap = cp; 3061 *datalen = size2int_sat(cpend - cp); 3062 *vvalue = NULL; 3063 return 1; 3064 } 3065 3066 /* 3067 * So far, so good. Copy out the value 3068 */ 3069 cp++; /* past '=' */ 3070 while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n')) 3071 cp++; 3072 np = cp; 3073 if ('"' == *np) { 3074 do { 3075 np++; 3076 } while (np < cpend && '"' != *np); 3077 if (np < cpend && '"' == *np) 3078 np++; 3079 } else { 3080 while (np < cpend && ',' != *np && '\r' != *np) 3081 np++; 3082 } 3083 len = np - cp; 3084 if (np > cpend || len >= sizeof(value) || 3085 (np < cpend && ',' != *np && '\r' != *np)) 3086 return 0; 3087 memcpy(value, cp, len); 3088 /* 3089 * Trim off any trailing whitespace 3090 */ 3091 while (len > 0 && isspace((unsigned char)value[len - 1])) 3092 len--; 3093 value[len] = '\0'; 3094 3095 /* 3096 * Return this. All done. 3097 */ 3098 if (np < cpend && ',' == *np) 3099 np++; 3100 *datap = np; 3101 *datalen = size2int_sat(cpend - np); 3102 *vvalue = value; 3103 return 1; 3104} 3105 3106 3107u_short 3108varfmt(const char * varname) 3109{ 3110 u_int n; 3111 3112 for (n = 0; n < COUNTOF(cookedvars); n++) 3113 if (!strcmp(varname, cookedvars[n].varname)) 3114 return cookedvars[n].fmt; 3115 3116 return PADDING; 3117} 3118 3119 3120/* 3121 * printvars - print variables returned in response packet 3122 */ 3123void 3124printvars( 3125 size_t length, 3126 const char *data, 3127 int status, 3128 int sttype, 3129 int quiet, 3130 FILE *fp 3131 ) 3132{ 3133 if (rawmode) 3134 rawprint(sttype, length, data, status, quiet, fp); 3135 else 3136 cookedprint(sttype, length, data, status, quiet, fp); 3137} 3138 3139 3140/* 3141 * rawprint - do a printout of the data in raw mode 3142 */ 3143static void 3144rawprint( 3145 int datatype, 3146 size_t length, 3147 const char *data, 3148 int status, 3149 int quiet, 3150 FILE *fp 3151 ) 3152{ 3153 const char *cp; 3154 const char *cpend; 3155 3156 /* 3157 * Essentially print the data as is. We reformat unprintables, though. 3158 */ 3159 cp = data; 3160 cpend = data + length; 3161 3162 if (!quiet) 3163 (void) fprintf(fp, "status=0x%04x,\n", status); 3164 3165 while (cp < cpend) { 3166 if (*cp == '\r') { 3167 /* 3168 * If this is a \r and the next character is a 3169 * \n, supress this, else pretty print it. Otherwise 3170 * just output the character. 3171 */ 3172 if (cp == (cpend - 1) || *(cp + 1) != '\n') 3173 makeascii(1, cp, fp); 3174 } else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp)) 3175 putc(*cp, fp); 3176 else 3177 makeascii(1, cp, fp); 3178 cp++; 3179 } 3180} 3181 3182 3183/* 3184 * Global data used by the cooked output routines 3185 */ 3186int out_chars; /* number of characters output */ 3187int out_linecount; /* number of characters output on this line */ 3188 3189 3190/* 3191 * startoutput - get ready to do cooked output 3192 */ 3193static void 3194startoutput(void) 3195{ 3196 out_chars = 0; 3197 out_linecount = 0; 3198} 3199 3200 3201/* 3202 * output - output a variable=value combination 3203 */ 3204static void 3205output( 3206 FILE *fp, 3207 const char *name, 3208 const char *value 3209 ) 3210{ 3211 int len; 3212 3213 /* strlen of "name=value" */ 3214 len = size2int_sat(strlen(name) + 1 + strlen(value)); 3215 3216 if (out_chars != 0) { 3217 out_chars += 2; 3218 if ((out_linecount + len + 2) > MAXOUTLINE) { 3219 fputs(",\n", fp); 3220 out_linecount = 0; 3221 } else { 3222 fputs(", ", fp); 3223 out_linecount += 2; 3224 } 3225 } 3226 3227 fputs(name, fp); 3228 putc('=', fp); 3229 fputs(value, fp); 3230 out_chars += len; 3231 out_linecount += len; 3232} 3233 3234 3235/* 3236 * endoutput - terminate a block of cooked output 3237 */ 3238static void 3239endoutput( 3240 FILE *fp 3241 ) 3242{ 3243 if (out_chars != 0) 3244 putc('\n', fp); 3245} 3246 3247 3248/* 3249 * outputarr - output an array of values 3250 */ 3251static void 3252outputarr( 3253 FILE *fp, 3254 char *name, 3255 int narr, 3256 l_fp *lfp 3257 ) 3258{ 3259 char *bp; 3260 char *cp; 3261 size_t i; 3262 size_t len; 3263 char buf[256]; 3264 3265 bp = buf; 3266 /* 3267 * Hack to align delay and offset values 3268 */ 3269 for (i = (int)strlen(name); i < 11; i++) 3270 *bp++ = ' '; 3271 3272 for (i = narr; i > 0; i--) { 3273 if (i != narr) 3274 *bp++ = ' '; 3275 cp = lfptoms(lfp, 2); 3276 len = strlen(cp); 3277 if (len > 7) { 3278 cp[7] = '\0'; 3279 len = 7; 3280 } 3281 while (len < 7) { 3282 *bp++ = ' '; 3283 len++; 3284 } 3285 while (*cp != '\0') 3286 *bp++ = *cp++; 3287 lfp++; 3288 } 3289 *bp = '\0'; 3290 output(fp, name, buf); 3291} 3292 3293static char * 3294tstflags( 3295 u_long val 3296 ) 3297{ 3298 register char *cp, *s; 3299 size_t cb; 3300 register int i; 3301 register const char *sep; 3302 3303 sep = ""; 3304 s = cp = circ_buf[nextcb]; 3305 if (++nextcb >= NUMCB) 3306 nextcb = 0; 3307 cb = sizeof(circ_buf[0]); 3308 3309 snprintf(cp, cb, "%02lx", val); 3310 cp += strlen(cp); 3311 cb -= strlen(cp); 3312 if (!val) { 3313 strlcat(cp, " ok", cb); 3314 cp += strlen(cp); 3315 cb -= strlen(cp); 3316 } else { 3317 if (cb) { 3318 *cp++ = ' '; 3319 cb--; 3320 } 3321 for (i = 0; i < (int)COUNTOF(tstflagnames); i++) { 3322 if (val & 0x1) { 3323 snprintf(cp, cb, "%s%s", sep, 3324 tstflagnames[i]); 3325 sep = ", "; 3326 cp += strlen(cp); 3327 cb -= strlen(cp); 3328 } 3329 val >>= 1; 3330 } 3331 } 3332 if (cb) 3333 *cp = '\0'; 3334 3335 return s; 3336} 3337 3338/* 3339 * cookedprint - output variables in cooked mode 3340 */ 3341static void 3342cookedprint( 3343 int datatype, 3344 size_t length, 3345 const char *data, 3346 int status, 3347 int quiet, 3348 FILE *fp 3349 ) 3350{ 3351 char *name; 3352 char *value; 3353 char output_raw; 3354 int fmt; 3355 l_fp lfp; 3356 sockaddr_u hval; 3357 u_long uval; 3358 int narr; 3359 size_t len; 3360 l_fp lfparr[8]; 3361 char b[12]; 3362 char bn[2 * MAXVARLEN]; 3363 char bv[2 * MAXVALLEN]; 3364 3365 UNUSED_ARG(datatype); 3366 3367 if (!quiet) 3368 fprintf(fp, "status=%04x %s,\n", status, 3369 statustoa(datatype, status)); 3370 3371 startoutput(); 3372 while (nextvar(&length, &data, &name, &value)) { 3373 fmt = varfmt(name); 3374 output_raw = 0; 3375 switch (fmt) { 3376 3377 case PADDING: 3378 output_raw = '*'; 3379 break; 3380 3381 case TS: 3382 if (!decodets(value, &lfp)) 3383 output_raw = '?'; 3384 else 3385 output(fp, name, prettydate(&lfp)); 3386 break; 3387 3388 case HA: /* fallthru */ 3389 case NA: 3390 if (!decodenetnum(value, &hval)) { 3391 output_raw = '?'; 3392 } else if (fmt == HA){ 3393 output(fp, name, nntohost(&hval)); 3394 } else { 3395 output(fp, name, stoa(&hval)); 3396 } 3397 break; 3398 3399 case RF: 3400 if (decodenetnum(value, &hval)) { 3401 if (ISREFCLOCKADR(&hval)) 3402 output(fp, name, 3403 refnumtoa(&hval)); 3404 else 3405 output(fp, name, stoa(&hval)); 3406 } else if (strlen(value) <= 4) { 3407 output(fp, name, value); 3408 } else { 3409 output_raw = '?'; 3410 } 3411 break; 3412 3413 case LP: 3414 if (!decodeuint(value, &uval) || uval > 3) { 3415 output_raw = '?'; 3416 } else { 3417 b[0] = (0x2 & uval) 3418 ? '1' 3419 : '0'; 3420 b[1] = (0x1 & uval) 3421 ? '1' 3422 : '0'; 3423 b[2] = '\0'; 3424 output(fp, name, b); 3425 } 3426 break; 3427 3428 case OC: 3429 if (!decodeuint(value, &uval)) { 3430 output_raw = '?'; 3431 } else { 3432 snprintf(b, sizeof(b), "%03lo", uval); 3433 output(fp, name, b); 3434 } 3435 break; 3436 3437 case AR: 3438 if (!decodearr(value, &narr, lfparr)) 3439 output_raw = '?'; 3440 else 3441 outputarr(fp, name, narr, lfparr); 3442 break; 3443 3444 case FX: 3445 if (!decodeuint(value, &uval)) 3446 output_raw = '?'; 3447 else 3448 output(fp, name, tstflags(uval)); 3449 break; 3450 3451 default: 3452 fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3453 name, value, fmt); 3454 output_raw = '?'; 3455 break; 3456 } 3457 3458 if (output_raw != 0) { 3459 /* TALOS-CAN-0063: avoid buffer overrun */ 3460 atoascii(name, MAXVARLEN, bn, sizeof(bn)); 3461 if (output_raw != '*') { 3462 atoascii(value, MAXVALLEN, 3463 bv, sizeof(bv) - 1); 3464 len = strlen(bv); 3465 bv[len] = output_raw; 3466 bv[len+1] = '\0'; 3467 } else { 3468 atoascii(value, MAXVALLEN, 3469 bv, sizeof(bv)); 3470 } 3471 output(fp, bn, bv); 3472 } 3473 } 3474 endoutput(fp); 3475} 3476 3477 3478/* 3479 * sortassoc - sort associations in the cache into ascending order 3480 */ 3481void 3482sortassoc(void) 3483{ 3484 if (numassoc > 1) 3485 qsort(assoc_cache, (size_t)numassoc, 3486 sizeof(assoc_cache[0]), &assoccmp); 3487} 3488 3489 3490/* 3491 * assoccmp - compare two associations 3492 */ 3493static int 3494assoccmp( 3495 const void *t1, 3496 const void *t2 3497 ) 3498{ 3499 const struct association *ass1 = t1; 3500 const struct association *ass2 = t2; 3501 3502 if (ass1->assid < ass2->assid) 3503 return -1; 3504 if (ass1->assid > ass2->assid) 3505 return 1; 3506 return 0; 3507} 3508 3509 3510/* 3511 * grow_assoc_cache() - enlarge dynamic assoc_cache array 3512 * 3513 * The strategy is to add an assumed 4k page size at a time, leaving 3514 * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3515 */ 3516void 3517grow_assoc_cache(void) 3518{ 3519 static size_t prior_sz; 3520 size_t new_sz; 3521 3522 new_sz = prior_sz + 4 * 1024; 3523 if (0 == prior_sz) { 3524 new_sz -= 4 * sizeof(void *); 3525 } 3526 assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3527 prior_sz = new_sz; 3528 assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3529} 3530 3531 3532/* 3533 * ntpq_custom_opt_handler - autoopts handler for -c and -p 3534 * 3535 * By default, autoopts loses the relative order of -c and -p options 3536 * on the command line. This routine replaces the default handler for 3537 * those routines and builds a list of commands to execute preserving 3538 * the order. 3539 */ 3540void 3541ntpq_custom_opt_handler( 3542 tOptions *pOptions, 3543 tOptDesc *pOptDesc 3544 ) 3545{ 3546 switch (pOptDesc->optValue) { 3547 3548 default: 3549 fprintf(stderr, 3550 "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3551 pOptDesc->optValue, pOptDesc->optValue); 3552 exit(1); 3553 3554 case 'c': 3555 ADDCMD(pOptDesc->pzLastArg); 3556 break; 3557 3558 case 'p': 3559 ADDCMD("peers"); 3560 break; 3561 } 3562} 3563/* 3564 * Obtain list of digest names 3565 */ 3566 3567#ifdef OPENSSL 3568# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3569struct hstate { 3570 char *list; 3571 const char **seen; 3572 int idx; 3573}; 3574#define K_PER_LINE 8 3575#define K_NL_PFX_STR "\n " 3576#define K_DELIM_STR ", " 3577static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg ) 3578{ 3579 size_t len, n; 3580 const char *name, *cp, **seen; 3581 struct hstate *hstate = arg; 3582 EVP_MD_CTX ctx; 3583 u_int digest_len; 3584 u_char digest[EVP_MAX_MD_SIZE]; 3585 3586 if (!m) 3587 return; /* Ignore aliases */ 3588 3589 name = EVP_MD_name(m); 3590 3591 /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */ 3592 3593 for( cp = name; *cp; cp++ ) { 3594 if( islower(*cp) ) 3595 return; 3596 } 3597 len = (cp - name) + 1; 3598 3599 /* There are duplicates. Discard if name has been seen. */ 3600 3601 for (seen = hstate->seen; *seen; seen++) 3602 if (!strcmp(*seen, name)) 3603 return; 3604 n = (seen - hstate->seen) + 2; 3605 hstate->seen = erealloc(hstate->seen, n * sizeof(*seen)); 3606 hstate->seen[n-2] = name; 3607 hstate->seen[n-1] = NULL; 3608 3609 /* Discard MACs that NTP won't accept. 3610 * Keep this consistent with keytype_from_text() in ssl_init.c. 3611 */ 3612 3613 EVP_DigestInit(&ctx, EVP_get_digestbyname(name)); 3614 EVP_DigestFinal(&ctx, digest, &digest_len); 3615 if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t))) 3616 return; 3617 3618 if (hstate->list != NULL) 3619 len += strlen(hstate->list); 3620 len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR); 3621 3622 if (hstate->list == NULL) { 3623 hstate->list = (char *)emalloc(len); 3624 hstate->list[0] = '\0'; 3625 } else 3626 hstate->list = (char *)erealloc(hstate->list, len); 3627 3628 sprintf(hstate->list + strlen(hstate->list), "%s%s", 3629 ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR), 3630 name); 3631 if (hstate->idx >= K_PER_LINE) 3632 hstate->idx = 1; 3633 else 3634 hstate->idx++; 3635} 3636# endif 3637#endif 3638 3639static char *list_digest_names(void) 3640{ 3641 char *list = NULL; 3642 3643#ifdef OPENSSL 3644# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3645 struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 3646 3647 hstate.seen = (const char **) emalloc_zero(1*sizeof( const char * )); // replaces -> calloc(1, sizeof( const char * )); 3648 3649 INIT_SSL(); 3650 EVP_MD_do_all_sorted(list_md_fn, &hstate); 3651 list = hstate.list; 3652 free(hstate.seen); 3653# else 3654 list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 3655 strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 3656# endif 3657#else 3658 list = (char *)emalloc(sizeof("md5")); 3659 strcpy(list, "md5"); 3660#endif 3661 3662 return list; 3663} 3664 3665#define CTRLC_STACK_MAX 4 3666static volatile size_t ctrlc_stack_len = 0; 3667static volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 3668 3669 3670 3671int/*BOOL*/ 3672push_ctrl_c_handler( 3673 Ctrl_C_Handler func 3674 ) 3675{ 3676 size_t size = ctrlc_stack_len; 3677 if (func && (size < CTRLC_STACK_MAX)) { 3678 ctrlc_stack[size] = func; 3679 ctrlc_stack_len = size + 1; 3680 return TRUE; 3681 } 3682 return FALSE; 3683} 3684 3685int/*BOOL*/ 3686pop_ctrl_c_handler( 3687 Ctrl_C_Handler func 3688 ) 3689{ 3690 size_t size = ctrlc_stack_len; 3691 if (size) { 3692 --size; 3693 if (func == NULL || func == ctrlc_stack[size]) { 3694 ctrlc_stack_len = size; 3695 return TRUE; 3696 } 3697 } 3698 return FALSE; 3699} 3700 3701static void 3702on_ctrlc(void) 3703{ 3704 size_t size = ctrlc_stack_len; 3705 while (size) 3706 if ((*ctrlc_stack[--size])()) 3707 break; 3708} 3709 3710static int 3711my_easprintf( 3712 char ** ppinto, 3713 const char * fmt , 3714 ... 3715 ) 3716{ 3717 va_list va; 3718 int prc; 3719 size_t len = 128; 3720 char * buf = emalloc(len); 3721 3722 again: 3723 /* Note: we expect the memory allocation to fail long before the 3724 * increment in buffer size actually overflows. 3725 */ 3726 buf = (buf) ? erealloc(buf, len) : emalloc(len); 3727 3728 va_start(va, fmt); 3729 prc = vsnprintf(buf, len, fmt, va); 3730 va_end(va); 3731 3732 if (prc < 0) { 3733 /* might be very old vsnprintf. Or actually MSVC... */ 3734 len += len >> 1; 3735 goto again; 3736 } 3737 if ((size_t)prc >= len) { 3738 /* at least we have the proper size now... */ 3739 len = (size_t)prc + 1; 3740 goto again; 3741 } 3742 if ((size_t)prc < (len - 32)) 3743 buf = erealloc(buf, (size_t)prc + 1); 3744 *ppinto = buf; 3745 return prc; 3746} 3747