154359Sroberto/* 254359Sroberto * ntpq - query an NTP server using mode 6 commands 354359Sroberto */ 4285612Sdelphij#include <config.h> 5182007Sroberto#include <ctype.h> 6182007Sroberto#include <signal.h> 7182007Sroberto#include <setjmp.h> 8330567Sgordon#include <stddef.h> 9330567Sgordon#include <stdio.h> 10182007Sroberto#include <sys/types.h> 11182007Sroberto#include <sys/time.h> 12285612Sdelphij#ifdef HAVE_UNISTD_H 13285612Sdelphij# include <unistd.h> 14285612Sdelphij#endif 15285612Sdelphij#ifdef HAVE_FCNTL_H 16285612Sdelphij# include <fcntl.h> 17285612Sdelphij#endif 18285612Sdelphij#ifdef SYS_WINNT 19285612Sdelphij# include <mswsock.h> 20285612Sdelphij#endif 21285612Sdelphij#include <isc/net.h> 22285612Sdelphij#include <isc/result.h> 23182007Sroberto 2482498Sroberto#include "ntpq.h" 25285612Sdelphij#include "ntp_assert.h" 26285612Sdelphij#include "ntp_stdlib.h" 2782498Sroberto#include "ntp_unixtime.h" 2882498Sroberto#include "ntp_calendar.h" 2982498Sroberto#include "ntp_select.h" 30285612Sdelphij#include "ntp_assert.h" 31285612Sdelphij#include "lib_strbuf.h" 32285612Sdelphij#include "ntp_lineedit.h" 33285612Sdelphij#include "ntp_debug.h" 34285612Sdelphij#ifdef OPENSSL 35285612Sdelphij#include "openssl/evp.h" 36285612Sdelphij#include "openssl/objects.h" 37285612Sdelphij#include "openssl/err.h" 38330567Sgordon#ifdef SYS_WINNT 39330567Sgordon# include "openssl/opensslv.h" 40330567Sgordon# if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L 41330567Sgordon# define HAVE_EVP_MD_DO_ALL_SORTED 1 42330567Sgordon# endif 43330567Sgordon#endif 44310419Sdelphij#include "libssl_compat.h" 45330567Sgordon 46330567Sgordon#define CMAC "AES128CMAC" 47285612Sdelphij#endif 48285612Sdelphij#include <ssl_applink.c> 4982498Sroberto 50285612Sdelphij#include "ntp_libopts.h" 51293650Sglebius#include "safecast.h" 52182007Sroberto 53285612Sdelphij#ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 54182007Sroberto# define open(name, flags) open(name, flags, 0777) 55182007Sroberto# define SERVER_PORT_NUM 123 5654359Sroberto#endif 5754359Sroberto 58182007Sroberto/* we use COMMAND as an autogen keyword */ 59182007Sroberto#ifdef COMMAND 60182007Sroberto# undef COMMAND 61182007Sroberto#endif 62182007Sroberto 6354359Sroberto/* 6454359Sroberto * Because we potentially understand a lot of commands we will run 6554359Sroberto * interactive if connected to a terminal. 6654359Sroberto */ 6754359Srobertoint interactive = 0; /* set to 1 when we should prompt */ 6854359Srobertoconst char *prompt = "ntpq> "; /* prompt to ask him about */ 6954359Sroberto 70285612Sdelphij/* 71285612Sdelphij * use old readvars behavior? --old-rv processing in ntpq resets 72285612Sdelphij * this value based on the presence or absence of --old-rv. It is 73285612Sdelphij * initialized to 1 here to maintain backward compatibility with 74285612Sdelphij * libntpq clients such as ntpsnmpd, which are free to reset it as 75285612Sdelphij * desired. 76285612Sdelphij */ 77285612Sdelphijint old_rv = 1; 7854359Sroberto 79298770Sdelphij/* 80298770Sdelphij * How should we display the refid? 81298770Sdelphij * REFID_HASH, REFID_IPV4 82298770Sdelphij */ 83298770Sdelphijte_Refid drefid = -1; 84285612Sdelphij 8554359Sroberto/* 86182007Sroberto * for get_systime() 87182007Sroberto */ 88182007Srobertos_char sys_precision; /* local clock precision (log2 s) */ 89182007Sroberto 90182007Sroberto/* 9154359Sroberto * Keyid used for authenticated requests. Obtained on the fly. 9254359Sroberto */ 93132451Srobertou_long info_auth_keyid = 0; 9454359Sroberto 95285612Sdelphijstatic int info_auth_keytype = NID_md5; /* MD5 */ 96285612Sdelphijstatic size_t info_auth_hashlen = 16; /* MD5 */ 9754359Srobertou_long current_time; /* needed by authkeys; not used */ 9854359Sroberto 9954359Sroberto/* 10054359Sroberto * Flag which indicates we should always send authenticated requests 10154359Sroberto */ 10254359Srobertoint always_auth = 0; 10354359Sroberto 10454359Sroberto/* 10554359Sroberto * Flag which indicates raw mode output. 10654359Sroberto */ 10754359Srobertoint rawmode = 0; 10854359Sroberto 10954359Sroberto/* 11054359Sroberto * Packet version number we use 11154359Sroberto */ 11254359Srobertou_char pktversion = NTP_OLDVERSION + 1; 11354359Sroberto 11454359Sroberto/* 11554359Sroberto * Don't jump if no set jmp. 11654359Sroberto */ 11754359Srobertovolatile int jump = 0; 11854359Sroberto 11954359Sroberto/* 12054359Sroberto * Format values 12154359Sroberto */ 12254359Sroberto#define PADDING 0 123285612Sdelphij#define HA 1 /* host address */ 124285612Sdelphij#define NA 2 /* network address */ 125285612Sdelphij#define LP 3 /* leap (print in binary) */ 126285612Sdelphij#define RF 4 /* refid (sometimes string, sometimes not) */ 127285612Sdelphij#define AR 5 /* array of times */ 128285612Sdelphij#define FX 6 /* test flags */ 129285612Sdelphij#define TS 7 /* l_fp timestamp in hex */ 130285612Sdelphij#define OC 8 /* integer, print in octal */ 13154359Sroberto#define EOV 255 /* end of table */ 13254359Sroberto 13354359Sroberto/* 134285612Sdelphij * For the most part ntpq simply displays what ntpd provides in the 135285612Sdelphij * mostly plain-text mode 6 responses. A few variable names are by 136285612Sdelphij * default "cooked" to provide more human-friendly output. 13754359Sroberto */ 138285612Sdelphijconst var_format cookedvars[] = { 139285612Sdelphij { "leap", LP }, 140285612Sdelphij { "reach", OC }, 141285612Sdelphij { "refid", RF }, 142285612Sdelphij { "reftime", TS }, 143285612Sdelphij { "clock", TS }, 144285612Sdelphij { "org", TS }, 145285612Sdelphij { "rec", TS }, 146285612Sdelphij { "xmt", TS }, 147285612Sdelphij { "flash", FX }, 148285612Sdelphij { "srcadr", HA }, 149285612Sdelphij { "peeradr", HA }, /* compat with others */ 150285612Sdelphij { "dstadr", NA }, 151285612Sdelphij { "filtdelay", AR }, 152285612Sdelphij { "filtoffset", AR }, 153285612Sdelphij { "filtdisp", AR }, 154285612Sdelphij { "filterror", AR }, /* compat with others */ 15554359Sroberto}; 15654359Sroberto 15754359Sroberto 15854359Sroberto 15954359Sroberto/* 16054359Sroberto * flasher bits 16154359Sroberto */ 16254359Srobertostatic const char *tstflagnames[] = { 163182007Sroberto "pkt_dup", /* TEST1 */ 164182007Sroberto "pkt_bogus", /* TEST2 */ 165285612Sdelphij "pkt_unsync", /* TEST3 */ 166182007Sroberto "pkt_denied", /* TEST4 */ 167182007Sroberto "pkt_auth", /* TEST5 */ 168285612Sdelphij "pkt_stratum", /* TEST6 */ 169285612Sdelphij "pkt_header", /* TEST7 */ 170182007Sroberto "pkt_autokey", /* TEST8 */ 171182007Sroberto "pkt_crypto", /* TEST9 */ 172182007Sroberto "peer_stratum", /* TEST10 */ 173182007Sroberto "peer_dist", /* TEST11 */ 174182007Sroberto "peer_loop", /* TEST12 */ 175285612Sdelphij "peer_unreach" /* TEST13 */ 17654359Sroberto}; 17754359Sroberto 17854359Sroberto 179285612Sdelphijint ntpqmain (int, char **); 18054359Sroberto/* 18154359Sroberto * Built in command handler declarations 18254359Sroberto */ 183285612Sdelphijstatic int openhost (const char *, int); 184285612Sdelphijstatic void dump_hex_printable(const void *, size_t); 185285612Sdelphijstatic int sendpkt (void *, size_t); 186293650Sglebiusstatic int getresponse (int, int, u_short *, size_t *, const char **, int); 187293650Sglebiusstatic int sendrequest (int, associd_t, int, size_t, const char *); 188285612Sdelphijstatic char * tstflags (u_long); 189285612Sdelphij#ifndef BUILD_AS_LIB 190285612Sdelphijstatic void getcmds (void); 191285612Sdelphij#ifndef SYS_WINNT 192293650Sglebiusstatic int abortcmd (void); 193285612Sdelphij#endif /* SYS_WINNT */ 194285612Sdelphijstatic void docmd (const char *); 195285612Sdelphijstatic void tokenize (const char *, char **, int *); 196285612Sdelphijstatic int getarg (const char *, int, arg_v *); 197285612Sdelphij#endif /* BUILD_AS_LIB */ 198285612Sdelphijstatic int findcmd (const char *, struct xcmd *, 199285612Sdelphij struct xcmd *, struct xcmd **); 200285612Sdelphijstatic int rtdatetolfp (char *, l_fp *); 201330567Sgordonstatic int decodearr (char *, int *, l_fp *, int); 202285612Sdelphijstatic void help (struct parse *, FILE *); 203285612Sdelphijstatic int helpsort (const void *, const void *); 204285612Sdelphijstatic void printusage (struct xcmd *, FILE *); 205285612Sdelphijstatic void timeout (struct parse *, FILE *); 206285612Sdelphijstatic void auth_delay (struct parse *, FILE *); 207285612Sdelphijstatic void host (struct parse *, FILE *); 208285612Sdelphijstatic void ntp_poll (struct parse *, FILE *); 209285612Sdelphijstatic void keyid (struct parse *, FILE *); 210285612Sdelphijstatic void keytype (struct parse *, FILE *); 211285612Sdelphijstatic void passwd (struct parse *, FILE *); 212285612Sdelphijstatic void hostnames (struct parse *, FILE *); 213285612Sdelphijstatic void setdebug (struct parse *, FILE *); 214285612Sdelphijstatic void quit (struct parse *, FILE *); 215298770Sdelphijstatic void showdrefid (struct parse *, FILE *); 216285612Sdelphijstatic void version (struct parse *, FILE *); 217285612Sdelphijstatic void raw (struct parse *, FILE *); 218285612Sdelphijstatic void cooked (struct parse *, FILE *); 219285612Sdelphijstatic void authenticate (struct parse *, FILE *); 220285612Sdelphijstatic void ntpversion (struct parse *, FILE *); 221285612Sdelphijstatic void warning (const char *, ...) 222285612Sdelphij __attribute__((__format__(__printf__, 1, 2))); 223285612Sdelphijstatic void error (const char *, ...) 224285612Sdelphij __attribute__((__format__(__printf__, 1, 2))); 225285612Sdelphijstatic u_long getkeyid (const char *); 226285612Sdelphijstatic void atoascii (const char *, size_t, char *, size_t); 227293650Sglebiusstatic void cookedprint (int, size_t, const char *, int, int, FILE *); 228293650Sglebiusstatic void rawprint (int, size_t, const char *, int, int, FILE *); 229285612Sdelphijstatic void startoutput (void); 230285612Sdelphijstatic void output (FILE *, const char *, const char *); 231285612Sdelphijstatic void endoutput (FILE *); 232285612Sdelphijstatic void outputarr (FILE *, char *, int, l_fp *); 233285612Sdelphijstatic int assoccmp (const void *, const void *); 234293650Sglebiusstatic void on_ctrlc (void); 235285612Sdelphij u_short varfmt (const char *); 236294569Sdelphijstatic int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 237285612Sdelphijvoid ntpq_custom_opt_handler (tOptions *, tOptDesc *); 238285612Sdelphij 239330567Sgordon/* read a character from memory and expand to integer */ 240330567Sgordonstatic inline int 241330567Sgordonpgetc( 242330567Sgordon const char *cp 243330567Sgordon ) 244330567Sgordon{ 245330567Sgordon return (int)*(const unsigned char*)cp; 246330567Sgordon} 247330567Sgordon 248330567Sgordon 249285612Sdelphij#ifdef OPENSSL 250285612Sdelphij# ifdef HAVE_EVP_MD_DO_ALL_SORTED 251285612Sdelphijstatic void list_md_fn(const EVP_MD *m, const char *from, 252285612Sdelphij const char *to, void *arg ); 253285612Sdelphij# endif 25454359Sroberto#endif 255330567Sgordonstatic char *insert_cmac(char *list); 256285612Sdelphijstatic char *list_digest_names(void); 25754359Sroberto 25854359Sroberto/* 25954359Sroberto * Built-in commands we understand 26054359Sroberto */ 26154359Srobertostruct xcmd builtins[] = { 262182007Sroberto { "?", help, { OPT|NTP_STR, NO, NO, NO }, 26354359Sroberto { "command", "", "", "" }, 26454359Sroberto "tell the use and syntax of commands" }, 265182007Sroberto { "help", help, { OPT|NTP_STR, NO, NO, NO }, 26654359Sroberto { "command", "", "", "" }, 26754359Sroberto "tell the use and syntax of commands" }, 268182007Sroberto { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 26954359Sroberto { "msec", "", "", "" }, 27054359Sroberto "set the primary receive time out" }, 271182007Sroberto { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 27254359Sroberto { "msec", "", "", "" }, 27354359Sroberto "set the delay added to encryption time stamps" }, 274182007Sroberto { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 275132451Sroberto { "-4|-6", "hostname", "", "" }, 27654359Sroberto "specify the host whose NTP server we talk to" }, 277182007Sroberto { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 27854359Sroberto { "n", "verbose", "", "" }, 27954359Sroberto "poll an NTP server in client mode `n' times" }, 280285612Sdelphij { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 28154359Sroberto { "", "", "", "" }, 28254359Sroberto "specify a password to use for authenticated requests"}, 283182007Sroberto { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 28454359Sroberto { "yes|no", "", "", "" }, 28554359Sroberto "specify whether hostnames or net numbers are printed"}, 286182007Sroberto { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 28754359Sroberto { "no|more|less", "", "", "" }, 28854359Sroberto "set/change debugging level" }, 28954359Sroberto { "quit", quit, { NO, NO, NO, NO }, 29054359Sroberto { "", "", "", "" }, 29154359Sroberto "exit ntpq" }, 29254359Sroberto { "exit", quit, { NO, NO, NO, NO }, 29354359Sroberto { "", "", "", "" }, 29454359Sroberto "exit ntpq" }, 295182007Sroberto { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 29654359Sroberto { "key#", "", "", "" }, 29754359Sroberto "set keyid to use for authenticated requests" }, 298298770Sdelphij { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 299298770Sdelphij { "hash|ipv4", "", "", "" }, 300298770Sdelphij "display refid's as IPv4 or hash" }, 30154359Sroberto { "version", version, { NO, NO, NO, NO }, 30254359Sroberto { "", "", "", "" }, 30354359Sroberto "print version number" }, 30454359Sroberto { "raw", raw, { NO, NO, NO, NO }, 30554359Sroberto { "", "", "", "" }, 30654359Sroberto "do raw mode variable output" }, 30754359Sroberto { "cooked", cooked, { NO, NO, NO, NO }, 30854359Sroberto { "", "", "", "" }, 30954359Sroberto "do cooked mode variable output" }, 310182007Sroberto { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 31154359Sroberto { "yes|no", "", "", "" }, 31254359Sroberto "always authenticate requests to this server" }, 313182007Sroberto { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 31454359Sroberto { "version number", "", "", "" }, 31554359Sroberto "set the NTP version number to use for requests" }, 316182007Sroberto { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 317285612Sdelphij { "key type %s", "", "", "" }, 318285612Sdelphij NULL }, 31954359Sroberto { 0, 0, { NO, NO, NO, NO }, 32054359Sroberto { "", "", "", "" }, "" } 32154359Sroberto}; 32254359Sroberto 32354359Sroberto 32454359Sroberto/* 32554359Sroberto * Default values we use. 32654359Sroberto */ 327285612Sdelphij#define DEFHOST "localhost" /* default host name */ 328285612Sdelphij#define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 329285612Sdelphij#define DEFSTIMEOUT 3 /* and 3 more for each additional */ 330285612Sdelphij/* 331285612Sdelphij * Requests are automatically retried once, so total timeout with no 332285612Sdelphij * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 333285612Sdelphij * extreme, a request eliciting 32 packets of responses each for some 334285612Sdelphij * reason nearly DEFSTIMEOUT seconds after the prior in that series, 335285612Sdelphij * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 336285612Sdelphij * 93 seconds to fail each of two times, or 186 seconds. 337285612Sdelphij * Some commands involve a series of requests, such as "peers" and 338285612Sdelphij * "mrulist", so the cumulative timeouts are even longer for those. 339285612Sdelphij */ 34054359Sroberto#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 34154359Sroberto#define LENHOSTNAME 256 /* host name is 256 characters long */ 34254359Sroberto#define MAXCMDS 100 /* maximum commands on cmd line */ 34354359Sroberto#define MAXHOSTS 200 /* maximum hosts on cmd line */ 34454359Sroberto#define MAXLINE 512 /* maximum line length */ 34554359Sroberto#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 34654359Sroberto#define MAXVARLEN 256 /* maximum length of a variable name */ 347285612Sdelphij#define MAXVALLEN 2048 /* maximum length of a variable value */ 34854359Sroberto#define MAXOUTLINE 72 /* maximum length of an output line */ 349285612Sdelphij#define SCREENWIDTH 76 /* nominal screen width in columns */ 35054359Sroberto 35154359Sroberto/* 35254359Sroberto * Some variables used and manipulated locally 35354359Sroberto */ 354285612Sdelphijstruct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 355285612Sdelphijstruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 35654359Srobertol_fp delay_time; /* delay time */ 35754359Srobertochar currenthost[LENHOSTNAME]; /* current host name */ 358285612Sdelphijint currenthostisnum; /* is prior text from IP? */ 359285612Sdelphijstruct sockaddr_in hostaddr; /* host address */ 36054359Srobertoint showhostnames = 1; /* show host names by default */ 361285612Sdelphijint wideremote = 0; /* show wide remote names? */ 36254359Sroberto 363132451Srobertoint ai_fam_templ; /* address family */ 364132451Srobertoint ai_fam_default; /* default address family */ 365132451SrobertoSOCKET sockfd; /* fd socket is opened on */ 36654359Srobertoint havehost = 0; /* set to 1 when host open */ 367132451Srobertoint s_port = 0; 36854359Srobertostruct servent *server_entry = NULL; /* server entry for ntp */ 36954359Sroberto 37054359Sroberto 37154359Sroberto/* 37254359Sroberto * Sequence number used for requests. It is incremented before 37354359Sroberto * it is used. 37454359Sroberto */ 37554359Srobertou_short sequence; 37654359Sroberto 37754359Sroberto/* 37854359Sroberto * Holds data returned from queries. Declare buffer long to be sure of 37954359Sroberto * alignment. 38054359Sroberto */ 38154359Sroberto#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 38254359Srobertolong pktdata[DATASIZE/sizeof(long)]; 38354359Sroberto 38454359Sroberto/* 385285612Sdelphij * assoc_cache[] is a dynamic array which allows references to 386285612Sdelphij * associations using &1 ... &N for n associations, avoiding manual 387285612Sdelphij * lookup of the current association IDs for a given ntpd. It also 388285612Sdelphij * caches the status word for each association, retrieved incidentally. 38954359Sroberto */ 390285612Sdelphijstruct association * assoc_cache; 391285612Sdelphiju_int assoc_cache_slots;/* count of allocated array entries */ 392285612Sdelphiju_int numassoc; /* number of cached associations */ 39354359Sroberto 39454359Sroberto/* 39554359Sroberto * For commands typed on the command line (with the -c option) 39654359Sroberto */ 397316722Sdelphijsize_t numcmds = 0; 39854359Srobertoconst char *ccmds[MAXCMDS]; 39954359Sroberto#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 40054359Sroberto 40154359Sroberto/* 40254359Sroberto * When multiple hosts are specified. 40354359Sroberto */ 40454359Sroberto 405285612Sdelphiju_int numhosts; 40654359Sroberto 407285612Sdelphijchost chosts[MAXHOSTS]; 408285612Sdelphij#define ADDHOST(cp) \ 409285612Sdelphij do { \ 410285612Sdelphij if (numhosts < MAXHOSTS) { \ 411285612Sdelphij chosts[numhosts].name = (cp); \ 412285612Sdelphij chosts[numhosts].fam = ai_fam_templ; \ 413285612Sdelphij numhosts++; \ 414285612Sdelphij } \ 415285612Sdelphij } while (0) 416285612Sdelphij 41754359Sroberto/* 41854359Sroberto * Macro definitions we use 41954359Sroberto */ 42054359Sroberto#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 42154359Sroberto#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 42254359Sroberto#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 42354359Sroberto 42454359Sroberto/* 42554359Sroberto * Jump buffer for longjumping back to the command level 42654359Sroberto */ 42754359Srobertojmp_buf interrupt_buf; 42854359Sroberto 42954359Sroberto/* 43054359Sroberto * Points at file being currently printed into 43154359Sroberto */ 43254359SrobertoFILE *current_output; 43354359Sroberto 43454359Sroberto/* 43554359Sroberto * Command table imported from ntpdc_ops.c 43654359Sroberto */ 43754359Srobertoextern struct xcmd opcmds[]; 43854359Sroberto 439289997Sglebiuschar const *progname; 44054359Sroberto 44154359Sroberto#ifdef NO_MAIN_ALLOWED 442285612Sdelphij#ifndef BUILD_AS_LIB 44354359SrobertoCALL(ntpq,"ntpq",ntpqmain); 44454359Sroberto 44554359Srobertovoid clear_globals(void) 44654359Sroberto{ 447285612Sdelphij extern int ntp_optind; 448285612Sdelphij showhostnames = 0; /* don'tshow host names by default */ 449285612Sdelphij ntp_optind = 0; 450285612Sdelphij server_entry = NULL; /* server entry for ntp */ 451285612Sdelphij havehost = 0; /* set to 1 when host open */ 452285612Sdelphij numassoc = 0; /* number of cached associations */ 453285612Sdelphij numcmds = 0; 454285612Sdelphij numhosts = 0; 45554359Sroberto} 456285612Sdelphij#endif /* !BUILD_AS_LIB */ 457285612Sdelphij#endif /* NO_MAIN_ALLOWED */ 45854359Sroberto 45954359Sroberto/* 46054359Sroberto * main - parse arguments and handle options 46154359Sroberto */ 46254359Sroberto#ifndef NO_MAIN_ALLOWED 46354359Srobertoint 46454359Srobertomain( 46554359Sroberto int argc, 46654359Sroberto char *argv[] 46754359Sroberto ) 46854359Sroberto{ 46954359Sroberto return ntpqmain(argc, argv); 47054359Sroberto} 47154359Sroberto#endif 47254359Sroberto 473330567Sgordon 474285612Sdelphij#ifndef BUILD_AS_LIB 47554359Srobertoint 47654359Srobertontpqmain( 47754359Sroberto int argc, 47854359Sroberto char *argv[] 47954359Sroberto ) 48054359Sroberto{ 481285612Sdelphij u_int ihost; 482316722Sdelphij size_t icmd; 48354359Sroberto 484285612Sdelphij 485182007Sroberto#ifdef SYS_VXWORKS 486182007Sroberto clear_globals(); 487182007Sroberto taskPrioritySet(taskIdSelf(), 100 ); 48854359Sroberto#endif 489182007Sroberto 49054359Sroberto delay_time.l_ui = 0; 49154359Sroberto delay_time.l_uf = DEFDELAY; 49254359Sroberto 493285612Sdelphij init_lib(); /* sets up ipv4_works, ipv6_works */ 494285612Sdelphij ssl_applink(); 495285612Sdelphij init_auth(); 496285612Sdelphij 497285612Sdelphij /* Check to see if we have IPv6. Otherwise default to IPv4 */ 498285612Sdelphij if (!ipv6_works) 499285612Sdelphij ai_fam_default = AF_INET; 500285612Sdelphij 501285612Sdelphij /* Fixup keytype's help based on available digest names */ 502285612Sdelphij 503132451Sroberto { 504285612Sdelphij char *list; 505294569Sdelphij char *msg; 506132451Sroberto 507285612Sdelphij list = list_digest_names(); 508330567Sgordon 509330567Sgordon for (icmd = 0; icmd < sizeof(builtins)/sizeof(*builtins); icmd++) { 510330567Sgordon if (strcmp("keytype", builtins[icmd].keyword) == 0) { 511285612Sdelphij break; 512330567Sgordon } 513285612Sdelphij } 514285612Sdelphij 515285612Sdelphij /* CID: 1295478 */ 516285612Sdelphij /* This should only "trip" if "keytype" is removed from builtins */ 517330567Sgordon INSIST(icmd < sizeof(builtins)/sizeof(*builtins)); 518285612Sdelphij 519285612Sdelphij#ifdef OPENSSL 520285612Sdelphij builtins[icmd].desc[0] = "digest-name"; 521294569Sdelphij my_easprintf(&msg, 522294569Sdelphij "set key type to use for authenticated requests, one of:%s", 523294569Sdelphij list); 524285612Sdelphij#else 525285612Sdelphij builtins[icmd].desc[0] = "md5"; 526294569Sdelphij my_easprintf(&msg, 527294569Sdelphij "set key type to use for authenticated requests (%s)", 528294569Sdelphij list); 529285612Sdelphij#endif 530285612Sdelphij builtins[icmd].comment = msg; 531285612Sdelphij free(list); 532132451Sroberto } 533132451Sroberto 53454359Sroberto progname = argv[0]; 535182007Sroberto 536182007Sroberto { 537285612Sdelphij int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 538182007Sroberto argc -= optct; 539182007Sroberto argv += optct; 540182007Sroberto } 541182007Sroberto 542285612Sdelphij /* 543285612Sdelphij * Process options other than -c and -p, which are specially 544285612Sdelphij * handled by ntpq_custom_opt_handler(). 545285612Sdelphij */ 546285612Sdelphij 547285612Sdelphij debug = OPT_VALUE_SET_DEBUG_LEVEL; 548285612Sdelphij 549285612Sdelphij if (HAVE_OPT(IPV4)) 550182007Sroberto ai_fam_templ = AF_INET; 551285612Sdelphij else if (HAVE_OPT(IPV6)) 552182007Sroberto ai_fam_templ = AF_INET6; 553285612Sdelphij else 554182007Sroberto ai_fam_templ = ai_fam_default; 555182007Sroberto 556285612Sdelphij if (HAVE_OPT(INTERACTIVE)) 557182007Sroberto interactive = 1; 558182007Sroberto 559285612Sdelphij if (HAVE_OPT(NUMERIC)) 560182007Sroberto showhostnames = 0; 561182007Sroberto 562285612Sdelphij if (HAVE_OPT(WIDE)) 563285612Sdelphij wideremote = 1; 564182007Sroberto 565285612Sdelphij old_rv = HAVE_OPT(OLD_RV); 566285612Sdelphij 567298770Sdelphij drefid = OPT_VALUE_REFID; 568298770Sdelphij 569285612Sdelphij if (0 == argc) { 57054359Sroberto ADDHOST(DEFHOST); 57154359Sroberto } else { 572285612Sdelphij for (ihost = 0; ihost < (u_int)argc; ihost++) { 573285612Sdelphij if ('-' == *argv[ihost]) { 574285612Sdelphij // 575285612Sdelphij // If I really cared I'd also check: 576285612Sdelphij // 0 == argv[ihost][2] 577285612Sdelphij // 578285612Sdelphij // and there are other cases as well... 579285612Sdelphij // 580285612Sdelphij if ('4' == argv[ihost][1]) { 581285612Sdelphij ai_fam_templ = AF_INET; 582285612Sdelphij continue; 583285612Sdelphij } else if ('6' == argv[ihost][1]) { 584285612Sdelphij ai_fam_templ = AF_INET6; 585285612Sdelphij continue; 586285612Sdelphij } else { 587285612Sdelphij // XXX Throw a usage error 588285612Sdelphij } 589285612Sdelphij } 590285612Sdelphij ADDHOST(argv[ihost]); 591285612Sdelphij } 59254359Sroberto } 59354359Sroberto 59454359Sroberto if (numcmds == 0 && interactive == 0 59554359Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 59654359Sroberto interactive = 1; 59754359Sroberto } 59854359Sroberto 599293650Sglebius set_ctrl_c_hook(on_ctrlc); 60054359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 60154359Sroberto if (interactive) 602293650Sglebius push_ctrl_c_handler(abortcmd); 60354359Sroberto#endif /* SYS_WINNT */ 60454359Sroberto 60554359Sroberto if (numcmds == 0) { 606285612Sdelphij (void) openhost(chosts[0].name, chosts[0].fam); 60754359Sroberto getcmds(); 60854359Sroberto } else { 60954359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 610330567Sgordon if (openhost(chosts[ihost].name, chosts[ihost].fam)) { 611330567Sgordon if (ihost) 612330567Sgordon fputc('\n', current_output); 613330567Sgordon for (icmd = 0; icmd < numcmds; icmd++) { 614330567Sgordon if (icmd) 615330567Sgordon fputc('\n', current_output); 616285612Sdelphij docmd(ccmds[icmd]); 617330567Sgordon } 618330567Sgordon } 61954359Sroberto } 62054359Sroberto } 62154359Sroberto#ifdef SYS_WINNT 62254359Sroberto WSACleanup(); 62354359Sroberto#endif /* SYS_WINNT */ 62454359Sroberto return 0; 62554359Sroberto} 626285612Sdelphij#endif /* !BUILD_AS_LIB */ 62754359Sroberto 62854359Sroberto/* 62954359Sroberto * openhost - open a socket to a host 63054359Sroberto */ 631285612Sdelphijstatic int 63254359Srobertoopenhost( 633285612Sdelphij const char *hname, 634285612Sdelphij int fam 63554359Sroberto ) 63654359Sroberto{ 637285612Sdelphij const char svc[] = "ntp"; 63854359Sroberto char temphost[LENHOSTNAME]; 639132451Sroberto int a_info, i; 640285612Sdelphij struct addrinfo hints, *ai; 641285612Sdelphij sockaddr_u addr; 642285612Sdelphij size_t octets; 643132451Sroberto register const char *cp; 644132451Sroberto char name[LENHOSTNAME]; 64554359Sroberto 646132451Sroberto /* 647132451Sroberto * We need to get by the [] if they were entered 648132451Sroberto */ 649285612Sdelphij 650132451Sroberto cp = hname; 651285612Sdelphij 652285612Sdelphij if (*cp == '[') { 653132451Sroberto cp++; 654285612Sdelphij for (i = 0; *cp && *cp != ']'; cp++, i++) 655132451Sroberto name[i] = *cp; 656285612Sdelphij if (*cp == ']') { 657285612Sdelphij name[i] = '\0'; 658285612Sdelphij hname = name; 659285612Sdelphij } else { 660285612Sdelphij return 0; 661285612Sdelphij } 66254359Sroberto } 66354359Sroberto 664132451Sroberto /* 665132451Sroberto * First try to resolve it as an ip address and if that fails, 666132451Sroberto * do a fullblown (dns) lookup. That way we only use the dns 667132451Sroberto * when it is needed and work around some implementations that 668132451Sroberto * will return an "IPv4-mapped IPv6 address" address if you 669132451Sroberto * give it an IPv4 address to lookup. 670132451Sroberto */ 671285612Sdelphij ZERO(hints); 672285612Sdelphij hints.ai_family = fam; 673132451Sroberto hints.ai_protocol = IPPROTO_UDP; 674132451Sroberto hints.ai_socktype = SOCK_DGRAM; 675285612Sdelphij hints.ai_flags = Z_AI_NUMERICHOST; 676285612Sdelphij ai = NULL; 677132451Sroberto 678285612Sdelphij a_info = getaddrinfo(hname, svc, &hints, &ai); 679182007Sroberto if (a_info == EAI_NONAME 680182007Sroberto#ifdef EAI_NODATA 681182007Sroberto || a_info == EAI_NODATA 682182007Sroberto#endif 683182007Sroberto ) { 684132451Sroberto hints.ai_flags = AI_CANONNAME; 685132451Sroberto#ifdef AI_ADDRCONFIG 686132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 687132451Sroberto#endif 688285612Sdelphij a_info = getaddrinfo(hname, svc, &hints, &ai); 689132451Sroberto } 690285612Sdelphij#ifdef AI_ADDRCONFIG 691132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 692132451Sroberto if (a_info == EAI_BADFLAGS) { 693285612Sdelphij hints.ai_flags &= ~AI_ADDRCONFIG; 694285612Sdelphij a_info = getaddrinfo(hname, svc, &hints, &ai); 695132451Sroberto } 696285612Sdelphij#endif 697132451Sroberto if (a_info != 0) { 698285612Sdelphij fprintf(stderr, "%s\n", gai_strerror(a_info)); 699132451Sroberto return 0; 700132451Sroberto } 701132451Sroberto 702285612Sdelphij INSIST(ai != NULL); 703285612Sdelphij ZERO(addr); 704285612Sdelphij octets = min(sizeof(addr), ai->ai_addrlen); 705285612Sdelphij memcpy(&addr, ai->ai_addr, octets); 706285612Sdelphij 707132451Sroberto if (ai->ai_canonname == NULL) { 708285612Sdelphij strlcpy(temphost, stoa(&addr), sizeof(temphost)); 709285612Sdelphij currenthostisnum = TRUE; 710132451Sroberto } else { 711285612Sdelphij strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 712285612Sdelphij currenthostisnum = FALSE; 713132451Sroberto } 714132451Sroberto 71554359Sroberto if (debug > 2) 716285612Sdelphij printf("Opening host %s (%s)\n", 717285612Sdelphij temphost, 718285612Sdelphij (ai->ai_family == AF_INET) 719285612Sdelphij ? "AF_INET" 720285612Sdelphij : (ai->ai_family == AF_INET6) 721285612Sdelphij ? "AF_INET6" 722285612Sdelphij : "AF-???" 723285612Sdelphij ); 72454359Sroberto 72554359Sroberto if (havehost == 1) { 72654359Sroberto if (debug > 2) 727285612Sdelphij printf("Closing old host %s\n", currenthost); 728285612Sdelphij closesocket(sockfd); 72954359Sroberto havehost = 0; 73054359Sroberto } 731285612Sdelphij strlcpy(currenthost, temphost, sizeof(currenthost)); 73254359Sroberto 733132451Sroberto /* port maps to the same location in both families */ 734285612Sdelphij s_port = NSRCPORT(&addr); 735132451Sroberto#ifdef SYS_VXWORKS 736132451Sroberto ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 737132451Sroberto if (ai->ai_family == AF_INET) 738132451Sroberto *(struct sockaddr_in *)&hostaddr= 739132451Sroberto *((struct sockaddr_in *)ai->ai_addr); 740132451Sroberto else 741132451Sroberto *(struct sockaddr_in6 *)&hostaddr= 742132451Sroberto *((struct sockaddr_in6 *)ai->ai_addr); 743132451Sroberto#endif /* SYS_VXWORKS */ 74454359Sroberto 74554359Sroberto#ifdef SYS_WINNT 74654359Sroberto { 74754359Sroberto int optionValue = SO_SYNCHRONOUS_NONALERT; 74854359Sroberto int err; 749182007Sroberto 750285612Sdelphij err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 751330567Sgordon (void *)&optionValue, sizeof(optionValue)); 752285612Sdelphij if (err) { 753285612Sdelphij mfprintf(stderr, 754285612Sdelphij "setsockopt(SO_SYNCHRONOUS_NONALERT)" 755285612Sdelphij " error: %m\n"); 756285612Sdelphij freeaddrinfo(ai); 75754359Sroberto exit(1); 75854359Sroberto } 75954359Sroberto } 760132451Sroberto#endif /* SYS_WINNT */ 76154359Sroberto 762285612Sdelphij sockfd = socket(ai->ai_family, ai->ai_socktype, 763285612Sdelphij ai->ai_protocol); 76454359Sroberto if (sockfd == INVALID_SOCKET) { 765285612Sdelphij error("socket"); 766285612Sdelphij freeaddrinfo(ai); 767285612Sdelphij return 0; 76854359Sroberto } 76954359Sroberto 770285612Sdelphij 77154359Sroberto#ifdef NEED_RCVBUF_SLOP 77254359Sroberto# ifdef SO_RCVBUF 77354359Sroberto { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 77454359Sroberto if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 775330567Sgordon (void *)&rbufsize, sizeof(int)) == -1) 776285612Sdelphij error("setsockopt"); 77754359Sroberto } 77854359Sroberto# endif 77954359Sroberto#endif 78054359Sroberto 781285612Sdelphij if 782132451Sroberto#ifdef SYS_VXWORKS 783285612Sdelphij (connect(sockfd, (struct sockaddr *)&hostaddr, 78454359Sroberto sizeof(hostaddr)) == -1) 785132451Sroberto#else 786285612Sdelphij (connect(sockfd, (struct sockaddr *)ai->ai_addr, 787293650Sglebius ai->ai_addrlen) == -1) 788132451Sroberto#endif /* SYS_VXWORKS */ 789293650Sglebius { 790285612Sdelphij error("connect"); 791132451Sroberto freeaddrinfo(ai); 792285612Sdelphij return 0; 793285612Sdelphij } 794285612Sdelphij freeaddrinfo(ai); 79554359Sroberto havehost = 1; 796285612Sdelphij numassoc = 0; 797285612Sdelphij 79854359Sroberto return 1; 79954359Sroberto} 80054359Sroberto 80154359Sroberto 802285612Sdelphijstatic void 803285612Sdelphijdump_hex_printable( 804285612Sdelphij const void * data, 805285612Sdelphij size_t len 806285612Sdelphij ) 807285612Sdelphij{ 808316722Sdelphij /* every line shows at most 16 bytes, so we need a buffer of 809316722Sdelphij * 4 * 16 (2 xdigits, 1 char, one sep for xdigits) 810316722Sdelphij * + 2 * 1 (block separators) 811316722Sdelphij * + <LF> + <NUL> 812316722Sdelphij *--------------- 813316722Sdelphij * 68 bytes 814316722Sdelphij */ 815316722Sdelphij static const char s_xdig[16] = "0123456789ABCDEF"; 816285612Sdelphij 817316722Sdelphij char lbuf[68]; 818316722Sdelphij int ch, rowlen; 819316722Sdelphij const u_char * cdata = data; 820316722Sdelphij char *xptr, *pptr; 821316722Sdelphij 822316722Sdelphij while (len) { 823316722Sdelphij memset(lbuf, ' ', sizeof(lbuf)); 824316722Sdelphij xptr = lbuf; 825316722Sdelphij pptr = lbuf + 3*16 + 2; 826316722Sdelphij 827316722Sdelphij rowlen = (len > 16) ? 16 : (int)len; 828285612Sdelphij len -= rowlen; 829316722Sdelphij 830316722Sdelphij do { 831316722Sdelphij ch = *cdata++; 832316722Sdelphij 833316722Sdelphij *xptr++ = s_xdig[ch >> 4 ]; 834316722Sdelphij *xptr++ = s_xdig[ch & 0x0F]; 835316722Sdelphij if (++xptr == lbuf + 3*8) 836316722Sdelphij ++xptr; 837316722Sdelphij 838316722Sdelphij *pptr++ = isprint(ch) ? (char)ch : '.'; 839316722Sdelphij } while (--rowlen); 840316722Sdelphij 841316722Sdelphij *pptr++ = '\n'; 842316722Sdelphij *pptr = '\0'; 843316722Sdelphij fputs(lbuf, stdout); 844285612Sdelphij } 845285612Sdelphij} 846285612Sdelphij 847285612Sdelphij 84854359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 84954359Sroberto/* 85054359Sroberto * sendpkt - send a packet to the remote host 85154359Sroberto */ 85254359Srobertostatic int 85354359Srobertosendpkt( 854285612Sdelphij void * xdata, 855285612Sdelphij size_t xdatalen 85654359Sroberto ) 85754359Sroberto{ 85854359Sroberto if (debug >= 3) 859285612Sdelphij printf("Sending %zu octets\n", xdatalen); 86054359Sroberto 861293650Sglebius if (send(sockfd, xdata, xdatalen, 0) == -1) { 862285612Sdelphij warning("write to %s failed", currenthost); 86354359Sroberto return -1; 86454359Sroberto } 86554359Sroberto 86654359Sroberto if (debug >= 4) { 867285612Sdelphij printf("Request packet:\n"); 868285612Sdelphij dump_hex_printable(xdata, xdatalen); 86954359Sroberto } 87054359Sroberto return 0; 87154359Sroberto} 87254359Sroberto 87354359Sroberto/* 87454359Sroberto * getresponse - get a (series of) response packet(s) and return the data 87554359Sroberto */ 87654359Srobertostatic int 87754359Srobertogetresponse( 87854359Sroberto int opcode, 87954359Sroberto int associd, 88054359Sroberto u_short *rstatus, 881293650Sglebius size_t *rsize, 882285612Sdelphij const char **rdata, 88354359Sroberto int timeo 88454359Sroberto ) 88554359Sroberto{ 88654359Sroberto struct ntp_control rpkt; 887285612Sdelphij struct sock_timeval tvo; 88854359Sroberto u_short offsets[MAXFRAGS+1]; 88954359Sroberto u_short counts[MAXFRAGS+1]; 89054359Sroberto u_short offset; 89154359Sroberto u_short count; 892285612Sdelphij size_t numfrags; 893285612Sdelphij size_t f; 894285612Sdelphij size_t ff; 89554359Sroberto int seenlastfrag; 896285612Sdelphij int shouldbesize; 89754359Sroberto fd_set fds; 89854359Sroberto int n; 899285612Sdelphij int errcode; 900294569Sdelphij /* absolute timeout checks. Not 'time_t' by intention! */ 901294569Sdelphij uint32_t tobase; /* base value for timeout */ 902294569Sdelphij uint32_t tospan; /* timeout span (max delay) */ 903294569Sdelphij uint32_t todiff; /* current delay */ 90454359Sroberto 905316722Sdelphij memset(offsets, 0, sizeof(offsets)); 906316722Sdelphij memset(counts , 0, sizeof(counts )); 907316722Sdelphij 90854359Sroberto /* 90954359Sroberto * This is pretty tricky. We may get between 1 and MAXFRAG packets 91054359Sroberto * back in response to the request. We peel the data out of 91154359Sroberto * each packet and collect it in one long block. When the last 91254359Sroberto * packet in the sequence is received we'll know how much data we 91354359Sroberto * should have had. Note we use one long time out, should reconsider. 91454359Sroberto */ 91554359Sroberto *rsize = 0; 91654359Sroberto if (rstatus) 917285612Sdelphij *rstatus = 0; 91854359Sroberto *rdata = (char *)pktdata; 91954359Sroberto 92054359Sroberto numfrags = 0; 92154359Sroberto seenlastfrag = 0; 92254359Sroberto 923294569Sdelphij tobase = (uint32_t)time(NULL); 924294569Sdelphij 92554359Sroberto FD_ZERO(&fds); 92654359Sroberto 927285612Sdelphij /* 928285612Sdelphij * Loop until we have an error or a complete response. Nearly all 929285612Sdelphij * code paths to loop again use continue. 930285612Sdelphij */ 931285612Sdelphij for (;;) { 93254359Sroberto 933285612Sdelphij if (numfrags == 0) 934285612Sdelphij tvo = tvout; 935285612Sdelphij else 936285612Sdelphij tvo = tvsout; 937294569Sdelphij tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 93854359Sroberto 939285612Sdelphij FD_SET(sockfd, &fds); 940293650Sglebius n = select(sockfd+1, &fds, NULL, NULL, &tvo); 941285612Sdelphij if (n == -1) { 942294569Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 943294569Sdelphij /* Windows does not know about EINTR (until very 944294569Sdelphij * recently) and the handling of console events 945294569Sdelphij * is *very* different from POSIX/UNIX signal 946294569Sdelphij * handling anyway. 947294569Sdelphij * 948294569Sdelphij * Under non-windows targets we map EINTR as 949294569Sdelphij * 'last packet was received' and try to exit 950294569Sdelphij * the receive sequence. 951294569Sdelphij */ 952294569Sdelphij if (errno == EINTR) { 953294569Sdelphij seenlastfrag = 1; 954294569Sdelphij goto maybe_final; 955294569Sdelphij } 956294569Sdelphij#endif 957285612Sdelphij warning("select fails"); 958285612Sdelphij return -1; 959285612Sdelphij } 960294569Sdelphij 961294569Sdelphij /* 962294569Sdelphij * Check if this is already too late. Trash the data and 963294569Sdelphij * fake a timeout if this is so. 964294569Sdelphij */ 965294569Sdelphij todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 966294569Sdelphij if ((n > 0) && (todiff > tospan)) { 967294569Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 968316722Sdelphij n -= n; /* faked timeout return from 'select()', 969316722Sdelphij * execute RMW cycle on 'n' 970316722Sdelphij */ 971294569Sdelphij } 972294569Sdelphij 973316722Sdelphij if (n <= 0) { 974285612Sdelphij /* 975285612Sdelphij * Timed out. Return what we have 976285612Sdelphij */ 977285612Sdelphij if (numfrags == 0) { 978285612Sdelphij if (timeo) 979285612Sdelphij fprintf(stderr, 980285612Sdelphij "%s: timed out, nothing received\n", 981285612Sdelphij currenthost); 982285612Sdelphij return ERR_TIMEOUT; 983285612Sdelphij } 98454359Sroberto if (timeo) 985285612Sdelphij fprintf(stderr, 986285612Sdelphij "%s: timed out with incomplete data\n", 987285612Sdelphij currenthost); 98854359Sroberto if (debug) { 989285612Sdelphij fprintf(stderr, 990285612Sdelphij "ERR_INCOMPLETE: Received fragments:\n"); 991285612Sdelphij for (f = 0; f < numfrags; f++) 992285612Sdelphij fprintf(stderr, 993285612Sdelphij "%2u: %5d %5d\t%3d octets\n", 994285612Sdelphij (u_int)f, offsets[f], 995285612Sdelphij offsets[f] + 996285612Sdelphij counts[f], 997285612Sdelphij counts[f]); 998285612Sdelphij fprintf(stderr, 999285612Sdelphij "last fragment %sreceived\n", 1000285612Sdelphij (seenlastfrag) 1001285612Sdelphij ? "" 1002285612Sdelphij : "not "); 100354359Sroberto } 100454359Sroberto return ERR_INCOMPLETE; 100554359Sroberto } 100654359Sroberto 1007285612Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 1008316722Sdelphij if (n < 0) { 1009285612Sdelphij warning("read"); 1010285612Sdelphij return -1; 1011285612Sdelphij } 101254359Sroberto 1013285612Sdelphij if (debug >= 4) { 1014285612Sdelphij printf("Response packet:\n"); 1015285612Sdelphij dump_hex_printable(&rpkt, n); 1016285612Sdelphij } 101754359Sroberto 1018285612Sdelphij /* 1019285612Sdelphij * Check for format errors. Bug proofing. 1020285612Sdelphij */ 1021285612Sdelphij if (n < (int)CTL_HEADER_LEN) { 1022285612Sdelphij if (debug) 1023285612Sdelphij printf("Short (%d byte) packet received\n", n); 1024285612Sdelphij continue; 102554359Sroberto } 1026285612Sdelphij if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 1027285612Sdelphij || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 1028285612Sdelphij if (debug) 1029285612Sdelphij printf("Packet received with version %d\n", 1030285612Sdelphij PKT_VERSION(rpkt.li_vn_mode)); 1031285612Sdelphij continue; 1032285612Sdelphij } 1033285612Sdelphij if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 1034285612Sdelphij if (debug) 1035285612Sdelphij printf("Packet received with mode %d\n", 1036285612Sdelphij PKT_MODE(rpkt.li_vn_mode)); 1037285612Sdelphij continue; 1038285612Sdelphij } 1039285612Sdelphij if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 1040285612Sdelphij if (debug) 1041285612Sdelphij printf("Received request packet, wanted response\n"); 1042285612Sdelphij continue; 1043285612Sdelphij } 104454359Sroberto 1045285612Sdelphij /* 1046285612Sdelphij * Check opcode and sequence number for a match. 1047285612Sdelphij * Could be old data getting to us. 1048285612Sdelphij */ 1049285612Sdelphij if (ntohs(rpkt.sequence) != sequence) { 1050285612Sdelphij if (debug) 1051285612Sdelphij printf("Received sequnce number %d, wanted %d\n", 1052285612Sdelphij ntohs(rpkt.sequence), sequence); 1053285612Sdelphij continue; 1054285612Sdelphij } 1055285612Sdelphij if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1056285612Sdelphij if (debug) 1057285612Sdelphij printf( 1058285612Sdelphij "Received opcode %d, wanted %d (sequence number okay)\n", 1059285612Sdelphij CTL_OP(rpkt.r_m_e_op), opcode); 1060285612Sdelphij continue; 1061285612Sdelphij } 106254359Sroberto 1063285612Sdelphij /* 1064285612Sdelphij * Check the error code. If non-zero, return it. 1065285612Sdelphij */ 1066285612Sdelphij if (CTL_ISERROR(rpkt.r_m_e_op)) { 1067285612Sdelphij errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1068285612Sdelphij if (CTL_ISMORE(rpkt.r_m_e_op)) 1069285612Sdelphij TRACE(1, ("Error code %d received on not-final packet\n", 1070285612Sdelphij errcode)); 1071285612Sdelphij if (errcode == CERR_UNSPEC) 1072285612Sdelphij return ERR_UNSPEC; 1073285612Sdelphij return errcode; 107454359Sroberto } 107554359Sroberto 107654359Sroberto /* 1077285612Sdelphij * Check the association ID to make sure it matches what 1078285612Sdelphij * we sent. 107954359Sroberto */ 1080285612Sdelphij if (ntohs(rpkt.associd) != associd) { 1081285612Sdelphij TRACE(1, ("Association ID %d doesn't match expected %d\n", 1082285612Sdelphij ntohs(rpkt.associd), associd)); 1083285612Sdelphij /* 1084285612Sdelphij * Hack for silly fuzzballs which, at the time of writing, 1085285612Sdelphij * return an assID of sys.peer when queried for system variables. 1086285612Sdelphij */ 108754359Sroberto#ifdef notdef 1088285612Sdelphij continue; 108954359Sroberto#endif 1090285612Sdelphij } 109154359Sroberto 1092285612Sdelphij /* 1093285612Sdelphij * Collect offset and count. Make sure they make sense. 1094285612Sdelphij */ 1095285612Sdelphij offset = ntohs(rpkt.offset); 1096285612Sdelphij count = ntohs(rpkt.count); 109754359Sroberto 109854359Sroberto /* 1099285612Sdelphij * validate received payload size is padded to next 32-bit 1100285612Sdelphij * boundary and no smaller than claimed by rpkt.count 110154359Sroberto */ 1102285612Sdelphij if (n & 0x3) { 1103285612Sdelphij TRACE(1, ("Response packet not padded, size = %d\n", 1104285612Sdelphij n)); 1105285612Sdelphij continue; 1106285612Sdelphij } 110754359Sroberto 1108285612Sdelphij shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 110954359Sroberto 1110285612Sdelphij if (n < shouldbesize) { 1111285612Sdelphij printf("Response packet claims %u octets payload, above %ld received\n", 1112301301Sdelphij count, (long)(n - CTL_HEADER_LEN)); 1113285612Sdelphij return ERR_INCOMPLETE; 1114285612Sdelphij } 1115285612Sdelphij 1116285612Sdelphij if (debug >= 3 && shouldbesize > n) { 1117285612Sdelphij u_int32 key; 1118285612Sdelphij u_int32 *lpkt; 1119285612Sdelphij int maclen; 1120285612Sdelphij 1121285612Sdelphij /* 1122285612Sdelphij * Usually we ignore authentication, but for debugging purposes 1123285612Sdelphij * we watch it here. 1124285612Sdelphij */ 1125285612Sdelphij /* round to 8 octet boundary */ 1126285612Sdelphij shouldbesize = (shouldbesize + 7) & ~7; 1127285612Sdelphij 1128285612Sdelphij maclen = n - shouldbesize; 1129285612Sdelphij if (maclen >= (int)MIN_MAC_LEN) { 1130285612Sdelphij printf( 1131285612Sdelphij "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1132285612Sdelphij n, shouldbesize, maclen); 1133285612Sdelphij lpkt = (u_int32 *)&rpkt; 1134285612Sdelphij printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1135285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1136285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1137285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1138285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1139285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1140285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1141285612Sdelphij key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1142285612Sdelphij printf("Authenticated with keyid %lu\n", (u_long)key); 1143285612Sdelphij if (key != 0 && key != info_auth_keyid) { 1144285612Sdelphij printf("We don't know that key\n"); 114554359Sroberto } else { 1146285612Sdelphij if (authdecrypt(key, (u_int32 *)&rpkt, 1147285612Sdelphij n - maclen, maclen)) { 1148285612Sdelphij printf("Auth okay!\n"); 1149285612Sdelphij } else { 1150285612Sdelphij printf("Auth failed!\n"); 1151285612Sdelphij } 115254359Sroberto } 115354359Sroberto } 115454359Sroberto } 115554359Sroberto 1156285612Sdelphij TRACE(2, ("Got packet, size = %d\n", n)); 1157285612Sdelphij if (count > (n - CTL_HEADER_LEN)) { 1158285612Sdelphij TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1159285612Sdelphij count, (long)n - CTL_HEADER_LEN)); 1160285612Sdelphij continue; 1161285612Sdelphij } 1162285612Sdelphij if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1163285612Sdelphij TRACE(1, ("Received count of 0 in non-final fragment\n")); 1164285612Sdelphij continue; 1165285612Sdelphij } 1166285612Sdelphij if (offset + count > sizeof(pktdata)) { 1167285612Sdelphij TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1168285612Sdelphij offset, count)); 1169285612Sdelphij return ERR_TOOMUCH; 1170285612Sdelphij } 1171285612Sdelphij if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1172285612Sdelphij TRACE(1, ("Received second last fragment packet\n")); 1173285612Sdelphij continue; 1174285612Sdelphij } 117554359Sroberto 1176285612Sdelphij /* 1177285612Sdelphij * So far, so good. Record this fragment, making sure it doesn't 1178285612Sdelphij * overlap anything. 1179285612Sdelphij */ 1180285612Sdelphij TRACE(2, ("Packet okay\n")); 118154359Sroberto 1182285612Sdelphij if (numfrags > (MAXFRAGS - 1)) { 1183285612Sdelphij TRACE(2, ("Number of fragments exceeds maximum %d\n", 1184285612Sdelphij MAXFRAGS - 1)); 1185285612Sdelphij return ERR_TOOMUCH; 118654359Sroberto } 118754359Sroberto 1188285612Sdelphij /* 1189285612Sdelphij * Find the position for the fragment relative to any 1190285612Sdelphij * previously received. 1191285612Sdelphij */ 1192285612Sdelphij for (f = 0; 1193285612Sdelphij f < numfrags && offsets[f] < offset; 1194285612Sdelphij f++) { 1195285612Sdelphij /* empty body */ ; 1196285612Sdelphij } 119754359Sroberto 1198285612Sdelphij if (f < numfrags && offset == offsets[f]) { 1199285612Sdelphij TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1200285612Sdelphij count, offset, counts[f], offsets[f])); 1201285612Sdelphij continue; 1202285612Sdelphij } 120354359Sroberto 1204285612Sdelphij if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1205285612Sdelphij TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1206285612Sdelphij offset, counts[f-1], offsets[f-1])); 1207285612Sdelphij continue; 120854359Sroberto } 1209285612Sdelphij 1210285612Sdelphij if (f < numfrags && (offset + count) > offsets[f]) { 1211285612Sdelphij TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1212285612Sdelphij count, offset, offsets[f])); 1213285612Sdelphij continue; 121454359Sroberto } 121554359Sroberto 1216285612Sdelphij for (ff = numfrags; ff > f; ff--) { 1217285612Sdelphij offsets[ff] = offsets[ff-1]; 1218285612Sdelphij counts[ff] = counts[ff-1]; 1219285612Sdelphij } 1220285612Sdelphij offsets[f] = offset; 1221285612Sdelphij counts[f] = count; 1222285612Sdelphij numfrags++; 122354359Sroberto 1224285612Sdelphij /* 1225285612Sdelphij * Got that stuffed in right. Figure out if this was the last. 1226285612Sdelphij * Record status info out of the last packet. 1227285612Sdelphij */ 1228285612Sdelphij if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1229285612Sdelphij seenlastfrag = 1; 1230285612Sdelphij if (rstatus != 0) 1231285612Sdelphij *rstatus = ntohs(rpkt.status); 1232285612Sdelphij } 123354359Sroberto 1234285612Sdelphij /* 1235294569Sdelphij * Copy the data into the data buffer, and bump the 1236294569Sdelphij * timout base in case we need more. 1237285612Sdelphij */ 1238285612Sdelphij memcpy((char *)pktdata + offset, &rpkt.u, count); 1239294569Sdelphij tobase = (uint32_t)time(NULL); 1240294569Sdelphij 1241285612Sdelphij /* 1242285612Sdelphij * If we've seen the last fragment, look for holes in the sequence. 1243285612Sdelphij * If there aren't any, we're done. 1244285612Sdelphij */ 1245301301Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 1246301301Sdelphij maybe_final: 1247301301Sdelphij#endif 1248301301Sdelphij 1249285612Sdelphij if (seenlastfrag && offsets[0] == 0) { 1250285612Sdelphij for (f = 1; f < numfrags; f++) 1251285612Sdelphij if (offsets[f-1] + counts[f-1] != 1252285612Sdelphij offsets[f]) 1253285612Sdelphij break; 1254285612Sdelphij if (f == numfrags) { 1255285612Sdelphij *rsize = offsets[f-1] + counts[f-1]; 1256285612Sdelphij TRACE(1, ("%lu packets reassembled into response\n", 1257285612Sdelphij (u_long)numfrags)); 1258285612Sdelphij return 0; 1259285612Sdelphij } 1260285612Sdelphij } 1261285612Sdelphij } /* giant for (;;) collecting response packets */ 1262285612Sdelphij} /* getresponse() */ 1263285612Sdelphij 1264285612Sdelphij 126554359Sroberto/* 126654359Sroberto * sendrequest - format and send a request packet 126754359Sroberto */ 126854359Srobertostatic int 126954359Srobertosendrequest( 127054359Sroberto int opcode, 1271285612Sdelphij associd_t associd, 127254359Sroberto int auth, 1273293650Sglebius size_t qsize, 1274285612Sdelphij const char *qdata 127554359Sroberto ) 127654359Sroberto{ 127754359Sroberto struct ntp_control qpkt; 1278293650Sglebius size_t pktsize; 1279285612Sdelphij u_long key_id; 1280285612Sdelphij char * pass; 1281293650Sglebius size_t maclen; 128254359Sroberto 128354359Sroberto /* 128454359Sroberto * Check to make sure the data will fit in one packet 128554359Sroberto */ 128654359Sroberto if (qsize > CTL_MAX_DATA_LEN) { 1287285612Sdelphij fprintf(stderr, 1288293650Sglebius "***Internal error! qsize (%zu) too large\n", 1289285612Sdelphij qsize); 129054359Sroberto return 1; 129154359Sroberto } 129254359Sroberto 129354359Sroberto /* 129454359Sroberto * Fill in the packet 129554359Sroberto */ 129654359Sroberto qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1297132451Sroberto qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 129854359Sroberto qpkt.sequence = htons(sequence); 129954359Sroberto qpkt.status = 0; 130054359Sroberto qpkt.associd = htons((u_short)associd); 130154359Sroberto qpkt.offset = 0; 130254359Sroberto qpkt.count = htons((u_short)qsize); 130354359Sroberto 1304285612Sdelphij pktsize = CTL_HEADER_LEN; 1305285612Sdelphij 130654359Sroberto /* 1307285612Sdelphij * If we have data, copy and pad it out to a 32-bit boundary. 130854359Sroberto */ 130954359Sroberto if (qsize > 0) { 1310285612Sdelphij memcpy(&qpkt.u, qdata, (size_t)qsize); 1311285612Sdelphij pktsize += qsize; 1312285612Sdelphij while (pktsize & (sizeof(u_int32) - 1)) { 1313285612Sdelphij qpkt.u.data[qsize++] = 0; 131454359Sroberto pktsize++; 131554359Sroberto } 131654359Sroberto } 131754359Sroberto 131854359Sroberto /* 131954359Sroberto * If it isn't authenticated we can just send it. Otherwise 132054359Sroberto * we're going to have to think about it a little. 132154359Sroberto */ 132254359Sroberto if (!auth && !always_auth) { 1323285612Sdelphij return sendpkt(&qpkt, pktsize); 1324285612Sdelphij } 132554359Sroberto 1326285612Sdelphij /* 1327285612Sdelphij * Pad out packet to a multiple of 8 octets to be sure 1328285612Sdelphij * receiver can handle it. 1329285612Sdelphij */ 1330285612Sdelphij while (pktsize & 7) { 1331285612Sdelphij qpkt.u.data[qsize++] = 0; 1332285612Sdelphij pktsize++; 1333285612Sdelphij } 133454359Sroberto 1335285612Sdelphij /* 1336285612Sdelphij * Get the keyid and the password if we don't have one. 1337285612Sdelphij */ 1338285612Sdelphij if (info_auth_keyid == 0) { 1339285612Sdelphij key_id = getkeyid("Keyid: "); 1340285612Sdelphij if (key_id == 0 || key_id > NTP_MAXKEY) { 1341285612Sdelphij fprintf(stderr, 1342285612Sdelphij "Invalid key identifier\n"); 1343285612Sdelphij return 1; 134454359Sroberto } 1345285612Sdelphij info_auth_keyid = key_id; 1346285612Sdelphij } 1347285612Sdelphij if (!authistrusted(info_auth_keyid)) { 1348285612Sdelphij pass = getpass_keytype(info_auth_keytype); 1349285612Sdelphij if ('\0' == pass[0]) { 1350285612Sdelphij fprintf(stderr, "Invalid password\n"); 1351285612Sdelphij return 1; 135254359Sroberto } 1353285612Sdelphij authusekey(info_auth_keyid, info_auth_keytype, 1354285612Sdelphij (u_char *)pass); 135554359Sroberto authtrust(info_auth_keyid, 1); 1356285612Sdelphij } 135754359Sroberto 1358285612Sdelphij /* 1359285612Sdelphij * Do the encryption. 1360285612Sdelphij */ 1361285612Sdelphij maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1362285612Sdelphij if (!maclen) { 1363285612Sdelphij fprintf(stderr, "Key not found\n"); 1364285612Sdelphij return 1; 1365285612Sdelphij } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1366285612Sdelphij fprintf(stderr, 1367293650Sglebius "%zu octet MAC, %zu expected with %zu octet digest\n", 1368285612Sdelphij maclen, (info_auth_hashlen + sizeof(keyid_t)), 1369285612Sdelphij info_auth_hashlen); 1370285612Sdelphij return 1; 137154359Sroberto } 1372285612Sdelphij 1373285612Sdelphij return sendpkt((char *)&qpkt, pktsize + maclen); 137454359Sroberto} 137554359Sroberto 137654359Sroberto 137754359Sroberto/* 1378285612Sdelphij * show_error_msg - display the error text for a mode 6 error response. 137954359Sroberto */ 1380285612Sdelphijvoid 1381285612Sdelphijshow_error_msg( 1382285612Sdelphij int m6resp, 1383285612Sdelphij associd_t associd 1384285612Sdelphij ) 1385285612Sdelphij{ 1386285612Sdelphij if (numhosts > 1) 1387285612Sdelphij fprintf(stderr, "server=%s ", currenthost); 1388285612Sdelphij 1389298770Sdelphij switch (m6resp) { 1390285612Sdelphij 1391285612Sdelphij case CERR_BADFMT: 1392285612Sdelphij fprintf(stderr, 1393285612Sdelphij "***Server reports a bad format request packet\n"); 1394285612Sdelphij break; 1395285612Sdelphij 1396285612Sdelphij case CERR_PERMISSION: 1397285612Sdelphij fprintf(stderr, 1398285612Sdelphij "***Server disallowed request (authentication?)\n"); 1399285612Sdelphij break; 1400285612Sdelphij 1401285612Sdelphij case CERR_BADOP: 1402285612Sdelphij fprintf(stderr, 1403285612Sdelphij "***Server reports a bad opcode in request\n"); 1404285612Sdelphij break; 1405285612Sdelphij 1406285612Sdelphij case CERR_BADASSOC: 1407285612Sdelphij fprintf(stderr, 1408285612Sdelphij "***Association ID %d unknown to server\n", 1409285612Sdelphij associd); 1410285612Sdelphij break; 1411285612Sdelphij 1412285612Sdelphij case CERR_UNKNOWNVAR: 1413285612Sdelphij fprintf(stderr, 1414285612Sdelphij "***A request variable unknown to the server\n"); 1415285612Sdelphij break; 1416285612Sdelphij 1417285612Sdelphij case CERR_BADVALUE: 1418285612Sdelphij fprintf(stderr, 1419285612Sdelphij "***Server indicates a request variable was bad\n"); 1420285612Sdelphij break; 1421285612Sdelphij 1422285612Sdelphij case ERR_UNSPEC: 1423285612Sdelphij fprintf(stderr, 1424285612Sdelphij "***Server returned an unspecified error\n"); 1425285612Sdelphij break; 1426285612Sdelphij 1427285612Sdelphij case ERR_TIMEOUT: 1428285612Sdelphij fprintf(stderr, "***Request timed out\n"); 1429285612Sdelphij break; 1430285612Sdelphij 1431285612Sdelphij case ERR_INCOMPLETE: 1432285612Sdelphij fprintf(stderr, 1433285612Sdelphij "***Response from server was incomplete\n"); 1434285612Sdelphij break; 1435285612Sdelphij 1436285612Sdelphij case ERR_TOOMUCH: 1437285612Sdelphij fprintf(stderr, 1438285612Sdelphij "***Buffer size exceeded for returned data\n"); 1439285612Sdelphij break; 1440285612Sdelphij 1441285612Sdelphij default: 1442285612Sdelphij fprintf(stderr, 1443285612Sdelphij "***Server returns unknown error code %d\n", 1444285612Sdelphij m6resp); 1445285612Sdelphij } 1446285612Sdelphij} 1447285612Sdelphij 1448285612Sdelphij/* 1449285612Sdelphij * doquery - send a request and process the response, displaying 1450285612Sdelphij * error messages for any error responses. 1451285612Sdelphij */ 145254359Srobertoint 145354359Srobertodoquery( 145454359Sroberto int opcode, 1455285612Sdelphij associd_t associd, 145654359Sroberto int auth, 1457293650Sglebius size_t qsize, 1458285612Sdelphij const char *qdata, 145954359Sroberto u_short *rstatus, 1460293650Sglebius size_t *rsize, 1461285612Sdelphij const char **rdata 146254359Sroberto ) 146354359Sroberto{ 1464285612Sdelphij return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1465285612Sdelphij rsize, rdata, FALSE); 1466285612Sdelphij} 1467285612Sdelphij 1468285612Sdelphij 1469285612Sdelphij/* 1470285612Sdelphij * doqueryex - send a request and process the response, optionally 1471285612Sdelphij * displaying error messages for any error responses. 1472285612Sdelphij */ 1473285612Sdelphijint 1474285612Sdelphijdoqueryex( 1475285612Sdelphij int opcode, 1476285612Sdelphij associd_t associd, 1477285612Sdelphij int auth, 1478293650Sglebius size_t qsize, 1479285612Sdelphij const char *qdata, 1480285612Sdelphij u_short *rstatus, 1481293650Sglebius size_t *rsize, 1482285612Sdelphij const char **rdata, 1483285612Sdelphij int quiet 1484285612Sdelphij ) 1485285612Sdelphij{ 148654359Sroberto int res; 148754359Sroberto int done; 148854359Sroberto 148954359Sroberto /* 149054359Sroberto * Check to make sure host is open 149154359Sroberto */ 149254359Sroberto if (!havehost) { 1493285612Sdelphij fprintf(stderr, "***No host open, use `host' command\n"); 149454359Sroberto return -1; 149554359Sroberto } 149654359Sroberto 149754359Sroberto done = 0; 149854359Sroberto sequence++; 149954359Sroberto 150054359Sroberto again: 150154359Sroberto /* 150254359Sroberto * send a request 150354359Sroberto */ 150454359Sroberto res = sendrequest(opcode, associd, auth, qsize, qdata); 150554359Sroberto if (res != 0) 1506285612Sdelphij return res; 1507285612Sdelphij 150854359Sroberto /* 150954359Sroberto * Get the response. If we got a standard error, print a message 151054359Sroberto */ 151154359Sroberto res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 151254359Sroberto 151354359Sroberto if (res > 0) { 151454359Sroberto if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 151554359Sroberto if (res == ERR_INCOMPLETE) { 151654359Sroberto /* 151754359Sroberto * better bump the sequence so we don't 151854359Sroberto * get confused about differing fragments. 151954359Sroberto */ 152054359Sroberto sequence++; 152154359Sroberto } 152254359Sroberto done = 1; 152354359Sroberto goto again; 152454359Sroberto } 1525285612Sdelphij if (!quiet) 1526285612Sdelphij show_error_msg(res, associd); 1527285612Sdelphij 152854359Sroberto } 152954359Sroberto return res; 153054359Sroberto} 153154359Sroberto 153254359Sroberto 1533285612Sdelphij#ifndef BUILD_AS_LIB 153454359Sroberto/* 153554359Sroberto * getcmds - read commands from the standard input and execute them 153654359Sroberto */ 153754359Srobertostatic void 153854359Srobertogetcmds(void) 153954359Sroberto{ 1540285612Sdelphij char * line; 1541285612Sdelphij int count; 154254359Sroberto 1543285612Sdelphij ntp_readline_init(interactive ? prompt : NULL); 1544106163Sroberto 1545285612Sdelphij for (;;) { 1546285612Sdelphij line = ntp_readline(&count); 1547285612Sdelphij if (NULL == line) 1548285612Sdelphij break; 1549285612Sdelphij docmd(line); 1550285612Sdelphij free(line); 1551285612Sdelphij } 155254359Sroberto 1553285612Sdelphij ntp_readline_uninit(); 155454359Sroberto} 1555285612Sdelphij#endif /* !BUILD_AS_LIB */ 155654359Sroberto 1557285612Sdelphij 1558285612Sdelphij#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 155954359Sroberto/* 156054359Sroberto * abortcmd - catch interrupts and abort the current command 156154359Sroberto */ 1562293650Sglebiusstatic int 1563293650Sglebiusabortcmd(void) 156454359Sroberto{ 156554359Sroberto if (current_output == stdout) 1566293650Sglebius (void) fflush(stdout); 156754359Sroberto putc('\n', stderr); 156854359Sroberto (void) fflush(stderr); 1569293650Sglebius if (jump) { 1570293650Sglebius jump = 0; 1571293650Sglebius longjmp(interrupt_buf, 1); 1572293650Sglebius } 1573293650Sglebius return TRUE; 157454359Sroberto} 1575285612Sdelphij#endif /* !SYS_WINNT && !BUILD_AS_LIB */ 157654359Sroberto 1577285612Sdelphij 1578285612Sdelphij#ifndef BUILD_AS_LIB 157954359Sroberto/* 158054359Sroberto * docmd - decode the command line and execute a command 158154359Sroberto */ 158254359Srobertostatic void 158354359Srobertodocmd( 158454359Sroberto const char *cmdline 158554359Sroberto ) 158654359Sroberto{ 158754359Sroberto char *tokens[1+MAXARGS+2]; 158854359Sroberto struct parse pcmd; 158954359Sroberto int ntok; 159054359Sroberto static int i; 159154359Sroberto struct xcmd *xcmd; 159254359Sroberto 159354359Sroberto /* 159454359Sroberto * Tokenize the command line. If nothing on it, return. 159554359Sroberto */ 159654359Sroberto tokenize(cmdline, tokens, &ntok); 159754359Sroberto if (ntok == 0) 159854359Sroberto return; 1599285612Sdelphij 160054359Sroberto /* 160154359Sroberto * Find the appropriate command description. 160254359Sroberto */ 160354359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 160454359Sroberto if (i == 0) { 160554359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 160654359Sroberto tokens[0]); 160754359Sroberto return; 160854359Sroberto } else if (i >= 2) { 160954359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 161054359Sroberto tokens[0]); 161154359Sroberto return; 161254359Sroberto } 1613285612Sdelphij 1614285612Sdelphij /* Warn about ignored extra args */ 1615285612Sdelphij for (i = MAXARGS + 1; i < ntok ; ++i) { 1616285612Sdelphij fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1617285612Sdelphij } 1618285612Sdelphij 161954359Sroberto /* 162054359Sroberto * Save the keyword, then walk through the arguments, interpreting 162154359Sroberto * as we go. 162254359Sroberto */ 162354359Sroberto pcmd.keyword = tokens[0]; 162454359Sroberto pcmd.nargs = 0; 162554359Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 162654359Sroberto if ((i+1) >= ntok) { 162754359Sroberto if (!(xcmd->arg[i] & OPT)) { 162854359Sroberto printusage(xcmd, stderr); 162954359Sroberto return; 163054359Sroberto } 163154359Sroberto break; 163254359Sroberto } 163354359Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1634285612Sdelphij break; 163554359Sroberto if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1636285612Sdelphij return; 163754359Sroberto pcmd.nargs++; 163854359Sroberto } 163954359Sroberto 164054359Sroberto i++; 164154359Sroberto if (i < ntok && *tokens[i] == '>') { 164254359Sroberto char *fname; 164354359Sroberto 164454359Sroberto if (*(tokens[i]+1) != '\0') 1645285612Sdelphij fname = tokens[i]+1; 164654359Sroberto else if ((i+1) < ntok) 1647285612Sdelphij fname = tokens[i+1]; 164854359Sroberto else { 164954359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 165054359Sroberto return; 165154359Sroberto } 165254359Sroberto 165354359Sroberto current_output = fopen(fname, "w"); 165454359Sroberto if (current_output == NULL) { 165554359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 165654359Sroberto perror(""); 165754359Sroberto return; 165854359Sroberto } 165954359Sroberto i = 1; /* flag we need a close */ 166054359Sroberto } else { 166154359Sroberto current_output = stdout; 166254359Sroberto i = 0; /* flag no close */ 166354359Sroberto } 166454359Sroberto 166554359Sroberto if (interactive && setjmp(interrupt_buf)) { 166654359Sroberto jump = 0; 166754359Sroberto return; 166854359Sroberto } else { 166954359Sroberto jump++; 167054359Sroberto (xcmd->handler)(&pcmd, current_output); 167154359Sroberto jump = 0; /* HMS: 961106: was after fclose() */ 167254359Sroberto if (i) (void) fclose(current_output); 167354359Sroberto } 1674285612Sdelphij 1675285612Sdelphij return; 167654359Sroberto} 167754359Sroberto 167854359Sroberto 167954359Sroberto/* 168054359Sroberto * tokenize - turn a command line into tokens 1681285612Sdelphij * 1682285612Sdelphij * SK: Modified to allow a quoted string 1683285612Sdelphij * 1684285612Sdelphij * HMS: If the first character of the first token is a ':' then (after 1685285612Sdelphij * eating inter-token whitespace) the 2nd token is the rest of the line. 168654359Sroberto */ 1687285612Sdelphij 168854359Srobertostatic void 168954359Srobertotokenize( 169054359Sroberto const char *line, 169154359Sroberto char **tokens, 169254359Sroberto int *ntok 169354359Sroberto ) 169454359Sroberto{ 169554359Sroberto register const char *cp; 169654359Sroberto register char *sp; 169754359Sroberto static char tspace[MAXLINE]; 169854359Sroberto 169954359Sroberto sp = tspace; 170054359Sroberto cp = line; 170154359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 170254359Sroberto tokens[*ntok] = sp; 1703285612Sdelphij 1704285612Sdelphij /* Skip inter-token whitespace */ 170554359Sroberto while (ISSPACE(*cp)) 170654359Sroberto cp++; 1707285612Sdelphij 1708285612Sdelphij /* If we're at EOL we're done */ 170954359Sroberto if (ISEOL(*cp)) 171054359Sroberto break; 171154359Sroberto 1712285612Sdelphij /* If this is the 2nd token and the first token begins 1713285612Sdelphij * with a ':', then just grab to EOL. 1714285612Sdelphij */ 1715285612Sdelphij 1716285612Sdelphij if (*ntok == 1 && tokens[0][0] == ':') { 1717285612Sdelphij do { 1718285612Sdelphij if (sp - tspace >= MAXLINE) 1719285612Sdelphij goto toobig; 1720285612Sdelphij *sp++ = *cp++; 1721285612Sdelphij } while (!ISEOL(*cp)); 1722285612Sdelphij } 1723285612Sdelphij 1724285612Sdelphij /* Check if this token begins with a double quote. 1725285612Sdelphij * If yes, continue reading till the next double quote 1726285612Sdelphij */ 1727285612Sdelphij else if (*cp == '\"') { 1728285612Sdelphij ++cp; 1729285612Sdelphij do { 1730285612Sdelphij if (sp - tspace >= MAXLINE) 1731285612Sdelphij goto toobig; 1732285612Sdelphij *sp++ = *cp++; 1733285612Sdelphij } while ((*cp != '\"') && !ISEOL(*cp)); 1734285612Sdelphij /* HMS: a missing closing " should be an error */ 1735285612Sdelphij } 1736285612Sdelphij else { 1737285612Sdelphij do { 1738285612Sdelphij if (sp - tspace >= MAXLINE) 1739285612Sdelphij goto toobig; 1740285612Sdelphij *sp++ = *cp++; 1741285612Sdelphij } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1742285612Sdelphij /* HMS: Why check for a " in the previous line? */ 1743285612Sdelphij } 1744285612Sdelphij 1745285612Sdelphij if (sp - tspace >= MAXLINE) 1746285612Sdelphij goto toobig; 174754359Sroberto *sp++ = '\0'; 174854359Sroberto } 1749285612Sdelphij return; 1750285612Sdelphij 1751285612Sdelphij toobig: 1752285612Sdelphij *ntok = 0; 1753285612Sdelphij fprintf(stderr, 1754285612Sdelphij "***Line `%s' is too big\n", 1755285612Sdelphij line); 1756285612Sdelphij return; 175754359Sroberto} 175854359Sroberto 175954359Sroberto 1760285612Sdelphij/* 1761285612Sdelphij * getarg - interpret an argument token 1762285612Sdelphij */ 1763285612Sdelphijstatic int 1764285612Sdelphijgetarg( 1765285612Sdelphij const char *str, 1766285612Sdelphij int code, 1767285612Sdelphij arg_v *argp 1768285612Sdelphij ) 1769285612Sdelphij{ 1770285612Sdelphij u_long ul; 177154359Sroberto 1772285612Sdelphij switch (code & ~OPT) { 1773285612Sdelphij case NTP_STR: 1774285612Sdelphij argp->string = str; 1775285612Sdelphij break; 1776285612Sdelphij 1777285612Sdelphij case NTP_ADD: 1778285612Sdelphij if (!getnetnum(str, &argp->netnum, NULL, 0)) 1779285612Sdelphij return 0; 1780285612Sdelphij break; 1781285612Sdelphij 1782285612Sdelphij case NTP_UINT: 1783285612Sdelphij if ('&' == str[0]) { 1784285612Sdelphij if (!atouint(&str[1], &ul)) { 1785285612Sdelphij fprintf(stderr, 1786285612Sdelphij "***Association index `%s' invalid/undecodable\n", 1787285612Sdelphij str); 1788285612Sdelphij return 0; 1789285612Sdelphij } 1790285612Sdelphij if (0 == numassoc) { 1791285612Sdelphij dogetassoc(stdout); 1792285612Sdelphij if (0 == numassoc) { 1793285612Sdelphij fprintf(stderr, 1794285612Sdelphij "***No associations found, `%s' unknown\n", 1795285612Sdelphij str); 1796285612Sdelphij return 0; 1797285612Sdelphij } 1798285612Sdelphij } 1799285612Sdelphij ul = min(ul, numassoc); 1800285612Sdelphij argp->uval = assoc_cache[ul - 1].assid; 1801285612Sdelphij break; 1802285612Sdelphij } 1803285612Sdelphij if (!atouint(str, &argp->uval)) { 1804285612Sdelphij fprintf(stderr, "***Illegal unsigned value %s\n", 1805285612Sdelphij str); 1806285612Sdelphij return 0; 1807285612Sdelphij } 1808285612Sdelphij break; 1809285612Sdelphij 1810285612Sdelphij case NTP_INT: 1811285612Sdelphij if (!atoint(str, &argp->ival)) { 1812285612Sdelphij fprintf(stderr, "***Illegal integer value %s\n", 1813285612Sdelphij str); 1814285612Sdelphij return 0; 1815285612Sdelphij } 1816285612Sdelphij break; 1817285612Sdelphij 1818285612Sdelphij case IP_VERSION: 1819285612Sdelphij if (!strcmp("-6", str)) { 1820285612Sdelphij argp->ival = 6; 1821285612Sdelphij } else if (!strcmp("-4", str)) { 1822285612Sdelphij argp->ival = 4; 1823285612Sdelphij } else { 1824285612Sdelphij fprintf(stderr, "***Version must be either 4 or 6\n"); 1825285612Sdelphij return 0; 1826285612Sdelphij } 1827285612Sdelphij break; 1828285612Sdelphij } 1829285612Sdelphij 1830285612Sdelphij return 1; 1831285612Sdelphij} 1832285612Sdelphij#endif /* !BUILD_AS_LIB */ 1833285612Sdelphij 1834285612Sdelphij 183554359Sroberto/* 183654359Sroberto * findcmd - find a command in a command description table 183754359Sroberto */ 183854359Srobertostatic int 183954359Srobertofindcmd( 1840285612Sdelphij const char * str, 1841285612Sdelphij struct xcmd * clist1, 1842285612Sdelphij struct xcmd * clist2, 1843285612Sdelphij struct xcmd ** cmd 184454359Sroberto ) 184554359Sroberto{ 1846285612Sdelphij struct xcmd *cl; 1847293650Sglebius size_t clen; 184854359Sroberto int nmatch; 184954359Sroberto struct xcmd *nearmatch = NULL; 185054359Sroberto struct xcmd *clist; 185154359Sroberto 185254359Sroberto clen = strlen(str); 185354359Sroberto nmatch = 0; 185454359Sroberto if (clist1 != 0) 185554359Sroberto clist = clist1; 185654359Sroberto else if (clist2 != 0) 185754359Sroberto clist = clist2; 185854359Sroberto else 185954359Sroberto return 0; 186054359Sroberto 186154359Sroberto again: 186254359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 186354359Sroberto /* do a first character check, for efficiency */ 186454359Sroberto if (*str != *(cl->keyword)) 186554359Sroberto continue; 186654359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 186754359Sroberto /* 186854359Sroberto * Could be extact match, could be approximate. 186954359Sroberto * Is exact if the length of the keyword is the 187054359Sroberto * same as the str. 187154359Sroberto */ 187254359Sroberto if (*((cl->keyword) + clen) == '\0') { 187354359Sroberto *cmd = cl; 187454359Sroberto return 1; 187554359Sroberto } 187654359Sroberto nmatch++; 187754359Sroberto nearmatch = cl; 187854359Sroberto } 187954359Sroberto } 188054359Sroberto 188154359Sroberto /* 188254359Sroberto * See if there is more to do. If so, go again. Sorry about the 188354359Sroberto * goto, too much looking at BSD sources... 188454359Sroberto */ 188554359Sroberto if (clist == clist1 && clist2 != 0) { 188654359Sroberto clist = clist2; 188754359Sroberto goto again; 188854359Sroberto } 188954359Sroberto 189054359Sroberto /* 189154359Sroberto * If we got extactly 1 near match, use it, else return number 189254359Sroberto * of matches. 189354359Sroberto */ 189454359Sroberto if (nmatch == 1) { 189554359Sroberto *cmd = nearmatch; 189654359Sroberto return 1; 189754359Sroberto } 189854359Sroberto return nmatch; 189954359Sroberto} 190054359Sroberto 190154359Sroberto 190254359Sroberto/* 190354359Sroberto * getnetnum - given a host name, return its net number 190454359Sroberto * and (optional) full name 190554359Sroberto */ 190654359Srobertoint 190754359Srobertogetnetnum( 190854359Sroberto const char *hname, 1909285612Sdelphij sockaddr_u *num, 1910132451Sroberto char *fullhost, 1911132451Sroberto int af 191254359Sroberto ) 191354359Sroberto{ 1914132451Sroberto struct addrinfo hints, *ai = NULL; 191554359Sroberto 1916285612Sdelphij ZERO(hints); 1917132451Sroberto hints.ai_flags = AI_CANONNAME; 1918132451Sroberto#ifdef AI_ADDRCONFIG 1919132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1920132451Sroberto#endif 1921285612Sdelphij 1922285612Sdelphij /* 1923285612Sdelphij * decodenetnum only works with addresses, but handles syntax 1924285612Sdelphij * that getaddrinfo doesn't: [2001::1]:1234 1925285612Sdelphij */ 192654359Sroberto if (decodenetnum(hname, num)) { 1927285612Sdelphij if (fullhost != NULL) 1928285612Sdelphij getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1929285612Sdelphij LENHOSTNAME, NULL, 0, 0); 193054359Sroberto return 1; 1931182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1932285612Sdelphij INSIST(sizeof(*num) >= ai->ai_addrlen); 1933285612Sdelphij memcpy(num, ai->ai_addr, ai->ai_addrlen); 1934285612Sdelphij if (fullhost != NULL) { 1935285612Sdelphij if (ai->ai_canonname != NULL) 1936285612Sdelphij strlcpy(fullhost, ai->ai_canonname, 1937285612Sdelphij LENHOSTNAME); 1938285612Sdelphij else 1939285612Sdelphij getnameinfo(&num->sa, SOCKLEN(num), 1940285612Sdelphij fullhost, LENHOSTNAME, NULL, 1941285612Sdelphij 0, 0); 1942285612Sdelphij } 1943285612Sdelphij freeaddrinfo(ai); 194454359Sroberto return 1; 194554359Sroberto } 1946285612Sdelphij fprintf(stderr, "***Can't find host %s\n", hname); 1947285612Sdelphij 1948285612Sdelphij return 0; 194954359Sroberto} 195054359Sroberto 1951285612Sdelphij 195254359Sroberto/* 195354359Sroberto * nntohost - convert network number to host name. This routine enforces 195454359Sroberto * the showhostnames setting. 195554359Sroberto */ 1956285612Sdelphijconst char * 195754359Srobertonntohost( 1958285612Sdelphij sockaddr_u *netnum 195954359Sroberto ) 196054359Sroberto{ 1961285612Sdelphij return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 196254359Sroberto} 196354359Sroberto 196454359Sroberto 196554359Sroberto/* 1966285612Sdelphij * nntohost_col - convert network number to host name in fixed width. 1967285612Sdelphij * This routine enforces the showhostnames setting. 1968285612Sdelphij * When displaying hostnames longer than the width, 1969285612Sdelphij * the first part of the hostname is displayed. When 1970285612Sdelphij * displaying numeric addresses longer than the width, 1971285612Sdelphij * Such as IPv6 addresses, the caller decides whether 1972285612Sdelphij * the first or last of the numeric address is used. 1973285612Sdelphij */ 1974285612Sdelphijconst char * 1975285612Sdelphijnntohost_col( 1976285612Sdelphij sockaddr_u * addr, 1977285612Sdelphij size_t width, 1978285612Sdelphij int preserve_lowaddrbits 1979285612Sdelphij ) 1980285612Sdelphij{ 1981285612Sdelphij const char * out; 1982285612Sdelphij 1983285612Sdelphij if (!showhostnames || SOCK_UNSPEC(addr)) { 1984285612Sdelphij if (preserve_lowaddrbits) 1985285612Sdelphij out = trunc_left(stoa(addr), width); 1986285612Sdelphij else 1987285612Sdelphij out = trunc_right(stoa(addr), width); 1988285612Sdelphij } else if (ISREFCLOCKADR(addr)) { 1989285612Sdelphij out = refnumtoa(addr); 1990285612Sdelphij } else { 1991285612Sdelphij out = trunc_right(socktohost(addr), width); 1992285612Sdelphij } 1993285612Sdelphij return out; 1994285612Sdelphij} 1995285612Sdelphij 1996285612Sdelphij 1997285612Sdelphij/* 1998285612Sdelphij * nntohostp() is the same as nntohost() plus a :port suffix 1999285612Sdelphij */ 2000285612Sdelphijconst char * 2001285612Sdelphijnntohostp( 2002285612Sdelphij sockaddr_u *netnum 2003285612Sdelphij ) 2004285612Sdelphij{ 2005285612Sdelphij const char * hostn; 2006285612Sdelphij char * buf; 2007285612Sdelphij 2008285612Sdelphij if (!showhostnames || SOCK_UNSPEC(netnum)) 2009285612Sdelphij return sptoa(netnum); 2010285612Sdelphij else if (ISREFCLOCKADR(netnum)) 2011285612Sdelphij return refnumtoa(netnum); 2012285612Sdelphij 2013285612Sdelphij hostn = socktohost(netnum); 2014285612Sdelphij LIB_GETBUF(buf); 2015285612Sdelphij snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 2016285612Sdelphij 2017285612Sdelphij return buf; 2018285612Sdelphij} 2019285612Sdelphij 2020285612Sdelphij/* 202154359Sroberto * rtdatetolfp - decode an RT-11 date into an l_fp 202254359Sroberto */ 202354359Srobertostatic int 202454359Srobertortdatetolfp( 202554359Sroberto char *str, 202654359Sroberto l_fp *lfp 202754359Sroberto ) 202854359Sroberto{ 202954359Sroberto register char *cp; 203054359Sroberto register int i; 203154359Sroberto struct calendar cal; 203254359Sroberto char buf[4]; 203354359Sroberto 203454359Sroberto cal.yearday = 0; 203554359Sroberto 203654359Sroberto /* 203754359Sroberto * An RT-11 date looks like: 203854359Sroberto * 203954359Sroberto * d[d]-Mth-y[y] hh:mm:ss 204054359Sroberto * 204154359Sroberto * (No docs, but assume 4-digit years are also legal...) 204254359Sroberto * 204354359Sroberto * d[d]-Mth-y[y[y[y]]] hh:mm:ss 204454359Sroberto */ 204554359Sroberto cp = str; 2046330567Sgordon if (!isdigit(pgetc(cp))) { 204754359Sroberto if (*cp == '-') { 204854359Sroberto /* 204954359Sroberto * Catch special case 205054359Sroberto */ 205154359Sroberto L_CLR(lfp); 205254359Sroberto return 1; 205354359Sroberto } 205454359Sroberto return 0; 205554359Sroberto } 205654359Sroberto 2057132451Sroberto cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 2058330567Sgordon if (isdigit(pgetc(cp))) { 2059132451Sroberto cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2060132451Sroberto cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 206154359Sroberto } 206254359Sroberto 206354359Sroberto if (*cp++ != '-') 206454359Sroberto return 0; 2065285612Sdelphij 206654359Sroberto for (i = 0; i < 3; i++) 206754359Sroberto buf[i] = *cp++; 206854359Sroberto buf[3] = '\0'; 206954359Sroberto 207054359Sroberto for (i = 0; i < 12; i++) 207154359Sroberto if (STREQ(buf, months[i])) 207254359Sroberto break; 207354359Sroberto if (i == 12) 207454359Sroberto return 0; 2075132451Sroberto cal.month = (u_char)(i + 1); 207654359Sroberto 207754359Sroberto if (*cp++ != '-') 207854359Sroberto return 0; 2079285612Sdelphij 2080330567Sgordon if (!isdigit(pgetc(cp))) 208154359Sroberto return 0; 2082132451Sroberto cal.year = (u_short)(*cp++ - '0'); 2083330567Sgordon if (isdigit(pgetc(cp))) { 2084132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2085132451Sroberto cal.year = (u_short)(*cp++ - '0'); 208654359Sroberto } 2087330567Sgordon if (isdigit(pgetc(cp))) { 2088132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2089132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 209054359Sroberto } 2091330567Sgordon if (isdigit(pgetc(cp))) { 2092132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2093132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 209454359Sroberto } 209554359Sroberto 209654359Sroberto /* 209754359Sroberto * Catch special case. If cal.year == 0 this is a zero timestamp. 209854359Sroberto */ 209954359Sroberto if (cal.year == 0) { 210054359Sroberto L_CLR(lfp); 210154359Sroberto return 1; 210254359Sroberto } 210354359Sroberto 2104330567Sgordon if (*cp++ != ' ' || !isdigit(pgetc(cp))) 210554359Sroberto return 0; 2106132451Sroberto cal.hour = (u_char)(*cp++ - '0'); 2107330567Sgordon if (isdigit(pgetc(cp))) { 2108132451Sroberto cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2109132451Sroberto cal.hour = (u_char)(cal.hour + *cp++ - '0'); 211054359Sroberto } 211154359Sroberto 2112330567Sgordon if (*cp++ != ':' || !isdigit(pgetc(cp))) 211354359Sroberto return 0; 2114132451Sroberto cal.minute = (u_char)(*cp++ - '0'); 2115330567Sgordon if (isdigit(pgetc(cp))) { 2116132451Sroberto cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2117132451Sroberto cal.minute = (u_char)(cal.minute + *cp++ - '0'); 211854359Sroberto } 211954359Sroberto 2120330567Sgordon if (*cp++ != ':' || !isdigit(pgetc(cp))) 212154359Sroberto return 0; 2122132451Sroberto cal.second = (u_char)(*cp++ - '0'); 2123330567Sgordon if (isdigit(pgetc(cp))) { 2124132451Sroberto cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2125132451Sroberto cal.second = (u_char)(cal.second + *cp++ - '0'); 212654359Sroberto } 212754359Sroberto 212854359Sroberto /* 212954359Sroberto * For RT-11, 1972 seems to be the pivot year 213054359Sroberto */ 213154359Sroberto if (cal.year < 72) 213254359Sroberto cal.year += 2000; 213354359Sroberto if (cal.year < 100) 213454359Sroberto cal.year += 1900; 213554359Sroberto 213654359Sroberto lfp->l_ui = caltontp(&cal); 213754359Sroberto lfp->l_uf = 0; 213854359Sroberto return 1; 213954359Sroberto} 214054359Sroberto 214154359Sroberto 214254359Sroberto/* 214354359Sroberto * decodets - decode a timestamp into an l_fp format number, with 214454359Sroberto * consideration of fuzzball formats. 214554359Sroberto */ 214654359Srobertoint 214754359Srobertodecodets( 214854359Sroberto char *str, 214954359Sroberto l_fp *lfp 215054359Sroberto ) 215154359Sroberto{ 2152285612Sdelphij char *cp; 2153285612Sdelphij char buf[30]; 2154285612Sdelphij size_t b; 2155285612Sdelphij 215654359Sroberto /* 215754359Sroberto * If it starts with a 0x, decode as hex. 215854359Sroberto */ 215954359Sroberto if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2160285612Sdelphij return hextolfp(str+2, lfp); 216154359Sroberto 216254359Sroberto /* 216354359Sroberto * If it starts with a '"', try it as an RT-11 date. 216454359Sroberto */ 216554359Sroberto if (*str == '"') { 2166285612Sdelphij cp = str + 1; 2167285612Sdelphij b = 0; 2168285612Sdelphij while ('"' != *cp && '\0' != *cp && 2169285612Sdelphij b < COUNTOF(buf) - 1) 2170285612Sdelphij buf[b++] = *cp++; 2171285612Sdelphij buf[b] = '\0'; 217254359Sroberto return rtdatetolfp(buf, lfp); 217354359Sroberto } 217454359Sroberto 217554359Sroberto /* 217654359Sroberto * Might still be hex. Check out the first character. Talk 217754359Sroberto * about heuristics! 217854359Sroberto */ 217954359Sroberto if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2180285612Sdelphij return hextolfp(str, lfp); 218154359Sroberto 218254359Sroberto /* 218354359Sroberto * Try it as a decimal. If this fails, try as an unquoted 218454359Sroberto * RT-11 date. This code should go away eventually. 218554359Sroberto */ 218654359Sroberto if (atolfp(str, lfp)) 2187285612Sdelphij return 1; 2188285612Sdelphij 218954359Sroberto return rtdatetolfp(str, lfp); 219054359Sroberto} 219154359Sroberto 219254359Sroberto 219354359Sroberto/* 219454359Sroberto * decodetime - decode a time value. It should be in milliseconds 219554359Sroberto */ 219654359Srobertoint 219754359Srobertodecodetime( 219854359Sroberto char *str, 219954359Sroberto l_fp *lfp 220054359Sroberto ) 220154359Sroberto{ 220254359Sroberto return mstolfp(str, lfp); 220354359Sroberto} 220454359Sroberto 220554359Sroberto 220654359Sroberto/* 220754359Sroberto * decodeint - decode an integer 220854359Sroberto */ 220954359Srobertoint 221054359Srobertodecodeint( 221154359Sroberto char *str, 221254359Sroberto long *val 221354359Sroberto ) 221454359Sroberto{ 221554359Sroberto if (*str == '0') { 221654359Sroberto if (*(str+1) == 'x' || *(str+1) == 'X') 2217285612Sdelphij return hextoint(str+2, (u_long *)val); 2218285612Sdelphij return octtoint(str, (u_long *)val); 221954359Sroberto } 222054359Sroberto return atoint(str, val); 222154359Sroberto} 222254359Sroberto 222354359Sroberto 222454359Sroberto/* 222554359Sroberto * decodeuint - decode an unsigned integer 222654359Sroberto */ 222754359Srobertoint 222854359Srobertodecodeuint( 222954359Sroberto char *str, 223054359Sroberto u_long *val 223154359Sroberto ) 223254359Sroberto{ 223354359Sroberto if (*str == '0') { 223454359Sroberto if (*(str + 1) == 'x' || *(str + 1) == 'X') 223554359Sroberto return (hextoint(str + 2, val)); 223654359Sroberto return (octtoint(str, val)); 223754359Sroberto } 223854359Sroberto return (atouint(str, val)); 223954359Sroberto} 224054359Sroberto 224154359Sroberto 224254359Sroberto/* 224354359Sroberto * decodearr - decode an array of time values 224454359Sroberto */ 224554359Srobertostatic int 224654359Srobertodecodearr( 2247330567Sgordon char *cp, 2248330567Sgordon int *narr, 2249330567Sgordon l_fp *lfpa, 2250330567Sgordon int amax 225154359Sroberto ) 225254359Sroberto{ 2253330567Sgordon char *bp; 225454359Sroberto char buf[60]; 225554359Sroberto 225654359Sroberto *narr = 0; 225754359Sroberto 2258330567Sgordon while (*narr < amax && *cp) { 2259330567Sgordon if (isspace(pgetc(cp))) { 2260330567Sgordon do 2261330567Sgordon ++cp; 2262330567Sgordon while (*cp && isspace(pgetc(cp))); 2263330567Sgordon } else { 2264330567Sgordon bp = buf; 2265330567Sgordon do { 2266330567Sgordon if (bp != (buf + sizeof(buf) - 1)) 2267330567Sgordon *bp++ = *cp; 2268330567Sgordon ++cp; 2269330567Sgordon } while (*cp && !isspace(pgetc(cp))); 2270330567Sgordon *bp = '\0'; 227154359Sroberto 2272330567Sgordon if (!decodetime(buf, lfpa)) 2273330567Sgordon return 0; 2274330567Sgordon ++(*narr); 2275330567Sgordon ++lfpa; 2276330567Sgordon } 227754359Sroberto } 227854359Sroberto return 1; 227954359Sroberto} 228054359Sroberto 228154359Sroberto 228254359Sroberto/* 228354359Sroberto * Finally, the built in command handlers 228454359Sroberto */ 228554359Sroberto 228654359Sroberto/* 228754359Sroberto * help - tell about commands, or details of a particular command 228854359Sroberto */ 228954359Srobertostatic void 229054359Srobertohelp( 229154359Sroberto struct parse *pcmd, 229254359Sroberto FILE *fp 229354359Sroberto ) 229454359Sroberto{ 2295285612Sdelphij struct xcmd *xcp = NULL; /* quiet warning */ 2296285612Sdelphij const char *cmd; 2297182007Sroberto const char *list[100]; 2298285612Sdelphij size_t word, words; 2299285612Sdelphij size_t row, rows; 2300285612Sdelphij size_t col, cols; 2301285612Sdelphij size_t length; 230254359Sroberto 230354359Sroberto if (pcmd->nargs == 0) { 2304182007Sroberto words = 0; 2305285612Sdelphij for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2306285612Sdelphij if (*(xcp->keyword) != '?' && 2307285612Sdelphij words < COUNTOF(list)) 2308285612Sdelphij list[words++] = xcp->keyword; 230954359Sroberto } 2310285612Sdelphij for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2311285612Sdelphij if (words < COUNTOF(list)) 2312285612Sdelphij list[words++] = xcp->keyword; 231354359Sroberto 2314285612Sdelphij qsort((void *)list, words, sizeof(list[0]), helpsort); 2315182007Sroberto col = 0; 2316182007Sroberto for (word = 0; word < words; word++) { 2317285612Sdelphij length = strlen(list[word]); 2318285612Sdelphij col = max(col, length); 231954359Sroberto } 232054359Sroberto 2321182007Sroberto cols = SCREENWIDTH / ++col; 2322285612Sdelphij rows = (words + cols - 1) / cols; 2323182007Sroberto 2324285612Sdelphij fprintf(fp, "ntpq commands:\n"); 2325182007Sroberto 2326182007Sroberto for (row = 0; row < rows; row++) { 2327285612Sdelphij for (word = row; word < words; word += rows) 2328285612Sdelphij fprintf(fp, "%-*.*s", (int)col, 2329285612Sdelphij (int)col - 1, list[word]); 2330285612Sdelphij fprintf(fp, "\n"); 2331285612Sdelphij } 233254359Sroberto } else { 233354359Sroberto cmd = pcmd->argval[0].string; 2334182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 2335182007Sroberto if (words == 0) { 2336285612Sdelphij fprintf(stderr, 2337285612Sdelphij "Command `%s' is unknown\n", cmd); 233854359Sroberto return; 2339182007Sroberto } else if (words >= 2) { 2340285612Sdelphij fprintf(stderr, 2341285612Sdelphij "Command `%s' is ambiguous\n", cmd); 234254359Sroberto return; 234354359Sroberto } 2344285612Sdelphij fprintf(fp, "function: %s\n", xcp->comment); 234554359Sroberto printusage(xcp, fp); 234654359Sroberto } 234754359Sroberto} 234854359Sroberto 234954359Sroberto 235054359Sroberto/* 235154359Sroberto * helpsort - do hostname qsort comparisons 235254359Sroberto */ 235354359Srobertostatic int 235454359Srobertohelpsort( 235554359Sroberto const void *t1, 235654359Sroberto const void *t2 235754359Sroberto ) 235854359Sroberto{ 2359285612Sdelphij const char * const * name1 = t1; 2360285612Sdelphij const char * const * name2 = t2; 236154359Sroberto 236254359Sroberto return strcmp(*name1, *name2); 236354359Sroberto} 236454359Sroberto 236554359Sroberto 236654359Sroberto/* 236754359Sroberto * printusage - print usage information for a command 236854359Sroberto */ 236954359Srobertostatic void 237054359Srobertoprintusage( 237154359Sroberto struct xcmd *xcp, 237254359Sroberto FILE *fp 237354359Sroberto ) 237454359Sroberto{ 237554359Sroberto register int i; 237654359Sroberto 2377285612Sdelphij /* XXX: Do we need to warn about extra args here too? */ 2378285612Sdelphij 237954359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 238054359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 238154359Sroberto if (xcp->arg[i] & OPT) 238254359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 238354359Sroberto else 238454359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 238554359Sroberto } 238654359Sroberto (void) fprintf(fp, "\n"); 238754359Sroberto} 238854359Sroberto 238954359Sroberto 239054359Sroberto/* 239154359Sroberto * timeout - set time out time 239254359Sroberto */ 239354359Srobertostatic void 239454359Srobertotimeout( 239554359Sroberto struct parse *pcmd, 239654359Sroberto FILE *fp 239754359Sroberto ) 239854359Sroberto{ 239954359Sroberto int val; 240054359Sroberto 240154359Sroberto if (pcmd->nargs == 0) { 2402285612Sdelphij val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 240354359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 240454359Sroberto } else { 240554359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 2406285612Sdelphij tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 240754359Sroberto * 1000; 240854359Sroberto } 240954359Sroberto} 241054359Sroberto 241154359Sroberto 241254359Sroberto/* 241354359Sroberto * auth_delay - set delay for auth requests 241454359Sroberto */ 241554359Srobertostatic void 241654359Srobertoauth_delay( 241754359Sroberto struct parse *pcmd, 241854359Sroberto FILE *fp 241954359Sroberto ) 242054359Sroberto{ 242154359Sroberto int isneg; 242254359Sroberto u_long val; 242354359Sroberto 242454359Sroberto if (pcmd->nargs == 0) { 242554359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 242654359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 242754359Sroberto } else { 242854359Sroberto if (pcmd->argval[0].ival < 0) { 242954359Sroberto isneg = 1; 243054359Sroberto val = (u_long)(-pcmd->argval[0].ival); 243154359Sroberto } else { 243254359Sroberto isneg = 0; 243354359Sroberto val = (u_long)pcmd->argval[0].ival; 243454359Sroberto } 243554359Sroberto 243654359Sroberto delay_time.l_ui = val / 1000; 243754359Sroberto val %= 1000; 243854359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 243954359Sroberto 244054359Sroberto if (isneg) 244154359Sroberto L_NEG(&delay_time); 244254359Sroberto } 244354359Sroberto} 244454359Sroberto 244554359Sroberto 244654359Sroberto/* 244754359Sroberto * host - set the host we are dealing with. 244854359Sroberto */ 244954359Srobertostatic void 245054359Srobertohost( 245154359Sroberto struct parse *pcmd, 245254359Sroberto FILE *fp 245354359Sroberto ) 245454359Sroberto{ 2455132451Sroberto int i; 2456132451Sroberto 245754359Sroberto if (pcmd->nargs == 0) { 245854359Sroberto if (havehost) 2459285612Sdelphij (void) fprintf(fp, "current host is %s\n", 2460285612Sdelphij currenthost); 246154359Sroberto else 2462285612Sdelphij (void) fprintf(fp, "no current host\n"); 2463132451Sroberto return; 2464132451Sroberto } 2465132451Sroberto 2466132451Sroberto i = 0; 2467132451Sroberto ai_fam_templ = ai_fam_default; 2468132451Sroberto if (pcmd->nargs == 2) { 2469132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 2470132451Sroberto ai_fam_templ = AF_INET; 2471132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 2472132451Sroberto ai_fam_templ = AF_INET6; 2473285612Sdelphij else 2474285612Sdelphij goto no_change; 2475132451Sroberto i = 1; 2476132451Sroberto } 2477285612Sdelphij if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2478285612Sdelphij fprintf(fp, "current host set to %s\n", currenthost); 247954359Sroberto } else { 2480285612Sdelphij no_change: 248154359Sroberto if (havehost) 2482285612Sdelphij fprintf(fp, "current host remains %s\n", 2483285612Sdelphij currenthost); 248454359Sroberto else 2485285612Sdelphij fprintf(fp, "still no current host\n"); 248654359Sroberto } 248754359Sroberto} 248854359Sroberto 248954359Sroberto 249054359Sroberto/* 249154359Sroberto * poll - do one (or more) polls of the host via NTP 249254359Sroberto */ 249354359Sroberto/*ARGSUSED*/ 249454359Srobertostatic void 249554359Srobertontp_poll( 249654359Sroberto struct parse *pcmd, 249754359Sroberto FILE *fp 249854359Sroberto ) 249954359Sroberto{ 250054359Sroberto (void) fprintf(fp, "poll not implemented yet\n"); 250154359Sroberto} 250254359Sroberto 250354359Sroberto 250454359Sroberto/* 2505298770Sdelphij * showdrefid2str - return a string explanation of the value of drefid 2506298770Sdelphij */ 2507298770Sdelphijstatic char * 2508298770Sdelphijshowdrefid2str(void) 2509298770Sdelphij{ 2510298770Sdelphij switch (drefid) { 2511298770Sdelphij case REFID_HASH: 2512298770Sdelphij return "hash"; 2513298770Sdelphij case REFID_IPV4: 2514298770Sdelphij return "ipv4"; 2515298770Sdelphij default: 2516298770Sdelphij return "Unknown"; 2517298770Sdelphij } 2518298770Sdelphij} 2519298770Sdelphij 2520298770Sdelphij 2521298770Sdelphij/* 2522298770Sdelphij * drefid - display/change "display hash" 2523298770Sdelphij */ 2524298770Sdelphijstatic void 2525298770Sdelphijshowdrefid( 2526298770Sdelphij struct parse *pcmd, 2527298770Sdelphij FILE *fp 2528298770Sdelphij ) 2529298770Sdelphij{ 2530298770Sdelphij if (pcmd->nargs == 0) { 2531298770Sdelphij (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2532298770Sdelphij return; 2533298770Sdelphij } else if (STREQ(pcmd->argval[0].string, "hash")) { 2534298770Sdelphij drefid = REFID_HASH; 2535298770Sdelphij } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2536298770Sdelphij drefid = REFID_IPV4; 2537298770Sdelphij } else { 2538298770Sdelphij (void) fprintf(fp, "What?\n"); 2539298770Sdelphij return; 2540298770Sdelphij } 2541298770Sdelphij (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2542298770Sdelphij} 2543298770Sdelphij 2544298770Sdelphij 2545298770Sdelphij/* 254654359Sroberto * keyid - get a keyid to use for authenticating requests 254754359Sroberto */ 254854359Srobertostatic void 254954359Srobertokeyid( 255054359Sroberto struct parse *pcmd, 255154359Sroberto FILE *fp 255254359Sroberto ) 255354359Sroberto{ 255454359Sroberto if (pcmd->nargs == 0) { 2555132451Sroberto if (info_auth_keyid == 0) 255654359Sroberto (void) fprintf(fp, "no keyid defined\n"); 255754359Sroberto else 255854359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 255954359Sroberto } else { 2560132451Sroberto /* allow zero so that keyid can be cleared. */ 2561132451Sroberto if(pcmd->argval[0].uval > NTP_MAXKEY) 2562132451Sroberto (void) fprintf(fp, "Invalid key identifier\n"); 256354359Sroberto info_auth_keyid = pcmd->argval[0].uval; 256454359Sroberto } 256554359Sroberto} 256654359Sroberto 256754359Sroberto/* 256854359Sroberto * keytype - get type of key to use for authenticating requests 256954359Sroberto */ 257054359Srobertostatic void 257154359Srobertokeytype( 257254359Sroberto struct parse *pcmd, 257354359Sroberto FILE *fp 257454359Sroberto ) 257554359Sroberto{ 2576285612Sdelphij const char * digest_name; 2577285612Sdelphij size_t digest_len; 2578285612Sdelphij int key_type; 257954359Sroberto 2580285612Sdelphij if (!pcmd->nargs) { 2581285612Sdelphij fprintf(fp, "keytype is %s with %lu octet digests\n", 2582285612Sdelphij keytype_name(info_auth_keytype), 2583285612Sdelphij (u_long)info_auth_hashlen); 2584285612Sdelphij return; 2585285612Sdelphij } 2586285612Sdelphij 2587285612Sdelphij digest_name = pcmd->argval[0].string; 2588285612Sdelphij digest_len = 0; 2589285612Sdelphij key_type = keytype_from_text(digest_name, &digest_len); 2590285612Sdelphij 2591285612Sdelphij if (!key_type) { 2592285612Sdelphij fprintf(fp, "keytype is not valid. " 2593285612Sdelphij#ifdef OPENSSL 2594285612Sdelphij "Type \"help keytype\" for the available digest types.\n"); 2595285612Sdelphij#else 2596285612Sdelphij "Only \"md5\" is available.\n"); 2597285612Sdelphij#endif 2598285612Sdelphij return; 2599285612Sdelphij } 2600285612Sdelphij 2601285612Sdelphij info_auth_keytype = key_type; 2602285612Sdelphij info_auth_hashlen = digest_len; 260354359Sroberto} 260454359Sroberto 260554359Sroberto 260654359Sroberto/* 260754359Sroberto * passwd - get an authentication key 260854359Sroberto */ 260954359Sroberto/*ARGSUSED*/ 261054359Srobertostatic void 261154359Srobertopasswd( 261254359Sroberto struct parse *pcmd, 261354359Sroberto FILE *fp 261454359Sroberto ) 261554359Sroberto{ 2616285612Sdelphij const char *pass; 261754359Sroberto 2618132451Sroberto if (info_auth_keyid == 0) { 2619285612Sdelphij info_auth_keyid = getkeyid("Keyid: "); 2620285612Sdelphij if (info_auth_keyid == 0) { 2621285612Sdelphij (void)fprintf(fp, "Keyid must be defined\n"); 262254359Sroberto return; 262354359Sroberto } 262454359Sroberto } 2625285612Sdelphij if (pcmd->nargs >= 1) 2626285612Sdelphij pass = pcmd->argval[0].string; 2627132451Sroberto else { 2628285612Sdelphij pass = getpass_keytype(info_auth_keytype); 2629285612Sdelphij if ('\0' == pass[0]) { 2630285612Sdelphij fprintf(fp, "Password unchanged\n"); 2631285612Sdelphij return; 2632285612Sdelphij } 2633132451Sroberto } 2634285612Sdelphij authusekey(info_auth_keyid, info_auth_keytype, 2635285612Sdelphij (const u_char *)pass); 2636285612Sdelphij authtrust(info_auth_keyid, 1); 263754359Sroberto} 263854359Sroberto 263954359Sroberto 264054359Sroberto/* 264154359Sroberto * hostnames - set the showhostnames flag 264254359Sroberto */ 264354359Srobertostatic void 264454359Srobertohostnames( 264554359Sroberto struct parse *pcmd, 264654359Sroberto FILE *fp 264754359Sroberto ) 264854359Sroberto{ 264954359Sroberto if (pcmd->nargs == 0) { 265054359Sroberto if (showhostnames) 265154359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 265254359Sroberto else 265354359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 265454359Sroberto } else { 265554359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 265654359Sroberto showhostnames = 1; 265754359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 265854359Sroberto showhostnames = 0; 265954359Sroberto else 266054359Sroberto (void)fprintf(stderr, "What?\n"); 266154359Sroberto } 266254359Sroberto} 266354359Sroberto 266454359Sroberto 266554359Sroberto 266654359Sroberto/* 266754359Sroberto * setdebug - set/change debugging level 266854359Sroberto */ 266954359Srobertostatic void 267054359Srobertosetdebug( 267154359Sroberto struct parse *pcmd, 267254359Sroberto FILE *fp 267354359Sroberto ) 267454359Sroberto{ 267554359Sroberto if (pcmd->nargs == 0) { 267654359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 267754359Sroberto return; 267854359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 267954359Sroberto debug = 0; 268054359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 268154359Sroberto debug++; 268254359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 268354359Sroberto debug--; 268454359Sroberto } else { 268554359Sroberto (void) fprintf(fp, "What?\n"); 268654359Sroberto return; 268754359Sroberto } 268854359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 268954359Sroberto} 269054359Sroberto 269154359Sroberto 269254359Sroberto/* 269354359Sroberto * quit - stop this nonsense 269454359Sroberto */ 269554359Sroberto/*ARGSUSED*/ 269654359Srobertostatic void 269754359Srobertoquit( 269854359Sroberto struct parse *pcmd, 269954359Sroberto FILE *fp 270054359Sroberto ) 270154359Sroberto{ 270254359Sroberto if (havehost) 270354359Sroberto closesocket(sockfd); /* cleanliness next to godliness */ 270454359Sroberto exit(0); 270554359Sroberto} 270654359Sroberto 270754359Sroberto 270854359Sroberto/* 270954359Sroberto * version - print the current version number 271054359Sroberto */ 271154359Sroberto/*ARGSUSED*/ 271254359Srobertostatic void 271354359Srobertoversion( 271454359Sroberto struct parse *pcmd, 271554359Sroberto FILE *fp 271654359Sroberto ) 271754359Sroberto{ 271854359Sroberto 271954359Sroberto (void) fprintf(fp, "%s\n", Version); 272054359Sroberto return; 272154359Sroberto} 272254359Sroberto 272354359Sroberto 272454359Sroberto/* 272554359Sroberto * raw - set raw mode output 272654359Sroberto */ 272754359Sroberto/*ARGSUSED*/ 272854359Srobertostatic void 272954359Srobertoraw( 273054359Sroberto struct parse *pcmd, 273154359Sroberto FILE *fp 273254359Sroberto ) 273354359Sroberto{ 273454359Sroberto rawmode = 1; 273554359Sroberto (void) fprintf(fp, "Output set to raw\n"); 273654359Sroberto} 273754359Sroberto 273854359Sroberto 273954359Sroberto/* 274054359Sroberto * cooked - set cooked mode output 274154359Sroberto */ 274254359Sroberto/*ARGSUSED*/ 274354359Srobertostatic void 274454359Srobertocooked( 274554359Sroberto struct parse *pcmd, 274654359Sroberto FILE *fp 274754359Sroberto ) 274854359Sroberto{ 274954359Sroberto rawmode = 0; 275054359Sroberto (void) fprintf(fp, "Output set to cooked\n"); 275154359Sroberto return; 275254359Sroberto} 275354359Sroberto 275454359Sroberto 275554359Sroberto/* 275654359Sroberto * authenticate - always authenticate requests to this host 275754359Sroberto */ 275854359Srobertostatic void 275954359Srobertoauthenticate( 276054359Sroberto struct parse *pcmd, 276154359Sroberto FILE *fp 276254359Sroberto ) 276354359Sroberto{ 276454359Sroberto if (pcmd->nargs == 0) { 276554359Sroberto if (always_auth) { 276654359Sroberto (void) fprintf(fp, 276754359Sroberto "authenticated requests being sent\n"); 276854359Sroberto } else 276954359Sroberto (void) fprintf(fp, 277054359Sroberto "unauthenticated requests being sent\n"); 277154359Sroberto } else { 277254359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) { 277354359Sroberto always_auth = 1; 277454359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 277554359Sroberto always_auth = 0; 277654359Sroberto } else 277754359Sroberto (void)fprintf(stderr, "What?\n"); 277854359Sroberto } 277954359Sroberto} 278054359Sroberto 278154359Sroberto 278254359Sroberto/* 278354359Sroberto * ntpversion - choose the NTP version to use 278454359Sroberto */ 278554359Srobertostatic void 278654359Srobertontpversion( 278754359Sroberto struct parse *pcmd, 278854359Sroberto FILE *fp 278954359Sroberto ) 279054359Sroberto{ 279154359Sroberto if (pcmd->nargs == 0) { 279254359Sroberto (void) fprintf(fp, 279354359Sroberto "NTP version being claimed is %d\n", pktversion); 279454359Sroberto } else { 279554359Sroberto if (pcmd->argval[0].uval < NTP_OLDVERSION 279654359Sroberto || pcmd->argval[0].uval > NTP_VERSION) { 279754359Sroberto (void) fprintf(stderr, "versions %d to %d, please\n", 279854359Sroberto NTP_OLDVERSION, NTP_VERSION); 279954359Sroberto } else { 280054359Sroberto pktversion = (u_char) pcmd->argval[0].uval; 280154359Sroberto } 280254359Sroberto } 280354359Sroberto} 280454359Sroberto 280554359Sroberto 2806285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 0))) 2807285612Sdelphijvwarning(const char *fmt, va_list ap) 2808285612Sdelphij{ 2809285612Sdelphij int serrno = errno; 2810285612Sdelphij (void) fprintf(stderr, "%s: ", progname); 2811285612Sdelphij vfprintf(stderr, fmt, ap); 2812293650Sglebius (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2813285612Sdelphij} 2814285612Sdelphij 281554359Sroberto/* 281654359Sroberto * warning - print a warning message 281754359Sroberto */ 2818285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 2))) 281954359Srobertowarning( 282054359Sroberto const char *fmt, 2821285612Sdelphij ... 282254359Sroberto ) 282354359Sroberto{ 2824285612Sdelphij va_list ap; 2825285612Sdelphij va_start(ap, fmt); 2826285612Sdelphij vwarning(fmt, ap); 2827285612Sdelphij va_end(ap); 282854359Sroberto} 282954359Sroberto 283054359Sroberto 283154359Sroberto/* 283254359Sroberto * error - print a message and exit 283354359Sroberto */ 2834285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 2))) 283554359Srobertoerror( 283654359Sroberto const char *fmt, 2837285612Sdelphij ... 283854359Sroberto ) 283954359Sroberto{ 2840285612Sdelphij va_list ap; 2841285612Sdelphij va_start(ap, fmt); 2842285612Sdelphij vwarning(fmt, ap); 2843285612Sdelphij va_end(ap); 284454359Sroberto exit(1); 284554359Sroberto} 284654359Sroberto/* 284754359Sroberto * getkeyid - prompt the user for a keyid to use 284854359Sroberto */ 284954359Srobertostatic u_long 285054359Srobertogetkeyid( 285154359Sroberto const char *keyprompt 285254359Sroberto ) 285354359Sroberto{ 2854285612Sdelphij int c; 285554359Sroberto FILE *fi; 285654359Sroberto char pbuf[20]; 2857285612Sdelphij size_t i; 2858285612Sdelphij size_t ilim; 285954359Sroberto 286054359Sroberto#ifndef SYS_WINNT 286154359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 286254359Sroberto#else 2863285612Sdelphij if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 286454359Sroberto#endif /* SYS_WINNT */ 286554359Sroberto fi = stdin; 2866285612Sdelphij else 286754359Sroberto setbuf(fi, (char *)NULL); 286854359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 2869285612Sdelphij for (i = 0, ilim = COUNTOF(pbuf) - 1; 2870285612Sdelphij i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2871285612Sdelphij ) 2872285612Sdelphij pbuf[i++] = (char)c; 2873285612Sdelphij pbuf[i] = '\0'; 287454359Sroberto if (fi != stdin) 2875285612Sdelphij fclose(fi); 287654359Sroberto 287754359Sroberto return (u_long) atoi(pbuf); 287854359Sroberto} 287954359Sroberto 288054359Sroberto 288154359Sroberto/* 288254359Sroberto * atoascii - printable-ize possibly ascii data using the character 288354359Sroberto * transformations cat -v uses. 288454359Sroberto */ 288554359Srobertostatic void 288654359Srobertoatoascii( 2887285612Sdelphij const char *in, 2888285612Sdelphij size_t in_octets, 2889285612Sdelphij char *out, 2890285612Sdelphij size_t out_octets 289154359Sroberto ) 289254359Sroberto{ 2893285612Sdelphij const u_char * pchIn; 2894285612Sdelphij const u_char * pchInLimit; 2895285612Sdelphij u_char * pchOut; 2896285612Sdelphij u_char c; 289754359Sroberto 2898285612Sdelphij pchIn = (const u_char *)in; 2899285612Sdelphij pchInLimit = pchIn + in_octets; 2900285612Sdelphij pchOut = (u_char *)out; 2901285612Sdelphij 2902285612Sdelphij if (NULL == pchIn) { 2903285612Sdelphij if (0 < out_octets) 2904285612Sdelphij *pchOut = '\0'; 290554359Sroberto return; 290654359Sroberto } 290754359Sroberto 2908285612Sdelphij#define ONEOUT(c) \ 2909285612Sdelphijdo { \ 2910285612Sdelphij if (0 == --out_octets) { \ 2911285612Sdelphij *pchOut = '\0'; \ 2912285612Sdelphij return; \ 2913285612Sdelphij } \ 2914285612Sdelphij *pchOut++ = (c); \ 2915285612Sdelphij} while (0) 2916285612Sdelphij 2917285612Sdelphij for ( ; pchIn < pchInLimit; pchIn++) { 2918285612Sdelphij c = *pchIn; 2919285612Sdelphij if ('\0' == c) 2920285612Sdelphij break; 2921285612Sdelphij if (c & 0x80) { 2922285612Sdelphij ONEOUT('M'); 2923285612Sdelphij ONEOUT('-'); 2924285612Sdelphij c &= 0x7f; 292554359Sroberto } 292654359Sroberto if (c < ' ') { 2927285612Sdelphij ONEOUT('^'); 2928285612Sdelphij ONEOUT((u_char)(c + '@')); 2929285612Sdelphij } else if (0x7f == c) { 2930285612Sdelphij ONEOUT('^'); 2931285612Sdelphij ONEOUT('?'); 2932285612Sdelphij } else 2933285612Sdelphij ONEOUT(c); 293454359Sroberto } 2935285612Sdelphij ONEOUT('\0'); 2936285612Sdelphij 2937285612Sdelphij#undef ONEOUT 293854359Sroberto} 293954359Sroberto 294054359Sroberto 294154359Sroberto/* 294254359Sroberto * makeascii - print possibly ascii data using the character 294354359Sroberto * transformations that cat -v uses. 294454359Sroberto */ 2945285612Sdelphijvoid 294654359Srobertomakeascii( 2947293650Sglebius size_t length, 2948285612Sdelphij const char *data, 294954359Sroberto FILE *fp 295054359Sroberto ) 295154359Sroberto{ 2952285612Sdelphij const u_char *data_u_char; 2953285612Sdelphij const u_char *cp; 2954285612Sdelphij int c; 295554359Sroberto 2956285612Sdelphij data_u_char = (const u_char *)data; 2957285612Sdelphij 2958285612Sdelphij for (cp = data_u_char; cp < data_u_char + length; cp++) { 295954359Sroberto c = (int)*cp; 2960285612Sdelphij if (c & 0x80) { 296154359Sroberto putc('M', fp); 296254359Sroberto putc('-', fp); 2963285612Sdelphij c &= 0x7f; 296454359Sroberto } 296554359Sroberto 296654359Sroberto if (c < ' ') { 296754359Sroberto putc('^', fp); 2968285612Sdelphij putc(c + '@', fp); 2969285612Sdelphij } else if (0x7f == c) { 297054359Sroberto putc('^', fp); 297154359Sroberto putc('?', fp); 2972285612Sdelphij } else 297354359Sroberto putc(c, fp); 297454359Sroberto } 297554359Sroberto} 297654359Sroberto 297754359Sroberto 297854359Sroberto/* 297954359Sroberto * asciize - same thing as makeascii except add a newline 298054359Sroberto */ 298154359Srobertovoid 298254359Srobertoasciize( 298354359Sroberto int length, 298454359Sroberto char *data, 298554359Sroberto FILE *fp 298654359Sroberto ) 298754359Sroberto{ 298854359Sroberto makeascii(length, data, fp); 298954359Sroberto putc('\n', fp); 299054359Sroberto} 299154359Sroberto 299254359Sroberto 299354359Sroberto/* 2994285612Sdelphij * truncate string to fit clipping excess at end. 2995285612Sdelphij * "too long" -> "too l" 2996285612Sdelphij * Used for hostnames. 2997285612Sdelphij */ 2998285612Sdelphijconst char * 2999285612Sdelphijtrunc_right( 3000285612Sdelphij const char * src, 3001285612Sdelphij size_t width 3002285612Sdelphij ) 3003285612Sdelphij{ 3004285612Sdelphij size_t sl; 3005285612Sdelphij char * out; 3006285612Sdelphij 3007285612Sdelphij 3008285612Sdelphij sl = strlen(src); 3009285612Sdelphij if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 3010285612Sdelphij LIB_GETBUF(out); 3011285612Sdelphij memcpy(out, src, width); 3012285612Sdelphij out[width] = '\0'; 3013285612Sdelphij 3014285612Sdelphij return out; 3015285612Sdelphij } 3016285612Sdelphij 3017285612Sdelphij return src; 3018285612Sdelphij} 3019285612Sdelphij 3020285612Sdelphij 3021285612Sdelphij/* 3022285612Sdelphij * truncate string to fit by preserving right side and using '_' to hint 3023285612Sdelphij * "too long" -> "_long" 3024285612Sdelphij * Used for local IPv6 addresses, where low bits differentiate. 3025285612Sdelphij */ 3026285612Sdelphijconst char * 3027285612Sdelphijtrunc_left( 3028285612Sdelphij const char * src, 3029285612Sdelphij size_t width 3030285612Sdelphij ) 3031285612Sdelphij{ 3032285612Sdelphij size_t sl; 3033285612Sdelphij char * out; 3034285612Sdelphij 3035285612Sdelphij 3036285612Sdelphij sl = strlen(src); 3037285612Sdelphij if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 3038285612Sdelphij LIB_GETBUF(out); 3039285612Sdelphij out[0] = '_'; 3040285612Sdelphij memcpy(&out[1], &src[sl + 1 - width], width); 3041285612Sdelphij 3042285612Sdelphij return out; 3043285612Sdelphij } 3044285612Sdelphij 3045285612Sdelphij return src; 3046285612Sdelphij} 3047285612Sdelphij 3048285612Sdelphij 3049285612Sdelphij/* 305054359Sroberto * Some circular buffer space 305154359Sroberto */ 305254359Sroberto#define CBLEN 80 305354359Sroberto#define NUMCB 6 305454359Sroberto 305554359Srobertochar circ_buf[NUMCB][CBLEN]; 305654359Srobertoint nextcb = 0; 305754359Sroberto 305854359Sroberto/* 305954359Sroberto * nextvar - find the next variable in the buffer 306054359Sroberto */ 306154359Srobertoint 306254359Srobertonextvar( 3063293650Sglebius size_t *datalen, 3064285612Sdelphij const char **datap, 306554359Sroberto char **vname, 306654359Sroberto char **vvalue 306754359Sroberto ) 306854359Sroberto{ 3069285612Sdelphij const char *cp; 3070285612Sdelphij const char *np; 3071285612Sdelphij const char *cpend; 3072285612Sdelphij size_t srclen; 3073285612Sdelphij size_t len; 307454359Sroberto static char name[MAXVARLEN]; 307554359Sroberto static char value[MAXVALLEN]; 307654359Sroberto 307754359Sroberto cp = *datap; 307854359Sroberto cpend = cp + *datalen; 307954359Sroberto 308054359Sroberto /* 308154359Sroberto * Space past commas and white space 308254359Sroberto */ 3083330567Sgordon while (cp < cpend && (*cp == ',' || isspace(pgetc(cp)))) 3084285612Sdelphij cp++; 3085285612Sdelphij if (cp >= cpend) 3086285612Sdelphij return 0; 3087285612Sdelphij 308854359Sroberto /* 308954359Sroberto * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace 309054359Sroberto * over any white space and terminate it. 309154359Sroberto */ 3092285612Sdelphij srclen = strcspn(cp, ",=\r\n"); 3093285612Sdelphij srclen = min(srclen, (size_t)(cpend - cp)); 3094285612Sdelphij len = srclen; 3095330567Sgordon while (len > 0 && isspace(pgetc(&cp[len - 1]))) 3096285612Sdelphij len--; 3097294569Sdelphij if (len >= sizeof(name)) 3098294569Sdelphij return 0; 3099285612Sdelphij if (len > 0) 3100285612Sdelphij memcpy(name, cp, len); 3101285612Sdelphij name[len] = '\0'; 310254359Sroberto *vname = name; 3103285612Sdelphij cp += srclen; 310454359Sroberto 310554359Sroberto /* 310654359Sroberto * Check if we hit the end of the buffer or a ','. If so we are done. 310754359Sroberto */ 3108285612Sdelphij if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { 3109285612Sdelphij if (cp < cpend) 3110285612Sdelphij cp++; 311154359Sroberto *datap = cp; 3112293650Sglebius *datalen = size2int_sat(cpend - cp); 3113285612Sdelphij *vvalue = NULL; 311454359Sroberto return 1; 311554359Sroberto } 311654359Sroberto 311754359Sroberto /* 311854359Sroberto * So far, so good. Copy out the value 311954359Sroberto */ 312054359Sroberto cp++; /* past '=' */ 3121330567Sgordon while (cp < cpend && (isspace(pgetc(cp)) && *cp != '\r' && *cp != '\n')) 3122285612Sdelphij cp++; 3123285612Sdelphij np = cp; 3124285612Sdelphij if ('"' == *np) { 3125285612Sdelphij do { 3126285612Sdelphij np++; 3127285612Sdelphij } while (np < cpend && '"' != *np); 3128285612Sdelphij if (np < cpend && '"' == *np) 3129285612Sdelphij np++; 3130285612Sdelphij } else { 3131285612Sdelphij while (np < cpend && ',' != *np && '\r' != *np) 3132285612Sdelphij np++; 313354359Sroberto } 3134285612Sdelphij len = np - cp; 3135285612Sdelphij if (np > cpend || len >= sizeof(value) || 3136285612Sdelphij (np < cpend && ',' != *np && '\r' != *np)) 3137285612Sdelphij return 0; 3138285612Sdelphij memcpy(value, cp, len); 313954359Sroberto /* 314054359Sroberto * Trim off any trailing whitespace 314154359Sroberto */ 3142330567Sgordon while (len > 0 && isspace(pgetc(&value[len - 1]))) 3143285612Sdelphij len--; 3144285612Sdelphij value[len] = '\0'; 314554359Sroberto 314654359Sroberto /* 314754359Sroberto * Return this. All done. 314854359Sroberto */ 3149285612Sdelphij if (np < cpend && ',' == *np) 3150285612Sdelphij np++; 3151285612Sdelphij *datap = np; 3152293650Sglebius *datalen = size2int_sat(cpend - np); 315354359Sroberto *vvalue = value; 315454359Sroberto return 1; 315554359Sroberto} 315654359Sroberto 315754359Sroberto 3158285612Sdelphiju_short 3159285612Sdelphijvarfmt(const char * varname) 316054359Sroberto{ 3161285612Sdelphij u_int n; 316254359Sroberto 3163285612Sdelphij for (n = 0; n < COUNTOF(cookedvars); n++) 3164285612Sdelphij if (!strcmp(varname, cookedvars[n].varname)) 3165285612Sdelphij return cookedvars[n].fmt; 3166285612Sdelphij 3167285612Sdelphij return PADDING; 316854359Sroberto} 316954359Sroberto 317054359Sroberto 317154359Sroberto/* 317254359Sroberto * printvars - print variables returned in response packet 317354359Sroberto */ 317454359Srobertovoid 317554359Srobertoprintvars( 3176293650Sglebius size_t length, 3177285612Sdelphij const char *data, 317854359Sroberto int status, 317954359Sroberto int sttype, 3180285612Sdelphij int quiet, 318154359Sroberto FILE *fp 318254359Sroberto ) 318354359Sroberto{ 318454359Sroberto if (rawmode) 3185285612Sdelphij rawprint(sttype, length, data, status, quiet, fp); 318654359Sroberto else 3187285612Sdelphij cookedprint(sttype, length, data, status, quiet, fp); 318854359Sroberto} 318954359Sroberto 319054359Sroberto 319154359Sroberto/* 319254359Sroberto * rawprint - do a printout of the data in raw mode 319354359Sroberto */ 319454359Srobertostatic void 319554359Srobertorawprint( 319654359Sroberto int datatype, 3197293650Sglebius size_t length, 3198285612Sdelphij const char *data, 319954359Sroberto int status, 3200285612Sdelphij int quiet, 320154359Sroberto FILE *fp 320254359Sroberto ) 320354359Sroberto{ 3204285612Sdelphij const char *cp; 3205285612Sdelphij const char *cpend; 320654359Sroberto 320754359Sroberto /* 320854359Sroberto * Essentially print the data as is. We reformat unprintables, though. 320954359Sroberto */ 321054359Sroberto cp = data; 321154359Sroberto cpend = data + length; 321254359Sroberto 3213285612Sdelphij if (!quiet) 3214285612Sdelphij (void) fprintf(fp, "status=0x%04x,\n", status); 321554359Sroberto 321654359Sroberto while (cp < cpend) { 321754359Sroberto if (*cp == '\r') { 321854359Sroberto /* 321954359Sroberto * If this is a \r and the next character is a 322054359Sroberto * \n, supress this, else pretty print it. Otherwise 322154359Sroberto * just output the character. 322254359Sroberto */ 3223285612Sdelphij if (cp == (cpend - 1) || *(cp + 1) != '\n') 322454359Sroberto makeascii(1, cp, fp); 3225330567Sgordon } else if (isspace(pgetc(cp)) || isprint(pgetc(cp))) 322654359Sroberto putc(*cp, fp); 3227285612Sdelphij else 322854359Sroberto makeascii(1, cp, fp); 322954359Sroberto cp++; 323054359Sroberto } 323154359Sroberto} 323254359Sroberto 323354359Sroberto 323454359Sroberto/* 323554359Sroberto * Global data used by the cooked output routines 323654359Sroberto */ 323754359Srobertoint out_chars; /* number of characters output */ 323854359Srobertoint out_linecount; /* number of characters output on this line */ 323954359Sroberto 324054359Sroberto 324154359Sroberto/* 324254359Sroberto * startoutput - get ready to do cooked output 324354359Sroberto */ 324454359Srobertostatic void 324554359Srobertostartoutput(void) 324654359Sroberto{ 324754359Sroberto out_chars = 0; 324854359Sroberto out_linecount = 0; 324954359Sroberto} 325054359Sroberto 325154359Sroberto 325254359Sroberto/* 325354359Sroberto * output - output a variable=value combination 325454359Sroberto */ 325554359Srobertostatic void 325654359Srobertooutput( 325754359Sroberto FILE *fp, 3258285612Sdelphij const char *name, 3259285612Sdelphij const char *value 326054359Sroberto ) 326154359Sroberto{ 3262293650Sglebius int len; 326354359Sroberto 3264285612Sdelphij /* strlen of "name=value" */ 3265293650Sglebius len = size2int_sat(strlen(name) + 1 + strlen(value)); 326654359Sroberto 326754359Sroberto if (out_chars != 0) { 3268285612Sdelphij out_chars += 2; 3269285612Sdelphij if ((out_linecount + len + 2) > MAXOUTLINE) { 3270285612Sdelphij fputs(",\n", fp); 327154359Sroberto out_linecount = 0; 327254359Sroberto } else { 3273285612Sdelphij fputs(", ", fp); 3274285612Sdelphij out_linecount += 2; 327554359Sroberto } 327654359Sroberto } 327754359Sroberto 327854359Sroberto fputs(name, fp); 327954359Sroberto putc('=', fp); 328054359Sroberto fputs(value, fp); 3281285612Sdelphij out_chars += len; 3282285612Sdelphij out_linecount += len; 328354359Sroberto} 328454359Sroberto 328554359Sroberto 328654359Sroberto/* 328754359Sroberto * endoutput - terminate a block of cooked output 328854359Sroberto */ 328954359Srobertostatic void 329054359Srobertoendoutput( 329154359Sroberto FILE *fp 329254359Sroberto ) 329354359Sroberto{ 329454359Sroberto if (out_chars != 0) 3295285612Sdelphij putc('\n', fp); 329654359Sroberto} 329754359Sroberto 329854359Sroberto 329954359Sroberto/* 330054359Sroberto * outputarr - output an array of values 330154359Sroberto */ 330254359Srobertostatic void 330354359Srobertooutputarr( 330454359Sroberto FILE *fp, 330554359Sroberto char *name, 330654359Sroberto int narr, 330754359Sroberto l_fp *lfp 330854359Sroberto ) 330954359Sroberto{ 3310293650Sglebius char *bp; 3311293650Sglebius char *cp; 3312293650Sglebius size_t i; 3313293650Sglebius size_t len; 331454359Sroberto char buf[256]; 331554359Sroberto 331654359Sroberto bp = buf; 331754359Sroberto /* 331854359Sroberto * Hack to align delay and offset values 331954359Sroberto */ 332054359Sroberto for (i = (int)strlen(name); i < 11; i++) 332154359Sroberto *bp++ = ' '; 3322285612Sdelphij 332354359Sroberto for (i = narr; i > 0; i--) { 332454359Sroberto if (i != narr) 332554359Sroberto *bp++ = ' '; 332654359Sroberto cp = lfptoms(lfp, 2); 332754359Sroberto len = strlen(cp); 332854359Sroberto if (len > 7) { 332954359Sroberto cp[7] = '\0'; 333054359Sroberto len = 7; 333154359Sroberto } 333254359Sroberto while (len < 7) { 333354359Sroberto *bp++ = ' '; 333454359Sroberto len++; 333554359Sroberto } 333654359Sroberto while (*cp != '\0') 333754359Sroberto *bp++ = *cp++; 333854359Sroberto lfp++; 333954359Sroberto } 334054359Sroberto *bp = '\0'; 334154359Sroberto output(fp, name, buf); 334254359Sroberto} 334354359Sroberto 334454359Srobertostatic char * 334554359Srobertotstflags( 334654359Sroberto u_long val 334754359Sroberto ) 334854359Sroberto{ 3349285612Sdelphij register char *cp, *s; 3350285612Sdelphij size_t cb; 335154359Sroberto register int i; 335254359Sroberto register const char *sep; 335354359Sroberto 335454359Sroberto sep = ""; 3355285612Sdelphij s = cp = circ_buf[nextcb]; 335654359Sroberto if (++nextcb >= NUMCB) 3357285612Sdelphij nextcb = 0; 3358285612Sdelphij cb = sizeof(circ_buf[0]); 335954359Sroberto 3360285612Sdelphij snprintf(cp, cb, "%02lx", val); 3361285612Sdelphij cp += strlen(cp); 3362285612Sdelphij cb -= strlen(cp); 336354359Sroberto if (!val) { 3364285612Sdelphij strlcat(cp, " ok", cb); 3365285612Sdelphij cp += strlen(cp); 3366285612Sdelphij cb -= strlen(cp); 336754359Sroberto } else { 3368285612Sdelphij if (cb) { 3369285612Sdelphij *cp++ = ' '; 3370285612Sdelphij cb--; 3371285612Sdelphij } 3372285612Sdelphij for (i = 0; i < (int)COUNTOF(tstflagnames); i++) { 337354359Sroberto if (val & 0x1) { 3374285612Sdelphij snprintf(cp, cb, "%s%s", sep, 3375285612Sdelphij tstflagnames[i]); 337654359Sroberto sep = ", "; 3377285612Sdelphij cp += strlen(cp); 3378285612Sdelphij cb -= strlen(cp); 337954359Sroberto } 338054359Sroberto val >>= 1; 338154359Sroberto } 338254359Sroberto } 3383285612Sdelphij if (cb) 3384285612Sdelphij *cp = '\0'; 3385285612Sdelphij 338654359Sroberto return s; 338754359Sroberto} 338854359Sroberto 338954359Sroberto/* 339054359Sroberto * cookedprint - output variables in cooked mode 339154359Sroberto */ 339254359Srobertostatic void 339354359Srobertocookedprint( 339454359Sroberto int datatype, 3395293650Sglebius size_t length, 3396285612Sdelphij const char *data, 339754359Sroberto int status, 3398285612Sdelphij int quiet, 339954359Sroberto FILE *fp 340054359Sroberto ) 340154359Sroberto{ 340254359Sroberto char *name; 340354359Sroberto char *value; 3404132451Sroberto char output_raw; 340554359Sroberto int fmt; 340654359Sroberto l_fp lfp; 3407285612Sdelphij sockaddr_u hval; 340854359Sroberto u_long uval; 3409285612Sdelphij int narr; 3410285612Sdelphij size_t len; 341154359Sroberto l_fp lfparr[8]; 3412285612Sdelphij char b[12]; 3413285612Sdelphij char bn[2 * MAXVARLEN]; 3414285612Sdelphij char bv[2 * MAXVALLEN]; 341554359Sroberto 3416285612Sdelphij UNUSED_ARG(datatype); 341754359Sroberto 3418285612Sdelphij if (!quiet) 3419285612Sdelphij fprintf(fp, "status=%04x %s,\n", status, 3420285612Sdelphij statustoa(datatype, status)); 342154359Sroberto 342254359Sroberto startoutput(); 342354359Sroberto while (nextvar(&length, &data, &name, &value)) { 3424285612Sdelphij fmt = varfmt(name); 3425285612Sdelphij output_raw = 0; 3426285612Sdelphij switch (fmt) { 3427285612Sdelphij 3428285612Sdelphij case PADDING: 342954359Sroberto output_raw = '*'; 3430285612Sdelphij break; 343154359Sroberto 3432285612Sdelphij case TS: 3433330567Sgordon if (!value || !decodets(value, &lfp)) 3434285612Sdelphij output_raw = '?'; 3435285612Sdelphij else 3436285612Sdelphij output(fp, name, prettydate(&lfp)); 3437285612Sdelphij break; 343854359Sroberto 3439285612Sdelphij case HA: /* fallthru */ 3440285612Sdelphij case NA: 3441330567Sgordon if (!value || !decodenetnum(value, &hval)) { 3442285612Sdelphij output_raw = '?'; 3443285612Sdelphij } else if (fmt == HA){ 3444285612Sdelphij output(fp, name, nntohost(&hval)); 3445285612Sdelphij } else { 3446285612Sdelphij output(fp, name, stoa(&hval)); 3447285612Sdelphij } 3448285612Sdelphij break; 344954359Sroberto 3450285612Sdelphij case RF: 3451330567Sgordon if (!value) { 3452330567Sgordon output_raw = '?'; 3453330567Sgordon } else if (decodenetnum(value, &hval)) { 3454285612Sdelphij if (ISREFCLOCKADR(&hval)) 3455285612Sdelphij output(fp, name, 3456285612Sdelphij refnumtoa(&hval)); 345754359Sroberto else 3458285612Sdelphij output(fp, name, stoa(&hval)); 3459285612Sdelphij } else if (strlen(value) <= 4) { 3460285612Sdelphij output(fp, name, value); 3461285612Sdelphij } else { 3462285612Sdelphij output_raw = '?'; 3463285612Sdelphij } 3464285612Sdelphij break; 346554359Sroberto 3466285612Sdelphij case LP: 3467330567Sgordon if (!value || !decodeuint(value, &uval) || uval > 3) { 3468285612Sdelphij output_raw = '?'; 3469285612Sdelphij } else { 3470285612Sdelphij b[0] = (0x2 & uval) 3471285612Sdelphij ? '1' 3472285612Sdelphij : '0'; 3473285612Sdelphij b[1] = (0x1 & uval) 3474285612Sdelphij ? '1' 3475285612Sdelphij : '0'; 3476285612Sdelphij b[2] = '\0'; 3477285612Sdelphij output(fp, name, b); 347854359Sroberto } 3479285612Sdelphij break; 348054359Sroberto 3481285612Sdelphij case OC: 3482330567Sgordon if (!value || !decodeuint(value, &uval)) { 3483285612Sdelphij output_raw = '?'; 3484285612Sdelphij } else { 3485285612Sdelphij snprintf(b, sizeof(b), "%03lo", uval); 3486285612Sdelphij output(fp, name, b); 3487285612Sdelphij } 3488285612Sdelphij break; 3489285612Sdelphij 3490285612Sdelphij case AR: 3491330567Sgordon if (!value || !decodearr(value, &narr, lfparr, 8)) 3492285612Sdelphij output_raw = '?'; 3493285612Sdelphij else 3494285612Sdelphij outputarr(fp, name, narr, lfparr); 3495285612Sdelphij break; 3496285612Sdelphij 3497285612Sdelphij case FX: 3498330567Sgordon if (!value || !decodeuint(value, &uval)) 3499285612Sdelphij output_raw = '?'; 3500285612Sdelphij else 3501285612Sdelphij output(fp, name, tstflags(uval)); 3502285612Sdelphij break; 3503285612Sdelphij 3504285612Sdelphij default: 3505285612Sdelphij fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3506285612Sdelphij name, value, fmt); 3507285612Sdelphij output_raw = '?'; 3508285612Sdelphij break; 350954359Sroberto } 3510285612Sdelphij 351154359Sroberto if (output_raw != 0) { 3512289997Sglebius /* TALOS-CAN-0063: avoid buffer overrun */ 3513285612Sdelphij atoascii(name, MAXVARLEN, bn, sizeof(bn)); 351454359Sroberto if (output_raw != '*') { 3515289997Sglebius atoascii(value, MAXVALLEN, 3516289997Sglebius bv, sizeof(bv) - 1); 351754359Sroberto len = strlen(bv); 351854359Sroberto bv[len] = output_raw; 351954359Sroberto bv[len+1] = '\0'; 3520289997Sglebius } else { 3521289997Sglebius atoascii(value, MAXVALLEN, 3522289997Sglebius bv, sizeof(bv)); 352354359Sroberto } 352454359Sroberto output(fp, bn, bv); 352554359Sroberto } 352654359Sroberto } 352754359Sroberto endoutput(fp); 352854359Sroberto} 352954359Sroberto 353054359Sroberto 353154359Sroberto/* 353254359Sroberto * sortassoc - sort associations in the cache into ascending order 353354359Sroberto */ 353454359Srobertovoid 353554359Srobertosortassoc(void) 353654359Sroberto{ 353754359Sroberto if (numassoc > 1) 3538285612Sdelphij qsort(assoc_cache, (size_t)numassoc, 3539285612Sdelphij sizeof(assoc_cache[0]), &assoccmp); 354054359Sroberto} 354154359Sroberto 354254359Sroberto 354354359Sroberto/* 354454359Sroberto * assoccmp - compare two associations 354554359Sroberto */ 354654359Srobertostatic int 354754359Srobertoassoccmp( 354854359Sroberto const void *t1, 354954359Sroberto const void *t2 355054359Sroberto ) 355154359Sroberto{ 3552285612Sdelphij const struct association *ass1 = t1; 3553285612Sdelphij const struct association *ass2 = t2; 355454359Sroberto 355554359Sroberto if (ass1->assid < ass2->assid) 3556285612Sdelphij return -1; 355754359Sroberto if (ass1->assid > ass2->assid) 3558285612Sdelphij return 1; 355954359Sroberto return 0; 356054359Sroberto} 3561285612Sdelphij 3562285612Sdelphij 3563285612Sdelphij/* 3564285612Sdelphij * grow_assoc_cache() - enlarge dynamic assoc_cache array 3565285612Sdelphij * 3566285612Sdelphij * The strategy is to add an assumed 4k page size at a time, leaving 3567285612Sdelphij * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3568285612Sdelphij */ 3569285612Sdelphijvoid 3570285612Sdelphijgrow_assoc_cache(void) 3571285612Sdelphij{ 3572285612Sdelphij static size_t prior_sz; 3573285612Sdelphij size_t new_sz; 3574285612Sdelphij 3575285612Sdelphij new_sz = prior_sz + 4 * 1024; 3576285612Sdelphij if (0 == prior_sz) { 3577285612Sdelphij new_sz -= 4 * sizeof(void *); 3578285612Sdelphij } 3579285612Sdelphij assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3580285612Sdelphij prior_sz = new_sz; 3581293650Sglebius assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3582285612Sdelphij} 3583285612Sdelphij 3584285612Sdelphij 3585285612Sdelphij/* 3586285612Sdelphij * ntpq_custom_opt_handler - autoopts handler for -c and -p 3587285612Sdelphij * 3588285612Sdelphij * By default, autoopts loses the relative order of -c and -p options 3589285612Sdelphij * on the command line. This routine replaces the default handler for 3590285612Sdelphij * those routines and builds a list of commands to execute preserving 3591285612Sdelphij * the order. 3592285612Sdelphij */ 3593285612Sdelphijvoid 3594285612Sdelphijntpq_custom_opt_handler( 3595285612Sdelphij tOptions *pOptions, 3596285612Sdelphij tOptDesc *pOptDesc 359754359Sroberto ) 359854359Sroberto{ 3599285612Sdelphij switch (pOptDesc->optValue) { 3600285612Sdelphij 3601285612Sdelphij default: 3602285612Sdelphij fprintf(stderr, 3603285612Sdelphij "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3604285612Sdelphij pOptDesc->optValue, pOptDesc->optValue); 3605285612Sdelphij exit(1); 3606285612Sdelphij 3607285612Sdelphij case 'c': 3608285612Sdelphij ADDCMD(pOptDesc->pzLastArg); 3609285612Sdelphij break; 3610285612Sdelphij 3611285612Sdelphij case 'p': 3612285612Sdelphij ADDCMD("peers"); 3613285612Sdelphij break; 3614285612Sdelphij } 361554359Sroberto} 3616285612Sdelphij/* 3617285612Sdelphij * Obtain list of digest names 3618285612Sdelphij */ 3619285612Sdelphij 3620330567Sgordon#if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED) 3621330567Sgordon# if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L 3622330567Sgordon# define HAVE_EVP_MD_DO_ALL_SORTED 3623330567Sgordon# endif 3624330567Sgordon#endif 3625330567Sgordon 3626285612Sdelphij#ifdef OPENSSL 3627285612Sdelphij# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3628330567Sgordon# define K_PER_LINE 8 3629330567Sgordon# define K_NL_PFX_STR "\n " 3630330567Sgordon# define K_DELIM_STR ", " 3631330567Sgordon 3632285612Sdelphijstruct hstate { 3633285612Sdelphij char *list; 3634285612Sdelphij const char **seen; 3635285612Sdelphij int idx; 3636285612Sdelphij}; 3637330567Sgordon 3638330567Sgordon 3639330567Sgordonstatic void 3640330567Sgordonlist_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg) 3641285612Sdelphij{ 3642330567Sgordon size_t len, n, digest_len; 3643330567Sgordon const char *name, **seen; 3644285612Sdelphij struct hstate *hstate = arg; 3645330567Sgordon char *cp; 3646285612Sdelphij 3647330567Sgordon /* m is MD obj, from is name or alias, to is base name for alias */ 3648330567Sgordon if (!m || !from || to) { 3649285612Sdelphij return; /* Ignore aliases */ 3650330567Sgordon } 3651285612Sdelphij 3652330567Sgordon /* Discard MACs that NTP won't accept. */ 3653330567Sgordon /* Keep this consistent with keytype_from_text() in ssl_init.c. */ 3654330567Sgordon if (EVP_MD_size(m) > (MAX_MAC_LEN - sizeof(keyid_t))) { 3655330567Sgordon return; 3656330567Sgordon } 3657330567Sgordon 3658285612Sdelphij name = EVP_MD_name(m); 3659285612Sdelphij 3660285612Sdelphij /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */ 3661285612Sdelphij 3662330567Sgordon for (cp = name; *cp; cp++) { 3663330567Sgordon if (islower((unsigned char)*cp)) { 3664285612Sdelphij return; 3665330567Sgordon } 3666285612Sdelphij } 3667330567Sgordon 3668285612Sdelphij len = (cp - name) + 1; 3669285612Sdelphij 3670285612Sdelphij /* There are duplicates. Discard if name has been seen. */ 3671285612Sdelphij 3672330567Sgordon for (seen = hstate->seen; *seen; seen++) { 3673330567Sgordon if (!strcmp(*seen, name)) { 3674285612Sdelphij return; 3675330567Sgordon } 3676330567Sgordon } 3677330567Sgordon 3678285612Sdelphij n = (seen - hstate->seen) + 2; 3679289997Sglebius hstate->seen = erealloc(hstate->seen, n * sizeof(*seen)); 3680285612Sdelphij hstate->seen[n-2] = name; 3681285612Sdelphij hstate->seen[n-1] = NULL; 3682285612Sdelphij 3683330567Sgordon if (hstate->list != NULL) { 3684330567Sgordon len += strlen(hstate->list); 3685330567Sgordon } 3686285612Sdelphij 3687330567Sgordon len += (hstate->idx >= K_PER_LINE) 3688330567Sgordon ? strlen(K_NL_PFX_STR) 3689330567Sgordon : strlen(K_DELIM_STR); 3690285612Sdelphij 3691285612Sdelphij if (hstate->list == NULL) { 3692330567Sgordon hstate->list = (char *)emalloc(len); 3693285612Sdelphij hstate->list[0] = '\0'; 3694330567Sgordon } else { 3695289997Sglebius hstate->list = (char *)erealloc(hstate->list, len); 3696330567Sgordon } 3697285612Sdelphij 3698285612Sdelphij sprintf(hstate->list + strlen(hstate->list), "%s%s", 3699330567Sgordon ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR), 3700285612Sdelphij name); 3701330567Sgordon 3702330567Sgordon if (hstate->idx >= K_PER_LINE) { 3703285612Sdelphij hstate->idx = 1; 3704330567Sgordon } else { 3705285612Sdelphij hstate->idx++; 3706330567Sgordon } 3707285612Sdelphij} 3708330567Sgordon 3709330567Sgordon 3710330567Sgordon/* Insert CMAC into SSL digests list */ 3711330567Sgordonstatic char * 3712330567Sgordoninsert_cmac(char *list) 3713330567Sgordon{ 3714330567Sgordon int insert; 3715330567Sgordon size_t len; 3716330567Sgordon 3717330567Sgordon 3718330567Sgordon /* If list empty, we need to insert CMAC on new line */ 3719330567Sgordon insert = (!list || !*list); 3720330567Sgordon 3721330567Sgordon if (insert) { 3722330567Sgordon len = strlen(K_NL_PFX_STR) + strlen(CMAC); 3723330567Sgordon list = (char *)erealloc(list, len + 1); 3724330567Sgordon sprintf(list, "%s%s", K_NL_PFX_STR, CMAC); 3725330567Sgordon } else { /* List not empty */ 3726330567Sgordon /* Check if CMAC already in list - future proofing */ 3727330567Sgordon const char *cmac_sn; 3728330567Sgordon char *cmac_p; 3729330567Sgordon 3730330567Sgordon cmac_sn = OBJ_nid2sn(NID_cmac); 3731330567Sgordon cmac_p = list; 3732330567Sgordon insert = cmac_sn != NULL && *cmac_sn != '\0'; 3733330567Sgordon 3734330567Sgordon /* CMAC in list if found, followed by nul char or ',' */ 3735330567Sgordon while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) { 3736330567Sgordon cmac_p += strlen(cmac_sn); 3737330567Sgordon /* Still need to insert if not nul and not ',' */ 3738330567Sgordon insert = *cmac_p && ',' != *cmac_p; 3739330567Sgordon } 3740330567Sgordon 3741330567Sgordon /* Find proper insertion point */ 3742330567Sgordon if (insert) { 3743330567Sgordon char *last_nl; 3744330567Sgordon char *point; 3745330567Sgordon char *delim; 3746330567Sgordon int found; 3747330567Sgordon 3748330567Sgordon /* Default to start if list empty */ 3749330567Sgordon found = 0; 3750330567Sgordon delim = list; 3751330567Sgordon len = strlen(list); 3752330567Sgordon 3753330567Sgordon /* While new lines */ 3754330567Sgordon while (delim < list + len && *delim && 3755330567Sgordon !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) { 3756330567Sgordon point = delim + strlen(K_NL_PFX_STR); 3757330567Sgordon 3758330567Sgordon /* While digest names on line */ 3759330567Sgordon while (point < list + len && *point) { 3760330567Sgordon /* Another digest after on same or next line? */ 3761330567Sgordon delim = strstr( point, K_DELIM_STR); 3762330567Sgordon last_nl = strstr( point, K_NL_PFX_STR); 3763330567Sgordon 3764330567Sgordon /* No - end of list */ 3765330567Sgordon if (!delim && !last_nl) { 3766330567Sgordon delim = list + len; 3767330567Sgordon } else 3768330567Sgordon /* New line and no delim or before delim? */ 3769330567Sgordon if (last_nl && (!delim || last_nl < delim)) { 3770330567Sgordon delim = last_nl; 3771330567Sgordon } 3772330567Sgordon 3773330567Sgordon /* Found insertion point where CMAC before entry? */ 3774330567Sgordon if (strncmp(CMAC, point, delim - point) < 0) { 3775330567Sgordon found = 1; 3776330567Sgordon break; 3777330567Sgordon } 3778330567Sgordon 3779330567Sgordon if (delim < list + len && *delim && 3780330567Sgordon !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) { 3781330567Sgordon point += strlen(K_DELIM_STR); 3782330567Sgordon } else { 3783330567Sgordon break; 3784330567Sgordon } 3785330567Sgordon } /* While digest names on line */ 3786330567Sgordon } /* While new lines */ 3787330567Sgordon 3788330567Sgordon /* If found in list */ 3789330567Sgordon if (found) { 3790330567Sgordon /* insert cmac and delim */ 3791330567Sgordon /* Space for list could move - save offset */ 3792330567Sgordon ptrdiff_t p_offset = point - list; 3793330567Sgordon len += strlen(CMAC) + strlen(K_DELIM_STR); 3794330567Sgordon list = (char *)erealloc(list, len + 1); 3795330567Sgordon point = list + p_offset; 3796330567Sgordon /* move to handle src/dest overlap */ 3797330567Sgordon memmove(point + strlen(CMAC) + strlen(K_DELIM_STR), 3798330567Sgordon point, strlen(point) + 1); 3799330567Sgordon strncpy(point, CMAC, strlen(CMAC)); 3800330567Sgordon strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR)); 3801330567Sgordon } else { /* End of list */ 3802330567Sgordon /* append delim and cmac */ 3803330567Sgordon len += strlen(K_DELIM_STR) + strlen(CMAC); 3804330567Sgordon list = (char *)erealloc(list, len + 1); 3805330567Sgordon strcpy(list + strlen(list), K_DELIM_STR); 3806330567Sgordon strcpy(list + strlen(list), CMAC); 3807330567Sgordon } 3808330567Sgordon } /* insert */ 3809330567Sgordon } /* List not empty */ 3810330567Sgordon 3811330567Sgordon return list; 3812330567Sgordon} 3813285612Sdelphij# endif 3814285612Sdelphij#endif 3815285612Sdelphij 3816330567Sgordon 3817330567Sgordonstatic char * 3818330567Sgordonlist_digest_names(void) 3819285612Sdelphij{ 3820285612Sdelphij char *list = NULL; 3821285612Sdelphij 3822285612Sdelphij#ifdef OPENSSL 3823285612Sdelphij# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3824285612Sdelphij struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 3825285612Sdelphij 3826330567Sgordon /* replace calloc(1, sizeof(const char *)) */ 3827330567Sgordon hstate.seen = (const char **)emalloc_zero(sizeof(const char *)); 3828285612Sdelphij 3829285612Sdelphij INIT_SSL(); 3830285612Sdelphij EVP_MD_do_all_sorted(list_md_fn, &hstate); 3831285612Sdelphij list = hstate.list; 3832285612Sdelphij free(hstate.seen); 3833330567Sgordon 3834330567Sgordon list = insert_cmac(list); /* Insert CMAC into SSL digests list */ 3835330567Sgordon 3836285612Sdelphij# else 3837289997Sglebius list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 3838285612Sdelphij strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 3839285612Sdelphij# endif 3840285612Sdelphij#else 3841289997Sglebius list = (char *)emalloc(sizeof("md5")); 3842285612Sdelphij strcpy(list, "md5"); 3843285612Sdelphij#endif 3844285612Sdelphij 3845285612Sdelphij return list; 3846285612Sdelphij} 3847293650Sglebius 3848293650Sglebius#define CTRLC_STACK_MAX 4 3849293650Sglebiusstatic volatile size_t ctrlc_stack_len = 0; 3850293650Sglebiusstatic volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 3851293650Sglebius 3852293650Sglebius 3853293650Sglebius 3854293650Sglebiusint/*BOOL*/ 3855293650Sglebiuspush_ctrl_c_handler( 3856293650Sglebius Ctrl_C_Handler func 3857293650Sglebius ) 3858293650Sglebius{ 3859293650Sglebius size_t size = ctrlc_stack_len; 3860293650Sglebius if (func && (size < CTRLC_STACK_MAX)) { 3861293650Sglebius ctrlc_stack[size] = func; 3862293650Sglebius ctrlc_stack_len = size + 1; 3863293650Sglebius return TRUE; 3864293650Sglebius } 3865293650Sglebius return FALSE; 3866293650Sglebius} 3867293650Sglebius 3868293650Sglebiusint/*BOOL*/ 3869293650Sglebiuspop_ctrl_c_handler( 3870293650Sglebius Ctrl_C_Handler func 3871293650Sglebius ) 3872293650Sglebius{ 3873293650Sglebius size_t size = ctrlc_stack_len; 3874293650Sglebius if (size) { 3875293650Sglebius --size; 3876293650Sglebius if (func == NULL || func == ctrlc_stack[size]) { 3877293650Sglebius ctrlc_stack_len = size; 3878293650Sglebius return TRUE; 3879293650Sglebius } 3880293650Sglebius } 3881293650Sglebius return FALSE; 3882293650Sglebius} 3883293650Sglebius 3884293650Sglebiusstatic void 3885293650Sglebiuson_ctrlc(void) 3886293650Sglebius{ 3887293650Sglebius size_t size = ctrlc_stack_len; 3888293650Sglebius while (size) 3889293650Sglebius if ((*ctrlc_stack[--size])()) 3890293650Sglebius break; 3891293650Sglebius} 3892294569Sdelphij 3893294569Sdelphijstatic int 3894294569Sdelphijmy_easprintf( 3895294569Sdelphij char ** ppinto, 3896294569Sdelphij const char * fmt , 3897294569Sdelphij ... 3898294569Sdelphij ) 3899294569Sdelphij{ 3900294569Sdelphij va_list va; 3901294569Sdelphij int prc; 3902294569Sdelphij size_t len = 128; 3903294569Sdelphij char * buf = emalloc(len); 3904294569Sdelphij 3905294569Sdelphij again: 3906294569Sdelphij /* Note: we expect the memory allocation to fail long before the 3907294569Sdelphij * increment in buffer size actually overflows. 3908294569Sdelphij */ 3909294569Sdelphij buf = (buf) ? erealloc(buf, len) : emalloc(len); 3910294569Sdelphij 3911294569Sdelphij va_start(va, fmt); 3912294569Sdelphij prc = vsnprintf(buf, len, fmt, va); 3913294569Sdelphij va_end(va); 3914294569Sdelphij 3915294569Sdelphij if (prc < 0) { 3916294569Sdelphij /* might be very old vsnprintf. Or actually MSVC... */ 3917294569Sdelphij len += len >> 1; 3918294569Sdelphij goto again; 3919294569Sdelphij } 3920294569Sdelphij if ((size_t)prc >= len) { 3921294569Sdelphij /* at least we have the proper size now... */ 3922294569Sdelphij len = (size_t)prc + 1; 3923294569Sdelphij goto again; 3924294569Sdelphij } 3925294569Sdelphij if ((size_t)prc < (len - 32)) 3926294569Sdelphij buf = erealloc(buf, (size_t)prc + 1); 3927294569Sdelphij *ppinto = buf; 3928294569Sdelphij return prc; 3929294569Sdelphij} 3930