154359Sroberto/* 254359Sroberto * ntpq - query an NTP server using mode 6 commands 354359Sroberto */ 4290001Sglebius#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> 11290001Sglebius#ifdef HAVE_UNISTD_H 12290001Sglebius# include <unistd.h> 13290001Sglebius#endif 14290001Sglebius#ifdef HAVE_FCNTL_H 15290001Sglebius# include <fcntl.h> 16290001Sglebius#endif 17290001Sglebius#ifdef SYS_WINNT 18290001Sglebius# include <mswsock.h> 19290001Sglebius#endif 20290001Sglebius#include <isc/net.h> 21290001Sglebius#include <isc/result.h> 22182007Sroberto 2382498Sroberto#include "ntpq.h" 24290001Sglebius#include "ntp_assert.h" 25290001Sglebius#include "ntp_stdlib.h" 2682498Sroberto#include "ntp_unixtime.h" 2782498Sroberto#include "ntp_calendar.h" 2882498Sroberto#include "ntp_select.h" 29290001Sglebius#include "ntp_assert.h" 30290001Sglebius#include "lib_strbuf.h" 31290001Sglebius#include "ntp_lineedit.h" 32290001Sglebius#include "ntp_debug.h" 33290001Sglebius#ifdef OPENSSL 34290001Sglebius#include "openssl/evp.h" 35290001Sglebius#include "openssl/objects.h" 36290001Sglebius#include "openssl/err.h" 37310419Sdelphij#include "libssl_compat.h" 38290001Sglebius#endif 39290001Sglebius#include <ssl_applink.c> 4082498Sroberto 41290001Sglebius#include "ntp_libopts.h" 42293896Sglebius#include "safecast.h" 43182007Sroberto 44290001Sglebius#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 61290001Sglebius/* 62290001Sglebius * use old readvars behavior? --old-rv processing in ntpq resets 63290001Sglebius * this value based on the presence or absence of --old-rv. It is 64290001Sglebius * initialized to 1 here to maintain backward compatibility with 65290001Sglebius * libntpq clients such as ntpsnmpd, which are free to reset it as 66290001Sglebius * desired. 67290001Sglebius */ 68290001Sglebiusint old_rv = 1; 6954359Sroberto 70298770Sdelphij/* 71298770Sdelphij * How should we display the refid? 72298770Sdelphij * REFID_HASH, REFID_IPV4 73298770Sdelphij */ 74298770Sdelphijte_Refid drefid = -1; 75290001Sglebius 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 86290001Sglebiusstatic int info_auth_keytype = NID_md5; /* MD5 */ 87290001Sglebiusstatic 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 114290001Sglebius#define HA 1 /* host address */ 115290001Sglebius#define NA 2 /* network address */ 116290001Sglebius#define LP 3 /* leap (print in binary) */ 117290001Sglebius#define RF 4 /* refid (sometimes string, sometimes not) */ 118290001Sglebius#define AR 5 /* array of times */ 119290001Sglebius#define FX 6 /* test flags */ 120290001Sglebius#define TS 7 /* l_fp timestamp in hex */ 121290001Sglebius#define OC 8 /* integer, print in octal */ 12254359Sroberto#define EOV 255 /* end of table */ 12354359Sroberto 12454359Sroberto/* 125290001Sglebius * For the most part ntpq simply displays what ntpd provides in the 126290001Sglebius * mostly plain-text mode 6 responses. A few variable names are by 127290001Sglebius * default "cooked" to provide more human-friendly output. 12854359Sroberto */ 129290001Sglebiusconst var_format cookedvars[] = { 130290001Sglebius { "leap", LP }, 131290001Sglebius { "reach", OC }, 132290001Sglebius { "refid", RF }, 133290001Sglebius { "reftime", TS }, 134290001Sglebius { "clock", TS }, 135290001Sglebius { "org", TS }, 136290001Sglebius { "rec", TS }, 137290001Sglebius { "xmt", TS }, 138290001Sglebius { "flash", FX }, 139290001Sglebius { "srcadr", HA }, 140290001Sglebius { "peeradr", HA }, /* compat with others */ 141290001Sglebius { "dstadr", NA }, 142290001Sglebius { "filtdelay", AR }, 143290001Sglebius { "filtoffset", AR }, 144290001Sglebius { "filtdisp", AR }, 145290001Sglebius { "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 */ 156290001Sglebius "pkt_unsync", /* TEST3 */ 157182007Sroberto "pkt_denied", /* TEST4 */ 158182007Sroberto "pkt_auth", /* TEST5 */ 159290001Sglebius "pkt_stratum", /* TEST6 */ 160290001Sglebius "pkt_header", /* TEST7 */ 161182007Sroberto "pkt_autokey", /* TEST8 */ 162182007Sroberto "pkt_crypto", /* TEST9 */ 163182007Sroberto "peer_stratum", /* TEST10 */ 164182007Sroberto "peer_dist", /* TEST11 */ 165182007Sroberto "peer_loop", /* TEST12 */ 166290001Sglebius "peer_unreach" /* TEST13 */ 16754359Sroberto}; 16854359Sroberto 16954359Sroberto 170290001Sglebiusint ntpqmain (int, char **); 17154359Sroberto/* 17254359Sroberto * Built in command handler declarations 17354359Sroberto */ 174290001Sglebiusstatic int openhost (const char *, int); 175290001Sglebiusstatic void dump_hex_printable(const void *, size_t); 176290001Sglebiusstatic int sendpkt (void *, size_t); 177293896Sglebiusstatic int getresponse (int, int, u_short *, size_t *, const char **, int); 178293896Sglebiusstatic int sendrequest (int, associd_t, int, size_t, const char *); 179290001Sglebiusstatic char * tstflags (u_long); 180290001Sglebius#ifndef BUILD_AS_LIB 181290001Sglebiusstatic void getcmds (void); 182290001Sglebius#ifndef SYS_WINNT 183293896Sglebiusstatic int abortcmd (void); 184290001Sglebius#endif /* SYS_WINNT */ 185290001Sglebiusstatic void docmd (const char *); 186290001Sglebiusstatic void tokenize (const char *, char **, int *); 187290001Sglebiusstatic int getarg (const char *, int, arg_v *); 188290001Sglebius#endif /* BUILD_AS_LIB */ 189290001Sglebiusstatic int findcmd (const char *, struct xcmd *, 190290001Sglebius struct xcmd *, struct xcmd **); 191290001Sglebiusstatic int rtdatetolfp (char *, l_fp *); 192290001Sglebiusstatic int decodearr (char *, int *, l_fp *); 193290001Sglebiusstatic void help (struct parse *, FILE *); 194290001Sglebiusstatic int helpsort (const void *, const void *); 195290001Sglebiusstatic void printusage (struct xcmd *, FILE *); 196290001Sglebiusstatic void timeout (struct parse *, FILE *); 197290001Sglebiusstatic void auth_delay (struct parse *, FILE *); 198290001Sglebiusstatic void host (struct parse *, FILE *); 199290001Sglebiusstatic void ntp_poll (struct parse *, FILE *); 200290001Sglebiusstatic void keyid (struct parse *, FILE *); 201290001Sglebiusstatic void keytype (struct parse *, FILE *); 202290001Sglebiusstatic void passwd (struct parse *, FILE *); 203290001Sglebiusstatic void hostnames (struct parse *, FILE *); 204290001Sglebiusstatic void setdebug (struct parse *, FILE *); 205290001Sglebiusstatic void quit (struct parse *, FILE *); 206298770Sdelphijstatic void showdrefid (struct parse *, FILE *); 207290001Sglebiusstatic void version (struct parse *, FILE *); 208290001Sglebiusstatic void raw (struct parse *, FILE *); 209290001Sglebiusstatic void cooked (struct parse *, FILE *); 210290001Sglebiusstatic void authenticate (struct parse *, FILE *); 211290001Sglebiusstatic void ntpversion (struct parse *, FILE *); 212290001Sglebiusstatic void warning (const char *, ...) 213290001Sglebius __attribute__((__format__(__printf__, 1, 2))); 214290001Sglebiusstatic void error (const char *, ...) 215290001Sglebius __attribute__((__format__(__printf__, 1, 2))); 216290001Sglebiusstatic u_long getkeyid (const char *); 217290001Sglebiusstatic void atoascii (const char *, size_t, char *, size_t); 218293896Sglebiusstatic void cookedprint (int, size_t, const char *, int, int, FILE *); 219293896Sglebiusstatic void rawprint (int, size_t, const char *, int, int, FILE *); 220290001Sglebiusstatic void startoutput (void); 221290001Sglebiusstatic void output (FILE *, const char *, const char *); 222290001Sglebiusstatic void endoutput (FILE *); 223290001Sglebiusstatic void outputarr (FILE *, char *, int, l_fp *); 224290001Sglebiusstatic int assoccmp (const void *, const void *); 225293896Sglebiusstatic void on_ctrlc (void); 226290001Sglebius u_short varfmt (const char *); 227294905Sdelphijstatic int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 228290001Sglebiusvoid ntpq_custom_opt_handler (tOptions *, tOptDesc *); 229290001Sglebius 230290001Sglebius#ifdef OPENSSL 231290001Sglebius# ifdef HAVE_EVP_MD_DO_ALL_SORTED 232290001Sglebiusstatic void list_md_fn(const EVP_MD *m, const char *from, 233290001Sglebius const char *to, void *arg ); 234290001Sglebius# endif 23554359Sroberto#endif 236290001Sglebiusstatic char *list_digest_names(void); 23754359Sroberto 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" }, 260290001Sglebius { "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" }, 278298770Sdelphij { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 279298770Sdelphij { "hash|ipv4", "", "", "" }, 280298770Sdelphij "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 }, 297290001Sglebius { "key type %s", "", "", "" }, 298290001Sglebius NULL }, 29954359Sroberto { 0, 0, { NO, NO, NO, NO }, 30054359Sroberto { "", "", "", "" }, "" } 30154359Sroberto}; 30254359Sroberto 30354359Sroberto 30454359Sroberto/* 30554359Sroberto * Default values we use. 30654359Sroberto */ 307290001Sglebius#define DEFHOST "localhost" /* default host name */ 308290001Sglebius#define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 309290001Sglebius#define DEFSTIMEOUT 3 /* and 3 more for each additional */ 310290001Sglebius/* 311290001Sglebius * Requests are automatically retried once, so total timeout with no 312290001Sglebius * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 313290001Sglebius * extreme, a request eliciting 32 packets of responses each for some 314290001Sglebius * reason nearly DEFSTIMEOUT seconds after the prior in that series, 315290001Sglebius * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 316290001Sglebius * 93 seconds to fail each of two times, or 186 seconds. 317290001Sglebius * Some commands involve a series of requests, such as "peers" and 318290001Sglebius * "mrulist", so the cumulative timeouts are even longer for those. 319290001Sglebius */ 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 */ 327290001Sglebius#define MAXVALLEN 2048 /* maximum length of a variable value */ 32854359Sroberto#define MAXOUTLINE 72 /* maximum length of an output line */ 329290001Sglebius#define SCREENWIDTH 76 /* nominal screen width in columns */ 33054359Sroberto 33154359Sroberto/* 33254359Sroberto * Some variables used and manipulated locally 33354359Sroberto */ 334290001Sglebiusstruct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 335290001Sglebiusstruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 33654359Srobertol_fp delay_time; /* delay time */ 33754359Srobertochar currenthost[LENHOSTNAME]; /* current host name */ 338290001Sglebiusint currenthostisnum; /* is prior text from IP? */ 339290001Sglebiusstruct sockaddr_in hostaddr; /* host address */ 34054359Srobertoint showhostnames = 1; /* show host names by default */ 341290001Sglebiusint 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/* 365290001Sglebius * assoc_cache[] is a dynamic array which allows references to 366290001Sglebius * associations using &1 ... &N for n associations, avoiding manual 367290001Sglebius * lookup of the current association IDs for a given ntpd. It also 368290001Sglebius * caches the status word for each association, retrieved incidentally. 36954359Sroberto */ 370290001Sglebiusstruct association * assoc_cache; 371290001Sglebiusu_int assoc_cache_slots;/* count of allocated array entries */ 372290001Sglebiusu_int numassoc; /* number of cached associations */ 37354359Sroberto 37454359Sroberto/* 37554359Sroberto * For commands typed on the command line (with the -c option) 37654359Sroberto */ 37754359Srobertoint 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 385290001Sglebiusu_int numhosts; 38654359Sroberto 387290001Sglebiuschost chosts[MAXHOSTS]; 388290001Sglebius#define ADDHOST(cp) \ 389290001Sglebius do { \ 390290001Sglebius if (numhosts < MAXHOSTS) { \ 391290001Sglebius chosts[numhosts].name = (cp); \ 392290001Sglebius chosts[numhosts].fam = ai_fam_templ; \ 393290001Sglebius numhosts++; \ 394290001Sglebius } \ 395290001Sglebius } while (0) 396290001Sglebius 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 419290001Sglebiuschar const *progname; 42054359Sroberto 42154359Sroberto#ifdef NO_MAIN_ALLOWED 422290001Sglebius#ifndef BUILD_AS_LIB 42354359SrobertoCALL(ntpq,"ntpq",ntpqmain); 42454359Sroberto 42554359Srobertovoid clear_globals(void) 42654359Sroberto{ 427290001Sglebius extern int ntp_optind; 428290001Sglebius showhostnames = 0; /* don'tshow host names by default */ 429290001Sglebius ntp_optind = 0; 430290001Sglebius server_entry = NULL; /* server entry for ntp */ 431290001Sglebius havehost = 0; /* set to 1 when host open */ 432290001Sglebius numassoc = 0; /* number of cached associations */ 433290001Sglebius numcmds = 0; 434290001Sglebius numhosts = 0; 43554359Sroberto} 436290001Sglebius#endif /* !BUILD_AS_LIB */ 437290001Sglebius#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 453290001Sglebius#ifndef BUILD_AS_LIB 45454359Srobertoint 45554359Srobertontpqmain( 45654359Sroberto int argc, 45754359Sroberto char *argv[] 45854359Sroberto ) 45954359Sroberto{ 460290001Sglebius u_int ihost; 461290001Sglebius int icmd; 46254359Sroberto 463290001Sglebius 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 472290001Sglebius init_lib(); /* sets up ipv4_works, ipv6_works */ 473290001Sglebius ssl_applink(); 474290001Sglebius init_auth(); 475290001Sglebius 476290001Sglebius /* Check to see if we have IPv6. Otherwise default to IPv4 */ 477290001Sglebius if (!ipv6_works) 478290001Sglebius ai_fam_default = AF_INET; 479290001Sglebius 480290001Sglebius /* Fixup keytype's help based on available digest names */ 481290001Sglebius 482132451Sroberto { 483290001Sglebius char *list; 484294905Sdelphij char *msg; 485132451Sroberto 486290001Sglebius list = list_digest_names(); 487290001Sglebius for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) { 488290001Sglebius if (strcmp("keytype", builtins[icmd].keyword) == 0) 489290001Sglebius break; 490290001Sglebius } 491290001Sglebius 492290001Sglebius /* CID: 1295478 */ 493290001Sglebius /* This should only "trip" if "keytype" is removed from builtins */ 494290001Sglebius INSIST(icmd < sizeof(builtins)/sizeof(builtins[0])); 495290001Sglebius 496290001Sglebius#ifdef OPENSSL 497290001Sglebius builtins[icmd].desc[0] = "digest-name"; 498294905Sdelphij my_easprintf(&msg, 499294905Sdelphij "set key type to use for authenticated requests, one of:%s", 500294905Sdelphij list); 501290001Sglebius#else 502290001Sglebius builtins[icmd].desc[0] = "md5"; 503294905Sdelphij my_easprintf(&msg, 504294905Sdelphij "set key type to use for authenticated requests (%s)", 505294905Sdelphij list); 506290001Sglebius#endif 507290001Sglebius builtins[icmd].comment = msg; 508290001Sglebius free(list); 509132451Sroberto } 510132451Sroberto 51154359Sroberto progname = argv[0]; 512182007Sroberto 513182007Sroberto { 514290001Sglebius int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 515182007Sroberto argc -= optct; 516182007Sroberto argv += optct; 517182007Sroberto } 518182007Sroberto 519290001Sglebius /* 520290001Sglebius * Process options other than -c and -p, which are specially 521290001Sglebius * handled by ntpq_custom_opt_handler(). 522290001Sglebius */ 523290001Sglebius 524290001Sglebius debug = OPT_VALUE_SET_DEBUG_LEVEL; 525290001Sglebius 526290001Sglebius if (HAVE_OPT(IPV4)) 527182007Sroberto ai_fam_templ = AF_INET; 528290001Sglebius else if (HAVE_OPT(IPV6)) 529182007Sroberto ai_fam_templ = AF_INET6; 530290001Sglebius else 531182007Sroberto ai_fam_templ = ai_fam_default; 532182007Sroberto 533290001Sglebius if (HAVE_OPT(INTERACTIVE)) 534182007Sroberto interactive = 1; 535182007Sroberto 536290001Sglebius if (HAVE_OPT(NUMERIC)) 537182007Sroberto showhostnames = 0; 538182007Sroberto 539290001Sglebius if (HAVE_OPT(WIDE)) 540290001Sglebius wideremote = 1; 541182007Sroberto 542290001Sglebius old_rv = HAVE_OPT(OLD_RV); 543290001Sglebius 544298770Sdelphij drefid = OPT_VALUE_REFID; 545298770Sdelphij 546290001Sglebius if (0 == argc) { 54754359Sroberto ADDHOST(DEFHOST); 54854359Sroberto } else { 549290001Sglebius for (ihost = 0; ihost < (u_int)argc; ihost++) { 550290001Sglebius if ('-' == *argv[ihost]) { 551290001Sglebius // 552290001Sglebius // If I really cared I'd also check: 553290001Sglebius // 0 == argv[ihost][2] 554290001Sglebius // 555290001Sglebius // and there are other cases as well... 556290001Sglebius // 557290001Sglebius if ('4' == argv[ihost][1]) { 558290001Sglebius ai_fam_templ = AF_INET; 559290001Sglebius continue; 560290001Sglebius } else if ('6' == argv[ihost][1]) { 561290001Sglebius ai_fam_templ = AF_INET6; 562290001Sglebius continue; 563290001Sglebius } else { 564290001Sglebius // XXX Throw a usage error 565290001Sglebius } 566290001Sglebius } 567290001Sglebius ADDHOST(argv[ihost]); 568290001Sglebius } 56954359Sroberto } 57054359Sroberto 57154359Sroberto if (numcmds == 0 && interactive == 0 57254359Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 57354359Sroberto interactive = 1; 57454359Sroberto } 57554359Sroberto 576293896Sglebius set_ctrl_c_hook(on_ctrlc); 57754359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 57854359Sroberto if (interactive) 579293896Sglebius push_ctrl_c_handler(abortcmd); 58054359Sroberto#endif /* SYS_WINNT */ 58154359Sroberto 58254359Sroberto if (numcmds == 0) { 583290001Sglebius (void) openhost(chosts[0].name, chosts[0].fam); 58454359Sroberto getcmds(); 58554359Sroberto } else { 58654359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 587290001Sglebius if (openhost(chosts[ihost].name, chosts[ihost].fam)) 588290001Sglebius for (icmd = 0; icmd < numcmds; icmd++) 589290001Sglebius docmd(ccmds[icmd]); 59054359Sroberto } 59154359Sroberto } 59254359Sroberto#ifdef SYS_WINNT 59354359Sroberto WSACleanup(); 59454359Sroberto#endif /* SYS_WINNT */ 59554359Sroberto return 0; 59654359Sroberto} 597290001Sglebius#endif /* !BUILD_AS_LIB */ 59854359Sroberto 59954359Sroberto/* 60054359Sroberto * openhost - open a socket to a host 60154359Sroberto */ 602290001Sglebiusstatic int 60354359Srobertoopenhost( 604290001Sglebius const char *hname, 605290001Sglebius int fam 60654359Sroberto ) 60754359Sroberto{ 608290001Sglebius const char svc[] = "ntp"; 60954359Sroberto char temphost[LENHOSTNAME]; 610132451Sroberto int a_info, i; 611290001Sglebius struct addrinfo hints, *ai; 612290001Sglebius sockaddr_u addr; 613290001Sglebius 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 */ 620290001Sglebius 621132451Sroberto cp = hname; 622290001Sglebius 623290001Sglebius if (*cp == '[') { 624132451Sroberto cp++; 625290001Sglebius for (i = 0; *cp && *cp != ']'; cp++, i++) 626132451Sroberto name[i] = *cp; 627290001Sglebius if (*cp == ']') { 628290001Sglebius name[i] = '\0'; 629290001Sglebius hname = name; 630290001Sglebius } else { 631290001Sglebius return 0; 632290001Sglebius } 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 */ 642290001Sglebius ZERO(hints); 643290001Sglebius hints.ai_family = fam; 644132451Sroberto hints.ai_protocol = IPPROTO_UDP; 645132451Sroberto hints.ai_socktype = SOCK_DGRAM; 646290001Sglebius hints.ai_flags = Z_AI_NUMERICHOST; 647290001Sglebius ai = NULL; 648132451Sroberto 649290001Sglebius 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 659290001Sglebius a_info = getaddrinfo(hname, svc, &hints, &ai); 660132451Sroberto } 661290001Sglebius#ifdef AI_ADDRCONFIG 662132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 663132451Sroberto if (a_info == EAI_BADFLAGS) { 664290001Sglebius hints.ai_flags &= ~AI_ADDRCONFIG; 665290001Sglebius a_info = getaddrinfo(hname, svc, &hints, &ai); 666132451Sroberto } 667290001Sglebius#endif 668132451Sroberto if (a_info != 0) { 669290001Sglebius fprintf(stderr, "%s\n", gai_strerror(a_info)); 670132451Sroberto return 0; 671132451Sroberto } 672132451Sroberto 673290001Sglebius INSIST(ai != NULL); 674290001Sglebius ZERO(addr); 675290001Sglebius octets = min(sizeof(addr), ai->ai_addrlen); 676290001Sglebius memcpy(&addr, ai->ai_addr, octets); 677290001Sglebius 678132451Sroberto if (ai->ai_canonname == NULL) { 679290001Sglebius strlcpy(temphost, stoa(&addr), sizeof(temphost)); 680290001Sglebius currenthostisnum = TRUE; 681132451Sroberto } else { 682290001Sglebius strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 683290001Sglebius currenthostisnum = FALSE; 684132451Sroberto } 685132451Sroberto 68654359Sroberto if (debug > 2) 687290001Sglebius printf("Opening host %s (%s)\n", 688290001Sglebius temphost, 689290001Sglebius (ai->ai_family == AF_INET) 690290001Sglebius ? "AF_INET" 691290001Sglebius : (ai->ai_family == AF_INET6) 692290001Sglebius ? "AF_INET6" 693290001Sglebius : "AF-???" 694290001Sglebius ); 69554359Sroberto 69654359Sroberto if (havehost == 1) { 69754359Sroberto if (debug > 2) 698290001Sglebius printf("Closing old host %s\n", currenthost); 699290001Sglebius closesocket(sockfd); 70054359Sroberto havehost = 0; 70154359Sroberto } 702290001Sglebius strlcpy(currenthost, temphost, sizeof(currenthost)); 70354359Sroberto 704132451Sroberto /* port maps to the same location in both families */ 705290001Sglebius 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 721290001Sglebius err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 722290001Sglebius (char *)&optionValue, sizeof(optionValue)); 723290001Sglebius if (err) { 724290001Sglebius mfprintf(stderr, 725290001Sglebius "setsockopt(SO_SYNCHRONOUS_NONALERT)" 726290001Sglebius " error: %m\n"); 727290001Sglebius freeaddrinfo(ai); 72854359Sroberto exit(1); 72954359Sroberto } 73054359Sroberto } 731132451Sroberto#endif /* SYS_WINNT */ 73254359Sroberto 733290001Sglebius sockfd = socket(ai->ai_family, ai->ai_socktype, 734290001Sglebius ai->ai_protocol); 73554359Sroberto if (sockfd == INVALID_SOCKET) { 736290001Sglebius error("socket"); 737290001Sglebius freeaddrinfo(ai); 738290001Sglebius return 0; 73954359Sroberto } 74054359Sroberto 741290001Sglebius 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) 747290001Sglebius error("setsockopt"); 74854359Sroberto } 74954359Sroberto# endif 75054359Sroberto#endif 75154359Sroberto 752290001Sglebius if 753132451Sroberto#ifdef SYS_VXWORKS 754290001Sglebius (connect(sockfd, (struct sockaddr *)&hostaddr, 75554359Sroberto sizeof(hostaddr)) == -1) 756132451Sroberto#else 757290001Sglebius (connect(sockfd, (struct sockaddr *)ai->ai_addr, 758293896Sglebius ai->ai_addrlen) == -1) 759132451Sroberto#endif /* SYS_VXWORKS */ 760293896Sglebius { 761290001Sglebius error("connect"); 762132451Sroberto freeaddrinfo(ai); 763290001Sglebius return 0; 764290001Sglebius } 765290001Sglebius freeaddrinfo(ai); 76654359Sroberto havehost = 1; 767290001Sglebius numassoc = 0; 768290001Sglebius 76954359Sroberto return 1; 77054359Sroberto} 77154359Sroberto 77254359Sroberto 773290001Sglebiusstatic void 774290001Sglebiusdump_hex_printable( 775290001Sglebius const void * data, 776290001Sglebius size_t len 777290001Sglebius ) 778290001Sglebius{ 779290001Sglebius const char * cdata; 780290001Sglebius const char * rowstart; 781290001Sglebius size_t idx; 782290001Sglebius size_t rowlen; 783290001Sglebius u_char uch; 784290001Sglebius 785290001Sglebius cdata = data; 786290001Sglebius while (len > 0) { 787290001Sglebius rowstart = cdata; 788290001Sglebius rowlen = min(16, len); 789290001Sglebius for (idx = 0; idx < rowlen; idx++) { 790290001Sglebius uch = *(cdata++); 791290001Sglebius printf("%02x ", uch); 792290001Sglebius } 793290001Sglebius for ( ; idx < 16 ; idx++) 794290001Sglebius printf(" "); 795290001Sglebius cdata = rowstart; 796290001Sglebius for (idx = 0; idx < rowlen; idx++) { 797290001Sglebius uch = *(cdata++); 798290001Sglebius printf("%c", (isprint(uch)) 799290001Sglebius ? uch 800290001Sglebius : '.'); 801290001Sglebius } 802290001Sglebius printf("\n"); 803290001Sglebius len -= rowlen; 804290001Sglebius } 805290001Sglebius} 806290001Sglebius 807290001Sglebius 80854359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 80954359Sroberto/* 81054359Sroberto * sendpkt - send a packet to the remote host 81154359Sroberto */ 81254359Srobertostatic int 81354359Srobertosendpkt( 814290001Sglebius void * xdata, 815290001Sglebius size_t xdatalen 81654359Sroberto ) 81754359Sroberto{ 81854359Sroberto if (debug >= 3) 819290001Sglebius printf("Sending %zu octets\n", xdatalen); 82054359Sroberto 821293896Sglebius if (send(sockfd, xdata, xdatalen, 0) == -1) { 822290001Sglebius warning("write to %s failed", currenthost); 82354359Sroberto return -1; 82454359Sroberto } 82554359Sroberto 82654359Sroberto if (debug >= 4) { 827290001Sglebius printf("Request packet:\n"); 828290001Sglebius dump_hex_printable(xdata, xdatalen); 82954359Sroberto } 83054359Sroberto return 0; 83154359Sroberto} 83254359Sroberto 83354359Sroberto/* 83454359Sroberto * getresponse - get a (series of) response packet(s) and return the data 83554359Sroberto */ 83654359Srobertostatic int 83754359Srobertogetresponse( 83854359Sroberto int opcode, 83954359Sroberto int associd, 84054359Sroberto u_short *rstatus, 841293896Sglebius size_t *rsize, 842290001Sglebius const char **rdata, 84354359Sroberto int timeo 84454359Sroberto ) 84554359Sroberto{ 84654359Sroberto struct ntp_control rpkt; 847290001Sglebius struct sock_timeval tvo; 84854359Sroberto u_short offsets[MAXFRAGS+1]; 84954359Sroberto u_short counts[MAXFRAGS+1]; 85054359Sroberto u_short offset; 85154359Sroberto u_short count; 852290001Sglebius size_t numfrags; 853290001Sglebius size_t f; 854290001Sglebius size_t ff; 85554359Sroberto int seenlastfrag; 856290001Sglebius int shouldbesize; 85754359Sroberto fd_set fds; 85854359Sroberto int n; 859290001Sglebius int errcode; 860294905Sdelphij /* absolute timeout checks. Not 'time_t' by intention! */ 861294905Sdelphij uint32_t tobase; /* base value for timeout */ 862294905Sdelphij uint32_t tospan; /* timeout span (max delay) */ 863294905Sdelphij uint32_t todiff; /* current delay */ 86454359Sroberto 86554359Sroberto /* 86654359Sroberto * This is pretty tricky. We may get between 1 and MAXFRAG packets 86754359Sroberto * back in response to the request. We peel the data out of 86854359Sroberto * each packet and collect it in one long block. When the last 86954359Sroberto * packet in the sequence is received we'll know how much data we 87054359Sroberto * should have had. Note we use one long time out, should reconsider. 87154359Sroberto */ 87254359Sroberto *rsize = 0; 87354359Sroberto if (rstatus) 874290001Sglebius *rstatus = 0; 87554359Sroberto *rdata = (char *)pktdata; 87654359Sroberto 87754359Sroberto numfrags = 0; 87854359Sroberto seenlastfrag = 0; 87954359Sroberto 880294905Sdelphij tobase = (uint32_t)time(NULL); 881294905Sdelphij 88254359Sroberto FD_ZERO(&fds); 88354359Sroberto 884290001Sglebius /* 885290001Sglebius * Loop until we have an error or a complete response. Nearly all 886290001Sglebius * code paths to loop again use continue. 887290001Sglebius */ 888290001Sglebius for (;;) { 88954359Sroberto 890290001Sglebius if (numfrags == 0) 891290001Sglebius tvo = tvout; 892290001Sglebius else 893290001Sglebius tvo = tvsout; 894294905Sdelphij tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 89554359Sroberto 896290001Sglebius FD_SET(sockfd, &fds); 897293896Sglebius n = select(sockfd+1, &fds, NULL, NULL, &tvo); 898290001Sglebius if (n == -1) { 899294905Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 900294905Sdelphij /* Windows does not know about EINTR (until very 901294905Sdelphij * recently) and the handling of console events 902294905Sdelphij * is *very* different from POSIX/UNIX signal 903294905Sdelphij * handling anyway. 904294905Sdelphij * 905294905Sdelphij * Under non-windows targets we map EINTR as 906294905Sdelphij * 'last packet was received' and try to exit 907294905Sdelphij * the receive sequence. 908294905Sdelphij */ 909294905Sdelphij if (errno == EINTR) { 910294905Sdelphij seenlastfrag = 1; 911294905Sdelphij goto maybe_final; 912294905Sdelphij } 913294905Sdelphij#endif 914290001Sglebius warning("select fails"); 915290001Sglebius return -1; 916290001Sglebius } 917294905Sdelphij 918294905Sdelphij /* 919294905Sdelphij * Check if this is already too late. Trash the data and 920294905Sdelphij * fake a timeout if this is so. 921294905Sdelphij */ 922294905Sdelphij todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 923294905Sdelphij if ((n > 0) && (todiff > tospan)) { 924294905Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 925294905Sdelphij n = 0; /* faked timeout return from 'select()'*/ 926294905Sdelphij } 927294905Sdelphij 928290001Sglebius if (n == 0) { 929290001Sglebius /* 930290001Sglebius * Timed out. Return what we have 931290001Sglebius */ 932290001Sglebius if (numfrags == 0) { 933290001Sglebius if (timeo) 934290001Sglebius fprintf(stderr, 935290001Sglebius "%s: timed out, nothing received\n", 936290001Sglebius currenthost); 937290001Sglebius return ERR_TIMEOUT; 938290001Sglebius } 93954359Sroberto if (timeo) 940290001Sglebius fprintf(stderr, 941290001Sglebius "%s: timed out with incomplete data\n", 942290001Sglebius currenthost); 94354359Sroberto if (debug) { 944290001Sglebius fprintf(stderr, 945290001Sglebius "ERR_INCOMPLETE: Received fragments:\n"); 946290001Sglebius for (f = 0; f < numfrags; f++) 947290001Sglebius fprintf(stderr, 948290001Sglebius "%2u: %5d %5d\t%3d octets\n", 949290001Sglebius (u_int)f, offsets[f], 950290001Sglebius offsets[f] + 951290001Sglebius counts[f], 952290001Sglebius counts[f]); 953290001Sglebius fprintf(stderr, 954290001Sglebius "last fragment %sreceived\n", 955290001Sglebius (seenlastfrag) 956290001Sglebius ? "" 957290001Sglebius : "not "); 95854359Sroberto } 95954359Sroberto return ERR_INCOMPLETE; 96054359Sroberto } 96154359Sroberto 962290001Sglebius n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 963290001Sglebius if (n == -1) { 964290001Sglebius warning("read"); 965290001Sglebius return -1; 966290001Sglebius } 96754359Sroberto 968290001Sglebius if (debug >= 4) { 969290001Sglebius printf("Response packet:\n"); 970290001Sglebius dump_hex_printable(&rpkt, n); 971290001Sglebius } 97254359Sroberto 973290001Sglebius /* 974290001Sglebius * Check for format errors. Bug proofing. 975290001Sglebius */ 976290001Sglebius if (n < (int)CTL_HEADER_LEN) { 977290001Sglebius if (debug) 978290001Sglebius printf("Short (%d byte) packet received\n", n); 979290001Sglebius continue; 98054359Sroberto } 981290001Sglebius if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 982290001Sglebius || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 983290001Sglebius if (debug) 984290001Sglebius printf("Packet received with version %d\n", 985290001Sglebius PKT_VERSION(rpkt.li_vn_mode)); 986290001Sglebius continue; 987290001Sglebius } 988290001Sglebius if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 989290001Sglebius if (debug) 990290001Sglebius printf("Packet received with mode %d\n", 991290001Sglebius PKT_MODE(rpkt.li_vn_mode)); 992290001Sglebius continue; 993290001Sglebius } 994290001Sglebius if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 995290001Sglebius if (debug) 996290001Sglebius printf("Received request packet, wanted response\n"); 997290001Sglebius continue; 998290001Sglebius } 99954359Sroberto 1000290001Sglebius /* 1001290001Sglebius * Check opcode and sequence number for a match. 1002290001Sglebius * Could be old data getting to us. 1003290001Sglebius */ 1004290001Sglebius if (ntohs(rpkt.sequence) != sequence) { 1005290001Sglebius if (debug) 1006290001Sglebius printf("Received sequnce number %d, wanted %d\n", 1007290001Sglebius ntohs(rpkt.sequence), sequence); 1008290001Sglebius continue; 1009290001Sglebius } 1010290001Sglebius if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1011290001Sglebius if (debug) 1012290001Sglebius printf( 1013290001Sglebius "Received opcode %d, wanted %d (sequence number okay)\n", 1014290001Sglebius CTL_OP(rpkt.r_m_e_op), opcode); 1015290001Sglebius continue; 1016290001Sglebius } 101754359Sroberto 1018290001Sglebius /* 1019290001Sglebius * Check the error code. If non-zero, return it. 1020290001Sglebius */ 1021290001Sglebius if (CTL_ISERROR(rpkt.r_m_e_op)) { 1022290001Sglebius errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1023290001Sglebius if (CTL_ISMORE(rpkt.r_m_e_op)) 1024290001Sglebius TRACE(1, ("Error code %d received on not-final packet\n", 1025290001Sglebius errcode)); 1026290001Sglebius if (errcode == CERR_UNSPEC) 1027290001Sglebius return ERR_UNSPEC; 1028290001Sglebius return errcode; 102954359Sroberto } 103054359Sroberto 103154359Sroberto /* 1032290001Sglebius * Check the association ID to make sure it matches what 1033290001Sglebius * we sent. 103454359Sroberto */ 1035290001Sglebius if (ntohs(rpkt.associd) != associd) { 1036290001Sglebius TRACE(1, ("Association ID %d doesn't match expected %d\n", 1037290001Sglebius ntohs(rpkt.associd), associd)); 1038290001Sglebius /* 1039290001Sglebius * Hack for silly fuzzballs which, at the time of writing, 1040290001Sglebius * return an assID of sys.peer when queried for system variables. 1041290001Sglebius */ 104254359Sroberto#ifdef notdef 1043290001Sglebius continue; 104454359Sroberto#endif 1045290001Sglebius } 104654359Sroberto 1047290001Sglebius /* 1048290001Sglebius * Collect offset and count. Make sure they make sense. 1049290001Sglebius */ 1050290001Sglebius offset = ntohs(rpkt.offset); 1051290001Sglebius count = ntohs(rpkt.count); 105254359Sroberto 105354359Sroberto /* 1054290001Sglebius * validate received payload size is padded to next 32-bit 1055290001Sglebius * boundary and no smaller than claimed by rpkt.count 105654359Sroberto */ 1057290001Sglebius if (n & 0x3) { 1058290001Sglebius TRACE(1, ("Response packet not padded, size = %d\n", 1059290001Sglebius n)); 1060290001Sglebius continue; 1061290001Sglebius } 106254359Sroberto 1063290001Sglebius shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 106454359Sroberto 1065290001Sglebius if (n < shouldbesize) { 1066290001Sglebius printf("Response packet claims %u octets payload, above %ld received\n", 1067301301Sdelphij count, (long)(n - CTL_HEADER_LEN)); 1068290001Sglebius return ERR_INCOMPLETE; 1069290001Sglebius } 1070290001Sglebius 1071290001Sglebius if (debug >= 3 && shouldbesize > n) { 1072290001Sglebius u_int32 key; 1073290001Sglebius u_int32 *lpkt; 1074290001Sglebius int maclen; 1075290001Sglebius 1076290001Sglebius /* 1077290001Sglebius * Usually we ignore authentication, but for debugging purposes 1078290001Sglebius * we watch it here. 1079290001Sglebius */ 1080290001Sglebius /* round to 8 octet boundary */ 1081290001Sglebius shouldbesize = (shouldbesize + 7) & ~7; 1082290001Sglebius 1083290001Sglebius maclen = n - shouldbesize; 1084290001Sglebius if (maclen >= (int)MIN_MAC_LEN) { 1085290001Sglebius printf( 1086290001Sglebius "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1087290001Sglebius n, shouldbesize, maclen); 1088290001Sglebius lpkt = (u_int32 *)&rpkt; 1089290001Sglebius printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1090290001Sglebius (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1091290001Sglebius (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1092290001Sglebius (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1093290001Sglebius (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1094290001Sglebius (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1095290001Sglebius (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1096290001Sglebius key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1097290001Sglebius printf("Authenticated with keyid %lu\n", (u_long)key); 1098290001Sglebius if (key != 0 && key != info_auth_keyid) { 1099290001Sglebius printf("We don't know that key\n"); 110054359Sroberto } else { 1101290001Sglebius if (authdecrypt(key, (u_int32 *)&rpkt, 1102290001Sglebius n - maclen, maclen)) { 1103290001Sglebius printf("Auth okay!\n"); 1104290001Sglebius } else { 1105290001Sglebius printf("Auth failed!\n"); 1106290001Sglebius } 110754359Sroberto } 110854359Sroberto } 110954359Sroberto } 111054359Sroberto 1111290001Sglebius TRACE(2, ("Got packet, size = %d\n", n)); 1112290001Sglebius if (count > (n - CTL_HEADER_LEN)) { 1113290001Sglebius TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1114290001Sglebius count, (long)n - CTL_HEADER_LEN)); 1115290001Sglebius continue; 1116290001Sglebius } 1117290001Sglebius if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1118290001Sglebius TRACE(1, ("Received count of 0 in non-final fragment\n")); 1119290001Sglebius continue; 1120290001Sglebius } 1121290001Sglebius if (offset + count > sizeof(pktdata)) { 1122290001Sglebius TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1123290001Sglebius offset, count)); 1124290001Sglebius return ERR_TOOMUCH; 1125290001Sglebius } 1126290001Sglebius if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1127290001Sglebius TRACE(1, ("Received second last fragment packet\n")); 1128290001Sglebius continue; 1129290001Sglebius } 113054359Sroberto 1131290001Sglebius /* 1132290001Sglebius * So far, so good. Record this fragment, making sure it doesn't 1133290001Sglebius * overlap anything. 1134290001Sglebius */ 1135290001Sglebius TRACE(2, ("Packet okay\n")); 113654359Sroberto 1137290001Sglebius if (numfrags > (MAXFRAGS - 1)) { 1138290001Sglebius TRACE(2, ("Number of fragments exceeds maximum %d\n", 1139290001Sglebius MAXFRAGS - 1)); 1140290001Sglebius return ERR_TOOMUCH; 114154359Sroberto } 114254359Sroberto 1143290001Sglebius /* 1144290001Sglebius * Find the position for the fragment relative to any 1145290001Sglebius * previously received. 1146290001Sglebius */ 1147290001Sglebius for (f = 0; 1148290001Sglebius f < numfrags && offsets[f] < offset; 1149290001Sglebius f++) { 1150290001Sglebius /* empty body */ ; 1151290001Sglebius } 115254359Sroberto 1153290001Sglebius if (f < numfrags && offset == offsets[f]) { 1154290001Sglebius TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1155290001Sglebius count, offset, counts[f], offsets[f])); 1156290001Sglebius continue; 1157290001Sglebius } 115854359Sroberto 1159290001Sglebius if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1160290001Sglebius TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1161290001Sglebius offset, counts[f-1], offsets[f-1])); 1162290001Sglebius continue; 116354359Sroberto } 1164290001Sglebius 1165290001Sglebius if (f < numfrags && (offset + count) > offsets[f]) { 1166290001Sglebius TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1167290001Sglebius count, offset, offsets[f])); 1168290001Sglebius continue; 116954359Sroberto } 117054359Sroberto 1171290001Sglebius for (ff = numfrags; ff > f; ff--) { 1172290001Sglebius offsets[ff] = offsets[ff-1]; 1173290001Sglebius counts[ff] = counts[ff-1]; 1174290001Sglebius } 1175290001Sglebius offsets[f] = offset; 1176290001Sglebius counts[f] = count; 1177290001Sglebius numfrags++; 117854359Sroberto 1179290001Sglebius /* 1180290001Sglebius * Got that stuffed in right. Figure out if this was the last. 1181290001Sglebius * Record status info out of the last packet. 1182290001Sglebius */ 1183290001Sglebius if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1184290001Sglebius seenlastfrag = 1; 1185290001Sglebius if (rstatus != 0) 1186290001Sglebius *rstatus = ntohs(rpkt.status); 1187290001Sglebius } 118854359Sroberto 1189290001Sglebius /* 1190294905Sdelphij * Copy the data into the data buffer, and bump the 1191294905Sdelphij * timout base in case we need more. 1192290001Sglebius */ 1193290001Sglebius memcpy((char *)pktdata + offset, &rpkt.u, count); 1194294905Sdelphij tobase = (uint32_t)time(NULL); 1195294905Sdelphij 1196290001Sglebius /* 1197290001Sglebius * If we've seen the last fragment, look for holes in the sequence. 1198290001Sglebius * If there aren't any, we're done. 1199290001Sglebius */ 1200301301Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 1201301301Sdelphij maybe_final: 1202301301Sdelphij#endif 1203301301Sdelphij 1204290001Sglebius if (seenlastfrag && offsets[0] == 0) { 1205290001Sglebius for (f = 1; f < numfrags; f++) 1206290001Sglebius if (offsets[f-1] + counts[f-1] != 1207290001Sglebius offsets[f]) 1208290001Sglebius break; 1209290001Sglebius if (f == numfrags) { 1210290001Sglebius *rsize = offsets[f-1] + counts[f-1]; 1211290001Sglebius TRACE(1, ("%lu packets reassembled into response\n", 1212290001Sglebius (u_long)numfrags)); 1213290001Sglebius return 0; 1214290001Sglebius } 1215290001Sglebius } 1216290001Sglebius } /* giant for (;;) collecting response packets */ 1217290001Sglebius} /* getresponse() */ 1218290001Sglebius 1219290001Sglebius 122054359Sroberto/* 122154359Sroberto * sendrequest - format and send a request packet 122254359Sroberto */ 122354359Srobertostatic int 122454359Srobertosendrequest( 122554359Sroberto int opcode, 1226290001Sglebius associd_t associd, 122754359Sroberto int auth, 1228293896Sglebius size_t qsize, 1229290001Sglebius const char *qdata 123054359Sroberto ) 123154359Sroberto{ 123254359Sroberto struct ntp_control qpkt; 1233293896Sglebius size_t pktsize; 1234290001Sglebius u_long key_id; 1235290001Sglebius char * pass; 1236293896Sglebius size_t maclen; 123754359Sroberto 123854359Sroberto /* 123954359Sroberto * Check to make sure the data will fit in one packet 124054359Sroberto */ 124154359Sroberto if (qsize > CTL_MAX_DATA_LEN) { 1242290001Sglebius fprintf(stderr, 1243293896Sglebius "***Internal error! qsize (%zu) too large\n", 1244290001Sglebius qsize); 124554359Sroberto return 1; 124654359Sroberto } 124754359Sroberto 124854359Sroberto /* 124954359Sroberto * Fill in the packet 125054359Sroberto */ 125154359Sroberto qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1252132451Sroberto qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 125354359Sroberto qpkt.sequence = htons(sequence); 125454359Sroberto qpkt.status = 0; 125554359Sroberto qpkt.associd = htons((u_short)associd); 125654359Sroberto qpkt.offset = 0; 125754359Sroberto qpkt.count = htons((u_short)qsize); 125854359Sroberto 1259290001Sglebius pktsize = CTL_HEADER_LEN; 1260290001Sglebius 126154359Sroberto /* 1262290001Sglebius * If we have data, copy and pad it out to a 32-bit boundary. 126354359Sroberto */ 126454359Sroberto if (qsize > 0) { 1265290001Sglebius memcpy(&qpkt.u, qdata, (size_t)qsize); 1266290001Sglebius pktsize += qsize; 1267290001Sglebius while (pktsize & (sizeof(u_int32) - 1)) { 1268290001Sglebius qpkt.u.data[qsize++] = 0; 126954359Sroberto pktsize++; 127054359Sroberto } 127154359Sroberto } 127254359Sroberto 127354359Sroberto /* 127454359Sroberto * If it isn't authenticated we can just send it. Otherwise 127554359Sroberto * we're going to have to think about it a little. 127654359Sroberto */ 127754359Sroberto if (!auth && !always_auth) { 1278290001Sglebius return sendpkt(&qpkt, pktsize); 1279290001Sglebius } 128054359Sroberto 1281290001Sglebius /* 1282290001Sglebius * Pad out packet to a multiple of 8 octets to be sure 1283290001Sglebius * receiver can handle it. 1284290001Sglebius */ 1285290001Sglebius while (pktsize & 7) { 1286290001Sglebius qpkt.u.data[qsize++] = 0; 1287290001Sglebius pktsize++; 1288290001Sglebius } 128954359Sroberto 1290290001Sglebius /* 1291290001Sglebius * Get the keyid and the password if we don't have one. 1292290001Sglebius */ 1293290001Sglebius if (info_auth_keyid == 0) { 1294290001Sglebius key_id = getkeyid("Keyid: "); 1295290001Sglebius if (key_id == 0 || key_id > NTP_MAXKEY) { 1296290001Sglebius fprintf(stderr, 1297290001Sglebius "Invalid key identifier\n"); 1298290001Sglebius return 1; 129954359Sroberto } 1300290001Sglebius info_auth_keyid = key_id; 1301290001Sglebius } 1302290001Sglebius if (!authistrusted(info_auth_keyid)) { 1303290001Sglebius pass = getpass_keytype(info_auth_keytype); 1304290001Sglebius if ('\0' == pass[0]) { 1305290001Sglebius fprintf(stderr, "Invalid password\n"); 1306290001Sglebius return 1; 130754359Sroberto } 1308290001Sglebius authusekey(info_auth_keyid, info_auth_keytype, 1309290001Sglebius (u_char *)pass); 131054359Sroberto authtrust(info_auth_keyid, 1); 1311290001Sglebius } 131254359Sroberto 1313290001Sglebius /* 1314290001Sglebius * Do the encryption. 1315290001Sglebius */ 1316290001Sglebius maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1317290001Sglebius if (!maclen) { 1318290001Sglebius fprintf(stderr, "Key not found\n"); 1319290001Sglebius return 1; 1320290001Sglebius } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1321290001Sglebius fprintf(stderr, 1322293896Sglebius "%zu octet MAC, %zu expected with %zu octet digest\n", 1323290001Sglebius maclen, (info_auth_hashlen + sizeof(keyid_t)), 1324290001Sglebius info_auth_hashlen); 1325290001Sglebius return 1; 132654359Sroberto } 1327290001Sglebius 1328290001Sglebius return sendpkt((char *)&qpkt, pktsize + maclen); 132954359Sroberto} 133054359Sroberto 133154359Sroberto 133254359Sroberto/* 1333290001Sglebius * show_error_msg - display the error text for a mode 6 error response. 133454359Sroberto */ 1335290001Sglebiusvoid 1336290001Sglebiusshow_error_msg( 1337290001Sglebius int m6resp, 1338290001Sglebius associd_t associd 1339290001Sglebius ) 1340290001Sglebius{ 1341290001Sglebius if (numhosts > 1) 1342290001Sglebius fprintf(stderr, "server=%s ", currenthost); 1343290001Sglebius 1344298770Sdelphij switch (m6resp) { 1345290001Sglebius 1346290001Sglebius case CERR_BADFMT: 1347290001Sglebius fprintf(stderr, 1348290001Sglebius "***Server reports a bad format request packet\n"); 1349290001Sglebius break; 1350290001Sglebius 1351290001Sglebius case CERR_PERMISSION: 1352290001Sglebius fprintf(stderr, 1353290001Sglebius "***Server disallowed request (authentication?)\n"); 1354290001Sglebius break; 1355290001Sglebius 1356290001Sglebius case CERR_BADOP: 1357290001Sglebius fprintf(stderr, 1358290001Sglebius "***Server reports a bad opcode in request\n"); 1359290001Sglebius break; 1360290001Sglebius 1361290001Sglebius case CERR_BADASSOC: 1362290001Sglebius fprintf(stderr, 1363290001Sglebius "***Association ID %d unknown to server\n", 1364290001Sglebius associd); 1365290001Sglebius break; 1366290001Sglebius 1367290001Sglebius case CERR_UNKNOWNVAR: 1368290001Sglebius fprintf(stderr, 1369290001Sglebius "***A request variable unknown to the server\n"); 1370290001Sglebius break; 1371290001Sglebius 1372290001Sglebius case CERR_BADVALUE: 1373290001Sglebius fprintf(stderr, 1374290001Sglebius "***Server indicates a request variable was bad\n"); 1375290001Sglebius break; 1376290001Sglebius 1377290001Sglebius case ERR_UNSPEC: 1378290001Sglebius fprintf(stderr, 1379290001Sglebius "***Server returned an unspecified error\n"); 1380290001Sglebius break; 1381290001Sglebius 1382290001Sglebius case ERR_TIMEOUT: 1383290001Sglebius fprintf(stderr, "***Request timed out\n"); 1384290001Sglebius break; 1385290001Sglebius 1386290001Sglebius case ERR_INCOMPLETE: 1387290001Sglebius fprintf(stderr, 1388290001Sglebius "***Response from server was incomplete\n"); 1389290001Sglebius break; 1390290001Sglebius 1391290001Sglebius case ERR_TOOMUCH: 1392290001Sglebius fprintf(stderr, 1393290001Sglebius "***Buffer size exceeded for returned data\n"); 1394290001Sglebius break; 1395290001Sglebius 1396290001Sglebius default: 1397290001Sglebius fprintf(stderr, 1398290001Sglebius "***Server returns unknown error code %d\n", 1399290001Sglebius m6resp); 1400290001Sglebius } 1401290001Sglebius} 1402290001Sglebius 1403290001Sglebius/* 1404290001Sglebius * doquery - send a request and process the response, displaying 1405290001Sglebius * error messages for any error responses. 1406290001Sglebius */ 140754359Srobertoint 140854359Srobertodoquery( 140954359Sroberto int opcode, 1410290001Sglebius associd_t associd, 141154359Sroberto int auth, 1412293896Sglebius size_t qsize, 1413290001Sglebius const char *qdata, 141454359Sroberto u_short *rstatus, 1415293896Sglebius size_t *rsize, 1416290001Sglebius const char **rdata 141754359Sroberto ) 141854359Sroberto{ 1419290001Sglebius return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1420290001Sglebius rsize, rdata, FALSE); 1421290001Sglebius} 1422290001Sglebius 1423290001Sglebius 1424290001Sglebius/* 1425290001Sglebius * doqueryex - send a request and process the response, optionally 1426290001Sglebius * displaying error messages for any error responses. 1427290001Sglebius */ 1428290001Sglebiusint 1429290001Sglebiusdoqueryex( 1430290001Sglebius int opcode, 1431290001Sglebius associd_t associd, 1432290001Sglebius int auth, 1433293896Sglebius size_t qsize, 1434290001Sglebius const char *qdata, 1435290001Sglebius u_short *rstatus, 1436293896Sglebius size_t *rsize, 1437290001Sglebius const char **rdata, 1438290001Sglebius int quiet 1439290001Sglebius ) 1440290001Sglebius{ 144154359Sroberto int res; 144254359Sroberto int done; 144354359Sroberto 144454359Sroberto /* 144554359Sroberto * Check to make sure host is open 144654359Sroberto */ 144754359Sroberto if (!havehost) { 1448290001Sglebius fprintf(stderr, "***No host open, use `host' command\n"); 144954359Sroberto return -1; 145054359Sroberto } 145154359Sroberto 145254359Sroberto done = 0; 145354359Sroberto sequence++; 145454359Sroberto 145554359Sroberto again: 145654359Sroberto /* 145754359Sroberto * send a request 145854359Sroberto */ 145954359Sroberto res = sendrequest(opcode, associd, auth, qsize, qdata); 146054359Sroberto if (res != 0) 1461290001Sglebius return res; 1462290001Sglebius 146354359Sroberto /* 146454359Sroberto * Get the response. If we got a standard error, print a message 146554359Sroberto */ 146654359Sroberto res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 146754359Sroberto 146854359Sroberto if (res > 0) { 146954359Sroberto if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 147054359Sroberto if (res == ERR_INCOMPLETE) { 147154359Sroberto /* 147254359Sroberto * better bump the sequence so we don't 147354359Sroberto * get confused about differing fragments. 147454359Sroberto */ 147554359Sroberto sequence++; 147654359Sroberto } 147754359Sroberto done = 1; 147854359Sroberto goto again; 147954359Sroberto } 1480290001Sglebius if (!quiet) 1481290001Sglebius show_error_msg(res, associd); 1482290001Sglebius 148354359Sroberto } 148454359Sroberto return res; 148554359Sroberto} 148654359Sroberto 148754359Sroberto 1488290001Sglebius#ifndef BUILD_AS_LIB 148954359Sroberto/* 149054359Sroberto * getcmds - read commands from the standard input and execute them 149154359Sroberto */ 149254359Srobertostatic void 149354359Srobertogetcmds(void) 149454359Sroberto{ 1495290001Sglebius char * line; 1496290001Sglebius int count; 149754359Sroberto 1498290001Sglebius ntp_readline_init(interactive ? prompt : NULL); 1499106163Sroberto 1500290001Sglebius for (;;) { 1501290001Sglebius line = ntp_readline(&count); 1502290001Sglebius if (NULL == line) 1503290001Sglebius break; 1504290001Sglebius docmd(line); 1505290001Sglebius free(line); 1506290001Sglebius } 150754359Sroberto 1508290001Sglebius ntp_readline_uninit(); 150954359Sroberto} 1510290001Sglebius#endif /* !BUILD_AS_LIB */ 151154359Sroberto 1512290001Sglebius 1513290001Sglebius#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 151454359Sroberto/* 151554359Sroberto * abortcmd - catch interrupts and abort the current command 151654359Sroberto */ 1517293896Sglebiusstatic int 1518293896Sglebiusabortcmd(void) 151954359Sroberto{ 152054359Sroberto if (current_output == stdout) 1521293896Sglebius (void) fflush(stdout); 152254359Sroberto putc('\n', stderr); 152354359Sroberto (void) fflush(stderr); 1524293896Sglebius if (jump) { 1525293896Sglebius jump = 0; 1526293896Sglebius longjmp(interrupt_buf, 1); 1527293896Sglebius } 1528293896Sglebius return TRUE; 152954359Sroberto} 1530290001Sglebius#endif /* !SYS_WINNT && !BUILD_AS_LIB */ 153154359Sroberto 1532290001Sglebius 1533290001Sglebius#ifndef BUILD_AS_LIB 153454359Sroberto/* 153554359Sroberto * docmd - decode the command line and execute a command 153654359Sroberto */ 153754359Srobertostatic void 153854359Srobertodocmd( 153954359Sroberto const char *cmdline 154054359Sroberto ) 154154359Sroberto{ 154254359Sroberto char *tokens[1+MAXARGS+2]; 154354359Sroberto struct parse pcmd; 154454359Sroberto int ntok; 154554359Sroberto static int i; 154654359Sroberto struct xcmd *xcmd; 154754359Sroberto 154854359Sroberto /* 154954359Sroberto * Tokenize the command line. If nothing on it, return. 155054359Sroberto */ 155154359Sroberto tokenize(cmdline, tokens, &ntok); 155254359Sroberto if (ntok == 0) 155354359Sroberto return; 1554290001Sglebius 155554359Sroberto /* 155654359Sroberto * Find the appropriate command description. 155754359Sroberto */ 155854359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 155954359Sroberto if (i == 0) { 156054359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 156154359Sroberto tokens[0]); 156254359Sroberto return; 156354359Sroberto } else if (i >= 2) { 156454359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 156554359Sroberto tokens[0]); 156654359Sroberto return; 156754359Sroberto } 1568290001Sglebius 1569290001Sglebius /* Warn about ignored extra args */ 1570290001Sglebius for (i = MAXARGS + 1; i < ntok ; ++i) { 1571290001Sglebius fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1572290001Sglebius } 1573290001Sglebius 157454359Sroberto /* 157554359Sroberto * Save the keyword, then walk through the arguments, interpreting 157654359Sroberto * as we go. 157754359Sroberto */ 157854359Sroberto pcmd.keyword = tokens[0]; 157954359Sroberto pcmd.nargs = 0; 158054359Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 158154359Sroberto if ((i+1) >= ntok) { 158254359Sroberto if (!(xcmd->arg[i] & OPT)) { 158354359Sroberto printusage(xcmd, stderr); 158454359Sroberto return; 158554359Sroberto } 158654359Sroberto break; 158754359Sroberto } 158854359Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1589290001Sglebius break; 159054359Sroberto if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1591290001Sglebius return; 159254359Sroberto pcmd.nargs++; 159354359Sroberto } 159454359Sroberto 159554359Sroberto i++; 159654359Sroberto if (i < ntok && *tokens[i] == '>') { 159754359Sroberto char *fname; 159854359Sroberto 159954359Sroberto if (*(tokens[i]+1) != '\0') 1600290001Sglebius fname = tokens[i]+1; 160154359Sroberto else if ((i+1) < ntok) 1602290001Sglebius fname = tokens[i+1]; 160354359Sroberto else { 160454359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 160554359Sroberto return; 160654359Sroberto } 160754359Sroberto 160854359Sroberto current_output = fopen(fname, "w"); 160954359Sroberto if (current_output == NULL) { 161054359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 161154359Sroberto perror(""); 161254359Sroberto return; 161354359Sroberto } 161454359Sroberto i = 1; /* flag we need a close */ 161554359Sroberto } else { 161654359Sroberto current_output = stdout; 161754359Sroberto i = 0; /* flag no close */ 161854359Sroberto } 161954359Sroberto 162054359Sroberto if (interactive && setjmp(interrupt_buf)) { 162154359Sroberto jump = 0; 162254359Sroberto return; 162354359Sroberto } else { 162454359Sroberto jump++; 162554359Sroberto (xcmd->handler)(&pcmd, current_output); 162654359Sroberto jump = 0; /* HMS: 961106: was after fclose() */ 162754359Sroberto if (i) (void) fclose(current_output); 162854359Sroberto } 1629290001Sglebius 1630290001Sglebius return; 163154359Sroberto} 163254359Sroberto 163354359Sroberto 163454359Sroberto/* 163554359Sroberto * tokenize - turn a command line into tokens 1636290001Sglebius * 1637290001Sglebius * SK: Modified to allow a quoted string 1638290001Sglebius * 1639290001Sglebius * HMS: If the first character of the first token is a ':' then (after 1640290001Sglebius * eating inter-token whitespace) the 2nd token is the rest of the line. 164154359Sroberto */ 1642290001Sglebius 164354359Srobertostatic void 164454359Srobertotokenize( 164554359Sroberto const char *line, 164654359Sroberto char **tokens, 164754359Sroberto int *ntok 164854359Sroberto ) 164954359Sroberto{ 165054359Sroberto register const char *cp; 165154359Sroberto register char *sp; 165254359Sroberto static char tspace[MAXLINE]; 165354359Sroberto 165454359Sroberto sp = tspace; 165554359Sroberto cp = line; 165654359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 165754359Sroberto tokens[*ntok] = sp; 1658290001Sglebius 1659290001Sglebius /* Skip inter-token whitespace */ 166054359Sroberto while (ISSPACE(*cp)) 166154359Sroberto cp++; 1662290001Sglebius 1663290001Sglebius /* If we're at EOL we're done */ 166454359Sroberto if (ISEOL(*cp)) 166554359Sroberto break; 166654359Sroberto 1667290001Sglebius /* If this is the 2nd token and the first token begins 1668290001Sglebius * with a ':', then just grab to EOL. 1669290001Sglebius */ 1670290001Sglebius 1671290001Sglebius if (*ntok == 1 && tokens[0][0] == ':') { 1672290001Sglebius do { 1673290001Sglebius if (sp - tspace >= MAXLINE) 1674290001Sglebius goto toobig; 1675290001Sglebius *sp++ = *cp++; 1676290001Sglebius } while (!ISEOL(*cp)); 1677290001Sglebius } 1678290001Sglebius 1679290001Sglebius /* Check if this token begins with a double quote. 1680290001Sglebius * If yes, continue reading till the next double quote 1681290001Sglebius */ 1682290001Sglebius else if (*cp == '\"') { 1683290001Sglebius ++cp; 1684290001Sglebius do { 1685290001Sglebius if (sp - tspace >= MAXLINE) 1686290001Sglebius goto toobig; 1687290001Sglebius *sp++ = *cp++; 1688290001Sglebius } while ((*cp != '\"') && !ISEOL(*cp)); 1689290001Sglebius /* HMS: a missing closing " should be an error */ 1690290001Sglebius } 1691290001Sglebius else { 1692290001Sglebius do { 1693290001Sglebius if (sp - tspace >= MAXLINE) 1694290001Sglebius goto toobig; 1695290001Sglebius *sp++ = *cp++; 1696290001Sglebius } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1697290001Sglebius /* HMS: Why check for a " in the previous line? */ 1698290001Sglebius } 1699290001Sglebius 1700290001Sglebius if (sp - tspace >= MAXLINE) 1701290001Sglebius goto toobig; 170254359Sroberto *sp++ = '\0'; 170354359Sroberto } 1704290001Sglebius return; 1705290001Sglebius 1706290001Sglebius toobig: 1707290001Sglebius *ntok = 0; 1708290001Sglebius fprintf(stderr, 1709290001Sglebius "***Line `%s' is too big\n", 1710290001Sglebius line); 1711290001Sglebius return; 171254359Sroberto} 171354359Sroberto 171454359Sroberto 1715290001Sglebius/* 1716290001Sglebius * getarg - interpret an argument token 1717290001Sglebius */ 1718290001Sglebiusstatic int 1719290001Sglebiusgetarg( 1720290001Sglebius const char *str, 1721290001Sglebius int code, 1722290001Sglebius arg_v *argp 1723290001Sglebius ) 1724290001Sglebius{ 1725290001Sglebius u_long ul; 172654359Sroberto 1727290001Sglebius switch (code & ~OPT) { 1728290001Sglebius case NTP_STR: 1729290001Sglebius argp->string = str; 1730290001Sglebius break; 1731290001Sglebius 1732290001Sglebius case NTP_ADD: 1733290001Sglebius if (!getnetnum(str, &argp->netnum, NULL, 0)) 1734290001Sglebius return 0; 1735290001Sglebius break; 1736290001Sglebius 1737290001Sglebius case NTP_UINT: 1738290001Sglebius if ('&' == str[0]) { 1739290001Sglebius if (!atouint(&str[1], &ul)) { 1740290001Sglebius fprintf(stderr, 1741290001Sglebius "***Association index `%s' invalid/undecodable\n", 1742290001Sglebius str); 1743290001Sglebius return 0; 1744290001Sglebius } 1745290001Sglebius if (0 == numassoc) { 1746290001Sglebius dogetassoc(stdout); 1747290001Sglebius if (0 == numassoc) { 1748290001Sglebius fprintf(stderr, 1749290001Sglebius "***No associations found, `%s' unknown\n", 1750290001Sglebius str); 1751290001Sglebius return 0; 1752290001Sglebius } 1753290001Sglebius } 1754290001Sglebius ul = min(ul, numassoc); 1755290001Sglebius argp->uval = assoc_cache[ul - 1].assid; 1756290001Sglebius break; 1757290001Sglebius } 1758290001Sglebius if (!atouint(str, &argp->uval)) { 1759290001Sglebius fprintf(stderr, "***Illegal unsigned value %s\n", 1760290001Sglebius str); 1761290001Sglebius return 0; 1762290001Sglebius } 1763290001Sglebius break; 1764290001Sglebius 1765290001Sglebius case NTP_INT: 1766290001Sglebius if (!atoint(str, &argp->ival)) { 1767290001Sglebius fprintf(stderr, "***Illegal integer value %s\n", 1768290001Sglebius str); 1769290001Sglebius return 0; 1770290001Sglebius } 1771290001Sglebius break; 1772290001Sglebius 1773290001Sglebius case IP_VERSION: 1774290001Sglebius if (!strcmp("-6", str)) { 1775290001Sglebius argp->ival = 6; 1776290001Sglebius } else if (!strcmp("-4", str)) { 1777290001Sglebius argp->ival = 4; 1778290001Sglebius } else { 1779290001Sglebius fprintf(stderr, "***Version must be either 4 or 6\n"); 1780290001Sglebius return 0; 1781290001Sglebius } 1782290001Sglebius break; 1783290001Sglebius } 1784290001Sglebius 1785290001Sglebius return 1; 1786290001Sglebius} 1787290001Sglebius#endif /* !BUILD_AS_LIB */ 1788290001Sglebius 1789290001Sglebius 179054359Sroberto/* 179154359Sroberto * findcmd - find a command in a command description table 179254359Sroberto */ 179354359Srobertostatic int 179454359Srobertofindcmd( 1795290001Sglebius const char * str, 1796290001Sglebius struct xcmd * clist1, 1797290001Sglebius struct xcmd * clist2, 1798290001Sglebius struct xcmd ** cmd 179954359Sroberto ) 180054359Sroberto{ 1801290001Sglebius struct xcmd *cl; 1802293896Sglebius size_t clen; 180354359Sroberto int nmatch; 180454359Sroberto struct xcmd *nearmatch = NULL; 180554359Sroberto struct xcmd *clist; 180654359Sroberto 180754359Sroberto clen = strlen(str); 180854359Sroberto nmatch = 0; 180954359Sroberto if (clist1 != 0) 181054359Sroberto clist = clist1; 181154359Sroberto else if (clist2 != 0) 181254359Sroberto clist = clist2; 181354359Sroberto else 181454359Sroberto return 0; 181554359Sroberto 181654359Sroberto again: 181754359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 181854359Sroberto /* do a first character check, for efficiency */ 181954359Sroberto if (*str != *(cl->keyword)) 182054359Sroberto continue; 182154359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 182254359Sroberto /* 182354359Sroberto * Could be extact match, could be approximate. 182454359Sroberto * Is exact if the length of the keyword is the 182554359Sroberto * same as the str. 182654359Sroberto */ 182754359Sroberto if (*((cl->keyword) + clen) == '\0') { 182854359Sroberto *cmd = cl; 182954359Sroberto return 1; 183054359Sroberto } 183154359Sroberto nmatch++; 183254359Sroberto nearmatch = cl; 183354359Sroberto } 183454359Sroberto } 183554359Sroberto 183654359Sroberto /* 183754359Sroberto * See if there is more to do. If so, go again. Sorry about the 183854359Sroberto * goto, too much looking at BSD sources... 183954359Sroberto */ 184054359Sroberto if (clist == clist1 && clist2 != 0) { 184154359Sroberto clist = clist2; 184254359Sroberto goto again; 184354359Sroberto } 184454359Sroberto 184554359Sroberto /* 184654359Sroberto * If we got extactly 1 near match, use it, else return number 184754359Sroberto * of matches. 184854359Sroberto */ 184954359Sroberto if (nmatch == 1) { 185054359Sroberto *cmd = nearmatch; 185154359Sroberto return 1; 185254359Sroberto } 185354359Sroberto return nmatch; 185454359Sroberto} 185554359Sroberto 185654359Sroberto 185754359Sroberto/* 185854359Sroberto * getnetnum - given a host name, return its net number 185954359Sroberto * and (optional) full name 186054359Sroberto */ 186154359Srobertoint 186254359Srobertogetnetnum( 186354359Sroberto const char *hname, 1864290001Sglebius sockaddr_u *num, 1865132451Sroberto char *fullhost, 1866132451Sroberto int af 186754359Sroberto ) 186854359Sroberto{ 1869132451Sroberto struct addrinfo hints, *ai = NULL; 187054359Sroberto 1871290001Sglebius ZERO(hints); 1872132451Sroberto hints.ai_flags = AI_CANONNAME; 1873132451Sroberto#ifdef AI_ADDRCONFIG 1874132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1875132451Sroberto#endif 1876290001Sglebius 1877290001Sglebius /* 1878290001Sglebius * decodenetnum only works with addresses, but handles syntax 1879290001Sglebius * that getaddrinfo doesn't: [2001::1]:1234 1880290001Sglebius */ 188154359Sroberto if (decodenetnum(hname, num)) { 1882290001Sglebius if (fullhost != NULL) 1883290001Sglebius getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1884290001Sglebius LENHOSTNAME, NULL, 0, 0); 188554359Sroberto return 1; 1886182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1887290001Sglebius INSIST(sizeof(*num) >= ai->ai_addrlen); 1888290001Sglebius memcpy(num, ai->ai_addr, ai->ai_addrlen); 1889290001Sglebius if (fullhost != NULL) { 1890290001Sglebius if (ai->ai_canonname != NULL) 1891290001Sglebius strlcpy(fullhost, ai->ai_canonname, 1892290001Sglebius LENHOSTNAME); 1893290001Sglebius else 1894290001Sglebius getnameinfo(&num->sa, SOCKLEN(num), 1895290001Sglebius fullhost, LENHOSTNAME, NULL, 1896290001Sglebius 0, 0); 1897290001Sglebius } 1898290001Sglebius freeaddrinfo(ai); 189954359Sroberto return 1; 190054359Sroberto } 1901290001Sglebius fprintf(stderr, "***Can't find host %s\n", hname); 1902290001Sglebius 1903290001Sglebius return 0; 190454359Sroberto} 190554359Sroberto 1906290001Sglebius 190754359Sroberto/* 190854359Sroberto * nntohost - convert network number to host name. This routine enforces 190954359Sroberto * the showhostnames setting. 191054359Sroberto */ 1911290001Sglebiusconst char * 191254359Srobertonntohost( 1913290001Sglebius sockaddr_u *netnum 191454359Sroberto ) 191554359Sroberto{ 1916290001Sglebius return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 191754359Sroberto} 191854359Sroberto 191954359Sroberto 192054359Sroberto/* 1921290001Sglebius * nntohost_col - convert network number to host name in fixed width. 1922290001Sglebius * This routine enforces the showhostnames setting. 1923290001Sglebius * When displaying hostnames longer than the width, 1924290001Sglebius * the first part of the hostname is displayed. When 1925290001Sglebius * displaying numeric addresses longer than the width, 1926290001Sglebius * Such as IPv6 addresses, the caller decides whether 1927290001Sglebius * the first or last of the numeric address is used. 1928290001Sglebius */ 1929290001Sglebiusconst char * 1930290001Sglebiusnntohost_col( 1931290001Sglebius sockaddr_u * addr, 1932290001Sglebius size_t width, 1933290001Sglebius int preserve_lowaddrbits 1934290001Sglebius ) 1935290001Sglebius{ 1936290001Sglebius const char * out; 1937290001Sglebius 1938290001Sglebius if (!showhostnames || SOCK_UNSPEC(addr)) { 1939290001Sglebius if (preserve_lowaddrbits) 1940290001Sglebius out = trunc_left(stoa(addr), width); 1941290001Sglebius else 1942290001Sglebius out = trunc_right(stoa(addr), width); 1943290001Sglebius } else if (ISREFCLOCKADR(addr)) { 1944290001Sglebius out = refnumtoa(addr); 1945290001Sglebius } else { 1946290001Sglebius out = trunc_right(socktohost(addr), width); 1947290001Sglebius } 1948290001Sglebius return out; 1949290001Sglebius} 1950290001Sglebius 1951290001Sglebius 1952290001Sglebius/* 1953290001Sglebius * nntohostp() is the same as nntohost() plus a :port suffix 1954290001Sglebius */ 1955290001Sglebiusconst char * 1956290001Sglebiusnntohostp( 1957290001Sglebius sockaddr_u *netnum 1958290001Sglebius ) 1959290001Sglebius{ 1960290001Sglebius const char * hostn; 1961290001Sglebius char * buf; 1962290001Sglebius 1963290001Sglebius if (!showhostnames || SOCK_UNSPEC(netnum)) 1964290001Sglebius return sptoa(netnum); 1965290001Sglebius else if (ISREFCLOCKADR(netnum)) 1966290001Sglebius return refnumtoa(netnum); 1967290001Sglebius 1968290001Sglebius hostn = socktohost(netnum); 1969290001Sglebius LIB_GETBUF(buf); 1970290001Sglebius snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 1971290001Sglebius 1972290001Sglebius return buf; 1973290001Sglebius} 1974290001Sglebius 1975290001Sglebius/* 197654359Sroberto * rtdatetolfp - decode an RT-11 date into an l_fp 197754359Sroberto */ 197854359Srobertostatic int 197954359Srobertortdatetolfp( 198054359Sroberto char *str, 198154359Sroberto l_fp *lfp 198254359Sroberto ) 198354359Sroberto{ 198454359Sroberto register char *cp; 198554359Sroberto register int i; 198654359Sroberto struct calendar cal; 198754359Sroberto char buf[4]; 198854359Sroberto 198954359Sroberto cal.yearday = 0; 199054359Sroberto 199154359Sroberto /* 199254359Sroberto * An RT-11 date looks like: 199354359Sroberto * 199454359Sroberto * d[d]-Mth-y[y] hh:mm:ss 199554359Sroberto * 199654359Sroberto * (No docs, but assume 4-digit years are also legal...) 199754359Sroberto * 199854359Sroberto * d[d]-Mth-y[y[y[y]]] hh:mm:ss 199954359Sroberto */ 200054359Sroberto cp = str; 200154359Sroberto if (!isdigit((int)*cp)) { 200254359Sroberto if (*cp == '-') { 200354359Sroberto /* 200454359Sroberto * Catch special case 200554359Sroberto */ 200654359Sroberto L_CLR(lfp); 200754359Sroberto return 1; 200854359Sroberto } 200954359Sroberto return 0; 201054359Sroberto } 201154359Sroberto 2012132451Sroberto cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 201354359Sroberto if (isdigit((int)*cp)) { 2014132451Sroberto cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2015132451Sroberto cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 201654359Sroberto } 201754359Sroberto 201854359Sroberto if (*cp++ != '-') 201954359Sroberto return 0; 2020290001Sglebius 202154359Sroberto for (i = 0; i < 3; i++) 202254359Sroberto buf[i] = *cp++; 202354359Sroberto buf[3] = '\0'; 202454359Sroberto 202554359Sroberto for (i = 0; i < 12; i++) 202654359Sroberto if (STREQ(buf, months[i])) 202754359Sroberto break; 202854359Sroberto if (i == 12) 202954359Sroberto return 0; 2030132451Sroberto cal.month = (u_char)(i + 1); 203154359Sroberto 203254359Sroberto if (*cp++ != '-') 203354359Sroberto return 0; 2034290001Sglebius 203554359Sroberto if (!isdigit((int)*cp)) 203654359Sroberto return 0; 2037132451Sroberto cal.year = (u_short)(*cp++ - '0'); 203854359Sroberto if (isdigit((int)*cp)) { 2039132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2040132451Sroberto cal.year = (u_short)(*cp++ - '0'); 204154359Sroberto } 204254359Sroberto if (isdigit((int)*cp)) { 2043132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2044132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 204554359Sroberto } 204654359Sroberto if (isdigit((int)*cp)) { 2047132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2048132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 204954359Sroberto } 205054359Sroberto 205154359Sroberto /* 205254359Sroberto * Catch special case. If cal.year == 0 this is a zero timestamp. 205354359Sroberto */ 205454359Sroberto if (cal.year == 0) { 205554359Sroberto L_CLR(lfp); 205654359Sroberto return 1; 205754359Sroberto } 205854359Sroberto 205954359Sroberto if (*cp++ != ' ' || !isdigit((int)*cp)) 206054359Sroberto return 0; 2061132451Sroberto cal.hour = (u_char)(*cp++ - '0'); 206254359Sroberto if (isdigit((int)*cp)) { 2063132451Sroberto cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2064132451Sroberto cal.hour = (u_char)(cal.hour + *cp++ - '0'); 206554359Sroberto } 206654359Sroberto 206754359Sroberto if (*cp++ != ':' || !isdigit((int)*cp)) 206854359Sroberto return 0; 2069132451Sroberto cal.minute = (u_char)(*cp++ - '0'); 207054359Sroberto if (isdigit((int)*cp)) { 2071132451Sroberto cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2072132451Sroberto cal.minute = (u_char)(cal.minute + *cp++ - '0'); 207354359Sroberto } 207454359Sroberto 207554359Sroberto if (*cp++ != ':' || !isdigit((int)*cp)) 207654359Sroberto return 0; 2077132451Sroberto cal.second = (u_char)(*cp++ - '0'); 207854359Sroberto if (isdigit((int)*cp)) { 2079132451Sroberto cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2080132451Sroberto cal.second = (u_char)(cal.second + *cp++ - '0'); 208154359Sroberto } 208254359Sroberto 208354359Sroberto /* 208454359Sroberto * For RT-11, 1972 seems to be the pivot year 208554359Sroberto */ 208654359Sroberto if (cal.year < 72) 208754359Sroberto cal.year += 2000; 208854359Sroberto if (cal.year < 100) 208954359Sroberto cal.year += 1900; 209054359Sroberto 209154359Sroberto lfp->l_ui = caltontp(&cal); 209254359Sroberto lfp->l_uf = 0; 209354359Sroberto return 1; 209454359Sroberto} 209554359Sroberto 209654359Sroberto 209754359Sroberto/* 209854359Sroberto * decodets - decode a timestamp into an l_fp format number, with 209954359Sroberto * consideration of fuzzball formats. 210054359Sroberto */ 210154359Srobertoint 210254359Srobertodecodets( 210354359Sroberto char *str, 210454359Sroberto l_fp *lfp 210554359Sroberto ) 210654359Sroberto{ 2107290001Sglebius char *cp; 2108290001Sglebius char buf[30]; 2109290001Sglebius size_t b; 2110290001Sglebius 211154359Sroberto /* 211254359Sroberto * If it starts with a 0x, decode as hex. 211354359Sroberto */ 211454359Sroberto if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2115290001Sglebius return hextolfp(str+2, lfp); 211654359Sroberto 211754359Sroberto /* 211854359Sroberto * If it starts with a '"', try it as an RT-11 date. 211954359Sroberto */ 212054359Sroberto if (*str == '"') { 2121290001Sglebius cp = str + 1; 2122290001Sglebius b = 0; 2123290001Sglebius while ('"' != *cp && '\0' != *cp && 2124290001Sglebius b < COUNTOF(buf) - 1) 2125290001Sglebius buf[b++] = *cp++; 2126290001Sglebius buf[b] = '\0'; 212754359Sroberto return rtdatetolfp(buf, lfp); 212854359Sroberto } 212954359Sroberto 213054359Sroberto /* 213154359Sroberto * Might still be hex. Check out the first character. Talk 213254359Sroberto * about heuristics! 213354359Sroberto */ 213454359Sroberto if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2135290001Sglebius return hextolfp(str, lfp); 213654359Sroberto 213754359Sroberto /* 213854359Sroberto * Try it as a decimal. If this fails, try as an unquoted 213954359Sroberto * RT-11 date. This code should go away eventually. 214054359Sroberto */ 214154359Sroberto if (atolfp(str, lfp)) 2142290001Sglebius return 1; 2143290001Sglebius 214454359Sroberto return rtdatetolfp(str, lfp); 214554359Sroberto} 214654359Sroberto 214754359Sroberto 214854359Sroberto/* 214954359Sroberto * decodetime - decode a time value. It should be in milliseconds 215054359Sroberto */ 215154359Srobertoint 215254359Srobertodecodetime( 215354359Sroberto char *str, 215454359Sroberto l_fp *lfp 215554359Sroberto ) 215654359Sroberto{ 215754359Sroberto return mstolfp(str, lfp); 215854359Sroberto} 215954359Sroberto 216054359Sroberto 216154359Sroberto/* 216254359Sroberto * decodeint - decode an integer 216354359Sroberto */ 216454359Srobertoint 216554359Srobertodecodeint( 216654359Sroberto char *str, 216754359Sroberto long *val 216854359Sroberto ) 216954359Sroberto{ 217054359Sroberto if (*str == '0') { 217154359Sroberto if (*(str+1) == 'x' || *(str+1) == 'X') 2172290001Sglebius return hextoint(str+2, (u_long *)val); 2173290001Sglebius return octtoint(str, (u_long *)val); 217454359Sroberto } 217554359Sroberto return atoint(str, val); 217654359Sroberto} 217754359Sroberto 217854359Sroberto 217954359Sroberto/* 218054359Sroberto * decodeuint - decode an unsigned integer 218154359Sroberto */ 218254359Srobertoint 218354359Srobertodecodeuint( 218454359Sroberto char *str, 218554359Sroberto u_long *val 218654359Sroberto ) 218754359Sroberto{ 218854359Sroberto if (*str == '0') { 218954359Sroberto if (*(str + 1) == 'x' || *(str + 1) == 'X') 219054359Sroberto return (hextoint(str + 2, val)); 219154359Sroberto return (octtoint(str, val)); 219254359Sroberto } 219354359Sroberto return (atouint(str, val)); 219454359Sroberto} 219554359Sroberto 219654359Sroberto 219754359Sroberto/* 219854359Sroberto * decodearr - decode an array of time values 219954359Sroberto */ 220054359Srobertostatic int 220154359Srobertodecodearr( 220254359Sroberto char *str, 220354359Sroberto int *narr, 220454359Sroberto l_fp *lfparr 220554359Sroberto ) 220654359Sroberto{ 220754359Sroberto register char *cp, *bp; 220854359Sroberto register l_fp *lfp; 220954359Sroberto char buf[60]; 221054359Sroberto 221154359Sroberto lfp = lfparr; 221254359Sroberto cp = str; 221354359Sroberto *narr = 0; 221454359Sroberto 221554359Sroberto while (*narr < 8) { 221654359Sroberto while (isspace((int)*cp)) 221754359Sroberto cp++; 221854359Sroberto if (*cp == '\0') 221954359Sroberto break; 222054359Sroberto 222154359Sroberto bp = buf; 222254359Sroberto while (!isspace((int)*cp) && *cp != '\0') 222354359Sroberto *bp++ = *cp++; 222454359Sroberto *bp++ = '\0'; 222554359Sroberto 222654359Sroberto if (!decodetime(buf, lfp)) 222754359Sroberto return 0; 222854359Sroberto (*narr)++; 222954359Sroberto lfp++; 223054359Sroberto } 223154359Sroberto return 1; 223254359Sroberto} 223354359Sroberto 223454359Sroberto 223554359Sroberto/* 223654359Sroberto * Finally, the built in command handlers 223754359Sroberto */ 223854359Sroberto 223954359Sroberto/* 224054359Sroberto * help - tell about commands, or details of a particular command 224154359Sroberto */ 224254359Srobertostatic void 224354359Srobertohelp( 224454359Sroberto struct parse *pcmd, 224554359Sroberto FILE *fp 224654359Sroberto ) 224754359Sroberto{ 2248290001Sglebius struct xcmd *xcp = NULL; /* quiet warning */ 2249290001Sglebius const char *cmd; 2250182007Sroberto const char *list[100]; 2251290001Sglebius size_t word, words; 2252290001Sglebius size_t row, rows; 2253290001Sglebius size_t col, cols; 2254290001Sglebius size_t length; 225554359Sroberto 225654359Sroberto if (pcmd->nargs == 0) { 2257182007Sroberto words = 0; 2258290001Sglebius for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2259290001Sglebius if (*(xcp->keyword) != '?' && 2260290001Sglebius words < COUNTOF(list)) 2261290001Sglebius list[words++] = xcp->keyword; 226254359Sroberto } 2263290001Sglebius for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2264290001Sglebius if (words < COUNTOF(list)) 2265290001Sglebius list[words++] = xcp->keyword; 226654359Sroberto 2267290001Sglebius qsort((void *)list, words, sizeof(list[0]), helpsort); 2268182007Sroberto col = 0; 2269182007Sroberto for (word = 0; word < words; word++) { 2270290001Sglebius length = strlen(list[word]); 2271290001Sglebius col = max(col, length); 227254359Sroberto } 227354359Sroberto 2274182007Sroberto cols = SCREENWIDTH / ++col; 2275290001Sglebius rows = (words + cols - 1) / cols; 2276182007Sroberto 2277290001Sglebius fprintf(fp, "ntpq commands:\n"); 2278182007Sroberto 2279182007Sroberto for (row = 0; row < rows; row++) { 2280290001Sglebius for (word = row; word < words; word += rows) 2281290001Sglebius fprintf(fp, "%-*.*s", (int)col, 2282290001Sglebius (int)col - 1, list[word]); 2283290001Sglebius fprintf(fp, "\n"); 2284290001Sglebius } 228554359Sroberto } else { 228654359Sroberto cmd = pcmd->argval[0].string; 2287182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 2288182007Sroberto if (words == 0) { 2289290001Sglebius fprintf(stderr, 2290290001Sglebius "Command `%s' is unknown\n", cmd); 229154359Sroberto return; 2292182007Sroberto } else if (words >= 2) { 2293290001Sglebius fprintf(stderr, 2294290001Sglebius "Command `%s' is ambiguous\n", cmd); 229554359Sroberto return; 229654359Sroberto } 2297290001Sglebius fprintf(fp, "function: %s\n", xcp->comment); 229854359Sroberto printusage(xcp, fp); 229954359Sroberto } 230054359Sroberto} 230154359Sroberto 230254359Sroberto 230354359Sroberto/* 230454359Sroberto * helpsort - do hostname qsort comparisons 230554359Sroberto */ 230654359Srobertostatic int 230754359Srobertohelpsort( 230854359Sroberto const void *t1, 230954359Sroberto const void *t2 231054359Sroberto ) 231154359Sroberto{ 2312290001Sglebius const char * const * name1 = t1; 2313290001Sglebius const char * const * name2 = t2; 231454359Sroberto 231554359Sroberto return strcmp(*name1, *name2); 231654359Sroberto} 231754359Sroberto 231854359Sroberto 231954359Sroberto/* 232054359Sroberto * printusage - print usage information for a command 232154359Sroberto */ 232254359Srobertostatic void 232354359Srobertoprintusage( 232454359Sroberto struct xcmd *xcp, 232554359Sroberto FILE *fp 232654359Sroberto ) 232754359Sroberto{ 232854359Sroberto register int i; 232954359Sroberto 2330290001Sglebius /* XXX: Do we need to warn about extra args here too? */ 2331290001Sglebius 233254359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 233354359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 233454359Sroberto if (xcp->arg[i] & OPT) 233554359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 233654359Sroberto else 233754359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 233854359Sroberto } 233954359Sroberto (void) fprintf(fp, "\n"); 234054359Sroberto} 234154359Sroberto 234254359Sroberto 234354359Sroberto/* 234454359Sroberto * timeout - set time out time 234554359Sroberto */ 234654359Srobertostatic void 234754359Srobertotimeout( 234854359Sroberto struct parse *pcmd, 234954359Sroberto FILE *fp 235054359Sroberto ) 235154359Sroberto{ 235254359Sroberto int val; 235354359Sroberto 235454359Sroberto if (pcmd->nargs == 0) { 2355290001Sglebius val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 235654359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 235754359Sroberto } else { 235854359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 2359290001Sglebius tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 236054359Sroberto * 1000; 236154359Sroberto } 236254359Sroberto} 236354359Sroberto 236454359Sroberto 236554359Sroberto/* 236654359Sroberto * auth_delay - set delay for auth requests 236754359Sroberto */ 236854359Srobertostatic void 236954359Srobertoauth_delay( 237054359Sroberto struct parse *pcmd, 237154359Sroberto FILE *fp 237254359Sroberto ) 237354359Sroberto{ 237454359Sroberto int isneg; 237554359Sroberto u_long val; 237654359Sroberto 237754359Sroberto if (pcmd->nargs == 0) { 237854359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 237954359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 238054359Sroberto } else { 238154359Sroberto if (pcmd->argval[0].ival < 0) { 238254359Sroberto isneg = 1; 238354359Sroberto val = (u_long)(-pcmd->argval[0].ival); 238454359Sroberto } else { 238554359Sroberto isneg = 0; 238654359Sroberto val = (u_long)pcmd->argval[0].ival; 238754359Sroberto } 238854359Sroberto 238954359Sroberto delay_time.l_ui = val / 1000; 239054359Sroberto val %= 1000; 239154359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 239254359Sroberto 239354359Sroberto if (isneg) 239454359Sroberto L_NEG(&delay_time); 239554359Sroberto } 239654359Sroberto} 239754359Sroberto 239854359Sroberto 239954359Sroberto/* 240054359Sroberto * host - set the host we are dealing with. 240154359Sroberto */ 240254359Srobertostatic void 240354359Srobertohost( 240454359Sroberto struct parse *pcmd, 240554359Sroberto FILE *fp 240654359Sroberto ) 240754359Sroberto{ 2408132451Sroberto int i; 2409132451Sroberto 241054359Sroberto if (pcmd->nargs == 0) { 241154359Sroberto if (havehost) 2412290001Sglebius (void) fprintf(fp, "current host is %s\n", 2413290001Sglebius currenthost); 241454359Sroberto else 2415290001Sglebius (void) fprintf(fp, "no current host\n"); 2416132451Sroberto return; 2417132451Sroberto } 2418132451Sroberto 2419132451Sroberto i = 0; 2420132451Sroberto ai_fam_templ = ai_fam_default; 2421132451Sroberto if (pcmd->nargs == 2) { 2422132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 2423132451Sroberto ai_fam_templ = AF_INET; 2424132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 2425132451Sroberto ai_fam_templ = AF_INET6; 2426290001Sglebius else 2427290001Sglebius goto no_change; 2428132451Sroberto i = 1; 2429132451Sroberto } 2430290001Sglebius if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2431290001Sglebius fprintf(fp, "current host set to %s\n", currenthost); 243254359Sroberto } else { 2433290001Sglebius no_change: 243454359Sroberto if (havehost) 2435290001Sglebius fprintf(fp, "current host remains %s\n", 2436290001Sglebius currenthost); 243754359Sroberto else 2438290001Sglebius fprintf(fp, "still no current host\n"); 243954359Sroberto } 244054359Sroberto} 244154359Sroberto 244254359Sroberto 244354359Sroberto/* 244454359Sroberto * poll - do one (or more) polls of the host via NTP 244554359Sroberto */ 244654359Sroberto/*ARGSUSED*/ 244754359Srobertostatic void 244854359Srobertontp_poll( 244954359Sroberto struct parse *pcmd, 245054359Sroberto FILE *fp 245154359Sroberto ) 245254359Sroberto{ 245354359Sroberto (void) fprintf(fp, "poll not implemented yet\n"); 245454359Sroberto} 245554359Sroberto 245654359Sroberto 245754359Sroberto/* 2458298770Sdelphij * showdrefid2str - return a string explanation of the value of drefid 2459298770Sdelphij */ 2460298770Sdelphijstatic char * 2461298770Sdelphijshowdrefid2str(void) 2462298770Sdelphij{ 2463298770Sdelphij switch (drefid) { 2464298770Sdelphij case REFID_HASH: 2465298770Sdelphij return "hash"; 2466298770Sdelphij case REFID_IPV4: 2467298770Sdelphij return "ipv4"; 2468298770Sdelphij default: 2469298770Sdelphij return "Unknown"; 2470298770Sdelphij } 2471298770Sdelphij} 2472298770Sdelphij 2473298770Sdelphij 2474298770Sdelphij/* 2475298770Sdelphij * drefid - display/change "display hash" 2476298770Sdelphij */ 2477298770Sdelphijstatic void 2478298770Sdelphijshowdrefid( 2479298770Sdelphij struct parse *pcmd, 2480298770Sdelphij FILE *fp 2481298770Sdelphij ) 2482298770Sdelphij{ 2483298770Sdelphij if (pcmd->nargs == 0) { 2484298770Sdelphij (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2485298770Sdelphij return; 2486298770Sdelphij } else if (STREQ(pcmd->argval[0].string, "hash")) { 2487298770Sdelphij drefid = REFID_HASH; 2488298770Sdelphij } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2489298770Sdelphij drefid = REFID_IPV4; 2490298770Sdelphij } else { 2491298770Sdelphij (void) fprintf(fp, "What?\n"); 2492298770Sdelphij return; 2493298770Sdelphij } 2494298770Sdelphij (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2495298770Sdelphij} 2496298770Sdelphij 2497298770Sdelphij 2498298770Sdelphij/* 249954359Sroberto * keyid - get a keyid to use for authenticating requests 250054359Sroberto */ 250154359Srobertostatic void 250254359Srobertokeyid( 250354359Sroberto struct parse *pcmd, 250454359Sroberto FILE *fp 250554359Sroberto ) 250654359Sroberto{ 250754359Sroberto if (pcmd->nargs == 0) { 2508132451Sroberto if (info_auth_keyid == 0) 250954359Sroberto (void) fprintf(fp, "no keyid defined\n"); 251054359Sroberto else 251154359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 251254359Sroberto } else { 2513132451Sroberto /* allow zero so that keyid can be cleared. */ 2514132451Sroberto if(pcmd->argval[0].uval > NTP_MAXKEY) 2515132451Sroberto (void) fprintf(fp, "Invalid key identifier\n"); 251654359Sroberto info_auth_keyid = pcmd->argval[0].uval; 251754359Sroberto } 251854359Sroberto} 251954359Sroberto 252054359Sroberto/* 252154359Sroberto * keytype - get type of key to use for authenticating requests 252254359Sroberto */ 252354359Srobertostatic void 252454359Srobertokeytype( 252554359Sroberto struct parse *pcmd, 252654359Sroberto FILE *fp 252754359Sroberto ) 252854359Sroberto{ 2529290001Sglebius const char * digest_name; 2530290001Sglebius size_t digest_len; 2531290001Sglebius int key_type; 253254359Sroberto 2533290001Sglebius if (!pcmd->nargs) { 2534290001Sglebius fprintf(fp, "keytype is %s with %lu octet digests\n", 2535290001Sglebius keytype_name(info_auth_keytype), 2536290001Sglebius (u_long)info_auth_hashlen); 2537290001Sglebius return; 2538290001Sglebius } 2539290001Sglebius 2540290001Sglebius digest_name = pcmd->argval[0].string; 2541290001Sglebius digest_len = 0; 2542290001Sglebius key_type = keytype_from_text(digest_name, &digest_len); 2543290001Sglebius 2544290001Sglebius if (!key_type) { 2545290001Sglebius fprintf(fp, "keytype is not valid. " 2546290001Sglebius#ifdef OPENSSL 2547290001Sglebius "Type \"help keytype\" for the available digest types.\n"); 2548290001Sglebius#else 2549290001Sglebius "Only \"md5\" is available.\n"); 2550290001Sglebius#endif 2551290001Sglebius return; 2552290001Sglebius } 2553290001Sglebius 2554290001Sglebius info_auth_keytype = key_type; 2555290001Sglebius info_auth_hashlen = digest_len; 255654359Sroberto} 255754359Sroberto 255854359Sroberto 255954359Sroberto/* 256054359Sroberto * passwd - get an authentication key 256154359Sroberto */ 256254359Sroberto/*ARGSUSED*/ 256354359Srobertostatic void 256454359Srobertopasswd( 256554359Sroberto struct parse *pcmd, 256654359Sroberto FILE *fp 256754359Sroberto ) 256854359Sroberto{ 2569290001Sglebius const char *pass; 257054359Sroberto 2571132451Sroberto if (info_auth_keyid == 0) { 2572290001Sglebius info_auth_keyid = getkeyid("Keyid: "); 2573290001Sglebius if (info_auth_keyid == 0) { 2574290001Sglebius (void)fprintf(fp, "Keyid must be defined\n"); 257554359Sroberto return; 257654359Sroberto } 257754359Sroberto } 2578290001Sglebius if (pcmd->nargs >= 1) 2579290001Sglebius pass = pcmd->argval[0].string; 2580132451Sroberto else { 2581290001Sglebius pass = getpass_keytype(info_auth_keytype); 2582290001Sglebius if ('\0' == pass[0]) { 2583290001Sglebius fprintf(fp, "Password unchanged\n"); 2584290001Sglebius return; 2585290001Sglebius } 2586132451Sroberto } 2587290001Sglebius authusekey(info_auth_keyid, info_auth_keytype, 2588290001Sglebius (const u_char *)pass); 2589290001Sglebius authtrust(info_auth_keyid, 1); 259054359Sroberto} 259154359Sroberto 259254359Sroberto 259354359Sroberto/* 259454359Sroberto * hostnames - set the showhostnames flag 259554359Sroberto */ 259654359Srobertostatic void 259754359Srobertohostnames( 259854359Sroberto struct parse *pcmd, 259954359Sroberto FILE *fp 260054359Sroberto ) 260154359Sroberto{ 260254359Sroberto if (pcmd->nargs == 0) { 260354359Sroberto if (showhostnames) 260454359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 260554359Sroberto else 260654359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 260754359Sroberto } else { 260854359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 260954359Sroberto showhostnames = 1; 261054359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 261154359Sroberto showhostnames = 0; 261254359Sroberto else 261354359Sroberto (void)fprintf(stderr, "What?\n"); 261454359Sroberto } 261554359Sroberto} 261654359Sroberto 261754359Sroberto 261854359Sroberto 261954359Sroberto/* 262054359Sroberto * setdebug - set/change debugging level 262154359Sroberto */ 262254359Srobertostatic void 262354359Srobertosetdebug( 262454359Sroberto struct parse *pcmd, 262554359Sroberto FILE *fp 262654359Sroberto ) 262754359Sroberto{ 262854359Sroberto if (pcmd->nargs == 0) { 262954359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 263054359Sroberto return; 263154359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 263254359Sroberto debug = 0; 263354359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 263454359Sroberto debug++; 263554359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 263654359Sroberto debug--; 263754359Sroberto } else { 263854359Sroberto (void) fprintf(fp, "What?\n"); 263954359Sroberto return; 264054359Sroberto } 264154359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 264254359Sroberto} 264354359Sroberto 264454359Sroberto 264554359Sroberto/* 264654359Sroberto * quit - stop this nonsense 264754359Sroberto */ 264854359Sroberto/*ARGSUSED*/ 264954359Srobertostatic void 265054359Srobertoquit( 265154359Sroberto struct parse *pcmd, 265254359Sroberto FILE *fp 265354359Sroberto ) 265454359Sroberto{ 265554359Sroberto if (havehost) 265654359Sroberto closesocket(sockfd); /* cleanliness next to godliness */ 265754359Sroberto exit(0); 265854359Sroberto} 265954359Sroberto 266054359Sroberto 266154359Sroberto/* 266254359Sroberto * version - print the current version number 266354359Sroberto */ 266454359Sroberto/*ARGSUSED*/ 266554359Srobertostatic void 266654359Srobertoversion( 266754359Sroberto struct parse *pcmd, 266854359Sroberto FILE *fp 266954359Sroberto ) 267054359Sroberto{ 267154359Sroberto 267254359Sroberto (void) fprintf(fp, "%s\n", Version); 267354359Sroberto return; 267454359Sroberto} 267554359Sroberto 267654359Sroberto 267754359Sroberto/* 267854359Sroberto * raw - set raw mode output 267954359Sroberto */ 268054359Sroberto/*ARGSUSED*/ 268154359Srobertostatic void 268254359Srobertoraw( 268354359Sroberto struct parse *pcmd, 268454359Sroberto FILE *fp 268554359Sroberto ) 268654359Sroberto{ 268754359Sroberto rawmode = 1; 268854359Sroberto (void) fprintf(fp, "Output set to raw\n"); 268954359Sroberto} 269054359Sroberto 269154359Sroberto 269254359Sroberto/* 269354359Sroberto * cooked - set cooked mode output 269454359Sroberto */ 269554359Sroberto/*ARGSUSED*/ 269654359Srobertostatic void 269754359Srobertocooked( 269854359Sroberto struct parse *pcmd, 269954359Sroberto FILE *fp 270054359Sroberto ) 270154359Sroberto{ 270254359Sroberto rawmode = 0; 270354359Sroberto (void) fprintf(fp, "Output set to cooked\n"); 270454359Sroberto return; 270554359Sroberto} 270654359Sroberto 270754359Sroberto 270854359Sroberto/* 270954359Sroberto * authenticate - always authenticate requests to this host 271054359Sroberto */ 271154359Srobertostatic void 271254359Srobertoauthenticate( 271354359Sroberto struct parse *pcmd, 271454359Sroberto FILE *fp 271554359Sroberto ) 271654359Sroberto{ 271754359Sroberto if (pcmd->nargs == 0) { 271854359Sroberto if (always_auth) { 271954359Sroberto (void) fprintf(fp, 272054359Sroberto "authenticated requests being sent\n"); 272154359Sroberto } else 272254359Sroberto (void) fprintf(fp, 272354359Sroberto "unauthenticated requests being sent\n"); 272454359Sroberto } else { 272554359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) { 272654359Sroberto always_auth = 1; 272754359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 272854359Sroberto always_auth = 0; 272954359Sroberto } else 273054359Sroberto (void)fprintf(stderr, "What?\n"); 273154359Sroberto } 273254359Sroberto} 273354359Sroberto 273454359Sroberto 273554359Sroberto/* 273654359Sroberto * ntpversion - choose the NTP version to use 273754359Sroberto */ 273854359Srobertostatic void 273954359Srobertontpversion( 274054359Sroberto struct parse *pcmd, 274154359Sroberto FILE *fp 274254359Sroberto ) 274354359Sroberto{ 274454359Sroberto if (pcmd->nargs == 0) { 274554359Sroberto (void) fprintf(fp, 274654359Sroberto "NTP version being claimed is %d\n", pktversion); 274754359Sroberto } else { 274854359Sroberto if (pcmd->argval[0].uval < NTP_OLDVERSION 274954359Sroberto || pcmd->argval[0].uval > NTP_VERSION) { 275054359Sroberto (void) fprintf(stderr, "versions %d to %d, please\n", 275154359Sroberto NTP_OLDVERSION, NTP_VERSION); 275254359Sroberto } else { 275354359Sroberto pktversion = (u_char) pcmd->argval[0].uval; 275454359Sroberto } 275554359Sroberto } 275654359Sroberto} 275754359Sroberto 275854359Sroberto 2759290001Sglebiusstatic void __attribute__((__format__(__printf__, 1, 0))) 2760290001Sglebiusvwarning(const char *fmt, va_list ap) 2761290001Sglebius{ 2762290001Sglebius int serrno = errno; 2763290001Sglebius (void) fprintf(stderr, "%s: ", progname); 2764290001Sglebius vfprintf(stderr, fmt, ap); 2765293896Sglebius (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2766290001Sglebius} 2767290001Sglebius 276854359Sroberto/* 276954359Sroberto * warning - print a warning message 277054359Sroberto */ 2771290001Sglebiusstatic void __attribute__((__format__(__printf__, 1, 2))) 277254359Srobertowarning( 277354359Sroberto const char *fmt, 2774290001Sglebius ... 277554359Sroberto ) 277654359Sroberto{ 2777290001Sglebius va_list ap; 2778290001Sglebius va_start(ap, fmt); 2779290001Sglebius vwarning(fmt, ap); 2780290001Sglebius va_end(ap); 278154359Sroberto} 278254359Sroberto 278354359Sroberto 278454359Sroberto/* 278554359Sroberto * error - print a message and exit 278654359Sroberto */ 2787290001Sglebiusstatic void __attribute__((__format__(__printf__, 1, 2))) 278854359Srobertoerror( 278954359Sroberto const char *fmt, 2790290001Sglebius ... 279154359Sroberto ) 279254359Sroberto{ 2793290001Sglebius va_list ap; 2794290001Sglebius va_start(ap, fmt); 2795290001Sglebius vwarning(fmt, ap); 2796290001Sglebius va_end(ap); 279754359Sroberto exit(1); 279854359Sroberto} 279954359Sroberto/* 280054359Sroberto * getkeyid - prompt the user for a keyid to use 280154359Sroberto */ 280254359Srobertostatic u_long 280354359Srobertogetkeyid( 280454359Sroberto const char *keyprompt 280554359Sroberto ) 280654359Sroberto{ 2807290001Sglebius int c; 280854359Sroberto FILE *fi; 280954359Sroberto char pbuf[20]; 2810290001Sglebius size_t i; 2811290001Sglebius size_t ilim; 281254359Sroberto 281354359Sroberto#ifndef SYS_WINNT 281454359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 281554359Sroberto#else 2816290001Sglebius if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 281754359Sroberto#endif /* SYS_WINNT */ 281854359Sroberto fi = stdin; 2819290001Sglebius else 282054359Sroberto setbuf(fi, (char *)NULL); 282154359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 2822290001Sglebius for (i = 0, ilim = COUNTOF(pbuf) - 1; 2823290001Sglebius i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2824290001Sglebius ) 2825290001Sglebius pbuf[i++] = (char)c; 2826290001Sglebius pbuf[i] = '\0'; 282754359Sroberto if (fi != stdin) 2828290001Sglebius fclose(fi); 282954359Sroberto 283054359Sroberto return (u_long) atoi(pbuf); 283154359Sroberto} 283254359Sroberto 283354359Sroberto 283454359Sroberto/* 283554359Sroberto * atoascii - printable-ize possibly ascii data using the character 283654359Sroberto * transformations cat -v uses. 283754359Sroberto */ 283854359Srobertostatic void 283954359Srobertoatoascii( 2840290001Sglebius const char *in, 2841290001Sglebius size_t in_octets, 2842290001Sglebius char *out, 2843290001Sglebius size_t out_octets 284454359Sroberto ) 284554359Sroberto{ 2846290001Sglebius const u_char * pchIn; 2847290001Sglebius const u_char * pchInLimit; 2848290001Sglebius u_char * pchOut; 2849290001Sglebius u_char c; 285054359Sroberto 2851290001Sglebius pchIn = (const u_char *)in; 2852290001Sglebius pchInLimit = pchIn + in_octets; 2853290001Sglebius pchOut = (u_char *)out; 2854290001Sglebius 2855290001Sglebius if (NULL == pchIn) { 2856290001Sglebius if (0 < out_octets) 2857290001Sglebius *pchOut = '\0'; 285854359Sroberto return; 285954359Sroberto } 286054359Sroberto 2861290001Sglebius#define ONEOUT(c) \ 2862290001Sglebiusdo { \ 2863290001Sglebius if (0 == --out_octets) { \ 2864290001Sglebius *pchOut = '\0'; \ 2865290001Sglebius return; \ 2866290001Sglebius } \ 2867290001Sglebius *pchOut++ = (c); \ 2868290001Sglebius} while (0) 2869290001Sglebius 2870290001Sglebius for ( ; pchIn < pchInLimit; pchIn++) { 2871290001Sglebius c = *pchIn; 2872290001Sglebius if ('\0' == c) 2873290001Sglebius break; 2874290001Sglebius if (c & 0x80) { 2875290001Sglebius ONEOUT('M'); 2876290001Sglebius ONEOUT('-'); 2877290001Sglebius c &= 0x7f; 287854359Sroberto } 287954359Sroberto if (c < ' ') { 2880290001Sglebius ONEOUT('^'); 2881290001Sglebius ONEOUT((u_char)(c + '@')); 2882290001Sglebius } else if (0x7f == c) { 2883290001Sglebius ONEOUT('^'); 2884290001Sglebius ONEOUT('?'); 2885290001Sglebius } else 2886290001Sglebius ONEOUT(c); 288754359Sroberto } 2888290001Sglebius ONEOUT('\0'); 2889290001Sglebius 2890290001Sglebius#undef ONEOUT 289154359Sroberto} 289254359Sroberto 289354359Sroberto 289454359Sroberto/* 289554359Sroberto * makeascii - print possibly ascii data using the character 289654359Sroberto * transformations that cat -v uses. 289754359Sroberto */ 2898290001Sglebiusvoid 289954359Srobertomakeascii( 2900293896Sglebius size_t length, 2901290001Sglebius const char *data, 290254359Sroberto FILE *fp 290354359Sroberto ) 290454359Sroberto{ 2905290001Sglebius const u_char *data_u_char; 2906290001Sglebius const u_char *cp; 2907290001Sglebius int c; 290854359Sroberto 2909290001Sglebius data_u_char = (const u_char *)data; 2910290001Sglebius 2911290001Sglebius for (cp = data_u_char; cp < data_u_char + length; cp++) { 291254359Sroberto c = (int)*cp; 2913290001Sglebius if (c & 0x80) { 291454359Sroberto putc('M', fp); 291554359Sroberto putc('-', fp); 2916290001Sglebius c &= 0x7f; 291754359Sroberto } 291854359Sroberto 291954359Sroberto if (c < ' ') { 292054359Sroberto putc('^', fp); 2921290001Sglebius putc(c + '@', fp); 2922290001Sglebius } else if (0x7f == c) { 292354359Sroberto putc('^', fp); 292454359Sroberto putc('?', fp); 2925290001Sglebius } else 292654359Sroberto putc(c, fp); 292754359Sroberto } 292854359Sroberto} 292954359Sroberto 293054359Sroberto 293154359Sroberto/* 293254359Sroberto * asciize - same thing as makeascii except add a newline 293354359Sroberto */ 293454359Srobertovoid 293554359Srobertoasciize( 293654359Sroberto int length, 293754359Sroberto char *data, 293854359Sroberto FILE *fp 293954359Sroberto ) 294054359Sroberto{ 294154359Sroberto makeascii(length, data, fp); 294254359Sroberto putc('\n', fp); 294354359Sroberto} 294454359Sroberto 294554359Sroberto 294654359Sroberto/* 2947290001Sglebius * truncate string to fit clipping excess at end. 2948290001Sglebius * "too long" -> "too l" 2949290001Sglebius * Used for hostnames. 2950290001Sglebius */ 2951290001Sglebiusconst char * 2952290001Sglebiustrunc_right( 2953290001Sglebius const char * src, 2954290001Sglebius size_t width 2955290001Sglebius ) 2956290001Sglebius{ 2957290001Sglebius size_t sl; 2958290001Sglebius char * out; 2959290001Sglebius 2960290001Sglebius 2961290001Sglebius sl = strlen(src); 2962290001Sglebius if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 2963290001Sglebius LIB_GETBUF(out); 2964290001Sglebius memcpy(out, src, width); 2965290001Sglebius out[width] = '\0'; 2966290001Sglebius 2967290001Sglebius return out; 2968290001Sglebius } 2969290001Sglebius 2970290001Sglebius return src; 2971290001Sglebius} 2972290001Sglebius 2973290001Sglebius 2974290001Sglebius/* 2975290001Sglebius * truncate string to fit by preserving right side and using '_' to hint 2976290001Sglebius * "too long" -> "_long" 2977290001Sglebius * Used for local IPv6 addresses, where low bits differentiate. 2978290001Sglebius */ 2979290001Sglebiusconst char * 2980290001Sglebiustrunc_left( 2981290001Sglebius const char * src, 2982290001Sglebius size_t width 2983290001Sglebius ) 2984290001Sglebius{ 2985290001Sglebius size_t sl; 2986290001Sglebius char * out; 2987290001Sglebius 2988290001Sglebius 2989290001Sglebius sl = strlen(src); 2990290001Sglebius if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 2991290001Sglebius LIB_GETBUF(out); 2992290001Sglebius out[0] = '_'; 2993290001Sglebius memcpy(&out[1], &src[sl + 1 - width], width); 2994290001Sglebius 2995290001Sglebius return out; 2996290001Sglebius } 2997290001Sglebius 2998290001Sglebius return src; 2999290001Sglebius} 3000290001Sglebius 3001290001Sglebius 3002290001Sglebius/* 300354359Sroberto * Some circular buffer space 300454359Sroberto */ 300554359Sroberto#define CBLEN 80 300654359Sroberto#define NUMCB 6 300754359Sroberto 300854359Srobertochar circ_buf[NUMCB][CBLEN]; 300954359Srobertoint nextcb = 0; 301054359Sroberto 301154359Sroberto/* 301254359Sroberto * nextvar - find the next variable in the buffer 301354359Sroberto */ 301454359Srobertoint 301554359Srobertonextvar( 3016293896Sglebius size_t *datalen, 3017290001Sglebius const char **datap, 301854359Sroberto char **vname, 301954359Sroberto char **vvalue 302054359Sroberto ) 302154359Sroberto{ 3022290001Sglebius const char *cp; 3023290001Sglebius const char *np; 3024290001Sglebius const char *cpend; 3025290001Sglebius size_t srclen; 3026290001Sglebius size_t len; 302754359Sroberto static char name[MAXVARLEN]; 302854359Sroberto static char value[MAXVALLEN]; 302954359Sroberto 303054359Sroberto cp = *datap; 303154359Sroberto cpend = cp + *datalen; 303254359Sroberto 303354359Sroberto /* 303454359Sroberto * Space past commas and white space 303554359Sroberto */ 303654359Sroberto while (cp < cpend && (*cp == ',' || isspace((int)*cp))) 3037290001Sglebius cp++; 3038290001Sglebius if (cp >= cpend) 3039290001Sglebius return 0; 3040290001Sglebius 304154359Sroberto /* 304254359Sroberto * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace 304354359Sroberto * over any white space and terminate it. 304454359Sroberto */ 3045290001Sglebius srclen = strcspn(cp, ",=\r\n"); 3046290001Sglebius srclen = min(srclen, (size_t)(cpend - cp)); 3047290001Sglebius len = srclen; 3048290001Sglebius while (len > 0 && isspace((unsigned char)cp[len - 1])) 3049290001Sglebius len--; 3050294905Sdelphij if (len >= sizeof(name)) 3051294905Sdelphij return 0; 3052290001Sglebius if (len > 0) 3053290001Sglebius memcpy(name, cp, len); 3054290001Sglebius name[len] = '\0'; 305554359Sroberto *vname = name; 3056290001Sglebius cp += srclen; 305754359Sroberto 305854359Sroberto /* 305954359Sroberto * Check if we hit the end of the buffer or a ','. If so we are done. 306054359Sroberto */ 3061290001Sglebius if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { 3062290001Sglebius if (cp < cpend) 3063290001Sglebius cp++; 306454359Sroberto *datap = cp; 3065293896Sglebius *datalen = size2int_sat(cpend - cp); 3066290001Sglebius *vvalue = NULL; 306754359Sroberto return 1; 306854359Sroberto } 306954359Sroberto 307054359Sroberto /* 307154359Sroberto * So far, so good. Copy out the value 307254359Sroberto */ 307354359Sroberto cp++; /* past '=' */ 3074290001Sglebius while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n')) 3075290001Sglebius cp++; 3076290001Sglebius np = cp; 3077290001Sglebius if ('"' == *np) { 3078290001Sglebius do { 3079290001Sglebius np++; 3080290001Sglebius } while (np < cpend && '"' != *np); 3081290001Sglebius if (np < cpend && '"' == *np) 3082290001Sglebius np++; 3083290001Sglebius } else { 3084290001Sglebius while (np < cpend && ',' != *np && '\r' != *np) 3085290001Sglebius np++; 308654359Sroberto } 3087290001Sglebius len = np - cp; 3088290001Sglebius if (np > cpend || len >= sizeof(value) || 3089290001Sglebius (np < cpend && ',' != *np && '\r' != *np)) 3090290001Sglebius return 0; 3091290001Sglebius memcpy(value, cp, len); 309254359Sroberto /* 309354359Sroberto * Trim off any trailing whitespace 309454359Sroberto */ 3095290001Sglebius while (len > 0 && isspace((unsigned char)value[len - 1])) 3096290001Sglebius len--; 3097290001Sglebius value[len] = '\0'; 309854359Sroberto 309954359Sroberto /* 310054359Sroberto * Return this. All done. 310154359Sroberto */ 3102290001Sglebius if (np < cpend && ',' == *np) 3103290001Sglebius np++; 3104290001Sglebius *datap = np; 3105293896Sglebius *datalen = size2int_sat(cpend - np); 310654359Sroberto *vvalue = value; 310754359Sroberto return 1; 310854359Sroberto} 310954359Sroberto 311054359Sroberto 3111290001Sglebiusu_short 3112290001Sglebiusvarfmt(const char * varname) 311354359Sroberto{ 3114290001Sglebius u_int n; 311554359Sroberto 3116290001Sglebius for (n = 0; n < COUNTOF(cookedvars); n++) 3117290001Sglebius if (!strcmp(varname, cookedvars[n].varname)) 3118290001Sglebius return cookedvars[n].fmt; 3119290001Sglebius 3120290001Sglebius return PADDING; 312154359Sroberto} 312254359Sroberto 312354359Sroberto 312454359Sroberto/* 312554359Sroberto * printvars - print variables returned in response packet 312654359Sroberto */ 312754359Srobertovoid 312854359Srobertoprintvars( 3129293896Sglebius size_t length, 3130290001Sglebius const char *data, 313154359Sroberto int status, 313254359Sroberto int sttype, 3133290001Sglebius int quiet, 313454359Sroberto FILE *fp 313554359Sroberto ) 313654359Sroberto{ 313754359Sroberto if (rawmode) 3138290001Sglebius rawprint(sttype, length, data, status, quiet, fp); 313954359Sroberto else 3140290001Sglebius cookedprint(sttype, length, data, status, quiet, fp); 314154359Sroberto} 314254359Sroberto 314354359Sroberto 314454359Sroberto/* 314554359Sroberto * rawprint - do a printout of the data in raw mode 314654359Sroberto */ 314754359Srobertostatic void 314854359Srobertorawprint( 314954359Sroberto int datatype, 3150293896Sglebius size_t length, 3151290001Sglebius const char *data, 315254359Sroberto int status, 3153290001Sglebius int quiet, 315454359Sroberto FILE *fp 315554359Sroberto ) 315654359Sroberto{ 3157290001Sglebius const char *cp; 3158290001Sglebius const char *cpend; 315954359Sroberto 316054359Sroberto /* 316154359Sroberto * Essentially print the data as is. We reformat unprintables, though. 316254359Sroberto */ 316354359Sroberto cp = data; 316454359Sroberto cpend = data + length; 316554359Sroberto 3166290001Sglebius if (!quiet) 3167290001Sglebius (void) fprintf(fp, "status=0x%04x,\n", status); 316854359Sroberto 316954359Sroberto while (cp < cpend) { 317054359Sroberto if (*cp == '\r') { 317154359Sroberto /* 317254359Sroberto * If this is a \r and the next character is a 317354359Sroberto * \n, supress this, else pretty print it. Otherwise 317454359Sroberto * just output the character. 317554359Sroberto */ 3176290001Sglebius if (cp == (cpend - 1) || *(cp + 1) != '\n') 317754359Sroberto makeascii(1, cp, fp); 3178290001Sglebius } else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp)) 317954359Sroberto putc(*cp, fp); 3180290001Sglebius else 318154359Sroberto makeascii(1, cp, fp); 318254359Sroberto cp++; 318354359Sroberto } 318454359Sroberto} 318554359Sroberto 318654359Sroberto 318754359Sroberto/* 318854359Sroberto * Global data used by the cooked output routines 318954359Sroberto */ 319054359Srobertoint out_chars; /* number of characters output */ 319154359Srobertoint out_linecount; /* number of characters output on this line */ 319254359Sroberto 319354359Sroberto 319454359Sroberto/* 319554359Sroberto * startoutput - get ready to do cooked output 319654359Sroberto */ 319754359Srobertostatic void 319854359Srobertostartoutput(void) 319954359Sroberto{ 320054359Sroberto out_chars = 0; 320154359Sroberto out_linecount = 0; 320254359Sroberto} 320354359Sroberto 320454359Sroberto 320554359Sroberto/* 320654359Sroberto * output - output a variable=value combination 320754359Sroberto */ 320854359Srobertostatic void 320954359Srobertooutput( 321054359Sroberto FILE *fp, 3211290001Sglebius const char *name, 3212290001Sglebius const char *value 321354359Sroberto ) 321454359Sroberto{ 3215293896Sglebius int len; 321654359Sroberto 3217290001Sglebius /* strlen of "name=value" */ 3218293896Sglebius len = size2int_sat(strlen(name) + 1 + strlen(value)); 321954359Sroberto 322054359Sroberto if (out_chars != 0) { 3221290001Sglebius out_chars += 2; 3222290001Sglebius if ((out_linecount + len + 2) > MAXOUTLINE) { 3223290001Sglebius fputs(",\n", fp); 322454359Sroberto out_linecount = 0; 322554359Sroberto } else { 3226290001Sglebius fputs(", ", fp); 3227290001Sglebius out_linecount += 2; 322854359Sroberto } 322954359Sroberto } 323054359Sroberto 323154359Sroberto fputs(name, fp); 323254359Sroberto putc('=', fp); 323354359Sroberto fputs(value, fp); 3234290001Sglebius out_chars += len; 3235290001Sglebius out_linecount += len; 323654359Sroberto} 323754359Sroberto 323854359Sroberto 323954359Sroberto/* 324054359Sroberto * endoutput - terminate a block of cooked output 324154359Sroberto */ 324254359Srobertostatic void 324354359Srobertoendoutput( 324454359Sroberto FILE *fp 324554359Sroberto ) 324654359Sroberto{ 324754359Sroberto if (out_chars != 0) 3248290001Sglebius putc('\n', fp); 324954359Sroberto} 325054359Sroberto 325154359Sroberto 325254359Sroberto/* 325354359Sroberto * outputarr - output an array of values 325454359Sroberto */ 325554359Srobertostatic void 325654359Srobertooutputarr( 325754359Sroberto FILE *fp, 325854359Sroberto char *name, 325954359Sroberto int narr, 326054359Sroberto l_fp *lfp 326154359Sroberto ) 326254359Sroberto{ 3263293896Sglebius char *bp; 3264293896Sglebius char *cp; 3265293896Sglebius size_t i; 3266293896Sglebius size_t len; 326754359Sroberto char buf[256]; 326854359Sroberto 326954359Sroberto bp = buf; 327054359Sroberto /* 327154359Sroberto * Hack to align delay and offset values 327254359Sroberto */ 327354359Sroberto for (i = (int)strlen(name); i < 11; i++) 327454359Sroberto *bp++ = ' '; 3275290001Sglebius 327654359Sroberto for (i = narr; i > 0; i--) { 327754359Sroberto if (i != narr) 327854359Sroberto *bp++ = ' '; 327954359Sroberto cp = lfptoms(lfp, 2); 328054359Sroberto len = strlen(cp); 328154359Sroberto if (len > 7) { 328254359Sroberto cp[7] = '\0'; 328354359Sroberto len = 7; 328454359Sroberto } 328554359Sroberto while (len < 7) { 328654359Sroberto *bp++ = ' '; 328754359Sroberto len++; 328854359Sroberto } 328954359Sroberto while (*cp != '\0') 329054359Sroberto *bp++ = *cp++; 329154359Sroberto lfp++; 329254359Sroberto } 329354359Sroberto *bp = '\0'; 329454359Sroberto output(fp, name, buf); 329554359Sroberto} 329654359Sroberto 329754359Srobertostatic char * 329854359Srobertotstflags( 329954359Sroberto u_long val 330054359Sroberto ) 330154359Sroberto{ 3302290001Sglebius register char *cp, *s; 3303290001Sglebius size_t cb; 330454359Sroberto register int i; 330554359Sroberto register const char *sep; 330654359Sroberto 330754359Sroberto sep = ""; 3308290001Sglebius s = cp = circ_buf[nextcb]; 330954359Sroberto if (++nextcb >= NUMCB) 3310290001Sglebius nextcb = 0; 3311290001Sglebius cb = sizeof(circ_buf[0]); 331254359Sroberto 3313290001Sglebius snprintf(cp, cb, "%02lx", val); 3314290001Sglebius cp += strlen(cp); 3315290001Sglebius cb -= strlen(cp); 331654359Sroberto if (!val) { 3317290001Sglebius strlcat(cp, " ok", cb); 3318290001Sglebius cp += strlen(cp); 3319290001Sglebius cb -= strlen(cp); 332054359Sroberto } else { 3321290001Sglebius if (cb) { 3322290001Sglebius *cp++ = ' '; 3323290001Sglebius cb--; 3324290001Sglebius } 3325290001Sglebius for (i = 0; i < (int)COUNTOF(tstflagnames); i++) { 332654359Sroberto if (val & 0x1) { 3327290001Sglebius snprintf(cp, cb, "%s%s", sep, 3328290001Sglebius tstflagnames[i]); 332954359Sroberto sep = ", "; 3330290001Sglebius cp += strlen(cp); 3331290001Sglebius cb -= strlen(cp); 333254359Sroberto } 333354359Sroberto val >>= 1; 333454359Sroberto } 333554359Sroberto } 3336290001Sglebius if (cb) 3337290001Sglebius *cp = '\0'; 3338290001Sglebius 333954359Sroberto return s; 334054359Sroberto} 334154359Sroberto 334254359Sroberto/* 334354359Sroberto * cookedprint - output variables in cooked mode 334454359Sroberto */ 334554359Srobertostatic void 334654359Srobertocookedprint( 334754359Sroberto int datatype, 3348293896Sglebius size_t length, 3349290001Sglebius const char *data, 335054359Sroberto int status, 3351290001Sglebius int quiet, 335254359Sroberto FILE *fp 335354359Sroberto ) 335454359Sroberto{ 335554359Sroberto char *name; 335654359Sroberto char *value; 3357132451Sroberto char output_raw; 335854359Sroberto int fmt; 335954359Sroberto l_fp lfp; 3360290001Sglebius sockaddr_u hval; 336154359Sroberto u_long uval; 3362290001Sglebius int narr; 3363290001Sglebius size_t len; 336454359Sroberto l_fp lfparr[8]; 3365290001Sglebius char b[12]; 3366290001Sglebius char bn[2 * MAXVARLEN]; 3367290001Sglebius char bv[2 * MAXVALLEN]; 336854359Sroberto 3369290001Sglebius UNUSED_ARG(datatype); 337054359Sroberto 3371290001Sglebius if (!quiet) 3372290001Sglebius fprintf(fp, "status=%04x %s,\n", status, 3373290001Sglebius statustoa(datatype, status)); 337454359Sroberto 337554359Sroberto startoutput(); 337654359Sroberto while (nextvar(&length, &data, &name, &value)) { 3377290001Sglebius fmt = varfmt(name); 3378290001Sglebius output_raw = 0; 3379290001Sglebius switch (fmt) { 3380290001Sglebius 3381290001Sglebius case PADDING: 338254359Sroberto output_raw = '*'; 3383290001Sglebius break; 338454359Sroberto 3385290001Sglebius case TS: 3386290001Sglebius if (!decodets(value, &lfp)) 3387290001Sglebius output_raw = '?'; 3388290001Sglebius else 3389290001Sglebius output(fp, name, prettydate(&lfp)); 3390290001Sglebius break; 339154359Sroberto 3392290001Sglebius case HA: /* fallthru */ 3393290001Sglebius case NA: 3394290001Sglebius if (!decodenetnum(value, &hval)) { 3395290001Sglebius output_raw = '?'; 3396290001Sglebius } else if (fmt == HA){ 3397290001Sglebius output(fp, name, nntohost(&hval)); 3398290001Sglebius } else { 3399290001Sglebius output(fp, name, stoa(&hval)); 3400290001Sglebius } 3401290001Sglebius break; 340254359Sroberto 3403290001Sglebius case RF: 3404290001Sglebius if (decodenetnum(value, &hval)) { 3405290001Sglebius if (ISREFCLOCKADR(&hval)) 3406290001Sglebius output(fp, name, 3407290001Sglebius refnumtoa(&hval)); 340854359Sroberto else 3409290001Sglebius output(fp, name, stoa(&hval)); 3410290001Sglebius } else if (strlen(value) <= 4) { 3411290001Sglebius output(fp, name, value); 3412290001Sglebius } else { 3413290001Sglebius output_raw = '?'; 3414290001Sglebius } 3415290001Sglebius break; 341654359Sroberto 3417290001Sglebius case LP: 3418290001Sglebius if (!decodeuint(value, &uval) || uval > 3) { 3419290001Sglebius output_raw = '?'; 3420290001Sglebius } else { 3421290001Sglebius b[0] = (0x2 & uval) 3422290001Sglebius ? '1' 3423290001Sglebius : '0'; 3424290001Sglebius b[1] = (0x1 & uval) 3425290001Sglebius ? '1' 3426290001Sglebius : '0'; 3427290001Sglebius b[2] = '\0'; 3428290001Sglebius output(fp, name, b); 342954359Sroberto } 3430290001Sglebius break; 343154359Sroberto 3432290001Sglebius case OC: 3433290001Sglebius if (!decodeuint(value, &uval)) { 3434290001Sglebius output_raw = '?'; 3435290001Sglebius } else { 3436290001Sglebius snprintf(b, sizeof(b), "%03lo", uval); 3437290001Sglebius output(fp, name, b); 3438290001Sglebius } 3439290001Sglebius break; 3440290001Sglebius 3441290001Sglebius case AR: 3442290001Sglebius if (!decodearr(value, &narr, lfparr)) 3443290001Sglebius output_raw = '?'; 3444290001Sglebius else 3445290001Sglebius outputarr(fp, name, narr, lfparr); 3446290001Sglebius break; 3447290001Sglebius 3448290001Sglebius case FX: 3449290001Sglebius if (!decodeuint(value, &uval)) 3450290001Sglebius output_raw = '?'; 3451290001Sglebius else 3452290001Sglebius output(fp, name, tstflags(uval)); 3453290001Sglebius break; 3454290001Sglebius 3455290001Sglebius default: 3456290001Sglebius fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3457290001Sglebius name, value, fmt); 3458290001Sglebius output_raw = '?'; 3459290001Sglebius break; 346054359Sroberto } 3461290001Sglebius 346254359Sroberto if (output_raw != 0) { 3463290001Sglebius /* TALOS-CAN-0063: avoid buffer overrun */ 3464290001Sglebius atoascii(name, MAXVARLEN, bn, sizeof(bn)); 346554359Sroberto if (output_raw != '*') { 3466290001Sglebius atoascii(value, MAXVALLEN, 3467290001Sglebius bv, sizeof(bv) - 1); 346854359Sroberto len = strlen(bv); 346954359Sroberto bv[len] = output_raw; 347054359Sroberto bv[len+1] = '\0'; 3471290001Sglebius } else { 3472290001Sglebius atoascii(value, MAXVALLEN, 3473290001Sglebius bv, sizeof(bv)); 347454359Sroberto } 347554359Sroberto output(fp, bn, bv); 347654359Sroberto } 347754359Sroberto } 347854359Sroberto endoutput(fp); 347954359Sroberto} 348054359Sroberto 348154359Sroberto 348254359Sroberto/* 348354359Sroberto * sortassoc - sort associations in the cache into ascending order 348454359Sroberto */ 348554359Srobertovoid 348654359Srobertosortassoc(void) 348754359Sroberto{ 348854359Sroberto if (numassoc > 1) 3489290001Sglebius qsort(assoc_cache, (size_t)numassoc, 3490290001Sglebius sizeof(assoc_cache[0]), &assoccmp); 349154359Sroberto} 349254359Sroberto 349354359Sroberto 349454359Sroberto/* 349554359Sroberto * assoccmp - compare two associations 349654359Sroberto */ 349754359Srobertostatic int 349854359Srobertoassoccmp( 349954359Sroberto const void *t1, 350054359Sroberto const void *t2 350154359Sroberto ) 350254359Sroberto{ 3503290001Sglebius const struct association *ass1 = t1; 3504290001Sglebius const struct association *ass2 = t2; 350554359Sroberto 350654359Sroberto if (ass1->assid < ass2->assid) 3507290001Sglebius return -1; 350854359Sroberto if (ass1->assid > ass2->assid) 3509290001Sglebius return 1; 351054359Sroberto return 0; 351154359Sroberto} 3512290001Sglebius 3513290001Sglebius 3514290001Sglebius/* 3515290001Sglebius * grow_assoc_cache() - enlarge dynamic assoc_cache array 3516290001Sglebius * 3517290001Sglebius * The strategy is to add an assumed 4k page size at a time, leaving 3518290001Sglebius * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3519290001Sglebius */ 3520290001Sglebiusvoid 3521290001Sglebiusgrow_assoc_cache(void) 3522290001Sglebius{ 3523290001Sglebius static size_t prior_sz; 3524290001Sglebius size_t new_sz; 3525290001Sglebius 3526290001Sglebius new_sz = prior_sz + 4 * 1024; 3527290001Sglebius if (0 == prior_sz) { 3528290001Sglebius new_sz -= 4 * sizeof(void *); 3529290001Sglebius } 3530290001Sglebius assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3531290001Sglebius prior_sz = new_sz; 3532293896Sglebius assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3533290001Sglebius} 3534290001Sglebius 3535290001Sglebius 3536290001Sglebius/* 3537290001Sglebius * ntpq_custom_opt_handler - autoopts handler for -c and -p 3538290001Sglebius * 3539290001Sglebius * By default, autoopts loses the relative order of -c and -p options 3540290001Sglebius * on the command line. This routine replaces the default handler for 3541290001Sglebius * those routines and builds a list of commands to execute preserving 3542290001Sglebius * the order. 3543290001Sglebius */ 3544290001Sglebiusvoid 3545290001Sglebiusntpq_custom_opt_handler( 3546290001Sglebius tOptions *pOptions, 3547290001Sglebius tOptDesc *pOptDesc 354854359Sroberto ) 354954359Sroberto{ 3550290001Sglebius switch (pOptDesc->optValue) { 3551290001Sglebius 3552290001Sglebius default: 3553290001Sglebius fprintf(stderr, 3554290001Sglebius "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3555290001Sglebius pOptDesc->optValue, pOptDesc->optValue); 3556290001Sglebius exit(1); 3557290001Sglebius 3558290001Sglebius case 'c': 3559290001Sglebius ADDCMD(pOptDesc->pzLastArg); 3560290001Sglebius break; 3561290001Sglebius 3562290001Sglebius case 'p': 3563290001Sglebius ADDCMD("peers"); 3564290001Sglebius break; 3565290001Sglebius } 356654359Sroberto} 3567290001Sglebius/* 3568290001Sglebius * Obtain list of digest names 3569290001Sglebius */ 3570290001Sglebius 3571290001Sglebius#ifdef OPENSSL 3572290001Sglebius# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3573290001Sglebiusstruct hstate { 3574290001Sglebius char *list; 3575290001Sglebius const char **seen; 3576290001Sglebius int idx; 3577290001Sglebius}; 3578290001Sglebius#define K_PER_LINE 8 3579290001Sglebius#define K_NL_PFX_STR "\n " 3580290001Sglebius#define K_DELIM_STR ", " 3581290001Sglebiusstatic void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg ) 3582290001Sglebius{ 3583290001Sglebius size_t len, n; 3584290001Sglebius const char *name, *cp, **seen; 3585290001Sglebius struct hstate *hstate = arg; 3586310419Sdelphij EVP_MD_CTX *ctx; 3587290001Sglebius u_int digest_len; 3588290001Sglebius u_char digest[EVP_MAX_MD_SIZE]; 3589290001Sglebius 3590290001Sglebius if (!m) 3591290001Sglebius return; /* Ignore aliases */ 3592290001Sglebius 3593290001Sglebius name = EVP_MD_name(m); 3594290001Sglebius 3595290001Sglebius /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */ 3596290001Sglebius 3597290001Sglebius for( cp = name; *cp; cp++ ) { 3598290001Sglebius if( islower(*cp) ) 3599290001Sglebius return; 3600290001Sglebius } 3601290001Sglebius len = (cp - name) + 1; 3602290001Sglebius 3603290001Sglebius /* There are duplicates. Discard if name has been seen. */ 3604290001Sglebius 3605290001Sglebius for (seen = hstate->seen; *seen; seen++) 3606290001Sglebius if (!strcmp(*seen, name)) 3607290001Sglebius return; 3608290001Sglebius n = (seen - hstate->seen) + 2; 3609290001Sglebius hstate->seen = erealloc(hstate->seen, n * sizeof(*seen)); 3610290001Sglebius hstate->seen[n-2] = name; 3611290001Sglebius hstate->seen[n-1] = NULL; 3612290001Sglebius 3613290001Sglebius /* Discard MACs that NTP won't accept. 3614290001Sglebius * Keep this consistent with keytype_from_text() in ssl_init.c. 3615290001Sglebius */ 3616290001Sglebius 3617310419Sdelphij ctx = EVP_MD_CTX_new(); 3618310419Sdelphij EVP_DigestInit(ctx, EVP_get_digestbyname(name)); 3619310419Sdelphij EVP_DigestFinal(ctx, digest, &digest_len); 3620310419Sdelphij EVP_MD_CTX_free(ctx); 3621290001Sglebius if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t))) 3622290001Sglebius return; 3623290001Sglebius 3624290001Sglebius if (hstate->list != NULL) 3625290001Sglebius len += strlen(hstate->list); 3626290001Sglebius len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR); 3627290001Sglebius 3628290001Sglebius if (hstate->list == NULL) { 3629290001Sglebius hstate->list = (char *)emalloc(len); 3630290001Sglebius hstate->list[0] = '\0'; 3631290001Sglebius } else 3632290001Sglebius hstate->list = (char *)erealloc(hstate->list, len); 3633290001Sglebius 3634290001Sglebius sprintf(hstate->list + strlen(hstate->list), "%s%s", 3635290001Sglebius ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR), 3636290001Sglebius name); 3637290001Sglebius if (hstate->idx >= K_PER_LINE) 3638290001Sglebius hstate->idx = 1; 3639290001Sglebius else 3640290001Sglebius hstate->idx++; 3641290001Sglebius} 3642290001Sglebius# endif 3643290001Sglebius#endif 3644290001Sglebius 3645290001Sglebiusstatic char *list_digest_names(void) 3646290001Sglebius{ 3647290001Sglebius char *list = NULL; 3648290001Sglebius 3649290001Sglebius#ifdef OPENSSL 3650290001Sglebius# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3651290001Sglebius struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 3652290001Sglebius 3653290001Sglebius hstate.seen = (const char **) emalloc_zero(1*sizeof( const char * )); // replaces -> calloc(1, sizeof( const char * )); 3654290001Sglebius 3655290001Sglebius INIT_SSL(); 3656290001Sglebius EVP_MD_do_all_sorted(list_md_fn, &hstate); 3657290001Sglebius list = hstate.list; 3658290001Sglebius free(hstate.seen); 3659290001Sglebius# else 3660290001Sglebius list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 3661290001Sglebius strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 3662290001Sglebius# endif 3663290001Sglebius#else 3664290001Sglebius list = (char *)emalloc(sizeof("md5")); 3665290001Sglebius strcpy(list, "md5"); 3666290001Sglebius#endif 3667290001Sglebius 3668290001Sglebius return list; 3669290001Sglebius} 3670293896Sglebius 3671293896Sglebius#define CTRLC_STACK_MAX 4 3672293896Sglebiusstatic volatile size_t ctrlc_stack_len = 0; 3673293896Sglebiusstatic volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 3674293896Sglebius 3675293896Sglebius 3676293896Sglebius 3677293896Sglebiusint/*BOOL*/ 3678293896Sglebiuspush_ctrl_c_handler( 3679293896Sglebius Ctrl_C_Handler func 3680293896Sglebius ) 3681293896Sglebius{ 3682293896Sglebius size_t size = ctrlc_stack_len; 3683293896Sglebius if (func && (size < CTRLC_STACK_MAX)) { 3684293896Sglebius ctrlc_stack[size] = func; 3685293896Sglebius ctrlc_stack_len = size + 1; 3686293896Sglebius return TRUE; 3687293896Sglebius } 3688293896Sglebius return FALSE; 3689293896Sglebius} 3690293896Sglebius 3691293896Sglebiusint/*BOOL*/ 3692293896Sglebiuspop_ctrl_c_handler( 3693293896Sglebius Ctrl_C_Handler func 3694293896Sglebius ) 3695293896Sglebius{ 3696293896Sglebius size_t size = ctrlc_stack_len; 3697293896Sglebius if (size) { 3698293896Sglebius --size; 3699293896Sglebius if (func == NULL || func == ctrlc_stack[size]) { 3700293896Sglebius ctrlc_stack_len = size; 3701293896Sglebius return TRUE; 3702293896Sglebius } 3703293896Sglebius } 3704293896Sglebius return FALSE; 3705293896Sglebius} 3706293896Sglebius 3707293896Sglebiusstatic void 3708293896Sglebiuson_ctrlc(void) 3709293896Sglebius{ 3710293896Sglebius size_t size = ctrlc_stack_len; 3711293896Sglebius while (size) 3712293896Sglebius if ((*ctrlc_stack[--size])()) 3713293896Sglebius break; 3714293896Sglebius} 3715294905Sdelphij 3716294905Sdelphijstatic int 3717294905Sdelphijmy_easprintf( 3718294905Sdelphij char ** ppinto, 3719294905Sdelphij const char * fmt , 3720294905Sdelphij ... 3721294905Sdelphij ) 3722294905Sdelphij{ 3723294905Sdelphij va_list va; 3724294905Sdelphij int prc; 3725294905Sdelphij size_t len = 128; 3726294905Sdelphij char * buf = emalloc(len); 3727294905Sdelphij 3728294905Sdelphij again: 3729294905Sdelphij /* Note: we expect the memory allocation to fail long before the 3730294905Sdelphij * increment in buffer size actually overflows. 3731294905Sdelphij */ 3732294905Sdelphij buf = (buf) ? erealloc(buf, len) : emalloc(len); 3733294905Sdelphij 3734294905Sdelphij va_start(va, fmt); 3735294905Sdelphij prc = vsnprintf(buf, len, fmt, va); 3736294905Sdelphij va_end(va); 3737294905Sdelphij 3738294905Sdelphij if (prc < 0) { 3739294905Sdelphij /* might be very old vsnprintf. Or actually MSVC... */ 3740294905Sdelphij len += len >> 1; 3741294905Sdelphij goto again; 3742294905Sdelphij } 3743294905Sdelphij if ((size_t)prc >= len) { 3744294905Sdelphij /* at least we have the proper size now... */ 3745294905Sdelphij len = (size_t)prc + 1; 3746294905Sdelphij goto again; 3747294905Sdelphij } 3748294905Sdelphij if ((size_t)prc < (len - 32)) 3749294905Sdelphij buf = erealloc(buf, (size_t)prc + 1); 3750294905Sdelphij *ppinto = buf; 3751294905Sdelphij return prc; 3752294905Sdelphij} 3753