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> 8330141Sdelphij#include <stddef.h> 9330141Sdelphij#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 35338531Sdelphij# include "openssl/evp.h" 36338531Sdelphij# include "openssl/objects.h" 37338531Sdelphij# include "openssl/err.h" 38338531Sdelphij# ifdef SYS_WINNT 39338531Sdelphij# include "openssl/opensslv.h" 40338531Sdelphij# if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L 41338531Sdelphij# define HAVE_EVP_MD_DO_ALL_SORTED 1 42338531Sdelphij# endif 43330141Sdelphij# endif 44338531Sdelphij# include "libssl_compat.h" 45338531Sdelphij# ifdef HAVE_OPENSSL_CMAC_H 46338531Sdelphij# include <openssl/cmac.h> 47338531Sdelphij# define CMAC "AES128CMAC" 48338531Sdelphij# endif 49330141Sdelphij#endif 50285612Sdelphij#include <ssl_applink.c> 5182498Sroberto 52285612Sdelphij#include "ntp_libopts.h" 53293650Sglebius#include "safecast.h" 54182007Sroberto 55285612Sdelphij#ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 56182007Sroberto# define open(name, flags) open(name, flags, 0777) 57182007Sroberto# define SERVER_PORT_NUM 123 5854359Sroberto#endif 5954359Sroberto 60182007Sroberto/* we use COMMAND as an autogen keyword */ 61182007Sroberto#ifdef COMMAND 62182007Sroberto# undef COMMAND 63182007Sroberto#endif 64182007Sroberto 6554359Sroberto/* 6654359Sroberto * Because we potentially understand a lot of commands we will run 6754359Sroberto * interactive if connected to a terminal. 6854359Sroberto */ 6954359Srobertoint interactive = 0; /* set to 1 when we should prompt */ 7054359Srobertoconst char *prompt = "ntpq> "; /* prompt to ask him about */ 7154359Sroberto 72285612Sdelphij/* 73285612Sdelphij * use old readvars behavior? --old-rv processing in ntpq resets 74285612Sdelphij * this value based on the presence or absence of --old-rv. It is 75285612Sdelphij * initialized to 1 here to maintain backward compatibility with 76285612Sdelphij * libntpq clients such as ntpsnmpd, which are free to reset it as 77285612Sdelphij * desired. 78285612Sdelphij */ 79285612Sdelphijint old_rv = 1; 8054359Sroberto 81298699Sdelphij/* 82298699Sdelphij * How should we display the refid? 83298699Sdelphij * REFID_HASH, REFID_IPV4 84298699Sdelphij */ 85298699Sdelphijte_Refid drefid = -1; 86285612Sdelphij 8754359Sroberto/* 88182007Sroberto * for get_systime() 89182007Sroberto */ 90182007Srobertos_char sys_precision; /* local clock precision (log2 s) */ 91182007Sroberto 92182007Sroberto/* 9354359Sroberto * Keyid used for authenticated requests. Obtained on the fly. 9454359Sroberto */ 95132451Srobertou_long info_auth_keyid = 0; 9654359Sroberto 97285612Sdelphijstatic int info_auth_keytype = NID_md5; /* MD5 */ 98285612Sdelphijstatic size_t info_auth_hashlen = 16; /* MD5 */ 9954359Srobertou_long current_time; /* needed by authkeys; not used */ 10054359Sroberto 10154359Sroberto/* 10254359Sroberto * Flag which indicates we should always send authenticated requests 10354359Sroberto */ 10454359Srobertoint always_auth = 0; 10554359Sroberto 10654359Sroberto/* 10754359Sroberto * Flag which indicates raw mode output. 10854359Sroberto */ 10954359Srobertoint rawmode = 0; 11054359Sroberto 11154359Sroberto/* 11254359Sroberto * Packet version number we use 11354359Sroberto */ 11454359Srobertou_char pktversion = NTP_OLDVERSION + 1; 11554359Sroberto 11654359Sroberto 11754359Sroberto/* 11854359Sroberto * Format values 11954359Sroberto */ 12054359Sroberto#define PADDING 0 121285612Sdelphij#define HA 1 /* host address */ 122285612Sdelphij#define NA 2 /* network address */ 123285612Sdelphij#define LP 3 /* leap (print in binary) */ 124285612Sdelphij#define RF 4 /* refid (sometimes string, sometimes not) */ 125285612Sdelphij#define AR 5 /* array of times */ 126285612Sdelphij#define FX 6 /* test flags */ 127285612Sdelphij#define TS 7 /* l_fp timestamp in hex */ 128285612Sdelphij#define OC 8 /* integer, print in octal */ 12954359Sroberto#define EOV 255 /* end of table */ 13054359Sroberto 13154359Sroberto/* 132285612Sdelphij * For the most part ntpq simply displays what ntpd provides in the 133285612Sdelphij * mostly plain-text mode 6 responses. A few variable names are by 134285612Sdelphij * default "cooked" to provide more human-friendly output. 13554359Sroberto */ 136285612Sdelphijconst var_format cookedvars[] = { 137285612Sdelphij { "leap", LP }, 138285612Sdelphij { "reach", OC }, 139285612Sdelphij { "refid", RF }, 140285612Sdelphij { "reftime", TS }, 141285612Sdelphij { "clock", TS }, 142285612Sdelphij { "org", TS }, 143285612Sdelphij { "rec", TS }, 144285612Sdelphij { "xmt", TS }, 145285612Sdelphij { "flash", FX }, 146285612Sdelphij { "srcadr", HA }, 147285612Sdelphij { "peeradr", HA }, /* compat with others */ 148285612Sdelphij { "dstadr", NA }, 149285612Sdelphij { "filtdelay", AR }, 150285612Sdelphij { "filtoffset", AR }, 151285612Sdelphij { "filtdisp", AR }, 152285612Sdelphij { "filterror", AR }, /* compat with others */ 15354359Sroberto}; 15454359Sroberto 15554359Sroberto 15654359Sroberto 15754359Sroberto/* 15854359Sroberto * flasher bits 15954359Sroberto */ 16054359Srobertostatic const char *tstflagnames[] = { 161182007Sroberto "pkt_dup", /* TEST1 */ 162182007Sroberto "pkt_bogus", /* TEST2 */ 163285612Sdelphij "pkt_unsync", /* TEST3 */ 164182007Sroberto "pkt_denied", /* TEST4 */ 165182007Sroberto "pkt_auth", /* TEST5 */ 166285612Sdelphij "pkt_stratum", /* TEST6 */ 167285612Sdelphij "pkt_header", /* TEST7 */ 168182007Sroberto "pkt_autokey", /* TEST8 */ 169182007Sroberto "pkt_crypto", /* TEST9 */ 170182007Sroberto "peer_stratum", /* TEST10 */ 171182007Sroberto "peer_dist", /* TEST11 */ 172182007Sroberto "peer_loop", /* TEST12 */ 173285612Sdelphij "peer_unreach" /* TEST13 */ 17454359Sroberto}; 17554359Sroberto 17654359Sroberto 177285612Sdelphijint ntpqmain (int, char **); 17854359Sroberto/* 17954359Sroberto * Built in command handler declarations 18054359Sroberto */ 181285612Sdelphijstatic int openhost (const char *, int); 182285612Sdelphijstatic void dump_hex_printable(const void *, size_t); 183285612Sdelphijstatic int sendpkt (void *, size_t); 184293650Sglebiusstatic int getresponse (int, int, u_short *, size_t *, const char **, int); 185293650Sglebiusstatic int sendrequest (int, associd_t, int, size_t, const char *); 186285612Sdelphijstatic char * tstflags (u_long); 187285612Sdelphij#ifndef BUILD_AS_LIB 188285612Sdelphijstatic void getcmds (void); 189285612Sdelphij#ifndef SYS_WINNT 190293650Sglebiusstatic int abortcmd (void); 191285612Sdelphij#endif /* SYS_WINNT */ 192285612Sdelphijstatic void docmd (const char *); 193285612Sdelphijstatic void tokenize (const char *, char **, int *); 194285612Sdelphijstatic int getarg (const char *, int, arg_v *); 195285612Sdelphij#endif /* BUILD_AS_LIB */ 196285612Sdelphijstatic int findcmd (const char *, struct xcmd *, 197285612Sdelphij struct xcmd *, struct xcmd **); 198285612Sdelphijstatic int rtdatetolfp (char *, l_fp *); 199330141Sdelphijstatic int decodearr (char *, int *, l_fp *, int); 200285612Sdelphijstatic void help (struct parse *, FILE *); 201285612Sdelphijstatic int helpsort (const void *, const void *); 202285612Sdelphijstatic void printusage (struct xcmd *, FILE *); 203285612Sdelphijstatic void timeout (struct parse *, FILE *); 204285612Sdelphijstatic void auth_delay (struct parse *, FILE *); 205285612Sdelphijstatic void host (struct parse *, FILE *); 206285612Sdelphijstatic void ntp_poll (struct parse *, FILE *); 207285612Sdelphijstatic void keyid (struct parse *, FILE *); 208285612Sdelphijstatic void keytype (struct parse *, FILE *); 209285612Sdelphijstatic void passwd (struct parse *, FILE *); 210285612Sdelphijstatic void hostnames (struct parse *, FILE *); 211285612Sdelphijstatic void setdebug (struct parse *, FILE *); 212285612Sdelphijstatic void quit (struct parse *, FILE *); 213298699Sdelphijstatic void showdrefid (struct parse *, FILE *); 214285612Sdelphijstatic void version (struct parse *, FILE *); 215285612Sdelphijstatic void raw (struct parse *, FILE *); 216285612Sdelphijstatic void cooked (struct parse *, FILE *); 217285612Sdelphijstatic void authenticate (struct parse *, FILE *); 218285612Sdelphijstatic void ntpversion (struct parse *, FILE *); 219338531Sdelphijstatic void warning (const char *, ...) NTP_PRINTF(1, 2); 220338531Sdelphijstatic void error (const char *, ...) NTP_PRINTF(1, 2); 221285612Sdelphijstatic u_long getkeyid (const char *); 222285612Sdelphijstatic void atoascii (const char *, size_t, char *, size_t); 223293650Sglebiusstatic void cookedprint (int, size_t, const char *, int, int, FILE *); 224293650Sglebiusstatic void rawprint (int, size_t, const char *, int, int, FILE *); 225285612Sdelphijstatic void startoutput (void); 226285612Sdelphijstatic void output (FILE *, const char *, const char *); 227285612Sdelphijstatic void endoutput (FILE *); 228285612Sdelphijstatic void outputarr (FILE *, char *, int, l_fp *); 229285612Sdelphijstatic int assoccmp (const void *, const void *); 230338531Sdelphij u_short varfmt (const char *); 231338531Sdelphij void ntpq_custom_opt_handler(tOptions *, tOptDesc *); 232338531Sdelphij 233338531Sdelphij#ifndef BUILD_AS_LIB 234338531Sdelphijstatic char *list_digest_names(void); 235338531Sdelphijstatic char *insert_cmac (char *list); 236293650Sglebiusstatic void on_ctrlc (void); 237294569Sdelphijstatic int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 238338531Sdelphij# if defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED) 239338531Sdelphijstatic void list_md_fn (const EVP_MD *m, const char *from, 240338531Sdelphij const char *to, void *arg); 241338531Sdelphij# endif /* defined(OPENSSL) && defined(HAVE_EVP_MD_DO_ALL_SORTED) */ 242338531Sdelphij#endif /* !defined(BUILD_AS_LIB) */ 243285612Sdelphij 244338531Sdelphij 245330141Sdelphij/* read a character from memory and expand to integer */ 246330141Sdelphijstatic inline int 247330141Sdelphijpgetc( 248330141Sdelphij const char *cp 249330141Sdelphij ) 250330141Sdelphij{ 251330141Sdelphij return (int)*(const unsigned char*)cp; 252330141Sdelphij} 253330141Sdelphij 254330141Sdelphij 25554359Sroberto 25654359Sroberto/* 25754359Sroberto * Built-in commands we understand 25854359Sroberto */ 25954359Srobertostruct xcmd builtins[] = { 260182007Sroberto { "?", help, { OPT|NTP_STR, NO, NO, NO }, 26154359Sroberto { "command", "", "", "" }, 26254359Sroberto "tell the use and syntax of commands" }, 263182007Sroberto { "help", help, { OPT|NTP_STR, NO, NO, NO }, 26454359Sroberto { "command", "", "", "" }, 26554359Sroberto "tell the use and syntax of commands" }, 266182007Sroberto { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 26754359Sroberto { "msec", "", "", "" }, 26854359Sroberto "set the primary receive time out" }, 269182007Sroberto { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 27054359Sroberto { "msec", "", "", "" }, 27154359Sroberto "set the delay added to encryption time stamps" }, 272182007Sroberto { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 273132451Sroberto { "-4|-6", "hostname", "", "" }, 27454359Sroberto "specify the host whose NTP server we talk to" }, 275182007Sroberto { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 27654359Sroberto { "n", "verbose", "", "" }, 27754359Sroberto "poll an NTP server in client mode `n' times" }, 278285612Sdelphij { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 27954359Sroberto { "", "", "", "" }, 28054359Sroberto "specify a password to use for authenticated requests"}, 281182007Sroberto { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 28254359Sroberto { "yes|no", "", "", "" }, 28354359Sroberto "specify whether hostnames or net numbers are printed"}, 284182007Sroberto { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 28554359Sroberto { "no|more|less", "", "", "" }, 28654359Sroberto "set/change debugging level" }, 28754359Sroberto { "quit", quit, { NO, NO, NO, NO }, 28854359Sroberto { "", "", "", "" }, 28954359Sroberto "exit ntpq" }, 29054359Sroberto { "exit", quit, { NO, NO, NO, NO }, 29154359Sroberto { "", "", "", "" }, 29254359Sroberto "exit ntpq" }, 293182007Sroberto { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 29454359Sroberto { "key#", "", "", "" }, 29554359Sroberto "set keyid to use for authenticated requests" }, 296298699Sdelphij { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 297298699Sdelphij { "hash|ipv4", "", "", "" }, 298298699Sdelphij "display refid's as IPv4 or hash" }, 29954359Sroberto { "version", version, { NO, NO, NO, NO }, 30054359Sroberto { "", "", "", "" }, 30154359Sroberto "print version number" }, 30254359Sroberto { "raw", raw, { NO, NO, NO, NO }, 30354359Sroberto { "", "", "", "" }, 30454359Sroberto "do raw mode variable output" }, 30554359Sroberto { "cooked", cooked, { NO, NO, NO, NO }, 30654359Sroberto { "", "", "", "" }, 30754359Sroberto "do cooked mode variable output" }, 308182007Sroberto { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 30954359Sroberto { "yes|no", "", "", "" }, 31054359Sroberto "always authenticate requests to this server" }, 311182007Sroberto { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 31254359Sroberto { "version number", "", "", "" }, 31354359Sroberto "set the NTP version number to use for requests" }, 314182007Sroberto { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 315285612Sdelphij { "key type %s", "", "", "" }, 316285612Sdelphij NULL }, 31754359Sroberto { 0, 0, { NO, NO, NO, NO }, 31854359Sroberto { "", "", "", "" }, "" } 31954359Sroberto}; 32054359Sroberto 32154359Sroberto 32254359Sroberto/* 32354359Sroberto * Default values we use. 32454359Sroberto */ 325285612Sdelphij#define DEFHOST "localhost" /* default host name */ 326285612Sdelphij#define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 327285612Sdelphij#define DEFSTIMEOUT 3 /* and 3 more for each additional */ 328285612Sdelphij/* 329285612Sdelphij * Requests are automatically retried once, so total timeout with no 330285612Sdelphij * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 331285612Sdelphij * extreme, a request eliciting 32 packets of responses each for some 332285612Sdelphij * reason nearly DEFSTIMEOUT seconds after the prior in that series, 333285612Sdelphij * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 334285612Sdelphij * 93 seconds to fail each of two times, or 186 seconds. 335285612Sdelphij * Some commands involve a series of requests, such as "peers" and 336285612Sdelphij * "mrulist", so the cumulative timeouts are even longer for those. 337285612Sdelphij */ 33854359Sroberto#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 33954359Sroberto#define LENHOSTNAME 256 /* host name is 256 characters long */ 34054359Sroberto#define MAXCMDS 100 /* maximum commands on cmd line */ 34154359Sroberto#define MAXHOSTS 200 /* maximum hosts on cmd line */ 34254359Sroberto#define MAXLINE 512 /* maximum line length */ 34354359Sroberto#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 34454359Sroberto#define MAXVARLEN 256 /* maximum length of a variable name */ 345285612Sdelphij#define MAXVALLEN 2048 /* maximum length of a variable value */ 34654359Sroberto#define MAXOUTLINE 72 /* maximum length of an output line */ 347285612Sdelphij#define SCREENWIDTH 76 /* nominal screen width in columns */ 34854359Sroberto 34954359Sroberto/* 35054359Sroberto * Some variables used and manipulated locally 35154359Sroberto */ 352285612Sdelphijstruct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 353285612Sdelphijstruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 35454359Srobertol_fp delay_time; /* delay time */ 35554359Srobertochar currenthost[LENHOSTNAME]; /* current host name */ 356285612Sdelphijint currenthostisnum; /* is prior text from IP? */ 357285612Sdelphijstruct sockaddr_in hostaddr; /* host address */ 35854359Srobertoint showhostnames = 1; /* show host names by default */ 359285612Sdelphijint wideremote = 0; /* show wide remote names? */ 36054359Sroberto 361132451Srobertoint ai_fam_templ; /* address family */ 362132451Srobertoint ai_fam_default; /* default address family */ 363132451SrobertoSOCKET sockfd; /* fd socket is opened on */ 36454359Srobertoint havehost = 0; /* set to 1 when host open */ 365132451Srobertoint s_port = 0; 36654359Srobertostruct servent *server_entry = NULL; /* server entry for ntp */ 36754359Sroberto 36854359Sroberto 36954359Sroberto/* 37054359Sroberto * Sequence number used for requests. It is incremented before 37154359Sroberto * it is used. 37254359Sroberto */ 37354359Srobertou_short sequence; 37454359Sroberto 37554359Sroberto/* 37654359Sroberto * Holds data returned from queries. Declare buffer long to be sure of 37754359Sroberto * alignment. 37854359Sroberto */ 37954359Sroberto#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 38054359Srobertolong pktdata[DATASIZE/sizeof(long)]; 38154359Sroberto 38254359Sroberto/* 383285612Sdelphij * assoc_cache[] is a dynamic array which allows references to 384285612Sdelphij * associations using &1 ... &N for n associations, avoiding manual 385285612Sdelphij * lookup of the current association IDs for a given ntpd. It also 386285612Sdelphij * caches the status word for each association, retrieved incidentally. 38754359Sroberto */ 388285612Sdelphijstruct association * assoc_cache; 389285612Sdelphiju_int assoc_cache_slots;/* count of allocated array entries */ 390285612Sdelphiju_int numassoc; /* number of cached associations */ 39154359Sroberto 39254359Sroberto/* 39354359Sroberto * For commands typed on the command line (with the -c option) 39454359Sroberto */ 395316069Sdelphijsize_t numcmds = 0; 39654359Srobertoconst char *ccmds[MAXCMDS]; 39754359Sroberto#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 39854359Sroberto 39954359Sroberto/* 40054359Sroberto * When multiple hosts are specified. 40154359Sroberto */ 40254359Sroberto 403285612Sdelphiju_int numhosts; 40454359Sroberto 405285612Sdelphijchost chosts[MAXHOSTS]; 406285612Sdelphij#define ADDHOST(cp) \ 407285612Sdelphij do { \ 408285612Sdelphij if (numhosts < MAXHOSTS) { \ 409285612Sdelphij chosts[numhosts].name = (cp); \ 410285612Sdelphij chosts[numhosts].fam = ai_fam_templ; \ 411285612Sdelphij numhosts++; \ 412285612Sdelphij } \ 413285612Sdelphij } while (0) 414285612Sdelphij 41554359Sroberto/* 41654359Sroberto * Macro definitions we use 41754359Sroberto */ 41854359Sroberto#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 41954359Sroberto#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 42054359Sroberto#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 42154359Sroberto 42254359Sroberto/* 423338531Sdelphij * Jump buffer for longjumping back to the command level. 424338531Sdelphij * 425338531Sdelphij * Since we do this from a signal handler, we use 'sig{set,long}jmp()' 426338531Sdelphij * if available. The signal is blocked by default during the excution of 427338531Sdelphij * a signal handler, and it is unspecified if '{set,long}jmp()' save and 428338531Sdelphij * restore the signal mask. They do on BSD, it depends on the GLIBC 429338531Sdelphij * version on Linux, and the gods know what happens on other OSes... 430338531Sdelphij * 431338531Sdelphij * So we use the 'sig{set,long}jmp()' functions where available, because 432338531Sdelphij * for them the semantics are well-defined. If we have to fall back to 433338531Sdelphij * '{set,long}jmp()', the CTRL-C handling might be a bit erratic. 43454359Sroberto */ 435338531Sdelphij#if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP 436338531Sdelphij# define JMP_BUF sigjmp_buf 437338531Sdelphij# define SETJMP(x) sigsetjmp((x), 1) 438338531Sdelphij# define LONGJMP(x, v) siglongjmp((x),(v)) 439338531Sdelphij#else 440338531Sdelphij# define JMP_BUF jmp_buf 441338531Sdelphij# define SETJMP(x) setjmp((x)) 442338531Sdelphij# define LONGJMP(x, v) longjmp((x),(v)) 443338531Sdelphij#endif 444338531Sdelphijstatic JMP_BUF interrupt_buf; 445338531Sdelphijstatic volatile int jump = 0; 44654359Sroberto 44754359Sroberto/* 44854359Sroberto * Points at file being currently printed into 44954359Sroberto */ 450338531SdelphijFILE *current_output = NULL; 45154359Sroberto 45254359Sroberto/* 45354359Sroberto * Command table imported from ntpdc_ops.c 45454359Sroberto */ 45554359Srobertoextern struct xcmd opcmds[]; 45654359Sroberto 457289997Sglebiuschar const *progname; 45854359Sroberto 45954359Sroberto#ifdef NO_MAIN_ALLOWED 460285612Sdelphij#ifndef BUILD_AS_LIB 46154359SrobertoCALL(ntpq,"ntpq",ntpqmain); 46254359Sroberto 46354359Srobertovoid clear_globals(void) 46454359Sroberto{ 465285612Sdelphij extern int ntp_optind; 466285612Sdelphij showhostnames = 0; /* don'tshow host names by default */ 467285612Sdelphij ntp_optind = 0; 468285612Sdelphij server_entry = NULL; /* server entry for ntp */ 469285612Sdelphij havehost = 0; /* set to 1 when host open */ 470285612Sdelphij numassoc = 0; /* number of cached associations */ 471285612Sdelphij numcmds = 0; 472285612Sdelphij numhosts = 0; 47354359Sroberto} 474285612Sdelphij#endif /* !BUILD_AS_LIB */ 475285612Sdelphij#endif /* NO_MAIN_ALLOWED */ 47654359Sroberto 47754359Sroberto/* 47854359Sroberto * main - parse arguments and handle options 47954359Sroberto */ 48054359Sroberto#ifndef NO_MAIN_ALLOWED 48154359Srobertoint 48254359Srobertomain( 48354359Sroberto int argc, 48454359Sroberto char *argv[] 48554359Sroberto ) 48654359Sroberto{ 48754359Sroberto return ntpqmain(argc, argv); 48854359Sroberto} 48954359Sroberto#endif 49054359Sroberto 491330141Sdelphij 492285612Sdelphij#ifndef BUILD_AS_LIB 49354359Srobertoint 49454359Srobertontpqmain( 49554359Sroberto int argc, 49654359Sroberto char *argv[] 49754359Sroberto ) 49854359Sroberto{ 499285612Sdelphij u_int ihost; 500316069Sdelphij size_t icmd; 50154359Sroberto 502285612Sdelphij 503182007Sroberto#ifdef SYS_VXWORKS 504182007Sroberto clear_globals(); 505182007Sroberto taskPrioritySet(taskIdSelf(), 100 ); 50654359Sroberto#endif 507182007Sroberto 50854359Sroberto delay_time.l_ui = 0; 50954359Sroberto delay_time.l_uf = DEFDELAY; 51054359Sroberto 511285612Sdelphij init_lib(); /* sets up ipv4_works, ipv6_works */ 512285612Sdelphij ssl_applink(); 513285612Sdelphij init_auth(); 514285612Sdelphij 515285612Sdelphij /* Check to see if we have IPv6. Otherwise default to IPv4 */ 516285612Sdelphij if (!ipv6_works) 517285612Sdelphij ai_fam_default = AF_INET; 518285612Sdelphij 519285612Sdelphij /* Fixup keytype's help based on available digest names */ 520285612Sdelphij 521132451Sroberto { 522285612Sdelphij char *list; 523294569Sdelphij char *msg; 524132451Sroberto 525285612Sdelphij list = list_digest_names(); 526330141Sdelphij 527330141Sdelphij for (icmd = 0; icmd < sizeof(builtins)/sizeof(*builtins); icmd++) { 528330141Sdelphij if (strcmp("keytype", builtins[icmd].keyword) == 0) { 529285612Sdelphij break; 530330141Sdelphij } 531285612Sdelphij } 532285612Sdelphij 533285612Sdelphij /* CID: 1295478 */ 534285612Sdelphij /* This should only "trip" if "keytype" is removed from builtins */ 535330141Sdelphij INSIST(icmd < sizeof(builtins)/sizeof(*builtins)); 536285612Sdelphij 537285612Sdelphij#ifdef OPENSSL 538285612Sdelphij builtins[icmd].desc[0] = "digest-name"; 539294569Sdelphij my_easprintf(&msg, 540294569Sdelphij "set key type to use for authenticated requests, one of:%s", 541294569Sdelphij list); 542285612Sdelphij#else 543285612Sdelphij builtins[icmd].desc[0] = "md5"; 544294569Sdelphij my_easprintf(&msg, 545294569Sdelphij "set key type to use for authenticated requests (%s)", 546294569Sdelphij list); 547285612Sdelphij#endif 548285612Sdelphij builtins[icmd].comment = msg; 549285612Sdelphij free(list); 550132451Sroberto } 551132451Sroberto 55254359Sroberto progname = argv[0]; 553182007Sroberto 554182007Sroberto { 555285612Sdelphij int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 556182007Sroberto argc -= optct; 557182007Sroberto argv += optct; 558182007Sroberto } 559182007Sroberto 560285612Sdelphij /* 561285612Sdelphij * Process options other than -c and -p, which are specially 562285612Sdelphij * handled by ntpq_custom_opt_handler(). 563285612Sdelphij */ 564285612Sdelphij 565285612Sdelphij debug = OPT_VALUE_SET_DEBUG_LEVEL; 566285612Sdelphij 567285612Sdelphij if (HAVE_OPT(IPV4)) 568182007Sroberto ai_fam_templ = AF_INET; 569285612Sdelphij else if (HAVE_OPT(IPV6)) 570182007Sroberto ai_fam_templ = AF_INET6; 571285612Sdelphij else 572182007Sroberto ai_fam_templ = ai_fam_default; 573182007Sroberto 574285612Sdelphij if (HAVE_OPT(INTERACTIVE)) 575182007Sroberto interactive = 1; 576182007Sroberto 577285612Sdelphij if (HAVE_OPT(NUMERIC)) 578182007Sroberto showhostnames = 0; 579182007Sroberto 580285612Sdelphij if (HAVE_OPT(WIDE)) 581285612Sdelphij wideremote = 1; 582182007Sroberto 583285612Sdelphij old_rv = HAVE_OPT(OLD_RV); 584285612Sdelphij 585298699Sdelphij drefid = OPT_VALUE_REFID; 586298699Sdelphij 587285612Sdelphij if (0 == argc) { 58854359Sroberto ADDHOST(DEFHOST); 58954359Sroberto } else { 590285612Sdelphij for (ihost = 0; ihost < (u_int)argc; ihost++) { 591285612Sdelphij if ('-' == *argv[ihost]) { 592285612Sdelphij // 593285612Sdelphij // If I really cared I'd also check: 594285612Sdelphij // 0 == argv[ihost][2] 595285612Sdelphij // 596285612Sdelphij // and there are other cases as well... 597285612Sdelphij // 598285612Sdelphij if ('4' == argv[ihost][1]) { 599285612Sdelphij ai_fam_templ = AF_INET; 600285612Sdelphij continue; 601285612Sdelphij } else if ('6' == argv[ihost][1]) { 602285612Sdelphij ai_fam_templ = AF_INET6; 603285612Sdelphij continue; 604285612Sdelphij } else { 605285612Sdelphij // XXX Throw a usage error 606285612Sdelphij } 607285612Sdelphij } 608285612Sdelphij ADDHOST(argv[ihost]); 609285612Sdelphij } 61054359Sroberto } 61154359Sroberto 61254359Sroberto if (numcmds == 0 && interactive == 0 61354359Sroberto && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 61454359Sroberto interactive = 1; 61554359Sroberto } 61654359Sroberto 617293650Sglebius set_ctrl_c_hook(on_ctrlc); 61854359Sroberto#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 61954359Sroberto if (interactive) 620293650Sglebius push_ctrl_c_handler(abortcmd); 62154359Sroberto#endif /* SYS_WINNT */ 62254359Sroberto 62354359Sroberto if (numcmds == 0) { 624285612Sdelphij (void) openhost(chosts[0].name, chosts[0].fam); 62554359Sroberto getcmds(); 62654359Sroberto } else { 62754359Sroberto for (ihost = 0; ihost < numhosts; ihost++) { 628330141Sdelphij if (openhost(chosts[ihost].name, chosts[ihost].fam)) { 629338531Sdelphij if (ihost && current_output) 630330141Sdelphij fputc('\n', current_output); 631330141Sdelphij for (icmd = 0; icmd < numcmds; icmd++) { 632338531Sdelphij if (icmd && current_output) 633330141Sdelphij fputc('\n', current_output); 634285612Sdelphij docmd(ccmds[icmd]); 635330141Sdelphij } 636330141Sdelphij } 63754359Sroberto } 63854359Sroberto } 63954359Sroberto#ifdef SYS_WINNT 64054359Sroberto WSACleanup(); 64154359Sroberto#endif /* SYS_WINNT */ 64254359Sroberto return 0; 64354359Sroberto} 644285612Sdelphij#endif /* !BUILD_AS_LIB */ 64554359Sroberto 64654359Sroberto/* 64754359Sroberto * openhost - open a socket to a host 64854359Sroberto */ 649285612Sdelphijstatic int 65054359Srobertoopenhost( 651285612Sdelphij const char *hname, 652285612Sdelphij int fam 65354359Sroberto ) 65454359Sroberto{ 655285612Sdelphij const char svc[] = "ntp"; 65654359Sroberto char temphost[LENHOSTNAME]; 657338531Sdelphij int a_info; 658285612Sdelphij struct addrinfo hints, *ai; 659285612Sdelphij sockaddr_u addr; 660285612Sdelphij size_t octets; 661338531Sdelphij const char *cp; 662132451Sroberto char name[LENHOSTNAME]; 66354359Sroberto 664132451Sroberto /* 665132451Sroberto * We need to get by the [] if they were entered 666132451Sroberto */ 667338531Sdelphij if (*hname == '[') { 668338531Sdelphij cp = strchr(hname + 1, ']'); 669338531Sdelphij if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) { 670338531Sdelphij errno = EINVAL; 671338531Sdelphij warning("%s", "bad hostname/address"); 672285612Sdelphij return 0; 673285612Sdelphij } 674338531Sdelphij memcpy(name, hname + 1, octets); 675338531Sdelphij name[octets] = '\0'; 676338531Sdelphij hname = name; 67754359Sroberto } 67854359Sroberto 679132451Sroberto /* 680132451Sroberto * First try to resolve it as an ip address and if that fails, 681132451Sroberto * do a fullblown (dns) lookup. That way we only use the dns 682132451Sroberto * when it is needed and work around some implementations that 683132451Sroberto * will return an "IPv4-mapped IPv6 address" address if you 684132451Sroberto * give it an IPv4 address to lookup. 685132451Sroberto */ 686285612Sdelphij ZERO(hints); 687285612Sdelphij hints.ai_family = fam; 688132451Sroberto hints.ai_protocol = IPPROTO_UDP; 689132451Sroberto hints.ai_socktype = SOCK_DGRAM; 690285612Sdelphij hints.ai_flags = Z_AI_NUMERICHOST; 691285612Sdelphij ai = NULL; 692132451Sroberto 693285612Sdelphij a_info = getaddrinfo(hname, svc, &hints, &ai); 694182007Sroberto if (a_info == EAI_NONAME 695182007Sroberto#ifdef EAI_NODATA 696182007Sroberto || a_info == EAI_NODATA 697182007Sroberto#endif 698182007Sroberto ) { 699132451Sroberto hints.ai_flags = AI_CANONNAME; 700132451Sroberto#ifdef AI_ADDRCONFIG 701132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 702132451Sroberto#endif 703285612Sdelphij a_info = getaddrinfo(hname, svc, &hints, &ai); 704132451Sroberto } 705285612Sdelphij#ifdef AI_ADDRCONFIG 706132451Sroberto /* Some older implementations don't like AI_ADDRCONFIG. */ 707132451Sroberto if (a_info == EAI_BADFLAGS) { 708285612Sdelphij hints.ai_flags &= ~AI_ADDRCONFIG; 709285612Sdelphij a_info = getaddrinfo(hname, svc, &hints, &ai); 710132451Sroberto } 711285612Sdelphij#endif 712132451Sroberto if (a_info != 0) { 713285612Sdelphij fprintf(stderr, "%s\n", gai_strerror(a_info)); 714132451Sroberto return 0; 715132451Sroberto } 716132451Sroberto 717285612Sdelphij INSIST(ai != NULL); 718285612Sdelphij ZERO(addr); 719285612Sdelphij octets = min(sizeof(addr), ai->ai_addrlen); 720285612Sdelphij memcpy(&addr, ai->ai_addr, octets); 721285612Sdelphij 722132451Sroberto if (ai->ai_canonname == NULL) { 723285612Sdelphij strlcpy(temphost, stoa(&addr), sizeof(temphost)); 724285612Sdelphij currenthostisnum = TRUE; 725132451Sroberto } else { 726285612Sdelphij strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 727285612Sdelphij currenthostisnum = FALSE; 728132451Sroberto } 729132451Sroberto 73054359Sroberto if (debug > 2) 731285612Sdelphij printf("Opening host %s (%s)\n", 732285612Sdelphij temphost, 733285612Sdelphij (ai->ai_family == AF_INET) 734285612Sdelphij ? "AF_INET" 735285612Sdelphij : (ai->ai_family == AF_INET6) 736285612Sdelphij ? "AF_INET6" 737285612Sdelphij : "AF-???" 738285612Sdelphij ); 73954359Sroberto 74054359Sroberto if (havehost == 1) { 74154359Sroberto if (debug > 2) 742285612Sdelphij printf("Closing old host %s\n", currenthost); 743285612Sdelphij closesocket(sockfd); 74454359Sroberto havehost = 0; 74554359Sroberto } 746285612Sdelphij strlcpy(currenthost, temphost, sizeof(currenthost)); 74754359Sroberto 748132451Sroberto /* port maps to the same location in both families */ 749285612Sdelphij s_port = NSRCPORT(&addr); 750132451Sroberto#ifdef SYS_VXWORKS 751132451Sroberto ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 752132451Sroberto if (ai->ai_family == AF_INET) 753132451Sroberto *(struct sockaddr_in *)&hostaddr= 754132451Sroberto *((struct sockaddr_in *)ai->ai_addr); 755132451Sroberto else 756132451Sroberto *(struct sockaddr_in6 *)&hostaddr= 757132451Sroberto *((struct sockaddr_in6 *)ai->ai_addr); 758132451Sroberto#endif /* SYS_VXWORKS */ 75954359Sroberto 76054359Sroberto#ifdef SYS_WINNT 76154359Sroberto { 76254359Sroberto int optionValue = SO_SYNCHRONOUS_NONALERT; 76354359Sroberto int err; 764182007Sroberto 765285612Sdelphij err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 766330141Sdelphij (void *)&optionValue, sizeof(optionValue)); 767285612Sdelphij if (err) { 768285612Sdelphij mfprintf(stderr, 769285612Sdelphij "setsockopt(SO_SYNCHRONOUS_NONALERT)" 770285612Sdelphij " error: %m\n"); 771285612Sdelphij freeaddrinfo(ai); 77254359Sroberto exit(1); 77354359Sroberto } 77454359Sroberto } 775132451Sroberto#endif /* SYS_WINNT */ 77654359Sroberto 777285612Sdelphij sockfd = socket(ai->ai_family, ai->ai_socktype, 778285612Sdelphij ai->ai_protocol); 77954359Sroberto if (sockfd == INVALID_SOCKET) { 780285612Sdelphij error("socket"); 781285612Sdelphij freeaddrinfo(ai); 782285612Sdelphij return 0; 78354359Sroberto } 78454359Sroberto 785285612Sdelphij 78654359Sroberto#ifdef NEED_RCVBUF_SLOP 78754359Sroberto# ifdef SO_RCVBUF 78854359Sroberto { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 78954359Sroberto if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 790330141Sdelphij (void *)&rbufsize, sizeof(int)) == -1) 791285612Sdelphij error("setsockopt"); 79254359Sroberto } 79354359Sroberto# endif 79454359Sroberto#endif 79554359Sroberto 796285612Sdelphij if 797132451Sroberto#ifdef SYS_VXWORKS 798285612Sdelphij (connect(sockfd, (struct sockaddr *)&hostaddr, 79954359Sroberto sizeof(hostaddr)) == -1) 800132451Sroberto#else 801285612Sdelphij (connect(sockfd, (struct sockaddr *)ai->ai_addr, 802293650Sglebius ai->ai_addrlen) == -1) 803132451Sroberto#endif /* SYS_VXWORKS */ 804293650Sglebius { 805285612Sdelphij error("connect"); 806132451Sroberto freeaddrinfo(ai); 807285612Sdelphij return 0; 808285612Sdelphij } 809285612Sdelphij freeaddrinfo(ai); 81054359Sroberto havehost = 1; 811285612Sdelphij numassoc = 0; 812285612Sdelphij 81354359Sroberto return 1; 81454359Sroberto} 81554359Sroberto 81654359Sroberto 817285612Sdelphijstatic void 818285612Sdelphijdump_hex_printable( 819285612Sdelphij const void * data, 820285612Sdelphij size_t len 821285612Sdelphij ) 822285612Sdelphij{ 823316069Sdelphij /* every line shows at most 16 bytes, so we need a buffer of 824316069Sdelphij * 4 * 16 (2 xdigits, 1 char, one sep for xdigits) 825316069Sdelphij * + 2 * 1 (block separators) 826316069Sdelphij * + <LF> + <NUL> 827316069Sdelphij *--------------- 828316069Sdelphij * 68 bytes 829316069Sdelphij */ 830316069Sdelphij static const char s_xdig[16] = "0123456789ABCDEF"; 831285612Sdelphij 832316069Sdelphij char lbuf[68]; 833316069Sdelphij int ch, rowlen; 834316069Sdelphij const u_char * cdata = data; 835316069Sdelphij char *xptr, *pptr; 836316069Sdelphij 837316069Sdelphij while (len) { 838316069Sdelphij memset(lbuf, ' ', sizeof(lbuf)); 839316069Sdelphij xptr = lbuf; 840316069Sdelphij pptr = lbuf + 3*16 + 2; 841316069Sdelphij 842316069Sdelphij rowlen = (len > 16) ? 16 : (int)len; 843285612Sdelphij len -= rowlen; 844316069Sdelphij 845316069Sdelphij do { 846316069Sdelphij ch = *cdata++; 847316069Sdelphij 848316069Sdelphij *xptr++ = s_xdig[ch >> 4 ]; 849316069Sdelphij *xptr++ = s_xdig[ch & 0x0F]; 850316069Sdelphij if (++xptr == lbuf + 3*8) 851316069Sdelphij ++xptr; 852316069Sdelphij 853316069Sdelphij *pptr++ = isprint(ch) ? (char)ch : '.'; 854316069Sdelphij } while (--rowlen); 855316069Sdelphij 856316069Sdelphij *pptr++ = '\n'; 857316069Sdelphij *pptr = '\0'; 858316069Sdelphij fputs(lbuf, stdout); 859285612Sdelphij } 860285612Sdelphij} 861285612Sdelphij 862285612Sdelphij 86354359Sroberto/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 86454359Sroberto/* 86554359Sroberto * sendpkt - send a packet to the remote host 86654359Sroberto */ 86754359Srobertostatic int 86854359Srobertosendpkt( 869285612Sdelphij void * xdata, 870285612Sdelphij size_t xdatalen 87154359Sroberto ) 87254359Sroberto{ 87354359Sroberto if (debug >= 3) 874285612Sdelphij printf("Sending %zu octets\n", xdatalen); 87554359Sroberto 876293650Sglebius if (send(sockfd, xdata, xdatalen, 0) == -1) { 877285612Sdelphij warning("write to %s failed", currenthost); 87854359Sroberto return -1; 87954359Sroberto } 88054359Sroberto 88154359Sroberto if (debug >= 4) { 882285612Sdelphij printf("Request packet:\n"); 883285612Sdelphij dump_hex_printable(xdata, xdatalen); 88454359Sroberto } 88554359Sroberto return 0; 88654359Sroberto} 88754359Sroberto 88854359Sroberto/* 88954359Sroberto * getresponse - get a (series of) response packet(s) and return the data 89054359Sroberto */ 89154359Srobertostatic int 89254359Srobertogetresponse( 89354359Sroberto int opcode, 89454359Sroberto int associd, 89554359Sroberto u_short *rstatus, 896293650Sglebius size_t *rsize, 897285612Sdelphij const char **rdata, 89854359Sroberto int timeo 89954359Sroberto ) 90054359Sroberto{ 90154359Sroberto struct ntp_control rpkt; 902285612Sdelphij struct sock_timeval tvo; 90354359Sroberto u_short offsets[MAXFRAGS+1]; 90454359Sroberto u_short counts[MAXFRAGS+1]; 90554359Sroberto u_short offset; 90654359Sroberto u_short count; 907285612Sdelphij size_t numfrags; 908285612Sdelphij size_t f; 909285612Sdelphij size_t ff; 91054359Sroberto int seenlastfrag; 911285612Sdelphij int shouldbesize; 91254359Sroberto fd_set fds; 91354359Sroberto int n; 914285612Sdelphij int errcode; 915294569Sdelphij /* absolute timeout checks. Not 'time_t' by intention! */ 916294569Sdelphij uint32_t tobase; /* base value for timeout */ 917294569Sdelphij uint32_t tospan; /* timeout span (max delay) */ 918294569Sdelphij uint32_t todiff; /* current delay */ 91954359Sroberto 920316069Sdelphij memset(offsets, 0, sizeof(offsets)); 921316069Sdelphij memset(counts , 0, sizeof(counts )); 922316069Sdelphij 92354359Sroberto /* 92454359Sroberto * This is pretty tricky. We may get between 1 and MAXFRAG packets 92554359Sroberto * back in response to the request. We peel the data out of 92654359Sroberto * each packet and collect it in one long block. When the last 92754359Sroberto * packet in the sequence is received we'll know how much data we 92854359Sroberto * should have had. Note we use one long time out, should reconsider. 92954359Sroberto */ 93054359Sroberto *rsize = 0; 93154359Sroberto if (rstatus) 932285612Sdelphij *rstatus = 0; 93354359Sroberto *rdata = (char *)pktdata; 93454359Sroberto 93554359Sroberto numfrags = 0; 93654359Sroberto seenlastfrag = 0; 93754359Sroberto 938294569Sdelphij tobase = (uint32_t)time(NULL); 939294569Sdelphij 94054359Sroberto FD_ZERO(&fds); 94154359Sroberto 942285612Sdelphij /* 943285612Sdelphij * Loop until we have an error or a complete response. Nearly all 944285612Sdelphij * code paths to loop again use continue. 945285612Sdelphij */ 946285612Sdelphij for (;;) { 94754359Sroberto 948285612Sdelphij if (numfrags == 0) 949285612Sdelphij tvo = tvout; 950285612Sdelphij else 951285612Sdelphij tvo = tvsout; 952294569Sdelphij tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 95354359Sroberto 954285612Sdelphij FD_SET(sockfd, &fds); 955293650Sglebius n = select(sockfd+1, &fds, NULL, NULL, &tvo); 956285612Sdelphij if (n == -1) { 957294569Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 958294569Sdelphij /* Windows does not know about EINTR (until very 959294569Sdelphij * recently) and the handling of console events 960294569Sdelphij * is *very* different from POSIX/UNIX signal 961294569Sdelphij * handling anyway. 962294569Sdelphij * 963294569Sdelphij * Under non-windows targets we map EINTR as 964294569Sdelphij * 'last packet was received' and try to exit 965294569Sdelphij * the receive sequence. 966294569Sdelphij */ 967294569Sdelphij if (errno == EINTR) { 968294569Sdelphij seenlastfrag = 1; 969294569Sdelphij goto maybe_final; 970294569Sdelphij } 971294569Sdelphij#endif 972285612Sdelphij warning("select fails"); 973285612Sdelphij return -1; 974285612Sdelphij } 975294569Sdelphij 976294569Sdelphij /* 977294569Sdelphij * Check if this is already too late. Trash the data and 978294569Sdelphij * fake a timeout if this is so. 979294569Sdelphij */ 980294569Sdelphij todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 981294569Sdelphij if ((n > 0) && (todiff > tospan)) { 982294569Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 983316069Sdelphij n -= n; /* faked timeout return from 'select()', 984316069Sdelphij * execute RMW cycle on 'n' 985316069Sdelphij */ 986294569Sdelphij } 987294569Sdelphij 988316069Sdelphij if (n <= 0) { 989285612Sdelphij /* 990285612Sdelphij * Timed out. Return what we have 991285612Sdelphij */ 992285612Sdelphij if (numfrags == 0) { 993285612Sdelphij if (timeo) 994285612Sdelphij fprintf(stderr, 995285612Sdelphij "%s: timed out, nothing received\n", 996285612Sdelphij currenthost); 997285612Sdelphij return ERR_TIMEOUT; 998285612Sdelphij } 99954359Sroberto if (timeo) 1000285612Sdelphij fprintf(stderr, 1001285612Sdelphij "%s: timed out with incomplete data\n", 1002285612Sdelphij currenthost); 100354359Sroberto if (debug) { 1004285612Sdelphij fprintf(stderr, 1005285612Sdelphij "ERR_INCOMPLETE: Received fragments:\n"); 1006285612Sdelphij for (f = 0; f < numfrags; f++) 1007285612Sdelphij fprintf(stderr, 1008285612Sdelphij "%2u: %5d %5d\t%3d octets\n", 1009285612Sdelphij (u_int)f, offsets[f], 1010285612Sdelphij offsets[f] + 1011285612Sdelphij counts[f], 1012285612Sdelphij counts[f]); 1013285612Sdelphij fprintf(stderr, 1014285612Sdelphij "last fragment %sreceived\n", 1015285612Sdelphij (seenlastfrag) 1016285612Sdelphij ? "" 1017285612Sdelphij : "not "); 101854359Sroberto } 101954359Sroberto return ERR_INCOMPLETE; 102054359Sroberto } 102154359Sroberto 1022285612Sdelphij n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 1023316069Sdelphij if (n < 0) { 1024285612Sdelphij warning("read"); 1025285612Sdelphij return -1; 1026285612Sdelphij } 102754359Sroberto 1028285612Sdelphij if (debug >= 4) { 1029285612Sdelphij printf("Response packet:\n"); 1030285612Sdelphij dump_hex_printable(&rpkt, n); 1031285612Sdelphij } 103254359Sroberto 1033285612Sdelphij /* 1034285612Sdelphij * Check for format errors. Bug proofing. 1035285612Sdelphij */ 1036285612Sdelphij if (n < (int)CTL_HEADER_LEN) { 1037285612Sdelphij if (debug) 1038285612Sdelphij printf("Short (%d byte) packet received\n", n); 1039285612Sdelphij continue; 104054359Sroberto } 1041285612Sdelphij if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 1042285612Sdelphij || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 1043285612Sdelphij if (debug) 1044285612Sdelphij printf("Packet received with version %d\n", 1045285612Sdelphij PKT_VERSION(rpkt.li_vn_mode)); 1046285612Sdelphij continue; 1047285612Sdelphij } 1048285612Sdelphij if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 1049285612Sdelphij if (debug) 1050285612Sdelphij printf("Packet received with mode %d\n", 1051285612Sdelphij PKT_MODE(rpkt.li_vn_mode)); 1052285612Sdelphij continue; 1053285612Sdelphij } 1054285612Sdelphij if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 1055285612Sdelphij if (debug) 1056285612Sdelphij printf("Received request packet, wanted response\n"); 1057285612Sdelphij continue; 1058285612Sdelphij } 105954359Sroberto 1060285612Sdelphij /* 1061285612Sdelphij * Check opcode and sequence number for a match. 1062285612Sdelphij * Could be old data getting to us. 1063285612Sdelphij */ 1064285612Sdelphij if (ntohs(rpkt.sequence) != sequence) { 1065285612Sdelphij if (debug) 1066285612Sdelphij printf("Received sequnce number %d, wanted %d\n", 1067285612Sdelphij ntohs(rpkt.sequence), sequence); 1068285612Sdelphij continue; 1069285612Sdelphij } 1070285612Sdelphij if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1071285612Sdelphij if (debug) 1072285612Sdelphij printf( 1073285612Sdelphij "Received opcode %d, wanted %d (sequence number okay)\n", 1074285612Sdelphij CTL_OP(rpkt.r_m_e_op), opcode); 1075285612Sdelphij continue; 1076285612Sdelphij } 107754359Sroberto 1078285612Sdelphij /* 1079285612Sdelphij * Check the error code. If non-zero, return it. 1080285612Sdelphij */ 1081285612Sdelphij if (CTL_ISERROR(rpkt.r_m_e_op)) { 1082285612Sdelphij errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1083285612Sdelphij if (CTL_ISMORE(rpkt.r_m_e_op)) 1084285612Sdelphij TRACE(1, ("Error code %d received on not-final packet\n", 1085285612Sdelphij errcode)); 1086285612Sdelphij if (errcode == CERR_UNSPEC) 1087285612Sdelphij return ERR_UNSPEC; 1088285612Sdelphij return errcode; 108954359Sroberto } 109054359Sroberto 109154359Sroberto /* 1092285612Sdelphij * Check the association ID to make sure it matches what 1093285612Sdelphij * we sent. 109454359Sroberto */ 1095285612Sdelphij if (ntohs(rpkt.associd) != associd) { 1096285612Sdelphij TRACE(1, ("Association ID %d doesn't match expected %d\n", 1097285612Sdelphij ntohs(rpkt.associd), associd)); 1098285612Sdelphij /* 1099285612Sdelphij * Hack for silly fuzzballs which, at the time of writing, 1100285612Sdelphij * return an assID of sys.peer when queried for system variables. 1101285612Sdelphij */ 110254359Sroberto#ifdef notdef 1103285612Sdelphij continue; 110454359Sroberto#endif 1105285612Sdelphij } 110654359Sroberto 1107285612Sdelphij /* 1108285612Sdelphij * Collect offset and count. Make sure they make sense. 1109285612Sdelphij */ 1110285612Sdelphij offset = ntohs(rpkt.offset); 1111285612Sdelphij count = ntohs(rpkt.count); 111254359Sroberto 111354359Sroberto /* 1114285612Sdelphij * validate received payload size is padded to next 32-bit 1115285612Sdelphij * boundary and no smaller than claimed by rpkt.count 111654359Sroberto */ 1117285612Sdelphij if (n & 0x3) { 1118285612Sdelphij TRACE(1, ("Response packet not padded, size = %d\n", 1119285612Sdelphij n)); 1120285612Sdelphij continue; 1121285612Sdelphij } 112254359Sroberto 1123285612Sdelphij shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 112454359Sroberto 1125285612Sdelphij if (n < shouldbesize) { 1126285612Sdelphij printf("Response packet claims %u octets payload, above %ld received\n", 1127301256Sdelphij count, (long)(n - CTL_HEADER_LEN)); 1128285612Sdelphij return ERR_INCOMPLETE; 1129285612Sdelphij } 1130285612Sdelphij 1131285612Sdelphij if (debug >= 3 && shouldbesize > n) { 1132285612Sdelphij u_int32 key; 1133285612Sdelphij u_int32 *lpkt; 1134285612Sdelphij int maclen; 1135285612Sdelphij 1136285612Sdelphij /* 1137285612Sdelphij * Usually we ignore authentication, but for debugging purposes 1138285612Sdelphij * we watch it here. 1139285612Sdelphij */ 1140285612Sdelphij /* round to 8 octet boundary */ 1141285612Sdelphij shouldbesize = (shouldbesize + 7) & ~7; 1142285612Sdelphij 1143285612Sdelphij maclen = n - shouldbesize; 1144285612Sdelphij if (maclen >= (int)MIN_MAC_LEN) { 1145285612Sdelphij printf( 1146285612Sdelphij "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1147285612Sdelphij n, shouldbesize, maclen); 1148285612Sdelphij lpkt = (u_int32 *)&rpkt; 1149285612Sdelphij printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1150285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1151285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1152285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1153285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1154285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1155285612Sdelphij (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1156285612Sdelphij key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1157285612Sdelphij printf("Authenticated with keyid %lu\n", (u_long)key); 1158285612Sdelphij if (key != 0 && key != info_auth_keyid) { 1159285612Sdelphij printf("We don't know that key\n"); 116054359Sroberto } else { 1161285612Sdelphij if (authdecrypt(key, (u_int32 *)&rpkt, 1162285612Sdelphij n - maclen, maclen)) { 1163285612Sdelphij printf("Auth okay!\n"); 1164285612Sdelphij } else { 1165285612Sdelphij printf("Auth failed!\n"); 1166285612Sdelphij } 116754359Sroberto } 116854359Sroberto } 116954359Sroberto } 117054359Sroberto 1171285612Sdelphij TRACE(2, ("Got packet, size = %d\n", n)); 1172285612Sdelphij if (count > (n - CTL_HEADER_LEN)) { 1173285612Sdelphij TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1174285612Sdelphij count, (long)n - CTL_HEADER_LEN)); 1175285612Sdelphij continue; 1176285612Sdelphij } 1177285612Sdelphij if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1178285612Sdelphij TRACE(1, ("Received count of 0 in non-final fragment\n")); 1179285612Sdelphij continue; 1180285612Sdelphij } 1181285612Sdelphij if (offset + count > sizeof(pktdata)) { 1182285612Sdelphij TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1183285612Sdelphij offset, count)); 1184285612Sdelphij return ERR_TOOMUCH; 1185285612Sdelphij } 1186285612Sdelphij if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1187285612Sdelphij TRACE(1, ("Received second last fragment packet\n")); 1188285612Sdelphij continue; 1189285612Sdelphij } 119054359Sroberto 1191285612Sdelphij /* 1192285612Sdelphij * So far, so good. Record this fragment, making sure it doesn't 1193285612Sdelphij * overlap anything. 1194285612Sdelphij */ 1195285612Sdelphij TRACE(2, ("Packet okay\n")); 119654359Sroberto 1197285612Sdelphij if (numfrags > (MAXFRAGS - 1)) { 1198285612Sdelphij TRACE(2, ("Number of fragments exceeds maximum %d\n", 1199285612Sdelphij MAXFRAGS - 1)); 1200285612Sdelphij return ERR_TOOMUCH; 120154359Sroberto } 120254359Sroberto 1203285612Sdelphij /* 1204285612Sdelphij * Find the position for the fragment relative to any 1205285612Sdelphij * previously received. 1206285612Sdelphij */ 1207285612Sdelphij for (f = 0; 1208285612Sdelphij f < numfrags && offsets[f] < offset; 1209285612Sdelphij f++) { 1210285612Sdelphij /* empty body */ ; 1211285612Sdelphij } 121254359Sroberto 1213285612Sdelphij if (f < numfrags && offset == offsets[f]) { 1214285612Sdelphij TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1215285612Sdelphij count, offset, counts[f], offsets[f])); 1216285612Sdelphij continue; 1217285612Sdelphij } 121854359Sroberto 1219285612Sdelphij if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1220285612Sdelphij TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1221285612Sdelphij offset, counts[f-1], offsets[f-1])); 1222285612Sdelphij continue; 122354359Sroberto } 1224285612Sdelphij 1225285612Sdelphij if (f < numfrags && (offset + count) > offsets[f]) { 1226285612Sdelphij TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1227285612Sdelphij count, offset, offsets[f])); 1228285612Sdelphij continue; 122954359Sroberto } 123054359Sroberto 1231285612Sdelphij for (ff = numfrags; ff > f; ff--) { 1232285612Sdelphij offsets[ff] = offsets[ff-1]; 1233285612Sdelphij counts[ff] = counts[ff-1]; 1234285612Sdelphij } 1235285612Sdelphij offsets[f] = offset; 1236285612Sdelphij counts[f] = count; 1237285612Sdelphij numfrags++; 123854359Sroberto 1239285612Sdelphij /* 1240285612Sdelphij * Got that stuffed in right. Figure out if this was the last. 1241285612Sdelphij * Record status info out of the last packet. 1242285612Sdelphij */ 1243285612Sdelphij if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1244285612Sdelphij seenlastfrag = 1; 1245285612Sdelphij if (rstatus != 0) 1246285612Sdelphij *rstatus = ntohs(rpkt.status); 1247285612Sdelphij } 124854359Sroberto 1249285612Sdelphij /* 1250294569Sdelphij * Copy the data into the data buffer, and bump the 1251294569Sdelphij * timout base in case we need more. 1252285612Sdelphij */ 1253285612Sdelphij memcpy((char *)pktdata + offset, &rpkt.u, count); 1254294569Sdelphij tobase = (uint32_t)time(NULL); 1255294569Sdelphij 1256285612Sdelphij /* 1257285612Sdelphij * If we've seen the last fragment, look for holes in the sequence. 1258285612Sdelphij * If there aren't any, we're done. 1259285612Sdelphij */ 1260301256Sdelphij#if !defined(SYS_WINNT) && defined(EINTR) 1261301256Sdelphij maybe_final: 1262301256Sdelphij#endif 1263301256Sdelphij 1264285612Sdelphij if (seenlastfrag && offsets[0] == 0) { 1265285612Sdelphij for (f = 1; f < numfrags; f++) 1266285612Sdelphij if (offsets[f-1] + counts[f-1] != 1267285612Sdelphij offsets[f]) 1268285612Sdelphij break; 1269285612Sdelphij if (f == numfrags) { 1270285612Sdelphij *rsize = offsets[f-1] + counts[f-1]; 1271285612Sdelphij TRACE(1, ("%lu packets reassembled into response\n", 1272285612Sdelphij (u_long)numfrags)); 1273285612Sdelphij return 0; 1274285612Sdelphij } 1275285612Sdelphij } 1276285612Sdelphij } /* giant for (;;) collecting response packets */ 1277285612Sdelphij} /* getresponse() */ 1278285612Sdelphij 1279285612Sdelphij 128054359Sroberto/* 128154359Sroberto * sendrequest - format and send a request packet 128254359Sroberto */ 128354359Srobertostatic int 128454359Srobertosendrequest( 128554359Sroberto int opcode, 1286285612Sdelphij associd_t associd, 128754359Sroberto int auth, 1288293650Sglebius size_t qsize, 1289285612Sdelphij const char *qdata 129054359Sroberto ) 129154359Sroberto{ 129254359Sroberto struct ntp_control qpkt; 1293293650Sglebius size_t pktsize; 1294285612Sdelphij u_long key_id; 1295285612Sdelphij char * pass; 1296293650Sglebius size_t maclen; 129754359Sroberto 129854359Sroberto /* 129954359Sroberto * Check to make sure the data will fit in one packet 130054359Sroberto */ 130154359Sroberto if (qsize > CTL_MAX_DATA_LEN) { 1302285612Sdelphij fprintf(stderr, 1303293650Sglebius "***Internal error! qsize (%zu) too large\n", 1304285612Sdelphij qsize); 130554359Sroberto return 1; 130654359Sroberto } 130754359Sroberto 130854359Sroberto /* 130954359Sroberto * Fill in the packet 131054359Sroberto */ 131154359Sroberto qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1312132451Sroberto qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 131354359Sroberto qpkt.sequence = htons(sequence); 131454359Sroberto qpkt.status = 0; 131554359Sroberto qpkt.associd = htons((u_short)associd); 131654359Sroberto qpkt.offset = 0; 131754359Sroberto qpkt.count = htons((u_short)qsize); 131854359Sroberto 1319285612Sdelphij pktsize = CTL_HEADER_LEN; 1320285612Sdelphij 132154359Sroberto /* 1322285612Sdelphij * If we have data, copy and pad it out to a 32-bit boundary. 132354359Sroberto */ 132454359Sroberto if (qsize > 0) { 1325285612Sdelphij memcpy(&qpkt.u, qdata, (size_t)qsize); 1326285612Sdelphij pktsize += qsize; 1327285612Sdelphij while (pktsize & (sizeof(u_int32) - 1)) { 1328285612Sdelphij qpkt.u.data[qsize++] = 0; 132954359Sroberto pktsize++; 133054359Sroberto } 133154359Sroberto } 133254359Sroberto 133354359Sroberto /* 133454359Sroberto * If it isn't authenticated we can just send it. Otherwise 133554359Sroberto * we're going to have to think about it a little. 133654359Sroberto */ 133754359Sroberto if (!auth && !always_auth) { 1338285612Sdelphij return sendpkt(&qpkt, pktsize); 1339285612Sdelphij } 134054359Sroberto 1341285612Sdelphij /* 1342285612Sdelphij * Pad out packet to a multiple of 8 octets to be sure 1343285612Sdelphij * receiver can handle it. 1344285612Sdelphij */ 1345285612Sdelphij while (pktsize & 7) { 1346285612Sdelphij qpkt.u.data[qsize++] = 0; 1347285612Sdelphij pktsize++; 1348285612Sdelphij } 134954359Sroberto 1350285612Sdelphij /* 1351285612Sdelphij * Get the keyid and the password if we don't have one. 1352285612Sdelphij */ 1353285612Sdelphij if (info_auth_keyid == 0) { 1354285612Sdelphij key_id = getkeyid("Keyid: "); 1355285612Sdelphij if (key_id == 0 || key_id > NTP_MAXKEY) { 1356285612Sdelphij fprintf(stderr, 1357285612Sdelphij "Invalid key identifier\n"); 1358285612Sdelphij return 1; 135954359Sroberto } 1360285612Sdelphij info_auth_keyid = key_id; 1361285612Sdelphij } 1362285612Sdelphij if (!authistrusted(info_auth_keyid)) { 1363285612Sdelphij pass = getpass_keytype(info_auth_keytype); 1364285612Sdelphij if ('\0' == pass[0]) { 1365285612Sdelphij fprintf(stderr, "Invalid password\n"); 1366285612Sdelphij return 1; 136754359Sroberto } 1368285612Sdelphij authusekey(info_auth_keyid, info_auth_keytype, 1369285612Sdelphij (u_char *)pass); 137054359Sroberto authtrust(info_auth_keyid, 1); 1371285612Sdelphij } 137254359Sroberto 1373285612Sdelphij /* 1374285612Sdelphij * Do the encryption. 1375285612Sdelphij */ 1376285612Sdelphij maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1377285612Sdelphij if (!maclen) { 1378285612Sdelphij fprintf(stderr, "Key not found\n"); 1379285612Sdelphij return 1; 1380285612Sdelphij } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1381285612Sdelphij fprintf(stderr, 1382293650Sglebius "%zu octet MAC, %zu expected with %zu octet digest\n", 1383285612Sdelphij maclen, (info_auth_hashlen + sizeof(keyid_t)), 1384285612Sdelphij info_auth_hashlen); 1385285612Sdelphij return 1; 138654359Sroberto } 1387285612Sdelphij 1388285612Sdelphij return sendpkt((char *)&qpkt, pktsize + maclen); 138954359Sroberto} 139054359Sroberto 139154359Sroberto 139254359Sroberto/* 1393285612Sdelphij * show_error_msg - display the error text for a mode 6 error response. 139454359Sroberto */ 1395285612Sdelphijvoid 1396285612Sdelphijshow_error_msg( 1397285612Sdelphij int m6resp, 1398285612Sdelphij associd_t associd 1399285612Sdelphij ) 1400285612Sdelphij{ 1401285612Sdelphij if (numhosts > 1) 1402285612Sdelphij fprintf(stderr, "server=%s ", currenthost); 1403285612Sdelphij 1404298699Sdelphij switch (m6resp) { 1405285612Sdelphij 1406285612Sdelphij case CERR_BADFMT: 1407285612Sdelphij fprintf(stderr, 1408285612Sdelphij "***Server reports a bad format request packet\n"); 1409285612Sdelphij break; 1410285612Sdelphij 1411285612Sdelphij case CERR_PERMISSION: 1412285612Sdelphij fprintf(stderr, 1413285612Sdelphij "***Server disallowed request (authentication?)\n"); 1414285612Sdelphij break; 1415285612Sdelphij 1416285612Sdelphij case CERR_BADOP: 1417285612Sdelphij fprintf(stderr, 1418285612Sdelphij "***Server reports a bad opcode in request\n"); 1419285612Sdelphij break; 1420285612Sdelphij 1421285612Sdelphij case CERR_BADASSOC: 1422285612Sdelphij fprintf(stderr, 1423285612Sdelphij "***Association ID %d unknown to server\n", 1424285612Sdelphij associd); 1425285612Sdelphij break; 1426285612Sdelphij 1427285612Sdelphij case CERR_UNKNOWNVAR: 1428285612Sdelphij fprintf(stderr, 1429285612Sdelphij "***A request variable unknown to the server\n"); 1430285612Sdelphij break; 1431285612Sdelphij 1432285612Sdelphij case CERR_BADVALUE: 1433285612Sdelphij fprintf(stderr, 1434285612Sdelphij "***Server indicates a request variable was bad\n"); 1435285612Sdelphij break; 1436285612Sdelphij 1437285612Sdelphij case ERR_UNSPEC: 1438285612Sdelphij fprintf(stderr, 1439285612Sdelphij "***Server returned an unspecified error\n"); 1440285612Sdelphij break; 1441285612Sdelphij 1442285612Sdelphij case ERR_TIMEOUT: 1443285612Sdelphij fprintf(stderr, "***Request timed out\n"); 1444285612Sdelphij break; 1445285612Sdelphij 1446285612Sdelphij case ERR_INCOMPLETE: 1447285612Sdelphij fprintf(stderr, 1448285612Sdelphij "***Response from server was incomplete\n"); 1449285612Sdelphij break; 1450285612Sdelphij 1451285612Sdelphij case ERR_TOOMUCH: 1452285612Sdelphij fprintf(stderr, 1453285612Sdelphij "***Buffer size exceeded for returned data\n"); 1454285612Sdelphij break; 1455285612Sdelphij 1456285612Sdelphij default: 1457285612Sdelphij fprintf(stderr, 1458285612Sdelphij "***Server returns unknown error code %d\n", 1459285612Sdelphij m6resp); 1460285612Sdelphij } 1461285612Sdelphij} 1462285612Sdelphij 1463285612Sdelphij/* 1464285612Sdelphij * doquery - send a request and process the response, displaying 1465285612Sdelphij * error messages for any error responses. 1466285612Sdelphij */ 146754359Srobertoint 146854359Srobertodoquery( 146954359Sroberto int opcode, 1470285612Sdelphij associd_t associd, 147154359Sroberto int auth, 1472293650Sglebius size_t qsize, 1473285612Sdelphij const char *qdata, 147454359Sroberto u_short *rstatus, 1475293650Sglebius size_t *rsize, 1476285612Sdelphij const char **rdata 147754359Sroberto ) 147854359Sroberto{ 1479285612Sdelphij return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1480285612Sdelphij rsize, rdata, FALSE); 1481285612Sdelphij} 1482285612Sdelphij 1483285612Sdelphij 1484285612Sdelphij/* 1485285612Sdelphij * doqueryex - send a request and process the response, optionally 1486285612Sdelphij * displaying error messages for any error responses. 1487285612Sdelphij */ 1488285612Sdelphijint 1489285612Sdelphijdoqueryex( 1490285612Sdelphij int opcode, 1491285612Sdelphij associd_t associd, 1492285612Sdelphij int auth, 1493293650Sglebius size_t qsize, 1494285612Sdelphij const char *qdata, 1495285612Sdelphij u_short *rstatus, 1496293650Sglebius size_t *rsize, 1497285612Sdelphij const char **rdata, 1498285612Sdelphij int quiet 1499285612Sdelphij ) 1500285612Sdelphij{ 150154359Sroberto int res; 150254359Sroberto int done; 150354359Sroberto 150454359Sroberto /* 150554359Sroberto * Check to make sure host is open 150654359Sroberto */ 150754359Sroberto if (!havehost) { 1508285612Sdelphij fprintf(stderr, "***No host open, use `host' command\n"); 150954359Sroberto return -1; 151054359Sroberto } 151154359Sroberto 151254359Sroberto done = 0; 151354359Sroberto sequence++; 151454359Sroberto 151554359Sroberto again: 151654359Sroberto /* 151754359Sroberto * send a request 151854359Sroberto */ 151954359Sroberto res = sendrequest(opcode, associd, auth, qsize, qdata); 152054359Sroberto if (res != 0) 1521285612Sdelphij return res; 1522285612Sdelphij 152354359Sroberto /* 152454359Sroberto * Get the response. If we got a standard error, print a message 152554359Sroberto */ 152654359Sroberto res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 152754359Sroberto 152854359Sroberto if (res > 0) { 152954359Sroberto if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 153054359Sroberto if (res == ERR_INCOMPLETE) { 153154359Sroberto /* 153254359Sroberto * better bump the sequence so we don't 153354359Sroberto * get confused about differing fragments. 153454359Sroberto */ 153554359Sroberto sequence++; 153654359Sroberto } 153754359Sroberto done = 1; 153854359Sroberto goto again; 153954359Sroberto } 1540285612Sdelphij if (!quiet) 1541285612Sdelphij show_error_msg(res, associd); 1542285612Sdelphij 154354359Sroberto } 154454359Sroberto return res; 154554359Sroberto} 154654359Sroberto 154754359Sroberto 1548285612Sdelphij#ifndef BUILD_AS_LIB 154954359Sroberto/* 155054359Sroberto * getcmds - read commands from the standard input and execute them 155154359Sroberto */ 155254359Srobertostatic void 155354359Srobertogetcmds(void) 155454359Sroberto{ 1555285612Sdelphij char * line; 1556285612Sdelphij int count; 155754359Sroberto 1558285612Sdelphij ntp_readline_init(interactive ? prompt : NULL); 1559106163Sroberto 1560285612Sdelphij for (;;) { 1561285612Sdelphij line = ntp_readline(&count); 1562285612Sdelphij if (NULL == line) 1563285612Sdelphij break; 1564285612Sdelphij docmd(line); 1565285612Sdelphij free(line); 1566285612Sdelphij } 156754359Sroberto 1568285612Sdelphij ntp_readline_uninit(); 156954359Sroberto} 1570285612Sdelphij#endif /* !BUILD_AS_LIB */ 157154359Sroberto 1572285612Sdelphij 1573285612Sdelphij#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 157454359Sroberto/* 157554359Sroberto * abortcmd - catch interrupts and abort the current command 157654359Sroberto */ 1577293650Sglebiusstatic int 1578293650Sglebiusabortcmd(void) 157954359Sroberto{ 158054359Sroberto if (current_output == stdout) 1581293650Sglebius (void) fflush(stdout); 158254359Sroberto putc('\n', stderr); 158354359Sroberto (void) fflush(stderr); 1584293650Sglebius if (jump) { 1585293650Sglebius jump = 0; 1586338531Sdelphij LONGJMP(interrupt_buf, 1); 1587293650Sglebius } 1588293650Sglebius return TRUE; 158954359Sroberto} 1590285612Sdelphij#endif /* !SYS_WINNT && !BUILD_AS_LIB */ 159154359Sroberto 1592285612Sdelphij 1593285612Sdelphij#ifndef BUILD_AS_LIB 159454359Sroberto/* 159554359Sroberto * docmd - decode the command line and execute a command 159654359Sroberto */ 159754359Srobertostatic void 159854359Srobertodocmd( 159954359Sroberto const char *cmdline 160054359Sroberto ) 160154359Sroberto{ 160254359Sroberto char *tokens[1+MAXARGS+2]; 160354359Sroberto struct parse pcmd; 160454359Sroberto int ntok; 160554359Sroberto static int i; 160654359Sroberto struct xcmd *xcmd; 160754359Sroberto 160854359Sroberto /* 160954359Sroberto * Tokenize the command line. If nothing on it, return. 161054359Sroberto */ 161154359Sroberto tokenize(cmdline, tokens, &ntok); 161254359Sroberto if (ntok == 0) 161354359Sroberto return; 1614285612Sdelphij 161554359Sroberto /* 161654359Sroberto * Find the appropriate command description. 161754359Sroberto */ 161854359Sroberto i = findcmd(tokens[0], builtins, opcmds, &xcmd); 161954359Sroberto if (i == 0) { 162054359Sroberto (void) fprintf(stderr, "***Command `%s' unknown\n", 162154359Sroberto tokens[0]); 162254359Sroberto return; 162354359Sroberto } else if (i >= 2) { 162454359Sroberto (void) fprintf(stderr, "***Command `%s' ambiguous\n", 162554359Sroberto tokens[0]); 162654359Sroberto return; 162754359Sroberto } 1628285612Sdelphij 1629285612Sdelphij /* Warn about ignored extra args */ 1630285612Sdelphij for (i = MAXARGS + 1; i < ntok ; ++i) { 1631285612Sdelphij fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1632285612Sdelphij } 1633285612Sdelphij 163454359Sroberto /* 163554359Sroberto * Save the keyword, then walk through the arguments, interpreting 163654359Sroberto * as we go. 163754359Sroberto */ 163854359Sroberto pcmd.keyword = tokens[0]; 163954359Sroberto pcmd.nargs = 0; 164054359Sroberto for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 164154359Sroberto if ((i+1) >= ntok) { 164254359Sroberto if (!(xcmd->arg[i] & OPT)) { 164354359Sroberto printusage(xcmd, stderr); 164454359Sroberto return; 164554359Sroberto } 164654359Sroberto break; 164754359Sroberto } 164854359Sroberto if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1649285612Sdelphij break; 165054359Sroberto if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1651285612Sdelphij return; 165254359Sroberto pcmd.nargs++; 165354359Sroberto } 165454359Sroberto 165554359Sroberto i++; 165654359Sroberto if (i < ntok && *tokens[i] == '>') { 165754359Sroberto char *fname; 165854359Sroberto 165954359Sroberto if (*(tokens[i]+1) != '\0') 1660285612Sdelphij fname = tokens[i]+1; 166154359Sroberto else if ((i+1) < ntok) 1662285612Sdelphij fname = tokens[i+1]; 166354359Sroberto else { 166454359Sroberto (void) fprintf(stderr, "***No file for redirect\n"); 166554359Sroberto return; 166654359Sroberto } 166754359Sroberto 166854359Sroberto current_output = fopen(fname, "w"); 166954359Sroberto if (current_output == NULL) { 167054359Sroberto (void) fprintf(stderr, "***Error opening %s: ", fname); 167154359Sroberto perror(""); 167254359Sroberto return; 167354359Sroberto } 167454359Sroberto } else { 167554359Sroberto current_output = stdout; 167654359Sroberto } 167754359Sroberto 1678338531Sdelphij if (interactive) { 1679338531Sdelphij if ( ! SETJMP(interrupt_buf)) { 1680338531Sdelphij jump = 1; 1681338531Sdelphij (xcmd->handler)(&pcmd, current_output); 1682338531Sdelphij jump = 0; 1683338531Sdelphij } else { 1684338531Sdelphij fflush(current_output); 1685338531Sdelphij fputs("\n >>> command aborted <<<\n", stderr); 1686338531Sdelphij fflush(stderr); 1687338531Sdelphij } 1688338531Sdelphij 1689338531Sdelphij } else { 169054359Sroberto jump = 0; 169154359Sroberto (xcmd->handler)(&pcmd, current_output); 169254359Sroberto } 1693338531Sdelphij if ((NULL != current_output) && (stdout != current_output)) { 1694338531Sdelphij (void)fclose(current_output); 1695338531Sdelphij current_output = NULL; 1696338531Sdelphij } 169754359Sroberto} 169854359Sroberto 169954359Sroberto 170054359Sroberto/* 170154359Sroberto * tokenize - turn a command line into tokens 1702285612Sdelphij * 1703285612Sdelphij * SK: Modified to allow a quoted string 1704285612Sdelphij * 1705285612Sdelphij * HMS: If the first character of the first token is a ':' then (after 1706285612Sdelphij * eating inter-token whitespace) the 2nd token is the rest of the line. 170754359Sroberto */ 1708285612Sdelphij 170954359Srobertostatic void 171054359Srobertotokenize( 171154359Sroberto const char *line, 171254359Sroberto char **tokens, 171354359Sroberto int *ntok 171454359Sroberto ) 171554359Sroberto{ 171654359Sroberto register const char *cp; 171754359Sroberto register char *sp; 171854359Sroberto static char tspace[MAXLINE]; 171954359Sroberto 172054359Sroberto sp = tspace; 172154359Sroberto cp = line; 172254359Sroberto for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 172354359Sroberto tokens[*ntok] = sp; 1724285612Sdelphij 1725285612Sdelphij /* Skip inter-token whitespace */ 172654359Sroberto while (ISSPACE(*cp)) 172754359Sroberto cp++; 1728285612Sdelphij 1729285612Sdelphij /* If we're at EOL we're done */ 173054359Sroberto if (ISEOL(*cp)) 173154359Sroberto break; 173254359Sroberto 1733285612Sdelphij /* If this is the 2nd token and the first token begins 1734285612Sdelphij * with a ':', then just grab to EOL. 1735285612Sdelphij */ 1736285612Sdelphij 1737285612Sdelphij if (*ntok == 1 && tokens[0][0] == ':') { 1738285612Sdelphij do { 1739285612Sdelphij if (sp - tspace >= MAXLINE) 1740285612Sdelphij goto toobig; 1741285612Sdelphij *sp++ = *cp++; 1742285612Sdelphij } while (!ISEOL(*cp)); 1743285612Sdelphij } 1744285612Sdelphij 1745285612Sdelphij /* Check if this token begins with a double quote. 1746285612Sdelphij * If yes, continue reading till the next double quote 1747285612Sdelphij */ 1748285612Sdelphij else if (*cp == '\"') { 1749285612Sdelphij ++cp; 1750285612Sdelphij do { 1751285612Sdelphij if (sp - tspace >= MAXLINE) 1752285612Sdelphij goto toobig; 1753285612Sdelphij *sp++ = *cp++; 1754285612Sdelphij } while ((*cp != '\"') && !ISEOL(*cp)); 1755285612Sdelphij /* HMS: a missing closing " should be an error */ 1756285612Sdelphij } 1757285612Sdelphij else { 1758285612Sdelphij do { 1759285612Sdelphij if (sp - tspace >= MAXLINE) 1760285612Sdelphij goto toobig; 1761285612Sdelphij *sp++ = *cp++; 1762285612Sdelphij } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1763285612Sdelphij /* HMS: Why check for a " in the previous line? */ 1764285612Sdelphij } 1765285612Sdelphij 1766285612Sdelphij if (sp - tspace >= MAXLINE) 1767285612Sdelphij goto toobig; 176854359Sroberto *sp++ = '\0'; 176954359Sroberto } 1770285612Sdelphij return; 1771285612Sdelphij 1772285612Sdelphij toobig: 1773285612Sdelphij *ntok = 0; 1774285612Sdelphij fprintf(stderr, 1775285612Sdelphij "***Line `%s' is too big\n", 1776285612Sdelphij line); 1777285612Sdelphij return; 177854359Sroberto} 177954359Sroberto 178054359Sroberto 1781285612Sdelphij/* 1782285612Sdelphij * getarg - interpret an argument token 1783285612Sdelphij */ 1784285612Sdelphijstatic int 1785285612Sdelphijgetarg( 1786285612Sdelphij const char *str, 1787285612Sdelphij int code, 1788285612Sdelphij arg_v *argp 1789285612Sdelphij ) 1790285612Sdelphij{ 1791285612Sdelphij u_long ul; 179254359Sroberto 1793285612Sdelphij switch (code & ~OPT) { 1794285612Sdelphij case NTP_STR: 1795285612Sdelphij argp->string = str; 1796285612Sdelphij break; 1797285612Sdelphij 1798285612Sdelphij case NTP_ADD: 1799285612Sdelphij if (!getnetnum(str, &argp->netnum, NULL, 0)) 1800285612Sdelphij return 0; 1801285612Sdelphij break; 1802285612Sdelphij 1803285612Sdelphij case NTP_UINT: 1804285612Sdelphij if ('&' == str[0]) { 1805285612Sdelphij if (!atouint(&str[1], &ul)) { 1806285612Sdelphij fprintf(stderr, 1807285612Sdelphij "***Association index `%s' invalid/undecodable\n", 1808285612Sdelphij str); 1809285612Sdelphij return 0; 1810285612Sdelphij } 1811285612Sdelphij if (0 == numassoc) { 1812285612Sdelphij dogetassoc(stdout); 1813285612Sdelphij if (0 == numassoc) { 1814285612Sdelphij fprintf(stderr, 1815285612Sdelphij "***No associations found, `%s' unknown\n", 1816285612Sdelphij str); 1817285612Sdelphij return 0; 1818285612Sdelphij } 1819285612Sdelphij } 1820285612Sdelphij ul = min(ul, numassoc); 1821285612Sdelphij argp->uval = assoc_cache[ul - 1].assid; 1822285612Sdelphij break; 1823285612Sdelphij } 1824285612Sdelphij if (!atouint(str, &argp->uval)) { 1825285612Sdelphij fprintf(stderr, "***Illegal unsigned value %s\n", 1826285612Sdelphij str); 1827285612Sdelphij return 0; 1828285612Sdelphij } 1829285612Sdelphij break; 1830285612Sdelphij 1831285612Sdelphij case NTP_INT: 1832285612Sdelphij if (!atoint(str, &argp->ival)) { 1833285612Sdelphij fprintf(stderr, "***Illegal integer value %s\n", 1834285612Sdelphij str); 1835285612Sdelphij return 0; 1836285612Sdelphij } 1837285612Sdelphij break; 1838285612Sdelphij 1839285612Sdelphij case IP_VERSION: 1840285612Sdelphij if (!strcmp("-6", str)) { 1841285612Sdelphij argp->ival = 6; 1842285612Sdelphij } else if (!strcmp("-4", str)) { 1843285612Sdelphij argp->ival = 4; 1844285612Sdelphij } else { 1845285612Sdelphij fprintf(stderr, "***Version must be either 4 or 6\n"); 1846285612Sdelphij return 0; 1847285612Sdelphij } 1848285612Sdelphij break; 1849285612Sdelphij } 1850285612Sdelphij 1851285612Sdelphij return 1; 1852285612Sdelphij} 1853285612Sdelphij#endif /* !BUILD_AS_LIB */ 1854285612Sdelphij 1855285612Sdelphij 185654359Sroberto/* 185754359Sroberto * findcmd - find a command in a command description table 185854359Sroberto */ 185954359Srobertostatic int 186054359Srobertofindcmd( 1861285612Sdelphij const char * str, 1862285612Sdelphij struct xcmd * clist1, 1863285612Sdelphij struct xcmd * clist2, 1864285612Sdelphij struct xcmd ** cmd 186554359Sroberto ) 186654359Sroberto{ 1867285612Sdelphij struct xcmd *cl; 1868293650Sglebius size_t clen; 186954359Sroberto int nmatch; 187054359Sroberto struct xcmd *nearmatch = NULL; 187154359Sroberto struct xcmd *clist; 187254359Sroberto 187354359Sroberto clen = strlen(str); 187454359Sroberto nmatch = 0; 187554359Sroberto if (clist1 != 0) 187654359Sroberto clist = clist1; 187754359Sroberto else if (clist2 != 0) 187854359Sroberto clist = clist2; 187954359Sroberto else 188054359Sroberto return 0; 188154359Sroberto 188254359Sroberto again: 188354359Sroberto for (cl = clist; cl->keyword != 0; cl++) { 188454359Sroberto /* do a first character check, for efficiency */ 188554359Sroberto if (*str != *(cl->keyword)) 188654359Sroberto continue; 188754359Sroberto if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 188854359Sroberto /* 188954359Sroberto * Could be extact match, could be approximate. 189054359Sroberto * Is exact if the length of the keyword is the 189154359Sroberto * same as the str. 189254359Sroberto */ 189354359Sroberto if (*((cl->keyword) + clen) == '\0') { 189454359Sroberto *cmd = cl; 189554359Sroberto return 1; 189654359Sroberto } 189754359Sroberto nmatch++; 189854359Sroberto nearmatch = cl; 189954359Sroberto } 190054359Sroberto } 190154359Sroberto 190254359Sroberto /* 190354359Sroberto * See if there is more to do. If so, go again. Sorry about the 190454359Sroberto * goto, too much looking at BSD sources... 190554359Sroberto */ 190654359Sroberto if (clist == clist1 && clist2 != 0) { 190754359Sroberto clist = clist2; 190854359Sroberto goto again; 190954359Sroberto } 191054359Sroberto 191154359Sroberto /* 191254359Sroberto * If we got extactly 1 near match, use it, else return number 191354359Sroberto * of matches. 191454359Sroberto */ 191554359Sroberto if (nmatch == 1) { 191654359Sroberto *cmd = nearmatch; 191754359Sroberto return 1; 191854359Sroberto } 191954359Sroberto return nmatch; 192054359Sroberto} 192154359Sroberto 192254359Sroberto 192354359Sroberto/* 192454359Sroberto * getnetnum - given a host name, return its net number 192554359Sroberto * and (optional) full name 192654359Sroberto */ 192754359Srobertoint 192854359Srobertogetnetnum( 192954359Sroberto const char *hname, 1930285612Sdelphij sockaddr_u *num, 1931132451Sroberto char *fullhost, 1932132451Sroberto int af 193354359Sroberto ) 193454359Sroberto{ 1935132451Sroberto struct addrinfo hints, *ai = NULL; 193654359Sroberto 1937285612Sdelphij ZERO(hints); 1938132451Sroberto hints.ai_flags = AI_CANONNAME; 1939132451Sroberto#ifdef AI_ADDRCONFIG 1940132451Sroberto hints.ai_flags |= AI_ADDRCONFIG; 1941132451Sroberto#endif 1942285612Sdelphij 1943285612Sdelphij /* 1944285612Sdelphij * decodenetnum only works with addresses, but handles syntax 1945285612Sdelphij * that getaddrinfo doesn't: [2001::1]:1234 1946285612Sdelphij */ 194754359Sroberto if (decodenetnum(hname, num)) { 1948285612Sdelphij if (fullhost != NULL) 1949285612Sdelphij getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1950285612Sdelphij LENHOSTNAME, NULL, 0, 0); 195154359Sroberto return 1; 1952182007Sroberto } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1953285612Sdelphij INSIST(sizeof(*num) >= ai->ai_addrlen); 1954285612Sdelphij memcpy(num, ai->ai_addr, ai->ai_addrlen); 1955285612Sdelphij if (fullhost != NULL) { 1956285612Sdelphij if (ai->ai_canonname != NULL) 1957285612Sdelphij strlcpy(fullhost, ai->ai_canonname, 1958285612Sdelphij LENHOSTNAME); 1959285612Sdelphij else 1960285612Sdelphij getnameinfo(&num->sa, SOCKLEN(num), 1961285612Sdelphij fullhost, LENHOSTNAME, NULL, 1962285612Sdelphij 0, 0); 1963285612Sdelphij } 1964285612Sdelphij freeaddrinfo(ai); 196554359Sroberto return 1; 196654359Sroberto } 1967285612Sdelphij fprintf(stderr, "***Can't find host %s\n", hname); 1968285612Sdelphij 1969285612Sdelphij return 0; 197054359Sroberto} 197154359Sroberto 1972285612Sdelphij 197354359Sroberto/* 197454359Sroberto * nntohost - convert network number to host name. This routine enforces 197554359Sroberto * the showhostnames setting. 197654359Sroberto */ 1977285612Sdelphijconst char * 197854359Srobertonntohost( 1979285612Sdelphij sockaddr_u *netnum 198054359Sroberto ) 198154359Sroberto{ 1982285612Sdelphij return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 198354359Sroberto} 198454359Sroberto 198554359Sroberto 198654359Sroberto/* 1987285612Sdelphij * nntohost_col - convert network number to host name in fixed width. 1988285612Sdelphij * This routine enforces the showhostnames setting. 1989285612Sdelphij * When displaying hostnames longer than the width, 1990285612Sdelphij * the first part of the hostname is displayed. When 1991285612Sdelphij * displaying numeric addresses longer than the width, 1992285612Sdelphij * Such as IPv6 addresses, the caller decides whether 1993285612Sdelphij * the first or last of the numeric address is used. 1994285612Sdelphij */ 1995285612Sdelphijconst char * 1996285612Sdelphijnntohost_col( 1997285612Sdelphij sockaddr_u * addr, 1998285612Sdelphij size_t width, 1999285612Sdelphij int preserve_lowaddrbits 2000285612Sdelphij ) 2001285612Sdelphij{ 2002285612Sdelphij const char * out; 2003285612Sdelphij 2004285612Sdelphij if (!showhostnames || SOCK_UNSPEC(addr)) { 2005285612Sdelphij if (preserve_lowaddrbits) 2006285612Sdelphij out = trunc_left(stoa(addr), width); 2007285612Sdelphij else 2008285612Sdelphij out = trunc_right(stoa(addr), width); 2009285612Sdelphij } else if (ISREFCLOCKADR(addr)) { 2010285612Sdelphij out = refnumtoa(addr); 2011285612Sdelphij } else { 2012285612Sdelphij out = trunc_right(socktohost(addr), width); 2013285612Sdelphij } 2014285612Sdelphij return out; 2015285612Sdelphij} 2016285612Sdelphij 2017285612Sdelphij 2018285612Sdelphij/* 2019285612Sdelphij * nntohostp() is the same as nntohost() plus a :port suffix 2020285612Sdelphij */ 2021285612Sdelphijconst char * 2022285612Sdelphijnntohostp( 2023285612Sdelphij sockaddr_u *netnum 2024285612Sdelphij ) 2025285612Sdelphij{ 2026285612Sdelphij const char * hostn; 2027285612Sdelphij char * buf; 2028285612Sdelphij 2029285612Sdelphij if (!showhostnames || SOCK_UNSPEC(netnum)) 2030285612Sdelphij return sptoa(netnum); 2031285612Sdelphij else if (ISREFCLOCKADR(netnum)) 2032285612Sdelphij return refnumtoa(netnum); 2033285612Sdelphij 2034285612Sdelphij hostn = socktohost(netnum); 2035285612Sdelphij LIB_GETBUF(buf); 2036285612Sdelphij snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 2037285612Sdelphij 2038285612Sdelphij return buf; 2039285612Sdelphij} 2040285612Sdelphij 2041285612Sdelphij/* 204254359Sroberto * rtdatetolfp - decode an RT-11 date into an l_fp 204354359Sroberto */ 204454359Srobertostatic int 204554359Srobertortdatetolfp( 204654359Sroberto char *str, 204754359Sroberto l_fp *lfp 204854359Sroberto ) 204954359Sroberto{ 205054359Sroberto register char *cp; 205154359Sroberto register int i; 205254359Sroberto struct calendar cal; 205354359Sroberto char buf[4]; 205454359Sroberto 205554359Sroberto cal.yearday = 0; 205654359Sroberto 205754359Sroberto /* 205854359Sroberto * An RT-11 date looks like: 205954359Sroberto * 206054359Sroberto * d[d]-Mth-y[y] hh:mm:ss 206154359Sroberto * 206254359Sroberto * (No docs, but assume 4-digit years are also legal...) 206354359Sroberto * 206454359Sroberto * d[d]-Mth-y[y[y[y]]] hh:mm:ss 206554359Sroberto */ 206654359Sroberto cp = str; 2067330141Sdelphij if (!isdigit(pgetc(cp))) { 206854359Sroberto if (*cp == '-') { 206954359Sroberto /* 207054359Sroberto * Catch special case 207154359Sroberto */ 207254359Sroberto L_CLR(lfp); 207354359Sroberto return 1; 207454359Sroberto } 207554359Sroberto return 0; 207654359Sroberto } 207754359Sroberto 2078132451Sroberto cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 2079330141Sdelphij if (isdigit(pgetc(cp))) { 2080132451Sroberto cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2081132451Sroberto cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 208254359Sroberto } 208354359Sroberto 208454359Sroberto if (*cp++ != '-') 208554359Sroberto return 0; 2086285612Sdelphij 208754359Sroberto for (i = 0; i < 3; i++) 208854359Sroberto buf[i] = *cp++; 208954359Sroberto buf[3] = '\0'; 209054359Sroberto 209154359Sroberto for (i = 0; i < 12; i++) 209254359Sroberto if (STREQ(buf, months[i])) 209354359Sroberto break; 209454359Sroberto if (i == 12) 209554359Sroberto return 0; 2096132451Sroberto cal.month = (u_char)(i + 1); 209754359Sroberto 209854359Sroberto if (*cp++ != '-') 209954359Sroberto return 0; 2100285612Sdelphij 2101330141Sdelphij if (!isdigit(pgetc(cp))) 210254359Sroberto return 0; 2103132451Sroberto cal.year = (u_short)(*cp++ - '0'); 2104330141Sdelphij if (isdigit(pgetc(cp))) { 2105132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2106132451Sroberto cal.year = (u_short)(*cp++ - '0'); 210754359Sroberto } 2108330141Sdelphij if (isdigit(pgetc(cp))) { 2109132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2110132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 211154359Sroberto } 2112330141Sdelphij if (isdigit(pgetc(cp))) { 2113132451Sroberto cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2114132451Sroberto cal.year = (u_short)(cal.year + *cp++ - '0'); 211554359Sroberto } 211654359Sroberto 211754359Sroberto /* 211854359Sroberto * Catch special case. If cal.year == 0 this is a zero timestamp. 211954359Sroberto */ 212054359Sroberto if (cal.year == 0) { 212154359Sroberto L_CLR(lfp); 212254359Sroberto return 1; 212354359Sroberto } 212454359Sroberto 2125330141Sdelphij if (*cp++ != ' ' || !isdigit(pgetc(cp))) 212654359Sroberto return 0; 2127132451Sroberto cal.hour = (u_char)(*cp++ - '0'); 2128330141Sdelphij if (isdigit(pgetc(cp))) { 2129132451Sroberto cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2130132451Sroberto cal.hour = (u_char)(cal.hour + *cp++ - '0'); 213154359Sroberto } 213254359Sroberto 2133330141Sdelphij if (*cp++ != ':' || !isdigit(pgetc(cp))) 213454359Sroberto return 0; 2135132451Sroberto cal.minute = (u_char)(*cp++ - '0'); 2136330141Sdelphij if (isdigit(pgetc(cp))) { 2137132451Sroberto cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2138132451Sroberto cal.minute = (u_char)(cal.minute + *cp++ - '0'); 213954359Sroberto } 214054359Sroberto 2141330141Sdelphij if (*cp++ != ':' || !isdigit(pgetc(cp))) 214254359Sroberto return 0; 2143132451Sroberto cal.second = (u_char)(*cp++ - '0'); 2144330141Sdelphij if (isdigit(pgetc(cp))) { 2145132451Sroberto cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2146132451Sroberto cal.second = (u_char)(cal.second + *cp++ - '0'); 214754359Sroberto } 214854359Sroberto 214954359Sroberto /* 215054359Sroberto * For RT-11, 1972 seems to be the pivot year 215154359Sroberto */ 215254359Sroberto if (cal.year < 72) 215354359Sroberto cal.year += 2000; 215454359Sroberto if (cal.year < 100) 215554359Sroberto cal.year += 1900; 215654359Sroberto 215754359Sroberto lfp->l_ui = caltontp(&cal); 215854359Sroberto lfp->l_uf = 0; 215954359Sroberto return 1; 216054359Sroberto} 216154359Sroberto 216254359Sroberto 216354359Sroberto/* 216454359Sroberto * decodets - decode a timestamp into an l_fp format number, with 216554359Sroberto * consideration of fuzzball formats. 216654359Sroberto */ 216754359Srobertoint 216854359Srobertodecodets( 216954359Sroberto char *str, 217054359Sroberto l_fp *lfp 217154359Sroberto ) 217254359Sroberto{ 2173285612Sdelphij char *cp; 2174285612Sdelphij char buf[30]; 2175285612Sdelphij size_t b; 2176285612Sdelphij 217754359Sroberto /* 217854359Sroberto * If it starts with a 0x, decode as hex. 217954359Sroberto */ 218054359Sroberto if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2181285612Sdelphij return hextolfp(str+2, lfp); 218254359Sroberto 218354359Sroberto /* 218454359Sroberto * If it starts with a '"', try it as an RT-11 date. 218554359Sroberto */ 218654359Sroberto if (*str == '"') { 2187285612Sdelphij cp = str + 1; 2188285612Sdelphij b = 0; 2189285612Sdelphij while ('"' != *cp && '\0' != *cp && 2190285612Sdelphij b < COUNTOF(buf) - 1) 2191285612Sdelphij buf[b++] = *cp++; 2192285612Sdelphij buf[b] = '\0'; 219354359Sroberto return rtdatetolfp(buf, lfp); 219454359Sroberto } 219554359Sroberto 219654359Sroberto /* 219754359Sroberto * Might still be hex. Check out the first character. Talk 219854359Sroberto * about heuristics! 219954359Sroberto */ 220054359Sroberto if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2201285612Sdelphij return hextolfp(str, lfp); 220254359Sroberto 220354359Sroberto /* 220454359Sroberto * Try it as a decimal. If this fails, try as an unquoted 220554359Sroberto * RT-11 date. This code should go away eventually. 220654359Sroberto */ 220754359Sroberto if (atolfp(str, lfp)) 2208285612Sdelphij return 1; 2209285612Sdelphij 221054359Sroberto return rtdatetolfp(str, lfp); 221154359Sroberto} 221254359Sroberto 221354359Sroberto 221454359Sroberto/* 221554359Sroberto * decodetime - decode a time value. It should be in milliseconds 221654359Sroberto */ 221754359Srobertoint 221854359Srobertodecodetime( 221954359Sroberto char *str, 222054359Sroberto l_fp *lfp 222154359Sroberto ) 222254359Sroberto{ 222354359Sroberto return mstolfp(str, lfp); 222454359Sroberto} 222554359Sroberto 222654359Sroberto 222754359Sroberto/* 222854359Sroberto * decodeint - decode an integer 222954359Sroberto */ 223054359Srobertoint 223154359Srobertodecodeint( 223254359Sroberto char *str, 223354359Sroberto long *val 223454359Sroberto ) 223554359Sroberto{ 223654359Sroberto if (*str == '0') { 223754359Sroberto if (*(str+1) == 'x' || *(str+1) == 'X') 2238285612Sdelphij return hextoint(str+2, (u_long *)val); 2239285612Sdelphij return octtoint(str, (u_long *)val); 224054359Sroberto } 224154359Sroberto return atoint(str, val); 224254359Sroberto} 224354359Sroberto 224454359Sroberto 224554359Sroberto/* 224654359Sroberto * decodeuint - decode an unsigned integer 224754359Sroberto */ 224854359Srobertoint 224954359Srobertodecodeuint( 225054359Sroberto char *str, 225154359Sroberto u_long *val 225254359Sroberto ) 225354359Sroberto{ 225454359Sroberto if (*str == '0') { 225554359Sroberto if (*(str + 1) == 'x' || *(str + 1) == 'X') 225654359Sroberto return (hextoint(str + 2, val)); 225754359Sroberto return (octtoint(str, val)); 225854359Sroberto } 225954359Sroberto return (atouint(str, val)); 226054359Sroberto} 226154359Sroberto 226254359Sroberto 226354359Sroberto/* 226454359Sroberto * decodearr - decode an array of time values 226554359Sroberto */ 226654359Srobertostatic int 226754359Srobertodecodearr( 2268330141Sdelphij char *cp, 2269330141Sdelphij int *narr, 2270330141Sdelphij l_fp *lfpa, 2271330141Sdelphij int amax 227254359Sroberto ) 227354359Sroberto{ 2274330141Sdelphij char *bp; 227554359Sroberto char buf[60]; 227654359Sroberto 227754359Sroberto *narr = 0; 227854359Sroberto 2279330141Sdelphij while (*narr < amax && *cp) { 2280330141Sdelphij if (isspace(pgetc(cp))) { 2281330141Sdelphij do 2282330141Sdelphij ++cp; 2283330141Sdelphij while (*cp && isspace(pgetc(cp))); 2284330141Sdelphij } else { 2285330141Sdelphij bp = buf; 2286330141Sdelphij do { 2287330141Sdelphij if (bp != (buf + sizeof(buf) - 1)) 2288330141Sdelphij *bp++ = *cp; 2289330141Sdelphij ++cp; 2290330141Sdelphij } while (*cp && !isspace(pgetc(cp))); 2291330141Sdelphij *bp = '\0'; 229254359Sroberto 2293330141Sdelphij if (!decodetime(buf, lfpa)) 2294330141Sdelphij return 0; 2295330141Sdelphij ++(*narr); 2296330141Sdelphij ++lfpa; 2297330141Sdelphij } 229854359Sroberto } 229954359Sroberto return 1; 230054359Sroberto} 230154359Sroberto 230254359Sroberto 230354359Sroberto/* 230454359Sroberto * Finally, the built in command handlers 230554359Sroberto */ 230654359Sroberto 230754359Sroberto/* 230854359Sroberto * help - tell about commands, or details of a particular command 230954359Sroberto */ 231054359Srobertostatic void 231154359Srobertohelp( 231254359Sroberto struct parse *pcmd, 231354359Sroberto FILE *fp 231454359Sroberto ) 231554359Sroberto{ 2316285612Sdelphij struct xcmd *xcp = NULL; /* quiet warning */ 2317285612Sdelphij const char *cmd; 2318182007Sroberto const char *list[100]; 2319285612Sdelphij size_t word, words; 2320285612Sdelphij size_t row, rows; 2321285612Sdelphij size_t col, cols; 2322285612Sdelphij size_t length; 232354359Sroberto 232454359Sroberto if (pcmd->nargs == 0) { 2325182007Sroberto words = 0; 2326285612Sdelphij for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2327285612Sdelphij if (*(xcp->keyword) != '?' && 2328285612Sdelphij words < COUNTOF(list)) 2329285612Sdelphij list[words++] = xcp->keyword; 233054359Sroberto } 2331285612Sdelphij for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2332285612Sdelphij if (words < COUNTOF(list)) 2333285612Sdelphij list[words++] = xcp->keyword; 233454359Sroberto 2335285612Sdelphij qsort((void *)list, words, sizeof(list[0]), helpsort); 2336182007Sroberto col = 0; 2337182007Sroberto for (word = 0; word < words; word++) { 2338285612Sdelphij length = strlen(list[word]); 2339285612Sdelphij col = max(col, length); 234054359Sroberto } 234154359Sroberto 2342182007Sroberto cols = SCREENWIDTH / ++col; 2343285612Sdelphij rows = (words + cols - 1) / cols; 2344182007Sroberto 2345285612Sdelphij fprintf(fp, "ntpq commands:\n"); 2346182007Sroberto 2347182007Sroberto for (row = 0; row < rows; row++) { 2348285612Sdelphij for (word = row; word < words; word += rows) 2349285612Sdelphij fprintf(fp, "%-*.*s", (int)col, 2350285612Sdelphij (int)col - 1, list[word]); 2351285612Sdelphij fprintf(fp, "\n"); 2352285612Sdelphij } 235354359Sroberto } else { 235454359Sroberto cmd = pcmd->argval[0].string; 2355182007Sroberto words = findcmd(cmd, builtins, opcmds, &xcp); 2356182007Sroberto if (words == 0) { 2357285612Sdelphij fprintf(stderr, 2358285612Sdelphij "Command `%s' is unknown\n", cmd); 235954359Sroberto return; 2360182007Sroberto } else if (words >= 2) { 2361285612Sdelphij fprintf(stderr, 2362285612Sdelphij "Command `%s' is ambiguous\n", cmd); 236354359Sroberto return; 236454359Sroberto } 2365285612Sdelphij fprintf(fp, "function: %s\n", xcp->comment); 236654359Sroberto printusage(xcp, fp); 236754359Sroberto } 236854359Sroberto} 236954359Sroberto 237054359Sroberto 237154359Sroberto/* 237254359Sroberto * helpsort - do hostname qsort comparisons 237354359Sroberto */ 237454359Srobertostatic int 237554359Srobertohelpsort( 237654359Sroberto const void *t1, 237754359Sroberto const void *t2 237854359Sroberto ) 237954359Sroberto{ 2380285612Sdelphij const char * const * name1 = t1; 2381285612Sdelphij const char * const * name2 = t2; 238254359Sroberto 238354359Sroberto return strcmp(*name1, *name2); 238454359Sroberto} 238554359Sroberto 238654359Sroberto 238754359Sroberto/* 238854359Sroberto * printusage - print usage information for a command 238954359Sroberto */ 239054359Srobertostatic void 239154359Srobertoprintusage( 239254359Sroberto struct xcmd *xcp, 239354359Sroberto FILE *fp 239454359Sroberto ) 239554359Sroberto{ 239654359Sroberto register int i; 239754359Sroberto 2398285612Sdelphij /* XXX: Do we need to warn about extra args here too? */ 2399285612Sdelphij 240054359Sroberto (void) fprintf(fp, "usage: %s", xcp->keyword); 240154359Sroberto for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 240254359Sroberto if (xcp->arg[i] & OPT) 240354359Sroberto (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 240454359Sroberto else 240554359Sroberto (void) fprintf(fp, " %s", xcp->desc[i]); 240654359Sroberto } 240754359Sroberto (void) fprintf(fp, "\n"); 240854359Sroberto} 240954359Sroberto 241054359Sroberto 241154359Sroberto/* 241254359Sroberto * timeout - set time out time 241354359Sroberto */ 241454359Srobertostatic void 241554359Srobertotimeout( 241654359Sroberto struct parse *pcmd, 241754359Sroberto FILE *fp 241854359Sroberto ) 241954359Sroberto{ 242054359Sroberto int val; 242154359Sroberto 242254359Sroberto if (pcmd->nargs == 0) { 2423285612Sdelphij val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 242454359Sroberto (void) fprintf(fp, "primary timeout %d ms\n", val); 242554359Sroberto } else { 242654359Sroberto tvout.tv_sec = pcmd->argval[0].uval / 1000; 2427285612Sdelphij tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 242854359Sroberto * 1000; 242954359Sroberto } 243054359Sroberto} 243154359Sroberto 243254359Sroberto 243354359Sroberto/* 243454359Sroberto * auth_delay - set delay for auth requests 243554359Sroberto */ 243654359Srobertostatic void 243754359Srobertoauth_delay( 243854359Sroberto struct parse *pcmd, 243954359Sroberto FILE *fp 244054359Sroberto ) 244154359Sroberto{ 244254359Sroberto int isneg; 244354359Sroberto u_long val; 244454359Sroberto 244554359Sroberto if (pcmd->nargs == 0) { 244654359Sroberto val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 244754359Sroberto (void) fprintf(fp, "delay %lu ms\n", val); 244854359Sroberto } else { 244954359Sroberto if (pcmd->argval[0].ival < 0) { 245054359Sroberto isneg = 1; 245154359Sroberto val = (u_long)(-pcmd->argval[0].ival); 245254359Sroberto } else { 245354359Sroberto isneg = 0; 245454359Sroberto val = (u_long)pcmd->argval[0].ival; 245554359Sroberto } 245654359Sroberto 245754359Sroberto delay_time.l_ui = val / 1000; 245854359Sroberto val %= 1000; 245954359Sroberto delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 246054359Sroberto 246154359Sroberto if (isneg) 246254359Sroberto L_NEG(&delay_time); 246354359Sroberto } 246454359Sroberto} 246554359Sroberto 246654359Sroberto 246754359Sroberto/* 246854359Sroberto * host - set the host we are dealing with. 246954359Sroberto */ 247054359Srobertostatic void 247154359Srobertohost( 247254359Sroberto struct parse *pcmd, 247354359Sroberto FILE *fp 247454359Sroberto ) 247554359Sroberto{ 2476132451Sroberto int i; 2477132451Sroberto 247854359Sroberto if (pcmd->nargs == 0) { 247954359Sroberto if (havehost) 2480285612Sdelphij (void) fprintf(fp, "current host is %s\n", 2481285612Sdelphij currenthost); 248254359Sroberto else 2483285612Sdelphij (void) fprintf(fp, "no current host\n"); 2484132451Sroberto return; 2485132451Sroberto } 2486132451Sroberto 2487132451Sroberto i = 0; 2488132451Sroberto ai_fam_templ = ai_fam_default; 2489132451Sroberto if (pcmd->nargs == 2) { 2490132451Sroberto if (!strcmp("-4", pcmd->argval[i].string)) 2491132451Sroberto ai_fam_templ = AF_INET; 2492132451Sroberto else if (!strcmp("-6", pcmd->argval[i].string)) 2493132451Sroberto ai_fam_templ = AF_INET6; 2494285612Sdelphij else 2495285612Sdelphij goto no_change; 2496132451Sroberto i = 1; 2497132451Sroberto } 2498285612Sdelphij if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2499285612Sdelphij fprintf(fp, "current host set to %s\n", currenthost); 250054359Sroberto } else { 2501285612Sdelphij no_change: 250254359Sroberto if (havehost) 2503285612Sdelphij fprintf(fp, "current host remains %s\n", 2504285612Sdelphij currenthost); 250554359Sroberto else 2506285612Sdelphij fprintf(fp, "still no current host\n"); 250754359Sroberto } 250854359Sroberto} 250954359Sroberto 251054359Sroberto 251154359Sroberto/* 251254359Sroberto * poll - do one (or more) polls of the host via NTP 251354359Sroberto */ 251454359Sroberto/*ARGSUSED*/ 251554359Srobertostatic void 251654359Srobertontp_poll( 251754359Sroberto struct parse *pcmd, 251854359Sroberto FILE *fp 251954359Sroberto ) 252054359Sroberto{ 252154359Sroberto (void) fprintf(fp, "poll not implemented yet\n"); 252254359Sroberto} 252354359Sroberto 252454359Sroberto 252554359Sroberto/* 2526298699Sdelphij * showdrefid2str - return a string explanation of the value of drefid 2527298699Sdelphij */ 2528338531Sdelphijstatic const char * 2529298699Sdelphijshowdrefid2str(void) 2530298699Sdelphij{ 2531298699Sdelphij switch (drefid) { 2532298699Sdelphij case REFID_HASH: 2533298699Sdelphij return "hash"; 2534298699Sdelphij case REFID_IPV4: 2535298699Sdelphij return "ipv4"; 2536298699Sdelphij default: 2537298699Sdelphij return "Unknown"; 2538298699Sdelphij } 2539298699Sdelphij} 2540298699Sdelphij 2541298699Sdelphij 2542298699Sdelphij/* 2543298699Sdelphij * drefid - display/change "display hash" 2544298699Sdelphij */ 2545298699Sdelphijstatic void 2546298699Sdelphijshowdrefid( 2547298699Sdelphij struct parse *pcmd, 2548298699Sdelphij FILE *fp 2549298699Sdelphij ) 2550298699Sdelphij{ 2551298699Sdelphij if (pcmd->nargs == 0) { 2552298699Sdelphij (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2553298699Sdelphij return; 2554298699Sdelphij } else if (STREQ(pcmd->argval[0].string, "hash")) { 2555298699Sdelphij drefid = REFID_HASH; 2556298699Sdelphij } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2557298699Sdelphij drefid = REFID_IPV4; 2558298699Sdelphij } else { 2559298699Sdelphij (void) fprintf(fp, "What?\n"); 2560298699Sdelphij return; 2561298699Sdelphij } 2562298699Sdelphij (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2563298699Sdelphij} 2564298699Sdelphij 2565298699Sdelphij 2566298699Sdelphij/* 256754359Sroberto * keyid - get a keyid to use for authenticating requests 256854359Sroberto */ 256954359Srobertostatic void 257054359Srobertokeyid( 257154359Sroberto struct parse *pcmd, 257254359Sroberto FILE *fp 257354359Sroberto ) 257454359Sroberto{ 257554359Sroberto if (pcmd->nargs == 0) { 2576132451Sroberto if (info_auth_keyid == 0) 257754359Sroberto (void) fprintf(fp, "no keyid defined\n"); 257854359Sroberto else 257954359Sroberto (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 258054359Sroberto } else { 2581132451Sroberto /* allow zero so that keyid can be cleared. */ 2582132451Sroberto if(pcmd->argval[0].uval > NTP_MAXKEY) 2583132451Sroberto (void) fprintf(fp, "Invalid key identifier\n"); 258454359Sroberto info_auth_keyid = pcmd->argval[0].uval; 258554359Sroberto } 258654359Sroberto} 258754359Sroberto 258854359Sroberto/* 258954359Sroberto * keytype - get type of key to use for authenticating requests 259054359Sroberto */ 259154359Srobertostatic void 259254359Srobertokeytype( 259354359Sroberto struct parse *pcmd, 259454359Sroberto FILE *fp 259554359Sroberto ) 259654359Sroberto{ 2597285612Sdelphij const char * digest_name; 2598285612Sdelphij size_t digest_len; 2599285612Sdelphij int key_type; 260054359Sroberto 2601285612Sdelphij if (!pcmd->nargs) { 2602285612Sdelphij fprintf(fp, "keytype is %s with %lu octet digests\n", 2603285612Sdelphij keytype_name(info_auth_keytype), 2604285612Sdelphij (u_long)info_auth_hashlen); 2605285612Sdelphij return; 2606285612Sdelphij } 2607285612Sdelphij 2608285612Sdelphij digest_name = pcmd->argval[0].string; 2609285612Sdelphij digest_len = 0; 2610285612Sdelphij key_type = keytype_from_text(digest_name, &digest_len); 2611285612Sdelphij 2612285612Sdelphij if (!key_type) { 2613285612Sdelphij fprintf(fp, "keytype is not valid. " 2614285612Sdelphij#ifdef OPENSSL 2615285612Sdelphij "Type \"help keytype\" for the available digest types.\n"); 2616285612Sdelphij#else 2617285612Sdelphij "Only \"md5\" is available.\n"); 2618285612Sdelphij#endif 2619285612Sdelphij return; 2620285612Sdelphij } 2621285612Sdelphij 2622285612Sdelphij info_auth_keytype = key_type; 2623285612Sdelphij info_auth_hashlen = digest_len; 262454359Sroberto} 262554359Sroberto 262654359Sroberto 262754359Sroberto/* 262854359Sroberto * passwd - get an authentication key 262954359Sroberto */ 263054359Sroberto/*ARGSUSED*/ 263154359Srobertostatic void 263254359Srobertopasswd( 263354359Sroberto struct parse *pcmd, 263454359Sroberto FILE *fp 263554359Sroberto ) 263654359Sroberto{ 2637285612Sdelphij const char *pass; 263854359Sroberto 2639132451Sroberto if (info_auth_keyid == 0) { 2640285612Sdelphij info_auth_keyid = getkeyid("Keyid: "); 2641285612Sdelphij if (info_auth_keyid == 0) { 2642285612Sdelphij (void)fprintf(fp, "Keyid must be defined\n"); 264354359Sroberto return; 264454359Sroberto } 264554359Sroberto } 2646285612Sdelphij if (pcmd->nargs >= 1) 2647285612Sdelphij pass = pcmd->argval[0].string; 2648132451Sroberto else { 2649285612Sdelphij pass = getpass_keytype(info_auth_keytype); 2650285612Sdelphij if ('\0' == pass[0]) { 2651285612Sdelphij fprintf(fp, "Password unchanged\n"); 2652285612Sdelphij return; 2653285612Sdelphij } 2654132451Sroberto } 2655285612Sdelphij authusekey(info_auth_keyid, info_auth_keytype, 2656285612Sdelphij (const u_char *)pass); 2657285612Sdelphij authtrust(info_auth_keyid, 1); 265854359Sroberto} 265954359Sroberto 266054359Sroberto 266154359Sroberto/* 266254359Sroberto * hostnames - set the showhostnames flag 266354359Sroberto */ 266454359Srobertostatic void 266554359Srobertohostnames( 266654359Sroberto struct parse *pcmd, 266754359Sroberto FILE *fp 266854359Sroberto ) 266954359Sroberto{ 267054359Sroberto if (pcmd->nargs == 0) { 267154359Sroberto if (showhostnames) 267254359Sroberto (void) fprintf(fp, "hostnames being shown\n"); 267354359Sroberto else 267454359Sroberto (void) fprintf(fp, "hostnames not being shown\n"); 267554359Sroberto } else { 267654359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) 267754359Sroberto showhostnames = 1; 267854359Sroberto else if (STREQ(pcmd->argval[0].string, "no")) 267954359Sroberto showhostnames = 0; 268054359Sroberto else 268154359Sroberto (void)fprintf(stderr, "What?\n"); 268254359Sroberto } 268354359Sroberto} 268454359Sroberto 268554359Sroberto 268654359Sroberto 268754359Sroberto/* 268854359Sroberto * setdebug - set/change debugging level 268954359Sroberto */ 269054359Srobertostatic void 269154359Srobertosetdebug( 269254359Sroberto struct parse *pcmd, 269354359Sroberto FILE *fp 269454359Sroberto ) 269554359Sroberto{ 269654359Sroberto if (pcmd->nargs == 0) { 269754359Sroberto (void) fprintf(fp, "debug level is %d\n", debug); 269854359Sroberto return; 269954359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 270054359Sroberto debug = 0; 270154359Sroberto } else if (STREQ(pcmd->argval[0].string, "more")) { 270254359Sroberto debug++; 270354359Sroberto } else if (STREQ(pcmd->argval[0].string, "less")) { 270454359Sroberto debug--; 270554359Sroberto } else { 270654359Sroberto (void) fprintf(fp, "What?\n"); 270754359Sroberto return; 270854359Sroberto } 270954359Sroberto (void) fprintf(fp, "debug level set to %d\n", debug); 271054359Sroberto} 271154359Sroberto 271254359Sroberto 271354359Sroberto/* 271454359Sroberto * quit - stop this nonsense 271554359Sroberto */ 271654359Sroberto/*ARGSUSED*/ 271754359Srobertostatic void 271854359Srobertoquit( 271954359Sroberto struct parse *pcmd, 272054359Sroberto FILE *fp 272154359Sroberto ) 272254359Sroberto{ 272354359Sroberto if (havehost) 272454359Sroberto closesocket(sockfd); /* cleanliness next to godliness */ 272554359Sroberto exit(0); 272654359Sroberto} 272754359Sroberto 272854359Sroberto 272954359Sroberto/* 273054359Sroberto * version - print the current version number 273154359Sroberto */ 273254359Sroberto/*ARGSUSED*/ 273354359Srobertostatic void 273454359Srobertoversion( 273554359Sroberto struct parse *pcmd, 273654359Sroberto FILE *fp 273754359Sroberto ) 273854359Sroberto{ 273954359Sroberto 274054359Sroberto (void) fprintf(fp, "%s\n", Version); 274154359Sroberto return; 274254359Sroberto} 274354359Sroberto 274454359Sroberto 274554359Sroberto/* 274654359Sroberto * raw - set raw mode output 274754359Sroberto */ 274854359Sroberto/*ARGSUSED*/ 274954359Srobertostatic void 275054359Srobertoraw( 275154359Sroberto struct parse *pcmd, 275254359Sroberto FILE *fp 275354359Sroberto ) 275454359Sroberto{ 275554359Sroberto rawmode = 1; 275654359Sroberto (void) fprintf(fp, "Output set to raw\n"); 275754359Sroberto} 275854359Sroberto 275954359Sroberto 276054359Sroberto/* 276154359Sroberto * cooked - set cooked mode output 276254359Sroberto */ 276354359Sroberto/*ARGSUSED*/ 276454359Srobertostatic void 276554359Srobertocooked( 276654359Sroberto struct parse *pcmd, 276754359Sroberto FILE *fp 276854359Sroberto ) 276954359Sroberto{ 277054359Sroberto rawmode = 0; 277154359Sroberto (void) fprintf(fp, "Output set to cooked\n"); 277254359Sroberto return; 277354359Sroberto} 277454359Sroberto 277554359Sroberto 277654359Sroberto/* 277754359Sroberto * authenticate - always authenticate requests to this host 277854359Sroberto */ 277954359Srobertostatic void 278054359Srobertoauthenticate( 278154359Sroberto struct parse *pcmd, 278254359Sroberto FILE *fp 278354359Sroberto ) 278454359Sroberto{ 278554359Sroberto if (pcmd->nargs == 0) { 278654359Sroberto if (always_auth) { 278754359Sroberto (void) fprintf(fp, 278854359Sroberto "authenticated requests being sent\n"); 278954359Sroberto } else 279054359Sroberto (void) fprintf(fp, 279154359Sroberto "unauthenticated requests being sent\n"); 279254359Sroberto } else { 279354359Sroberto if (STREQ(pcmd->argval[0].string, "yes")) { 279454359Sroberto always_auth = 1; 279554359Sroberto } else if (STREQ(pcmd->argval[0].string, "no")) { 279654359Sroberto always_auth = 0; 279754359Sroberto } else 279854359Sroberto (void)fprintf(stderr, "What?\n"); 279954359Sroberto } 280054359Sroberto} 280154359Sroberto 280254359Sroberto 280354359Sroberto/* 280454359Sroberto * ntpversion - choose the NTP version to use 280554359Sroberto */ 280654359Srobertostatic void 280754359Srobertontpversion( 280854359Sroberto struct parse *pcmd, 280954359Sroberto FILE *fp 281054359Sroberto ) 281154359Sroberto{ 281254359Sroberto if (pcmd->nargs == 0) { 281354359Sroberto (void) fprintf(fp, 281454359Sroberto "NTP version being claimed is %d\n", pktversion); 281554359Sroberto } else { 281654359Sroberto if (pcmd->argval[0].uval < NTP_OLDVERSION 281754359Sroberto || pcmd->argval[0].uval > NTP_VERSION) { 281854359Sroberto (void) fprintf(stderr, "versions %d to %d, please\n", 281954359Sroberto NTP_OLDVERSION, NTP_VERSION); 282054359Sroberto } else { 282154359Sroberto pktversion = (u_char) pcmd->argval[0].uval; 282254359Sroberto } 282354359Sroberto } 282454359Sroberto} 282554359Sroberto 282654359Sroberto 2827285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 0))) 2828285612Sdelphijvwarning(const char *fmt, va_list ap) 2829285612Sdelphij{ 2830285612Sdelphij int serrno = errno; 2831285612Sdelphij (void) fprintf(stderr, "%s: ", progname); 2832285612Sdelphij vfprintf(stderr, fmt, ap); 2833293650Sglebius (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2834285612Sdelphij} 2835285612Sdelphij 283654359Sroberto/* 283754359Sroberto * warning - print a warning message 283854359Sroberto */ 2839285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 2))) 284054359Srobertowarning( 284154359Sroberto const char *fmt, 2842285612Sdelphij ... 284354359Sroberto ) 284454359Sroberto{ 2845285612Sdelphij va_list ap; 2846285612Sdelphij va_start(ap, fmt); 2847285612Sdelphij vwarning(fmt, ap); 2848285612Sdelphij va_end(ap); 284954359Sroberto} 285054359Sroberto 285154359Sroberto 285254359Sroberto/* 285354359Sroberto * error - print a message and exit 285454359Sroberto */ 2855285612Sdelphijstatic void __attribute__((__format__(__printf__, 1, 2))) 285654359Srobertoerror( 285754359Sroberto const char *fmt, 2858285612Sdelphij ... 285954359Sroberto ) 286054359Sroberto{ 2861285612Sdelphij va_list ap; 2862285612Sdelphij va_start(ap, fmt); 2863285612Sdelphij vwarning(fmt, ap); 2864285612Sdelphij va_end(ap); 286554359Sroberto exit(1); 286654359Sroberto} 286754359Sroberto/* 286854359Sroberto * getkeyid - prompt the user for a keyid to use 286954359Sroberto */ 287054359Srobertostatic u_long 287154359Srobertogetkeyid( 287254359Sroberto const char *keyprompt 287354359Sroberto ) 287454359Sroberto{ 2875285612Sdelphij int c; 287654359Sroberto FILE *fi; 287754359Sroberto char pbuf[20]; 2878285612Sdelphij size_t i; 2879285612Sdelphij size_t ilim; 288054359Sroberto 288154359Sroberto#ifndef SYS_WINNT 288254359Sroberto if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 288354359Sroberto#else 2884285612Sdelphij if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 288554359Sroberto#endif /* SYS_WINNT */ 288654359Sroberto fi = stdin; 2887285612Sdelphij else 288854359Sroberto setbuf(fi, (char *)NULL); 288954359Sroberto fprintf(stderr, "%s", keyprompt); fflush(stderr); 2890285612Sdelphij for (i = 0, ilim = COUNTOF(pbuf) - 1; 2891285612Sdelphij i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2892285612Sdelphij ) 2893285612Sdelphij pbuf[i++] = (char)c; 2894285612Sdelphij pbuf[i] = '\0'; 289554359Sroberto if (fi != stdin) 2896285612Sdelphij fclose(fi); 289754359Sroberto 289854359Sroberto return (u_long) atoi(pbuf); 289954359Sroberto} 290054359Sroberto 290154359Sroberto 290254359Sroberto/* 290354359Sroberto * atoascii - printable-ize possibly ascii data using the character 290454359Sroberto * transformations cat -v uses. 290554359Sroberto */ 290654359Srobertostatic void 290754359Srobertoatoascii( 2908285612Sdelphij const char *in, 2909285612Sdelphij size_t in_octets, 2910285612Sdelphij char *out, 2911285612Sdelphij size_t out_octets 291254359Sroberto ) 291354359Sroberto{ 2914285612Sdelphij const u_char * pchIn; 2915285612Sdelphij const u_char * pchInLimit; 2916285612Sdelphij u_char * pchOut; 2917285612Sdelphij u_char c; 291854359Sroberto 2919285612Sdelphij pchIn = (const u_char *)in; 2920285612Sdelphij pchInLimit = pchIn + in_octets; 2921285612Sdelphij pchOut = (u_char *)out; 2922285612Sdelphij 2923285612Sdelphij if (NULL == pchIn) { 2924285612Sdelphij if (0 < out_octets) 2925285612Sdelphij *pchOut = '\0'; 292654359Sroberto return; 292754359Sroberto } 292854359Sroberto 2929285612Sdelphij#define ONEOUT(c) \ 2930285612Sdelphijdo { \ 2931285612Sdelphij if (0 == --out_octets) { \ 2932285612Sdelphij *pchOut = '\0'; \ 2933285612Sdelphij return; \ 2934285612Sdelphij } \ 2935285612Sdelphij *pchOut++ = (c); \ 2936285612Sdelphij} while (0) 2937285612Sdelphij 2938285612Sdelphij for ( ; pchIn < pchInLimit; pchIn++) { 2939285612Sdelphij c = *pchIn; 2940285612Sdelphij if ('\0' == c) 2941285612Sdelphij break; 2942285612Sdelphij if (c & 0x80) { 2943285612Sdelphij ONEOUT('M'); 2944285612Sdelphij ONEOUT('-'); 2945285612Sdelphij c &= 0x7f; 294654359Sroberto } 294754359Sroberto if (c < ' ') { 2948285612Sdelphij ONEOUT('^'); 2949285612Sdelphij ONEOUT((u_char)(c + '@')); 2950285612Sdelphij } else if (0x7f == c) { 2951285612Sdelphij ONEOUT('^'); 2952285612Sdelphij ONEOUT('?'); 2953285612Sdelphij } else 2954285612Sdelphij ONEOUT(c); 295554359Sroberto } 2956285612Sdelphij ONEOUT('\0'); 2957285612Sdelphij 2958285612Sdelphij#undef ONEOUT 295954359Sroberto} 296054359Sroberto 296154359Sroberto 296254359Sroberto/* 296354359Sroberto * makeascii - print possibly ascii data using the character 296454359Sroberto * transformations that cat -v uses. 296554359Sroberto */ 2966285612Sdelphijvoid 296754359Srobertomakeascii( 2968293650Sglebius size_t length, 2969285612Sdelphij const char *data, 297054359Sroberto FILE *fp 297154359Sroberto ) 297254359Sroberto{ 2973285612Sdelphij const u_char *data_u_char; 2974285612Sdelphij const u_char *cp; 2975285612Sdelphij int c; 297654359Sroberto 2977285612Sdelphij data_u_char = (const u_char *)data; 2978285612Sdelphij 2979285612Sdelphij for (cp = data_u_char; cp < data_u_char + length; cp++) { 298054359Sroberto c = (int)*cp; 2981285612Sdelphij if (c & 0x80) { 298254359Sroberto putc('M', fp); 298354359Sroberto putc('-', fp); 2984285612Sdelphij c &= 0x7f; 298554359Sroberto } 298654359Sroberto 298754359Sroberto if (c < ' ') { 298854359Sroberto putc('^', fp); 2989285612Sdelphij putc(c + '@', fp); 2990285612Sdelphij } else if (0x7f == c) { 299154359Sroberto putc('^', fp); 299254359Sroberto putc('?', fp); 2993285612Sdelphij } else 299454359Sroberto putc(c, fp); 299554359Sroberto } 299654359Sroberto} 299754359Sroberto 299854359Sroberto 299954359Sroberto/* 300054359Sroberto * asciize - same thing as makeascii except add a newline 300154359Sroberto */ 300254359Srobertovoid 300354359Srobertoasciize( 300454359Sroberto int length, 300554359Sroberto char *data, 300654359Sroberto FILE *fp 300754359Sroberto ) 300854359Sroberto{ 300954359Sroberto makeascii(length, data, fp); 301054359Sroberto putc('\n', fp); 301154359Sroberto} 301254359Sroberto 301354359Sroberto 301454359Sroberto/* 3015285612Sdelphij * truncate string to fit clipping excess at end. 3016285612Sdelphij * "too long" -> "too l" 3017285612Sdelphij * Used for hostnames. 3018285612Sdelphij */ 3019285612Sdelphijconst char * 3020285612Sdelphijtrunc_right( 3021285612Sdelphij const char * src, 3022285612Sdelphij size_t width 3023285612Sdelphij ) 3024285612Sdelphij{ 3025285612Sdelphij size_t sl; 3026285612Sdelphij char * out; 3027285612Sdelphij 3028285612Sdelphij 3029285612Sdelphij sl = strlen(src); 3030285612Sdelphij if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 3031285612Sdelphij LIB_GETBUF(out); 3032285612Sdelphij memcpy(out, src, width); 3033285612Sdelphij out[width] = '\0'; 3034285612Sdelphij 3035285612Sdelphij return out; 3036285612Sdelphij } 3037285612Sdelphij 3038285612Sdelphij return src; 3039285612Sdelphij} 3040285612Sdelphij 3041285612Sdelphij 3042285612Sdelphij/* 3043285612Sdelphij * truncate string to fit by preserving right side and using '_' to hint 3044285612Sdelphij * "too long" -> "_long" 3045285612Sdelphij * Used for local IPv6 addresses, where low bits differentiate. 3046285612Sdelphij */ 3047285612Sdelphijconst char * 3048285612Sdelphijtrunc_left( 3049285612Sdelphij const char * src, 3050285612Sdelphij size_t width 3051285612Sdelphij ) 3052285612Sdelphij{ 3053285612Sdelphij size_t sl; 3054285612Sdelphij char * out; 3055285612Sdelphij 3056285612Sdelphij 3057285612Sdelphij sl = strlen(src); 3058285612Sdelphij if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 3059285612Sdelphij LIB_GETBUF(out); 3060285612Sdelphij out[0] = '_'; 3061285612Sdelphij memcpy(&out[1], &src[sl + 1 - width], width); 3062285612Sdelphij 3063285612Sdelphij return out; 3064285612Sdelphij } 3065285612Sdelphij 3066285612Sdelphij return src; 3067285612Sdelphij} 3068285612Sdelphij 3069285612Sdelphij 3070285612Sdelphij/* 307154359Sroberto * Some circular buffer space 307254359Sroberto */ 307354359Sroberto#define CBLEN 80 307454359Sroberto#define NUMCB 6 307554359Sroberto 307654359Srobertochar circ_buf[NUMCB][CBLEN]; 307754359Srobertoint nextcb = 0; 307854359Sroberto 3079338531Sdelphij/* -------------------------------------------------------------------- 3080338531Sdelphij * Parsing a response value list 3081338531Sdelphij * 3082338531Sdelphij * This sounds simple (and it actually is not really hard) but it has 3083338531Sdelphij * some pitfalls. 3084338531Sdelphij * 3085338531Sdelphij * Rule1: CR/LF is never embedded in an item 3086338531Sdelphij * Rule2: An item is a name, optionally followed by a value 3087338531Sdelphij * Rule3: The value is separated from the name by a '=' 3088338531Sdelphij * Rule4: Items are separated by a ',' 3089338531Sdelphij * Rule5: values can be quoted by '"', in which case they can contain 3090338531Sdelphij * arbitrary characters but *not* '"', CR and LF 3091338531Sdelphij * 3092338531Sdelphij * There are a few implementations out there that require a somewhat 3093338531Sdelphij * relaxed attitude when parsing a value list, especially since we want 3094338531Sdelphij * to copy names and values into local buffers. If these would overflow, 3095338531Sdelphij * the item should be skipped without terminating the parsing sequence. 3096338531Sdelphij * 3097338531Sdelphij * Also, for empty values, there might be a '=' after the name or not; 3098338531Sdelphij * we treat that equivalent. 3099338531Sdelphij * 3100338531Sdelphij * Parsing an item definitely breaks on a CR/LF. If an item is not 3101338531Sdelphij * followed by a comma (','), parsing stops. In the middle of a quoted 3102338531Sdelphij * character sequence CR/LF terminates the parsing finally without 3103338531Sdelphij * returning a value. 3104338531Sdelphij * 3105338531Sdelphij * White space and other noise is ignored when parsing the data buffer; 3106338531Sdelphij * only CR, LF, ',', '=' and '"' are characters with a special meaning. 3107338531Sdelphij * White space is stripped from the names and values *after* working 3108338531Sdelphij * through the buffer, before making the local copies. If whitespace 3109338531Sdelphij * stripping results in an empty name, parsing resumes. 3110338531Sdelphij */ 3111338531Sdelphij 311254359Sroberto/* 3113338531Sdelphij * nextvar parsing helpers 3114338531Sdelphij */ 3115338531Sdelphij 3116338531Sdelphij/* predicate: allowed chars inside a quoted string */ 3117338531Sdelphijstatic int/*BOOL*/ cp_qschar(int ch) 3118338531Sdelphij{ 3119338531Sdelphij return ch && (ch != '"' && ch != '\r' && ch != '\n'); 3120338531Sdelphij} 3121338531Sdelphij 3122338531Sdelphij/* predicate: allowed chars inside an unquoted string */ 3123338531Sdelphijstatic int/*BOOL*/ cp_uqchar(int ch) 3124338531Sdelphij{ 3125338531Sdelphij return ch && (ch != ',' && ch != '"' && ch != '\r' && ch != '\n'); 3126338531Sdelphij} 3127338531Sdelphij 3128338531Sdelphij/* predicate: allowed chars inside a value name */ 3129338531Sdelphijstatic int/*BOOL*/ cp_namechar(int ch) 3130338531Sdelphij{ 3131338531Sdelphij return ch && (ch != ',' && ch != '=' && ch != '\r' && ch != '\n'); 3132338531Sdelphij} 3133338531Sdelphij 3134338531Sdelphij/* predicate: characters *between* list items. We're relaxed here. */ 3135338531Sdelphijstatic int/*BOOL*/ cp_ivspace(int ch) 3136338531Sdelphij{ 3137338531Sdelphij return (ch == ',' || (ch > 0 && ch <= ' ')); 3138338531Sdelphij} 3139338531Sdelphij 3140338531Sdelphij/* get current character (or NUL when on end) */ 3141338531Sdelphijstatic inline int 3142338531Sdelphijpf_getch( 3143338531Sdelphij const char ** datap, 3144338531Sdelphij const char * endp 3145338531Sdelphij ) 3146338531Sdelphij{ 3147338531Sdelphij return (*datap != endp) 3148338531Sdelphij ? *(const unsigned char*)*datap 3149338531Sdelphij : '\0'; 3150338531Sdelphij} 3151338531Sdelphij 3152338531Sdelphij/* get next character (or NUL when on end) */ 3153338531Sdelphijstatic inline int 3154338531Sdelphijpf_nextch( 3155338531Sdelphij const char ** datap, 3156338531Sdelphij const char * endp 3157338531Sdelphij ) 3158338531Sdelphij{ 3159338531Sdelphij return (*datap != endp && ++(*datap) != endp) 3160338531Sdelphij ? *(const unsigned char*)*datap 3161338531Sdelphij : '\0'; 3162338531Sdelphij} 3163338531Sdelphij 3164338531Sdelphijstatic size_t 3165338531Sdelphijstr_strip( 3166338531Sdelphij const char ** datap, 3167338531Sdelphij size_t len 3168338531Sdelphij ) 3169338531Sdelphij{ 3170338531Sdelphij static const char empty[] = ""; 3171338531Sdelphij 3172338531Sdelphij if (*datap && len) { 3173338531Sdelphij const char * cpl = *datap; 3174338531Sdelphij const char * cpr = cpl + len; 3175338531Sdelphij 3176338531Sdelphij while (cpl != cpr && *(const unsigned char*)cpl <= ' ') 3177338531Sdelphij ++cpl; 3178338531Sdelphij while (cpl != cpr && *(const unsigned char*)(cpr - 1) <= ' ') 3179338531Sdelphij --cpr; 3180338531Sdelphij *datap = cpl; 3181338531Sdelphij len = (size_t)(cpr - cpl); 3182338531Sdelphij } else { 3183338531Sdelphij *datap = empty; 3184338531Sdelphij len = 0; 3185338531Sdelphij } 3186338531Sdelphij return len; 3187338531Sdelphij} 3188338531Sdelphij 3189338531Sdelphijstatic void 3190338531Sdelphijpf_error( 3191338531Sdelphij const char * what, 3192338531Sdelphij const char * where, 3193338531Sdelphij const char * whend 3194338531Sdelphij ) 3195338531Sdelphij{ 3196338531Sdelphij# ifndef BUILD_AS_LIB 3197338531Sdelphij 3198338531Sdelphij FILE * ofp = (debug > 0) ? stdout : stderr; 3199338531Sdelphij size_t len = (size_t)(whend - where); 3200338531Sdelphij 3201338531Sdelphij if (len > 50) /* *must* fit into an 'int'! */ 3202338531Sdelphij len = 50; 3203338531Sdelphij fprintf(ofp, "nextvar: %s: '%.*s'\n", 3204338531Sdelphij what, (int)len, where); 3205338531Sdelphij 3206338531Sdelphij# else /*defined(BUILD_AS_LIB)*/ 3207338531Sdelphij 3208338531Sdelphij UNUSED_ARG(what); 3209338531Sdelphij UNUSED_ARG(where); 3210338531Sdelphij UNUSED_ARG(whend); 3211338531Sdelphij 3212338531Sdelphij# endif /*defined(BUILD_AS_LIB)*/ 3213338531Sdelphij} 3214338531Sdelphij 3215338531Sdelphij/* 321654359Sroberto * nextvar - find the next variable in the buffer 321754359Sroberto */ 3218338531Sdelphijint/*BOOL*/ 321954359Srobertonextvar( 3220293650Sglebius size_t *datalen, 3221285612Sdelphij const char **datap, 322254359Sroberto char **vname, 322354359Sroberto char **vvalue 322454359Sroberto ) 322554359Sroberto{ 3226338531Sdelphij enum PState { sDone, sInit, sName, sValU, sValQ }; 3227338531Sdelphij 3228338531Sdelphij static char name[MAXVARLEN], value[MAXVALLEN]; 322954359Sroberto 3230338531Sdelphij const char *cp, *cpend; 3231338531Sdelphij const char *np, *vp; 3232338531Sdelphij size_t nlen, vlen; 3233338531Sdelphij int ch; 3234338531Sdelphij enum PState st; 3235338531Sdelphij 3236338531Sdelphij cpend = *datap + *datalen; 323754359Sroberto 3238338531Sdelphij again: 3239338531Sdelphij np = vp = NULL; 3240338531Sdelphij nlen = vlen = 0; 3241338531Sdelphij 3242338531Sdelphij st = sInit; 3243338531Sdelphij ch = pf_getch(datap, cpend); 3244285612Sdelphij 3245338531Sdelphij while (st != sDone) { 3246338531Sdelphij switch (st) 3247338531Sdelphij { 3248338531Sdelphij case sInit: /* handle inter-item chars */ 3249338531Sdelphij while (cp_ivspace(ch)) 3250338531Sdelphij ch = pf_nextch(datap, cpend); 3251338531Sdelphij if (cp_namechar(ch)) { 3252338531Sdelphij np = *datap; 3253338531Sdelphij cp = np; 3254338531Sdelphij st = sName; 3255338531Sdelphij ch = pf_nextch(datap, cpend); 3256338531Sdelphij } else { 3257338531Sdelphij goto final_done; 3258338531Sdelphij } 3259338531Sdelphij break; 3260338531Sdelphij 3261338531Sdelphij case sName: /* collect name */ 3262338531Sdelphij while (cp_namechar(ch)) 3263338531Sdelphij ch = pf_nextch(datap, cpend); 3264338531Sdelphij nlen = (size_t)(*datap - np); 3265338531Sdelphij if (ch == '=') { 3266338531Sdelphij ch = pf_nextch(datap, cpend); 3267338531Sdelphij vp = *datap; 3268338531Sdelphij st = sValU; 3269338531Sdelphij } else { 3270338531Sdelphij if (ch != ',') 3271338531Sdelphij *datap = cpend; 3272338531Sdelphij st = sDone; 3273338531Sdelphij } 3274338531Sdelphij break; 3275338531Sdelphij 3276338531Sdelphij case sValU: /* collect unquoted part(s) of value */ 3277338531Sdelphij while (cp_uqchar(ch)) 3278338531Sdelphij ch = pf_nextch(datap, cpend); 3279338531Sdelphij if (ch == '"') { 3280338531Sdelphij ch = pf_nextch(datap, cpend); 3281338531Sdelphij st = sValQ; 3282338531Sdelphij } else { 3283338531Sdelphij vlen = (size_t)(*datap - vp); 3284338531Sdelphij if (ch != ',') 3285338531Sdelphij *datap = cpend; 3286338531Sdelphij st = sDone; 3287338531Sdelphij } 3288338531Sdelphij break; 3289338531Sdelphij 3290338531Sdelphij case sValQ: /* collect quoted part(s) of value */ 3291338531Sdelphij while (cp_qschar(ch)) 3292338531Sdelphij ch = pf_nextch(datap, cpend); 3293338531Sdelphij if (ch == '"') { 3294338531Sdelphij ch = pf_nextch(datap, cpend); 3295338531Sdelphij st = sValU; 3296338531Sdelphij } else { 3297338531Sdelphij pf_error("no closing quote, stop", cp, cpend); 3298338531Sdelphij goto final_done; 3299338531Sdelphij } 3300338531Sdelphij break; 3301338531Sdelphij 3302338531Sdelphij default: 3303338531Sdelphij pf_error("state machine error, stop", *datap, cpend); 3304338531Sdelphij goto final_done; 3305338531Sdelphij } 330654359Sroberto } 330754359Sroberto 3308338531Sdelphij /* If name or value do not fit their buffer, croak and start 3309338531Sdelphij * over. If there's no name at all after whitespace stripping, 3310338531Sdelphij * redo silently. 331154359Sroberto */ 3312338531Sdelphij nlen = str_strip(&np, nlen); 3313338531Sdelphij vlen = str_strip(&vp, vlen); 3314338531Sdelphij 3315338531Sdelphij if (nlen == 0) { 3316338531Sdelphij goto again; 331754359Sroberto } 3318338531Sdelphij if (nlen >= sizeof(name)) { 3319338531Sdelphij pf_error("runaway name", np, cpend); 3320338531Sdelphij goto again; 3321338531Sdelphij } 3322338531Sdelphij if (vlen >= sizeof(value)) { 3323338531Sdelphij pf_error("runaway value", vp, cpend); 3324338531Sdelphij goto again; 3325338531Sdelphij } 332654359Sroberto 3327338531Sdelphij /* copy name and value into NUL-terminated buffers */ 3328338531Sdelphij memcpy(name, np, nlen); 3329338531Sdelphij name[nlen] = '\0'; 3330338531Sdelphij *vname = name; 3331338531Sdelphij 3332338531Sdelphij memcpy(value, vp, vlen); 3333338531Sdelphij value[vlen] = '\0'; 333454359Sroberto *vvalue = value; 3335338531Sdelphij 3336338531Sdelphij /* check if there's more to do or if we are finshed */ 3337338531Sdelphij *datalen = (size_t)(cpend - *datap); 3338338531Sdelphij return TRUE; 3339338531Sdelphij 3340338531Sdelphij final_done: 3341338531Sdelphij *datap = cpend; 3342338531Sdelphij *datalen = 0; 3343338531Sdelphij return FALSE; 334454359Sroberto} 334554359Sroberto 334654359Sroberto 3347285612Sdelphiju_short 3348285612Sdelphijvarfmt(const char * varname) 334954359Sroberto{ 3350285612Sdelphij u_int n; 335154359Sroberto 3352285612Sdelphij for (n = 0; n < COUNTOF(cookedvars); n++) 3353285612Sdelphij if (!strcmp(varname, cookedvars[n].varname)) 3354285612Sdelphij return cookedvars[n].fmt; 3355285612Sdelphij 3356285612Sdelphij return PADDING; 335754359Sroberto} 335854359Sroberto 335954359Sroberto 336054359Sroberto/* 336154359Sroberto * printvars - print variables returned in response packet 336254359Sroberto */ 336354359Srobertovoid 336454359Srobertoprintvars( 3365293650Sglebius size_t length, 3366285612Sdelphij const char *data, 336754359Sroberto int status, 336854359Sroberto int sttype, 3369285612Sdelphij int quiet, 337054359Sroberto FILE *fp 337154359Sroberto ) 337254359Sroberto{ 337354359Sroberto if (rawmode) 3374285612Sdelphij rawprint(sttype, length, data, status, quiet, fp); 337554359Sroberto else 3376285612Sdelphij cookedprint(sttype, length, data, status, quiet, fp); 337754359Sroberto} 337854359Sroberto 337954359Sroberto 338054359Sroberto/* 338154359Sroberto * rawprint - do a printout of the data in raw mode 338254359Sroberto */ 338354359Srobertostatic void 338454359Srobertorawprint( 338554359Sroberto int datatype, 3386293650Sglebius size_t length, 3387285612Sdelphij const char *data, 338854359Sroberto int status, 3389285612Sdelphij int quiet, 339054359Sroberto FILE *fp 339154359Sroberto ) 339254359Sroberto{ 3393285612Sdelphij const char *cp; 3394285612Sdelphij const char *cpend; 339554359Sroberto 339654359Sroberto /* 339754359Sroberto * Essentially print the data as is. We reformat unprintables, though. 339854359Sroberto */ 339954359Sroberto cp = data; 340054359Sroberto cpend = data + length; 340154359Sroberto 3402285612Sdelphij if (!quiet) 3403285612Sdelphij (void) fprintf(fp, "status=0x%04x,\n", status); 340454359Sroberto 340554359Sroberto while (cp < cpend) { 340654359Sroberto if (*cp == '\r') { 340754359Sroberto /* 340854359Sroberto * If this is a \r and the next character is a 340954359Sroberto * \n, supress this, else pretty print it. Otherwise 341054359Sroberto * just output the character. 341154359Sroberto */ 3412285612Sdelphij if (cp == (cpend - 1) || *(cp + 1) != '\n') 341354359Sroberto makeascii(1, cp, fp); 3414330141Sdelphij } else if (isspace(pgetc(cp)) || isprint(pgetc(cp))) 341554359Sroberto putc(*cp, fp); 3416285612Sdelphij else 341754359Sroberto makeascii(1, cp, fp); 341854359Sroberto cp++; 341954359Sroberto } 342054359Sroberto} 342154359Sroberto 342254359Sroberto 342354359Sroberto/* 342454359Sroberto * Global data used by the cooked output routines 342554359Sroberto */ 342654359Srobertoint out_chars; /* number of characters output */ 342754359Srobertoint out_linecount; /* number of characters output on this line */ 342854359Sroberto 342954359Sroberto 343054359Sroberto/* 343154359Sroberto * startoutput - get ready to do cooked output 343254359Sroberto */ 343354359Srobertostatic void 343454359Srobertostartoutput(void) 343554359Sroberto{ 343654359Sroberto out_chars = 0; 343754359Sroberto out_linecount = 0; 343854359Sroberto} 343954359Sroberto 344054359Sroberto 344154359Sroberto/* 344254359Sroberto * output - output a variable=value combination 344354359Sroberto */ 344454359Srobertostatic void 344554359Srobertooutput( 344654359Sroberto FILE *fp, 3447285612Sdelphij const char *name, 3448285612Sdelphij const char *value 344954359Sroberto ) 345054359Sroberto{ 3451293650Sglebius int len; 345254359Sroberto 3453285612Sdelphij /* strlen of "name=value" */ 3454293650Sglebius len = size2int_sat(strlen(name) + 1 + strlen(value)); 345554359Sroberto 345654359Sroberto if (out_chars != 0) { 3457285612Sdelphij out_chars += 2; 3458285612Sdelphij if ((out_linecount + len + 2) > MAXOUTLINE) { 3459285612Sdelphij fputs(",\n", fp); 346054359Sroberto out_linecount = 0; 346154359Sroberto } else { 3462285612Sdelphij fputs(", ", fp); 3463285612Sdelphij out_linecount += 2; 346454359Sroberto } 346554359Sroberto } 346654359Sroberto 346754359Sroberto fputs(name, fp); 346854359Sroberto putc('=', fp); 346954359Sroberto fputs(value, fp); 3470285612Sdelphij out_chars += len; 3471285612Sdelphij out_linecount += len; 347254359Sroberto} 347354359Sroberto 347454359Sroberto 347554359Sroberto/* 347654359Sroberto * endoutput - terminate a block of cooked output 347754359Sroberto */ 347854359Srobertostatic void 347954359Srobertoendoutput( 348054359Sroberto FILE *fp 348154359Sroberto ) 348254359Sroberto{ 348354359Sroberto if (out_chars != 0) 3484285612Sdelphij putc('\n', fp); 348554359Sroberto} 348654359Sroberto 348754359Sroberto 348854359Sroberto/* 348954359Sroberto * outputarr - output an array of values 349054359Sroberto */ 349154359Srobertostatic void 349254359Srobertooutputarr( 349354359Sroberto FILE *fp, 349454359Sroberto char *name, 349554359Sroberto int narr, 349654359Sroberto l_fp *lfp 349754359Sroberto ) 349854359Sroberto{ 3499293650Sglebius char *bp; 3500293650Sglebius char *cp; 3501293650Sglebius size_t i; 3502293650Sglebius size_t len; 350354359Sroberto char buf[256]; 350454359Sroberto 350554359Sroberto bp = buf; 350654359Sroberto /* 350754359Sroberto * Hack to align delay and offset values 350854359Sroberto */ 350954359Sroberto for (i = (int)strlen(name); i < 11; i++) 3510338531Sdelphij *bp++ = ' '; 3511285612Sdelphij 351254359Sroberto for (i = narr; i > 0; i--) { 3513338531Sdelphij if (i != (size_t)narr) 3514338531Sdelphij *bp++ = ' '; 351554359Sroberto cp = lfptoms(lfp, 2); 351654359Sroberto len = strlen(cp); 351754359Sroberto if (len > 7) { 351854359Sroberto cp[7] = '\0'; 351954359Sroberto len = 7; 352054359Sroberto } 352154359Sroberto while (len < 7) { 352254359Sroberto *bp++ = ' '; 352354359Sroberto len++; 352454359Sroberto } 352554359Sroberto while (*cp != '\0') 352654359Sroberto *bp++ = *cp++; 352754359Sroberto lfp++; 352854359Sroberto } 352954359Sroberto *bp = '\0'; 353054359Sroberto output(fp, name, buf); 353154359Sroberto} 353254359Sroberto 353354359Srobertostatic char * 353454359Srobertotstflags( 353554359Sroberto u_long val 353654359Sroberto ) 353754359Sroberto{ 3538338531Sdelphij# if CBLEN < 10 3539338531Sdelphij# error BLEN is too small -- increase! 3540338531Sdelphij# endif 354154359Sroberto 3542338531Sdelphij char *cp, *s; 3543338531Sdelphij size_t cb, i; 3544338531Sdelphij int l; 3545338531Sdelphij 3546285612Sdelphij s = cp = circ_buf[nextcb]; 354754359Sroberto if (++nextcb >= NUMCB) 3548285612Sdelphij nextcb = 0; 3549285612Sdelphij cb = sizeof(circ_buf[0]); 355054359Sroberto 3551338531Sdelphij l = snprintf(cp, cb, "%02lx", val); 3552338531Sdelphij if (l < 0 || (size_t)l >= cb) 3553338531Sdelphij goto fail; 3554338531Sdelphij cp += l; 3555338531Sdelphij cb -= l; 355654359Sroberto if (!val) { 3557338531Sdelphij l = strlcat(cp, " ok", cb); 3558338531Sdelphij if ((size_t)l >= cb) 3559338531Sdelphij goto fail; 3560338531Sdelphij cp += l; 3561338531Sdelphij cb -= l; 356254359Sroberto } else { 3563338531Sdelphij const char *sep; 3564338531Sdelphij 3565338531Sdelphij sep = " "; 3566338531Sdelphij for (i = 0; i < COUNTOF(tstflagnames); i++) { 356754359Sroberto if (val & 0x1) { 3568338531Sdelphij l = snprintf(cp, cb, "%s%s", sep, 3569338531Sdelphij tstflagnames[i]); 3570338531Sdelphij if (l < 0) 3571338531Sdelphij goto fail; 3572338531Sdelphij if ((size_t)l >= cb) { 3573338531Sdelphij cp += cb - 4; 3574338531Sdelphij cb = 4; 3575338531Sdelphij l = strlcpy (cp, "...", cb); 3576338531Sdelphij cp += l; 3577338531Sdelphij cb -= l; 3578338531Sdelphij break; 3579338531Sdelphij } 358054359Sroberto sep = ", "; 3581338531Sdelphij cp += l; 3582338531Sdelphij cb -= l; 358354359Sroberto } 358454359Sroberto val >>= 1; 358554359Sroberto } 358654359Sroberto } 3587285612Sdelphij 358854359Sroberto return s; 3589338531Sdelphij 3590338531Sdelphij fail: 3591338531Sdelphij *cp = '\0'; 3592338531Sdelphij return s; 359354359Sroberto} 359454359Sroberto 359554359Sroberto/* 359654359Sroberto * cookedprint - output variables in cooked mode 359754359Sroberto */ 359854359Srobertostatic void 359954359Srobertocookedprint( 360054359Sroberto int datatype, 3601293650Sglebius size_t length, 3602285612Sdelphij const char *data, 360354359Sroberto int status, 3604285612Sdelphij int quiet, 360554359Sroberto FILE *fp 360654359Sroberto ) 360754359Sroberto{ 360854359Sroberto char *name; 360954359Sroberto char *value; 3610132451Sroberto char output_raw; 361154359Sroberto int fmt; 361254359Sroberto l_fp lfp; 3613285612Sdelphij sockaddr_u hval; 361454359Sroberto u_long uval; 3615285612Sdelphij int narr; 3616285612Sdelphij size_t len; 361754359Sroberto l_fp lfparr[8]; 3618285612Sdelphij char b[12]; 3619285612Sdelphij char bn[2 * MAXVARLEN]; 3620285612Sdelphij char bv[2 * MAXVALLEN]; 362154359Sroberto 3622285612Sdelphij UNUSED_ARG(datatype); 362354359Sroberto 3624285612Sdelphij if (!quiet) 3625285612Sdelphij fprintf(fp, "status=%04x %s,\n", status, 3626285612Sdelphij statustoa(datatype, status)); 362754359Sroberto 362854359Sroberto startoutput(); 362954359Sroberto while (nextvar(&length, &data, &name, &value)) { 3630285612Sdelphij fmt = varfmt(name); 3631285612Sdelphij output_raw = 0; 3632285612Sdelphij switch (fmt) { 3633285612Sdelphij 3634285612Sdelphij case PADDING: 363554359Sroberto output_raw = '*'; 3636285612Sdelphij break; 363754359Sroberto 3638285612Sdelphij case TS: 3639330141Sdelphij if (!value || !decodets(value, &lfp)) 3640285612Sdelphij output_raw = '?'; 3641285612Sdelphij else 3642285612Sdelphij output(fp, name, prettydate(&lfp)); 3643285612Sdelphij break; 364454359Sroberto 3645285612Sdelphij case HA: /* fallthru */ 3646285612Sdelphij case NA: 3647330141Sdelphij if (!value || !decodenetnum(value, &hval)) { 3648285612Sdelphij output_raw = '?'; 3649285612Sdelphij } else if (fmt == HA){ 3650285612Sdelphij output(fp, name, nntohost(&hval)); 3651285612Sdelphij } else { 3652285612Sdelphij output(fp, name, stoa(&hval)); 3653285612Sdelphij } 3654285612Sdelphij break; 365554359Sroberto 3656285612Sdelphij case RF: 3657330141Sdelphij if (!value) { 3658330141Sdelphij output_raw = '?'; 3659330141Sdelphij } else if (decodenetnum(value, &hval)) { 3660285612Sdelphij if (ISREFCLOCKADR(&hval)) 3661285612Sdelphij output(fp, name, 3662285612Sdelphij refnumtoa(&hval)); 366354359Sroberto else 3664285612Sdelphij output(fp, name, stoa(&hval)); 3665285612Sdelphij } else if (strlen(value) <= 4) { 3666285612Sdelphij output(fp, name, value); 3667285612Sdelphij } else { 3668285612Sdelphij output_raw = '?'; 3669285612Sdelphij } 3670285612Sdelphij break; 367154359Sroberto 3672285612Sdelphij case LP: 3673330141Sdelphij if (!value || !decodeuint(value, &uval) || uval > 3) { 3674285612Sdelphij output_raw = '?'; 3675285612Sdelphij } else { 3676285612Sdelphij b[0] = (0x2 & uval) 3677285612Sdelphij ? '1' 3678285612Sdelphij : '0'; 3679285612Sdelphij b[1] = (0x1 & uval) 3680285612Sdelphij ? '1' 3681285612Sdelphij : '0'; 3682285612Sdelphij b[2] = '\0'; 3683285612Sdelphij output(fp, name, b); 368454359Sroberto } 3685285612Sdelphij break; 368654359Sroberto 3687285612Sdelphij case OC: 3688330141Sdelphij if (!value || !decodeuint(value, &uval)) { 3689285612Sdelphij output_raw = '?'; 3690285612Sdelphij } else { 3691285612Sdelphij snprintf(b, sizeof(b), "%03lo", uval); 3692285612Sdelphij output(fp, name, b); 3693285612Sdelphij } 3694285612Sdelphij break; 3695285612Sdelphij 3696285612Sdelphij case AR: 3697330141Sdelphij if (!value || !decodearr(value, &narr, lfparr, 8)) 3698285612Sdelphij output_raw = '?'; 3699285612Sdelphij else 3700285612Sdelphij outputarr(fp, name, narr, lfparr); 3701285612Sdelphij break; 3702285612Sdelphij 3703285612Sdelphij case FX: 3704330141Sdelphij if (!value || !decodeuint(value, &uval)) 3705285612Sdelphij output_raw = '?'; 3706285612Sdelphij else 3707285612Sdelphij output(fp, name, tstflags(uval)); 3708285612Sdelphij break; 3709285612Sdelphij 3710285612Sdelphij default: 3711285612Sdelphij fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3712285612Sdelphij name, value, fmt); 3713285612Sdelphij output_raw = '?'; 3714285612Sdelphij break; 371554359Sroberto } 3716285612Sdelphij 371754359Sroberto if (output_raw != 0) { 3718289997Sglebius /* TALOS-CAN-0063: avoid buffer overrun */ 3719285612Sdelphij atoascii(name, MAXVARLEN, bn, sizeof(bn)); 372054359Sroberto if (output_raw != '*') { 3721289997Sglebius atoascii(value, MAXVALLEN, 3722289997Sglebius bv, sizeof(bv) - 1); 372354359Sroberto len = strlen(bv); 372454359Sroberto bv[len] = output_raw; 372554359Sroberto bv[len+1] = '\0'; 3726289997Sglebius } else { 3727289997Sglebius atoascii(value, MAXVALLEN, 3728289997Sglebius bv, sizeof(bv)); 372954359Sroberto } 373054359Sroberto output(fp, bn, bv); 373154359Sroberto } 373254359Sroberto } 373354359Sroberto endoutput(fp); 373454359Sroberto} 373554359Sroberto 373654359Sroberto 373754359Sroberto/* 373854359Sroberto * sortassoc - sort associations in the cache into ascending order 373954359Sroberto */ 374054359Srobertovoid 374154359Srobertosortassoc(void) 374254359Sroberto{ 374354359Sroberto if (numassoc > 1) 3744285612Sdelphij qsort(assoc_cache, (size_t)numassoc, 3745285612Sdelphij sizeof(assoc_cache[0]), &assoccmp); 374654359Sroberto} 374754359Sroberto 374854359Sroberto 374954359Sroberto/* 375054359Sroberto * assoccmp - compare two associations 375154359Sroberto */ 375254359Srobertostatic int 375354359Srobertoassoccmp( 375454359Sroberto const void *t1, 375554359Sroberto const void *t2 375654359Sroberto ) 375754359Sroberto{ 3758285612Sdelphij const struct association *ass1 = t1; 3759285612Sdelphij const struct association *ass2 = t2; 376054359Sroberto 376154359Sroberto if (ass1->assid < ass2->assid) 3762285612Sdelphij return -1; 376354359Sroberto if (ass1->assid > ass2->assid) 3764285612Sdelphij return 1; 376554359Sroberto return 0; 376654359Sroberto} 3767285612Sdelphij 3768285612Sdelphij 3769285612Sdelphij/* 3770285612Sdelphij * grow_assoc_cache() - enlarge dynamic assoc_cache array 3771285612Sdelphij * 3772285612Sdelphij * The strategy is to add an assumed 4k page size at a time, leaving 3773285612Sdelphij * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3774285612Sdelphij */ 3775285612Sdelphijvoid 3776285612Sdelphijgrow_assoc_cache(void) 3777285612Sdelphij{ 3778285612Sdelphij static size_t prior_sz; 3779285612Sdelphij size_t new_sz; 3780285612Sdelphij 3781285612Sdelphij new_sz = prior_sz + 4 * 1024; 3782285612Sdelphij if (0 == prior_sz) { 3783285612Sdelphij new_sz -= 4 * sizeof(void *); 3784285612Sdelphij } 3785285612Sdelphij assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3786285612Sdelphij prior_sz = new_sz; 3787293650Sglebius assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3788285612Sdelphij} 3789285612Sdelphij 3790285612Sdelphij 3791285612Sdelphij/* 3792285612Sdelphij * ntpq_custom_opt_handler - autoopts handler for -c and -p 3793285612Sdelphij * 3794285612Sdelphij * By default, autoopts loses the relative order of -c and -p options 3795285612Sdelphij * on the command line. This routine replaces the default handler for 3796285612Sdelphij * those routines and builds a list of commands to execute preserving 3797285612Sdelphij * the order. 3798285612Sdelphij */ 3799285612Sdelphijvoid 3800285612Sdelphijntpq_custom_opt_handler( 3801285612Sdelphij tOptions *pOptions, 3802285612Sdelphij tOptDesc *pOptDesc 380354359Sroberto ) 380454359Sroberto{ 3805285612Sdelphij switch (pOptDesc->optValue) { 3806285612Sdelphij 3807285612Sdelphij default: 3808285612Sdelphij fprintf(stderr, 3809285612Sdelphij "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3810285612Sdelphij pOptDesc->optValue, pOptDesc->optValue); 3811285612Sdelphij exit(1); 3812285612Sdelphij 3813285612Sdelphij case 'c': 3814285612Sdelphij ADDCMD(pOptDesc->pzLastArg); 3815285612Sdelphij break; 3816285612Sdelphij 3817285612Sdelphij case 'p': 3818285612Sdelphij ADDCMD("peers"); 3819285612Sdelphij break; 3820285612Sdelphij } 382154359Sroberto} 3822285612Sdelphij/* 3823285612Sdelphij * Obtain list of digest names 3824285612Sdelphij */ 3825285612Sdelphij 3826330141Sdelphij#if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED) 3827330141Sdelphij# if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L 3828330141Sdelphij# define HAVE_EVP_MD_DO_ALL_SORTED 3829330141Sdelphij# endif 3830330141Sdelphij#endif 3831330141Sdelphij 3832285612Sdelphij#ifdef OPENSSL 3833285612Sdelphij# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3834330141Sdelphij# define K_PER_LINE 8 3835330141Sdelphij# define K_NL_PFX_STR "\n " 3836330141Sdelphij# define K_DELIM_STR ", " 3837330141Sdelphij 3838285612Sdelphijstruct hstate { 3839338531Sdelphij char *list; 3840338531Sdelphij const char **seen; 3841338531Sdelphij int idx; 3842285612Sdelphij}; 3843330141Sdelphij 3844330141Sdelphij 3845338531Sdelphij# ifndef BUILD_AS_LIB 3846330141Sdelphijstatic void 3847330141Sdelphijlist_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg) 3848285612Sdelphij{ 3849338531Sdelphij size_t len, n; 3850338531Sdelphij const char *name, **seen; 3851338531Sdelphij struct hstate *hstate = arg; 3852338531Sdelphij const char *cp; 3853338531Sdelphij 3854338531Sdelphij /* m is MD obj, from is name or alias, to is base name for alias */ 3855338531Sdelphij if (!m || !from || to) 3856338531Sdelphij return; /* Ignore aliases */ 3857285612Sdelphij 3858338531Sdelphij /* Discard MACs that NTP won't accept. */ 3859338531Sdelphij /* Keep this consistent with keytype_from_text() in ssl_init.c. */ 3860338531Sdelphij if (EVP_MD_size(m) > (MAX_MAC_LEN - sizeof(keyid_t))) 3861338531Sdelphij return; 3862338531Sdelphij 3863338531Sdelphij name = EVP_MD_name(m); 3864338531Sdelphij 3865338531Sdelphij /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */ 3866338531Sdelphij 3867338531Sdelphij for (cp = name; *cp; cp++) 3868338531Sdelphij if (islower((unsigned char)*cp)) 3869338531Sdelphij return; 3870285612Sdelphij 3871338531Sdelphij len = (cp - name) + 1; 3872338531Sdelphij 3873338531Sdelphij /* There are duplicates. Discard if name has been seen. */ 3874338531Sdelphij 3875338531Sdelphij for (seen = hstate->seen; *seen; seen++) 3876338531Sdelphij if (!strcmp(*seen, name)) 3877338531Sdelphij return; 3878330141Sdelphij 3879338531Sdelphij n = (seen - hstate->seen) + 2; 3880338531Sdelphij hstate->seen = erealloc(hstate->seen, n * sizeof(*seen)); 3881338531Sdelphij hstate->seen[n-2] = name; 3882338531Sdelphij hstate->seen[n-1] = NULL; 3883338531Sdelphij 3884338531Sdelphij if (hstate->list != NULL) 3885338531Sdelphij len += strlen(hstate->list); 3886285612Sdelphij 3887338531Sdelphij len += (hstate->idx >= K_PER_LINE) 3888338531Sdelphij ? strlen(K_NL_PFX_STR) 3889338531Sdelphij : strlen(K_DELIM_STR); 3890285612Sdelphij 3891338531Sdelphij if (hstate->list == NULL) { 3892338531Sdelphij hstate->list = (char *)emalloc(len); 3893338531Sdelphij hstate->list[0] = '\0'; 3894338531Sdelphij } else { 3895338531Sdelphij hstate->list = (char *)erealloc(hstate->list, len); 3896330141Sdelphij } 3897338531Sdelphij 3898338531Sdelphij sprintf(hstate->list + strlen(hstate->list), "%s%s", 3899338531Sdelphij ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR), 3900338531Sdelphij name); 3901338531Sdelphij 3902338531Sdelphij if (hstate->idx >= K_PER_LINE) 3903338531Sdelphij hstate->idx = 1; 3904338531Sdelphij else 3905338531Sdelphij hstate->idx++; 3906285612Sdelphij} 3907338531Sdelphij# endif /* !defined(BUILD_AS_LIB) */ 3908330141Sdelphij 3909338531Sdelphij# ifndef BUILD_AS_LIB 3910330141Sdelphij/* Insert CMAC into SSL digests list */ 3911330141Sdelphijstatic char * 3912330141Sdelphijinsert_cmac(char *list) 3913330141Sdelphij{ 3914338531Sdelphij#ifdef ENABLE_CMAC 3915338531Sdelphij int insert; 3916338531Sdelphij size_t len; 3917330141Sdelphij 3918330141Sdelphij 3919338531Sdelphij /* If list empty, we need to insert CMAC on new line */ 3920338531Sdelphij insert = (!list || !*list); 3921338531Sdelphij 3922330141Sdelphij if (insert) { 3923338531Sdelphij len = strlen(K_NL_PFX_STR) + strlen(CMAC); 3924330141Sdelphij list = (char *)erealloc(list, len + 1); 3925338531Sdelphij sprintf(list, "%s%s", K_NL_PFX_STR, CMAC); 3926338531Sdelphij } else { /* List not empty */ 3927338531Sdelphij /* Check if CMAC already in list - future proofing */ 3928338531Sdelphij const char *cmac_sn; 3929338531Sdelphij char *cmac_p; 3930338531Sdelphij 3931338531Sdelphij cmac_sn = OBJ_nid2sn(NID_cmac); 3932338531Sdelphij cmac_p = list; 3933338531Sdelphij insert = cmac_sn != NULL && *cmac_sn != '\0'; 3934338531Sdelphij 3935338531Sdelphij /* CMAC in list if found, followed by nul char or ',' */ 3936338531Sdelphij while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) { 3937338531Sdelphij cmac_p += strlen(cmac_sn); 3938338531Sdelphij /* Still need to insert if not nul and not ',' */ 3939338531Sdelphij insert = *cmac_p && ',' != *cmac_p; 3940338531Sdelphij } 3941338531Sdelphij 3942338531Sdelphij /* Find proper insertion point */ 3943338531Sdelphij if (insert) { 3944338531Sdelphij char *last_nl; 3945338531Sdelphij char *point; 3946338531Sdelphij char *delim; 3947338531Sdelphij int found; 3948338531Sdelphij 3949338531Sdelphij /* Default to start if list empty */ 3950338531Sdelphij found = 0; 3951338531Sdelphij delim = list; 3952338531Sdelphij len = strlen(list); 3953338531Sdelphij 3954338531Sdelphij /* While new lines */ 3955338531Sdelphij while (delim < list + len && *delim && 3956338531Sdelphij !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) { 3957338531Sdelphij point = delim + strlen(K_NL_PFX_STR); 3958338531Sdelphij 3959338531Sdelphij /* While digest names on line */ 3960338531Sdelphij while (point < list + len && *point) { 3961338531Sdelphij /* Another digest after on same or next line? */ 3962338531Sdelphij delim = strstr( point, K_DELIM_STR); 3963338531Sdelphij last_nl = strstr( point, K_NL_PFX_STR); 3964338531Sdelphij 3965338531Sdelphij /* No - end of list */ 3966338531Sdelphij if (!delim && !last_nl) { 3967338531Sdelphij delim = list + len; 3968338531Sdelphij } else 3969338531Sdelphij /* New line and no delim or before delim? */ 3970338531Sdelphij if (last_nl && (!delim || last_nl < delim)) { 3971338531Sdelphij delim = last_nl; 3972338531Sdelphij } 3973338531Sdelphij 3974338531Sdelphij /* Found insertion point where CMAC before entry? */ 3975338531Sdelphij if (strncmp(CMAC, point, delim - point) < 0) { 3976338531Sdelphij found = 1; 3977338531Sdelphij break; 3978338531Sdelphij } 3979338531Sdelphij 3980338531Sdelphij if (delim < list + len && *delim && 3981338531Sdelphij !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) { 3982338531Sdelphij point += strlen(K_DELIM_STR); 3983338531Sdelphij } else { 3984338531Sdelphij break; 3985338531Sdelphij } 3986338531Sdelphij } /* While digest names on line */ 3987338531Sdelphij } /* While new lines */ 3988338531Sdelphij 3989338531Sdelphij /* If found in list */ 3990338531Sdelphij if (found) { 3991338531Sdelphij /* insert cmac and delim */ 3992338531Sdelphij /* Space for list could move - save offset */ 3993338531Sdelphij ptrdiff_t p_offset = point - list; 3994338531Sdelphij len += strlen(CMAC) + strlen(K_DELIM_STR); 3995338531Sdelphij list = (char *)erealloc(list, len + 1); 3996338531Sdelphij point = list + p_offset; 3997338531Sdelphij /* move to handle src/dest overlap */ 3998338531Sdelphij memmove(point + strlen(CMAC) + strlen(K_DELIM_STR), 3999330141Sdelphij point, strlen(point) + 1); 4000338531Sdelphij strncpy(point, CMAC, strlen(CMAC)); 4001338531Sdelphij strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR)); 4002338531Sdelphij } else { /* End of list */ 4003338531Sdelphij /* append delim and cmac */ 4004338531Sdelphij len += strlen(K_DELIM_STR) + strlen(CMAC); 4005338531Sdelphij list = (char *)erealloc(list, len + 1); 4006338531Sdelphij strcpy(list + strlen(list), K_DELIM_STR); 4007338531Sdelphij strcpy(list + strlen(list), CMAC); 4008338531Sdelphij } 4009338531Sdelphij } /* insert */ 4010338531Sdelphij } /* List not empty */ 4011338531Sdelphij#endif /*ENABLE_CMAC*/ 4012338531Sdelphij return list; 4013330141Sdelphij} 4014338531Sdelphij# endif /* !defined(BUILD_AS_LIB) */ 4015285612Sdelphij# endif 4016285612Sdelphij#endif 4017285612Sdelphij 4018330141Sdelphij 4019338531Sdelphij#ifndef BUILD_AS_LIB 4020330141Sdelphijstatic char * 4021330141Sdelphijlist_digest_names(void) 4022285612Sdelphij{ 4023338531Sdelphij char *list = NULL; 4024338531Sdelphij 4025285612Sdelphij#ifdef OPENSSL 4026285612Sdelphij# ifdef HAVE_EVP_MD_DO_ALL_SORTED 4027338531Sdelphij struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 4028338531Sdelphij 4029338531Sdelphij /* replace calloc(1, sizeof(const char *)) */ 4030338531Sdelphij hstate.seen = (const char **)emalloc_zero(sizeof(const char *)); 4031338531Sdelphij 4032338531Sdelphij INIT_SSL(); 4033338531Sdelphij EVP_MD_do_all_sorted(list_md_fn, &hstate); 4034338531Sdelphij list = hstate.list; 4035338531Sdelphij free(hstate.seen); 4036338531Sdelphij 4037338531Sdelphij list = insert_cmac(list); /* Insert CMAC into SSL digests list */ 4038338531Sdelphij 4039285612Sdelphij# else 4040338531Sdelphij list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 4041338531Sdelphij strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 4042285612Sdelphij# endif 4043285612Sdelphij#else 4044338531Sdelphij list = (char *)emalloc(sizeof("md5")); 4045338531Sdelphij strcpy(list, "md5"); 4046285612Sdelphij#endif 4047338531Sdelphij 4048338531Sdelphij return list; 4049285612Sdelphij} 4050338531Sdelphij#endif /* !defined(BUILD_AS_LIB) */ 4051293650Sglebius 4052293650Sglebius#define CTRLC_STACK_MAX 4 4053293650Sglebiusstatic volatile size_t ctrlc_stack_len = 0; 4054293650Sglebiusstatic volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 4055293650Sglebius 4056293650Sglebius 4057293650Sglebius 4058293650Sglebiusint/*BOOL*/ 4059293650Sglebiuspush_ctrl_c_handler( 4060293650Sglebius Ctrl_C_Handler func 4061293650Sglebius ) 4062293650Sglebius{ 4063293650Sglebius size_t size = ctrlc_stack_len; 4064293650Sglebius if (func && (size < CTRLC_STACK_MAX)) { 4065293650Sglebius ctrlc_stack[size] = func; 4066293650Sglebius ctrlc_stack_len = size + 1; 4067293650Sglebius return TRUE; 4068293650Sglebius } 4069293650Sglebius return FALSE; 4070293650Sglebius} 4071293650Sglebius 4072293650Sglebiusint/*BOOL*/ 4073293650Sglebiuspop_ctrl_c_handler( 4074293650Sglebius Ctrl_C_Handler func 4075293650Sglebius ) 4076293650Sglebius{ 4077293650Sglebius size_t size = ctrlc_stack_len; 4078293650Sglebius if (size) { 4079293650Sglebius --size; 4080293650Sglebius if (func == NULL || func == ctrlc_stack[size]) { 4081293650Sglebius ctrlc_stack_len = size; 4082293650Sglebius return TRUE; 4083293650Sglebius } 4084293650Sglebius } 4085293650Sglebius return FALSE; 4086293650Sglebius} 4087293650Sglebius 4088338531Sdelphij#ifndef BUILD_AS_LIB 4089293650Sglebiusstatic void 4090293650Sglebiuson_ctrlc(void) 4091293650Sglebius{ 4092293650Sglebius size_t size = ctrlc_stack_len; 4093293650Sglebius while (size) 4094293650Sglebius if ((*ctrlc_stack[--size])()) 4095293650Sglebius break; 4096293650Sglebius} 4097338531Sdelphij#endif /* !defined(BUILD_AS_LIB) */ 4098294569Sdelphij 4099338531Sdelphij#ifndef BUILD_AS_LIB 4100294569Sdelphijstatic int 4101294569Sdelphijmy_easprintf( 4102294569Sdelphij char ** ppinto, 4103294569Sdelphij const char * fmt , 4104294569Sdelphij ... 4105294569Sdelphij ) 4106294569Sdelphij{ 4107294569Sdelphij va_list va; 4108294569Sdelphij int prc; 4109294569Sdelphij size_t len = 128; 4110294569Sdelphij char * buf = emalloc(len); 4111294569Sdelphij 4112294569Sdelphij again: 4113294569Sdelphij /* Note: we expect the memory allocation to fail long before the 4114294569Sdelphij * increment in buffer size actually overflows. 4115294569Sdelphij */ 4116294569Sdelphij buf = (buf) ? erealloc(buf, len) : emalloc(len); 4117294569Sdelphij 4118294569Sdelphij va_start(va, fmt); 4119294569Sdelphij prc = vsnprintf(buf, len, fmt, va); 4120294569Sdelphij va_end(va); 4121294569Sdelphij 4122294569Sdelphij if (prc < 0) { 4123294569Sdelphij /* might be very old vsnprintf. Or actually MSVC... */ 4124294569Sdelphij len += len >> 1; 4125294569Sdelphij goto again; 4126294569Sdelphij } 4127294569Sdelphij if ((size_t)prc >= len) { 4128294569Sdelphij /* at least we have the proper size now... */ 4129294569Sdelphij len = (size_t)prc + 1; 4130294569Sdelphij goto again; 4131294569Sdelphij } 4132294569Sdelphij if ((size_t)prc < (len - 32)) 4133294569Sdelphij buf = erealloc(buf, (size_t)prc + 1); 4134294569Sdelphij *ppinto = buf; 4135294569Sdelphij return prc; 4136294569Sdelphij} 4137338531Sdelphij#endif /* !defined(BUILD_AS_LIB) */ 4138