154359Sroberto/* 254359Sroberto * ntpq - query an NTP server using mode 6 commands 354359Sroberto */ 4280849Scy#include <config.h> 554359Sroberto#include <stdio.h> 6182007Sroberto#include <ctype.h> 7182007Sroberto#include <signal.h> 8182007Sroberto#include <setjmp.h> 9182007Sroberto#include <sys/types.h> 10182007Sroberto#include <sys/time.h> 11280849Scy#ifdef HAVE_UNISTD_H 12280849Scy# include <unistd.h> 13280849Scy#endif 14280849Scy#ifdef HAVE_FCNTL_H 15280849Scy# include <fcntl.h> 16280849Scy#endif 17280849Scy#ifdef SYS_WINNT 18280849Scy# include <mswsock.h> 19280849Scy#endif 20280849Scy#include <isc/net.h> 21280849Scy#include <isc/result.h> 22182007Sroberto 2382498Sroberto#include "ntpq.h" 24285169Scy#include "ntp_assert.h" 25280849Scy#include "ntp_stdlib.h" 2682498Sroberto#include "ntp_unixtime.h" 2782498Sroberto#include "ntp_calendar.h" 2882498Sroberto#include "ntp_select.h" 29280849Scy#include "ntp_assert.h" 30280849Scy#include "lib_strbuf.h" 31280849Scy#include "ntp_lineedit.h" 32280849Scy#include "ntp_debug.h" 33280849Scy#ifdef OPENSSL 34280849Scy#include "openssl/evp.h" 35280849Scy#include "openssl/objects.h" 36285169Scy#include "openssl/err.h" 37310419Sdelphij#include "libssl_compat.h" 38280849Scy#endif 39280849Scy#include <ssl_applink.c> 4082498Sroberto 41280849Scy#include "ntp_libopts.h" 42293423Sdelphij#include "safecast.h" 43182007Sroberto 44280849Scy#ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 45182007Sroberto# define open(name, flags) open(name, flags, 0777) 46182007Sroberto# define SERVER_PORT_NUM 123 4754359Sroberto#endif 4854359Sroberto 49182007Sroberto/* we use COMMAND as an autogen keyword */ 50182007Sroberto#ifdef COMMAND 51182007Sroberto# undef COMMAND 52182007Sroberto#endif 53182007Sroberto 5454359Sroberto/* 5554359Sroberto * Because we potentially understand a lot of commands we will run 5654359Sroberto * interactive if connected to a terminal. 5754359Sroberto */ 5854359Srobertoint interactive = 0; /* set to 1 when we should prompt */ 5954359Srobertoconst char *prompt = "ntpq> "; /* prompt to ask him about */ 6054359Sroberto 61280849Scy/* 62280849Scy * use old readvars behavior? --old-rv processing in ntpq resets 63280849Scy * this value based on the presence or absence of --old-rv. It is 64280849Scy * initialized to 1 here to maintain backward compatibility with 65280849Scy * libntpq clients such as ntpsnmpd, which are free to reset it as 66280849Scy * desired. 67280849Scy */ 68280849Scyint old_rv = 1; 6954359Sroberto 70298695Sdelphij/* 71298695Sdelphij * How should we display the refid? 72298695Sdelphij * REFID_HASH, REFID_IPV4 73298695Sdelphij */ 74298695Sdelphijte_Refid drefid = -1; 75280849Scy 7654359Sroberto/* 77182007Sroberto * for get_systime() 78182007Sroberto */ 79182007Srobertos_char sys_precision; /* local clock precision (log2 s) */ 80182007Sroberto 81182007Sroberto/* 8254359Sroberto * Keyid used for authenticated requests. Obtained on the fly. 8354359Sroberto */ 84132451Srobertou_long info_auth_keyid = 0; 8554359Sroberto 86280849Scystatic int info_auth_keytype = NID_md5; /* MD5 */ 87280849Scystatic size_t info_auth_hashlen = 16; /* MD5 */ 8854359Srobertou_long current_time; /* needed by authkeys; not used */ 8954359Sroberto 9054359Sroberto/* 9154359Sroberto * Flag which indicates we should always send authenticated requests 9254359Sroberto */ 9354359Srobertoint always_auth = 0; 9454359Sroberto 9554359Sroberto/* 9654359Sroberto * Flag which indicates raw mode output. 9754359Sroberto */ 9854359Srobertoint rawmode = 0; 9954359Sroberto 10054359Sroberto/* 10154359Sroberto * Packet version number we use 10254359Sroberto */ 10354359Srobertou_char pktversion = NTP_OLDVERSION + 1; 10454359Sroberto 10554359Sroberto/* 10654359Sroberto * Don't jump if no set jmp. 10754359Sroberto */ 10854359Srobertovolatile int jump = 0; 10954359Sroberto 11054359Sroberto/* 11154359Sroberto * Format values 11254359Sroberto */ 11354359Sroberto#define PADDING 0 114280849Scy#define HA 1 /* host address */ 115280849Scy#define NA 2 /* network address */ 116280849Scy#define LP 3 /* leap (print in binary) */ 117280849Scy#define RF 4 /* refid (sometimes string, sometimes not) */ 118280849Scy#define AR 5 /* array of times */ 119280849Scy#define FX 6 /* test flags */ 120280849Scy#define TS 7 /* l_fp timestamp in hex */ 121280849Scy#define OC 8 /* integer, print in octal */ 12254359Sroberto#define EOV 255 /* end of table */ 12354359Sroberto 12454359Sroberto/* 125280849Scy * For the most part ntpq simply displays what ntpd provides in the 126280849Scy * mostly plain-text mode 6 responses. A few variable names are by 127280849Scy * default "cooked" to provide more human-friendly output. 12854359Sroberto */ 129280849Scyconst var_format cookedvars[] = { 130280849Scy { "leap", LP }, 131280849Scy { "reach", OC }, 132280849Scy { "refid", RF }, 133280849Scy { "reftime", TS }, 134280849Scy { "clock", TS }, 135280849Scy { "org", TS }, 136280849Scy { "rec", TS }, 137280849Scy { "xmt", TS }, 138280849Scy { "flash", FX }, 139280849Scy { "srcadr", HA }, 140280849Scy { "peeradr", HA }, /* compat with others */ 141280849Scy { "dstadr", NA }, 142280849Scy { "filtdelay", AR }, 143280849Scy { "filtoffset", AR }, 144280849Scy { "filtdisp", AR }, 145280849Scy { "filterror", AR }, /* compat with others */ 14654359Sroberto}; 14754359Sroberto 14854359Sroberto 14954359Sroberto 15054359Sroberto/* 15154359Sroberto * flasher bits 15254359Sroberto */ 15354359Srobertostatic const char *tstflagnames[] = { 154182007Sroberto "pkt_dup", /* TEST1 */ 155182007Sroberto "pkt_bogus", /* TEST2 */ 156280849Scy "pkt_unsync", /* TEST3 */ 157182007Sroberto "pkt_denied", /* TEST4 */ 158182007Sroberto "pkt_auth", /* TEST5 */ 159280849Scy "pkt_stratum", /* TEST6 */ 160280849Scy "pkt_header", /* TEST7 */ 161182007Sroberto "pkt_autokey", /* TEST8 */ 162182007Sroberto "pkt_crypto", /* TEST9 */ 163182007Sroberto "peer_stratum", /* TEST10 */ 164182007Sroberto "peer_dist", /* TEST11 */ 165182007Sroberto "peer_loop", /* TEST12 */ 166280849Scy "peer_unreach" /* TEST13 */ 16754359Sroberto}; 16854359Sroberto 16954359Sroberto 170280849Scyint ntpqmain (int, char **); 17154359Sroberto/* 17254359Sroberto * Built in command handler declarations 17354359Sroberto */ 174280849Scystatic int openhost (const char *, int); 175280849Scystatic void dump_hex_printable(const void *, size_t); 176280849Scystatic int sendpkt (void *, size_t); 177293423Sdelphijstatic int getresponse (int, int, u_short *, size_t *, const char **, int); 178293423Sdelphijstatic int sendrequest (int, associd_t, int, size_t, const char *); 179280849Scystatic char * tstflags (u_long); 180280849Scy#ifndef BUILD_AS_LIB 181280849Scystatic void getcmds (void); 182280849Scy#ifndef SYS_WINNT 183293423Sdelphijstatic int abortcmd (void); 184280849Scy#endif /* SYS_WINNT */ 185280849Scystatic void docmd (const char *); 186280849Scystatic void tokenize (const char *, char **, int *); 187280849Scystatic int getarg (const char *, int, arg_v *); 188280849Scy#endif /* BUILD_AS_LIB */ 189280849Scystatic int findcmd (const char *, struct xcmd *, 190280849Scy struct xcmd *, struct xcmd **); 191280849Scystatic int rtdatetolfp (char *, l_fp *); 192280849Scystatic int decodearr (char *, int *, l_fp *); 193280849Scystatic void help (struct parse *, FILE *); 194280849Scystatic int helpsort (const void *, const void *); 195280849Scystatic void printusage (struct xcmd *, FILE *); 196280849Scystatic void timeout (struct parse *, FILE *); 197280849Scystatic void auth_delay (struct parse *, FILE *); 198280849Scystatic void host (struct parse *, FILE *); 199280849Scystatic void ntp_poll (struct parse *, FILE *); 200280849Scystatic void keyid (struct parse *, FILE *); 201280849Scystatic void keytype (struct parse *, FILE *); 202280849Scystatic void passwd (struct parse *, FILE *); 203280849Scystatic void hostnames (struct parse *, FILE *); 204280849Scystatic void setdebug (struct parse *, FILE *); 205280849Scystatic void quit (struct parse *, FILE *); 206298695Sdelphijstatic void showdrefid (struct parse *, FILE *); 207280849Scystatic void version (struct parse *, FILE *); 208280849Scystatic void raw (struct parse *, FILE *); 209280849Scystatic void cooked (struct parse *, FILE *); 210280849Scystatic void authenticate (struct parse *, FILE *); 211280849Scystatic void ntpversion (struct parse *, FILE *); 212280849Scystatic void warning (const char *, ...) 213280849Scy __attribute__((__format__(__printf__, 1, 2))); 214280849Scystatic void error (const char *, ...) 215280849Scy __attribute__((__format__(__printf__, 1, 2))); 216280849Scystatic u_long getkeyid (const char *); 217280849Scystatic void atoascii (const char *, size_t, char *, size_t); 218293423Sdelphijstatic void cookedprint (int, size_t, const char *, int, int, FILE *); 219293423Sdelphijstatic void rawprint (int, size_t, const char *, int, int, FILE *); 220280849Scystatic void startoutput (void); 221280849Scystatic void output (FILE *, const char *, const char *); 222280849Scystatic void endoutput (FILE *); 223280849Scystatic void outputarr (FILE *, char *, int, l_fp *); 224280849Scystatic int assoccmp (const void *, const void *); 225293423Sdelphijstatic void on_ctrlc (void); 226280849Scy u_short varfmt (const char *); 227294554Sdelphijstatic int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 228280849Scyvoid ntpq_custom_opt_handler (tOptions *, tOptDesc *); 22954359Sroberto 230285169Scy#ifdef OPENSSL 231285169Scy# ifdef HAVE_EVP_MD_DO_ALL_SORTED 232285169Scystatic void list_md_fn(const EVP_MD *m, const char *from, 233285169Scy const char *to, void *arg ); 234285169Scy# endif 235285169Scy#endif 236285169Scystatic char *list_digest_names(void); 237280849Scy 23854359Sroberto/* 23954359Sroberto * Built-in commands we understand 24054359Sroberto */ 24154359Srobertostruct xcmd builtins[] = { 242182007Sroberto { "?", help, { OPT|NTP_STR, NO, NO, NO }, 24354359Sroberto { "command", "", "", "" }, 24454359Sroberto "tell the use and syntax of commands" }, 245182007Sroberto { "help", help, { OPT|NTP_STR, NO, NO, NO }, 24654359Sroberto { "command", "", "", "" }, 24754359Sroberto "tell the use and syntax of commands" }, 248182007Sroberto { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 24954359Sroberto { "msec", "", "", "" }, 25054359Sroberto "set the primary receive time out" }, 251182007Sroberto { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 25254359Sroberto { "msec", "", "", "" }, 25354359Sroberto "set the delay added to encryption time stamps" }, 254182007Sroberto { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 255132451Sroberto { "-4|-6", "hostname", "", "" }, 25654359Sroberto "specify the host whose NTP server we talk to" }, 257182007Sroberto { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 25854359Sroberto { "n", "verbose", "", "" }, 25954359Sroberto "poll an NTP server in client mode `n' times" }, 260280849Scy { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 26154359Sroberto { "", "", "", "" }, 26254359Sroberto "specify a password to use for authenticated requests"}, 263182007Sroberto { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 26454359Sroberto { "yes|no", "", "", "" }, 26554359Sroberto "specify whether hostnames or net numbers are printed"}, 266182007Sroberto { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 26754359Sroberto { "no|more|less", "", "", "" }, 26854359Sroberto "set/change debugging level" }, 26954359Sroberto { "quit", quit, { NO, NO, NO, NO }, 27054359Sroberto { "", "", "", "" }, 27154359Sroberto "exit ntpq" }, 27254359Sroberto { "exit", quit, { NO, NO, NO, NO }, 27354359Sroberto { "", "", "", "" }, 27454359Sroberto "exit ntpq" }, 275182007Sroberto { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 27654359Sroberto { "key#", "", "", "" }, 27754359Sroberto "set keyid to use for authenticated requests" }, 278298695Sdelphij { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 279298695Sdelphij { "hash|ipv4", "", "", "" }, 280298695Sdelphij "display refid's as IPv4 or hash" }, 28154359Sroberto { "version", version, { NO, NO, NO, NO }, 28254359Sroberto { "", "", "", "" }, 28354359Sroberto "print version number" }, 28454359Sroberto { "raw", raw, { NO, NO, NO, NO }, 28554359Sroberto { "", "", "", "" }, 28654359Sroberto "do raw mode variable output" }, 28754359Sroberto { "cooked", cooked, { NO, NO, NO, NO }, 28854359Sroberto { "", "", "", "" }, 28954359Sroberto "do cooked mode variable output" }, 290182007Sroberto { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 29154359Sroberto { "yes|no", "", "", "" }, 29254359Sroberto "always authenticate requests to this server" }, 293182007Sroberto { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 29454359Sroberto { "version number", "", "", "" }, 29554359Sroberto "set the NTP version number to use for requests" }, 296182007Sroberto { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 297285169Scy { "key type %s", "", "", "" }, 298285169Scy NULL }, 29954359Sroberto { 0, 0, { NO, NO, NO, NO }, 30054359Sroberto { "", "", "", "" }, "" } 30154359Sroberto}; 30254359Sroberto 30354359Sroberto 30454359Sroberto/* 30554359Sroberto * Default values we use. 30654359Sroberto */ 307280849Scy#define DEFHOST "localhost" /* default host name */ 308280849Scy#define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 309280849Scy#define DEFSTIMEOUT 3 /* and 3 more for each additional */ 310280849Scy/* 311280849Scy * Requests are automatically retried once, so total timeout with no 312280849Scy * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 313280849Scy * extreme, a request eliciting 32 packets of responses each for some 314280849Scy * reason nearly DEFSTIMEOUT seconds after the prior in that series, 315280849Scy * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 316280849Scy * 93 seconds to fail each of two times, or 186 seconds. 317280849Scy * Some commands involve a series of requests, such as "peers" and 318280849Scy * "mrulist", so the cumulative timeouts are even longer for those. 319280849Scy */ 32054359Sroberto#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 32154359Sroberto#define LENHOSTNAME 256 /* host name is 256 characters long */ 32254359Sroberto#define MAXCMDS 100 /* maximum commands on cmd line */ 32354359Sroberto#define MAXHOSTS 200 /* maximum hosts on cmd line */ 32454359Sroberto#define MAXLINE 512 /* maximum line length */ 32554359Sroberto#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 32654359Sroberto#define MAXVARLEN 256 /* maximum length of a variable name */ 327280849Scy#define MAXVALLEN 2048 /* maximum length of a variable value */ 32854359Sroberto#define MAXOUTLINE 72 /* maximum length of an output line */ 329280849Scy#define SCREENWIDTH 76 /* nominal screen width in columns */ 33054359Sroberto 33154359Sroberto/* 33254359Sroberto * Some variables used and manipulated locally 33354359Sroberto */ 334280849Scystruct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 335280849Scystruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 33654359Srobertol_fp delay_time; /* delay time */ 33754359Srobertochar currenthost[LENHOSTNAME]; /* current host name */ 338280849Scyint currenthostisnum; /* is prior text from IP? */ 339280849Scystruct sockaddr_in hostaddr; /* host address */ 34054359Srobertoint showhostnames = 1; /* show host names by default */ 341280849Scyint wideremote = 0; /* show wide remote names? */ 34254359Sroberto 343132451Srobertoint ai_fam_templ; /* address family */ 344132451Srobertoint ai_fam_default; /* default address family */ 345132451SrobertoSOCKET sockfd; /* fd socket is opened on */ 34654359Srobertoint havehost = 0; /* set to 1 when host open */ 347132451Srobertoint s_port = 0; 34854359Srobertostruct servent *server_entry = NULL; /* server entry for ntp */ 34954359Sroberto 35054359Sroberto 35154359Sroberto/* 35254359Sroberto * Sequence number used for requests. It is incremented before 35354359Sroberto * it is used. 35454359Sroberto */ 35554359Srobertou_short sequence; 35654359Sroberto 35754359Sroberto/* 35854359Sroberto * Holds data returned from queries. Declare buffer long to be sure of 35954359Sroberto * alignment. 36054359Sroberto */ 36154359Sroberto#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 36254359Srobertolong pktdata[DATASIZE/sizeof(long)]; 36354359Sroberto 36454359Sroberto/* 365280849Scy * assoc_cache[] is a dynamic array which allows references to 366280849Scy * associations using &1 ... &N for n associations, avoiding manual 367280849Scy * lookup of the current association IDs for a given ntpd. It also 368280849Scy * caches the status word for each association, retrieved incidentally. 36954359Sroberto */ 370280849Scystruct association * assoc_cache; 371280849Scyu_int assoc_cache_slots;/* count of allocated array entries */ 372280849Scyu_int numassoc; /* number of cached associations */ 37354359Sroberto 37454359Sroberto/* 37554359Sroberto * For commands typed on the command line (with the -c option) 37654359Sroberto */ 377316722Sdelphijsize_t numcmds = 0; 37854359Srobertoconst char *ccmds[MAXCMDS]; 37954359Sroberto#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 38054359Sroberto 38154359Sroberto/* 38254359Sroberto * When multiple hosts are specified. 38354359Sroberto */ 38454359Sroberto 385280849Scyu_int numhosts; 38654359Sroberto 387280849Scychost chosts[MAXHOSTS]; 388280849Scy#define ADDHOST(cp) \ 389280849Scy do { \ 390280849Scy if (numhosts < MAXHOSTS) { \ 391280849Scy chosts[numhosts].name = (cp); \ 392280849Scy chosts[numhosts].fam = ai_fam_templ; \ 393280849Scy numhosts++; \ 394280849Scy } \ 395280849Scy } while (0) 396280849Scy 39754359Sroberto/* 39854359Sroberto * Macro definitions we use 39954359Sroberto */ 40054359Sroberto#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 40154359Sroberto#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 40254359Sroberto#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 40354359Sroberto 40454359Sroberto/* 40554359Sroberto * Jump buffer for longjumping back to the command level 40654359Sroberto */ 40754359Srobertojmp_buf interrupt_buf; 40854359Sroberto 40954359Sroberto/* 41054359Sroberto * Points at file being currently printed into 41154359Sroberto */ 41254359SrobertoFILE *current_output; 41354359Sroberto 41454359Sroberto/* 41554359Sroberto * Command table imported from ntpdc_ops.c 41654359Sroberto */ 41754359Srobertoextern struct xcmd opcmds[]; 41854359Sroberto 419289764Sglebiuschar const *progname; 42054359Sroberto 42154359Sroberto#ifdef NO_MAIN_ALLOWED 422280849Scy#ifndef BUILD_AS_LIB 42354359SrobertoCALL(ntpq,"ntpq",ntpqmain); 42454359Sroberto 42554359Srobertovoid clear_globals(void) 42654359Sroberto{ 427280849Scy extern int ntp_optind; 428280849Scy showhostnames = 0; /* don'tshow host names by default */ 429280849Scy ntp_optind = 0; 430280849Scy server_entry = NULL; /* server entry for ntp */ 431280849Scy havehost = 0; /* set to 1 when host open */ 432280849Scy numassoc = 0; /* number of cached associations */ 433280849Scy numcmds = 0; 434280849Scy numhosts = 0; 43554359Sroberto} 436280849Scy#endif /* !BUILD_AS_LIB */ 437280849Scy#endif /* NO_MAIN_ALLOWED */ 43854359Sroberto 43954359Sroberto/* 44054359Sroberto * main - parse arguments and handle options 44154359Sroberto */ 44254359Sroberto#ifndef NO_MAIN_ALLOWED 44354359Srobertoint 44454359Srobertomain( 44554359Sroberto int argc, 44654359Sroberto char *argv[] 44754359Sroberto ) 44854359Sroberto{ 44954359Sroberto return ntpqmain(argc, argv); 45054359Sroberto} 45154359Sroberto#endif 45254359Sroberto 453280849Scy#ifndef BUILD_AS_LIB 45454359Srobertoint 45554359Srobertontpqmain( 45654359Sroberto int argc, 45754359Sroberto char *argv[] 45854359Sroberto ) 45954359Sroberto{ 460280849Scy u_int ihost; 461316722Sdelphij size_t icmd; 46254359Sroberto 463280849Scy 464182007Sroberto#ifdef SYS_VXWORKS 465182007Sroberto clear_globals(); 466182007Sroberto taskPrioritySet(taskIdSelf(), 100 ); 46754359Sroberto#endif 468182007Sroberto 46954359Sroberto delay_time.l_ui = 0; 47054359Sroberto delay_time.l_uf = DEFDELAY; 47154359Sroberto 472280849Scy init_lib(); /* sets up ipv4_works, ipv6_works */ 473280849Scy ssl_applink(); 474280849Scy init_auth(); 475132451Sroberto 476280849Scy /* Check to see if we have IPv6. Otherwise default to IPv4 */ 477280849Scy if (!ipv6_works) 478132451Sroberto ai_fam_default = AF_INET; 479132451Sroberto 480285169Scy /* Fixup keytype's help based on available digest names */ 481285169Scy 482285169Scy { 483285169Scy char *list; 484294554Sdelphij char *msg; 485285169Scy 486285169Scy list = list_digest_names(); 487285169Scy for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) { 488285169Scy if (strcmp("keytype", builtins[icmd].keyword) == 0) 489285169Scy break; 490285169Scy } 491285169Scy 492285169Scy /* CID: 1295478 */ 493285169Scy /* This should only "trip" if "keytype" is removed from builtins */ 494285169Scy INSIST(icmd < sizeof(builtins)/sizeof(builtins[0])); 495285169Scy 496285169Scy#ifdef OPENSSL 497285169Scy builtins[icmd].desc[0] = "digest-name"; 498294554Sdelphij my_easprintf(&msg, 499294554Sdelphij "set key type to use for authenticated requests, one of:%s", 500294554Sdelphij list); 501285169Scy#else 502285169Scy builtins[icmd].desc[0] = "md5"; 503294554Sdelphij my_easprintf(&msg, 504294554Sdelphij "set key type to use for authenticated requests (%s)", 505294554Sdelphij list); 506285169Scy#endif 507285169Scy builtins[icmd].comment = msg; 508285169Scy free(list); 509285169Scy } 510285169Scy 51154359Sroberto progname = argv[0]; 512182007Sroberto 513182007Sroberto { 514280849Scy int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 515182007Sroberto argc -= optct; 516182007Sroberto argv += optct; 517182007Sroberto } 518182007Sroberto 519280849Scy /* 520280849Scy * Process options other than -c and -p, which are specially 521280849Scy * handled by ntpq_custom_opt_handler(). 522280849Scy */ 523280849Scy 524280849Scy debug = OPT_VALUE_SET_DEBUG_LEVEL; 525280849Scy 526280849Scy if (HAVE_OPT(IPV4)) 527182007Sroberto ai_fam_templ = AF_INET; 528280849Scy else if (HAVE_OPT(IPV6)) 529182007Sroberto ai_fam_templ = AF_INET6; 530280849Scy else 531182007Sroberto ai_fam_templ = ai_fam_default; 532182007Sroberto 533280849Scy if (HAVE_OPT(INTERACTIVE)) 534182007Sroberto interactive = 1; 535182007Sroberto 536280849Scy if (HAVE_OPT(NUMERIC)) 537182007Sroberto showhostnames = 0; 538182007Sroberto 539280849Scy if (HAVE_OPT(WIDE)) 540280849Scy wideremote = 1; 541182007Sroberto 542280849Scy old_rv = HAVE_OPT(OLD_RV); 543280849Scy 544298695Sdelphij drefid = OPT_VALUE_REFID; 545298695Sdelphij 546280849Scy if (0 == argc) { 54754359Sroberto ADDHOST(DEFHOST); 54854359Sroberto } else { 549280849Scy for (ihost = 0; ihost < (u_int)argc; ihost++) { 550280849Scy if ('-' == *argv[ihost]) { 551280849Scy // 552280849Scy // If I really cared I'd also check: 553280849Scy // 0 == argv[ihost][2] 554280849Scy // 555280849Scy // and there are other cases as well... 556280849Scy // 557280849Scy if ('4' == argv[ihost][1]) { 558280849Scy ai_fam_templ = AF_INET; 559280849Scy continue; 560280849Scy } else if ('6' == argv[ihost][1]) { 561280849Scy ai_fam_templ = AF_INET6; 562280849Scy continue; 563280849Scy } else { 564280849Scy // XXX Throw a usage error 565280849Scy } 566280849Scy } 567280849Scy ADDHOST(argv[ihost]); 568280849Scy } 56954359Sroberto } 57054359Sroberto 57154359Sroberto if (numcmds == 0 && interactive == 0 57254359Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 57354359Sroberto interactive = 1; 57454359Sroberto } 57554359Sroberto 576293423Sdelphij set_ctrl_c_hook(on_ctrlc); 57754359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 57854359Sroberto if (interactive) 579293423Sdelphij push_ctrl_c_handler(abortcmd); 58054359Sroberto#endif /* SYS_WINNT */ 58154359Sroberto 58254359Sroberto if (numcmds == 0) { 583280849Scy (void) openhost(chosts[0].name, chosts[0].fam); 58454359Sroberto getcmds(); 58554359Sroberto } else { 58654359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 587280849Scy if (openhost(chosts[ihost].name, chosts[ihost].fam)) 588280849Scy for (icmd = 0; icmd < numcmds; icmd++) 589280849Scy docmd(ccmds[icmd]); 59054359Sroberto } 59154359Sroberto } 59254359Sroberto#ifdef SYS_WINNT 59354359Sroberto WSACleanup(); 59454359Sroberto#endif /* SYS_WINNT */ 59554359Sroberto return 0; 59654359Sroberto} 597280849Scy#endif /* !BUILD_AS_LIB */ 59854359Sroberto 59954359Sroberto/* 60054359Sroberto * openhost - open a socket to a host 60154359Sroberto */ 602280849Scystatic int 60354359Srobertoopenhost( 604280849Scy const char *hname, 605280849Scy int fam 60654359Sroberto ) 60754359Sroberto{ 608280849Scy const char svc[] = "ntp"; 60954359Sroberto char temphost[LENHOSTNAME]; 610132451Sroberto int a_info, i; 611280849Scy struct addrinfo hints, *ai; 612280849Scy sockaddr_u addr; 613280849Scy size_t octets; 614132451Sroberto register const char *cp; 615132451Sroberto char name[LENHOSTNAME]; 61654359Sroberto 617132451Sroberto /* 618132451Sroberto * We need to get by the [] if they were entered 619132451Sroberto */ 620280849Scy 621132451Sroberto cp = hname; 622280849Scy 623280849Scy if (*cp == '[') { 624132451Sroberto cp++; 625280849Scy for (i = 0; *cp && *cp != ']'; cp++, i++) 626132451Sroberto name[i] = *cp; 627280849Scy if (*cp == ']') { 628280849Scy name[i] = '\0'; 629280849Scy hname = name; 630280849Scy } else { 631280849Scy return 0; 632280849Scy } 63354359Sroberto } 63454359Sroberto 635132451Sroberto /* 636132451Sroberto * First try to resolve it as an ip address and if that fails, 637132451Sroberto * do a fullblown (dns) lookup. That way we only use the dns 638132451Sroberto * when it is needed and work around some implementations that 639132451Sroberto * will return an "IPv4-mapped IPv6 address" address if you 640132451Sroberto * give it an IPv4 address to lookup. 641132451Sroberto */ 642280849Scy ZERO(hints); 643280849Scy hints.ai_family = fam; 644132451Sroberto hints.ai_protocol = IPPROTO_UDP; 645132451Sroberto hints.ai_socktype = SOCK_DGRAM; 646280849Scy hints.ai_flags = Z_AI_NUMERICHOST; 647280849Scy ai = NULL; 648132451Sroberto 649280849Scy a_info = getaddrinfo(hname, svc, &hints, &ai); 650182007Sroberto if (a_info == EAI_NONAME 651182007Sroberto#ifdef EAI_NODATA 652182007Sroberto || a_info == EAI_NODATA 653182007Sroberto#endif 654182007Sroberto ) { 655132451Sroberto hints.ai_flags = AI_CANONNAME; 656132451Sroberto#ifdef AI_ADDRCONFIG 657132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 658132451Sroberto#endif 659280849Scy a_info = getaddrinfo(hname, svc, &hints, &ai); 660132451Sroberto } 661280849Scy#ifdef AI_ADDRCONFIG 662132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 663132451Sroberto if (a_info == EAI_BADFLAGS) { 664280849Scy hints.ai_flags &= ~AI_ADDRCONFIG; 665280849Scy a_info = getaddrinfo(hname, svc, &hints, &ai); 666132451Sroberto } 667280849Scy#endif 668132451Sroberto if (a_info != 0) { 669280849Scy fprintf(stderr, "%s\n", gai_strerror(a_info)); 670132451Sroberto return 0; 671132451Sroberto } 672132451Sroberto 673280849Scy INSIST(ai != NULL); 674280849Scy ZERO(addr); 675280849Scy octets = min(sizeof(addr), ai->ai_addrlen); 676280849Scy memcpy(&addr, ai->ai_addr, octets); 677280849Scy 678132451Sroberto if (ai->ai_canonname == NULL) { 679280849Scy strlcpy(temphost, stoa(&addr), sizeof(temphost)); 680280849Scy currenthostisnum = TRUE; 681132451Sroberto } else { 682280849Scy strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 683280849Scy currenthostisnum = FALSE; 684132451Sroberto } 685132451Sroberto 68654359Sroberto if (debug > 2) 687280849Scy printf("Opening host %s (%s)\n", 688280849Scy temphost, 689280849Scy (ai->ai_family == AF_INET) 690280849Scy ? "AF_INET" 691280849Scy : (ai->ai_family == AF_INET6) 692280849Scy ? "AF_INET6" 693280849Scy : "AF-???" 694280849Scy ); 69554359Sroberto 69654359Sroberto if (havehost == 1) { 69754359Sroberto if (debug > 2) 698280849Scy printf("Closing old host %s\n", currenthost); 699280849Scy closesocket(sockfd); 70054359Sroberto havehost = 0; 70154359Sroberto } 702280849Scy strlcpy(currenthost, temphost, sizeof(currenthost)); 70354359Sroberto 704132451Sroberto /* port maps to the same location in both families */ 705280849Scy s_port = NSRCPORT(&addr); 706132451Sroberto#ifdef SYS_VXWORKS 707132451Sroberto ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 708132451Sroberto if (ai->ai_family == AF_INET) 709132451Sroberto *(struct sockaddr_in *)&hostaddr= 710132451Sroberto *((struct sockaddr_in *)ai->ai_addr); 711132451Sroberto else 712132451Sroberto *(struct sockaddr_in6 *)&hostaddr= 713132451Sroberto *((struct sockaddr_in6 *)ai->ai_addr); 714132451Sroberto#endif /* SYS_VXWORKS */ 71554359Sroberto 71654359Sroberto#ifdef SYS_WINNT 71754359Sroberto { 71854359Sroberto int optionValue = SO_SYNCHRONOUS_NONALERT; 71954359Sroberto int err; 720182007Sroberto 721280849Scy err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 722280849Scy (char *)&optionValue, sizeof(optionValue)); 723280849Scy if (err) { 724280849Scy mfprintf(stderr, 725280849Scy "setsockopt(SO_SYNCHRONOUS_NONALERT)" 726280849Scy " error: %m\n"); 727280849Scy freeaddrinfo(ai); 72854359Sroberto exit(1); 72954359Sroberto } 73054359Sroberto } 731132451Sroberto#endif /* SYS_WINNT */ 73254359Sroberto 733280849Scy sockfd = socket(ai->ai_family, ai->ai_socktype, 734280849Scy ai->ai_protocol); 73554359Sroberto if (sockfd == INVALID_SOCKET) { 736280849Scy error("socket"); 737280849Scy freeaddrinfo(ai); 738280849Scy return 0; 73954359Sroberto } 74054359Sroberto 741280849Scy 74254359Sroberto#ifdef NEED_RCVBUF_SLOP 74354359Sroberto# ifdef SO_RCVBUF 74454359Sroberto { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 74554359Sroberto if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 74654359Sroberto &rbufsize, sizeof(int)) == -1) 747280849Scy error("setsockopt"); 74854359Sroberto } 74954359Sroberto# endif 75054359Sroberto#endif 75154359Sroberto 752280849Scy if 753132451Sroberto#ifdef SYS_VXWORKS 754280849Scy (connect(sockfd, (struct sockaddr *)&hostaddr, 75554359Sroberto sizeof(hostaddr)) == -1) 756132451Sroberto#else 757280849Scy (connect(sockfd, (struct sockaddr *)ai->ai_addr, 758293423Sdelphij ai->ai_addrlen) == -1) 759132451Sroberto#endif /* SYS_VXWORKS */ 760293423Sdelphij { 761280849Scy error("connect"); 762132451Sroberto freeaddrinfo(ai); 763280849Scy return 0; 764280849Scy } 765280849Scy freeaddrinfo(ai); 76654359Sroberto havehost = 1; 767280849Scy numassoc = 0; 768280849Scy 76954359Sroberto return 1; 77054359Sroberto} 77154359Sroberto 77254359Sroberto 773280849Scystatic void 774280849Scydump_hex_printable( 775280849Scy const void * data, 776280849Scy size_t len 777280849Scy ) 778280849Scy{ 779316722Sdelphij /* every line shows at most 16 bytes, so we need a buffer of 780316722Sdelphij * 4 * 16 (2 xdigits, 1 char, one sep for xdigits) 781316722Sdelphij * + 2 * 1 (block separators) 782316722Sdelphij * + <LF> + <NUL> 783316722Sdelphij *--------------- 784316722Sdelphij * 68 bytes 785316722Sdelphij */ 786316722Sdelphij static const char s_xdig[16] = "0123456789ABCDEF"; 787280849Scy 788316722Sdelphij char lbuf[68]; 789316722Sdelphij int ch, rowlen; 790316722Sdelphij const u_char * cdata = data; 791316722Sdelphij char *xptr, *pptr; 792316722Sdelphij 793316722Sdelphij while (len) { 794316722Sdelphij memset(lbuf, ' ', sizeof(lbuf)); 795316722Sdelphij xptr = lbuf; 796316722Sdelphij pptr = lbuf + 3*16 + 2; 797316722Sdelphij 798316722Sdelphij rowlen = (len > 16) ? 16 : (int)len; 799280849Scy len -= rowlen; 800316722Sdelphij 801316722Sdelphij do { 802316722Sdelphij ch = *cdata++; 803316722Sdelphij 804316722Sdelphij *xptr++ = s_xdig[ch >> 4 ]; 805316722Sdelphij *xptr++ = s_xdig[ch & 0x0F]; 806316722Sdelphij if (++xptr == lbuf + 3*8) 807316722Sdelphij ++xptr; 808316722Sdelphij 809316722Sdelphij *pptr++ = isprint(ch) ? (char)ch : '.'; 810316722Sdelphij } while (--rowlen); 811316722Sdelphij 812316722Sdelphij *pptr++ = '\n'; 813316722Sdelphij *pptr = '\0'; 814316722Sdelphij fputs(lbuf, stdout); 815280849Scy } 816280849Scy} 817280849Scy 818280849Scy 81954359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 82054359Sroberto/* 82154359Sroberto * sendpkt - send a packet to the remote host 82254359Sroberto */ 82354359Srobertostatic int 82454359Srobertosendpkt( 825280849Scy void * xdata, 826280849Scy size_t xdatalen 82754359Sroberto ) 82854359Sroberto{ 82954359Sroberto if (debug >= 3) 830280849Scy printf("Sending %zu octets\n", xdatalen); 83154359Sroberto 832293423Sdelphij if (send(sockfd, xdata, xdatalen, 0) == -1) { 833280849Scy warning("write to %s failed", currenthost); 83454359Sroberto return -1; 83554359Sroberto } 83654359Sroberto 83754359Sroberto if (debug >= 4) { 838280849Scy printf("Request packet:\n"); 839280849Scy dump_hex_printable(xdata, xdatalen); 84054359Sroberto } 84154359Sroberto return 0; 84254359Sroberto} 84354359Sroberto 84454359Sroberto/* 84554359Sroberto * getresponse - get a (series of) response packet(s) and return the data 84654359Sroberto */ 84754359Srobertostatic int 84854359Srobertogetresponse( 84954359Sroberto int opcode, 85054359Sroberto int associd, 85154359Sroberto u_short *rstatus, 852293423Sdelphij size_t *rsize, 853280849Scy const char **rdata, 85454359Sroberto int timeo 85554359Sroberto ) 85654359Sroberto{ 85754359Sroberto struct ntp_control rpkt; 858280849Scy struct sock_timeval tvo; 85954359Sroberto u_short offsets[MAXFRAGS+1]; 86054359Sroberto u_short counts[MAXFRAGS+1]; 86154359Sroberto u_short offset; 86254359Sroberto u_short count; 863280849Scy size_t numfrags; 864280849Scy size_t f; 865280849Scy size_t ff; 86654359Sroberto int seenlastfrag; 867280849Scy int shouldbesize; 86854359Sroberto fd_set fds; 86954359Sroberto int n; 870280849Scy int errcode; 871294554Sdelphij /* absolute timeout checks. Not 'time_t' by intention! */ 872294554Sdelphij uint32_t tobase; /* base value for timeout */ 873294554Sdelphij uint32_t tospan; /* timeout span (max delay) */ 874294554Sdelphij uint32_t todiff; /* current delay */ 87554359Sroberto 876316722Sdelphij memset(offsets, 0, sizeof(offsets)); 877316722Sdelphij memset(counts , 0, sizeof(counts )); 878316722Sdelphij 87954359Sroberto /* 88054359Sroberto * This is pretty tricky. We may get between 1 and MAXFRAG packets 88154359Sroberto * back in response to the request. We peel the data out of 88254359Sroberto * each packet and collect it in one long block. When the last 88354359Sroberto * packet in the sequence is received we'll know how much data we 88454359Sroberto * should have had. Note we use one long time out, should reconsider. 88554359Sroberto */ 88654359Sroberto *rsize = 0; 88754359Sroberto if (rstatus) 888280849Scy *rstatus = 0; 88954359Sroberto *rdata = (char *)pktdata; 89054359Sroberto 89154359Sroberto numfrags = 0; 89254359Sroberto seenlastfrag = 0; 89354359Sroberto 894294554Sdelphij tobase = (uint32_t)time(NULL); 895294554Sdelphij 89654359Sroberto FD_ZERO(&fds); 89754359Sroberto 898280849Scy /* 899280849Scy * Loop until we have an error or a complete response. Nearly all 900280849Scy * code paths to loop again use continue. 901280849Scy */ 902280849Scy for (;;) { 90354359Sroberto 904280849Scy if (numfrags == 0) 905280849Scy tvo = tvout; 906280849Scy else 907280849Scy tvo = tvsout; 908294554Sdelphij tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 90954359Sroberto 910280849Scy FD_SET(sockfd, &fds); 911293423Sdelphij n = select(sockfd+1, &fds, NULL, NULL, &tvo); 912280849Scy if (n == -1) { 913294554Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 914294554Sdelphij /* Windows does not know about EINTR (until very 915294554Sdelphij * recently) and the handling of console events 916294554Sdelphij * is *very* different from POSIX/UNIX signal 917294554Sdelphij * handling anyway. 918294554Sdelphij * 919294554Sdelphij * Under non-windows targets we map EINTR as 920294554Sdelphij * 'last packet was received' and try to exit 921294554Sdelphij * the receive sequence. 922294554Sdelphij */ 923294554Sdelphij if (errno == EINTR) { 924294554Sdelphij seenlastfrag = 1; 925294554Sdelphij goto maybe_final; 926294554Sdelphij } 927294554Sdelphij#endif 928280849Scy warning("select fails"); 929280849Scy return -1; 930280849Scy } 931294554Sdelphij 932294554Sdelphij /* 933294554Sdelphij * Check if this is already too late. Trash the data and 934294554Sdelphij * fake a timeout if this is so. 935294554Sdelphij */ 936294554Sdelphij todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 937294554Sdelphij if ((n > 0) && (todiff > tospan)) { 938294554Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 939316722Sdelphij n -= n; /* faked timeout return from 'select()', 940316722Sdelphij * execute RMW cycle on 'n' 941316722Sdelphij */ 942294554Sdelphij } 943294554Sdelphij 944316722Sdelphij if (n <= 0) { 945280849Scy /* 946280849Scy * Timed out. Return what we have 947280849Scy */ 948280849Scy if (numfrags == 0) { 949280849Scy if (timeo) 950280849Scy fprintf(stderr, 951280849Scy "%s: timed out, nothing received\n", 952280849Scy currenthost); 953280849Scy return ERR_TIMEOUT; 954280849Scy } 95554359Sroberto if (timeo) 956280849Scy fprintf(stderr, 957280849Scy "%s: timed out with incomplete data\n", 958280849Scy currenthost); 95954359Sroberto if (debug) { 960280849Scy fprintf(stderr, 961280849Scy "ERR_INCOMPLETE: Received fragments:\n"); 962280849Scy for (f = 0; f < numfrags; f++) 963280849Scy fprintf(stderr, 964280849Scy "%2u: %5d %5d\t%3d octets\n", 965280849Scy (u_int)f, offsets[f], 966280849Scy offsets[f] + 967280849Scy counts[f], 968280849Scy counts[f]); 969280849Scy fprintf(stderr, 970280849Scy "last fragment %sreceived\n", 971280849Scy (seenlastfrag) 972280849Scy ? "" 973280849Scy : "not "); 97454359Sroberto } 97554359Sroberto return ERR_INCOMPLETE; 97654359Sroberto } 97754359Sroberto 978280849Scy n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 979316722Sdelphij if (n < 0) { 980280849Scy warning("read"); 981280849Scy return -1; 982280849Scy } 98354359Sroberto 984280849Scy if (debug >= 4) { 985280849Scy printf("Response packet:\n"); 986280849Scy dump_hex_printable(&rpkt, n); 987280849Scy } 98854359Sroberto 989280849Scy /* 990280849Scy * Check for format errors. Bug proofing. 991280849Scy */ 992280849Scy if (n < (int)CTL_HEADER_LEN) { 993280849Scy if (debug) 994280849Scy printf("Short (%d byte) packet received\n", n); 995280849Scy continue; 99654359Sroberto } 997280849Scy if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 998280849Scy || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 999280849Scy if (debug) 1000280849Scy printf("Packet received with version %d\n", 1001280849Scy PKT_VERSION(rpkt.li_vn_mode)); 1002280849Scy continue; 1003280849Scy } 1004280849Scy if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 1005280849Scy if (debug) 1006280849Scy printf("Packet received with mode %d\n", 1007280849Scy PKT_MODE(rpkt.li_vn_mode)); 1008280849Scy continue; 1009280849Scy } 1010280849Scy if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 1011280849Scy if (debug) 1012280849Scy printf("Received request packet, wanted response\n"); 1013280849Scy continue; 1014280849Scy } 101554359Sroberto 1016280849Scy /* 1017280849Scy * Check opcode and sequence number for a match. 1018280849Scy * Could be old data getting to us. 1019280849Scy */ 1020280849Scy if (ntohs(rpkt.sequence) != sequence) { 1021280849Scy if (debug) 1022280849Scy printf("Received sequnce number %d, wanted %d\n", 1023280849Scy ntohs(rpkt.sequence), sequence); 1024280849Scy continue; 1025280849Scy } 1026280849Scy if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1027280849Scy if (debug) 1028280849Scy printf( 1029280849Scy "Received opcode %d, wanted %d (sequence number okay)\n", 1030280849Scy CTL_OP(rpkt.r_m_e_op), opcode); 1031280849Scy continue; 1032280849Scy } 103354359Sroberto 1034280849Scy /* 1035280849Scy * Check the error code. If non-zero, return it. 1036280849Scy */ 1037280849Scy if (CTL_ISERROR(rpkt.r_m_e_op)) { 1038280849Scy errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1039280849Scy if (CTL_ISMORE(rpkt.r_m_e_op)) 1040280849Scy TRACE(1, ("Error code %d received on not-final packet\n", 1041280849Scy errcode)); 1042280849Scy if (errcode == CERR_UNSPEC) 1043280849Scy return ERR_UNSPEC; 1044280849Scy return errcode; 104554359Sroberto } 104654359Sroberto 104754359Sroberto /* 1048280849Scy * Check the association ID to make sure it matches what 1049280849Scy * we sent. 105054359Sroberto */ 1051280849Scy if (ntohs(rpkt.associd) != associd) { 1052280849Scy TRACE(1, ("Association ID %d doesn't match expected %d\n", 1053280849Scy ntohs(rpkt.associd), associd)); 1054280849Scy /* 1055280849Scy * Hack for silly fuzzballs which, at the time of writing, 1056280849Scy * return an assID of sys.peer when queried for system variables. 1057280849Scy */ 105854359Sroberto#ifdef notdef 1059280849Scy continue; 106054359Sroberto#endif 1061280849Scy } 106254359Sroberto 1063280849Scy /* 1064280849Scy * Collect offset and count. Make sure they make sense. 1065280849Scy */ 1066280849Scy offset = ntohs(rpkt.offset); 1067280849Scy count = ntohs(rpkt.count); 106854359Sroberto 106954359Sroberto /* 1070280849Scy * validate received payload size is padded to next 32-bit 1071280849Scy * boundary and no smaller than claimed by rpkt.count 107254359Sroberto */ 1073280849Scy if (n & 0x3) { 1074280849Scy TRACE(1, ("Response packet not padded, size = %d\n", 1075280849Scy n)); 1076280849Scy continue; 1077280849Scy } 107854359Sroberto 1079280849Scy shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 108054359Sroberto 1081280849Scy if (n < shouldbesize) { 1082280849Scy printf("Response packet claims %u octets payload, above %ld received\n", 1083301247Sdelphij count, (long)(n - CTL_HEADER_LEN)); 1084280849Scy return ERR_INCOMPLETE; 1085280849Scy } 1086280849Scy 1087280849Scy if (debug >= 3 && shouldbesize > n) { 1088280849Scy u_int32 key; 1089280849Scy u_int32 *lpkt; 1090280849Scy int maclen; 1091280849Scy 1092280849Scy /* 1093280849Scy * Usually we ignore authentication, but for debugging purposes 1094280849Scy * we watch it here. 1095280849Scy */ 1096280849Scy /* round to 8 octet boundary */ 1097280849Scy shouldbesize = (shouldbesize + 7) & ~7; 1098280849Scy 1099280849Scy maclen = n - shouldbesize; 1100280849Scy if (maclen >= (int)MIN_MAC_LEN) { 1101280849Scy printf( 1102280849Scy "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1103280849Scy n, shouldbesize, maclen); 1104280849Scy lpkt = (u_int32 *)&rpkt; 1105280849Scy printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1106280849Scy (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1107280849Scy (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1108280849Scy (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1109280849Scy (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1110280849Scy (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1111280849Scy (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1112280849Scy key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1113280849Scy printf("Authenticated with keyid %lu\n", (u_long)key); 1114280849Scy if (key != 0 && key != info_auth_keyid) { 1115280849Scy printf("We don't know that key\n"); 111654359Sroberto } else { 1117280849Scy if (authdecrypt(key, (u_int32 *)&rpkt, 1118280849Scy n - maclen, maclen)) { 1119280849Scy printf("Auth okay!\n"); 1120280849Scy } else { 1121280849Scy printf("Auth failed!\n"); 1122280849Scy } 112354359Sroberto } 112454359Sroberto } 112554359Sroberto } 112654359Sroberto 1127280849Scy TRACE(2, ("Got packet, size = %d\n", n)); 1128280849Scy if (count > (n - CTL_HEADER_LEN)) { 1129280849Scy TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1130280849Scy count, (long)n - CTL_HEADER_LEN)); 1131280849Scy continue; 1132280849Scy } 1133280849Scy if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1134280849Scy TRACE(1, ("Received count of 0 in non-final fragment\n")); 1135280849Scy continue; 1136280849Scy } 1137280849Scy if (offset + count > sizeof(pktdata)) { 1138280849Scy TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1139280849Scy offset, count)); 1140280849Scy return ERR_TOOMUCH; 1141280849Scy } 1142280849Scy if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1143280849Scy TRACE(1, ("Received second last fragment packet\n")); 1144280849Scy continue; 1145280849Scy } 114654359Sroberto 1147280849Scy /* 1148280849Scy * So far, so good. Record this fragment, making sure it doesn't 1149280849Scy * overlap anything. 1150280849Scy */ 1151280849Scy TRACE(2, ("Packet okay\n")); 115254359Sroberto 1153280849Scy if (numfrags > (MAXFRAGS - 1)) { 1154280849Scy TRACE(2, ("Number of fragments exceeds maximum %d\n", 1155280849Scy MAXFRAGS - 1)); 1156280849Scy return ERR_TOOMUCH; 115754359Sroberto } 115854359Sroberto 1159280849Scy /* 1160280849Scy * Find the position for the fragment relative to any 1161280849Scy * previously received. 1162280849Scy */ 1163280849Scy for (f = 0; 1164280849Scy f < numfrags && offsets[f] < offset; 1165280849Scy f++) { 1166280849Scy /* empty body */ ; 1167280849Scy } 116854359Sroberto 1169280849Scy if (f < numfrags && offset == offsets[f]) { 1170280849Scy TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1171280849Scy count, offset, counts[f], offsets[f])); 1172280849Scy continue; 1173280849Scy } 117454359Sroberto 1175280849Scy if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1176280849Scy TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1177280849Scy offset, counts[f-1], offsets[f-1])); 1178280849Scy continue; 117954359Sroberto } 1180280849Scy 1181280849Scy if (f < numfrags && (offset + count) > offsets[f]) { 1182280849Scy TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1183280849Scy count, offset, offsets[f])); 1184280849Scy continue; 118554359Sroberto } 118654359Sroberto 1187280849Scy for (ff = numfrags; ff > f; ff--) { 1188280849Scy offsets[ff] = offsets[ff-1]; 1189280849Scy counts[ff] = counts[ff-1]; 1190280849Scy } 1191280849Scy offsets[f] = offset; 1192280849Scy counts[f] = count; 1193280849Scy numfrags++; 119454359Sroberto 1195280849Scy /* 1196280849Scy * Got that stuffed in right. Figure out if this was the last. 1197280849Scy * Record status info out of the last packet. 1198280849Scy */ 1199280849Scy if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1200280849Scy seenlastfrag = 1; 1201280849Scy if (rstatus != 0) 1202280849Scy *rstatus = ntohs(rpkt.status); 1203280849Scy } 120454359Sroberto 1205280849Scy /* 1206294554Sdelphij * Copy the data into the data buffer, and bump the 1207294554Sdelphij * timout base in case we need more. 1208280849Scy */ 1209280849Scy memcpy((char *)pktdata + offset, &rpkt.u, count); 1210294554Sdelphij tobase = (uint32_t)time(NULL); 1211294554Sdelphij 1212280849Scy /* 1213280849Scy * If we've seen the last fragment, look for holes in the sequence. 1214280849Scy * If there aren't any, we're done. 1215280849Scy */ 1216301247Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 1217301247Sdelphij maybe_final: 1218301247Sdelphij#endif 1219301247Sdelphij 1220280849Scy if (seenlastfrag && offsets[0] == 0) { 1221280849Scy for (f = 1; f < numfrags; f++) 1222280849Scy if (offsets[f-1] + counts[f-1] != 1223280849Scy offsets[f]) 1224280849Scy break; 1225280849Scy if (f == numfrags) { 1226280849Scy *rsize = offsets[f-1] + counts[f-1]; 1227280849Scy TRACE(1, ("%lu packets reassembled into response\n", 1228280849Scy (u_long)numfrags)); 1229280849Scy return 0; 1230280849Scy } 1231280849Scy } 1232280849Scy } /* giant for (;;) collecting response packets */ 1233280849Scy} /* getresponse() */ 1234280849Scy 1235280849Scy 123654359Sroberto/* 123754359Sroberto * sendrequest - format and send a request packet 123854359Sroberto */ 123954359Srobertostatic int 124054359Srobertosendrequest( 124154359Sroberto int opcode, 1242280849Scy associd_t associd, 124354359Sroberto int auth, 1244293423Sdelphij size_t qsize, 1245280849Scy const char *qdata 124654359Sroberto ) 124754359Sroberto{ 124854359Sroberto struct ntp_control qpkt; 1249293423Sdelphij size_t pktsize; 1250280849Scy u_long key_id; 1251280849Scy char * pass; 1252293423Sdelphij size_t maclen; 125354359Sroberto 125454359Sroberto /* 125554359Sroberto * Check to make sure the data will fit in one packet 125654359Sroberto */ 125754359Sroberto if (qsize > CTL_MAX_DATA_LEN) { 1258280849Scy fprintf(stderr, 1259293423Sdelphij "***Internal error! qsize (%zu) too large\n", 1260280849Scy qsize); 126154359Sroberto return 1; 126254359Sroberto } 126354359Sroberto 126454359Sroberto /* 126554359Sroberto * Fill in the packet 126654359Sroberto */ 126754359Sroberto qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1268132451Sroberto qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 126954359Sroberto qpkt.sequence = htons(sequence); 127054359Sroberto qpkt.status = 0; 127154359Sroberto qpkt.associd = htons((u_short)associd); 127254359Sroberto qpkt.offset = 0; 127354359Sroberto qpkt.count = htons((u_short)qsize); 127454359Sroberto 1275280849Scy pktsize = CTL_HEADER_LEN; 1276280849Scy 127754359Sroberto /* 1278280849Scy * If we have data, copy and pad it out to a 32-bit boundary. 127954359Sroberto */ 128054359Sroberto if (qsize > 0) { 1281280849Scy memcpy(&qpkt.u, qdata, (size_t)qsize); 1282280849Scy pktsize += qsize; 1283280849Scy while (pktsize & (sizeof(u_int32) - 1)) { 1284280849Scy qpkt.u.data[qsize++] = 0; 128554359Sroberto pktsize++; 128654359Sroberto } 128754359Sroberto } 128854359Sroberto 128954359Sroberto /* 129054359Sroberto * If it isn't authenticated we can just send it. Otherwise 129154359Sroberto * we're going to have to think about it a little. 129254359Sroberto */ 129354359Sroberto if (!auth && !always_auth) { 1294280849Scy return sendpkt(&qpkt, pktsize); 1295280849Scy } 129654359Sroberto 1297280849Scy /* 1298280849Scy * Pad out packet to a multiple of 8 octets to be sure 1299280849Scy * receiver can handle it. 1300280849Scy */ 1301280849Scy while (pktsize & 7) { 1302280849Scy qpkt.u.data[qsize++] = 0; 1303280849Scy pktsize++; 1304280849Scy } 130554359Sroberto 1306280849Scy /* 1307280849Scy * Get the keyid and the password if we don't have one. 1308280849Scy */ 1309280849Scy if (info_auth_keyid == 0) { 1310280849Scy key_id = getkeyid("Keyid: "); 1311280849Scy if (key_id == 0 || key_id > NTP_MAXKEY) { 1312280849Scy fprintf(stderr, 1313280849Scy "Invalid key identifier\n"); 1314280849Scy return 1; 131554359Sroberto } 1316280849Scy info_auth_keyid = key_id; 1317280849Scy } 1318280849Scy if (!authistrusted(info_auth_keyid)) { 1319280849Scy pass = getpass_keytype(info_auth_keytype); 1320280849Scy if ('\0' == pass[0]) { 1321280849Scy fprintf(stderr, "Invalid password\n"); 1322280849Scy return 1; 132354359Sroberto } 1324280849Scy authusekey(info_auth_keyid, info_auth_keytype, 1325280849Scy (u_char *)pass); 132654359Sroberto authtrust(info_auth_keyid, 1); 1327280849Scy } 132854359Sroberto 1329280849Scy /* 1330280849Scy * Do the encryption. 1331280849Scy */ 1332280849Scy maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1333280849Scy if (!maclen) { 1334280849Scy fprintf(stderr, "Key not found\n"); 1335280849Scy return 1; 1336280849Scy } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1337280849Scy fprintf(stderr, 1338293423Sdelphij "%zu octet MAC, %zu expected with %zu octet digest\n", 1339280849Scy maclen, (info_auth_hashlen + sizeof(keyid_t)), 1340280849Scy info_auth_hashlen); 1341280849Scy return 1; 134254359Sroberto } 1343280849Scy 1344280849Scy return sendpkt((char *)&qpkt, pktsize + maclen); 134554359Sroberto} 134654359Sroberto 134754359Sroberto 134854359Sroberto/* 1349280849Scy * show_error_msg - display the error text for a mode 6 error response. 135054359Sroberto */ 1351280849Scyvoid 1352280849Scyshow_error_msg( 1353280849Scy int m6resp, 1354280849Scy associd_t associd 1355280849Scy ) 1356280849Scy{ 1357280849Scy if (numhosts > 1) 1358280849Scy fprintf(stderr, "server=%s ", currenthost); 1359280849Scy 1360298695Sdelphij switch (m6resp) { 1361280849Scy 1362280849Scy case CERR_BADFMT: 1363280849Scy fprintf(stderr, 1364280849Scy "***Server reports a bad format request packet\n"); 1365280849Scy break; 1366280849Scy 1367280849Scy case CERR_PERMISSION: 1368280849Scy fprintf(stderr, 1369280849Scy "***Server disallowed request (authentication?)\n"); 1370280849Scy break; 1371280849Scy 1372280849Scy case CERR_BADOP: 1373280849Scy fprintf(stderr, 1374280849Scy "***Server reports a bad opcode in request\n"); 1375280849Scy break; 1376280849Scy 1377280849Scy case CERR_BADASSOC: 1378280849Scy fprintf(stderr, 1379280849Scy "***Association ID %d unknown to server\n", 1380280849Scy associd); 1381280849Scy break; 1382280849Scy 1383280849Scy case CERR_UNKNOWNVAR: 1384280849Scy fprintf(stderr, 1385280849Scy "***A request variable unknown to the server\n"); 1386280849Scy break; 1387280849Scy 1388280849Scy case CERR_BADVALUE: 1389280849Scy fprintf(stderr, 1390280849Scy "***Server indicates a request variable was bad\n"); 1391280849Scy break; 1392280849Scy 1393280849Scy case ERR_UNSPEC: 1394280849Scy fprintf(stderr, 1395280849Scy "***Server returned an unspecified error\n"); 1396280849Scy break; 1397280849Scy 1398280849Scy case ERR_TIMEOUT: 1399280849Scy fprintf(stderr, "***Request timed out\n"); 1400280849Scy break; 1401280849Scy 1402280849Scy case ERR_INCOMPLETE: 1403280849Scy fprintf(stderr, 1404280849Scy "***Response from server was incomplete\n"); 1405280849Scy break; 1406280849Scy 1407280849Scy case ERR_TOOMUCH: 1408280849Scy fprintf(stderr, 1409280849Scy "***Buffer size exceeded for returned data\n"); 1410280849Scy break; 1411280849Scy 1412280849Scy default: 1413280849Scy fprintf(stderr, 1414280849Scy "***Server returns unknown error code %d\n", 1415280849Scy m6resp); 1416280849Scy } 1417280849Scy} 1418280849Scy 1419280849Scy/* 1420280849Scy * doquery - send a request and process the response, displaying 1421280849Scy * error messages for any error responses. 1422280849Scy */ 142354359Srobertoint 142454359Srobertodoquery( 142554359Sroberto int opcode, 1426280849Scy associd_t associd, 142754359Sroberto int auth, 1428293423Sdelphij size_t qsize, 1429280849Scy const char *qdata, 143054359Sroberto u_short *rstatus, 1431293423Sdelphij size_t *rsize, 1432280849Scy const char **rdata 143354359Sroberto ) 143454359Sroberto{ 1435280849Scy return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1436280849Scy rsize, rdata, FALSE); 1437280849Scy} 1438280849Scy 1439280849Scy 1440280849Scy/* 1441280849Scy * doqueryex - send a request and process the response, optionally 1442280849Scy * displaying error messages for any error responses. 1443280849Scy */ 1444280849Scyint 1445280849Scydoqueryex( 1446280849Scy int opcode, 1447280849Scy associd_t associd, 1448280849Scy int auth, 1449293423Sdelphij size_t qsize, 1450280849Scy const char *qdata, 1451280849Scy u_short *rstatus, 1452293423Sdelphij size_t *rsize, 1453280849Scy const char **rdata, 1454280849Scy int quiet 1455280849Scy ) 1456280849Scy{ 145754359Sroberto int res; 145854359Sroberto int done; 145954359Sroberto 146054359Sroberto /* 146154359Sroberto * Check to make sure host is open 146254359Sroberto */ 146354359Sroberto if (!havehost) { 1464280849Scy fprintf(stderr, "***No host open, use `host' command\n"); 146554359Sroberto return -1; 146654359Sroberto } 146754359Sroberto 146854359Sroberto done = 0; 146954359Sroberto sequence++; 147054359Sroberto 147154359Sroberto again: 147254359Sroberto /* 147354359Sroberto * send a request 147454359Sroberto */ 147554359Sroberto res = sendrequest(opcode, associd, auth, qsize, qdata); 147654359Sroberto if (res != 0) 1477280849Scy return res; 1478280849Scy 147954359Sroberto /* 148054359Sroberto * Get the response. If we got a standard error, print a message 148154359Sroberto */ 148254359Sroberto res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 148354359Sroberto 148454359Sroberto if (res > 0) { 148554359Sroberto if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 148654359Sroberto if (res == ERR_INCOMPLETE) { 148754359Sroberto /* 148854359Sroberto * better bump the sequence so we don't 148954359Sroberto * get confused about differing fragments. 149054359Sroberto */ 149154359Sroberto sequence++; 149254359Sroberto } 149354359Sroberto done = 1; 149454359Sroberto goto again; 149554359Sroberto } 1496280849Scy if (!quiet) 1497280849Scy show_error_msg(res, associd); 1498280849Scy 149954359Sroberto } 150054359Sroberto return res; 150154359Sroberto} 150254359Sroberto 150354359Sroberto 1504280849Scy#ifndef BUILD_AS_LIB 150554359Sroberto/* 150654359Sroberto * getcmds - read commands from the standard input and execute them 150754359Sroberto */ 150854359Srobertostatic void 150954359Srobertogetcmds(void) 151054359Sroberto{ 1511280849Scy char * line; 1512280849Scy int count; 151354359Sroberto 1514280849Scy ntp_readline_init(interactive ? prompt : NULL); 1515106163Sroberto 1516280849Scy for (;;) { 1517280849Scy line = ntp_readline(&count); 1518280849Scy if (NULL == line) 1519280849Scy break; 1520280849Scy docmd(line); 1521280849Scy free(line); 1522280849Scy } 152354359Sroberto 1524280849Scy ntp_readline_uninit(); 152554359Sroberto} 1526280849Scy#endif /* !BUILD_AS_LIB */ 152754359Sroberto 1528280849Scy 1529280849Scy#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 153054359Sroberto/* 153154359Sroberto * abortcmd - catch interrupts and abort the current command 153254359Sroberto */ 1533293423Sdelphijstatic int 1534293423Sdelphijabortcmd(void) 153554359Sroberto{ 153654359Sroberto if (current_output == stdout) 1537293423Sdelphij (void) fflush(stdout); 153854359Sroberto putc('\n', stderr); 153954359Sroberto (void) fflush(stderr); 1540293423Sdelphij if (jump) { 1541293423Sdelphij jump = 0; 1542293423Sdelphij longjmp(interrupt_buf, 1); 1543293423Sdelphij } 1544293423Sdelphij return TRUE; 154554359Sroberto} 1546280849Scy#endif /* !SYS_WINNT && !BUILD_AS_LIB */ 154754359Sroberto 1548280849Scy 1549280849Scy#ifndef BUILD_AS_LIB 155054359Sroberto/* 155154359Sroberto * docmd - decode the command line and execute a command 155254359Sroberto */ 155354359Srobertostatic void 155454359Srobertodocmd( 155554359Sroberto const char *cmdline 155654359Sroberto ) 155754359Sroberto{ 155854359Sroberto char *tokens[1+MAXARGS+2]; 155954359Sroberto struct parse pcmd; 156054359Sroberto int ntok; 156154359Sroberto static int i; 156254359Sroberto struct xcmd *xcmd; 156354359Sroberto 156454359Sroberto /* 156554359Sroberto * Tokenize the command line. If nothing on it, return. 156654359Sroberto */ 156754359Sroberto tokenize(cmdline, tokens, &ntok); 156854359Sroberto if (ntok == 0) 156954359Sroberto return; 1570280849Scy 157154359Sroberto /* 157254359Sroberto * Find the appropriate command description. 157354359Sroberto */ 157454359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 157554359Sroberto if (i == 0) { 157654359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 157754359Sroberto tokens[0]); 157854359Sroberto return; 157954359Sroberto } else if (i >= 2) { 158054359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 158154359Sroberto tokens[0]); 158254359Sroberto return; 158354359Sroberto } 1584280849Scy 1585280849Scy /* Warn about ignored extra args */ 1586280849Scy for (i = MAXARGS + 1; i < ntok ; ++i) { 1587280849Scy fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1588280849Scy } 1589280849Scy 159054359Sroberto /* 159154359Sroberto * Save the keyword, then walk through the arguments, interpreting 159254359Sroberto * as we go. 159354359Sroberto */ 159454359Sroberto pcmd.keyword = tokens[0]; 159554359Sroberto pcmd.nargs = 0; 159654359Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 159754359Sroberto if ((i+1) >= ntok) { 159854359Sroberto if (!(xcmd->arg[i] & OPT)) { 159954359Sroberto printusage(xcmd, stderr); 160054359Sroberto return; 160154359Sroberto } 160254359Sroberto break; 160354359Sroberto } 160454359Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1605280849Scy break; 160654359Sroberto if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1607280849Scy return; 160854359Sroberto pcmd.nargs++; 160954359Sroberto } 161054359Sroberto 161154359Sroberto i++; 161254359Sroberto if (i < ntok && *tokens[i] == '>') { 161354359Sroberto char *fname; 161454359Sroberto 161554359Sroberto if (*(tokens[i]+1) != '\0') 1616280849Scy fname = tokens[i]+1; 161754359Sroberto else if ((i+1) < ntok) 1618280849Scy fname = tokens[i+1]; 161954359Sroberto else { 162054359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 162154359Sroberto return; 162254359Sroberto } 162354359Sroberto 162454359Sroberto current_output = fopen(fname, "w"); 162554359Sroberto if (current_output == NULL) { 162654359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 162754359Sroberto perror(""); 162854359Sroberto return; 162954359Sroberto } 163054359Sroberto i = 1; /* flag we need a close */ 163154359Sroberto } else { 163254359Sroberto current_output = stdout; 163354359Sroberto i = 0; /* flag no close */ 163454359Sroberto } 163554359Sroberto 163654359Sroberto if (interactive && setjmp(interrupt_buf)) { 163754359Sroberto jump = 0; 163854359Sroberto return; 163954359Sroberto } else { 164054359Sroberto jump++; 164154359Sroberto (xcmd->handler)(&pcmd, current_output); 164254359Sroberto jump = 0; /* HMS: 961106: was after fclose() */ 164354359Sroberto if (i) (void) fclose(current_output); 164454359Sroberto } 1645280849Scy 1646280849Scy return; 164754359Sroberto} 164854359Sroberto 164954359Sroberto 165054359Sroberto/* 165154359Sroberto * tokenize - turn a command line into tokens 1652280849Scy * 1653280849Scy * SK: Modified to allow a quoted string 1654280849Scy * 1655280849Scy * HMS: If the first character of the first token is a ':' then (after 1656280849Scy * eating inter-token whitespace) the 2nd token is the rest of the line. 165754359Sroberto */ 1658280849Scy 165954359Srobertostatic void 166054359Srobertotokenize( 166154359Sroberto const char *line, 166254359Sroberto char **tokens, 166354359Sroberto int *ntok 166454359Sroberto ) 166554359Sroberto{ 166654359Sroberto register const char *cp; 166754359Sroberto register char *sp; 166854359Sroberto static char tspace[MAXLINE]; 166954359Sroberto 167054359Sroberto sp = tspace; 167154359Sroberto cp = line; 167254359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 167354359Sroberto tokens[*ntok] = sp; 1674280849Scy 1675280849Scy /* Skip inter-token whitespace */ 167654359Sroberto while (ISSPACE(*cp)) 167754359Sroberto cp++; 1678280849Scy 1679280849Scy /* If we're at EOL we're done */ 168054359Sroberto if (ISEOL(*cp)) 168154359Sroberto break; 168254359Sroberto 1683280849Scy /* If this is the 2nd token and the first token begins 1684280849Scy * with a ':', then just grab to EOL. 1685280849Scy */ 1686280849Scy 1687280849Scy if (*ntok == 1 && tokens[0][0] == ':') { 1688280849Scy do { 1689280849Scy if (sp - tspace >= MAXLINE) 1690280849Scy goto toobig; 1691280849Scy *sp++ = *cp++; 1692280849Scy } while (!ISEOL(*cp)); 1693280849Scy } 1694280849Scy 1695280849Scy /* Check if this token begins with a double quote. 1696280849Scy * If yes, continue reading till the next double quote 1697280849Scy */ 1698280849Scy else if (*cp == '\"') { 1699280849Scy ++cp; 1700280849Scy do { 1701280849Scy if (sp - tspace >= MAXLINE) 1702280849Scy goto toobig; 1703280849Scy *sp++ = *cp++; 1704280849Scy } while ((*cp != '\"') && !ISEOL(*cp)); 1705280849Scy /* HMS: a missing closing " should be an error */ 1706280849Scy } 1707280849Scy else { 1708280849Scy do { 1709280849Scy if (sp - tspace >= MAXLINE) 1710280849Scy goto toobig; 1711280849Scy *sp++ = *cp++; 1712280849Scy } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1713280849Scy /* HMS: Why check for a " in the previous line? */ 1714280849Scy } 1715280849Scy 1716280849Scy if (sp - tspace >= MAXLINE) 1717280849Scy goto toobig; 171854359Sroberto *sp++ = '\0'; 171954359Sroberto } 1720280849Scy return; 1721280849Scy 1722280849Scy toobig: 1723280849Scy *ntok = 0; 1724280849Scy fprintf(stderr, 1725280849Scy "***Line `%s' is too big\n", 1726280849Scy line); 1727280849Scy return; 172854359Sroberto} 172954359Sroberto 173054359Sroberto 1731280849Scy/* 1732280849Scy * getarg - interpret an argument token 1733280849Scy */ 1734280849Scystatic int 1735280849Scygetarg( 1736280849Scy const char *str, 1737280849Scy int code, 1738280849Scy arg_v *argp 1739280849Scy ) 1740280849Scy{ 1741280849Scy u_long ul; 174254359Sroberto 1743280849Scy switch (code & ~OPT) { 1744280849Scy case NTP_STR: 1745280849Scy argp->string = str; 1746280849Scy break; 1747280849Scy 1748280849Scy case NTP_ADD: 1749280849Scy if (!getnetnum(str, &argp->netnum, NULL, 0)) 1750280849Scy return 0; 1751280849Scy break; 1752280849Scy 1753280849Scy case NTP_UINT: 1754280849Scy if ('&' == str[0]) { 1755280849Scy if (!atouint(&str[1], &ul)) { 1756280849Scy fprintf(stderr, 1757280849Scy "***Association index `%s' invalid/undecodable\n", 1758280849Scy str); 1759280849Scy return 0; 1760280849Scy } 1761280849Scy if (0 == numassoc) { 1762280849Scy dogetassoc(stdout); 1763280849Scy if (0 == numassoc) { 1764280849Scy fprintf(stderr, 1765280849Scy "***No associations found, `%s' unknown\n", 1766280849Scy str); 1767280849Scy return 0; 1768280849Scy } 1769280849Scy } 1770280849Scy ul = min(ul, numassoc); 1771280849Scy argp->uval = assoc_cache[ul - 1].assid; 1772280849Scy break; 1773280849Scy } 1774280849Scy if (!atouint(str, &argp->uval)) { 1775280849Scy fprintf(stderr, "***Illegal unsigned value %s\n", 1776280849Scy str); 1777280849Scy return 0; 1778280849Scy } 1779280849Scy break; 1780280849Scy 1781280849Scy case NTP_INT: 1782280849Scy if (!atoint(str, &argp->ival)) { 1783280849Scy fprintf(stderr, "***Illegal integer value %s\n", 1784280849Scy str); 1785280849Scy return 0; 1786280849Scy } 1787280849Scy break; 1788280849Scy 1789280849Scy case IP_VERSION: 1790280849Scy if (!strcmp("-6", str)) { 1791280849Scy argp->ival = 6; 1792280849Scy } else if (!strcmp("-4", str)) { 1793280849Scy argp->ival = 4; 1794280849Scy } else { 1795280849Scy fprintf(stderr, "***Version must be either 4 or 6\n"); 1796280849Scy return 0; 1797280849Scy } 1798280849Scy break; 1799280849Scy } 1800280849Scy 1801280849Scy return 1; 1802280849Scy} 1803280849Scy#endif /* !BUILD_AS_LIB */ 1804280849Scy 1805280849Scy 180654359Sroberto/* 180754359Sroberto * findcmd - find a command in a command description table 180854359Sroberto */ 180954359Srobertostatic int 181054359Srobertofindcmd( 1811280849Scy const char * str, 1812280849Scy struct xcmd * clist1, 1813280849Scy struct xcmd * clist2, 1814280849Scy struct xcmd ** cmd 181554359Sroberto ) 181654359Sroberto{ 1817280849Scy struct xcmd *cl; 1818293423Sdelphij size_t clen; 181954359Sroberto int nmatch; 182054359Sroberto struct xcmd *nearmatch = NULL; 182154359Sroberto struct xcmd *clist; 182254359Sroberto 182354359Sroberto clen = strlen(str); 182454359Sroberto nmatch = 0; 182554359Sroberto if (clist1 != 0) 182654359Sroberto clist = clist1; 182754359Sroberto else if (clist2 != 0) 182854359Sroberto clist = clist2; 182954359Sroberto else 183054359Sroberto return 0; 183154359Sroberto 183254359Sroberto again: 183354359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 183454359Sroberto /* do a first character check, for efficiency */ 183554359Sroberto if (*str != *(cl->keyword)) 183654359Sroberto continue; 183754359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 183854359Sroberto /* 183954359Sroberto * Could be extact match, could be approximate. 184054359Sroberto * Is exact if the length of the keyword is the 184154359Sroberto * same as the str. 184254359Sroberto */ 184354359Sroberto if (*((cl->keyword) + clen) == '\0') { 184454359Sroberto *cmd = cl; 184554359Sroberto return 1; 184654359Sroberto } 184754359Sroberto nmatch++; 184854359Sroberto nearmatch = cl; 184954359Sroberto } 185054359Sroberto } 185154359Sroberto 185254359Sroberto /* 185354359Sroberto * See if there is more to do. If so, go again. Sorry about the 185454359Sroberto * goto, too much looking at BSD sources... 185554359Sroberto */ 185654359Sroberto if (clist == clist1 && clist2 != 0) { 185754359Sroberto clist = clist2; 185854359Sroberto goto again; 185954359Sroberto } 186054359Sroberto 186154359Sroberto /* 186254359Sroberto * If we got extactly 1 near match, use it, else return number 186354359Sroberto * of matches. 186454359Sroberto */ 186554359Sroberto if (nmatch == 1) { 186654359Sroberto *cmd = nearmatch; 186754359Sroberto return 1; 186854359Sroberto } 186954359Sroberto return nmatch; 187054359Sroberto} 187154359Sroberto 187254359Sroberto 187354359Sroberto/* 187454359Sroberto * getnetnum - given a host name, return its net number 187554359Sroberto * and (optional) full name 187654359Sroberto */ 187754359Srobertoint 187854359Srobertogetnetnum( 187954359Sroberto const char *hname, 1880280849Scy sockaddr_u *num, 1881132451Sroberto char *fullhost, 1882132451Sroberto int af 188354359Sroberto ) 188454359Sroberto{ 1885132451Sroberto struct addrinfo hints, *ai = NULL; 188654359Sroberto 1887280849Scy ZERO(hints); 1888132451Sroberto hints.ai_flags = AI_CANONNAME; 1889132451Sroberto#ifdef AI_ADDRCONFIG 1890132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1891132451Sroberto#endif 1892280849Scy 1893280849Scy /* 1894280849Scy * decodenetnum only works with addresses, but handles syntax 1895280849Scy * that getaddrinfo doesn't: [2001::1]:1234 1896280849Scy */ 189754359Sroberto if (decodenetnum(hname, num)) { 1898280849Scy if (fullhost != NULL) 1899280849Scy getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1900280849Scy LENHOSTNAME, NULL, 0, 0); 190154359Sroberto return 1; 1902182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1903280849Scy INSIST(sizeof(*num) >= ai->ai_addrlen); 1904280849Scy memcpy(num, ai->ai_addr, ai->ai_addrlen); 1905280849Scy if (fullhost != NULL) { 1906280849Scy if (ai->ai_canonname != NULL) 1907280849Scy strlcpy(fullhost, ai->ai_canonname, 1908280849Scy LENHOSTNAME); 1909280849Scy else 1910280849Scy getnameinfo(&num->sa, SOCKLEN(num), 1911280849Scy fullhost, LENHOSTNAME, NULL, 1912280849Scy 0, 0); 1913280849Scy } 1914280849Scy freeaddrinfo(ai); 191554359Sroberto return 1; 191654359Sroberto } 1917280849Scy fprintf(stderr, "***Can't find host %s\n", hname); 1918280849Scy 1919280849Scy return 0; 192054359Sroberto} 192154359Sroberto 1922280849Scy 192354359Sroberto/* 192454359Sroberto * nntohost - convert network number to host name. This routine enforces 192554359Sroberto * the showhostnames setting. 192654359Sroberto */ 1927280849Scyconst char * 192854359Srobertonntohost( 1929280849Scy sockaddr_u *netnum 193054359Sroberto ) 193154359Sroberto{ 1932280849Scy return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 193354359Sroberto} 193454359Sroberto 193554359Sroberto 193654359Sroberto/* 1937280849Scy * nntohost_col - convert network number to host name in fixed width. 1938280849Scy * This routine enforces the showhostnames setting. 1939280849Scy * When displaying hostnames longer than the width, 1940280849Scy * the first part of the hostname is displayed. When 1941280849Scy * displaying numeric addresses longer than the width, 1942280849Scy * Such as IPv6 addresses, the caller decides whether 1943280849Scy * the first or last of the numeric address is used. 1944280849Scy */ 1945280849Scyconst char * 1946280849Scynntohost_col( 1947280849Scy sockaddr_u * addr, 1948280849Scy size_t width, 1949280849Scy int preserve_lowaddrbits 1950280849Scy ) 1951280849Scy{ 1952280849Scy const char * out; 1953280849Scy 1954280849Scy if (!showhostnames || SOCK_UNSPEC(addr)) { 1955280849Scy if (preserve_lowaddrbits) 1956280849Scy out = trunc_left(stoa(addr), width); 1957280849Scy else 1958280849Scy out = trunc_right(stoa(addr), width); 1959280849Scy } else if (ISREFCLOCKADR(addr)) { 1960280849Scy out = refnumtoa(addr); 1961280849Scy } else { 1962280849Scy out = trunc_right(socktohost(addr), width); 1963280849Scy } 1964280849Scy return out; 1965280849Scy} 1966280849Scy 1967280849Scy 1968280849Scy/* 1969280849Scy * nntohostp() is the same as nntohost() plus a :port suffix 1970280849Scy */ 1971280849Scyconst char * 1972280849Scynntohostp( 1973280849Scy sockaddr_u *netnum 1974280849Scy ) 1975280849Scy{ 1976280849Scy const char * hostn; 1977280849Scy char * buf; 1978280849Scy 1979280849Scy if (!showhostnames || SOCK_UNSPEC(netnum)) 1980280849Scy return sptoa(netnum); 1981280849Scy else if (ISREFCLOCKADR(netnum)) 1982280849Scy return refnumtoa(netnum); 1983280849Scy 1984280849Scy hostn = socktohost(netnum); 1985280849Scy LIB_GETBUF(buf); 1986280849Scy snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 1987280849Scy 1988280849Scy return buf; 1989280849Scy} 1990280849Scy 1991280849Scy/* 199254359Sroberto * rtdatetolfp - decode an RT-11 date into an l_fp 199354359Sroberto */ 199454359Srobertostatic int 199554359Srobertortdatetolfp( 199654359Sroberto char *str, 199754359Sroberto l_fp *lfp 199854359Sroberto ) 199954359Sroberto{ 200054359Sroberto register char *cp; 200154359Sroberto register int i; 200254359Sroberto struct calendar cal; 200354359Sroberto char buf[4]; 200454359Sroberto 200554359Sroberto cal.yearday = 0; 200654359Sroberto 200754359Sroberto /* 200854359Sroberto * An RT-11 date looks like: 200954359Sroberto * 201054359Sroberto * d[d]-Mth-y[y] hh:mm:ss 201154359Sroberto * 201254359Sroberto * (No docs, but assume 4-digit years are also legal...) 201354359Sroberto * 201454359Sroberto * d[d]-Mth-y[y[y[y]]] hh:mm:ss 201554359Sroberto */ 201654359Sroberto cp = str; 201754359Sroberto if (!isdigit((int)*cp)) { 201854359Sroberto if (*cp == '-') { 201954359Sroberto /* 202054359Sroberto * Catch special case 202154359Sroberto */ 202254359Sroberto L_CLR(lfp); 202354359Sroberto return 1; 202454359Sroberto } 202554359Sroberto return 0; 202654359Sroberto } 202754359Sroberto 2028132451Sroberto cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 202954359Sroberto if (isdigit((int)*cp)) { 2030132451Sroberto cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2031132451Sroberto cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 203254359Sroberto } 203354359Sroberto 203454359Sroberto if (*cp++ != '-') 203554359Sroberto return 0; 2036280849Scy 203754359Sroberto for (i = 0; i < 3; i++) 203854359Sroberto buf[i] = *cp++; 203954359Sroberto buf[3] = '\0'; 204054359Sroberto 204154359Sroberto for (i = 0; i < 12; i++) 204254359Sroberto if (STREQ(buf, months[i])) 204354359Sroberto break; 204454359Sroberto if (i == 12) 204554359Sroberto return 0; 2046132451Sroberto cal.month = (u_char)(i + 1); 204754359Sroberto 204854359Sroberto if (*cp++ != '-') 204954359Sroberto return 0; 2050280849Scy 205154359Sroberto if (!isdigit((int)*cp)) 205254359Sroberto return 0; 2053132451Sroberto cal.year = (u_short)(*cp++ - '0'); 205454359Sroberto if (isdigit((int)*cp)) { 2055132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2056132451Sroberto cal.year = (u_short)(*cp++ - '0'); 205754359Sroberto } 205854359Sroberto if (isdigit((int)*cp)) { 2059132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2060132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 206154359Sroberto } 206254359Sroberto if (isdigit((int)*cp)) { 2063132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2064132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 206554359Sroberto } 206654359Sroberto 206754359Sroberto /* 206854359Sroberto * Catch special case. If cal.year == 0 this is a zero timestamp. 206954359Sroberto */ 207054359Sroberto if (cal.year == 0) { 207154359Sroberto L_CLR(lfp); 207254359Sroberto return 1; 207354359Sroberto } 207454359Sroberto 207554359Sroberto if (*cp++ != ' ' || !isdigit((int)*cp)) 207654359Sroberto return 0; 2077132451Sroberto cal.hour = (u_char)(*cp++ - '0'); 207854359Sroberto if (isdigit((int)*cp)) { 2079132451Sroberto cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2080132451Sroberto cal.hour = (u_char)(cal.hour + *cp++ - '0'); 208154359Sroberto } 208254359Sroberto 208354359Sroberto if (*cp++ != ':' || !isdigit((int)*cp)) 208454359Sroberto return 0; 2085132451Sroberto cal.minute = (u_char)(*cp++ - '0'); 208654359Sroberto if (isdigit((int)*cp)) { 2087132451Sroberto cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2088132451Sroberto cal.minute = (u_char)(cal.minute + *cp++ - '0'); 208954359Sroberto } 209054359Sroberto 209154359Sroberto if (*cp++ != ':' || !isdigit((int)*cp)) 209254359Sroberto return 0; 2093132451Sroberto cal.second = (u_char)(*cp++ - '0'); 209454359Sroberto if (isdigit((int)*cp)) { 2095132451Sroberto cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2096132451Sroberto cal.second = (u_char)(cal.second + *cp++ - '0'); 209754359Sroberto } 209854359Sroberto 209954359Sroberto /* 210054359Sroberto * For RT-11, 1972 seems to be the pivot year 210154359Sroberto */ 210254359Sroberto if (cal.year < 72) 210354359Sroberto cal.year += 2000; 210454359Sroberto if (cal.year < 100) 210554359Sroberto cal.year += 1900; 210654359Sroberto 210754359Sroberto lfp->l_ui = caltontp(&cal); 210854359Sroberto lfp->l_uf = 0; 210954359Sroberto return 1; 211054359Sroberto} 211154359Sroberto 211254359Sroberto 211354359Sroberto/* 211454359Sroberto * decodets - decode a timestamp into an l_fp format number, with 211554359Sroberto * consideration of fuzzball formats. 211654359Sroberto */ 211754359Srobertoint 211854359Srobertodecodets( 211954359Sroberto char *str, 212054359Sroberto l_fp *lfp 212154359Sroberto ) 212254359Sroberto{ 2123280849Scy char *cp; 2124280849Scy char buf[30]; 2125280849Scy size_t b; 2126280849Scy 212754359Sroberto /* 212854359Sroberto * If it starts with a 0x, decode as hex. 212954359Sroberto */ 213054359Sroberto if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2131280849Scy return hextolfp(str+2, lfp); 213254359Sroberto 213354359Sroberto /* 213454359Sroberto * If it starts with a '"', try it as an RT-11 date. 213554359Sroberto */ 213654359Sroberto if (*str == '"') { 2137280849Scy cp = str + 1; 2138280849Scy b = 0; 2139280849Scy while ('"' != *cp && '\0' != *cp && 2140280849Scy b < COUNTOF(buf) - 1) 2141280849Scy buf[b++] = *cp++; 2142280849Scy buf[b] = '\0'; 214354359Sroberto return rtdatetolfp(buf, lfp); 214454359Sroberto } 214554359Sroberto 214654359Sroberto /* 214754359Sroberto * Might still be hex. Check out the first character. Talk 214854359Sroberto * about heuristics! 214954359Sroberto */ 215054359Sroberto if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2151280849Scy return hextolfp(str, lfp); 215254359Sroberto 215354359Sroberto /* 215454359Sroberto * Try it as a decimal. If this fails, try as an unquoted 215554359Sroberto * RT-11 date. This code should go away eventually. 215654359Sroberto */ 215754359Sroberto if (atolfp(str, lfp)) 2158280849Scy return 1; 2159280849Scy 216054359Sroberto return rtdatetolfp(str, lfp); 216154359Sroberto} 216254359Sroberto 216354359Sroberto 216454359Sroberto/* 216554359Sroberto * decodetime - decode a time value. It should be in milliseconds 216654359Sroberto */ 216754359Srobertoint 216854359Srobertodecodetime( 216954359Sroberto char *str, 217054359Sroberto l_fp *lfp 217154359Sroberto ) 217254359Sroberto{ 217354359Sroberto return mstolfp(str, lfp); 217454359Sroberto} 217554359Sroberto 217654359Sroberto 217754359Sroberto/* 217854359Sroberto * decodeint - decode an integer 217954359Sroberto */ 218054359Srobertoint 218154359Srobertodecodeint( 218254359Sroberto char *str, 218354359Sroberto long *val 218454359Sroberto ) 218554359Sroberto{ 218654359Sroberto if (*str == '0') { 218754359Sroberto if (*(str+1) == 'x' || *(str+1) == 'X') 2188280849Scy return hextoint(str+2, (u_long *)val); 2189280849Scy return octtoint(str, (u_long *)val); 219054359Sroberto } 219154359Sroberto return atoint(str, val); 219254359Sroberto} 219354359Sroberto 219454359Sroberto 219554359Sroberto/* 219654359Sroberto * decodeuint - decode an unsigned integer 219754359Sroberto */ 219854359Srobertoint 219954359Srobertodecodeuint( 220054359Sroberto char *str, 220154359Sroberto u_long *val 220254359Sroberto ) 220354359Sroberto{ 220454359Sroberto if (*str == '0') { 220554359Sroberto if (*(str + 1) == 'x' || *(str + 1) == 'X') 220654359Sroberto return (hextoint(str + 2, val)); 220754359Sroberto return (octtoint(str, val)); 220854359Sroberto } 220954359Sroberto return (atouint(str, val)); 221054359Sroberto} 221154359Sroberto 221254359Sroberto 221354359Sroberto/* 221454359Sroberto * decodearr - decode an array of time values 221554359Sroberto */ 221654359Srobertostatic int 221754359Srobertodecodearr( 221854359Sroberto char *str, 221954359Sroberto int *narr, 222054359Sroberto l_fp *lfparr 222154359Sroberto ) 222254359Sroberto{ 222354359Sroberto register char *cp, *bp; 222454359Sroberto register l_fp *lfp; 222554359Sroberto char buf[60]; 222654359Sroberto 222754359Sroberto lfp = lfparr; 222854359Sroberto cp = str; 222954359Sroberto *narr = 0; 223054359Sroberto 223154359Sroberto while (*narr < 8) { 223254359Sroberto while (isspace((int)*cp)) 223354359Sroberto cp++; 223454359Sroberto if (*cp == '\0') 223554359Sroberto break; 223654359Sroberto 223754359Sroberto bp = buf; 223854359Sroberto while (!isspace((int)*cp) && *cp != '\0') 223954359Sroberto *bp++ = *cp++; 224054359Sroberto *bp++ = '\0'; 224154359Sroberto 224254359Sroberto if (!decodetime(buf, lfp)) 224354359Sroberto return 0; 224454359Sroberto (*narr)++; 224554359Sroberto lfp++; 224654359Sroberto } 224754359Sroberto return 1; 224854359Sroberto} 224954359Sroberto 225054359Sroberto 225154359Sroberto/* 225254359Sroberto * Finally, the built in command handlers 225354359Sroberto */ 225454359Sroberto 225554359Sroberto/* 225654359Sroberto * help - tell about commands, or details of a particular command 225754359Sroberto */ 225854359Srobertostatic void 225954359Srobertohelp( 226054359Sroberto struct parse *pcmd, 226154359Sroberto FILE *fp 226254359Sroberto ) 226354359Sroberto{ 2264280849Scy struct xcmd *xcp = NULL; /* quiet warning */ 2265280849Scy const char *cmd; 2266182007Sroberto const char *list[100]; 2267280849Scy size_t word, words; 2268280849Scy size_t row, rows; 2269280849Scy size_t col, cols; 2270280849Scy size_t length; 227154359Sroberto 227254359Sroberto if (pcmd->nargs == 0) { 2273182007Sroberto words = 0; 2274280849Scy for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2275280849Scy if (*(xcp->keyword) != '?' && 2276280849Scy words < COUNTOF(list)) 2277280849Scy list[words++] = xcp->keyword; 227854359Sroberto } 2279280849Scy for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2280280849Scy if (words < COUNTOF(list)) 2281280849Scy list[words++] = xcp->keyword; 228254359Sroberto 2283280849Scy qsort((void *)list, words, sizeof(list[0]), helpsort); 2284182007Sroberto col = 0; 2285182007Sroberto for (word = 0; word < words; word++) { 2286280849Scy length = strlen(list[word]); 2287280849Scy col = max(col, length); 228854359Sroberto } 228954359Sroberto 2290182007Sroberto cols = SCREENWIDTH / ++col; 2291280849Scy rows = (words + cols - 1) / cols; 2292182007Sroberto 2293280849Scy fprintf(fp, "ntpq commands:\n"); 2294182007Sroberto 2295182007Sroberto for (row = 0; row < rows; row++) { 2296280849Scy for (word = row; word < words; word += rows) 2297280849Scy fprintf(fp, "%-*.*s", (int)col, 2298280849Scy (int)col - 1, list[word]); 2299280849Scy fprintf(fp, "\n"); 2300280849Scy } 230154359Sroberto } else { 230254359Sroberto cmd = pcmd->argval[0].string; 2303182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 2304182007Sroberto if (words == 0) { 2305280849Scy fprintf(stderr, 2306280849Scy "Command `%s' is unknown\n", cmd); 230754359Sroberto return; 2308182007Sroberto } else if (words >= 2) { 2309280849Scy fprintf(stderr, 2310280849Scy "Command `%s' is ambiguous\n", cmd); 231154359Sroberto return; 231254359Sroberto } 2313280849Scy fprintf(fp, "function: %s\n", xcp->comment); 231454359Sroberto printusage(xcp, fp); 231554359Sroberto } 231654359Sroberto} 231754359Sroberto 231854359Sroberto 231954359Sroberto/* 232054359Sroberto * helpsort - do hostname qsort comparisons 232154359Sroberto */ 232254359Srobertostatic int 232354359Srobertohelpsort( 232454359Sroberto const void *t1, 232554359Sroberto const void *t2 232654359Sroberto ) 232754359Sroberto{ 2328280849Scy const char * const * name1 = t1; 2329280849Scy const char * const * name2 = t2; 233054359Sroberto 233154359Sroberto return strcmp(*name1, *name2); 233254359Sroberto} 233354359Sroberto 233454359Sroberto 233554359Sroberto/* 233654359Sroberto * printusage - print usage information for a command 233754359Sroberto */ 233854359Srobertostatic void 233954359Srobertoprintusage( 234054359Sroberto struct xcmd *xcp, 234154359Sroberto FILE *fp 234254359Sroberto ) 234354359Sroberto{ 234454359Sroberto register int i; 234554359Sroberto 2346280849Scy /* XXX: Do we need to warn about extra args here too? */ 2347280849Scy 234854359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 234954359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 235054359Sroberto if (xcp->arg[i] & OPT) 235154359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 235254359Sroberto else 235354359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 235454359Sroberto } 235554359Sroberto (void) fprintf(fp, "\n"); 235654359Sroberto} 235754359Sroberto 235854359Sroberto 235954359Sroberto/* 236054359Sroberto * timeout - set time out time 236154359Sroberto */ 236254359Srobertostatic void 236354359Srobertotimeout( 236454359Sroberto struct parse *pcmd, 236554359Sroberto FILE *fp 236654359Sroberto ) 236754359Sroberto{ 236854359Sroberto int val; 236954359Sroberto 237054359Sroberto if (pcmd->nargs == 0) { 2371280849Scy val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 237254359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 237354359Sroberto } else { 237454359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 2375280849Scy tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 237654359Sroberto * 1000; 237754359Sroberto } 237854359Sroberto} 237954359Sroberto 238054359Sroberto 238154359Sroberto/* 238254359Sroberto * auth_delay - set delay for auth requests 238354359Sroberto */ 238454359Srobertostatic void 238554359Srobertoauth_delay( 238654359Sroberto struct parse *pcmd, 238754359Sroberto FILE *fp 238854359Sroberto ) 238954359Sroberto{ 239054359Sroberto int isneg; 239154359Sroberto u_long val; 239254359Sroberto 239354359Sroberto if (pcmd->nargs == 0) { 239454359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 239554359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 239654359Sroberto } else { 239754359Sroberto if (pcmd->argval[0].ival < 0) { 239854359Sroberto isneg = 1; 239954359Sroberto val = (u_long)(-pcmd->argval[0].ival); 240054359Sroberto } else { 240154359Sroberto isneg = 0; 240254359Sroberto val = (u_long)pcmd->argval[0].ival; 240354359Sroberto } 240454359Sroberto 240554359Sroberto delay_time.l_ui = val / 1000; 240654359Sroberto val %= 1000; 240754359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 240854359Sroberto 240954359Sroberto if (isneg) 241054359Sroberto L_NEG(&delay_time); 241154359Sroberto } 241254359Sroberto} 241354359Sroberto 241454359Sroberto 241554359Sroberto/* 241654359Sroberto * host - set the host we are dealing with. 241754359Sroberto */ 241854359Srobertostatic void 241954359Srobertohost( 242054359Sroberto struct parse *pcmd, 242154359Sroberto FILE *fp 242254359Sroberto ) 242354359Sroberto{ 2424132451Sroberto int i; 2425132451Sroberto 242654359Sroberto if (pcmd->nargs == 0) { 242754359Sroberto if (havehost) 2428280849Scy (void) fprintf(fp, "current host is %s\n", 2429280849Scy currenthost); 243054359Sroberto else 2431280849Scy (void) fprintf(fp, "no current host\n"); 2432132451Sroberto return; 2433132451Sroberto } 2434132451Sroberto 2435132451Sroberto i = 0; 2436132451Sroberto ai_fam_templ = ai_fam_default; 2437132451Sroberto if (pcmd->nargs == 2) { 2438132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 2439132451Sroberto ai_fam_templ = AF_INET; 2440132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 2441132451Sroberto ai_fam_templ = AF_INET6; 2442280849Scy else 2443280849Scy goto no_change; 2444132451Sroberto i = 1; 2445132451Sroberto } 2446280849Scy if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2447280849Scy fprintf(fp, "current host set to %s\n", currenthost); 244854359Sroberto } else { 2449280849Scy no_change: 245054359Sroberto if (havehost) 2451280849Scy fprintf(fp, "current host remains %s\n", 2452280849Scy currenthost); 245354359Sroberto else 2454280849Scy fprintf(fp, "still no current host\n"); 245554359Sroberto } 245654359Sroberto} 245754359Sroberto 245854359Sroberto 245954359Sroberto/* 246054359Sroberto * poll - do one (or more) polls of the host via NTP 246154359Sroberto */ 246254359Sroberto/*ARGSUSED*/ 246354359Srobertostatic void 246454359Srobertontp_poll( 246554359Sroberto struct parse *pcmd, 246654359Sroberto FILE *fp 246754359Sroberto ) 246854359Sroberto{ 246954359Sroberto (void) fprintf(fp, "poll not implemented yet\n"); 247054359Sroberto} 247154359Sroberto 247254359Sroberto 247354359Sroberto/* 2474298695Sdelphij * showdrefid2str - return a string explanation of the value of drefid 2475298695Sdelphij */ 2476298695Sdelphijstatic char * 2477298695Sdelphijshowdrefid2str(void) 2478298695Sdelphij{ 2479298695Sdelphij switch (drefid) { 2480298695Sdelphij case REFID_HASH: 2481298695Sdelphij return "hash"; 2482298695Sdelphij case REFID_IPV4: 2483298695Sdelphij return "ipv4"; 2484298695Sdelphij default: 2485298695Sdelphij return "Unknown"; 2486298695Sdelphij } 2487298695Sdelphij} 2488298695Sdelphij 2489298695Sdelphij 2490298695Sdelphij/* 2491298695Sdelphij * drefid - display/change "display hash" 2492298695Sdelphij */ 2493298695Sdelphijstatic void 2494298695Sdelphijshowdrefid( 2495298695Sdelphij struct parse *pcmd, 2496298695Sdelphij FILE *fp 2497298695Sdelphij ) 2498298695Sdelphij{ 2499298695Sdelphij if (pcmd->nargs == 0) { 2500298695Sdelphij (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2501298695Sdelphij return; 2502298695Sdelphij } else if (STREQ(pcmd->argval[0].string, "hash")) { 2503298695Sdelphij drefid = REFID_HASH; 2504298695Sdelphij } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2505298695Sdelphij drefid = REFID_IPV4; 2506298695Sdelphij } else { 2507298695Sdelphij (void) fprintf(fp, "What?\n"); 2508298695Sdelphij return; 2509298695Sdelphij } 2510298695Sdelphij (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2511298695Sdelphij} 2512298695Sdelphij 2513298695Sdelphij 2514298695Sdelphij/* 251554359Sroberto * keyid - get a keyid to use for authenticating requests 251654359Sroberto */ 251754359Srobertostatic void 251854359Srobertokeyid( 251954359Sroberto struct parse *pcmd, 252054359Sroberto FILE *fp 252154359Sroberto ) 252254359Sroberto{ 252354359Sroberto if (pcmd->nargs == 0) { 2524132451Sroberto if (info_auth_keyid == 0) 252554359Sroberto (void) fprintf(fp, "no keyid defined\n"); 252654359Sroberto else 252754359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 252854359Sroberto } else { 2529132451Sroberto /* allow zero so that keyid can be cleared. */ 2530132451Sroberto if(pcmd->argval[0].uval > NTP_MAXKEY) 2531132451Sroberto (void) fprintf(fp, "Invalid key identifier\n"); 253254359Sroberto info_auth_keyid = pcmd->argval[0].uval; 253354359Sroberto } 253454359Sroberto} 253554359Sroberto 253654359Sroberto/* 253754359Sroberto * keytype - get type of key to use for authenticating requests 253854359Sroberto */ 253954359Srobertostatic void 254054359Srobertokeytype( 254154359Sroberto struct parse *pcmd, 254254359Sroberto FILE *fp 254354359Sroberto ) 254454359Sroberto{ 2545280849Scy const char * digest_name; 2546280849Scy size_t digest_len; 2547280849Scy int key_type; 254854359Sroberto 2549280849Scy if (!pcmd->nargs) { 2550280849Scy fprintf(fp, "keytype is %s with %lu octet digests\n", 2551280849Scy keytype_name(info_auth_keytype), 2552280849Scy (u_long)info_auth_hashlen); 2553280849Scy return; 2554280849Scy } 2555280849Scy 2556280849Scy digest_name = pcmd->argval[0].string; 2557280849Scy digest_len = 0; 2558280849Scy key_type = keytype_from_text(digest_name, &digest_len); 2559280849Scy 2560280849Scy if (!key_type) { 2561285169Scy fprintf(fp, "keytype is not valid. " 2562280849Scy#ifdef OPENSSL 2563285169Scy "Type \"help keytype\" for the available digest types.\n"); 2564280849Scy#else 2565285169Scy "Only \"md5\" is available.\n"); 2566280849Scy#endif 2567280849Scy return; 2568280849Scy } 2569280849Scy 2570280849Scy info_auth_keytype = key_type; 2571280849Scy info_auth_hashlen = digest_len; 257254359Sroberto} 257354359Sroberto 257454359Sroberto 257554359Sroberto/* 257654359Sroberto * passwd - get an authentication key 257754359Sroberto */ 257854359Sroberto/*ARGSUSED*/ 257954359Srobertostatic void 258054359Srobertopasswd( 258154359Sroberto struct parse *pcmd, 258254359Sroberto FILE *fp 258354359Sroberto ) 258454359Sroberto{ 2585280849Scy const char *pass; 258654359Sroberto 2587132451Sroberto if (info_auth_keyid == 0) { 2588280849Scy info_auth_keyid = getkeyid("Keyid: "); 2589280849Scy if (info_auth_keyid == 0) { 2590280849Scy (void)fprintf(fp, "Keyid must be defined\n"); 259154359Sroberto return; 259254359Sroberto } 259354359Sroberto } 2594280849Scy if (pcmd->nargs >= 1) 2595280849Scy pass = pcmd->argval[0].string; 2596132451Sroberto else { 2597280849Scy pass = getpass_keytype(info_auth_keytype); 2598280849Scy if ('\0' == pass[0]) { 2599280849Scy fprintf(fp, "Password unchanged\n"); 2600280849Scy return; 2601280849Scy } 2602132451Sroberto } 2603280849Scy authusekey(info_auth_keyid, info_auth_keytype, 2604280849Scy (const u_char *)pass); 2605280849Scy authtrust(info_auth_keyid, 1); 260654359Sroberto} 260754359Sroberto 260854359Sroberto 260954359Sroberto/* 261054359Sroberto * hostnames - set the showhostnames flag 261154359Sroberto */ 261254359Srobertostatic void 261354359Srobertohostnames( 261454359Sroberto struct parse *pcmd, 261554359Sroberto FILE *fp 261654359Sroberto ) 261754359Sroberto{ 261854359Sroberto if (pcmd->nargs == 0) { 261954359Sroberto if (showhostnames) 262054359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 262154359Sroberto else 262254359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 262354359Sroberto } else { 262454359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 262554359Sroberto showhostnames = 1; 262654359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 262754359Sroberto showhostnames = 0; 262854359Sroberto else 262954359Sroberto (void)fprintf(stderr, "What?\n"); 263054359Sroberto } 263154359Sroberto} 263254359Sroberto 263354359Sroberto 263454359Sroberto 263554359Sroberto/* 263654359Sroberto * setdebug - set/change debugging level 263754359Sroberto */ 263854359Srobertostatic void 263954359Srobertosetdebug( 264054359Sroberto struct parse *pcmd, 264154359Sroberto FILE *fp 264254359Sroberto ) 264354359Sroberto{ 264454359Sroberto if (pcmd->nargs == 0) { 264554359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 264654359Sroberto return; 264754359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 264854359Sroberto debug = 0; 264954359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 265054359Sroberto debug++; 265154359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 265254359Sroberto debug--; 265354359Sroberto } else { 265454359Sroberto (void) fprintf(fp, "What?\n"); 265554359Sroberto return; 265654359Sroberto } 265754359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 265854359Sroberto} 265954359Sroberto 266054359Sroberto 266154359Sroberto/* 266254359Sroberto * quit - stop this nonsense 266354359Sroberto */ 266454359Sroberto/*ARGSUSED*/ 266554359Srobertostatic void 266654359Srobertoquit( 266754359Sroberto struct parse *pcmd, 266854359Sroberto FILE *fp 266954359Sroberto ) 267054359Sroberto{ 267154359Sroberto if (havehost) 267254359Sroberto closesocket(sockfd); /* cleanliness next to godliness */ 267354359Sroberto exit(0); 267454359Sroberto} 267554359Sroberto 267654359Sroberto 267754359Sroberto/* 267854359Sroberto * version - print the current version number 267954359Sroberto */ 268054359Sroberto/*ARGSUSED*/ 268154359Srobertostatic void 268254359Srobertoversion( 268354359Sroberto struct parse *pcmd, 268454359Sroberto FILE *fp 268554359Sroberto ) 268654359Sroberto{ 268754359Sroberto 268854359Sroberto (void) fprintf(fp, "%s\n", Version); 268954359Sroberto return; 269054359Sroberto} 269154359Sroberto 269254359Sroberto 269354359Sroberto/* 269454359Sroberto * raw - set raw mode output 269554359Sroberto */ 269654359Sroberto/*ARGSUSED*/ 269754359Srobertostatic void 269854359Srobertoraw( 269954359Sroberto struct parse *pcmd, 270054359Sroberto FILE *fp 270154359Sroberto ) 270254359Sroberto{ 270354359Sroberto rawmode = 1; 270454359Sroberto (void) fprintf(fp, "Output set to raw\n"); 270554359Sroberto} 270654359Sroberto 270754359Sroberto 270854359Sroberto/* 270954359Sroberto * cooked - set cooked mode output 271054359Sroberto */ 271154359Sroberto/*ARGSUSED*/ 271254359Srobertostatic void 271354359Srobertocooked( 271454359Sroberto struct parse *pcmd, 271554359Sroberto FILE *fp 271654359Sroberto ) 271754359Sroberto{ 271854359Sroberto rawmode = 0; 271954359Sroberto (void) fprintf(fp, "Output set to cooked\n"); 272054359Sroberto return; 272154359Sroberto} 272254359Sroberto 272354359Sroberto 272454359Sroberto/* 272554359Sroberto * authenticate - always authenticate requests to this host 272654359Sroberto */ 272754359Srobertostatic void 272854359Srobertoauthenticate( 272954359Sroberto struct parse *pcmd, 273054359Sroberto FILE *fp 273154359Sroberto ) 273254359Sroberto{ 273354359Sroberto if (pcmd->nargs == 0) { 273454359Sroberto if (always_auth) { 273554359Sroberto (void) fprintf(fp, 273654359Sroberto "authenticated requests being sent\n"); 273754359Sroberto } else 273854359Sroberto (void) fprintf(fp, 273954359Sroberto "unauthenticated requests being sent\n"); 274054359Sroberto } else { 274154359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) { 274254359Sroberto always_auth = 1; 274354359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 274454359Sroberto always_auth = 0; 274554359Sroberto } else 274654359Sroberto (void)fprintf(stderr, "What?\n"); 274754359Sroberto } 274854359Sroberto} 274954359Sroberto 275054359Sroberto 275154359Sroberto/* 275254359Sroberto * ntpversion - choose the NTP version to use 275354359Sroberto */ 275454359Srobertostatic void 275554359Srobertontpversion( 275654359Sroberto struct parse *pcmd, 275754359Sroberto FILE *fp 275854359Sroberto ) 275954359Sroberto{ 276054359Sroberto if (pcmd->nargs == 0) { 276154359Sroberto (void) fprintf(fp, 276254359Sroberto "NTP version being claimed is %d\n", pktversion); 276354359Sroberto } else { 276454359Sroberto if (pcmd->argval[0].uval < NTP_OLDVERSION 276554359Sroberto || pcmd->argval[0].uval > NTP_VERSION) { 276654359Sroberto (void) fprintf(stderr, "versions %d to %d, please\n", 276754359Sroberto NTP_OLDVERSION, NTP_VERSION); 276854359Sroberto } else { 276954359Sroberto pktversion = (u_char) pcmd->argval[0].uval; 277054359Sroberto } 277154359Sroberto } 277254359Sroberto} 277354359Sroberto 277454359Sroberto 2775280849Scystatic void __attribute__((__format__(__printf__, 1, 0))) 2776280849Scyvwarning(const char *fmt, va_list ap) 2777280849Scy{ 2778280849Scy int serrno = errno; 2779280849Scy (void) fprintf(stderr, "%s: ", progname); 2780280849Scy vfprintf(stderr, fmt, ap); 2781293423Sdelphij (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2782280849Scy} 2783280849Scy 278454359Sroberto/* 278554359Sroberto * warning - print a warning message 278654359Sroberto */ 2787280849Scystatic void __attribute__((__format__(__printf__, 1, 2))) 278854359Srobertowarning( 278954359Sroberto const char *fmt, 2790280849Scy ... 279154359Sroberto ) 279254359Sroberto{ 2793280849Scy va_list ap; 2794280849Scy va_start(ap, fmt); 2795280849Scy vwarning(fmt, ap); 2796280849Scy va_end(ap); 279754359Sroberto} 279854359Sroberto 279954359Sroberto 280054359Sroberto/* 280154359Sroberto * error - print a message and exit 280254359Sroberto */ 2803280849Scystatic void __attribute__((__format__(__printf__, 1, 2))) 280454359Srobertoerror( 280554359Sroberto const char *fmt, 2806280849Scy ... 280754359Sroberto ) 280854359Sroberto{ 2809280849Scy va_list ap; 2810280849Scy va_start(ap, fmt); 2811280849Scy vwarning(fmt, ap); 2812280849Scy va_end(ap); 281354359Sroberto exit(1); 281454359Sroberto} 281554359Sroberto/* 281654359Sroberto * getkeyid - prompt the user for a keyid to use 281754359Sroberto */ 281854359Srobertostatic u_long 281954359Srobertogetkeyid( 282054359Sroberto const char *keyprompt 282154359Sroberto ) 282254359Sroberto{ 2823280849Scy int c; 282454359Sroberto FILE *fi; 282554359Sroberto char pbuf[20]; 2826280849Scy size_t i; 2827280849Scy size_t ilim; 282854359Sroberto 282954359Sroberto#ifndef SYS_WINNT 283054359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 283154359Sroberto#else 2832280849Scy if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 283354359Sroberto#endif /* SYS_WINNT */ 283454359Sroberto fi = stdin; 2835280849Scy else 283654359Sroberto setbuf(fi, (char *)NULL); 283754359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 2838280849Scy for (i = 0, ilim = COUNTOF(pbuf) - 1; 2839280849Scy i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2840280849Scy ) 2841280849Scy pbuf[i++] = (char)c; 2842280849Scy pbuf[i] = '\0'; 284354359Sroberto if (fi != stdin) 2844280849Scy fclose(fi); 284554359Sroberto 284654359Sroberto return (u_long) atoi(pbuf); 284754359Sroberto} 284854359Sroberto 284954359Sroberto 285054359Sroberto/* 285154359Sroberto * atoascii - printable-ize possibly ascii data using the character 285254359Sroberto * transformations cat -v uses. 285354359Sroberto */ 285454359Srobertostatic void 285554359Srobertoatoascii( 2856280849Scy const char *in, 2857280849Scy size_t in_octets, 2858280849Scy char *out, 2859280849Scy size_t out_octets 286054359Sroberto ) 286154359Sroberto{ 2862280849Scy const u_char * pchIn; 2863280849Scy const u_char * pchInLimit; 2864280849Scy u_char * pchOut; 2865280849Scy u_char c; 286654359Sroberto 2867280849Scy pchIn = (const u_char *)in; 2868280849Scy pchInLimit = pchIn + in_octets; 2869280849Scy pchOut = (u_char *)out; 2870280849Scy 2871280849Scy if (NULL == pchIn) { 2872280849Scy if (0 < out_octets) 2873280849Scy *pchOut = '\0'; 287454359Sroberto return; 287554359Sroberto } 287654359Sroberto 2877280849Scy#define ONEOUT(c) \ 2878280849Scydo { \ 2879280849Scy if (0 == --out_octets) { \ 2880280849Scy *pchOut = '\0'; \ 2881280849Scy return; \ 2882280849Scy } \ 2883280849Scy *pchOut++ = (c); \ 2884280849Scy} while (0) 2885280849Scy 2886280849Scy for ( ; pchIn < pchInLimit; pchIn++) { 2887280849Scy c = *pchIn; 2888280849Scy if ('\0' == c) 2889280849Scy break; 2890280849Scy if (c & 0x80) { 2891280849Scy ONEOUT('M'); 2892280849Scy ONEOUT('-'); 2893280849Scy c &= 0x7f; 289454359Sroberto } 289554359Sroberto if (c < ' ') { 2896280849Scy ONEOUT('^'); 2897280849Scy ONEOUT((u_char)(c + '@')); 2898280849Scy } else if (0x7f == c) { 2899280849Scy ONEOUT('^'); 2900280849Scy ONEOUT('?'); 2901280849Scy } else 2902280849Scy ONEOUT(c); 290354359Sroberto } 2904280849Scy ONEOUT('\0'); 2905280849Scy 2906280849Scy#undef ONEOUT 290754359Sroberto} 290854359Sroberto 290954359Sroberto 291054359Sroberto/* 291154359Sroberto * makeascii - print possibly ascii data using the character 291254359Sroberto * transformations that cat -v uses. 291354359Sroberto */ 2914280849Scyvoid 291554359Srobertomakeascii( 2916293423Sdelphij size_t length, 2917280849Scy const char *data, 291854359Sroberto FILE *fp 291954359Sroberto ) 292054359Sroberto{ 2921280849Scy const u_char *data_u_char; 2922280849Scy const u_char *cp; 2923280849Scy int c; 292454359Sroberto 2925280849Scy data_u_char = (const u_char *)data; 2926280849Scy 2927280849Scy for (cp = data_u_char; cp < data_u_char + length; cp++) { 292854359Sroberto c = (int)*cp; 2929280849Scy if (c & 0x80) { 293054359Sroberto putc('M', fp); 293154359Sroberto putc('-', fp); 2932280849Scy c &= 0x7f; 293354359Sroberto } 293454359Sroberto 293554359Sroberto if (c < ' ') { 293654359Sroberto putc('^', fp); 2937280849Scy putc(c + '@', fp); 2938280849Scy } else if (0x7f == c) { 293954359Sroberto putc('^', fp); 294054359Sroberto putc('?', fp); 2941280849Scy } else 294254359Sroberto putc(c, fp); 294354359Sroberto } 294454359Sroberto} 294554359Sroberto 294654359Sroberto 294754359Sroberto/* 294854359Sroberto * asciize - same thing as makeascii except add a newline 294954359Sroberto */ 295054359Srobertovoid 295154359Srobertoasciize( 295254359Sroberto int length, 295354359Sroberto char *data, 295454359Sroberto FILE *fp 295554359Sroberto ) 295654359Sroberto{ 295754359Sroberto makeascii(length, data, fp); 295854359Sroberto putc('\n', fp); 295954359Sroberto} 296054359Sroberto 296154359Sroberto 296254359Sroberto/* 2963280849Scy * truncate string to fit clipping excess at end. 2964280849Scy * "too long" -> "too l" 2965280849Scy * Used for hostnames. 2966280849Scy */ 2967280849Scyconst char * 2968280849Scytrunc_right( 2969280849Scy const char * src, 2970280849Scy size_t width 2971280849Scy ) 2972280849Scy{ 2973280849Scy size_t sl; 2974280849Scy char * out; 2975280849Scy 2976280849Scy 2977280849Scy sl = strlen(src); 2978280849Scy if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 2979280849Scy LIB_GETBUF(out); 2980280849Scy memcpy(out, src, width); 2981280849Scy out[width] = '\0'; 2982280849Scy 2983280849Scy return out; 2984280849Scy } 2985280849Scy 2986280849Scy return src; 2987280849Scy} 2988280849Scy 2989280849Scy 2990280849Scy/* 2991280849Scy * truncate string to fit by preserving right side and using '_' to hint 2992280849Scy * "too long" -> "_long" 2993280849Scy * Used for local IPv6 addresses, where low bits differentiate. 2994280849Scy */ 2995280849Scyconst char * 2996280849Scytrunc_left( 2997280849Scy const char * src, 2998280849Scy size_t width 2999280849Scy ) 3000280849Scy{ 3001280849Scy size_t sl; 3002280849Scy char * out; 3003280849Scy 3004280849Scy 3005280849Scy sl = strlen(src); 3006280849Scy if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 3007280849Scy LIB_GETBUF(out); 3008280849Scy out[0] = '_'; 3009280849Scy memcpy(&out[1], &src[sl + 1 - width], width); 3010280849Scy 3011280849Scy return out; 3012280849Scy } 3013280849Scy 3014280849Scy return src; 3015280849Scy} 3016280849Scy 3017280849Scy 3018280849Scy/* 301954359Sroberto * Some circular buffer space 302054359Sroberto */ 302154359Sroberto#define CBLEN 80 302254359Sroberto#define NUMCB 6 302354359Sroberto 302454359Srobertochar circ_buf[NUMCB][CBLEN]; 302554359Srobertoint nextcb = 0; 302654359Sroberto 302754359Sroberto/* 302854359Sroberto * nextvar - find the next variable in the buffer 302954359Sroberto */ 303054359Srobertoint 303154359Srobertonextvar( 3032293423Sdelphij size_t *datalen, 3033280849Scy const char **datap, 303454359Sroberto char **vname, 303554359Sroberto char **vvalue 303654359Sroberto ) 303754359Sroberto{ 3038280849Scy const char *cp; 3039280849Scy const char *np; 3040280849Scy const char *cpend; 3041280849Scy size_t srclen; 3042280849Scy size_t len; 304354359Sroberto static char name[MAXVARLEN]; 304454359Sroberto static char value[MAXVALLEN]; 304554359Sroberto 304654359Sroberto cp = *datap; 304754359Sroberto cpend = cp + *datalen; 304854359Sroberto 304954359Sroberto /* 305054359Sroberto * Space past commas and white space 305154359Sroberto */ 305254359Sroberto while (cp < cpend && (*cp == ',' || isspace((int)*cp))) 3053280849Scy cp++; 3054280849Scy if (cp >= cpend) 3055280849Scy return 0; 3056280849Scy 305754359Sroberto /* 305854359Sroberto * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace 305954359Sroberto * over any white space and terminate it. 306054359Sroberto */ 3061280849Scy srclen = strcspn(cp, ",=\r\n"); 3062280849Scy srclen = min(srclen, (size_t)(cpend - cp)); 3063280849Scy len = srclen; 3064280849Scy while (len > 0 && isspace((unsigned char)cp[len - 1])) 3065280849Scy len--; 3066294554Sdelphij if (len >= sizeof(name)) 3067294554Sdelphij return 0; 3068280849Scy if (len > 0) 3069280849Scy memcpy(name, cp, len); 3070280849Scy name[len] = '\0'; 307154359Sroberto *vname = name; 3072280849Scy cp += srclen; 307354359Sroberto 307454359Sroberto /* 307554359Sroberto * Check if we hit the end of the buffer or a ','. If so we are done. 307654359Sroberto */ 3077280849Scy if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { 3078280849Scy if (cp < cpend) 3079280849Scy cp++; 308054359Sroberto *datap = cp; 3081293423Sdelphij *datalen = size2int_sat(cpend - cp); 3082280849Scy *vvalue = NULL; 308354359Sroberto return 1; 308454359Sroberto } 308554359Sroberto 308654359Sroberto /* 308754359Sroberto * So far, so good. Copy out the value 308854359Sroberto */ 308954359Sroberto cp++; /* past '=' */ 3090280849Scy while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n')) 3091280849Scy cp++; 3092280849Scy np = cp; 3093280849Scy if ('"' == *np) { 3094280849Scy do { 3095280849Scy np++; 3096280849Scy } while (np < cpend && '"' != *np); 3097280849Scy if (np < cpend && '"' == *np) 3098280849Scy np++; 3099280849Scy } else { 3100280849Scy while (np < cpend && ',' != *np && '\r' != *np) 3101280849Scy np++; 310254359Sroberto } 3103280849Scy len = np - cp; 3104280849Scy if (np > cpend || len >= sizeof(value) || 3105280849Scy (np < cpend && ',' != *np && '\r' != *np)) 3106280849Scy return 0; 3107280849Scy memcpy(value, cp, len); 310854359Sroberto /* 310954359Sroberto * Trim off any trailing whitespace 311054359Sroberto */ 3111280849Scy while (len > 0 && isspace((unsigned char)value[len - 1])) 3112280849Scy len--; 3113280849Scy value[len] = '\0'; 311454359Sroberto 311554359Sroberto /* 311654359Sroberto * Return this. All done. 311754359Sroberto */ 3118280849Scy if (np < cpend && ',' == *np) 3119280849Scy np++; 3120280849Scy *datap = np; 3121293423Sdelphij *datalen = size2int_sat(cpend - np); 312254359Sroberto *vvalue = value; 312354359Sroberto return 1; 312454359Sroberto} 312554359Sroberto 312654359Sroberto 3127280849Scyu_short 3128280849Scyvarfmt(const char * varname) 312954359Sroberto{ 3130280849Scy u_int n; 313154359Sroberto 3132280849Scy for (n = 0; n < COUNTOF(cookedvars); n++) 3133280849Scy if (!strcmp(varname, cookedvars[n].varname)) 3134280849Scy return cookedvars[n].fmt; 3135280849Scy 3136280849Scy return PADDING; 313754359Sroberto} 313854359Sroberto 313954359Sroberto 314054359Sroberto/* 314154359Sroberto * printvars - print variables returned in response packet 314254359Sroberto */ 314354359Srobertovoid 314454359Srobertoprintvars( 3145293423Sdelphij size_t length, 3146280849Scy const char *data, 314754359Sroberto int status, 314854359Sroberto int sttype, 3149280849Scy int quiet, 315054359Sroberto FILE *fp 315154359Sroberto ) 315254359Sroberto{ 315354359Sroberto if (rawmode) 3154280849Scy rawprint(sttype, length, data, status, quiet, fp); 315554359Sroberto else 3156280849Scy cookedprint(sttype, length, data, status, quiet, fp); 315754359Sroberto} 315854359Sroberto 315954359Sroberto 316054359Sroberto/* 316154359Sroberto * rawprint - do a printout of the data in raw mode 316254359Sroberto */ 316354359Srobertostatic void 316454359Srobertorawprint( 316554359Sroberto int datatype, 3166293423Sdelphij size_t length, 3167280849Scy const char *data, 316854359Sroberto int status, 3169280849Scy int quiet, 317054359Sroberto FILE *fp 317154359Sroberto ) 317254359Sroberto{ 3173280849Scy const char *cp; 3174280849Scy const char *cpend; 317554359Sroberto 317654359Sroberto /* 317754359Sroberto * Essentially print the data as is. We reformat unprintables, though. 317854359Sroberto */ 317954359Sroberto cp = data; 318054359Sroberto cpend = data + length; 318154359Sroberto 3182280849Scy if (!quiet) 3183280849Scy (void) fprintf(fp, "status=0x%04x,\n", status); 318454359Sroberto 318554359Sroberto while (cp < cpend) { 318654359Sroberto if (*cp == '\r') { 318754359Sroberto /* 318854359Sroberto * If this is a \r and the next character is a 318954359Sroberto * \n, supress this, else pretty print it. Otherwise 319054359Sroberto * just output the character. 319154359Sroberto */ 3192280849Scy if (cp == (cpend - 1) || *(cp + 1) != '\n') 319354359Sroberto makeascii(1, cp, fp); 3194280849Scy } else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp)) 319554359Sroberto putc(*cp, fp); 3196280849Scy else 319754359Sroberto makeascii(1, cp, fp); 319854359Sroberto cp++; 319954359Sroberto } 320054359Sroberto} 320154359Sroberto 320254359Sroberto 320354359Sroberto/* 320454359Sroberto * Global data used by the cooked output routines 320554359Sroberto */ 320654359Srobertoint out_chars; /* number of characters output */ 320754359Srobertoint out_linecount; /* number of characters output on this line */ 320854359Sroberto 320954359Sroberto 321054359Sroberto/* 321154359Sroberto * startoutput - get ready to do cooked output 321254359Sroberto */ 321354359Srobertostatic void 321454359Srobertostartoutput(void) 321554359Sroberto{ 321654359Sroberto out_chars = 0; 321754359Sroberto out_linecount = 0; 321854359Sroberto} 321954359Sroberto 322054359Sroberto 322154359Sroberto/* 322254359Sroberto * output - output a variable=value combination 322354359Sroberto */ 322454359Srobertostatic void 322554359Srobertooutput( 322654359Sroberto FILE *fp, 3227280849Scy const char *name, 3228280849Scy const char *value 322954359Sroberto ) 323054359Sroberto{ 3231293423Sdelphij int len; 323254359Sroberto 3233280849Scy /* strlen of "name=value" */ 3234293423Sdelphij len = size2int_sat(strlen(name) + 1 + strlen(value)); 323554359Sroberto 323654359Sroberto if (out_chars != 0) { 3237280849Scy out_chars += 2; 3238280849Scy if ((out_linecount + len + 2) > MAXOUTLINE) { 3239280849Scy fputs(",\n", fp); 324054359Sroberto out_linecount = 0; 324154359Sroberto } else { 3242280849Scy fputs(", ", fp); 3243280849Scy out_linecount += 2; 324454359Sroberto } 324554359Sroberto } 324654359Sroberto 324754359Sroberto fputs(name, fp); 324854359Sroberto putc('=', fp); 324954359Sroberto fputs(value, fp); 3250280849Scy out_chars += len; 3251280849Scy out_linecount += len; 325254359Sroberto} 325354359Sroberto 325454359Sroberto 325554359Sroberto/* 325654359Sroberto * endoutput - terminate a block of cooked output 325754359Sroberto */ 325854359Srobertostatic void 325954359Srobertoendoutput( 326054359Sroberto FILE *fp 326154359Sroberto ) 326254359Sroberto{ 326354359Sroberto if (out_chars != 0) 3264280849Scy putc('\n', fp); 326554359Sroberto} 326654359Sroberto 326754359Sroberto 326854359Sroberto/* 326954359Sroberto * outputarr - output an array of values 327054359Sroberto */ 327154359Srobertostatic void 327254359Srobertooutputarr( 327354359Sroberto FILE *fp, 327454359Sroberto char *name, 327554359Sroberto int narr, 327654359Sroberto l_fp *lfp 327754359Sroberto ) 327854359Sroberto{ 3279293423Sdelphij char *bp; 3280293423Sdelphij char *cp; 3281293423Sdelphij size_t i; 3282293423Sdelphij size_t len; 328354359Sroberto char buf[256]; 328454359Sroberto 328554359Sroberto bp = buf; 328654359Sroberto /* 328754359Sroberto * Hack to align delay and offset values 328854359Sroberto */ 328954359Sroberto for (i = (int)strlen(name); i < 11; i++) 329054359Sroberto *bp++ = ' '; 3291280849Scy 329254359Sroberto for (i = narr; i > 0; i--) { 329354359Sroberto if (i != narr) 329454359Sroberto *bp++ = ' '; 329554359Sroberto cp = lfptoms(lfp, 2); 329654359Sroberto len = strlen(cp); 329754359Sroberto if (len > 7) { 329854359Sroberto cp[7] = '\0'; 329954359Sroberto len = 7; 330054359Sroberto } 330154359Sroberto while (len < 7) { 330254359Sroberto *bp++ = ' '; 330354359Sroberto len++; 330454359Sroberto } 330554359Sroberto while (*cp != '\0') 330654359Sroberto *bp++ = *cp++; 330754359Sroberto lfp++; 330854359Sroberto } 330954359Sroberto *bp = '\0'; 331054359Sroberto output(fp, name, buf); 331154359Sroberto} 331254359Sroberto 331354359Srobertostatic char * 331454359Srobertotstflags( 331554359Sroberto u_long val 331654359Sroberto ) 331754359Sroberto{ 3318280849Scy register char *cp, *s; 3319280849Scy size_t cb; 332054359Sroberto register int i; 332154359Sroberto register const char *sep; 332254359Sroberto 332354359Sroberto sep = ""; 3324280849Scy s = cp = circ_buf[nextcb]; 332554359Sroberto if (++nextcb >= NUMCB) 3326280849Scy nextcb = 0; 3327280849Scy cb = sizeof(circ_buf[0]); 332854359Sroberto 3329280849Scy snprintf(cp, cb, "%02lx", val); 3330280849Scy cp += strlen(cp); 3331280849Scy cb -= strlen(cp); 333254359Sroberto if (!val) { 3333280849Scy strlcat(cp, " ok", cb); 3334280849Scy cp += strlen(cp); 3335280849Scy cb -= strlen(cp); 333654359Sroberto } else { 3337280849Scy if (cb) { 3338280849Scy *cp++ = ' '; 3339280849Scy cb--; 3340280849Scy } 3341280849Scy for (i = 0; i < (int)COUNTOF(tstflagnames); i++) { 334254359Sroberto if (val & 0x1) { 3343280849Scy snprintf(cp, cb, "%s%s", sep, 3344280849Scy tstflagnames[i]); 334554359Sroberto sep = ", "; 3346280849Scy cp += strlen(cp); 3347280849Scy cb -= strlen(cp); 334854359Sroberto } 334954359Sroberto val >>= 1; 335054359Sroberto } 335154359Sroberto } 3352280849Scy if (cb) 3353280849Scy *cp = '\0'; 3354280849Scy 335554359Sroberto return s; 335654359Sroberto} 335754359Sroberto 335854359Sroberto/* 335954359Sroberto * cookedprint - output variables in cooked mode 336054359Sroberto */ 336154359Srobertostatic void 336254359Srobertocookedprint( 336354359Sroberto int datatype, 3364293423Sdelphij size_t length, 3365280849Scy const char *data, 336654359Sroberto int status, 3367280849Scy int quiet, 336854359Sroberto FILE *fp 336954359Sroberto ) 337054359Sroberto{ 337154359Sroberto char *name; 337254359Sroberto char *value; 3373132451Sroberto char output_raw; 337454359Sroberto int fmt; 337554359Sroberto l_fp lfp; 3376280849Scy sockaddr_u hval; 337754359Sroberto u_long uval; 3378280849Scy int narr; 3379280849Scy size_t len; 338054359Sroberto l_fp lfparr[8]; 3381280849Scy char b[12]; 3382280849Scy char bn[2 * MAXVARLEN]; 3383280849Scy char bv[2 * MAXVALLEN]; 338454359Sroberto 3385280849Scy UNUSED_ARG(datatype); 338654359Sroberto 3387280849Scy if (!quiet) 3388280849Scy fprintf(fp, "status=%04x %s,\n", status, 3389280849Scy statustoa(datatype, status)); 339054359Sroberto 339154359Sroberto startoutput(); 339254359Sroberto while (nextvar(&length, &data, &name, &value)) { 3393280849Scy fmt = varfmt(name); 3394280849Scy output_raw = 0; 3395280849Scy switch (fmt) { 3396280849Scy 3397280849Scy case PADDING: 339854359Sroberto output_raw = '*'; 3399280849Scy break; 340054359Sroberto 3401280849Scy case TS: 3402280849Scy if (!decodets(value, &lfp)) 3403280849Scy output_raw = '?'; 3404280849Scy else 3405280849Scy output(fp, name, prettydate(&lfp)); 3406280849Scy break; 340754359Sroberto 3408280849Scy case HA: /* fallthru */ 3409280849Scy case NA: 3410280849Scy if (!decodenetnum(value, &hval)) { 3411280849Scy output_raw = '?'; 3412280849Scy } else if (fmt == HA){ 3413280849Scy output(fp, name, nntohost(&hval)); 3414280849Scy } else { 3415280849Scy output(fp, name, stoa(&hval)); 3416280849Scy } 3417280849Scy break; 341854359Sroberto 3419280849Scy case RF: 3420280849Scy if (decodenetnum(value, &hval)) { 3421280849Scy if (ISREFCLOCKADR(&hval)) 3422280849Scy output(fp, name, 3423280849Scy refnumtoa(&hval)); 342454359Sroberto else 3425280849Scy output(fp, name, stoa(&hval)); 3426280849Scy } else if (strlen(value) <= 4) { 3427280849Scy output(fp, name, value); 3428280849Scy } else { 3429280849Scy output_raw = '?'; 3430280849Scy } 3431280849Scy break; 343254359Sroberto 3433280849Scy case LP: 3434280849Scy if (!decodeuint(value, &uval) || uval > 3) { 3435280849Scy output_raw = '?'; 3436280849Scy } else { 3437280849Scy b[0] = (0x2 & uval) 3438280849Scy ? '1' 3439280849Scy : '0'; 3440280849Scy b[1] = (0x1 & uval) 3441280849Scy ? '1' 3442280849Scy : '0'; 3443280849Scy b[2] = '\0'; 3444280849Scy output(fp, name, b); 344554359Sroberto } 3446280849Scy break; 344754359Sroberto 3448280849Scy case OC: 3449280849Scy if (!decodeuint(value, &uval)) { 3450280849Scy output_raw = '?'; 3451280849Scy } else { 3452280849Scy snprintf(b, sizeof(b), "%03lo", uval); 3453280849Scy output(fp, name, b); 3454280849Scy } 3455280849Scy break; 3456280849Scy 3457280849Scy case AR: 3458280849Scy if (!decodearr(value, &narr, lfparr)) 3459280849Scy output_raw = '?'; 3460280849Scy else 3461280849Scy outputarr(fp, name, narr, lfparr); 3462280849Scy break; 3463280849Scy 3464280849Scy case FX: 3465280849Scy if (!decodeuint(value, &uval)) 3466280849Scy output_raw = '?'; 3467280849Scy else 3468280849Scy output(fp, name, tstflags(uval)); 3469280849Scy break; 3470280849Scy 3471280849Scy default: 3472280849Scy fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3473280849Scy name, value, fmt); 3474280849Scy output_raw = '?'; 3475280849Scy break; 347654359Sroberto } 3477280849Scy 347854359Sroberto if (output_raw != 0) { 3479289764Sglebius /* TALOS-CAN-0063: avoid buffer overrun */ 3480280849Scy atoascii(name, MAXVARLEN, bn, sizeof(bn)); 348154359Sroberto if (output_raw != '*') { 3482289764Sglebius atoascii(value, MAXVALLEN, 3483289764Sglebius bv, sizeof(bv) - 1); 348454359Sroberto len = strlen(bv); 348554359Sroberto bv[len] = output_raw; 348654359Sroberto bv[len+1] = '\0'; 3487289764Sglebius } else { 3488289764Sglebius atoascii(value, MAXVALLEN, 3489289764Sglebius bv, sizeof(bv)); 349054359Sroberto } 349154359Sroberto output(fp, bn, bv); 349254359Sroberto } 349354359Sroberto } 349454359Sroberto endoutput(fp); 349554359Sroberto} 349654359Sroberto 349754359Sroberto 349854359Sroberto/* 349954359Sroberto * sortassoc - sort associations in the cache into ascending order 350054359Sroberto */ 350154359Srobertovoid 350254359Srobertosortassoc(void) 350354359Sroberto{ 350454359Sroberto if (numassoc > 1) 3505280849Scy qsort(assoc_cache, (size_t)numassoc, 3506280849Scy sizeof(assoc_cache[0]), &assoccmp); 350754359Sroberto} 350854359Sroberto 350954359Sroberto 351054359Sroberto/* 351154359Sroberto * assoccmp - compare two associations 351254359Sroberto */ 351354359Srobertostatic int 351454359Srobertoassoccmp( 351554359Sroberto const void *t1, 351654359Sroberto const void *t2 351754359Sroberto ) 351854359Sroberto{ 3519280849Scy const struct association *ass1 = t1; 3520280849Scy const struct association *ass2 = t2; 352154359Sroberto 352254359Sroberto if (ass1->assid < ass2->assid) 3523280849Scy return -1; 352454359Sroberto if (ass1->assid > ass2->assid) 3525280849Scy return 1; 352654359Sroberto return 0; 352754359Sroberto} 3528280849Scy 3529280849Scy 3530280849Scy/* 3531280849Scy * grow_assoc_cache() - enlarge dynamic assoc_cache array 3532280849Scy * 3533280849Scy * The strategy is to add an assumed 4k page size at a time, leaving 3534280849Scy * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3535280849Scy */ 3536280849Scyvoid 3537280849Scygrow_assoc_cache(void) 3538280849Scy{ 3539280849Scy static size_t prior_sz; 3540280849Scy size_t new_sz; 3541280849Scy 3542280849Scy new_sz = prior_sz + 4 * 1024; 3543280849Scy if (0 == prior_sz) { 3544280849Scy new_sz -= 4 * sizeof(void *); 3545280849Scy } 3546280849Scy assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3547280849Scy prior_sz = new_sz; 3548293423Sdelphij assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3549280849Scy} 3550280849Scy 3551280849Scy 3552280849Scy/* 3553280849Scy * ntpq_custom_opt_handler - autoopts handler for -c and -p 3554280849Scy * 3555280849Scy * By default, autoopts loses the relative order of -c and -p options 3556280849Scy * on the command line. This routine replaces the default handler for 3557280849Scy * those routines and builds a list of commands to execute preserving 3558280849Scy * the order. 3559280849Scy */ 3560280849Scyvoid 3561280849Scyntpq_custom_opt_handler( 3562280849Scy tOptions *pOptions, 3563280849Scy tOptDesc *pOptDesc 356454359Sroberto ) 356554359Sroberto{ 3566280849Scy switch (pOptDesc->optValue) { 3567280849Scy 3568280849Scy default: 3569280849Scy fprintf(stderr, 3570280849Scy "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3571280849Scy pOptDesc->optValue, pOptDesc->optValue); 3572280849Scy exit(1); 3573280849Scy 3574280849Scy case 'c': 3575280849Scy ADDCMD(pOptDesc->pzLastArg); 3576280849Scy break; 3577280849Scy 3578280849Scy case 'p': 3579280849Scy ADDCMD("peers"); 3580280849Scy break; 3581280849Scy } 358254359Sroberto} 3583285169Scy/* 3584285169Scy * Obtain list of digest names 3585285169Scy */ 3586285169Scy 3587285169Scy#ifdef OPENSSL 3588285169Scy# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3589285169Scystruct hstate { 3590285169Scy char *list; 3591285169Scy const char **seen; 3592285169Scy int idx; 3593285169Scy}; 3594285169Scy#define K_PER_LINE 8 3595285169Scy#define K_NL_PFX_STR "\n " 3596285169Scy#define K_DELIM_STR ", " 3597285169Scystatic void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg ) 3598285169Scy{ 3599285169Scy size_t len, n; 3600285169Scy const char *name, *cp, **seen; 3601285169Scy struct hstate *hstate = arg; 3602310419Sdelphij EVP_MD_CTX *ctx; 3603285169Scy u_int digest_len; 3604285169Scy u_char digest[EVP_MAX_MD_SIZE]; 3605285169Scy 3606285169Scy if (!m) 3607285169Scy return; /* Ignore aliases */ 3608285169Scy 3609285169Scy name = EVP_MD_name(m); 3610285169Scy 3611285169Scy /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */ 3612285169Scy 3613285169Scy for( cp = name; *cp; cp++ ) { 3614316722Sdelphij if( islower((unsigned char)*cp) ) 3615285169Scy return; 3616285169Scy } 3617285169Scy len = (cp - name) + 1; 3618285169Scy 3619285169Scy /* There are duplicates. Discard if name has been seen. */ 3620285169Scy 3621285169Scy for (seen = hstate->seen; *seen; seen++) 3622285169Scy if (!strcmp(*seen, name)) 3623285169Scy return; 3624285169Scy n = (seen - hstate->seen) + 2; 3625289764Sglebius hstate->seen = erealloc(hstate->seen, n * sizeof(*seen)); 3626285169Scy hstate->seen[n-2] = name; 3627285169Scy hstate->seen[n-1] = NULL; 3628285169Scy 3629285169Scy /* Discard MACs that NTP won't accept. 3630285169Scy * Keep this consistent with keytype_from_text() in ssl_init.c. 3631285169Scy */ 3632285169Scy 3633310419Sdelphij ctx = EVP_MD_CTX_new(); 3634310419Sdelphij EVP_DigestInit(ctx, EVP_get_digestbyname(name)); 3635310419Sdelphij EVP_DigestFinal(ctx, digest, &digest_len); 3636310419Sdelphij EVP_MD_CTX_free(ctx); 3637285169Scy if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t))) 3638285169Scy return; 3639285169Scy 3640285169Scy if (hstate->list != NULL) 3641285169Scy len += strlen(hstate->list); 3642285169Scy len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR); 3643285169Scy 3644285169Scy if (hstate->list == NULL) { 3645289764Sglebius hstate->list = (char *)emalloc(len); 3646285169Scy hstate->list[0] = '\0'; 3647285169Scy } else 3648289764Sglebius hstate->list = (char *)erealloc(hstate->list, len); 3649285169Scy 3650285169Scy sprintf(hstate->list + strlen(hstate->list), "%s%s", 3651285169Scy ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR), 3652285169Scy name); 3653285169Scy if (hstate->idx >= K_PER_LINE) 3654285169Scy hstate->idx = 1; 3655285169Scy else 3656285169Scy hstate->idx++; 3657285169Scy} 3658285169Scy# endif 3659285169Scy#endif 3660285169Scy 3661285169Scystatic char *list_digest_names(void) 3662285169Scy{ 3663285169Scy char *list = NULL; 3664285169Scy 3665285169Scy#ifdef OPENSSL 3666285169Scy# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3667285169Scy struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 3668285169Scy 3669289764Sglebius hstate.seen = (const char **) emalloc_zero(1*sizeof( const char * )); // replaces -> calloc(1, sizeof( const char * )); 3670285169Scy 3671285169Scy INIT_SSL(); 3672285169Scy EVP_MD_do_all_sorted(list_md_fn, &hstate); 3673285169Scy list = hstate.list; 3674285169Scy free(hstate.seen); 3675285169Scy# else 3676289764Sglebius list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 3677285169Scy strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 3678285169Scy# endif 3679285169Scy#else 3680289764Sglebius list = (char *)emalloc(sizeof("md5")); 3681285169Scy strcpy(list, "md5"); 3682285169Scy#endif 3683285169Scy 3684285169Scy return list; 3685285169Scy} 3686293423Sdelphij 3687293423Sdelphij#define CTRLC_STACK_MAX 4 3688293423Sdelphijstatic volatile size_t ctrlc_stack_len = 0; 3689293423Sdelphijstatic volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 3690293423Sdelphij 3691293423Sdelphij 3692293423Sdelphij 3693293423Sdelphijint/*BOOL*/ 3694293423Sdelphijpush_ctrl_c_handler( 3695293423Sdelphij Ctrl_C_Handler func 3696293423Sdelphij ) 3697293423Sdelphij{ 3698293423Sdelphij size_t size = ctrlc_stack_len; 3699293423Sdelphij if (func && (size < CTRLC_STACK_MAX)) { 3700293423Sdelphij ctrlc_stack[size] = func; 3701293423Sdelphij ctrlc_stack_len = size + 1; 3702293423Sdelphij return TRUE; 3703293423Sdelphij } 3704293423Sdelphij return FALSE; 3705293423Sdelphij} 3706293423Sdelphij 3707293423Sdelphijint/*BOOL*/ 3708293423Sdelphijpop_ctrl_c_handler( 3709293423Sdelphij Ctrl_C_Handler func 3710293423Sdelphij ) 3711293423Sdelphij{ 3712293423Sdelphij size_t size = ctrlc_stack_len; 3713293423Sdelphij if (size) { 3714293423Sdelphij --size; 3715293423Sdelphij if (func == NULL || func == ctrlc_stack[size]) { 3716293423Sdelphij ctrlc_stack_len = size; 3717293423Sdelphij return TRUE; 3718293423Sdelphij } 3719293423Sdelphij } 3720293423Sdelphij return FALSE; 3721293423Sdelphij} 3722293423Sdelphij 3723293423Sdelphijstatic void 3724293423Sdelphijon_ctrlc(void) 3725293423Sdelphij{ 3726293423Sdelphij size_t size = ctrlc_stack_len; 3727293423Sdelphij while (size) 3728293423Sdelphij if ((*ctrlc_stack[--size])()) 3729293423Sdelphij break; 3730293423Sdelphij} 3731294554Sdelphij 3732294554Sdelphijstatic int 3733294554Sdelphijmy_easprintf( 3734294554Sdelphij char ** ppinto, 3735294554Sdelphij const char * fmt , 3736294554Sdelphij ... 3737294554Sdelphij ) 3738294554Sdelphij{ 3739294554Sdelphij va_list va; 3740294554Sdelphij int prc; 3741294554Sdelphij size_t len = 128; 3742294554Sdelphij char * buf = emalloc(len); 3743294554Sdelphij 3744294554Sdelphij again: 3745294554Sdelphij /* Note: we expect the memory allocation to fail long before the 3746294554Sdelphij * increment in buffer size actually overflows. 3747294554Sdelphij */ 3748294554Sdelphij buf = (buf) ? erealloc(buf, len) : emalloc(len); 3749294554Sdelphij 3750294554Sdelphij va_start(va, fmt); 3751294554Sdelphij prc = vsnprintf(buf, len, fmt, va); 3752294554Sdelphij va_end(va); 3753294554Sdelphij 3754294554Sdelphij if (prc < 0) { 3755294554Sdelphij /* might be very old vsnprintf. Or actually MSVC... */ 3756294554Sdelphij len += len >> 1; 3757294554Sdelphij goto again; 3758294554Sdelphij } 3759294554Sdelphij if ((size_t)prc >= len) { 3760294554Sdelphij /* at least we have the proper size now... */ 3761294554Sdelphij len = (size_t)prc + 1; 3762294554Sdelphij goto again; 3763294554Sdelphij } 3764294554Sdelphij if ((size_t)prc < (len - 32)) 3765294554Sdelphij buf = erealloc(buf, (size_t)prc + 1); 3766294554Sdelphij *ppinto = buf; 3767294554Sdelphij return prc; 3768294554Sdelphij} 3769