1*eabc0478Schristos /* $NetBSD: ntpq.c,v 1.23 2024/08/18 20:47:19 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntpq - query an NTP server using mode 6 commands 5abb0f93cSkardel */ 62950cc38Schristos #include <config.h> 7abb0f93cSkardel #include <ctype.h> 8abb0f93cSkardel #include <signal.h> 9abb0f93cSkardel #include <setjmp.h> 104eea345dSchristos #include <stddef.h> 114eea345dSchristos #include <stdio.h> 12abb0f93cSkardel #include <sys/types.h> 13abb0f93cSkardel #include <sys/time.h> 142950cc38Schristos #ifdef HAVE_UNISTD_H 152950cc38Schristos # include <unistd.h> 162950cc38Schristos #endif 172950cc38Schristos #ifdef HAVE_FCNTL_H 182950cc38Schristos # include <fcntl.h> 192950cc38Schristos #endif 202950cc38Schristos #ifdef SYS_WINNT 212950cc38Schristos # include <mswsock.h> 22*eabc0478Schristos # define PATH_DEVNULL "NUL:" 23*eabc0478Schristos #else 24*eabc0478Schristos # define PATH_DEVNULL "/dev/null" 252950cc38Schristos #endif 262950cc38Schristos #include <isc/net.h> 272950cc38Schristos #include <isc/result.h> 28abb0f93cSkardel 29abb0f93cSkardel #include "ntpq.h" 30abb0f93cSkardel #include "ntp_unixtime.h" 31abb0f93cSkardel #include "ntp_calendar.h" 32abb0f93cSkardel #include "ntp_select.h" 33abb0f93cSkardel #include "ntp_lineedit.h" 34abb0f93cSkardel #include "ntp_debug.h" 352950cc38Schristos #ifdef OPENSSL 362950cc38Schristos # include "openssl/evp.h" 372950cc38Schristos # include "openssl/objects.h" 385d681e99Schristos # include "openssl/err.h" 394eea345dSchristos # ifdef SYS_WINNT 404eea345dSchristos # include "openssl/opensslv.h" 414eea345dSchristos # if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L 424eea345dSchristos # define HAVE_EVP_MD_DO_ALL_SORTED 1 434eea345dSchristos # endif 444eea345dSchristos # endif 4503cfe0ffSchristos # include "libssl_compat.h" 4679045f13Schristos # ifdef HAVE_OPENSSL_CMAC_H 4779045f13Schristos # include <openssl/cmac.h> 484eea345dSchristos # define CMAC "AES128CMAC" 492950cc38Schristos # endif 5079045f13Schristos #endif 51abb0f93cSkardel #include <ssl_applink.c> 52abb0f93cSkardel 533123f114Skardel #include "ntp_libopts.h" 548b8da087Schristos #include "safecast.h" 55abb0f93cSkardel 562950cc38Schristos #ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 57abb0f93cSkardel # define open(name, flags) open(name, flags, 0777) 58abb0f93cSkardel # define SERVER_PORT_NUM 123 59abb0f93cSkardel #endif 60abb0f93cSkardel 61abb0f93cSkardel /* we use COMMAND as an autogen keyword */ 62abb0f93cSkardel #ifdef COMMAND 63abb0f93cSkardel # undef COMMAND 64abb0f93cSkardel #endif 65abb0f93cSkardel 66abb0f93cSkardel /* 67abb0f93cSkardel * Because we potentially understand a lot of commands we will run 68abb0f93cSkardel * interactive if connected to a terminal. 69abb0f93cSkardel */ 70abb0f93cSkardel int interactive = 0; /* set to 1 when we should prompt */ 71abb0f93cSkardel const char *prompt = "ntpq> "; /* prompt to ask him about */ 72abb0f93cSkardel 73abb0f93cSkardel /* 74abb0f93cSkardel * use old readvars behavior? --old-rv processing in ntpq resets 75abb0f93cSkardel * this value based on the presence or absence of --old-rv. It is 76abb0f93cSkardel * initialized to 1 here to maintain backward compatibility with 77abb0f93cSkardel * libntpq clients such as ntpsnmpd, which are free to reset it as 78abb0f93cSkardel * desired. 79abb0f93cSkardel */ 80abb0f93cSkardel int old_rv = 1; 81abb0f93cSkardel 8268dbbb44Schristos /* 8368dbbb44Schristos * How should we display the refid? 8468dbbb44Schristos * REFID_HASH, REFID_IPV4 8568dbbb44Schristos */ 8668dbbb44Schristos te_Refid drefid = -1; 87abb0f93cSkardel 88abb0f93cSkardel /* 89abb0f93cSkardel * for get_systime() 90abb0f93cSkardel */ 91abb0f93cSkardel s_char sys_precision; /* local clock precision (log2 s) */ 92abb0f93cSkardel 93abb0f93cSkardel /* 94abb0f93cSkardel * Keyid used for authenticated requests. Obtained on the fly. 95abb0f93cSkardel */ 96abb0f93cSkardel u_long info_auth_keyid = 0; 97abb0f93cSkardel 98abb0f93cSkardel static int info_auth_keytype = NID_md5; /* MD5 */ 99abb0f93cSkardel static size_t info_auth_hashlen = 16; /* MD5 */ 100abb0f93cSkardel u_long current_time; /* needed by authkeys; not used */ 101abb0f93cSkardel 102abb0f93cSkardel /* 103abb0f93cSkardel * Flag which indicates we should always send authenticated requests 104abb0f93cSkardel */ 105abb0f93cSkardel int always_auth = 0; 106abb0f93cSkardel 107abb0f93cSkardel /* 108abb0f93cSkardel * Flag which indicates raw mode output. 109abb0f93cSkardel */ 110abb0f93cSkardel int rawmode = 0; 111abb0f93cSkardel 112abb0f93cSkardel /* 113abb0f93cSkardel * Packet version number we use 114abb0f93cSkardel */ 115abb0f93cSkardel u_char pktversion = NTP_OLDVERSION + 1; 116abb0f93cSkardel 117abb0f93cSkardel 118abb0f93cSkardel /* 119abb0f93cSkardel * Format values 120abb0f93cSkardel */ 121abb0f93cSkardel #define PADDING 0 1222950cc38Schristos #define HA 1 /* host address */ 1232950cc38Schristos #define NA 2 /* network address */ 1242950cc38Schristos #define LP 3 /* leap (print in binary) */ 1252950cc38Schristos #define RF 4 /* refid (sometimes string, sometimes not) */ 126cdfa2a7eSchristos #define AU 5 /* array of unsigned times */ 1272950cc38Schristos #define FX 6 /* test flags */ 1282950cc38Schristos #define TS 7 /* l_fp timestamp in hex */ 1292950cc38Schristos #define OC 8 /* integer, print in octal */ 130cdfa2a7eSchristos #define AS 9 /* array of signed times */ 131cdfa2a7eSchristos #define SN 10 /* signed number: must display +/- sign */ 132abb0f93cSkardel #define EOV 255 /* end of table */ 133abb0f93cSkardel 134abb0f93cSkardel /* 1352950cc38Schristos * For the most part ntpq simply displays what ntpd provides in the 1362950cc38Schristos * mostly plain-text mode 6 responses. A few variable names are by 1372950cc38Schristos * default "cooked" to provide more human-friendly output. 138abb0f93cSkardel */ 1392950cc38Schristos const var_format cookedvars[] = { 1402950cc38Schristos { "leap", LP }, 1412950cc38Schristos { "reach", OC }, 1422950cc38Schristos { "refid", RF }, 1432950cc38Schristos { "reftime", TS }, 1442950cc38Schristos { "clock", TS }, 1452950cc38Schristos { "org", TS }, 1462950cc38Schristos { "rec", TS }, 1472950cc38Schristos { "xmt", TS }, 1482950cc38Schristos { "flash", FX }, 1492950cc38Schristos { "srcadr", HA }, 1502950cc38Schristos { "peeradr", HA }, /* compat with others */ 1512950cc38Schristos { "dstadr", NA }, 152cdfa2a7eSchristos { "filtdelay", AU }, 153cdfa2a7eSchristos { "filtoffset", AS }, 154cdfa2a7eSchristos { "filtdisp", AU }, 155cdfa2a7eSchristos { "filterror", AU }, /* compat with others */ 156cdfa2a7eSchristos { "offset", SN }, 157cdfa2a7eSchristos { "frequency", SN } 158abb0f93cSkardel }; 159abb0f93cSkardel 160abb0f93cSkardel 161abb0f93cSkardel 162abb0f93cSkardel /* 163abb0f93cSkardel * flasher bits 164abb0f93cSkardel */ 165abb0f93cSkardel static const char *tstflagnames[] = { 166abb0f93cSkardel "pkt_dup", /* TEST1 */ 167abb0f93cSkardel "pkt_bogus", /* TEST2 */ 168abb0f93cSkardel "pkt_unsync", /* TEST3 */ 169abb0f93cSkardel "pkt_denied", /* TEST4 */ 170abb0f93cSkardel "pkt_auth", /* TEST5 */ 171abb0f93cSkardel "pkt_stratum", /* TEST6 */ 172abb0f93cSkardel "pkt_header", /* TEST7 */ 173abb0f93cSkardel "pkt_autokey", /* TEST8 */ 174abb0f93cSkardel "pkt_crypto", /* TEST9 */ 175abb0f93cSkardel "peer_stratum", /* TEST10 */ 176abb0f93cSkardel "peer_dist", /* TEST11 */ 177abb0f93cSkardel "peer_loop", /* TEST12 */ 178abb0f93cSkardel "peer_unreach" /* TEST13 */ 179abb0f93cSkardel }; 180abb0f93cSkardel 181abb0f93cSkardel 182abb0f93cSkardel int ntpqmain (int, char **); 183abb0f93cSkardel /* 184abb0f93cSkardel * Built in command handler declarations 185abb0f93cSkardel */ 1862950cc38Schristos static int openhost (const char *, int); 1872950cc38Schristos static void dump_hex_printable(const void *, size_t); 188abb0f93cSkardel static int sendpkt (void *, size_t); 1898b8da087Schristos static int getresponse (int, int, u_short *, size_t *, const char **, int); 1908b8da087Schristos static int sendrequest (int, associd_t, int, size_t, const char *); 191abb0f93cSkardel static char * tstflags (u_long); 192abb0f93cSkardel #ifndef BUILD_AS_LIB 193abb0f93cSkardel static void getcmds (void); 194abb0f93cSkardel #ifndef SYS_WINNT 1958b8da087Schristos static int abortcmd (void); 196abb0f93cSkardel #endif /* SYS_WINNT */ 197abb0f93cSkardel static void docmd (const char *); 198abb0f93cSkardel static void tokenize (const char *, char **, int *); 1992950cc38Schristos static int getarg (const char *, int, arg_v *); 200abb0f93cSkardel #endif /* BUILD_AS_LIB */ 2012950cc38Schristos static int findcmd (const char *, struct xcmd *, 2022950cc38Schristos struct xcmd *, struct xcmd **); 203abb0f93cSkardel static int rtdatetolfp (char *, l_fp *); 2044eea345dSchristos static int decodearr (char *, int *, l_fp *, int); 205abb0f93cSkardel static void help (struct parse *, FILE *); 206abb0f93cSkardel static int helpsort (const void *, const void *); 207abb0f93cSkardel static void printusage (struct xcmd *, FILE *); 208abb0f93cSkardel static void timeout (struct parse *, FILE *); 209abb0f93cSkardel static void auth_delay (struct parse *, FILE *); 210abb0f93cSkardel static void host (struct parse *, FILE *); 211abb0f93cSkardel static void ntp_poll (struct parse *, FILE *); 212abb0f93cSkardel static void keyid (struct parse *, FILE *); 213abb0f93cSkardel static void keytype (struct parse *, FILE *); 214abb0f93cSkardel static void passwd (struct parse *, FILE *); 215abb0f93cSkardel static void hostnames (struct parse *, FILE *); 216abb0f93cSkardel static void setdebug (struct parse *, FILE *); 217abb0f93cSkardel static void quit (struct parse *, FILE *); 21868dbbb44Schristos static void showdrefid (struct parse *, FILE *); 219abb0f93cSkardel static void version (struct parse *, FILE *); 220abb0f93cSkardel static void raw (struct parse *, FILE *); 221abb0f93cSkardel static void cooked (struct parse *, FILE *); 222abb0f93cSkardel static void authenticate (struct parse *, FILE *); 223abb0f93cSkardel static void ntpversion (struct parse *, FILE *); 22479045f13Schristos static void warning (const char *, ...) NTP_PRINTF(1, 2); 22579045f13Schristos static void error (const char *, ...) NTP_PRINTF(1, 2); 226abb0f93cSkardel static u_long getkeyid (const char *); 227abb0f93cSkardel static void atoascii (const char *, size_t, char *, size_t); 2288b8da087Schristos static void cookedprint (int, size_t, const char *, int, int, FILE *); 2298b8da087Schristos static void rawprint (int, size_t, const char *, int, int, FILE *); 230abb0f93cSkardel static void startoutput (void); 2312950cc38Schristos static void output (FILE *, const char *, const char *); 232abb0f93cSkardel static void endoutput (FILE *); 233cdfa2a7eSchristos static void outputarr (FILE *, char *, int, l_fp *, int); 234abb0f93cSkardel static int assoccmp (const void *, const void *); 2352950cc38Schristos u_short varfmt (const char *); 236abb0f93cSkardel void ntpq_custom_opt_handler(tOptions *, tOptDesc *); 237abb0f93cSkardel 23879045f13Schristos #ifndef BUILD_AS_LIB 23979045f13Schristos static char *list_digest_names(void); 24079045f13Schristos static void on_ctrlc (void); 24179045f13Schristos static int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 242*eabc0478Schristos #ifdef OPENSSL 243*eabc0478Schristos static char *insert_cmac (char *list); 244*eabc0478Schristos # ifdef HAVE_EVP_MD_DO_ALL_SORTED 24579045f13Schristos static void list_md_fn (const EVP_MD *m, const char *from, 24679045f13Schristos const char *to, void *arg); 247*eabc0478Schristos # endif /* HAVE_EVP_MD_DO_ALL_SORTED */ 248*eabc0478Schristos #endif /* OPENSSL */ 24979045f13Schristos #endif /* !defined(BUILD_AS_LIB) */ 25079045f13Schristos 25179045f13Schristos 2524eea345dSchristos /* read a character from memory and expand to integer */ 2534eea345dSchristos static inline int 2544eea345dSchristos pgetc( 2554eea345dSchristos const char *cp 2564eea345dSchristos ) 2574eea345dSchristos { 2584eea345dSchristos return (int)*(const unsigned char*)cp; 2594eea345dSchristos } 2604eea345dSchristos 2614eea345dSchristos 262abb0f93cSkardel 263abb0f93cSkardel /* 264abb0f93cSkardel * Built-in commands we understand 265abb0f93cSkardel */ 266abb0f93cSkardel struct xcmd builtins[] = { 267abb0f93cSkardel { "?", help, { OPT|NTP_STR, NO, NO, NO }, 268abb0f93cSkardel { "command", "", "", "" }, 269abb0f93cSkardel "tell the use and syntax of commands" }, 270abb0f93cSkardel { "help", help, { OPT|NTP_STR, NO, NO, NO }, 271abb0f93cSkardel { "command", "", "", "" }, 272abb0f93cSkardel "tell the use and syntax of commands" }, 273abb0f93cSkardel { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 274abb0f93cSkardel { "msec", "", "", "" }, 275abb0f93cSkardel "set the primary receive time out" }, 276abb0f93cSkardel { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 277abb0f93cSkardel { "msec", "", "", "" }, 278abb0f93cSkardel "set the delay added to encryption time stamps" }, 279abb0f93cSkardel { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 280abb0f93cSkardel { "-4|-6", "hostname", "", "" }, 281abb0f93cSkardel "specify the host whose NTP server we talk to" }, 282abb0f93cSkardel { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 283abb0f93cSkardel { "n", "verbose", "", "" }, 284abb0f93cSkardel "poll an NTP server in client mode `n' times" }, 2852950cc38Schristos { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 286abb0f93cSkardel { "", "", "", "" }, 287abb0f93cSkardel "specify a password to use for authenticated requests"}, 288abb0f93cSkardel { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 289abb0f93cSkardel { "yes|no", "", "", "" }, 290abb0f93cSkardel "specify whether hostnames or net numbers are printed"}, 291abb0f93cSkardel { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 292abb0f93cSkardel { "no|more|less", "", "", "" }, 293abb0f93cSkardel "set/change debugging level" }, 294abb0f93cSkardel { "quit", quit, { NO, NO, NO, NO }, 295abb0f93cSkardel { "", "", "", "" }, 296abb0f93cSkardel "exit ntpq" }, 297abb0f93cSkardel { "exit", quit, { NO, NO, NO, NO }, 298abb0f93cSkardel { "", "", "", "" }, 299abb0f93cSkardel "exit ntpq" }, 300abb0f93cSkardel { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 301abb0f93cSkardel { "key#", "", "", "" }, 302abb0f93cSkardel "set keyid to use for authenticated requests" }, 30368dbbb44Schristos { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 30468dbbb44Schristos { "hash|ipv4", "", "", "" }, 30568dbbb44Schristos "display refid's as IPv4 or hash" }, 306abb0f93cSkardel { "version", version, { NO, NO, NO, NO }, 307abb0f93cSkardel { "", "", "", "" }, 308abb0f93cSkardel "print version number" }, 309abb0f93cSkardel { "raw", raw, { NO, NO, NO, NO }, 310abb0f93cSkardel { "", "", "", "" }, 311abb0f93cSkardel "do raw mode variable output" }, 312abb0f93cSkardel { "cooked", cooked, { NO, NO, NO, NO }, 313abb0f93cSkardel { "", "", "", "" }, 314abb0f93cSkardel "do cooked mode variable output" }, 315abb0f93cSkardel { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 316abb0f93cSkardel { "yes|no", "", "", "" }, 317abb0f93cSkardel "always authenticate requests to this server" }, 318abb0f93cSkardel { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 319abb0f93cSkardel { "version number", "", "", "" }, 320abb0f93cSkardel "set the NTP version number to use for requests" }, 321abb0f93cSkardel { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 3225d681e99Schristos { "key type %s", "", "", "" }, 3235d681e99Schristos NULL }, 324abb0f93cSkardel { 0, 0, { NO, NO, NO, NO }, 325abb0f93cSkardel { "", "", "", "" }, "" } 326abb0f93cSkardel }; 327abb0f93cSkardel 328abb0f93cSkardel 329abb0f93cSkardel /* 330abb0f93cSkardel * Default values we use. 331abb0f93cSkardel */ 332abb0f93cSkardel #define DEFHOST "localhost" /* default host name */ 3332950cc38Schristos #define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 3342950cc38Schristos #define DEFSTIMEOUT 3 /* and 3 more for each additional */ 3352950cc38Schristos /* 3362950cc38Schristos * Requests are automatically retried once, so total timeout with no 3372950cc38Schristos * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 3382950cc38Schristos * extreme, a request eliciting 32 packets of responses each for some 3392950cc38Schristos * reason nearly DEFSTIMEOUT seconds after the prior in that series, 3402950cc38Schristos * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 3412950cc38Schristos * 93 seconds to fail each of two times, or 186 seconds. 3422950cc38Schristos * Some commands involve a series of requests, such as "peers" and 3432950cc38Schristos * "mrulist", so the cumulative timeouts are even longer for those. 3442950cc38Schristos */ 345abb0f93cSkardel #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 346abb0f93cSkardel #define LENHOSTNAME 256 /* host name is 256 characters long */ 347abb0f93cSkardel #define MAXCMDS 100 /* maximum commands on cmd line */ 348abb0f93cSkardel #define MAXHOSTS 200 /* maximum hosts on cmd line */ 349abb0f93cSkardel #define MAXLINE 512 /* maximum line length */ 350abb0f93cSkardel #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 351abb0f93cSkardel #define MAXVARLEN 256 /* maximum length of a variable name */ 3522950cc38Schristos #define MAXVALLEN 2048 /* maximum length of a variable value */ 353abb0f93cSkardel #define MAXOUTLINE 72 /* maximum length of an output line */ 354abb0f93cSkardel #define SCREENWIDTH 76 /* nominal screen width in columns */ 355abb0f93cSkardel 356abb0f93cSkardel /* 357abb0f93cSkardel * Some variables used and manipulated locally 358abb0f93cSkardel */ 359abb0f93cSkardel struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 360abb0f93cSkardel struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 361abb0f93cSkardel l_fp delay_time; /* delay time */ 362abb0f93cSkardel char currenthost[LENHOSTNAME]; /* current host name */ 3633123f114Skardel int currenthostisnum; /* is prior text from IP? */ 364a2545411Skardel struct sockaddr_in hostaddr; /* host address */ 365abb0f93cSkardel int showhostnames = 1; /* show host names by default */ 366ea66d795Schristos int wideremote = 0; /* show wide remote names? */ 367abb0f93cSkardel 368abb0f93cSkardel int ai_fam_templ; /* address family */ 369abb0f93cSkardel int ai_fam_default; /* default address family */ 370abb0f93cSkardel SOCKET sockfd; /* fd socket is opened on */ 371abb0f93cSkardel int havehost = 0; /* set to 1 when host open */ 372abb0f93cSkardel int s_port = 0; 373abb0f93cSkardel struct servent *server_entry = NULL; /* server entry for ntp */ 374abb0f93cSkardel 375abb0f93cSkardel 376abb0f93cSkardel /* 377abb0f93cSkardel * Sequence number used for requests. It is incremented before 378abb0f93cSkardel * it is used. 379abb0f93cSkardel */ 380abb0f93cSkardel u_short sequence; 381abb0f93cSkardel 382abb0f93cSkardel /* 383abb0f93cSkardel * Holds data returned from queries. Declare buffer long to be sure of 384abb0f93cSkardel * alignment. 385abb0f93cSkardel */ 386abb0f93cSkardel #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 387abb0f93cSkardel long pktdata[DATASIZE/sizeof(long)]; 388abb0f93cSkardel 389abb0f93cSkardel /* 3902950cc38Schristos * assoc_cache[] is a dynamic array which allows references to 3912950cc38Schristos * associations using &1 ... &N for n associations, avoiding manual 3922950cc38Schristos * lookup of the current association IDs for a given ntpd. It also 3932950cc38Schristos * caches the status word for each association, retrieved incidentally. 394abb0f93cSkardel */ 3952950cc38Schristos struct association * assoc_cache; 3962950cc38Schristos u_int assoc_cache_slots;/* count of allocated array entries */ 3972950cc38Schristos u_int numassoc; /* number of cached associations */ 398abb0f93cSkardel 399abb0f93cSkardel /* 400abb0f93cSkardel * For commands typed on the command line (with the -c option) 401abb0f93cSkardel */ 4025d681e99Schristos size_t numcmds = 0; 403*eabc0478Schristos size_t defcmds = 0; /* Options on the command line are 'defined'! */ 404*eabc0478Schristos char *ccmds[MAXCMDS]; 405*eabc0478Schristos #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = estrdup(cp) 406abb0f93cSkardel 407abb0f93cSkardel /* 408abb0f93cSkardel * When multiple hosts are specified. 409abb0f93cSkardel */ 410abb0f93cSkardel 4112950cc38Schristos u_int numhosts; 4122950cc38Schristos 4132950cc38Schristos chost chosts[MAXHOSTS]; 4142950cc38Schristos #define ADDHOST(cp) \ 4152950cc38Schristos do { \ 4162950cc38Schristos if (numhosts < MAXHOSTS) { \ 4172950cc38Schristos chosts[numhosts].name = (cp); \ 4182950cc38Schristos chosts[numhosts].fam = ai_fam_templ; \ 4192950cc38Schristos numhosts++; \ 4202950cc38Schristos } \ 4212950cc38Schristos } while (0) 422abb0f93cSkardel 423abb0f93cSkardel /* 424abb0f93cSkardel * Macro definitions we use 425abb0f93cSkardel */ 426abb0f93cSkardel #define ISSPACE(c) ((c) == ' ' || (c) == '\t') 427abb0f93cSkardel #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 428abb0f93cSkardel #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 429abb0f93cSkardel 430abb0f93cSkardel /* 43179045f13Schristos * Jump buffer for longjumping back to the command level. 43279045f13Schristos * 43379045f13Schristos * Since we do this from a signal handler, we use 'sig{set,long}jmp()' 43479045f13Schristos * if available. The signal is blocked by default during the excution of 43579045f13Schristos * a signal handler, and it is unspecified if '{set,long}jmp()' save and 43679045f13Schristos * restore the signal mask. They do on BSD, it depends on the GLIBC 43779045f13Schristos * version on Linux, and the gods know what happens on other OSes... 43879045f13Schristos * 43979045f13Schristos * So we use the 'sig{set,long}jmp()' functions where available, because 44079045f13Schristos * for them the semantics are well-defined. If we have to fall back to 44179045f13Schristos * '{set,long}jmp()', the CTRL-C handling might be a bit erratic. 442abb0f93cSkardel */ 44379045f13Schristos #if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP 44479045f13Schristos # define JMP_BUF sigjmp_buf 44579045f13Schristos # define SETJMP(x) sigsetjmp((x), 1) 44679045f13Schristos # define LONGJMP(x, v) siglongjmp((x),(v)) 44779045f13Schristos #else 44879045f13Schristos # define JMP_BUF jmp_buf 44979045f13Schristos # define SETJMP(x) setjmp((x)) 45079045f13Schristos # define LONGJMP(x, v) longjmp((x),(v)) 45179045f13Schristos #endif 452*eabc0478Schristos 453*eabc0478Schristos #ifndef BUILD_AS_LIB 45479045f13Schristos static JMP_BUF interrupt_buf; 45579045f13Schristos static volatile int jump = 0; 456*eabc0478Schristos #endif 457abb0f93cSkardel 458abb0f93cSkardel /* 459abb0f93cSkardel * Points at file being currently printed into 460abb0f93cSkardel */ 46179045f13Schristos FILE *current_output = NULL; 462abb0f93cSkardel 463abb0f93cSkardel /* 464abb0f93cSkardel * Command table imported from ntpdc_ops.c 465abb0f93cSkardel */ 466abb0f93cSkardel extern struct xcmd opcmds[]; 467abb0f93cSkardel 468af12ab5eSchristos char const *progname; 469abb0f93cSkardel 470abb0f93cSkardel #ifdef NO_MAIN_ALLOWED 471abb0f93cSkardel #ifndef BUILD_AS_LIB 472abb0f93cSkardel CALL(ntpq,"ntpq",ntpqmain); 473abb0f93cSkardel 474abb0f93cSkardel void clear_globals(void) 475abb0f93cSkardel { 476abb0f93cSkardel extern int ntp_optind; 477abb0f93cSkardel showhostnames = 0; /* don'tshow host names by default */ 478abb0f93cSkardel ntp_optind = 0; 479abb0f93cSkardel server_entry = NULL; /* server entry for ntp */ 480abb0f93cSkardel havehost = 0; /* set to 1 when host open */ 481abb0f93cSkardel numassoc = 0; /* number of cached associations */ 482abb0f93cSkardel numcmds = 0; 483abb0f93cSkardel numhosts = 0; 484abb0f93cSkardel } 485abb0f93cSkardel #endif /* !BUILD_AS_LIB */ 486abb0f93cSkardel #endif /* NO_MAIN_ALLOWED */ 487abb0f93cSkardel 488abb0f93cSkardel /* 489abb0f93cSkardel * main - parse arguments and handle options 490abb0f93cSkardel */ 491abb0f93cSkardel #ifndef NO_MAIN_ALLOWED 492abb0f93cSkardel int 493abb0f93cSkardel main( 494abb0f93cSkardel int argc, 495abb0f93cSkardel char *argv[] 496abb0f93cSkardel ) 497abb0f93cSkardel { 498abb0f93cSkardel return ntpqmain(argc, argv); 499abb0f93cSkardel } 500abb0f93cSkardel #endif 501abb0f93cSkardel 5024eea345dSchristos 503abb0f93cSkardel #ifndef BUILD_AS_LIB 504abb0f93cSkardel int 505abb0f93cSkardel ntpqmain( 506abb0f93cSkardel int argc, 507abb0f93cSkardel char *argv[] 508abb0f93cSkardel ) 509abb0f93cSkardel { 5102950cc38Schristos u_int ihost; 5115d681e99Schristos size_t icmd; 5122950cc38Schristos 513abb0f93cSkardel 514abb0f93cSkardel #ifdef SYS_VXWORKS 515abb0f93cSkardel clear_globals(); 516abb0f93cSkardel taskPrioritySet(taskIdSelf(), 100 ); 517abb0f93cSkardel #endif 518abb0f93cSkardel 519abb0f93cSkardel delay_time.l_ui = 0; 520abb0f93cSkardel delay_time.l_uf = DEFDELAY; 521abb0f93cSkardel 522abb0f93cSkardel init_lib(); /* sets up ipv4_works, ipv6_works */ 523abb0f93cSkardel ssl_applink(); 5242950cc38Schristos init_auth(); 525abb0f93cSkardel 526abb0f93cSkardel /* Check to see if we have IPv6. Otherwise default to IPv4 */ 527abb0f93cSkardel if (!ipv6_works) 528abb0f93cSkardel ai_fam_default = AF_INET; 529abb0f93cSkardel 5305d681e99Schristos /* Fixup keytype's help based on available digest names */ 5315d681e99Schristos 5325d681e99Schristos { 5335d681e99Schristos char *list; 5345d681e99Schristos char *msg; 5355d681e99Schristos 5365d681e99Schristos list = list_digest_names(); 5374eea345dSchristos 5384eea345dSchristos for (icmd = 0; icmd < sizeof(builtins)/sizeof(*builtins); icmd++) { 5394eea345dSchristos if (strcmp("keytype", builtins[icmd].keyword) == 0) { 5405d681e99Schristos break; 5415d681e99Schristos } 5424eea345dSchristos } 5435d681e99Schristos 5445d681e99Schristos /* CID: 1295478 */ 5455d681e99Schristos /* This should only "trip" if "keytype" is removed from builtins */ 5464eea345dSchristos INSIST(icmd < sizeof(builtins)/sizeof(*builtins)); 5475d681e99Schristos 5485d681e99Schristos #ifdef OPENSSL 5495d681e99Schristos builtins[icmd].desc[0] = "digest-name"; 55068dbbb44Schristos my_easprintf(&msg, 55168dbbb44Schristos "set key type to use for authenticated requests, one of:%s", 55268dbbb44Schristos list); 5535d681e99Schristos #else 5545d681e99Schristos builtins[icmd].desc[0] = "md5"; 55568dbbb44Schristos my_easprintf(&msg, 55668dbbb44Schristos "set key type to use for authenticated requests (%s)", 5575d681e99Schristos list); 55868dbbb44Schristos #endif 5595d681e99Schristos builtins[icmd].comment = msg; 5605d681e99Schristos free(list); 5615d681e99Schristos } 5625d681e99Schristos 563abb0f93cSkardel progname = argv[0]; 564abb0f93cSkardel 565abb0f93cSkardel { 5663123f114Skardel int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 567abb0f93cSkardel argc -= optct; 568abb0f93cSkardel argv += optct; 569abb0f93cSkardel } 570abb0f93cSkardel 571abb0f93cSkardel /* 572abb0f93cSkardel * Process options other than -c and -p, which are specially 573abb0f93cSkardel * handled by ntpq_custom_opt_handler(). 574abb0f93cSkardel */ 575abb0f93cSkardel 5762950cc38Schristos debug = OPT_VALUE_SET_DEBUG_LEVEL; 577abb0f93cSkardel 578abb0f93cSkardel if (HAVE_OPT(IPV4)) 579abb0f93cSkardel ai_fam_templ = AF_INET; 580abb0f93cSkardel else if (HAVE_OPT(IPV6)) 581abb0f93cSkardel ai_fam_templ = AF_INET6; 582abb0f93cSkardel else 583abb0f93cSkardel ai_fam_templ = ai_fam_default; 584abb0f93cSkardel 585abb0f93cSkardel if (HAVE_OPT(INTERACTIVE)) 586abb0f93cSkardel interactive = 1; 587abb0f93cSkardel 588abb0f93cSkardel if (HAVE_OPT(NUMERIC)) 589abb0f93cSkardel showhostnames = 0; 590abb0f93cSkardel 591ea66d795Schristos if (HAVE_OPT(WIDE)) 592ea66d795Schristos wideremote = 1; 593ea66d795Schristos 594abb0f93cSkardel old_rv = HAVE_OPT(OLD_RV); 595abb0f93cSkardel 59668dbbb44Schristos drefid = OPT_VALUE_REFID; 59768dbbb44Schristos 5982950cc38Schristos if (0 == argc) { 599abb0f93cSkardel ADDHOST(DEFHOST); 600abb0f93cSkardel } else { 6012950cc38Schristos for (ihost = 0; ihost < (u_int)argc; ihost++) { 6022950cc38Schristos if ('-' == *argv[ihost]) { 6032950cc38Schristos // 6042950cc38Schristos // If I really cared I'd also check: 6052950cc38Schristos // 0 == argv[ihost][2] 6062950cc38Schristos // 6072950cc38Schristos // and there are other cases as well... 6082950cc38Schristos // 6092950cc38Schristos if ('4' == argv[ihost][1]) { 6102950cc38Schristos ai_fam_templ = AF_INET; 6112950cc38Schristos continue; 6122950cc38Schristos } else if ('6' == argv[ihost][1]) { 6132950cc38Schristos ai_fam_templ = AF_INET6; 6142950cc38Schristos continue; 6152950cc38Schristos } else { 6162950cc38Schristos // XXX Throw a usage error 6172950cc38Schristos } 6182950cc38Schristos } 6192950cc38Schristos ADDHOST(argv[ihost]); 6202950cc38Schristos } 621abb0f93cSkardel } 622abb0f93cSkardel 623*eabc0478Schristos if (defcmds == 0 && interactive == 0 624abb0f93cSkardel && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 625abb0f93cSkardel interactive = 1; 626abb0f93cSkardel } 627abb0f93cSkardel 6288b8da087Schristos set_ctrl_c_hook(on_ctrlc); 629abb0f93cSkardel #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 630abb0f93cSkardel if (interactive) 6318b8da087Schristos push_ctrl_c_handler(abortcmd); 632abb0f93cSkardel #endif /* SYS_WINNT */ 633abb0f93cSkardel 634*eabc0478Schristos if (numcmds > 0) { 635abb0f93cSkardel for (ihost = 0; ihost < numhosts; ihost++) { 6364eea345dSchristos if (openhost(chosts[ihost].name, chosts[ihost].fam)) { 63779045f13Schristos if (ihost && current_output) 6384eea345dSchristos fputc('\n', current_output); 6394eea345dSchristos for (icmd = 0; icmd < numcmds; icmd++) { 64079045f13Schristos if (icmd && current_output) 6414eea345dSchristos fputc('\n', current_output); 642abb0f93cSkardel docmd(ccmds[icmd]); 643abb0f93cSkardel } 644abb0f93cSkardel } 6454eea345dSchristos } 646*eabc0478Schristos /* Release memory allocated in ADDCMD */ 647*eabc0478Schristos for (icmd = 0; icmd < numcmds; icmd++) 648*eabc0478Schristos free(ccmds[icmd]); 649*eabc0478Schristos } 650*eabc0478Schristos 651*eabc0478Schristos if (defcmds == 0) { /* No command line commands, so go interactive */ 652*eabc0478Schristos (void) openhost(chosts[0].name, chosts[0].fam); 653*eabc0478Schristos getcmds(); 6544eea345dSchristos } 655abb0f93cSkardel #ifdef SYS_WINNT 656abb0f93cSkardel WSACleanup(); 657abb0f93cSkardel #endif /* SYS_WINNT */ 658abb0f93cSkardel return 0; 659abb0f93cSkardel } 660abb0f93cSkardel #endif /* !BUILD_AS_LIB */ 661abb0f93cSkardel 662abb0f93cSkardel /* 663abb0f93cSkardel * openhost - open a socket to a host 664abb0f93cSkardel */ 665abb0f93cSkardel static int 666abb0f93cSkardel openhost( 6672950cc38Schristos const char *hname, 6682950cc38Schristos int fam 669abb0f93cSkardel ) 670abb0f93cSkardel { 6712950cc38Schristos const char svc[] = "ntp"; 672abb0f93cSkardel char temphost[LENHOSTNAME]; 67379045f13Schristos int a_info; 6742950cc38Schristos struct addrinfo hints, *ai; 6752950cc38Schristos sockaddr_u addr; 6762950cc38Schristos size_t octets; 67779045f13Schristos const char *cp; 678abb0f93cSkardel char name[LENHOSTNAME]; 679abb0f93cSkardel 680abb0f93cSkardel /* 681abb0f93cSkardel * We need to get by the [] if they were entered 682abb0f93cSkardel */ 68379045f13Schristos if (*hname == '[') { 68479045f13Schristos cp = strchr(hname + 1, ']'); 68579045f13Schristos if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) { 68679045f13Schristos errno = EINVAL; 68779045f13Schristos warning("%s", "bad hostname/address"); 688abb0f93cSkardel return 0; 689abb0f93cSkardel } 69079045f13Schristos memcpy(name, hname + 1, octets); 69179045f13Schristos name[octets] = '\0'; 69279045f13Schristos hname = name; 693abb0f93cSkardel } 694abb0f93cSkardel 695abb0f93cSkardel /* 696abb0f93cSkardel * First try to resolve it as an ip address and if that fails, 697abb0f93cSkardel * do a fullblown (dns) lookup. That way we only use the dns 698abb0f93cSkardel * when it is needed and work around some implementations that 699abb0f93cSkardel * will return an "IPv4-mapped IPv6 address" address if you 700abb0f93cSkardel * give it an IPv4 address to lookup. 701abb0f93cSkardel */ 7023123f114Skardel ZERO(hints); 7032950cc38Schristos hints.ai_family = fam; 704abb0f93cSkardel hints.ai_protocol = IPPROTO_UDP; 705abb0f93cSkardel hints.ai_socktype = SOCK_DGRAM; 7063123f114Skardel hints.ai_flags = Z_AI_NUMERICHOST; 7072950cc38Schristos ai = NULL; 708abb0f93cSkardel 7092950cc38Schristos a_info = getaddrinfo(hname, svc, &hints, &ai); 710abb0f93cSkardel if (a_info == EAI_NONAME 711abb0f93cSkardel #ifdef EAI_NODATA 712abb0f93cSkardel || a_info == EAI_NODATA 713abb0f93cSkardel #endif 714abb0f93cSkardel ) { 715abb0f93cSkardel hints.ai_flags = AI_CANONNAME; 716abb0f93cSkardel #ifdef AI_ADDRCONFIG 717abb0f93cSkardel hints.ai_flags |= AI_ADDRCONFIG; 718abb0f93cSkardel #endif 7192950cc38Schristos a_info = getaddrinfo(hname, svc, &hints, &ai); 720abb0f93cSkardel } 721abb0f93cSkardel #ifdef AI_ADDRCONFIG 722*eabc0478Schristos /* 723*eabc0478Schristos * Some older implementations don't like AI_ADDRCONFIG. 724*eabc0478Schristos * Some versions of Windows return WSANO_DATA when there is no 725*eabc0478Schristos * global address and AI_ADDRCONFIG is used. AI_ADDRCONFIG 726*eabc0478Schristos * is useful to short-circuit DNS lookups for IP protocols 727*eabc0478Schristos * for which the host has no local addresses. Windows 728*eabc0478Schristos * unfortunately instead interprets AI_ADDRCONFIG to relate 729*eabc0478Schristos * to off-host connectivity and so fails lookup when 730*eabc0478Schristos * localhost works. 731*eabc0478Schristos * To further muddy matters, some versions of WS2tcpip.h 732*eabc0478Schristos * comment out #define EAI_NODATA WSANODATA claiming it 733*eabc0478Schristos * was removed from RFC 2553bis and mentioning a need to 734*eabc0478Schristos * contact the authors to find out why, but "helpfully" 735*eabc0478Schristos * #defines EAI_NODATA EAI_NONAME (== WSAHOST_NOT_FOUND) 736*eabc0478Schristos * So we get more ugly platform-specific workarounds. 737*eabc0478Schristos */ 738*eabc0478Schristos if ( 739*eabc0478Schristos #if defined(WIN32) 740*eabc0478Schristos WSANO_DATA == a_info || EAI_NONAME == a_info || 741*eabc0478Schristos #endif 742*eabc0478Schristos EAI_BADFLAGS == a_info) { 7432950cc38Schristos hints.ai_flags &= ~AI_ADDRCONFIG; 7442950cc38Schristos a_info = getaddrinfo(hname, svc, &hints, &ai); 745abb0f93cSkardel } 746abb0f93cSkardel #endif 747abb0f93cSkardel if (a_info != 0) { 7482950cc38Schristos fprintf(stderr, "%s\n", gai_strerror(a_info)); 749abb0f93cSkardel return 0; 750abb0f93cSkardel } 751abb0f93cSkardel 7522950cc38Schristos INSIST(ai != NULL); 7532950cc38Schristos ZERO(addr); 7542950cc38Schristos octets = min(sizeof(addr), ai->ai_addrlen); 7552950cc38Schristos memcpy(&addr, ai->ai_addr, octets); 7562950cc38Schristos 7572950cc38Schristos if (ai->ai_canonname == NULL) { 7582950cc38Schristos strlcpy(temphost, stoa(&addr), sizeof(temphost)); 7593123f114Skardel currenthostisnum = TRUE; 760abb0f93cSkardel } else { 7612950cc38Schristos strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 7623123f114Skardel currenthostisnum = FALSE; 763abb0f93cSkardel } 764abb0f93cSkardel 765abb0f93cSkardel if (debug > 2) 7662950cc38Schristos printf("Opening host %s (%s)\n", 7672950cc38Schristos temphost, 7682950cc38Schristos (ai->ai_family == AF_INET) 7692950cc38Schristos ? "AF_INET" 7702950cc38Schristos : (ai->ai_family == AF_INET6) 7712950cc38Schristos ? "AF_INET6" 7722950cc38Schristos : "AF-???" 7732950cc38Schristos ); 774abb0f93cSkardel 775abb0f93cSkardel if (havehost == 1) { 776abb0f93cSkardel if (debug > 2) 777abb0f93cSkardel printf("Closing old host %s\n", currenthost); 7782950cc38Schristos closesocket(sockfd); 779abb0f93cSkardel havehost = 0; 780abb0f93cSkardel } 7812950cc38Schristos strlcpy(currenthost, temphost, sizeof(currenthost)); 782abb0f93cSkardel 783abb0f93cSkardel /* port maps to the same location in both families */ 7842950cc38Schristos s_port = NSRCPORT(&addr); 785abb0f93cSkardel #ifdef SYS_VXWORKS 786abb0f93cSkardel ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 787abb0f93cSkardel if (ai->ai_family == AF_INET) 788abb0f93cSkardel *(struct sockaddr_in *)&hostaddr= 789abb0f93cSkardel *((struct sockaddr_in *)ai->ai_addr); 790abb0f93cSkardel else 791abb0f93cSkardel *(struct sockaddr_in6 *)&hostaddr= 792abb0f93cSkardel *((struct sockaddr_in6 *)ai->ai_addr); 793abb0f93cSkardel #endif /* SYS_VXWORKS */ 794abb0f93cSkardel 795abb0f93cSkardel #ifdef SYS_WINNT 796abb0f93cSkardel { 797abb0f93cSkardel int optionValue = SO_SYNCHRONOUS_NONALERT; 798abb0f93cSkardel int err; 799abb0f93cSkardel 800abb0f93cSkardel err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 8014eea345dSchristos (void *)&optionValue, sizeof(optionValue)); 802abb0f93cSkardel if (err) { 8032950cc38Schristos mfprintf(stderr, 804abb0f93cSkardel "setsockopt(SO_SYNCHRONOUS_NONALERT)" 8052950cc38Schristos " error: %m\n"); 8062950cc38Schristos freeaddrinfo(ai); 807abb0f93cSkardel exit(1); 808abb0f93cSkardel } 809abb0f93cSkardel } 810abb0f93cSkardel #endif /* SYS_WINNT */ 811abb0f93cSkardel 8122950cc38Schristos sockfd = socket(ai->ai_family, ai->ai_socktype, 8132950cc38Schristos ai->ai_protocol); 814abb0f93cSkardel if (sockfd == INVALID_SOCKET) { 815058f310fSchristos error("socket"); 8162950cc38Schristos freeaddrinfo(ai); 8172950cc38Schristos return 0; 818abb0f93cSkardel } 819abb0f93cSkardel 820abb0f93cSkardel 821abb0f93cSkardel #ifdef NEED_RCVBUF_SLOP 822abb0f93cSkardel # ifdef SO_RCVBUF 823abb0f93cSkardel { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 824abb0f93cSkardel if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 8254eea345dSchristos (void *)&rbufsize, sizeof(int)) == -1) 826058f310fSchristos error("setsockopt"); 827abb0f93cSkardel } 828abb0f93cSkardel # endif 829abb0f93cSkardel #endif 830abb0f93cSkardel 8312950cc38Schristos if 832abb0f93cSkardel #ifdef SYS_VXWORKS 8332950cc38Schristos (connect(sockfd, (struct sockaddr *)&hostaddr, 834abb0f93cSkardel sizeof(hostaddr)) == -1) 835abb0f93cSkardel #else 8362950cc38Schristos (connect(sockfd, (struct sockaddr *)ai->ai_addr, 837abb0f93cSkardel ai->ai_addrlen) == -1) 838abb0f93cSkardel #endif /* SYS_VXWORKS */ 8392950cc38Schristos { 840058f310fSchristos error("connect"); 8412950cc38Schristos freeaddrinfo(ai); 8422950cc38Schristos return 0; 8432950cc38Schristos } 844abb0f93cSkardel freeaddrinfo(ai); 845abb0f93cSkardel havehost = 1; 8462950cc38Schristos numassoc = 0; 8472950cc38Schristos 848abb0f93cSkardel return 1; 849abb0f93cSkardel } 850abb0f93cSkardel 851abb0f93cSkardel 8522950cc38Schristos static void 8532950cc38Schristos dump_hex_printable( 8542950cc38Schristos const void * data, 8552950cc38Schristos size_t len 8562950cc38Schristos ) 8572950cc38Schristos { 858ccc794f0Schristos /* every line shows at most 16 bytes, so we need a buffer of 859ccc794f0Schristos * 4 * 16 (2 xdigits, 1 char, one sep for xdigits) 860ccc794f0Schristos * + 2 * 1 (block separators) 861ccc794f0Schristos * + <LF> + <NUL> 862ccc794f0Schristos *--------------- 863ccc794f0Schristos * 68 bytes 864ccc794f0Schristos */ 865ccc794f0Schristos static const char s_xdig[16] = "0123456789ABCDEF"; 8662950cc38Schristos 867ccc794f0Schristos char lbuf[68]; 868ccc794f0Schristos int ch, rowlen; 869ccc794f0Schristos const u_char * cdata = data; 870ccc794f0Schristos char *xptr, *pptr; 871ccc794f0Schristos 872ccc794f0Schristos while (len) { 873ccc794f0Schristos memset(lbuf, ' ', sizeof(lbuf)); 874ccc794f0Schristos xptr = lbuf; 875ccc794f0Schristos pptr = lbuf + 3*16 + 2; 876ccc794f0Schristos 877ccc794f0Schristos rowlen = (len > 16) ? 16 : (int)len; 8782950cc38Schristos len -= rowlen; 879ccc794f0Schristos 880ccc794f0Schristos do { 881ccc794f0Schristos ch = *cdata++; 882ccc794f0Schristos 883ccc794f0Schristos *xptr++ = s_xdig[ch >> 4 ]; 884ccc794f0Schristos *xptr++ = s_xdig[ch & 0x0F]; 885ccc794f0Schristos if (++xptr == lbuf + 3*8) 886ccc794f0Schristos ++xptr; 887ccc794f0Schristos 888ccc794f0Schristos *pptr++ = isprint(ch) ? (char)ch : '.'; 889ccc794f0Schristos } while (--rowlen); 890ccc794f0Schristos 891ccc794f0Schristos *pptr++ = '\n'; 892ccc794f0Schristos *pptr = '\0'; 893ccc794f0Schristos fputs(lbuf, stdout); 8942950cc38Schristos } 8952950cc38Schristos } 8962950cc38Schristos 8972950cc38Schristos 898abb0f93cSkardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 899abb0f93cSkardel /* 900abb0f93cSkardel * sendpkt - send a packet to the remote host 901abb0f93cSkardel */ 902abb0f93cSkardel static int 903abb0f93cSkardel sendpkt( 904abb0f93cSkardel void * xdata, 905abb0f93cSkardel size_t xdatalen 906abb0f93cSkardel ) 907abb0f93cSkardel { 908abb0f93cSkardel if (debug >= 3) 909e19314b7Schristos printf("Sending %zu octets\n", xdatalen); 910abb0f93cSkardel 9118b8da087Schristos if (send(sockfd, xdata, xdatalen, 0) == -1) { 912058f310fSchristos warning("write to %s failed", currenthost); 913abb0f93cSkardel return -1; 914abb0f93cSkardel } 915abb0f93cSkardel 916abb0f93cSkardel if (debug >= 4) { 9172950cc38Schristos printf("Request packet:\n"); 9182950cc38Schristos dump_hex_printable(xdata, xdatalen); 919abb0f93cSkardel } 920abb0f93cSkardel return 0; 921abb0f93cSkardel } 922abb0f93cSkardel 923abb0f93cSkardel /* 924abb0f93cSkardel * getresponse - get a (series of) response packet(s) and return the data 925abb0f93cSkardel */ 926abb0f93cSkardel static int 927abb0f93cSkardel getresponse( 928abb0f93cSkardel int opcode, 929abb0f93cSkardel int associd, 930abb0f93cSkardel u_short *rstatus, 9318b8da087Schristos size_t *rsize, 9323123f114Skardel const char **rdata, 933abb0f93cSkardel int timeo 934abb0f93cSkardel ) 935abb0f93cSkardel { 936abb0f93cSkardel struct ntp_control rpkt; 937abb0f93cSkardel struct sock_timeval tvo; 938abb0f93cSkardel u_short offsets[MAXFRAGS+1]; 939abb0f93cSkardel u_short counts[MAXFRAGS+1]; 940abb0f93cSkardel u_short offset; 941abb0f93cSkardel u_short count; 9423123f114Skardel size_t numfrags; 9433123f114Skardel size_t f; 9443123f114Skardel size_t ff; 945abb0f93cSkardel int seenlastfrag; 946abb0f93cSkardel int shouldbesize; 947abb0f93cSkardel fd_set fds; 948abb0f93cSkardel int n; 9492950cc38Schristos int errcode; 95068dbbb44Schristos /* absolute timeout checks. Not 'time_t' by intention! */ 95168dbbb44Schristos uint32_t tobase; /* base value for timeout */ 95268dbbb44Schristos uint32_t tospan; /* timeout span (max delay) */ 95368dbbb44Schristos uint32_t todiff; /* current delay */ 954abb0f93cSkardel 955ccc794f0Schristos memset(offsets, 0, sizeof(offsets)); 956ccc794f0Schristos memset(counts , 0, sizeof(counts )); 957ccc794f0Schristos 958abb0f93cSkardel /* 959abb0f93cSkardel * This is pretty tricky. We may get between 1 and MAXFRAG packets 960abb0f93cSkardel * back in response to the request. We peel the data out of 961abb0f93cSkardel * each packet and collect it in one long block. When the last 962abb0f93cSkardel * packet in the sequence is received we'll know how much data we 963abb0f93cSkardel * should have had. Note we use one long time out, should reconsider. 964abb0f93cSkardel */ 965abb0f93cSkardel *rsize = 0; 966abb0f93cSkardel if (rstatus) 967abb0f93cSkardel *rstatus = 0; 968abb0f93cSkardel *rdata = (char *)pktdata; 969abb0f93cSkardel 970abb0f93cSkardel numfrags = 0; 971abb0f93cSkardel seenlastfrag = 0; 972abb0f93cSkardel 97368dbbb44Schristos tobase = (uint32_t)time(NULL); 97468dbbb44Schristos 975abb0f93cSkardel FD_ZERO(&fds); 976abb0f93cSkardel 977abb0f93cSkardel /* 978abb0f93cSkardel * Loop until we have an error or a complete response. Nearly all 9793123f114Skardel * code paths to loop again use continue. 980abb0f93cSkardel */ 981abb0f93cSkardel for (;;) { 982abb0f93cSkardel 983abb0f93cSkardel if (numfrags == 0) 984abb0f93cSkardel tvo = tvout; 985abb0f93cSkardel else 986abb0f93cSkardel tvo = tvsout; 98768dbbb44Schristos tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 988abb0f93cSkardel 989abb0f93cSkardel FD_SET(sockfd, &fds); 9903123f114Skardel n = select(sockfd+1, &fds, NULL, NULL, &tvo); 991abb0f93cSkardel if (n == -1) { 99268dbbb44Schristos #if !defined(SYS_WINNT) && defined(EINTR) 99368dbbb44Schristos /* Windows does not know about EINTR (until very 99468dbbb44Schristos * recently) and the handling of console events 99568dbbb44Schristos * is *very* different from POSIX/UNIX signal 99668dbbb44Schristos * handling anyway. 99768dbbb44Schristos * 99868dbbb44Schristos * Under non-windows targets we map EINTR as 99968dbbb44Schristos * 'last packet was received' and try to exit 100068dbbb44Schristos * the receive sequence. 100168dbbb44Schristos */ 100268dbbb44Schristos if (errno == EINTR) { 100368dbbb44Schristos seenlastfrag = 1; 100468dbbb44Schristos goto maybe_final; 100568dbbb44Schristos } 100668dbbb44Schristos #endif 1007058f310fSchristos warning("select fails"); 1008abb0f93cSkardel return -1; 1009abb0f93cSkardel } 101068dbbb44Schristos 101168dbbb44Schristos /* 101268dbbb44Schristos * Check if this is already too late. Trash the data and 101368dbbb44Schristos * fake a timeout if this is so. 101468dbbb44Schristos */ 101568dbbb44Schristos todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 101668dbbb44Schristos if ((n > 0) && (todiff > tospan)) { 101768dbbb44Schristos n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 1018ccc794f0Schristos n -= n; /* faked timeout return from 'select()', 1019ccc794f0Schristos * execute RMW cycle on 'n' 1020ccc794f0Schristos */ 102168dbbb44Schristos } 102268dbbb44Schristos 1023ccc794f0Schristos if (n <= 0) { 1024abb0f93cSkardel /* 1025abb0f93cSkardel * Timed out. Return what we have 1026abb0f93cSkardel */ 1027abb0f93cSkardel if (numfrags == 0) { 1028abb0f93cSkardel if (timeo) 10293123f114Skardel fprintf(stderr, 1030abb0f93cSkardel "%s: timed out, nothing received\n", 1031abb0f93cSkardel currenthost); 1032abb0f93cSkardel return ERR_TIMEOUT; 10333123f114Skardel } 1034abb0f93cSkardel if (timeo) 10353123f114Skardel fprintf(stderr, 1036abb0f93cSkardel "%s: timed out with incomplete data\n", 1037abb0f93cSkardel currenthost); 1038abb0f93cSkardel if (debug) { 10393123f114Skardel fprintf(stderr, 10403123f114Skardel "ERR_INCOMPLETE: Received fragments:\n"); 10413123f114Skardel for (f = 0; f < numfrags; f++) 10423123f114Skardel fprintf(stderr, 10432950cc38Schristos "%2u: %5d %5d\t%3d octets\n", 10442950cc38Schristos (u_int)f, offsets[f], 10453123f114Skardel offsets[f] + 10463123f114Skardel counts[f], 10473123f114Skardel counts[f]); 10483123f114Skardel fprintf(stderr, 10493123f114Skardel "last fragment %sreceived\n", 10503123f114Skardel (seenlastfrag) 10513123f114Skardel ? "" 10523123f114Skardel : "not "); 1053abb0f93cSkardel } 1054abb0f93cSkardel return ERR_INCOMPLETE; 1055abb0f93cSkardel } 1056abb0f93cSkardel 1057abb0f93cSkardel n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 1058ccc794f0Schristos if (n < 0) { 1059058f310fSchristos warning("read"); 1060abb0f93cSkardel return -1; 1061abb0f93cSkardel } 1062abb0f93cSkardel 1063abb0f93cSkardel if (debug >= 4) { 10642950cc38Schristos printf("Response packet:\n"); 10652950cc38Schristos dump_hex_printable(&rpkt, n); 1066abb0f93cSkardel } 1067abb0f93cSkardel 1068abb0f93cSkardel /* 1069abb0f93cSkardel * Check for format errors. Bug proofing. 1070abb0f93cSkardel */ 1071a2545411Skardel if (n < (int)CTL_HEADER_LEN) { 1072abb0f93cSkardel if (debug) 1073abb0f93cSkardel printf("Short (%d byte) packet received\n", n); 1074abb0f93cSkardel continue; 1075abb0f93cSkardel } 1076abb0f93cSkardel if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 1077abb0f93cSkardel || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 1078abb0f93cSkardel if (debug) 1079abb0f93cSkardel printf("Packet received with version %d\n", 1080abb0f93cSkardel PKT_VERSION(rpkt.li_vn_mode)); 1081abb0f93cSkardel continue; 1082abb0f93cSkardel } 1083abb0f93cSkardel if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 1084abb0f93cSkardel if (debug) 1085abb0f93cSkardel printf("Packet received with mode %d\n", 1086abb0f93cSkardel PKT_MODE(rpkt.li_vn_mode)); 1087abb0f93cSkardel continue; 1088abb0f93cSkardel } 1089abb0f93cSkardel if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 1090abb0f93cSkardel if (debug) 1091abb0f93cSkardel printf("Received request packet, wanted response\n"); 1092abb0f93cSkardel continue; 1093abb0f93cSkardel } 1094abb0f93cSkardel 1095abb0f93cSkardel /* 1096abb0f93cSkardel * Check opcode and sequence number for a match. 1097abb0f93cSkardel * Could be old data getting to us. 1098abb0f93cSkardel */ 1099abb0f93cSkardel if (ntohs(rpkt.sequence) != sequence) { 1100abb0f93cSkardel if (debug) 11013123f114Skardel printf("Received sequnce number %d, wanted %d\n", 1102abb0f93cSkardel ntohs(rpkt.sequence), sequence); 1103abb0f93cSkardel continue; 1104abb0f93cSkardel } 1105abb0f93cSkardel if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1106abb0f93cSkardel if (debug) 1107abb0f93cSkardel printf( 1108abb0f93cSkardel "Received opcode %d, wanted %d (sequence number okay)\n", 1109abb0f93cSkardel CTL_OP(rpkt.r_m_e_op), opcode); 1110abb0f93cSkardel continue; 1111abb0f93cSkardel } 1112abb0f93cSkardel 1113abb0f93cSkardel /* 1114abb0f93cSkardel * Check the error code. If non-zero, return it. 1115abb0f93cSkardel */ 1116abb0f93cSkardel if (CTL_ISERROR(rpkt.r_m_e_op)) { 1117abb0f93cSkardel errcode = (ntohs(rpkt.status) >> 8) & 0xff; 11182950cc38Schristos if (CTL_ISMORE(rpkt.r_m_e_op)) 11192950cc38Schristos TRACE(1, ("Error code %d received on not-final packet\n", 11202950cc38Schristos errcode)); 1121abb0f93cSkardel if (errcode == CERR_UNSPEC) 1122abb0f93cSkardel return ERR_UNSPEC; 1123abb0f93cSkardel return errcode; 1124abb0f93cSkardel } 1125abb0f93cSkardel 1126abb0f93cSkardel /* 1127abb0f93cSkardel * Check the association ID to make sure it matches what 1128abb0f93cSkardel * we sent. 1129abb0f93cSkardel */ 1130abb0f93cSkardel if (ntohs(rpkt.associd) != associd) { 11312950cc38Schristos TRACE(1, ("Association ID %d doesn't match expected %d\n", 11322950cc38Schristos ntohs(rpkt.associd), associd)); 1133abb0f93cSkardel /* 1134abb0f93cSkardel * Hack for silly fuzzballs which, at the time of writing, 1135abb0f93cSkardel * return an assID of sys.peer when queried for system variables. 1136abb0f93cSkardel */ 1137abb0f93cSkardel #ifdef notdef 1138abb0f93cSkardel continue; 1139abb0f93cSkardel #endif 1140abb0f93cSkardel } 1141abb0f93cSkardel 1142abb0f93cSkardel /* 1143abb0f93cSkardel * Collect offset and count. Make sure they make sense. 1144abb0f93cSkardel */ 1145abb0f93cSkardel offset = ntohs(rpkt.offset); 1146abb0f93cSkardel count = ntohs(rpkt.count); 1147abb0f93cSkardel 1148abb0f93cSkardel /* 1149abb0f93cSkardel * validate received payload size is padded to next 32-bit 1150abb0f93cSkardel * boundary and no smaller than claimed by rpkt.count 1151abb0f93cSkardel */ 1152abb0f93cSkardel if (n & 0x3) { 11532950cc38Schristos TRACE(1, ("Response packet not padded, size = %d\n", 11542950cc38Schristos n)); 1155abb0f93cSkardel continue; 1156abb0f93cSkardel } 1157abb0f93cSkardel 1158abb0f93cSkardel shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 1159abb0f93cSkardel 1160abb0f93cSkardel if (n < shouldbesize) { 11612950cc38Schristos printf("Response packet claims %u octets payload, above %ld received\n", 1162717847f5Schristos count, (long)(n - CTL_HEADER_LEN)); 1163abb0f93cSkardel return ERR_INCOMPLETE; 1164abb0f93cSkardel } 1165abb0f93cSkardel 1166abb0f93cSkardel if (debug >= 3 && shouldbesize > n) { 1167abb0f93cSkardel u_int32 key; 1168abb0f93cSkardel u_int32 *lpkt; 1169abb0f93cSkardel int maclen; 1170abb0f93cSkardel 1171abb0f93cSkardel /* 1172abb0f93cSkardel * Usually we ignore authentication, but for debugging purposes 1173abb0f93cSkardel * we watch it here. 1174abb0f93cSkardel */ 1175abb0f93cSkardel /* round to 8 octet boundary */ 1176abb0f93cSkardel shouldbesize = (shouldbesize + 7) & ~7; 1177abb0f93cSkardel 1178abb0f93cSkardel maclen = n - shouldbesize; 1179e19314b7Schristos if (maclen >= (int)MIN_MAC_LEN) { 1180abb0f93cSkardel printf( 1181abb0f93cSkardel "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1182abb0f93cSkardel n, shouldbesize, maclen); 1183abb0f93cSkardel lpkt = (u_int32 *)&rpkt; 1184abb0f93cSkardel printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1185abb0f93cSkardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1186abb0f93cSkardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1187abb0f93cSkardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1188abb0f93cSkardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1189abb0f93cSkardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1190abb0f93cSkardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1191abb0f93cSkardel key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1192abb0f93cSkardel printf("Authenticated with keyid %lu\n", (u_long)key); 1193abb0f93cSkardel if (key != 0 && key != info_auth_keyid) { 1194abb0f93cSkardel printf("We don't know that key\n"); 1195abb0f93cSkardel } else { 1196abb0f93cSkardel if (authdecrypt(key, (u_int32 *)&rpkt, 1197abb0f93cSkardel n - maclen, maclen)) { 1198abb0f93cSkardel printf("Auth okay!\n"); 1199abb0f93cSkardel } else { 1200abb0f93cSkardel printf("Auth failed!\n"); 1201abb0f93cSkardel } 1202abb0f93cSkardel } 1203abb0f93cSkardel } 1204abb0f93cSkardel } 1205abb0f93cSkardel 12062950cc38Schristos TRACE(2, ("Got packet, size = %d\n", n)); 12072950cc38Schristos if (count > (n - CTL_HEADER_LEN)) { 12082950cc38Schristos TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 12092950cc38Schristos count, (long)n - CTL_HEADER_LEN)); 1210abb0f93cSkardel continue; 1211abb0f93cSkardel } 1212abb0f93cSkardel if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 12132950cc38Schristos TRACE(1, ("Received count of 0 in non-final fragment\n")); 1214abb0f93cSkardel continue; 1215abb0f93cSkardel } 1216abb0f93cSkardel if (offset + count > sizeof(pktdata)) { 12172950cc38Schristos TRACE(1, ("Offset %u, count %u, too big for buffer\n", 12182950cc38Schristos offset, count)); 1219abb0f93cSkardel return ERR_TOOMUCH; 1220abb0f93cSkardel } 1221abb0f93cSkardel if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 12222950cc38Schristos TRACE(1, ("Received second last fragment packet\n")); 1223abb0f93cSkardel continue; 1224abb0f93cSkardel } 1225abb0f93cSkardel 1226abb0f93cSkardel /* 1227abb0f93cSkardel * So far, so good. Record this fragment, making sure it doesn't 1228abb0f93cSkardel * overlap anything. 1229abb0f93cSkardel */ 12302950cc38Schristos TRACE(2, ("Packet okay\n")); 1231abb0f93cSkardel 1232abb0f93cSkardel if (numfrags > (MAXFRAGS - 1)) { 12332950cc38Schristos TRACE(2, ("Number of fragments exceeds maximum %d\n", 12342950cc38Schristos MAXFRAGS - 1)); 1235abb0f93cSkardel return ERR_TOOMUCH; 1236abb0f93cSkardel } 1237abb0f93cSkardel 1238abb0f93cSkardel /* 1239abb0f93cSkardel * Find the position for the fragment relative to any 1240abb0f93cSkardel * previously received. 1241abb0f93cSkardel */ 12423123f114Skardel for (f = 0; 12433123f114Skardel f < numfrags && offsets[f] < offset; 12443123f114Skardel f++) { 1245abb0f93cSkardel /* empty body */ ; 1246abb0f93cSkardel } 1247abb0f93cSkardel 12483123f114Skardel if (f < numfrags && offset == offsets[f]) { 12492950cc38Schristos TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 12502950cc38Schristos count, offset, counts[f], offsets[f])); 1251abb0f93cSkardel continue; 1252abb0f93cSkardel } 1253abb0f93cSkardel 12543123f114Skardel if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 12552950cc38Schristos TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 12562950cc38Schristos offset, counts[f-1], offsets[f-1])); 1257abb0f93cSkardel continue; 1258abb0f93cSkardel } 1259abb0f93cSkardel 12603123f114Skardel if (f < numfrags && (offset + count) > offsets[f]) { 12612950cc38Schristos TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 12622950cc38Schristos count, offset, offsets[f])); 1263abb0f93cSkardel continue; 1264abb0f93cSkardel } 1265abb0f93cSkardel 12663123f114Skardel for (ff = numfrags; ff > f; ff--) { 12673123f114Skardel offsets[ff] = offsets[ff-1]; 12683123f114Skardel counts[ff] = counts[ff-1]; 1269abb0f93cSkardel } 12703123f114Skardel offsets[f] = offset; 12713123f114Skardel counts[f] = count; 1272abb0f93cSkardel numfrags++; 1273abb0f93cSkardel 1274abb0f93cSkardel /* 1275abb0f93cSkardel * Got that stuffed in right. Figure out if this was the last. 1276abb0f93cSkardel * Record status info out of the last packet. 1277abb0f93cSkardel */ 1278abb0f93cSkardel if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1279abb0f93cSkardel seenlastfrag = 1; 1280abb0f93cSkardel if (rstatus != 0) 1281abb0f93cSkardel *rstatus = ntohs(rpkt.status); 1282abb0f93cSkardel } 1283abb0f93cSkardel 1284abb0f93cSkardel /* 128568dbbb44Schristos * Copy the data into the data buffer, and bump the 128668dbbb44Schristos * timout base in case we need more. 1287abb0f93cSkardel */ 12882950cc38Schristos memcpy((char *)pktdata + offset, &rpkt.u, count); 128968dbbb44Schristos tobase = (uint32_t)time(NULL); 1290abb0f93cSkardel 1291abb0f93cSkardel /* 1292abb0f93cSkardel * If we've seen the last fragment, look for holes in the sequence. 1293abb0f93cSkardel * If there aren't any, we're done. 1294abb0f93cSkardel */ 1295717847f5Schristos #if !defined(SYS_WINNT) && defined(EINTR) 129668dbbb44Schristos maybe_final: 1297717847f5Schristos #endif 1298717847f5Schristos 1299abb0f93cSkardel if (seenlastfrag && offsets[0] == 0) { 13003123f114Skardel for (f = 1; f < numfrags; f++) 13013123f114Skardel if (offsets[f-1] + counts[f-1] != 13023123f114Skardel offsets[f]) 1303abb0f93cSkardel break; 13043123f114Skardel if (f == numfrags) { 13053123f114Skardel *rsize = offsets[f-1] + counts[f-1]; 13062950cc38Schristos TRACE(1, ("%lu packets reassembled into response\n", 13072950cc38Schristos (u_long)numfrags)); 1308abb0f93cSkardel return 0; 1309abb0f93cSkardel } 1310abb0f93cSkardel } 1311abb0f93cSkardel } /* giant for (;;) collecting response packets */ 1312abb0f93cSkardel } /* getresponse() */ 1313abb0f93cSkardel 1314abb0f93cSkardel 1315abb0f93cSkardel /* 1316abb0f93cSkardel * sendrequest - format and send a request packet 1317abb0f93cSkardel */ 1318abb0f93cSkardel static int 1319abb0f93cSkardel sendrequest( 1320abb0f93cSkardel int opcode, 13212950cc38Schristos associd_t associd, 1322abb0f93cSkardel int auth, 13238b8da087Schristos size_t qsize, 13242950cc38Schristos const char *qdata 1325abb0f93cSkardel ) 1326abb0f93cSkardel { 1327abb0f93cSkardel struct ntp_control qpkt; 13288b8da087Schristos size_t pktsize; 1329abb0f93cSkardel u_long key_id; 1330abb0f93cSkardel char * pass; 13318b8da087Schristos size_t maclen; 1332abb0f93cSkardel 1333abb0f93cSkardel /* 1334abb0f93cSkardel * Check to make sure the data will fit in one packet 1335abb0f93cSkardel */ 1336abb0f93cSkardel if (qsize > CTL_MAX_DATA_LEN) { 1337abb0f93cSkardel fprintf(stderr, 13388b8da087Schristos "***Internal error! qsize (%zu) too large\n", 1339abb0f93cSkardel qsize); 1340abb0f93cSkardel return 1; 1341abb0f93cSkardel } 1342abb0f93cSkardel 1343abb0f93cSkardel /* 1344abb0f93cSkardel * Fill in the packet 1345abb0f93cSkardel */ 1346abb0f93cSkardel qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1347abb0f93cSkardel qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 1348abb0f93cSkardel qpkt.sequence = htons(sequence); 1349abb0f93cSkardel qpkt.status = 0; 1350abb0f93cSkardel qpkt.associd = htons((u_short)associd); 1351abb0f93cSkardel qpkt.offset = 0; 1352abb0f93cSkardel qpkt.count = htons((u_short)qsize); 1353abb0f93cSkardel 1354abb0f93cSkardel pktsize = CTL_HEADER_LEN; 1355abb0f93cSkardel 1356abb0f93cSkardel /* 1357abb0f93cSkardel * If we have data, copy and pad it out to a 32-bit boundary. 1358abb0f93cSkardel */ 1359abb0f93cSkardel if (qsize > 0) { 13602950cc38Schristos memcpy(&qpkt.u, qdata, (size_t)qsize); 1361abb0f93cSkardel pktsize += qsize; 1362abb0f93cSkardel while (pktsize & (sizeof(u_int32) - 1)) { 13632950cc38Schristos qpkt.u.data[qsize++] = 0; 1364abb0f93cSkardel pktsize++; 1365abb0f93cSkardel } 1366abb0f93cSkardel } 1367abb0f93cSkardel 1368abb0f93cSkardel /* 1369abb0f93cSkardel * If it isn't authenticated we can just send it. Otherwise 1370abb0f93cSkardel * we're going to have to think about it a little. 1371abb0f93cSkardel */ 1372abb0f93cSkardel if (!auth && !always_auth) { 1373abb0f93cSkardel return sendpkt(&qpkt, pktsize); 1374abb0f93cSkardel } 1375abb0f93cSkardel 1376abb0f93cSkardel /* 1377abb0f93cSkardel * Pad out packet to a multiple of 8 octets to be sure 1378abb0f93cSkardel * receiver can handle it. 1379abb0f93cSkardel */ 1380abb0f93cSkardel while (pktsize & 7) { 13812950cc38Schristos qpkt.u.data[qsize++] = 0; 1382abb0f93cSkardel pktsize++; 1383abb0f93cSkardel } 1384abb0f93cSkardel 1385abb0f93cSkardel /* 1386abb0f93cSkardel * Get the keyid and the password if we don't have one. 1387abb0f93cSkardel */ 1388abb0f93cSkardel if (info_auth_keyid == 0) { 1389abb0f93cSkardel key_id = getkeyid("Keyid: "); 1390abb0f93cSkardel if (key_id == 0 || key_id > NTP_MAXKEY) { 1391abb0f93cSkardel fprintf(stderr, 1392abb0f93cSkardel "Invalid key identifier\n"); 1393abb0f93cSkardel return 1; 1394abb0f93cSkardel } 1395abb0f93cSkardel info_auth_keyid = key_id; 1396abb0f93cSkardel } 1397abb0f93cSkardel if (!authistrusted(info_auth_keyid)) { 13983123f114Skardel pass = getpass_keytype(info_auth_keytype); 1399abb0f93cSkardel if ('\0' == pass[0]) { 1400abb0f93cSkardel fprintf(stderr, "Invalid password\n"); 1401abb0f93cSkardel return 1; 1402abb0f93cSkardel } 1403abb0f93cSkardel authusekey(info_auth_keyid, info_auth_keytype, 1404abb0f93cSkardel (u_char *)pass); 1405abb0f93cSkardel authtrust(info_auth_keyid, 1); 1406abb0f93cSkardel } 1407abb0f93cSkardel 1408abb0f93cSkardel /* 1409abb0f93cSkardel * Do the encryption. 1410abb0f93cSkardel */ 1411abb0f93cSkardel maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1412abb0f93cSkardel if (!maclen) { 1413abb0f93cSkardel fprintf(stderr, "Key not found\n"); 1414abb0f93cSkardel return 1; 1415abb0f93cSkardel } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1416abb0f93cSkardel fprintf(stderr, 14178b8da087Schristos "%zu octet MAC, %zu expected with %zu octet digest\n", 1418abb0f93cSkardel maclen, (info_auth_hashlen + sizeof(keyid_t)), 1419abb0f93cSkardel info_auth_hashlen); 1420abb0f93cSkardel return 1; 1421abb0f93cSkardel } 1422abb0f93cSkardel 1423abb0f93cSkardel return sendpkt((char *)&qpkt, pktsize + maclen); 1424abb0f93cSkardel } 1425abb0f93cSkardel 1426abb0f93cSkardel 1427abb0f93cSkardel /* 14283123f114Skardel * show_error_msg - display the error text for a mode 6 error response. 14293123f114Skardel */ 14303123f114Skardel void 14313123f114Skardel show_error_msg( 14323123f114Skardel int m6resp, 14333123f114Skardel associd_t associd 14343123f114Skardel ) 14353123f114Skardel { 14363123f114Skardel if (numhosts > 1) 14373123f114Skardel fprintf(stderr, "server=%s ", currenthost); 14383123f114Skardel 14393123f114Skardel switch (m6resp) { 14403123f114Skardel 14413123f114Skardel case CERR_BADFMT: 14423123f114Skardel fprintf(stderr, 14433123f114Skardel "***Server reports a bad format request packet\n"); 14443123f114Skardel break; 14453123f114Skardel 14463123f114Skardel case CERR_PERMISSION: 14473123f114Skardel fprintf(stderr, 14483123f114Skardel "***Server disallowed request (authentication?)\n"); 14493123f114Skardel break; 14503123f114Skardel 14513123f114Skardel case CERR_BADOP: 14523123f114Skardel fprintf(stderr, 14533123f114Skardel "***Server reports a bad opcode in request\n"); 14543123f114Skardel break; 14553123f114Skardel 14563123f114Skardel case CERR_BADASSOC: 14573123f114Skardel fprintf(stderr, 14583123f114Skardel "***Association ID %d unknown to server\n", 14593123f114Skardel associd); 14603123f114Skardel break; 14613123f114Skardel 14623123f114Skardel case CERR_UNKNOWNVAR: 14633123f114Skardel fprintf(stderr, 14643123f114Skardel "***A request variable unknown to the server\n"); 14653123f114Skardel break; 14663123f114Skardel 14673123f114Skardel case CERR_BADVALUE: 14683123f114Skardel fprintf(stderr, 14693123f114Skardel "***Server indicates a request variable was bad\n"); 14703123f114Skardel break; 14713123f114Skardel 14723123f114Skardel case ERR_UNSPEC: 14733123f114Skardel fprintf(stderr, 14743123f114Skardel "***Server returned an unspecified error\n"); 14753123f114Skardel break; 14763123f114Skardel 14773123f114Skardel case ERR_TIMEOUT: 14783123f114Skardel fprintf(stderr, "***Request timed out\n"); 14793123f114Skardel break; 14803123f114Skardel 14813123f114Skardel case ERR_INCOMPLETE: 14823123f114Skardel fprintf(stderr, 14833123f114Skardel "***Response from server was incomplete\n"); 14843123f114Skardel break; 14853123f114Skardel 14863123f114Skardel case ERR_TOOMUCH: 14873123f114Skardel fprintf(stderr, 14883123f114Skardel "***Buffer size exceeded for returned data\n"); 14893123f114Skardel break; 14903123f114Skardel 14913123f114Skardel default: 14923123f114Skardel fprintf(stderr, 14933123f114Skardel "***Server returns unknown error code %d\n", 14943123f114Skardel m6resp); 14953123f114Skardel } 14963123f114Skardel } 14973123f114Skardel 14983123f114Skardel /* 14993123f114Skardel * doquery - send a request and process the response, displaying 15003123f114Skardel * error messages for any error responses. 1501abb0f93cSkardel */ 1502abb0f93cSkardel int 1503abb0f93cSkardel doquery( 1504abb0f93cSkardel int opcode, 15053123f114Skardel associd_t associd, 1506abb0f93cSkardel int auth, 15078b8da087Schristos size_t qsize, 15082950cc38Schristos const char *qdata, 1509abb0f93cSkardel u_short *rstatus, 15108b8da087Schristos size_t *rsize, 15113123f114Skardel const char **rdata 15123123f114Skardel ) 15133123f114Skardel { 15143123f114Skardel return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 15153123f114Skardel rsize, rdata, FALSE); 15163123f114Skardel } 15173123f114Skardel 15183123f114Skardel 15193123f114Skardel /* 15203123f114Skardel * doqueryex - send a request and process the response, optionally 15213123f114Skardel * displaying error messages for any error responses. 15223123f114Skardel */ 15233123f114Skardel int 15243123f114Skardel doqueryex( 15253123f114Skardel int opcode, 15263123f114Skardel associd_t associd, 15273123f114Skardel int auth, 15288b8da087Schristos size_t qsize, 15292950cc38Schristos const char *qdata, 15303123f114Skardel u_short *rstatus, 15318b8da087Schristos size_t *rsize, 15323123f114Skardel const char **rdata, 15333123f114Skardel int quiet 1534abb0f93cSkardel ) 1535abb0f93cSkardel { 1536abb0f93cSkardel int res; 1537abb0f93cSkardel int done; 1538abb0f93cSkardel 1539abb0f93cSkardel /* 1540abb0f93cSkardel * Check to make sure host is open 1541abb0f93cSkardel */ 1542abb0f93cSkardel if (!havehost) { 15433123f114Skardel fprintf(stderr, "***No host open, use `host' command\n"); 1544abb0f93cSkardel return -1; 1545abb0f93cSkardel } 1546abb0f93cSkardel 1547abb0f93cSkardel done = 0; 1548abb0f93cSkardel sequence++; 1549abb0f93cSkardel 1550abb0f93cSkardel again: 1551abb0f93cSkardel /* 1552abb0f93cSkardel * send a request 1553abb0f93cSkardel */ 1554abb0f93cSkardel res = sendrequest(opcode, associd, auth, qsize, qdata); 1555abb0f93cSkardel if (res != 0) 1556abb0f93cSkardel return res; 1557abb0f93cSkardel 1558abb0f93cSkardel /* 1559abb0f93cSkardel * Get the response. If we got a standard error, print a message 1560abb0f93cSkardel */ 1561abb0f93cSkardel res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 1562abb0f93cSkardel 1563abb0f93cSkardel if (res > 0) { 1564abb0f93cSkardel if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 1565abb0f93cSkardel if (res == ERR_INCOMPLETE) { 1566abb0f93cSkardel /* 1567abb0f93cSkardel * better bump the sequence so we don't 1568abb0f93cSkardel * get confused about differing fragments. 1569abb0f93cSkardel */ 1570abb0f93cSkardel sequence++; 1571abb0f93cSkardel } 1572abb0f93cSkardel done = 1; 1573abb0f93cSkardel goto again; 1574abb0f93cSkardel } 15753123f114Skardel if (!quiet) 15763123f114Skardel show_error_msg(res, associd); 15773123f114Skardel 1578abb0f93cSkardel } 1579abb0f93cSkardel return res; 1580abb0f93cSkardel } 1581abb0f93cSkardel 1582abb0f93cSkardel 1583abb0f93cSkardel #ifndef BUILD_AS_LIB 1584abb0f93cSkardel /* 1585abb0f93cSkardel * getcmds - read commands from the standard input and execute them 1586abb0f93cSkardel */ 1587abb0f93cSkardel static void 1588abb0f93cSkardel getcmds(void) 1589abb0f93cSkardel { 1590abb0f93cSkardel char * line; 1591abb0f93cSkardel int count; 1592abb0f93cSkardel 1593abb0f93cSkardel ntp_readline_init(interactive ? prompt : NULL); 1594abb0f93cSkardel 1595abb0f93cSkardel for (;;) { 1596abb0f93cSkardel line = ntp_readline(&count); 1597abb0f93cSkardel if (NULL == line) 1598abb0f93cSkardel break; 1599abb0f93cSkardel docmd(line); 1600abb0f93cSkardel free(line); 1601abb0f93cSkardel } 1602abb0f93cSkardel 1603abb0f93cSkardel ntp_readline_uninit(); 1604abb0f93cSkardel } 1605abb0f93cSkardel #endif /* !BUILD_AS_LIB */ 1606abb0f93cSkardel 1607abb0f93cSkardel 1608abb0f93cSkardel #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 1609abb0f93cSkardel /* 1610abb0f93cSkardel * abortcmd - catch interrupts and abort the current command 1611abb0f93cSkardel */ 16128b8da087Schristos static int 16138b8da087Schristos abortcmd(void) 1614abb0f93cSkardel { 1615abb0f93cSkardel if (current_output == stdout) 1616abb0f93cSkardel (void) fflush(stdout); 1617abb0f93cSkardel putc('\n', stderr); 1618abb0f93cSkardel (void) fflush(stderr); 16198b8da087Schristos if (jump) { 16208b8da087Schristos jump = 0; 162179045f13Schristos LONGJMP(interrupt_buf, 1); 16228b8da087Schristos } 16238b8da087Schristos return TRUE; 1624abb0f93cSkardel } 1625abb0f93cSkardel #endif /* !SYS_WINNT && !BUILD_AS_LIB */ 1626abb0f93cSkardel 1627abb0f93cSkardel 1628abb0f93cSkardel #ifndef BUILD_AS_LIB 1629abb0f93cSkardel /* 1630abb0f93cSkardel * docmd - decode the command line and execute a command 1631abb0f93cSkardel */ 1632abb0f93cSkardel static void 1633abb0f93cSkardel docmd( 1634abb0f93cSkardel const char *cmdline 1635abb0f93cSkardel ) 1636abb0f93cSkardel { 1637abb0f93cSkardel char *tokens[1+MAXARGS+2]; 1638abb0f93cSkardel struct parse pcmd; 1639abb0f93cSkardel int ntok; 1640abb0f93cSkardel static int i; 1641abb0f93cSkardel struct xcmd *xcmd; 1642*eabc0478Schristos int executeonly = 0; 1643abb0f93cSkardel 1644abb0f93cSkardel /* 1645abb0f93cSkardel * Tokenize the command line. If nothing on it, return. 1646abb0f93cSkardel */ 1647abb0f93cSkardel tokenize(cmdline, tokens, &ntok); 1648abb0f93cSkardel if (ntok == 0) 1649abb0f93cSkardel return; 1650abb0f93cSkardel 1651abb0f93cSkardel /* 1652*eabc0478Schristos * If command prefixed by '~', then quiet output 1653*eabc0478Schristos */ 1654*eabc0478Schristos if (*tokens[0] == '~') { 1655*eabc0478Schristos executeonly++; 1656*eabc0478Schristos tokens[0]++; 1657*eabc0478Schristos } 1658*eabc0478Schristos 1659*eabc0478Schristos /* 1660abb0f93cSkardel * Find the appropriate command description. 1661abb0f93cSkardel */ 1662abb0f93cSkardel i = findcmd(tokens[0], builtins, opcmds, &xcmd); 1663abb0f93cSkardel if (i == 0) { 1664abb0f93cSkardel (void) fprintf(stderr, "***Command `%s' unknown\n", 1665abb0f93cSkardel tokens[0]); 1666abb0f93cSkardel return; 1667abb0f93cSkardel } else if (i >= 2) { 1668abb0f93cSkardel (void) fprintf(stderr, "***Command `%s' ambiguous\n", 1669abb0f93cSkardel tokens[0]); 1670abb0f93cSkardel return; 1671abb0f93cSkardel } 1672abb0f93cSkardel 16732950cc38Schristos /* Warn about ignored extra args */ 16742950cc38Schristos for (i = MAXARGS + 1; i < ntok ; ++i) { 16752950cc38Schristos fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 16762950cc38Schristos } 16772950cc38Schristos 1678abb0f93cSkardel /* 1679abb0f93cSkardel * Save the keyword, then walk through the arguments, interpreting 1680abb0f93cSkardel * as we go. 1681abb0f93cSkardel */ 1682abb0f93cSkardel pcmd.keyword = tokens[0]; 1683abb0f93cSkardel pcmd.nargs = 0; 1684abb0f93cSkardel for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 1685abb0f93cSkardel if ((i+1) >= ntok) { 1686abb0f93cSkardel if (!(xcmd->arg[i] & OPT)) { 1687abb0f93cSkardel printusage(xcmd, stderr); 1688abb0f93cSkardel return; 1689abb0f93cSkardel } 1690abb0f93cSkardel break; 1691abb0f93cSkardel } 1692abb0f93cSkardel if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1693abb0f93cSkardel break; 1694abb0f93cSkardel if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1695abb0f93cSkardel return; 1696abb0f93cSkardel pcmd.nargs++; 1697abb0f93cSkardel } 1698abb0f93cSkardel 1699abb0f93cSkardel i++; 1700abb0f93cSkardel if (i < ntok && *tokens[i] == '>') { 1701abb0f93cSkardel char *fname; 1702abb0f93cSkardel 1703abb0f93cSkardel if (*(tokens[i]+1) != '\0') 1704abb0f93cSkardel fname = tokens[i]+1; 1705abb0f93cSkardel else if ((i+1) < ntok) 1706abb0f93cSkardel fname = tokens[i+1]; 1707abb0f93cSkardel else { 1708abb0f93cSkardel (void) fprintf(stderr, "***No file for redirect\n"); 1709abb0f93cSkardel return; 1710abb0f93cSkardel } 1711abb0f93cSkardel 1712abb0f93cSkardel current_output = fopen(fname, "w"); 1713abb0f93cSkardel if (current_output == NULL) { 1714abb0f93cSkardel (void) fprintf(stderr, "***Error opening %s: ", fname); 1715abb0f93cSkardel perror(""); 1716abb0f93cSkardel return; 1717abb0f93cSkardel } 1718*eabc0478Schristos } else if (executeonly) { /* Redirect all output to null */ 1719*eabc0478Schristos current_output = fopen(PATH_DEVNULL, "w"); 1720*eabc0478Schristos if (current_output == NULL) { 1721*eabc0478Schristos (void) fprintf(stderr, "***Error redirecting output to /dev/null: "); 1722*eabc0478Schristos perror(""); 1723*eabc0478Schristos return; 1724*eabc0478Schristos } 1725abb0f93cSkardel } else { 1726abb0f93cSkardel current_output = stdout; 1727abb0f93cSkardel } 1728abb0f93cSkardel 172979045f13Schristos if (interactive) { 173079045f13Schristos if ( ! SETJMP(interrupt_buf)) { 173179045f13Schristos jump = 1; 1732abb0f93cSkardel (xcmd->handler)(&pcmd, current_output); 173379045f13Schristos jump = 0; 173479045f13Schristos } else { 173579045f13Schristos fflush(current_output); 173679045f13Schristos fputs("\n >>> command aborted <<<\n", stderr); 173779045f13Schristos fflush(stderr); 1738abb0f93cSkardel } 17392950cc38Schristos 174079045f13Schristos } else { 174179045f13Schristos jump = 0; 174279045f13Schristos (xcmd->handler)(&pcmd, current_output); 174379045f13Schristos } 174479045f13Schristos if ((NULL != current_output) && (stdout != current_output)) { 174579045f13Schristos (void)fclose(current_output); 174679045f13Schristos current_output = NULL; 174779045f13Schristos } 1748abb0f93cSkardel } 1749abb0f93cSkardel 1750abb0f93cSkardel 1751abb0f93cSkardel /* 1752abb0f93cSkardel * tokenize - turn a command line into tokens 1753abb0f93cSkardel * 1754abb0f93cSkardel * SK: Modified to allow a quoted string 1755abb0f93cSkardel * 1756abb0f93cSkardel * HMS: If the first character of the first token is a ':' then (after 1757abb0f93cSkardel * eating inter-token whitespace) the 2nd token is the rest of the line. 1758abb0f93cSkardel */ 1759abb0f93cSkardel 1760abb0f93cSkardel static void 1761abb0f93cSkardel tokenize( 1762abb0f93cSkardel const char *line, 1763abb0f93cSkardel char **tokens, 1764abb0f93cSkardel int *ntok 1765abb0f93cSkardel ) 1766abb0f93cSkardel { 1767abb0f93cSkardel register const char *cp; 1768abb0f93cSkardel register char *sp; 1769abb0f93cSkardel static char tspace[MAXLINE]; 1770abb0f93cSkardel 1771abb0f93cSkardel sp = tspace; 1772abb0f93cSkardel cp = line; 1773abb0f93cSkardel for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 1774abb0f93cSkardel tokens[*ntok] = sp; 1775abb0f93cSkardel 1776abb0f93cSkardel /* Skip inter-token whitespace */ 1777abb0f93cSkardel while (ISSPACE(*cp)) 1778abb0f93cSkardel cp++; 1779abb0f93cSkardel 1780abb0f93cSkardel /* If we're at EOL we're done */ 1781abb0f93cSkardel if (ISEOL(*cp)) 1782abb0f93cSkardel break; 1783abb0f93cSkardel 1784abb0f93cSkardel /* If this is the 2nd token and the first token begins 1785abb0f93cSkardel * with a ':', then just grab to EOL. 1786abb0f93cSkardel */ 1787abb0f93cSkardel 1788abb0f93cSkardel if (*ntok == 1 && tokens[0][0] == ':') { 1789abb0f93cSkardel do { 1790ea66d795Schristos if (sp - tspace >= MAXLINE) 1791ea66d795Schristos goto toobig; 1792abb0f93cSkardel *sp++ = *cp++; 1793abb0f93cSkardel } while (!ISEOL(*cp)); 1794abb0f93cSkardel } 1795abb0f93cSkardel 1796abb0f93cSkardel /* Check if this token begins with a double quote. 1797abb0f93cSkardel * If yes, continue reading till the next double quote 1798abb0f93cSkardel */ 1799abb0f93cSkardel else if (*cp == '\"') { 1800abb0f93cSkardel ++cp; 1801abb0f93cSkardel do { 1802ea66d795Schristos if (sp - tspace >= MAXLINE) 1803ea66d795Schristos goto toobig; 1804abb0f93cSkardel *sp++ = *cp++; 1805abb0f93cSkardel } while ((*cp != '\"') && !ISEOL(*cp)); 1806abb0f93cSkardel /* HMS: a missing closing " should be an error */ 1807abb0f93cSkardel } 1808abb0f93cSkardel else { 1809abb0f93cSkardel do { 1810ea66d795Schristos if (sp - tspace >= MAXLINE) 1811ea66d795Schristos goto toobig; 1812abb0f93cSkardel *sp++ = *cp++; 1813abb0f93cSkardel } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1814abb0f93cSkardel /* HMS: Why check for a " in the previous line? */ 1815abb0f93cSkardel } 1816abb0f93cSkardel 1817ea66d795Schristos if (sp - tspace >= MAXLINE) 1818ea66d795Schristos goto toobig; 1819abb0f93cSkardel *sp++ = '\0'; 1820abb0f93cSkardel } 1821ea66d795Schristos return; 1822ea66d795Schristos 1823ea66d795Schristos toobig: 1824ea66d795Schristos *ntok = 0; 1825ea66d795Schristos fprintf(stderr, 1826ea66d795Schristos "***Line `%s' is too big\n", 1827ea66d795Schristos line); 1828ea66d795Schristos return; 1829abb0f93cSkardel } 1830abb0f93cSkardel 1831abb0f93cSkardel 1832abb0f93cSkardel /* 1833abb0f93cSkardel * getarg - interpret an argument token 1834abb0f93cSkardel */ 1835abb0f93cSkardel static int 1836abb0f93cSkardel getarg( 18372950cc38Schristos const char *str, 1838abb0f93cSkardel int code, 1839abb0f93cSkardel arg_v *argp 1840abb0f93cSkardel ) 1841abb0f93cSkardel { 18422950cc38Schristos u_long ul; 1843abb0f93cSkardel 1844abb0f93cSkardel switch (code & ~OPT) { 1845abb0f93cSkardel case NTP_STR: 1846abb0f93cSkardel argp->string = str; 1847abb0f93cSkardel break; 18482950cc38Schristos 1849abb0f93cSkardel case NTP_ADD: 18502950cc38Schristos if (!getnetnum(str, &argp->netnum, NULL, 0)) 1851abb0f93cSkardel return 0; 1852abb0f93cSkardel break; 18532950cc38Schristos 1854abb0f93cSkardel case NTP_UINT: 18552950cc38Schristos if ('&' == str[0]) { 18562950cc38Schristos if (!atouint(&str[1], &ul)) { 18572950cc38Schristos fprintf(stderr, 18582950cc38Schristos "***Association index `%s' invalid/undecodable\n", 18592950cc38Schristos str); 1860abb0f93cSkardel return 0; 1861abb0f93cSkardel } 18622950cc38Schristos if (0 == numassoc) { 18632950cc38Schristos dogetassoc(stdout); 18642950cc38Schristos if (0 == numassoc) { 18652950cc38Schristos fprintf(stderr, 18662950cc38Schristos "***No associations found, `%s' unknown\n", 18672950cc38Schristos str); 1868abb0f93cSkardel return 0; 1869abb0f93cSkardel } 1870abb0f93cSkardel } 18712950cc38Schristos ul = min(ul, numassoc); 18722950cc38Schristos argp->uval = assoc_cache[ul - 1].assid; 1873abb0f93cSkardel break; 1874abb0f93cSkardel } 18752950cc38Schristos if (!atouint(str, &argp->uval)) { 18762950cc38Schristos fprintf(stderr, "***Illegal unsigned value %s\n", 18772950cc38Schristos str); 1878abb0f93cSkardel return 0; 1879abb0f93cSkardel } 1880abb0f93cSkardel break; 18812950cc38Schristos 18822950cc38Schristos case NTP_INT: 18832950cc38Schristos if (!atoint(str, &argp->ival)) { 18842950cc38Schristos fprintf(stderr, "***Illegal integer value %s\n", 18852950cc38Schristos str); 18862950cc38Schristos return 0; 18872950cc38Schristos } 18882950cc38Schristos break; 18892950cc38Schristos 1890abb0f93cSkardel case IP_VERSION: 18912950cc38Schristos if (!strcmp("-6", str)) { 1892abb0f93cSkardel argp->ival = 6; 18932950cc38Schristos } else if (!strcmp("-4", str)) { 1894abb0f93cSkardel argp->ival = 4; 18952950cc38Schristos } else { 18962950cc38Schristos fprintf(stderr, "***Version must be either 4 or 6\n"); 1897abb0f93cSkardel return 0; 1898abb0f93cSkardel } 1899abb0f93cSkardel break; 1900abb0f93cSkardel } 1901abb0f93cSkardel 1902abb0f93cSkardel return 1; 1903abb0f93cSkardel } 1904abb0f93cSkardel #endif /* !BUILD_AS_LIB */ 1905abb0f93cSkardel 1906abb0f93cSkardel 1907abb0f93cSkardel /* 1908abb0f93cSkardel * findcmd - find a command in a command description table 1909abb0f93cSkardel */ 1910abb0f93cSkardel static int 1911abb0f93cSkardel findcmd( 19122950cc38Schristos const char * str, 1913abb0f93cSkardel struct xcmd * clist1, 1914abb0f93cSkardel struct xcmd * clist2, 1915abb0f93cSkardel struct xcmd ** cmd 1916abb0f93cSkardel ) 1917abb0f93cSkardel { 19182950cc38Schristos struct xcmd *cl; 19198b8da087Schristos size_t clen; 1920abb0f93cSkardel int nmatch; 1921abb0f93cSkardel struct xcmd *nearmatch = NULL; 1922abb0f93cSkardel struct xcmd *clist; 1923abb0f93cSkardel 1924abb0f93cSkardel clen = strlen(str); 1925abb0f93cSkardel nmatch = 0; 1926abb0f93cSkardel if (clist1 != 0) 1927abb0f93cSkardel clist = clist1; 1928abb0f93cSkardel else if (clist2 != 0) 1929abb0f93cSkardel clist = clist2; 1930abb0f93cSkardel else 1931abb0f93cSkardel return 0; 1932abb0f93cSkardel 1933abb0f93cSkardel again: 1934abb0f93cSkardel for (cl = clist; cl->keyword != 0; cl++) { 1935abb0f93cSkardel /* do a first character check, for efficiency */ 1936abb0f93cSkardel if (*str != *(cl->keyword)) 1937abb0f93cSkardel continue; 1938abb0f93cSkardel if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 1939abb0f93cSkardel /* 1940abb0f93cSkardel * Could be extact match, could be approximate. 1941abb0f93cSkardel * Is exact if the length of the keyword is the 1942abb0f93cSkardel * same as the str. 1943abb0f93cSkardel */ 1944abb0f93cSkardel if (*((cl->keyword) + clen) == '\0') { 1945abb0f93cSkardel *cmd = cl; 1946abb0f93cSkardel return 1; 1947abb0f93cSkardel } 1948abb0f93cSkardel nmatch++; 1949abb0f93cSkardel nearmatch = cl; 1950abb0f93cSkardel } 1951abb0f93cSkardel } 1952abb0f93cSkardel 1953abb0f93cSkardel /* 1954abb0f93cSkardel * See if there is more to do. If so, go again. Sorry about the 1955abb0f93cSkardel * goto, too much looking at BSD sources... 1956abb0f93cSkardel */ 1957abb0f93cSkardel if (clist == clist1 && clist2 != 0) { 1958abb0f93cSkardel clist = clist2; 1959abb0f93cSkardel goto again; 1960abb0f93cSkardel } 1961abb0f93cSkardel 1962abb0f93cSkardel /* 1963abb0f93cSkardel * If we got extactly 1 near match, use it, else return number 1964abb0f93cSkardel * of matches. 1965abb0f93cSkardel */ 1966abb0f93cSkardel if (nmatch == 1) { 1967abb0f93cSkardel *cmd = nearmatch; 1968abb0f93cSkardel return 1; 1969abb0f93cSkardel } 1970abb0f93cSkardel return nmatch; 1971abb0f93cSkardel } 1972abb0f93cSkardel 1973abb0f93cSkardel 1974abb0f93cSkardel /* 1975abb0f93cSkardel * getnetnum - given a host name, return its net number 1976abb0f93cSkardel * and (optional) full name 1977abb0f93cSkardel */ 1978abb0f93cSkardel int 1979abb0f93cSkardel getnetnum( 1980abb0f93cSkardel const char *hname, 1981abb0f93cSkardel sockaddr_u *num, 1982abb0f93cSkardel char *fullhost, 1983abb0f93cSkardel int af 1984abb0f93cSkardel ) 1985abb0f93cSkardel { 1986abb0f93cSkardel struct addrinfo hints, *ai = NULL; 1987abb0f93cSkardel 19883123f114Skardel ZERO(hints); 1989abb0f93cSkardel hints.ai_flags = AI_CANONNAME; 1990abb0f93cSkardel #ifdef AI_ADDRCONFIG 1991abb0f93cSkardel hints.ai_flags |= AI_ADDRCONFIG; 1992abb0f93cSkardel #endif 1993abb0f93cSkardel 19943123f114Skardel /* 19953123f114Skardel * decodenetnum only works with addresses, but handles syntax 19963123f114Skardel * that getaddrinfo doesn't: [2001::1]:1234 19973123f114Skardel */ 1998abb0f93cSkardel if (decodenetnum(hname, num)) { 19993123f114Skardel if (fullhost != NULL) 20003123f114Skardel getnameinfo(&num->sa, SOCKLEN(num), fullhost, 20013123f114Skardel LENHOSTNAME, NULL, 0, 0); 2002abb0f93cSkardel return 1; 2003abb0f93cSkardel } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 20042950cc38Schristos INSIST(sizeof(*num) >= ai->ai_addrlen); 20053123f114Skardel memcpy(num, ai->ai_addr, ai->ai_addrlen); 20063123f114Skardel if (fullhost != NULL) { 20072950cc38Schristos if (ai->ai_canonname != NULL) 20082950cc38Schristos strlcpy(fullhost, ai->ai_canonname, 20093123f114Skardel LENHOSTNAME); 20102950cc38Schristos else 20113123f114Skardel getnameinfo(&num->sa, SOCKLEN(num), 20123123f114Skardel fullhost, LENHOSTNAME, NULL, 20133123f114Skardel 0, 0); 2014abb0f93cSkardel } 20152950cc38Schristos freeaddrinfo(ai); 20163123f114Skardel return 1; 20173123f114Skardel } 20183123f114Skardel fprintf(stderr, "***Can't find host %s\n", hname); 20193123f114Skardel 20203123f114Skardel return 0; 2021abb0f93cSkardel } 2022abb0f93cSkardel 20232950cc38Schristos 2024abb0f93cSkardel /* 2025abb0f93cSkardel * nntohost - convert network number to host name. This routine enforces 2026abb0f93cSkardel * the showhostnames setting. 2027abb0f93cSkardel */ 20283123f114Skardel const char * 2029abb0f93cSkardel nntohost( 2030abb0f93cSkardel sockaddr_u *netnum 2031abb0f93cSkardel ) 2032abb0f93cSkardel { 20333123f114Skardel return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 20343123f114Skardel } 20353123f114Skardel 20363123f114Skardel 20373123f114Skardel /* 20383123f114Skardel * nntohost_col - convert network number to host name in fixed width. 20393123f114Skardel * This routine enforces the showhostnames setting. 20403123f114Skardel * When displaying hostnames longer than the width, 20413123f114Skardel * the first part of the hostname is displayed. When 20423123f114Skardel * displaying numeric addresses longer than the width, 20433123f114Skardel * Such as IPv6 addresses, the caller decides whether 20443123f114Skardel * the first or last of the numeric address is used. 20453123f114Skardel */ 20463123f114Skardel const char * 20473123f114Skardel nntohost_col( 20483123f114Skardel sockaddr_u * addr, 20493123f114Skardel size_t width, 20503123f114Skardel int preserve_lowaddrbits 20513123f114Skardel ) 20523123f114Skardel { 20533123f114Skardel const char * out; 20543123f114Skardel 20552950cc38Schristos if (!showhostnames || SOCK_UNSPEC(addr)) { 20563123f114Skardel if (preserve_lowaddrbits) 20573123f114Skardel out = trunc_left(stoa(addr), width); 2058abb0f93cSkardel else 20593123f114Skardel out = trunc_right(stoa(addr), width); 20603123f114Skardel } else if (ISREFCLOCKADR(addr)) { 20613123f114Skardel out = refnumtoa(addr); 20623123f114Skardel } else { 20633123f114Skardel out = trunc_right(socktohost(addr), width); 20643123f114Skardel } 20653123f114Skardel return out; 2066abb0f93cSkardel } 2067abb0f93cSkardel 2068abb0f93cSkardel 2069abb0f93cSkardel /* 20702950cc38Schristos * nntohostp() is the same as nntohost() plus a :port suffix 20712950cc38Schristos */ 20722950cc38Schristos const char * 20732950cc38Schristos nntohostp( 20742950cc38Schristos sockaddr_u *netnum 20752950cc38Schristos ) 20762950cc38Schristos { 20772950cc38Schristos const char * hostn; 20782950cc38Schristos char * buf; 20792950cc38Schristos 20802950cc38Schristos if (!showhostnames || SOCK_UNSPEC(netnum)) 20812950cc38Schristos return sptoa(netnum); 20822950cc38Schristos else if (ISREFCLOCKADR(netnum)) 20832950cc38Schristos return refnumtoa(netnum); 20842950cc38Schristos 20852950cc38Schristos hostn = socktohost(netnum); 20862950cc38Schristos LIB_GETBUF(buf); 20872950cc38Schristos snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 20882950cc38Schristos 20892950cc38Schristos return buf; 20902950cc38Schristos } 20912950cc38Schristos 20922950cc38Schristos /* 2093abb0f93cSkardel * rtdatetolfp - decode an RT-11 date into an l_fp 2094abb0f93cSkardel */ 2095abb0f93cSkardel static int 2096abb0f93cSkardel rtdatetolfp( 2097abb0f93cSkardel char *str, 2098abb0f93cSkardel l_fp *lfp 2099abb0f93cSkardel ) 2100abb0f93cSkardel { 2101abb0f93cSkardel register char *cp; 2102abb0f93cSkardel register int i; 2103abb0f93cSkardel struct calendar cal; 2104abb0f93cSkardel char buf[4]; 2105abb0f93cSkardel 2106abb0f93cSkardel cal.yearday = 0; 2107abb0f93cSkardel 2108abb0f93cSkardel /* 2109abb0f93cSkardel * An RT-11 date looks like: 2110abb0f93cSkardel * 2111abb0f93cSkardel * d[d]-Mth-y[y] hh:mm:ss 2112abb0f93cSkardel * 2113abb0f93cSkardel * (No docs, but assume 4-digit years are also legal...) 2114abb0f93cSkardel * 2115abb0f93cSkardel * d[d]-Mth-y[y[y[y]]] hh:mm:ss 2116abb0f93cSkardel */ 2117abb0f93cSkardel cp = str; 21184eea345dSchristos if (!isdigit(pgetc(cp))) { 2119abb0f93cSkardel if (*cp == '-') { 2120abb0f93cSkardel /* 2121abb0f93cSkardel * Catch special case 2122abb0f93cSkardel */ 2123abb0f93cSkardel L_CLR(lfp); 2124abb0f93cSkardel return 1; 2125abb0f93cSkardel } 2126abb0f93cSkardel return 0; 2127abb0f93cSkardel } 2128abb0f93cSkardel 2129abb0f93cSkardel cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 21304eea345dSchristos if (isdigit(pgetc(cp))) { 2131abb0f93cSkardel cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2132abb0f93cSkardel cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 2133abb0f93cSkardel } 2134abb0f93cSkardel 2135abb0f93cSkardel if (*cp++ != '-') 2136abb0f93cSkardel return 0; 2137abb0f93cSkardel 2138abb0f93cSkardel for (i = 0; i < 3; i++) 2139abb0f93cSkardel buf[i] = *cp++; 2140abb0f93cSkardel buf[3] = '\0'; 2141abb0f93cSkardel 2142abb0f93cSkardel for (i = 0; i < 12; i++) 2143abb0f93cSkardel if (STREQ(buf, months[i])) 2144abb0f93cSkardel break; 2145abb0f93cSkardel if (i == 12) 2146abb0f93cSkardel return 0; 2147abb0f93cSkardel cal.month = (u_char)(i + 1); 2148abb0f93cSkardel 2149abb0f93cSkardel if (*cp++ != '-') 2150abb0f93cSkardel return 0; 2151abb0f93cSkardel 21524eea345dSchristos if (!isdigit(pgetc(cp))) 2153abb0f93cSkardel return 0; 2154abb0f93cSkardel cal.year = (u_short)(*cp++ - '0'); 21554eea345dSchristos if (isdigit(pgetc(cp))) { 2156abb0f93cSkardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2157abb0f93cSkardel cal.year = (u_short)(*cp++ - '0'); 2158abb0f93cSkardel } 21594eea345dSchristos if (isdigit(pgetc(cp))) { 2160abb0f93cSkardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2161abb0f93cSkardel cal.year = (u_short)(cal.year + *cp++ - '0'); 2162abb0f93cSkardel } 21634eea345dSchristos if (isdigit(pgetc(cp))) { 2164abb0f93cSkardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2165abb0f93cSkardel cal.year = (u_short)(cal.year + *cp++ - '0'); 2166abb0f93cSkardel } 2167abb0f93cSkardel 2168abb0f93cSkardel /* 2169abb0f93cSkardel * Catch special case. If cal.year == 0 this is a zero timestamp. 2170abb0f93cSkardel */ 2171abb0f93cSkardel if (cal.year == 0) { 2172abb0f93cSkardel L_CLR(lfp); 2173abb0f93cSkardel return 1; 2174abb0f93cSkardel } 2175abb0f93cSkardel 21764eea345dSchristos if (*cp++ != ' ' || !isdigit(pgetc(cp))) 2177abb0f93cSkardel return 0; 2178abb0f93cSkardel cal.hour = (u_char)(*cp++ - '0'); 21794eea345dSchristos if (isdigit(pgetc(cp))) { 2180abb0f93cSkardel cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2181abb0f93cSkardel cal.hour = (u_char)(cal.hour + *cp++ - '0'); 2182abb0f93cSkardel } 2183abb0f93cSkardel 21844eea345dSchristos if (*cp++ != ':' || !isdigit(pgetc(cp))) 2185abb0f93cSkardel return 0; 2186abb0f93cSkardel cal.minute = (u_char)(*cp++ - '0'); 21874eea345dSchristos if (isdigit(pgetc(cp))) { 2188abb0f93cSkardel cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2189abb0f93cSkardel cal.minute = (u_char)(cal.minute + *cp++ - '0'); 2190abb0f93cSkardel } 2191abb0f93cSkardel 21924eea345dSchristos if (*cp++ != ':' || !isdigit(pgetc(cp))) 2193abb0f93cSkardel return 0; 2194abb0f93cSkardel cal.second = (u_char)(*cp++ - '0'); 21954eea345dSchristos if (isdigit(pgetc(cp))) { 2196abb0f93cSkardel cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2197abb0f93cSkardel cal.second = (u_char)(cal.second + *cp++ - '0'); 2198abb0f93cSkardel } 2199abb0f93cSkardel 2200abb0f93cSkardel /* 2201abb0f93cSkardel * For RT-11, 1972 seems to be the pivot year 2202abb0f93cSkardel */ 2203abb0f93cSkardel if (cal.year < 72) 2204abb0f93cSkardel cal.year += 2000; 2205abb0f93cSkardel if (cal.year < 100) 2206abb0f93cSkardel cal.year += 1900; 2207abb0f93cSkardel 2208*eabc0478Schristos /* check for complaints from 'caltontp()'! */ 2209abb0f93cSkardel lfp->l_uf = 0; 2210*eabc0478Schristos errno = 0; 2211*eabc0478Schristos lfp->l_ui = caltontp(&cal); 2212*eabc0478Schristos return (errno == 0); 2213abb0f93cSkardel } 2214abb0f93cSkardel 2215abb0f93cSkardel 2216abb0f93cSkardel /* 2217abb0f93cSkardel * decodets - decode a timestamp into an l_fp format number, with 2218abb0f93cSkardel * consideration of fuzzball formats. 2219abb0f93cSkardel */ 2220abb0f93cSkardel int 2221abb0f93cSkardel decodets( 2222abb0f93cSkardel char *str, 2223abb0f93cSkardel l_fp *lfp 2224abb0f93cSkardel ) 2225abb0f93cSkardel { 22263123f114Skardel char *cp; 22273123f114Skardel char buf[30]; 22283123f114Skardel size_t b; 22293123f114Skardel 2230abb0f93cSkardel /* 2231abb0f93cSkardel * If it starts with a 0x, decode as hex. 2232abb0f93cSkardel */ 2233abb0f93cSkardel if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2234abb0f93cSkardel return hextolfp(str+2, lfp); 2235abb0f93cSkardel 2236abb0f93cSkardel /* 2237abb0f93cSkardel * If it starts with a '"', try it as an RT-11 date. 2238abb0f93cSkardel */ 2239abb0f93cSkardel if (*str == '"') { 22403123f114Skardel cp = str + 1; 22413123f114Skardel b = 0; 22423123f114Skardel while ('"' != *cp && '\0' != *cp && 22433123f114Skardel b < COUNTOF(buf) - 1) 22443123f114Skardel buf[b++] = *cp++; 22453123f114Skardel buf[b] = '\0'; 2246abb0f93cSkardel return rtdatetolfp(buf, lfp); 2247abb0f93cSkardel } 2248abb0f93cSkardel 2249abb0f93cSkardel /* 2250abb0f93cSkardel * Might still be hex. Check out the first character. Talk 2251abb0f93cSkardel * about heuristics! 2252abb0f93cSkardel */ 2253abb0f93cSkardel if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2254abb0f93cSkardel return hextolfp(str, lfp); 2255abb0f93cSkardel 2256abb0f93cSkardel /* 2257abb0f93cSkardel * Try it as a decimal. If this fails, try as an unquoted 2258abb0f93cSkardel * RT-11 date. This code should go away eventually. 2259abb0f93cSkardel */ 2260abb0f93cSkardel if (atolfp(str, lfp)) 2261abb0f93cSkardel return 1; 2262abb0f93cSkardel 2263abb0f93cSkardel return rtdatetolfp(str, lfp); 2264abb0f93cSkardel } 2265abb0f93cSkardel 2266abb0f93cSkardel 2267abb0f93cSkardel /* 2268abb0f93cSkardel * decodetime - decode a time value. It should be in milliseconds 2269abb0f93cSkardel */ 2270abb0f93cSkardel int 2271abb0f93cSkardel decodetime( 2272abb0f93cSkardel char *str, 2273abb0f93cSkardel l_fp *lfp 2274abb0f93cSkardel ) 2275abb0f93cSkardel { 2276abb0f93cSkardel return mstolfp(str, lfp); 2277abb0f93cSkardel } 2278abb0f93cSkardel 2279abb0f93cSkardel 2280abb0f93cSkardel /* 2281abb0f93cSkardel * decodeint - decode an integer 2282abb0f93cSkardel */ 2283abb0f93cSkardel int 2284abb0f93cSkardel decodeint( 2285abb0f93cSkardel char *str, 2286abb0f93cSkardel long *val 2287abb0f93cSkardel ) 2288abb0f93cSkardel { 2289abb0f93cSkardel if (*str == '0') { 2290abb0f93cSkardel if (*(str+1) == 'x' || *(str+1) == 'X') 2291abb0f93cSkardel return hextoint(str+2, (u_long *)val); 2292abb0f93cSkardel return octtoint(str, (u_long *)val); 2293abb0f93cSkardel } 2294abb0f93cSkardel return atoint(str, val); 2295abb0f93cSkardel } 2296abb0f93cSkardel 2297abb0f93cSkardel 2298abb0f93cSkardel /* 2299abb0f93cSkardel * decodeuint - decode an unsigned integer 2300abb0f93cSkardel */ 2301abb0f93cSkardel int 2302abb0f93cSkardel decodeuint( 2303abb0f93cSkardel char *str, 2304abb0f93cSkardel u_long *val 2305abb0f93cSkardel ) 2306abb0f93cSkardel { 2307abb0f93cSkardel if (*str == '0') { 2308abb0f93cSkardel if (*(str + 1) == 'x' || *(str + 1) == 'X') 2309abb0f93cSkardel return (hextoint(str + 2, val)); 2310abb0f93cSkardel return (octtoint(str, val)); 2311abb0f93cSkardel } 2312abb0f93cSkardel return (atouint(str, val)); 2313abb0f93cSkardel } 2314abb0f93cSkardel 2315abb0f93cSkardel 2316abb0f93cSkardel /* 2317abb0f93cSkardel * decodearr - decode an array of time values 2318abb0f93cSkardel */ 2319abb0f93cSkardel static int 2320abb0f93cSkardel decodearr( 23214eea345dSchristos char *cp, 2322abb0f93cSkardel int *narr, 23234eea345dSchristos l_fp *lfpa, 23244eea345dSchristos int amax 2325abb0f93cSkardel ) 2326abb0f93cSkardel { 23274eea345dSchristos char *bp; 2328abb0f93cSkardel char buf[60]; 2329abb0f93cSkardel 2330abb0f93cSkardel *narr = 0; 2331abb0f93cSkardel 23324eea345dSchristos while (*narr < amax && *cp) { 23334eea345dSchristos if (isspace(pgetc(cp))) { 23344eea345dSchristos do 23354eea345dSchristos ++cp; 23364eea345dSchristos while (*cp && isspace(pgetc(cp))); 23374eea345dSchristos } else { 2338abb0f93cSkardel bp = buf; 23394eea345dSchristos do { 23404eea345dSchristos if (bp != (buf + sizeof(buf) - 1)) 23414eea345dSchristos *bp++ = *cp; 23424eea345dSchristos ++cp; 23434eea345dSchristos } while (*cp && !isspace(pgetc(cp))); 23444eea345dSchristos *bp = '\0'; 2345abb0f93cSkardel 23464eea345dSchristos if (!decodetime(buf, lfpa)) 2347abb0f93cSkardel return 0; 23484eea345dSchristos ++(*narr); 23494eea345dSchristos ++lfpa; 23504eea345dSchristos } 2351abb0f93cSkardel } 2352abb0f93cSkardel return 1; 2353abb0f93cSkardel } 2354abb0f93cSkardel 2355abb0f93cSkardel 2356abb0f93cSkardel /* 2357abb0f93cSkardel * Finally, the built in command handlers 2358abb0f93cSkardel */ 2359abb0f93cSkardel 2360abb0f93cSkardel /* 2361abb0f93cSkardel * help - tell about commands, or details of a particular command 2362abb0f93cSkardel */ 2363abb0f93cSkardel static void 2364abb0f93cSkardel help( 2365abb0f93cSkardel struct parse *pcmd, 2366abb0f93cSkardel FILE *fp 2367abb0f93cSkardel ) 2368abb0f93cSkardel { 2369abb0f93cSkardel struct xcmd *xcp = NULL; /* quiet warning */ 23702950cc38Schristos const char *cmd; 2371abb0f93cSkardel const char *list[100]; 23723123f114Skardel size_t word, words; 23733123f114Skardel size_t row, rows; 23743123f114Skardel size_t col, cols; 23753123f114Skardel size_t length; 2376abb0f93cSkardel 2377abb0f93cSkardel if (pcmd->nargs == 0) { 2378abb0f93cSkardel words = 0; 23793123f114Skardel for (xcp = builtins; xcp->keyword != NULL; xcp++) { 23802950cc38Schristos if (*(xcp->keyword) != '?' && 23812950cc38Schristos words < COUNTOF(list)) 2382abb0f93cSkardel list[words++] = xcp->keyword; 2383abb0f93cSkardel } 23843123f114Skardel for (xcp = opcmds; xcp->keyword != NULL; xcp++) 23852950cc38Schristos if (words < COUNTOF(list)) 2386abb0f93cSkardel list[words++] = xcp->keyword; 2387abb0f93cSkardel 23882950cc38Schristos qsort((void *)list, words, sizeof(list[0]), helpsort); 2389abb0f93cSkardel col = 0; 2390abb0f93cSkardel for (word = 0; word < words; word++) { 23913123f114Skardel length = strlen(list[word]); 23923123f114Skardel col = max(col, length); 2393abb0f93cSkardel } 2394abb0f93cSkardel 2395abb0f93cSkardel cols = SCREENWIDTH / ++col; 2396abb0f93cSkardel rows = (words + cols - 1) / cols; 2397abb0f93cSkardel 23983123f114Skardel fprintf(fp, "ntpq commands:\n"); 2399abb0f93cSkardel 2400abb0f93cSkardel for (row = 0; row < rows; row++) { 24013123f114Skardel for (word = row; word < words; word += rows) 24022950cc38Schristos fprintf(fp, "%-*.*s", (int)col, 24032950cc38Schristos (int)col - 1, list[word]); 24043123f114Skardel fprintf(fp, "\n"); 2405abb0f93cSkardel } 2406abb0f93cSkardel } else { 2407abb0f93cSkardel cmd = pcmd->argval[0].string; 2408abb0f93cSkardel words = findcmd(cmd, builtins, opcmds, &xcp); 2409abb0f93cSkardel if (words == 0) { 24103123f114Skardel fprintf(stderr, 2411abb0f93cSkardel "Command `%s' is unknown\n", cmd); 2412abb0f93cSkardel return; 2413abb0f93cSkardel } else if (words >= 2) { 24143123f114Skardel fprintf(stderr, 2415abb0f93cSkardel "Command `%s' is ambiguous\n", cmd); 2416abb0f93cSkardel return; 2417abb0f93cSkardel } 24183123f114Skardel fprintf(fp, "function: %s\n", xcp->comment); 2419abb0f93cSkardel printusage(xcp, fp); 2420abb0f93cSkardel } 2421abb0f93cSkardel } 2422abb0f93cSkardel 2423abb0f93cSkardel 2424abb0f93cSkardel /* 2425abb0f93cSkardel * helpsort - do hostname qsort comparisons 2426abb0f93cSkardel */ 2427abb0f93cSkardel static int 2428abb0f93cSkardel helpsort( 2429abb0f93cSkardel const void *t1, 2430abb0f93cSkardel const void *t2 2431abb0f93cSkardel ) 2432abb0f93cSkardel { 24333123f114Skardel const char * const * name1 = t1; 24343123f114Skardel const char * const * name2 = t2; 2435abb0f93cSkardel 2436abb0f93cSkardel return strcmp(*name1, *name2); 2437abb0f93cSkardel } 2438abb0f93cSkardel 2439abb0f93cSkardel 2440abb0f93cSkardel /* 2441abb0f93cSkardel * printusage - print usage information for a command 2442abb0f93cSkardel */ 2443abb0f93cSkardel static void 2444abb0f93cSkardel printusage( 2445abb0f93cSkardel struct xcmd *xcp, 2446abb0f93cSkardel FILE *fp 2447abb0f93cSkardel ) 2448abb0f93cSkardel { 2449abb0f93cSkardel register int i; 2450abb0f93cSkardel 24512950cc38Schristos /* XXX: Do we need to warn about extra args here too? */ 24522950cc38Schristos 2453abb0f93cSkardel (void) fprintf(fp, "usage: %s", xcp->keyword); 2454abb0f93cSkardel for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 2455abb0f93cSkardel if (xcp->arg[i] & OPT) 2456abb0f93cSkardel (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 2457abb0f93cSkardel else 2458abb0f93cSkardel (void) fprintf(fp, " %s", xcp->desc[i]); 2459abb0f93cSkardel } 2460abb0f93cSkardel (void) fprintf(fp, "\n"); 2461abb0f93cSkardel } 2462abb0f93cSkardel 2463abb0f93cSkardel 2464abb0f93cSkardel /* 2465abb0f93cSkardel * timeout - set time out time 2466abb0f93cSkardel */ 2467abb0f93cSkardel static void 2468abb0f93cSkardel timeout( 2469abb0f93cSkardel struct parse *pcmd, 2470abb0f93cSkardel FILE *fp 2471abb0f93cSkardel ) 2472abb0f93cSkardel { 2473abb0f93cSkardel int val; 2474abb0f93cSkardel 2475abb0f93cSkardel if (pcmd->nargs == 0) { 2476abb0f93cSkardel val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 2477abb0f93cSkardel (void) fprintf(fp, "primary timeout %d ms\n", val); 2478abb0f93cSkardel } else { 2479abb0f93cSkardel tvout.tv_sec = pcmd->argval[0].uval / 1000; 2480abb0f93cSkardel tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 2481abb0f93cSkardel * 1000; 2482abb0f93cSkardel } 2483abb0f93cSkardel } 2484abb0f93cSkardel 2485abb0f93cSkardel 2486abb0f93cSkardel /* 2487abb0f93cSkardel * auth_delay - set delay for auth requests 2488abb0f93cSkardel */ 2489abb0f93cSkardel static void 2490abb0f93cSkardel auth_delay( 2491abb0f93cSkardel struct parse *pcmd, 2492abb0f93cSkardel FILE *fp 2493abb0f93cSkardel ) 2494abb0f93cSkardel { 2495abb0f93cSkardel int isneg; 2496abb0f93cSkardel u_long val; 2497abb0f93cSkardel 2498abb0f93cSkardel if (pcmd->nargs == 0) { 2499abb0f93cSkardel val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 2500abb0f93cSkardel (void) fprintf(fp, "delay %lu ms\n", val); 2501abb0f93cSkardel } else { 2502abb0f93cSkardel if (pcmd->argval[0].ival < 0) { 2503abb0f93cSkardel isneg = 1; 2504abb0f93cSkardel val = (u_long)(-pcmd->argval[0].ival); 2505abb0f93cSkardel } else { 2506abb0f93cSkardel isneg = 0; 2507abb0f93cSkardel val = (u_long)pcmd->argval[0].ival; 2508abb0f93cSkardel } 2509abb0f93cSkardel 2510abb0f93cSkardel delay_time.l_ui = val / 1000; 2511abb0f93cSkardel val %= 1000; 2512abb0f93cSkardel delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 2513abb0f93cSkardel 2514abb0f93cSkardel if (isneg) 2515abb0f93cSkardel L_NEG(&delay_time); 2516abb0f93cSkardel } 2517abb0f93cSkardel } 2518abb0f93cSkardel 2519abb0f93cSkardel 2520abb0f93cSkardel /* 2521abb0f93cSkardel * host - set the host we are dealing with. 2522abb0f93cSkardel */ 2523abb0f93cSkardel static void 2524abb0f93cSkardel host( 2525abb0f93cSkardel struct parse *pcmd, 2526abb0f93cSkardel FILE *fp 2527abb0f93cSkardel ) 2528abb0f93cSkardel { 2529abb0f93cSkardel int i; 2530abb0f93cSkardel 2531abb0f93cSkardel if (pcmd->nargs == 0) { 2532abb0f93cSkardel if (havehost) 2533abb0f93cSkardel (void) fprintf(fp, "current host is %s\n", 2534abb0f93cSkardel currenthost); 2535abb0f93cSkardel else 2536abb0f93cSkardel (void) fprintf(fp, "no current host\n"); 2537abb0f93cSkardel return; 2538abb0f93cSkardel } 2539abb0f93cSkardel 2540abb0f93cSkardel i = 0; 2541abb0f93cSkardel ai_fam_templ = ai_fam_default; 2542abb0f93cSkardel if (pcmd->nargs == 2) { 2543abb0f93cSkardel if (!strcmp("-4", pcmd->argval[i].string)) 2544abb0f93cSkardel ai_fam_templ = AF_INET; 2545abb0f93cSkardel else if (!strcmp("-6", pcmd->argval[i].string)) 2546abb0f93cSkardel ai_fam_templ = AF_INET6; 2547abb0f93cSkardel else 25482950cc38Schristos goto no_change; 2549abb0f93cSkardel i = 1; 2550abb0f93cSkardel } 25512950cc38Schristos if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 25522950cc38Schristos fprintf(fp, "current host set to %s\n", currenthost); 2553abb0f93cSkardel } else { 25542950cc38Schristos no_change: 2555abb0f93cSkardel if (havehost) 25562950cc38Schristos fprintf(fp, "current host remains %s\n", 2557abb0f93cSkardel currenthost); 2558abb0f93cSkardel else 25592950cc38Schristos fprintf(fp, "still no current host\n"); 2560abb0f93cSkardel } 2561abb0f93cSkardel } 2562abb0f93cSkardel 2563abb0f93cSkardel 2564abb0f93cSkardel /* 2565abb0f93cSkardel * poll - do one (or more) polls of the host via NTP 2566abb0f93cSkardel */ 2567abb0f93cSkardel /*ARGSUSED*/ 2568abb0f93cSkardel static void 2569abb0f93cSkardel ntp_poll( 2570abb0f93cSkardel struct parse *pcmd, 2571abb0f93cSkardel FILE *fp 2572abb0f93cSkardel ) 2573abb0f93cSkardel { 2574abb0f93cSkardel (void) fprintf(fp, "poll not implemented yet\n"); 2575abb0f93cSkardel } 2576abb0f93cSkardel 2577abb0f93cSkardel 2578abb0f93cSkardel /* 257968dbbb44Schristos * showdrefid2str - return a string explanation of the value of drefid 258068dbbb44Schristos */ 258168dbbb44Schristos static const char * 258268dbbb44Schristos showdrefid2str(void) 258368dbbb44Schristos { 258468dbbb44Schristos switch (drefid) { 258568dbbb44Schristos case REFID_HASH: 258668dbbb44Schristos return "hash"; 258768dbbb44Schristos case REFID_IPV4: 258868dbbb44Schristos return "ipv4"; 258968dbbb44Schristos default: 259068dbbb44Schristos return "Unknown"; 259168dbbb44Schristos } 259268dbbb44Schristos } 259368dbbb44Schristos 259468dbbb44Schristos 259568dbbb44Schristos /* 259668dbbb44Schristos * drefid - display/change "display hash" 259768dbbb44Schristos */ 259868dbbb44Schristos static void 259968dbbb44Schristos showdrefid( 260068dbbb44Schristos struct parse *pcmd, 260168dbbb44Schristos FILE *fp 260268dbbb44Schristos ) 260368dbbb44Schristos { 260468dbbb44Schristos if (pcmd->nargs == 0) { 260568dbbb44Schristos (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 260668dbbb44Schristos return; 260768dbbb44Schristos } else if (STREQ(pcmd->argval[0].string, "hash")) { 260868dbbb44Schristos drefid = REFID_HASH; 260968dbbb44Schristos } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 261068dbbb44Schristos drefid = REFID_IPV4; 261168dbbb44Schristos } else { 261268dbbb44Schristos (void) fprintf(fp, "What?\n"); 261368dbbb44Schristos return; 261468dbbb44Schristos } 261568dbbb44Schristos (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 261668dbbb44Schristos } 261768dbbb44Schristos 261868dbbb44Schristos 261968dbbb44Schristos /* 2620abb0f93cSkardel * keyid - get a keyid to use for authenticating requests 2621abb0f93cSkardel */ 2622abb0f93cSkardel static void 2623abb0f93cSkardel keyid( 2624abb0f93cSkardel struct parse *pcmd, 2625abb0f93cSkardel FILE *fp 2626abb0f93cSkardel ) 2627abb0f93cSkardel { 2628abb0f93cSkardel if (pcmd->nargs == 0) { 2629abb0f93cSkardel if (info_auth_keyid == 0) 2630abb0f93cSkardel (void) fprintf(fp, "no keyid defined\n"); 2631abb0f93cSkardel else 2632abb0f93cSkardel (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 2633abb0f93cSkardel } else { 2634abb0f93cSkardel /* allow zero so that keyid can be cleared. */ 2635abb0f93cSkardel if(pcmd->argval[0].uval > NTP_MAXKEY) 2636abb0f93cSkardel (void) fprintf(fp, "Invalid key identifier\n"); 2637abb0f93cSkardel info_auth_keyid = pcmd->argval[0].uval; 2638abb0f93cSkardel } 2639abb0f93cSkardel } 2640abb0f93cSkardel 2641abb0f93cSkardel /* 2642abb0f93cSkardel * keytype - get type of key to use for authenticating requests 2643abb0f93cSkardel */ 2644abb0f93cSkardel static void 2645abb0f93cSkardel keytype( 2646abb0f93cSkardel struct parse *pcmd, 2647abb0f93cSkardel FILE *fp 2648abb0f93cSkardel ) 2649abb0f93cSkardel { 2650abb0f93cSkardel const char * digest_name; 2651abb0f93cSkardel size_t digest_len; 2652abb0f93cSkardel int key_type; 2653abb0f93cSkardel 2654abb0f93cSkardel if (!pcmd->nargs) { 26552f3ccb49Skardel fprintf(fp, "keytype is %s with %lu octet digests\n", 2656abb0f93cSkardel keytype_name(info_auth_keytype), 26573123f114Skardel (u_long)info_auth_hashlen); 2658abb0f93cSkardel return; 2659abb0f93cSkardel } 2660abb0f93cSkardel 2661abb0f93cSkardel digest_name = pcmd->argval[0].string; 2662abb0f93cSkardel digest_len = 0; 2663abb0f93cSkardel key_type = keytype_from_text(digest_name, &digest_len); 2664abb0f93cSkardel 2665abb0f93cSkardel if (!key_type) { 26665d681e99Schristos fprintf(fp, "keytype is not valid. " 2667abb0f93cSkardel #ifdef OPENSSL 26685d681e99Schristos "Type \"help keytype\" for the available digest types.\n"); 2669abb0f93cSkardel #else 26705d681e99Schristos "Only \"md5\" is available.\n"); 2671abb0f93cSkardel #endif 2672abb0f93cSkardel return; 2673abb0f93cSkardel } 2674abb0f93cSkardel 2675abb0f93cSkardel info_auth_keytype = key_type; 2676abb0f93cSkardel info_auth_hashlen = digest_len; 2677abb0f93cSkardel } 2678abb0f93cSkardel 2679abb0f93cSkardel 2680abb0f93cSkardel /* 2681abb0f93cSkardel * passwd - get an authentication key 2682abb0f93cSkardel */ 2683abb0f93cSkardel /*ARGSUSED*/ 2684abb0f93cSkardel static void 2685abb0f93cSkardel passwd( 2686abb0f93cSkardel struct parse *pcmd, 2687abb0f93cSkardel FILE *fp 2688abb0f93cSkardel ) 2689abb0f93cSkardel { 26902950cc38Schristos const char *pass; 2691abb0f93cSkardel 2692abb0f93cSkardel if (info_auth_keyid == 0) { 26932950cc38Schristos info_auth_keyid = getkeyid("Keyid: "); 26942950cc38Schristos if (info_auth_keyid == 0) { 26952950cc38Schristos (void)fprintf(fp, "Keyid must be defined\n"); 2696abb0f93cSkardel return; 2697abb0f93cSkardel } 2698abb0f93cSkardel } 26993123f114Skardel if (pcmd->nargs >= 1) 27003123f114Skardel pass = pcmd->argval[0].string; 2701abb0f93cSkardel else { 27023123f114Skardel pass = getpass_keytype(info_auth_keytype); 27033123f114Skardel if ('\0' == pass[0]) { 27043123f114Skardel fprintf(fp, "Password unchanged\n"); 27053123f114Skardel return; 27063123f114Skardel } 27073123f114Skardel } 27082950cc38Schristos authusekey(info_auth_keyid, info_auth_keytype, 27092950cc38Schristos (const u_char *)pass); 2710abb0f93cSkardel authtrust(info_auth_keyid, 1); 2711abb0f93cSkardel } 2712abb0f93cSkardel 2713abb0f93cSkardel 2714abb0f93cSkardel /* 2715abb0f93cSkardel * hostnames - set the showhostnames flag 2716abb0f93cSkardel */ 2717abb0f93cSkardel static void 2718abb0f93cSkardel hostnames( 2719abb0f93cSkardel struct parse *pcmd, 2720abb0f93cSkardel FILE *fp 2721abb0f93cSkardel ) 2722abb0f93cSkardel { 2723abb0f93cSkardel if (pcmd->nargs == 0) { 2724abb0f93cSkardel if (showhostnames) 2725abb0f93cSkardel (void) fprintf(fp, "hostnames being shown\n"); 2726abb0f93cSkardel else 2727abb0f93cSkardel (void) fprintf(fp, "hostnames not being shown\n"); 2728abb0f93cSkardel } else { 2729abb0f93cSkardel if (STREQ(pcmd->argval[0].string, "yes")) 2730abb0f93cSkardel showhostnames = 1; 2731abb0f93cSkardel else if (STREQ(pcmd->argval[0].string, "no")) 2732abb0f93cSkardel showhostnames = 0; 2733abb0f93cSkardel else 2734abb0f93cSkardel (void)fprintf(stderr, "What?\n"); 2735abb0f93cSkardel } 2736abb0f93cSkardel } 2737abb0f93cSkardel 2738abb0f93cSkardel 2739abb0f93cSkardel 2740abb0f93cSkardel /* 2741abb0f93cSkardel * setdebug - set/change debugging level 2742abb0f93cSkardel */ 2743abb0f93cSkardel static void 2744abb0f93cSkardel setdebug( 2745abb0f93cSkardel struct parse *pcmd, 2746abb0f93cSkardel FILE *fp 2747abb0f93cSkardel ) 2748abb0f93cSkardel { 2749abb0f93cSkardel if (pcmd->nargs == 0) { 2750abb0f93cSkardel (void) fprintf(fp, "debug level is %d\n", debug); 2751abb0f93cSkardel return; 2752abb0f93cSkardel } else if (STREQ(pcmd->argval[0].string, "no")) { 2753abb0f93cSkardel debug = 0; 2754abb0f93cSkardel } else if (STREQ(pcmd->argval[0].string, "more")) { 2755abb0f93cSkardel debug++; 2756abb0f93cSkardel } else if (STREQ(pcmd->argval[0].string, "less")) { 2757abb0f93cSkardel debug--; 2758abb0f93cSkardel } else { 2759abb0f93cSkardel (void) fprintf(fp, "What?\n"); 2760abb0f93cSkardel return; 2761abb0f93cSkardel } 2762abb0f93cSkardel (void) fprintf(fp, "debug level set to %d\n", debug); 2763abb0f93cSkardel } 2764abb0f93cSkardel 2765abb0f93cSkardel 2766abb0f93cSkardel /* 2767abb0f93cSkardel * quit - stop this nonsense 2768abb0f93cSkardel */ 2769abb0f93cSkardel /*ARGSUSED*/ 2770abb0f93cSkardel static void 2771abb0f93cSkardel quit( 2772abb0f93cSkardel struct parse *pcmd, 2773abb0f93cSkardel FILE *fp 2774abb0f93cSkardel ) 2775abb0f93cSkardel { 2776abb0f93cSkardel if (havehost) 2777abb0f93cSkardel closesocket(sockfd); /* cleanliness next to godliness */ 2778abb0f93cSkardel exit(0); 2779abb0f93cSkardel } 2780abb0f93cSkardel 2781abb0f93cSkardel 2782abb0f93cSkardel /* 2783abb0f93cSkardel * version - print the current version number 2784abb0f93cSkardel */ 2785abb0f93cSkardel /*ARGSUSED*/ 2786abb0f93cSkardel static void 2787abb0f93cSkardel version( 2788abb0f93cSkardel struct parse *pcmd, 2789abb0f93cSkardel FILE *fp 2790abb0f93cSkardel ) 2791abb0f93cSkardel { 2792abb0f93cSkardel 2793abb0f93cSkardel (void) fprintf(fp, "%s\n", Version); 2794abb0f93cSkardel return; 2795abb0f93cSkardel } 2796abb0f93cSkardel 2797abb0f93cSkardel 2798abb0f93cSkardel /* 2799abb0f93cSkardel * raw - set raw mode output 2800abb0f93cSkardel */ 2801abb0f93cSkardel /*ARGSUSED*/ 2802abb0f93cSkardel static void 2803abb0f93cSkardel raw( 2804abb0f93cSkardel struct parse *pcmd, 2805abb0f93cSkardel FILE *fp 2806abb0f93cSkardel ) 2807abb0f93cSkardel { 2808abb0f93cSkardel rawmode = 1; 2809abb0f93cSkardel (void) fprintf(fp, "Output set to raw\n"); 2810abb0f93cSkardel } 2811abb0f93cSkardel 2812abb0f93cSkardel 2813abb0f93cSkardel /* 2814abb0f93cSkardel * cooked - set cooked mode output 2815abb0f93cSkardel */ 2816abb0f93cSkardel /*ARGSUSED*/ 2817abb0f93cSkardel static void 2818abb0f93cSkardel cooked( 2819abb0f93cSkardel struct parse *pcmd, 2820abb0f93cSkardel FILE *fp 2821abb0f93cSkardel ) 2822abb0f93cSkardel { 2823abb0f93cSkardel rawmode = 0; 2824abb0f93cSkardel (void) fprintf(fp, "Output set to cooked\n"); 2825abb0f93cSkardel return; 2826abb0f93cSkardel } 2827abb0f93cSkardel 2828abb0f93cSkardel 2829abb0f93cSkardel /* 2830abb0f93cSkardel * authenticate - always authenticate requests to this host 2831abb0f93cSkardel */ 2832abb0f93cSkardel static void 2833abb0f93cSkardel authenticate( 2834abb0f93cSkardel struct parse *pcmd, 2835abb0f93cSkardel FILE *fp 2836abb0f93cSkardel ) 2837abb0f93cSkardel { 2838abb0f93cSkardel if (pcmd->nargs == 0) { 2839abb0f93cSkardel if (always_auth) { 2840abb0f93cSkardel (void) fprintf(fp, 2841abb0f93cSkardel "authenticated requests being sent\n"); 2842abb0f93cSkardel } else 2843abb0f93cSkardel (void) fprintf(fp, 2844abb0f93cSkardel "unauthenticated requests being sent\n"); 2845abb0f93cSkardel } else { 2846abb0f93cSkardel if (STREQ(pcmd->argval[0].string, "yes")) { 2847abb0f93cSkardel always_auth = 1; 2848abb0f93cSkardel } else if (STREQ(pcmd->argval[0].string, "no")) { 2849abb0f93cSkardel always_auth = 0; 2850abb0f93cSkardel } else 2851abb0f93cSkardel (void)fprintf(stderr, "What?\n"); 2852abb0f93cSkardel } 2853abb0f93cSkardel } 2854abb0f93cSkardel 2855abb0f93cSkardel 2856abb0f93cSkardel /* 2857abb0f93cSkardel * ntpversion - choose the NTP version to use 2858abb0f93cSkardel */ 2859abb0f93cSkardel static void 2860abb0f93cSkardel ntpversion( 2861abb0f93cSkardel struct parse *pcmd, 2862abb0f93cSkardel FILE *fp 2863abb0f93cSkardel ) 2864abb0f93cSkardel { 2865abb0f93cSkardel if (pcmd->nargs == 0) { 2866abb0f93cSkardel (void) fprintf(fp, 2867abb0f93cSkardel "NTP version being claimed is %d\n", pktversion); 2868abb0f93cSkardel } else { 2869abb0f93cSkardel if (pcmd->argval[0].uval < NTP_OLDVERSION 2870abb0f93cSkardel || pcmd->argval[0].uval > NTP_VERSION) { 2871abb0f93cSkardel (void) fprintf(stderr, "versions %d to %d, please\n", 2872abb0f93cSkardel NTP_OLDVERSION, NTP_VERSION); 2873abb0f93cSkardel } else { 2874abb0f93cSkardel pktversion = (u_char) pcmd->argval[0].uval; 2875abb0f93cSkardel } 2876abb0f93cSkardel } 2877abb0f93cSkardel } 2878abb0f93cSkardel 2879abb0f93cSkardel 2880058f310fSchristos static void __attribute__((__format__(__printf__, 1, 0))) 2881058f310fSchristos vwarning(const char *fmt, va_list ap) 2882058f310fSchristos { 2883058f310fSchristos int serrno = errno; 2884058f310fSchristos (void) fprintf(stderr, "%s: ", progname); 2885058f310fSchristos vfprintf(stderr, fmt, ap); 28868b8da087Schristos (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2887058f310fSchristos } 2888058f310fSchristos 2889abb0f93cSkardel /* 2890abb0f93cSkardel * warning - print a warning message 2891abb0f93cSkardel */ 2892058f310fSchristos static void __attribute__((__format__(__printf__, 1, 2))) 2893abb0f93cSkardel warning( 2894abb0f93cSkardel const char *fmt, 2895058f310fSchristos ... 2896abb0f93cSkardel ) 2897abb0f93cSkardel { 2898058f310fSchristos va_list ap; 2899058f310fSchristos va_start(ap, fmt); 2900058f310fSchristos vwarning(fmt, ap); 2901058f310fSchristos va_end(ap); 2902abb0f93cSkardel } 2903abb0f93cSkardel 2904abb0f93cSkardel 2905abb0f93cSkardel /* 2906abb0f93cSkardel * error - print a message and exit 2907abb0f93cSkardel */ 2908058f310fSchristos static void __attribute__((__format__(__printf__, 1, 2))) 2909abb0f93cSkardel error( 2910abb0f93cSkardel const char *fmt, 2911058f310fSchristos ... 2912abb0f93cSkardel ) 2913abb0f93cSkardel { 2914058f310fSchristos va_list ap; 2915058f310fSchristos va_start(ap, fmt); 2916058f310fSchristos vwarning(fmt, ap); 2917058f310fSchristos va_end(ap); 2918abb0f93cSkardel exit(1); 2919abb0f93cSkardel } 2920abb0f93cSkardel /* 2921abb0f93cSkardel * getkeyid - prompt the user for a keyid to use 2922abb0f93cSkardel */ 2923abb0f93cSkardel static u_long 2924abb0f93cSkardel getkeyid( 2925abb0f93cSkardel const char *keyprompt 2926abb0f93cSkardel ) 2927abb0f93cSkardel { 29283123f114Skardel int c; 2929abb0f93cSkardel FILE *fi; 2930abb0f93cSkardel char pbuf[20]; 29313123f114Skardel size_t i; 29323123f114Skardel size_t ilim; 2933abb0f93cSkardel 2934abb0f93cSkardel #ifndef SYS_WINNT 2935abb0f93cSkardel if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 2936abb0f93cSkardel #else 2937abb0f93cSkardel if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 2938abb0f93cSkardel #endif /* SYS_WINNT */ 2939abb0f93cSkardel fi = stdin; 2940abb0f93cSkardel else 2941abb0f93cSkardel setbuf(fi, (char *)NULL); 2942abb0f93cSkardel fprintf(stderr, "%s", keyprompt); fflush(stderr); 29433123f114Skardel for (i = 0, ilim = COUNTOF(pbuf) - 1; 29443123f114Skardel i < ilim && (c = getc(fi)) != '\n' && c != EOF; 29453123f114Skardel ) 29463123f114Skardel pbuf[i++] = (char)c; 29473123f114Skardel pbuf[i] = '\0'; 2948abb0f93cSkardel if (fi != stdin) 2949abb0f93cSkardel fclose(fi); 2950abb0f93cSkardel 2951abb0f93cSkardel return (u_long) atoi(pbuf); 2952abb0f93cSkardel } 2953abb0f93cSkardel 2954abb0f93cSkardel 2955abb0f93cSkardel /* 2956abb0f93cSkardel * atoascii - printable-ize possibly ascii data using the character 2957abb0f93cSkardel * transformations cat -v uses. 2958abb0f93cSkardel */ 2959abb0f93cSkardel static void 2960abb0f93cSkardel atoascii( 2961abb0f93cSkardel const char *in, 2962abb0f93cSkardel size_t in_octets, 2963abb0f93cSkardel char *out, 2964abb0f93cSkardel size_t out_octets 2965abb0f93cSkardel ) 2966abb0f93cSkardel { 29672950cc38Schristos const u_char * pchIn; 2968abb0f93cSkardel const u_char * pchInLimit; 29692950cc38Schristos u_char * pchOut; 29702950cc38Schristos u_char c; 2971abb0f93cSkardel 2972abb0f93cSkardel pchIn = (const u_char *)in; 2973abb0f93cSkardel pchInLimit = pchIn + in_octets; 2974abb0f93cSkardel pchOut = (u_char *)out; 2975abb0f93cSkardel 2976abb0f93cSkardel if (NULL == pchIn) { 2977abb0f93cSkardel if (0 < out_octets) 2978abb0f93cSkardel *pchOut = '\0'; 2979abb0f93cSkardel return; 2980abb0f93cSkardel } 2981abb0f93cSkardel 2982abb0f93cSkardel #define ONEOUT(c) \ 2983abb0f93cSkardel do { \ 2984abb0f93cSkardel if (0 == --out_octets) { \ 2985abb0f93cSkardel *pchOut = '\0'; \ 2986abb0f93cSkardel return; \ 2987abb0f93cSkardel } \ 2988abb0f93cSkardel *pchOut++ = (c); \ 2989abb0f93cSkardel } while (0) 2990abb0f93cSkardel 2991abb0f93cSkardel for ( ; pchIn < pchInLimit; pchIn++) { 2992abb0f93cSkardel c = *pchIn; 2993abb0f93cSkardel if ('\0' == c) 2994abb0f93cSkardel break; 2995abb0f93cSkardel if (c & 0x80) { 2996abb0f93cSkardel ONEOUT('M'); 2997abb0f93cSkardel ONEOUT('-'); 2998abb0f93cSkardel c &= 0x7f; 2999abb0f93cSkardel } 3000abb0f93cSkardel if (c < ' ') { 3001abb0f93cSkardel ONEOUT('^'); 3002abb0f93cSkardel ONEOUT((u_char)(c + '@')); 3003abb0f93cSkardel } else if (0x7f == c) { 3004abb0f93cSkardel ONEOUT('^'); 3005abb0f93cSkardel ONEOUT('?'); 3006abb0f93cSkardel } else 3007abb0f93cSkardel ONEOUT(c); 3008abb0f93cSkardel } 3009abb0f93cSkardel ONEOUT('\0'); 3010abb0f93cSkardel 3011abb0f93cSkardel #undef ONEOUT 3012abb0f93cSkardel } 3013abb0f93cSkardel 3014abb0f93cSkardel 3015abb0f93cSkardel /* 3016abb0f93cSkardel * makeascii - print possibly ascii data using the character 3017abb0f93cSkardel * transformations that cat -v uses. 3018abb0f93cSkardel */ 30193123f114Skardel void 3020abb0f93cSkardel makeascii( 30218b8da087Schristos size_t length, 30223123f114Skardel const char *data, 3023abb0f93cSkardel FILE *fp 3024abb0f93cSkardel ) 3025abb0f93cSkardel { 30263123f114Skardel const u_char *data_u_char; 30273123f114Skardel const u_char *cp; 30283123f114Skardel int c; 3029abb0f93cSkardel 30303123f114Skardel data_u_char = (const u_char *)data; 30313123f114Skardel 30323123f114Skardel for (cp = data_u_char; cp < data_u_char + length; cp++) { 3033abb0f93cSkardel c = (int)*cp; 3034abb0f93cSkardel if (c & 0x80) { 3035abb0f93cSkardel putc('M', fp); 3036abb0f93cSkardel putc('-', fp); 3037abb0f93cSkardel c &= 0x7f; 3038abb0f93cSkardel } 3039abb0f93cSkardel 3040abb0f93cSkardel if (c < ' ') { 3041abb0f93cSkardel putc('^', fp); 3042abb0f93cSkardel putc(c + '@', fp); 3043abb0f93cSkardel } else if (0x7f == c) { 3044abb0f93cSkardel putc('^', fp); 3045abb0f93cSkardel putc('?', fp); 3046abb0f93cSkardel } else 3047abb0f93cSkardel putc(c, fp); 3048abb0f93cSkardel } 3049abb0f93cSkardel } 3050abb0f93cSkardel 3051abb0f93cSkardel 3052abb0f93cSkardel /* 3053abb0f93cSkardel * asciize - same thing as makeascii except add a newline 3054abb0f93cSkardel */ 3055abb0f93cSkardel void 3056abb0f93cSkardel asciize( 3057abb0f93cSkardel int length, 3058abb0f93cSkardel char *data, 3059abb0f93cSkardel FILE *fp 3060abb0f93cSkardel ) 3061abb0f93cSkardel { 3062abb0f93cSkardel makeascii(length, data, fp); 3063abb0f93cSkardel putc('\n', fp); 3064abb0f93cSkardel } 3065abb0f93cSkardel 3066abb0f93cSkardel 3067abb0f93cSkardel /* 30683123f114Skardel * truncate string to fit clipping excess at end. 30693123f114Skardel * "too long" -> "too l" 30703123f114Skardel * Used for hostnames. 30713123f114Skardel */ 30723123f114Skardel const char * 30733123f114Skardel trunc_right( 30743123f114Skardel const char * src, 30753123f114Skardel size_t width 30763123f114Skardel ) 30773123f114Skardel { 30783123f114Skardel size_t sl; 30793123f114Skardel char * out; 30803123f114Skardel 30813123f114Skardel 30823123f114Skardel sl = strlen(src); 30833123f114Skardel if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 30843123f114Skardel LIB_GETBUF(out); 30853123f114Skardel memcpy(out, src, width); 30863123f114Skardel out[width] = '\0'; 30873123f114Skardel 30883123f114Skardel return out; 30893123f114Skardel } 30903123f114Skardel 30913123f114Skardel return src; 30923123f114Skardel } 30933123f114Skardel 30943123f114Skardel 30953123f114Skardel /* 30963123f114Skardel * truncate string to fit by preserving right side and using '_' to hint 30973123f114Skardel * "too long" -> "_long" 30983123f114Skardel * Used for local IPv6 addresses, where low bits differentiate. 30993123f114Skardel */ 31003123f114Skardel const char * 31013123f114Skardel trunc_left( 31023123f114Skardel const char * src, 31033123f114Skardel size_t width 31043123f114Skardel ) 31053123f114Skardel { 31063123f114Skardel size_t sl; 31073123f114Skardel char * out; 31083123f114Skardel 31093123f114Skardel 31103123f114Skardel sl = strlen(src); 31113123f114Skardel if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 31123123f114Skardel LIB_GETBUF(out); 31133123f114Skardel out[0] = '_'; 31143123f114Skardel memcpy(&out[1], &src[sl + 1 - width], width); 31153123f114Skardel 31163123f114Skardel return out; 31173123f114Skardel } 31183123f114Skardel 31193123f114Skardel return src; 31203123f114Skardel } 31213123f114Skardel 31223123f114Skardel 31233123f114Skardel /* 3124abb0f93cSkardel * Some circular buffer space 3125abb0f93cSkardel */ 3126abb0f93cSkardel #define CBLEN 80 3127abb0f93cSkardel #define NUMCB 6 3128abb0f93cSkardel 3129abb0f93cSkardel char circ_buf[NUMCB][CBLEN]; 3130abb0f93cSkardel int nextcb = 0; 3131abb0f93cSkardel 313279045f13Schristos /* -------------------------------------------------------------------- 313379045f13Schristos * Parsing a response value list 313479045f13Schristos * 313579045f13Schristos * This sounds simple (and it actually is not really hard) but it has 313679045f13Schristos * some pitfalls. 313779045f13Schristos * 313879045f13Schristos * Rule1: CR/LF is never embedded in an item 313979045f13Schristos * Rule2: An item is a name, optionally followed by a value 314079045f13Schristos * Rule3: The value is separated from the name by a '=' 314179045f13Schristos * Rule4: Items are separated by a ',' 314279045f13Schristos * Rule5: values can be quoted by '"', in which case they can contain 314379045f13Schristos * arbitrary characters but *not* '"', CR and LF 314479045f13Schristos * 314579045f13Schristos * There are a few implementations out there that require a somewhat 314679045f13Schristos * relaxed attitude when parsing a value list, especially since we want 314779045f13Schristos * to copy names and values into local buffers. If these would overflow, 314879045f13Schristos * the item should be skipped without terminating the parsing sequence. 314979045f13Schristos * 315079045f13Schristos * Also, for empty values, there might be a '=' after the name or not; 315179045f13Schristos * we treat that equivalent. 315279045f13Schristos * 315379045f13Schristos * Parsing an item definitely breaks on a CR/LF. If an item is not 315479045f13Schristos * followed by a comma (','), parsing stops. In the middle of a quoted 315579045f13Schristos * character sequence CR/LF terminates the parsing finally without 315679045f13Schristos * returning a value. 315779045f13Schristos * 315879045f13Schristos * White space and other noise is ignored when parsing the data buffer; 315979045f13Schristos * only CR, LF, ',', '=' and '"' are characters with a special meaning. 316079045f13Schristos * White space is stripped from the names and values *after* working 316179045f13Schristos * through the buffer, before making the local copies. If whitespace 316279045f13Schristos * stripping results in an empty name, parsing resumes. 316379045f13Schristos */ 316479045f13Schristos 316579045f13Schristos /* 316679045f13Schristos * nextvar parsing helpers 316779045f13Schristos */ 316879045f13Schristos 316979045f13Schristos /* predicate: allowed chars inside a quoted string */ 317079045f13Schristos static int/*BOOL*/ cp_qschar(int ch) 317179045f13Schristos { 317279045f13Schristos return ch && (ch != '"' && ch != '\r' && ch != '\n'); 317379045f13Schristos } 317479045f13Schristos 317579045f13Schristos /* predicate: allowed chars inside an unquoted string */ 317679045f13Schristos static int/*BOOL*/ cp_uqchar(int ch) 317779045f13Schristos { 317879045f13Schristos return ch && (ch != ',' && ch != '"' && ch != '\r' && ch != '\n'); 317979045f13Schristos } 318079045f13Schristos 318179045f13Schristos /* predicate: allowed chars inside a value name */ 318279045f13Schristos static int/*BOOL*/ cp_namechar(int ch) 318379045f13Schristos { 318479045f13Schristos return ch && (ch != ',' && ch != '=' && ch != '\r' && ch != '\n'); 318579045f13Schristos } 318679045f13Schristos 318779045f13Schristos /* predicate: characters *between* list items. We're relaxed here. */ 318879045f13Schristos static int/*BOOL*/ cp_ivspace(int ch) 318979045f13Schristos { 319079045f13Schristos return (ch == ',' || (ch > 0 && ch <= ' ')); 319179045f13Schristos } 319279045f13Schristos 319379045f13Schristos /* get current character (or NUL when on end) */ 319479045f13Schristos static inline int 319579045f13Schristos pf_getch( 319679045f13Schristos const char ** datap, 319779045f13Schristos const char * endp 319879045f13Schristos ) 319979045f13Schristos { 320079045f13Schristos return (*datap != endp) 320179045f13Schristos ? *(const unsigned char*)*datap 320279045f13Schristos : '\0'; 320379045f13Schristos } 320479045f13Schristos 320579045f13Schristos /* get next character (or NUL when on end) */ 320679045f13Schristos static inline int 320779045f13Schristos pf_nextch( 320879045f13Schristos const char ** datap, 320979045f13Schristos const char * endp 321079045f13Schristos ) 321179045f13Schristos { 321279045f13Schristos return (*datap != endp && ++(*datap) != endp) 321379045f13Schristos ? *(const unsigned char*)*datap 321479045f13Schristos : '\0'; 321579045f13Schristos } 321679045f13Schristos 321779045f13Schristos static size_t 321879045f13Schristos str_strip( 321979045f13Schristos const char ** datap, 322079045f13Schristos size_t len 322179045f13Schristos ) 322279045f13Schristos { 322379045f13Schristos static const char empty[] = ""; 322479045f13Schristos 322579045f13Schristos if (*datap && len) { 322679045f13Schristos const char * cpl = *datap; 322779045f13Schristos const char * cpr = cpl + len; 322879045f13Schristos 322979045f13Schristos while (cpl != cpr && *(const unsigned char*)cpl <= ' ') 323079045f13Schristos ++cpl; 323179045f13Schristos while (cpl != cpr && *(const unsigned char*)(cpr - 1) <= ' ') 323279045f13Schristos --cpr; 323379045f13Schristos *datap = cpl; 323479045f13Schristos len = (size_t)(cpr - cpl); 323579045f13Schristos } else { 323679045f13Schristos *datap = empty; 323779045f13Schristos len = 0; 323879045f13Schristos } 323979045f13Schristos return len; 324079045f13Schristos } 324179045f13Schristos 324279045f13Schristos static void 324379045f13Schristos pf_error( 324479045f13Schristos const char * what, 324579045f13Schristos const char * where, 324679045f13Schristos const char * whend 324779045f13Schristos ) 324879045f13Schristos { 324979045f13Schristos # ifndef BUILD_AS_LIB 325079045f13Schristos 325179045f13Schristos FILE * ofp = (debug > 0) ? stdout : stderr; 325279045f13Schristos size_t len = (size_t)(whend - where); 325379045f13Schristos 325479045f13Schristos if (len > 50) /* *must* fit into an 'int'! */ 325579045f13Schristos len = 50; 325679045f13Schristos fprintf(ofp, "nextvar: %s: '%.*s'\n", 325779045f13Schristos what, (int)len, where); 325879045f13Schristos 325979045f13Schristos # else /*defined(BUILD_AS_LIB)*/ 326079045f13Schristos 326179045f13Schristos UNUSED_ARG(what); 326279045f13Schristos UNUSED_ARG(where); 326379045f13Schristos UNUSED_ARG(whend); 326479045f13Schristos 326579045f13Schristos # endif /*defined(BUILD_AS_LIB)*/ 326679045f13Schristos } 326779045f13Schristos 3268abb0f93cSkardel /* 3269abb0f93cSkardel * nextvar - find the next variable in the buffer 3270abb0f93cSkardel */ 327179045f13Schristos int/*BOOL*/ 3272abb0f93cSkardel nextvar( 32738b8da087Schristos size_t *datalen, 32743123f114Skardel const char **datap, 3275abb0f93cSkardel char **vname, 3276abb0f93cSkardel char **vvalue 3277abb0f93cSkardel ) 3278abb0f93cSkardel { 327979045f13Schristos enum PState { sDone, sInit, sName, sValU, sValQ }; 3280abb0f93cSkardel 328179045f13Schristos static char name[MAXVARLEN], value[MAXVALLEN]; 3282abb0f93cSkardel 328379045f13Schristos const char *cp, *cpend; 328479045f13Schristos const char *np, *vp; 328579045f13Schristos size_t nlen, vlen; 328679045f13Schristos int ch; 328779045f13Schristos enum PState st; 3288abb0f93cSkardel 328979045f13Schristos cpend = *datap + *datalen; 3290abb0f93cSkardel 329179045f13Schristos again: 329279045f13Schristos np = vp = NULL; 329379045f13Schristos nlen = vlen = 0; 3294abb0f93cSkardel 329579045f13Schristos st = sInit; 329679045f13Schristos ch = pf_getch(datap, cpend); 329779045f13Schristos 329879045f13Schristos while (st != sDone) { 329979045f13Schristos switch (st) 330079045f13Schristos { 330179045f13Schristos case sInit: /* handle inter-item chars */ 330279045f13Schristos while (cp_ivspace(ch)) 330379045f13Schristos ch = pf_nextch(datap, cpend); 330479045f13Schristos if (cp_namechar(ch)) { 330579045f13Schristos np = *datap; 330679045f13Schristos cp = np; 330779045f13Schristos st = sName; 330879045f13Schristos ch = pf_nextch(datap, cpend); 33092950cc38Schristos } else { 331079045f13Schristos goto final_done; 3311abb0f93cSkardel } 331279045f13Schristos break; 3313abb0f93cSkardel 331479045f13Schristos case sName: /* collect name */ 331579045f13Schristos while (cp_namechar(ch)) 331679045f13Schristos ch = pf_nextch(datap, cpend); 331779045f13Schristos nlen = (size_t)(*datap - np); 331879045f13Schristos if (ch == '=') { 331979045f13Schristos ch = pf_nextch(datap, cpend); 332079045f13Schristos vp = *datap; 332179045f13Schristos st = sValU; 332279045f13Schristos } else { 332379045f13Schristos if (ch != ',') 332479045f13Schristos *datap = cpend; 332579045f13Schristos st = sDone; 332679045f13Schristos } 332779045f13Schristos break; 332879045f13Schristos 332979045f13Schristos case sValU: /* collect unquoted part(s) of value */ 333079045f13Schristos while (cp_uqchar(ch)) 333179045f13Schristos ch = pf_nextch(datap, cpend); 333279045f13Schristos if (ch == '"') { 333379045f13Schristos ch = pf_nextch(datap, cpend); 333479045f13Schristos st = sValQ; 333579045f13Schristos } else { 333679045f13Schristos vlen = (size_t)(*datap - vp); 333779045f13Schristos if (ch != ',') 333879045f13Schristos *datap = cpend; 333979045f13Schristos st = sDone; 334079045f13Schristos } 334179045f13Schristos break; 334279045f13Schristos 334379045f13Schristos case sValQ: /* collect quoted part(s) of value */ 334479045f13Schristos while (cp_qschar(ch)) 334579045f13Schristos ch = pf_nextch(datap, cpend); 334679045f13Schristos if (ch == '"') { 334779045f13Schristos ch = pf_nextch(datap, cpend); 334879045f13Schristos st = sValU; 334979045f13Schristos } else { 335079045f13Schristos pf_error("no closing quote, stop", cp, cpend); 335179045f13Schristos goto final_done; 335279045f13Schristos } 335379045f13Schristos break; 335479045f13Schristos 335579045f13Schristos default: 335679045f13Schristos pf_error("state machine error, stop", *datap, cpend); 335779045f13Schristos goto final_done; 335879045f13Schristos } 335979045f13Schristos } 336079045f13Schristos 336179045f13Schristos /* If name or value do not fit their buffer, croak and start 336279045f13Schristos * over. If there's no name at all after whitespace stripping, 336379045f13Schristos * redo silently. 3364abb0f93cSkardel */ 336579045f13Schristos nlen = str_strip(&np, nlen); 336679045f13Schristos vlen = str_strip(&vp, vlen); 336779045f13Schristos 336879045f13Schristos if (nlen == 0) { 336979045f13Schristos goto again; 337079045f13Schristos } 337179045f13Schristos if (nlen >= sizeof(name)) { 337279045f13Schristos pf_error("runaway name", np, cpend); 337379045f13Schristos goto again; 337479045f13Schristos } 337579045f13Schristos if (vlen >= sizeof(value)) { 337679045f13Schristos pf_error("runaway value", vp, cpend); 337779045f13Schristos goto again; 337879045f13Schristos } 337979045f13Schristos 338079045f13Schristos /* copy name and value into NUL-terminated buffers */ 338179045f13Schristos memcpy(name, np, nlen); 338279045f13Schristos name[nlen] = '\0'; 338379045f13Schristos *vname = name; 338479045f13Schristos 338579045f13Schristos memcpy(value, vp, vlen); 338679045f13Schristos value[vlen] = '\0'; 3387abb0f93cSkardel *vvalue = value; 338879045f13Schristos 338979045f13Schristos /* check if there's more to do or if we are finshed */ 339079045f13Schristos *datalen = (size_t)(cpend - *datap); 339179045f13Schristos return TRUE; 339279045f13Schristos 339379045f13Schristos final_done: 339479045f13Schristos *datap = cpend; 339579045f13Schristos *datalen = 0; 339679045f13Schristos return FALSE; 3397abb0f93cSkardel } 3398abb0f93cSkardel 3399abb0f93cSkardel 34002950cc38Schristos u_short 34012950cc38Schristos varfmt(const char * varname) 3402abb0f93cSkardel { 34032950cc38Schristos u_int n; 3404abb0f93cSkardel 34052950cc38Schristos for (n = 0; n < COUNTOF(cookedvars); n++) 34062950cc38Schristos if (!strcmp(varname, cookedvars[n].varname)) 34072950cc38Schristos return cookedvars[n].fmt; 3408abb0f93cSkardel 34092950cc38Schristos return PADDING; 34102950cc38Schristos } 3411abb0f93cSkardel 3412abb0f93cSkardel 3413abb0f93cSkardel /* 3414abb0f93cSkardel * printvars - print variables returned in response packet 3415abb0f93cSkardel */ 3416abb0f93cSkardel void 3417abb0f93cSkardel printvars( 34188b8da087Schristos size_t length, 34193123f114Skardel const char *data, 3420abb0f93cSkardel int status, 3421abb0f93cSkardel int sttype, 3422abb0f93cSkardel int quiet, 3423abb0f93cSkardel FILE *fp 3424abb0f93cSkardel ) 3425abb0f93cSkardel { 3426abb0f93cSkardel if (rawmode) 3427abb0f93cSkardel rawprint(sttype, length, data, status, quiet, fp); 3428abb0f93cSkardel else 3429abb0f93cSkardel cookedprint(sttype, length, data, status, quiet, fp); 3430abb0f93cSkardel } 3431abb0f93cSkardel 3432abb0f93cSkardel 3433abb0f93cSkardel /* 3434abb0f93cSkardel * rawprint - do a printout of the data in raw mode 3435abb0f93cSkardel */ 3436abb0f93cSkardel static void 3437abb0f93cSkardel rawprint( 3438abb0f93cSkardel int datatype, 34398b8da087Schristos size_t length, 34403123f114Skardel const char *data, 3441abb0f93cSkardel int status, 3442abb0f93cSkardel int quiet, 3443abb0f93cSkardel FILE *fp 3444abb0f93cSkardel ) 3445abb0f93cSkardel { 34463123f114Skardel const char *cp; 34473123f114Skardel const char *cpend; 3448abb0f93cSkardel 3449abb0f93cSkardel /* 3450abb0f93cSkardel * Essentially print the data as is. We reformat unprintables, though. 3451abb0f93cSkardel */ 3452abb0f93cSkardel cp = data; 3453abb0f93cSkardel cpend = data + length; 3454abb0f93cSkardel 3455abb0f93cSkardel if (!quiet) 3456abb0f93cSkardel (void) fprintf(fp, "status=0x%04x,\n", status); 3457abb0f93cSkardel 3458abb0f93cSkardel while (cp < cpend) { 3459abb0f93cSkardel if (*cp == '\r') { 3460abb0f93cSkardel /* 3461abb0f93cSkardel * If this is a \r and the next character is a 3462abb0f93cSkardel * \n, supress this, else pretty print it. Otherwise 3463abb0f93cSkardel * just output the character. 3464abb0f93cSkardel */ 3465abb0f93cSkardel if (cp == (cpend - 1) || *(cp + 1) != '\n') 3466abb0f93cSkardel makeascii(1, cp, fp); 34674eea345dSchristos } else if (isspace(pgetc(cp)) || isprint(pgetc(cp))) 3468abb0f93cSkardel putc(*cp, fp); 3469abb0f93cSkardel else 3470abb0f93cSkardel makeascii(1, cp, fp); 3471abb0f93cSkardel cp++; 3472abb0f93cSkardel } 3473abb0f93cSkardel } 3474abb0f93cSkardel 3475abb0f93cSkardel 3476abb0f93cSkardel /* 3477abb0f93cSkardel * Global data used by the cooked output routines 3478abb0f93cSkardel */ 3479abb0f93cSkardel int out_chars; /* number of characters output */ 3480abb0f93cSkardel int out_linecount; /* number of characters output on this line */ 3481abb0f93cSkardel 3482abb0f93cSkardel 3483abb0f93cSkardel /* 3484abb0f93cSkardel * startoutput - get ready to do cooked output 3485abb0f93cSkardel */ 3486abb0f93cSkardel static void 3487abb0f93cSkardel startoutput(void) 3488abb0f93cSkardel { 3489abb0f93cSkardel out_chars = 0; 3490abb0f93cSkardel out_linecount = 0; 3491abb0f93cSkardel } 3492abb0f93cSkardel 3493abb0f93cSkardel 3494abb0f93cSkardel /* 3495abb0f93cSkardel * output - output a variable=value combination 3496abb0f93cSkardel */ 3497abb0f93cSkardel static void 3498abb0f93cSkardel output( 3499abb0f93cSkardel FILE *fp, 35002950cc38Schristos const char *name, 35013123f114Skardel const char *value 3502abb0f93cSkardel ) 3503abb0f93cSkardel { 35048b8da087Schristos int len; 3505abb0f93cSkardel 3506abb0f93cSkardel /* strlen of "name=value" */ 35078b8da087Schristos len = size2int_sat(strlen(name) + 1 + strlen(value)); 3508abb0f93cSkardel 3509abb0f93cSkardel if (out_chars != 0) { 3510abb0f93cSkardel out_chars += 2; 3511abb0f93cSkardel if ((out_linecount + len + 2) > MAXOUTLINE) { 3512abb0f93cSkardel fputs(",\n", fp); 3513abb0f93cSkardel out_linecount = 0; 3514abb0f93cSkardel } else { 3515abb0f93cSkardel fputs(", ", fp); 3516abb0f93cSkardel out_linecount += 2; 3517abb0f93cSkardel } 3518abb0f93cSkardel } 3519abb0f93cSkardel 3520abb0f93cSkardel fputs(name, fp); 3521abb0f93cSkardel putc('=', fp); 3522abb0f93cSkardel fputs(value, fp); 3523abb0f93cSkardel out_chars += len; 3524abb0f93cSkardel out_linecount += len; 3525abb0f93cSkardel } 3526abb0f93cSkardel 3527abb0f93cSkardel 3528abb0f93cSkardel /* 3529abb0f93cSkardel * endoutput - terminate a block of cooked output 3530abb0f93cSkardel */ 3531abb0f93cSkardel static void 3532abb0f93cSkardel endoutput( 3533abb0f93cSkardel FILE *fp 3534abb0f93cSkardel ) 3535abb0f93cSkardel { 3536abb0f93cSkardel if (out_chars != 0) 3537abb0f93cSkardel putc('\n', fp); 3538abb0f93cSkardel } 3539abb0f93cSkardel 3540abb0f93cSkardel 3541abb0f93cSkardel /* 3542abb0f93cSkardel * outputarr - output an array of values 3543abb0f93cSkardel */ 3544abb0f93cSkardel static void 3545abb0f93cSkardel outputarr( 3546abb0f93cSkardel FILE *fp, 3547abb0f93cSkardel char *name, 3548abb0f93cSkardel int narr, 3549cdfa2a7eSchristos l_fp *lfp, 3550cdfa2a7eSchristos int issigned 3551abb0f93cSkardel ) 3552abb0f93cSkardel { 35538b8da087Schristos char *bp; 35548b8da087Schristos char *cp; 35558b8da087Schristos size_t i; 35568b8da087Schristos size_t len; 3557abb0f93cSkardel char buf[256]; 3558abb0f93cSkardel 3559abb0f93cSkardel bp = buf; 3560abb0f93cSkardel /* 3561abb0f93cSkardel * Hack to align delay and offset values 3562abb0f93cSkardel */ 3563abb0f93cSkardel for (i = (int)strlen(name); i < 11; i++) 3564abb0f93cSkardel *bp++ = ' '; 3565abb0f93cSkardel 3566abb0f93cSkardel for (i = narr; i > 0; i--) { 35678b8da087Schristos if (i != (size_t)narr) 3568abb0f93cSkardel *bp++ = ' '; 3569cdfa2a7eSchristos cp = (issigned ? lfptoms(lfp, 2) : ulfptoms(lfp, 2)); 3570abb0f93cSkardel len = strlen(cp); 3571abb0f93cSkardel if (len > 7) { 3572abb0f93cSkardel cp[7] = '\0'; 3573abb0f93cSkardel len = 7; 3574abb0f93cSkardel } 3575abb0f93cSkardel while (len < 7) { 3576abb0f93cSkardel *bp++ = ' '; 3577abb0f93cSkardel len++; 3578abb0f93cSkardel } 3579abb0f93cSkardel while (*cp != '\0') 3580abb0f93cSkardel *bp++ = *cp++; 3581abb0f93cSkardel lfp++; 3582abb0f93cSkardel } 3583abb0f93cSkardel *bp = '\0'; 3584abb0f93cSkardel output(fp, name, buf); 3585abb0f93cSkardel } 3586abb0f93cSkardel 3587abb0f93cSkardel static char * 3588abb0f93cSkardel tstflags( 3589abb0f93cSkardel u_long val 3590abb0f93cSkardel ) 3591abb0f93cSkardel { 359279045f13Schristos # if CBLEN < 10 3593*eabc0478Schristos # error CBLEN is too small -- increase! 359479045f13Schristos # endif 3595abb0f93cSkardel 359679045f13Schristos char *cp, *s; 359779045f13Schristos size_t cb, i; 359879045f13Schristos int l; 359979045f13Schristos 36003123f114Skardel s = cp = circ_buf[nextcb]; 3601abb0f93cSkardel if (++nextcb >= NUMCB) 3602abb0f93cSkardel nextcb = 0; 36033123f114Skardel cb = sizeof(circ_buf[0]); 3604abb0f93cSkardel 360579045f13Schristos l = snprintf(cp, cb, "%02lx", val); 360679045f13Schristos if (l < 0 || (size_t)l >= cb) 360779045f13Schristos goto fail; 360879045f13Schristos cp += l; 360979045f13Schristos cb -= l; 3610abb0f93cSkardel if (!val) { 361179045f13Schristos l = strlcat(cp, " ok", cb); 361279045f13Schristos if ((size_t)l >= cb) 361379045f13Schristos goto fail; 361479045f13Schristos cp += l; 361579045f13Schristos cb -= l; 3616abb0f93cSkardel } else { 361779045f13Schristos const char *sep; 361879045f13Schristos 361979045f13Schristos sep = " "; 362079045f13Schristos for (i = 0; i < COUNTOF(tstflagnames); i++) { 3621abb0f93cSkardel if (val & 0x1) { 362279045f13Schristos l = snprintf(cp, cb, "%s%s", sep, 36233123f114Skardel tstflagnames[i]); 362479045f13Schristos if (l < 0) 362579045f13Schristos goto fail; 362679045f13Schristos if ((size_t)l >= cb) { 362779045f13Schristos cp += cb - 4; 362879045f13Schristos cb = 4; 362979045f13Schristos l = strlcpy (cp, "...", cb); 363079045f13Schristos cp += l; 363179045f13Schristos cb -= l; 363279045f13Schristos break; 363379045f13Schristos } 3634abb0f93cSkardel sep = ", "; 363579045f13Schristos cp += l; 363679045f13Schristos cb -= l; 3637abb0f93cSkardel } 3638abb0f93cSkardel val >>= 1; 3639abb0f93cSkardel } 3640abb0f93cSkardel } 36413123f114Skardel 3642abb0f93cSkardel return s; 364379045f13Schristos 364479045f13Schristos fail: 364579045f13Schristos *cp = '\0'; 364679045f13Schristos return s; 3647abb0f93cSkardel } 3648abb0f93cSkardel 3649abb0f93cSkardel /* 3650abb0f93cSkardel * cookedprint - output variables in cooked mode 3651abb0f93cSkardel */ 3652abb0f93cSkardel static void 3653abb0f93cSkardel cookedprint( 3654abb0f93cSkardel int datatype, 36558b8da087Schristos size_t length, 36563123f114Skardel const char *data, 3657abb0f93cSkardel int status, 3658abb0f93cSkardel int quiet, 3659abb0f93cSkardel FILE *fp 3660abb0f93cSkardel ) 3661abb0f93cSkardel { 3662abb0f93cSkardel char *name; 3663abb0f93cSkardel char *value; 3664abb0f93cSkardel char output_raw; 3665abb0f93cSkardel int fmt; 3666abb0f93cSkardel l_fp lfp; 3667abb0f93cSkardel sockaddr_u hval; 3668abb0f93cSkardel u_long uval; 3669abb0f93cSkardel int narr; 36702950cc38Schristos size_t len; 36712950cc38Schristos l_fp lfparr[8]; 36722950cc38Schristos char b[12]; 36732950cc38Schristos char bn[2 * MAXVARLEN]; 36742950cc38Schristos char bv[2 * MAXVALLEN]; 3675abb0f93cSkardel 36762950cc38Schristos UNUSED_ARG(datatype); 3677abb0f93cSkardel 3678abb0f93cSkardel if (!quiet) 3679abb0f93cSkardel fprintf(fp, "status=%04x %s,\n", status, 3680abb0f93cSkardel statustoa(datatype, status)); 3681abb0f93cSkardel 3682abb0f93cSkardel startoutput(); 3683abb0f93cSkardel while (nextvar(&length, &data, &name, &value)) { 36842950cc38Schristos fmt = varfmt(name); 3685abb0f93cSkardel output_raw = 0; 3686abb0f93cSkardel switch (fmt) { 36872950cc38Schristos 36882950cc38Schristos case PADDING: 36892950cc38Schristos output_raw = '*'; 36902950cc38Schristos break; 36912950cc38Schristos 3692abb0f93cSkardel case TS: 36934eea345dSchristos if (!value || !decodets(value, &lfp)) 3694abb0f93cSkardel output_raw = '?'; 3695abb0f93cSkardel else 3696abb0f93cSkardel output(fp, name, prettydate(&lfp)); 3697abb0f93cSkardel break; 3698abb0f93cSkardel 36992950cc38Schristos case HA: /* fallthru */ 3700abb0f93cSkardel case NA: 37014eea345dSchristos if (!value || !decodenetnum(value, &hval)) { 3702abb0f93cSkardel output_raw = '?'; 37032950cc38Schristos } else if (fmt == HA){ 3704abb0f93cSkardel output(fp, name, nntohost(&hval)); 3705abb0f93cSkardel } else { 3706abb0f93cSkardel output(fp, name, stoa(&hval)); 3707abb0f93cSkardel } 3708abb0f93cSkardel break; 3709abb0f93cSkardel 3710abb0f93cSkardel case RF: 37114eea345dSchristos if (!value) { 37124eea345dSchristos output_raw = '?'; 37134eea345dSchristos } else if (decodenetnum(value, &hval)) { 3714cdfa2a7eSchristos if (datatype == TYPE_CLOCK && IS_IPV4(&hval)) { 3715cdfa2a7eSchristos /* 3716cdfa2a7eSchristos * Workaround to override numeric refid formats 3717cdfa2a7eSchristos * for refclocks received from faulty nptd servers 3718cdfa2a7eSchristos * and output them as text. 3719cdfa2a7eSchristos */ 3720cdfa2a7eSchristos int i; 3721cdfa2a7eSchristos unsigned char *str = (unsigned char *)&(hval.sa4).sin_addr; 3722cdfa2a7eSchristos char refid_buf[5]; 3723cdfa2a7eSchristos for (i=0; i<4 && str[i]; i++) 3724cdfa2a7eSchristos refid_buf[i] = (isprint(str[i]) ? str[i] : '?'); 3725cdfa2a7eSchristos refid_buf[i] = 0; /* Null terminator */ 3726cdfa2a7eSchristos output(fp, name, refid_buf); 3727cdfa2a7eSchristos } else if (ISREFCLOCKADR(&hval)) { 3728cdfa2a7eSchristos output(fp, name, refnumtoa(&hval)); 3729cdfa2a7eSchristos } else { 3730cdfa2a7eSchristos if (drefid == REFID_IPV4) { 3731abb0f93cSkardel output(fp, name, stoa(&hval)); 3732cdfa2a7eSchristos } else { 3733cdfa2a7eSchristos char refid_buf[12]; 3734cdfa2a7eSchristos snprintf (refid_buf, sizeof(refid_buf), 3735cdfa2a7eSchristos "0x%08x", ntohl(addr2refid(&hval))); 3736cdfa2a7eSchristos output(fp, name, refid_buf); 3737cdfa2a7eSchristos } 3738cdfa2a7eSchristos } 37392950cc38Schristos } else if (strlen(value) <= 4) { 3740abb0f93cSkardel output(fp, name, value); 37412950cc38Schristos } else { 3742abb0f93cSkardel output_raw = '?'; 37432950cc38Schristos } 3744abb0f93cSkardel break; 3745abb0f93cSkardel 3746abb0f93cSkardel case LP: 37474eea345dSchristos if (!value || !decodeuint(value, &uval) || uval > 3) { 3748abb0f93cSkardel output_raw = '?'; 37492950cc38Schristos } else { 37502950cc38Schristos b[0] = (0x2 & uval) 37512950cc38Schristos ? '1' 37522950cc38Schristos : '0'; 37532950cc38Schristos b[1] = (0x1 & uval) 37542950cc38Schristos ? '1' 37552950cc38Schristos : '0'; 3756abb0f93cSkardel b[2] = '\0'; 3757abb0f93cSkardel output(fp, name, b); 3758abb0f93cSkardel } 3759abb0f93cSkardel break; 3760abb0f93cSkardel 3761abb0f93cSkardel case OC: 37624eea345dSchristos if (!value || !decodeuint(value, &uval)) { 3763abb0f93cSkardel output_raw = '?'; 37642950cc38Schristos } else { 37652950cc38Schristos snprintf(b, sizeof(b), "%03lo", uval); 3766abb0f93cSkardel output(fp, name, b); 3767abb0f93cSkardel } 3768abb0f93cSkardel break; 3769abb0f93cSkardel 3770cdfa2a7eSchristos case AU: 3771cdfa2a7eSchristos case AS: 37724eea345dSchristos if (!value || !decodearr(value, &narr, lfparr, 8)) 3773abb0f93cSkardel output_raw = '?'; 3774abb0f93cSkardel else 3775cdfa2a7eSchristos outputarr(fp, name, narr, lfparr, (fmt==AS)); 3776abb0f93cSkardel break; 3777abb0f93cSkardel 3778abb0f93cSkardel case FX: 37794eea345dSchristos if (!value || !decodeuint(value, &uval)) 3780abb0f93cSkardel output_raw = '?'; 3781abb0f93cSkardel else 3782abb0f93cSkardel output(fp, name, tstflags(uval)); 3783abb0f93cSkardel break; 3784abb0f93cSkardel 3785cdfa2a7eSchristos case SN: 3786cdfa2a7eSchristos if (!value) 3787cdfa2a7eSchristos output_raw = '?'; 37887ee11f2fSchristos else if (isdigit(*(const unsigned char *)value)) { /* number without sign */ 3789cdfa2a7eSchristos bv[0] = '+'; 3790cdfa2a7eSchristos atoascii (value, MAXVALLEN, bv+1, sizeof(bv)-1); 3791cdfa2a7eSchristos output(fp, name, bv); 3792cdfa2a7eSchristos } else 3793cdfa2a7eSchristos output_raw = '*'; /* output as-is */ 3794cdfa2a7eSchristos break; 3795cdfa2a7eSchristos 3796abb0f93cSkardel default: 37972950cc38Schristos fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3798abb0f93cSkardel name, value, fmt); 37992950cc38Schristos output_raw = '?'; 3800abb0f93cSkardel break; 3801abb0f93cSkardel } 3802abb0f93cSkardel 3803abb0f93cSkardel if (output_raw != 0) { 3804af12ab5eSchristos /* TALOS-CAN-0063: avoid buffer overrun */ 3805abb0f93cSkardel atoascii(name, MAXVARLEN, bn, sizeof(bn)); 3806abb0f93cSkardel if (output_raw != '*') { 3807af12ab5eSchristos atoascii(value, MAXVALLEN, 3808af12ab5eSchristos bv, sizeof(bv) - 1); 3809abb0f93cSkardel len = strlen(bv); 3810abb0f93cSkardel bv[len] = output_raw; 3811abb0f93cSkardel bv[len+1] = '\0'; 3812af12ab5eSchristos } else { 3813af12ab5eSchristos atoascii(value, MAXVALLEN, 3814af12ab5eSchristos bv, sizeof(bv)); 3815abb0f93cSkardel } 3816abb0f93cSkardel output(fp, bn, bv); 3817abb0f93cSkardel } 3818abb0f93cSkardel } 3819abb0f93cSkardel endoutput(fp); 3820abb0f93cSkardel } 3821abb0f93cSkardel 3822abb0f93cSkardel 3823abb0f93cSkardel /* 3824abb0f93cSkardel * sortassoc - sort associations in the cache into ascending order 3825abb0f93cSkardel */ 3826abb0f93cSkardel void 3827abb0f93cSkardel sortassoc(void) 3828abb0f93cSkardel { 3829abb0f93cSkardel if (numassoc > 1) 38302950cc38Schristos qsort(assoc_cache, (size_t)numassoc, 38312950cc38Schristos sizeof(assoc_cache[0]), &assoccmp); 3832abb0f93cSkardel } 3833abb0f93cSkardel 3834abb0f93cSkardel 3835abb0f93cSkardel /* 3836abb0f93cSkardel * assoccmp - compare two associations 3837abb0f93cSkardel */ 3838abb0f93cSkardel static int 3839abb0f93cSkardel assoccmp( 3840abb0f93cSkardel const void *t1, 3841abb0f93cSkardel const void *t2 3842abb0f93cSkardel ) 3843abb0f93cSkardel { 38443123f114Skardel const struct association *ass1 = t1; 38453123f114Skardel const struct association *ass2 = t2; 3846abb0f93cSkardel 3847abb0f93cSkardel if (ass1->assid < ass2->assid) 3848abb0f93cSkardel return -1; 3849abb0f93cSkardel if (ass1->assid > ass2->assid) 3850abb0f93cSkardel return 1; 3851abb0f93cSkardel return 0; 3852abb0f93cSkardel } 38533123f114Skardel 3854abb0f93cSkardel 3855abb0f93cSkardel /* 38562950cc38Schristos * grow_assoc_cache() - enlarge dynamic assoc_cache array 38572950cc38Schristos * 38582950cc38Schristos * The strategy is to add an assumed 4k page size at a time, leaving 38592950cc38Schristos * room for malloc() bookkeeping overhead equivalent to 4 pointers. 38602950cc38Schristos */ 38612950cc38Schristos void 38622950cc38Schristos grow_assoc_cache(void) 38632950cc38Schristos { 38642950cc38Schristos static size_t prior_sz; 38652950cc38Schristos size_t new_sz; 38662950cc38Schristos 38672950cc38Schristos new_sz = prior_sz + 4 * 1024; 38682950cc38Schristos if (0 == prior_sz) { 38692950cc38Schristos new_sz -= 4 * sizeof(void *); 38702950cc38Schristos } 38712950cc38Schristos assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 38722950cc38Schristos prior_sz = new_sz; 38738b8da087Schristos assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 38742950cc38Schristos } 38752950cc38Schristos 38762950cc38Schristos 38772950cc38Schristos /* 3878abb0f93cSkardel * ntpq_custom_opt_handler - autoopts handler for -c and -p 3879abb0f93cSkardel * 3880abb0f93cSkardel * By default, autoopts loses the relative order of -c and -p options 3881abb0f93cSkardel * on the command line. This routine replaces the default handler for 3882abb0f93cSkardel * those routines and builds a list of commands to execute preserving 3883abb0f93cSkardel * the order. 3884abb0f93cSkardel */ 3885abb0f93cSkardel void 3886abb0f93cSkardel ntpq_custom_opt_handler( 3887abb0f93cSkardel tOptions *pOptions, 3888abb0f93cSkardel tOptDesc *pOptDesc 3889abb0f93cSkardel ) 3890abb0f93cSkardel { 3891abb0f93cSkardel switch (pOptDesc->optValue) { 3892abb0f93cSkardel 3893abb0f93cSkardel default: 3894abb0f93cSkardel fprintf(stderr, 3895abb0f93cSkardel "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3896abb0f93cSkardel pOptDesc->optValue, pOptDesc->optValue); 38972950cc38Schristos exit(1); 3898abb0f93cSkardel 3899abb0f93cSkardel case 'c': 3900*eabc0478Schristos if ((pOptDesc->fOptState & OPTST_SET_MASK) == OPTST_DEFINED) 3901*eabc0478Schristos defcmds++; 3902abb0f93cSkardel ADDCMD(pOptDesc->pzLastArg); 3903abb0f93cSkardel break; 3904abb0f93cSkardel 3905abb0f93cSkardel case 'p': 3906*eabc0478Schristos if ((pOptDesc->fOptState & OPTST_SET_MASK) == OPTST_DEFINED) 3907*eabc0478Schristos defcmds++; 3908abb0f93cSkardel ADDCMD("peers"); 3909abb0f93cSkardel break; 3910abb0f93cSkardel } 3911abb0f93cSkardel } 39125d681e99Schristos /* 39135d681e99Schristos * Obtain list of digest names 39145d681e99Schristos */ 39155d681e99Schristos 39164eea345dSchristos #if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED) 39174eea345dSchristos # if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L 39184eea345dSchristos # define HAVE_EVP_MD_DO_ALL_SORTED 39194eea345dSchristos # endif 39204eea345dSchristos #endif 39214eea345dSchristos 39225d681e99Schristos #ifdef OPENSSL 39235d681e99Schristos # ifdef HAVE_EVP_MD_DO_ALL_SORTED 39244eea345dSchristos # define K_PER_LINE 8 39254eea345dSchristos # define K_NL_PFX_STR "\n " 39264eea345dSchristos # define K_DELIM_STR ", " 39274eea345dSchristos 39285d681e99Schristos struct hstate { 39295d681e99Schristos char *list; 3930*eabc0478Schristos char const **seen; 39315d681e99Schristos int idx; 39325d681e99Schristos }; 39334eea345dSchristos 39344eea345dSchristos 393579045f13Schristos # ifndef BUILD_AS_LIB 39364eea345dSchristos static void 39374eea345dSchristos list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg) 39385d681e99Schristos { 39395d681e99Schristos size_t len, n; 39404eea345dSchristos const char *name, **seen; 39415d681e99Schristos struct hstate *hstate = arg; 39425d681e99Schristos 39434eea345dSchristos /* m is MD obj, from is name or alias, to is base name for alias */ 3944*eabc0478Schristos if (!m || !from || to) { 39455d681e99Schristos return; /* Ignore aliases */ 3946*eabc0478Schristos } 39474eea345dSchristos 39484eea345dSchristos /* Discard MACs that NTP won't accept. */ 39494eea345dSchristos /* Keep this consistent with keytype_from_text() in ssl_init.c. */ 3950*eabc0478Schristos if ((size_t)EVP_MD_size(m) > MAX_MDG_LEN) { 39514eea345dSchristos return; 3952*eabc0478Schristos } 39535d681e99Schristos 39545d681e99Schristos name = EVP_MD_name(m); 3955*eabc0478Schristos len = strlen(name) + 1; 39565d681e99Schristos 39575d681e99Schristos /* There are duplicates. Discard if name has been seen. */ 39585d681e99Schristos 395979045f13Schristos for (seen = hstate->seen; *seen; seen++) 3960*eabc0478Schristos if (!strcasecmp(*seen, name)) 39615d681e99Schristos return; 39624eea345dSchristos 39635d681e99Schristos n = (seen - hstate->seen) + 2; 3964*eabc0478Schristos hstate->seen = erealloc((void *)hstate->seen, n * sizeof(*seen)); 39655d681e99Schristos hstate->seen[n-2] = name; 39665d681e99Schristos hstate->seen[n-1] = NULL; 39675d681e99Schristos 396879045f13Schristos if (hstate->list != NULL) 39695d681e99Schristos len += strlen(hstate->list); 39704eea345dSchristos 39714eea345dSchristos len += (hstate->idx >= K_PER_LINE) 39724eea345dSchristos ? strlen(K_NL_PFX_STR) 39734eea345dSchristos : strlen(K_DELIM_STR); 39745d681e99Schristos 39755d681e99Schristos if (hstate->list == NULL) { 3976af12ab5eSchristos hstate->list = (char *)emalloc(len); 39775d681e99Schristos hstate->list[0] = '\0'; 39784eea345dSchristos } else { 3979af12ab5eSchristos hstate->list = (char *)erealloc(hstate->list, len); 39804eea345dSchristos } 39815d681e99Schristos 39825d681e99Schristos sprintf(hstate->list + strlen(hstate->list), "%s%s", 39835d681e99Schristos ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR), 39845d681e99Schristos name); 39854eea345dSchristos 398679045f13Schristos if (hstate->idx >= K_PER_LINE) 39875d681e99Schristos hstate->idx = 1; 398879045f13Schristos else 39895d681e99Schristos hstate->idx++; 39905d681e99Schristos } 399179045f13Schristos # endif /* !defined(BUILD_AS_LIB) */ 39924eea345dSchristos 399379045f13Schristos # ifndef BUILD_AS_LIB 39944eea345dSchristos /* Insert CMAC into SSL digests list */ 39954eea345dSchristos static char * 39964eea345dSchristos insert_cmac(char *list) 39974eea345dSchristos { 399879045f13Schristos #ifdef ENABLE_CMAC 39994eea345dSchristos int insert; 40004eea345dSchristos size_t len; 40014eea345dSchristos 40024eea345dSchristos 40034eea345dSchristos /* If list empty, we need to insert CMAC on new line */ 40044eea345dSchristos insert = (!list || !*list); 40054eea345dSchristos 40064eea345dSchristos if (insert) { 40074eea345dSchristos len = strlen(K_NL_PFX_STR) + strlen(CMAC); 40084eea345dSchristos list = (char *)erealloc(list, len + 1); 40094eea345dSchristos sprintf(list, "%s%s", K_NL_PFX_STR, CMAC); 40104eea345dSchristos } else { /* List not empty */ 40114eea345dSchristos /* Check if CMAC already in list - future proofing */ 40124eea345dSchristos const char *cmac_sn; 40134eea345dSchristos char *cmac_p; 40144eea345dSchristos 40154eea345dSchristos cmac_sn = OBJ_nid2sn(NID_cmac); 40164eea345dSchristos cmac_p = list; 40174eea345dSchristos insert = cmac_sn != NULL && *cmac_sn != '\0'; 40184eea345dSchristos 40194eea345dSchristos /* CMAC in list if found, followed by nul char or ',' */ 40204eea345dSchristos while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) { 40214eea345dSchristos cmac_p += strlen(cmac_sn); 40224eea345dSchristos /* Still need to insert if not nul and not ',' */ 40234eea345dSchristos insert = *cmac_p && ',' != *cmac_p; 40244eea345dSchristos } 40254eea345dSchristos 40264eea345dSchristos /* Find proper insertion point */ 40274eea345dSchristos if (insert) { 40284eea345dSchristos char *last_nl; 40294eea345dSchristos char *point; 40304eea345dSchristos char *delim; 40314eea345dSchristos int found; 40324eea345dSchristos 40334eea345dSchristos /* Default to start if list empty */ 40344eea345dSchristos found = 0; 40354eea345dSchristos delim = list; 40364eea345dSchristos len = strlen(list); 40374eea345dSchristos 40384eea345dSchristos /* While new lines */ 40394eea345dSchristos while (delim < list + len && *delim && 40404eea345dSchristos !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) { 40414eea345dSchristos point = delim + strlen(K_NL_PFX_STR); 40424eea345dSchristos 40434eea345dSchristos /* While digest names on line */ 40444eea345dSchristos while (point < list + len && *point) { 40454eea345dSchristos /* Another digest after on same or next line? */ 40464eea345dSchristos delim = strstr( point, K_DELIM_STR); 40474eea345dSchristos last_nl = strstr( point, K_NL_PFX_STR); 40484eea345dSchristos 40494eea345dSchristos /* No - end of list */ 40504eea345dSchristos if (!delim && !last_nl) { 40514eea345dSchristos delim = list + len; 4052*eabc0478Schristos } else { 40534eea345dSchristos /* New line and no delim or before delim? */ 40544eea345dSchristos if (last_nl && (!delim || last_nl < delim)) { 40554eea345dSchristos delim = last_nl; 40564eea345dSchristos } 4057*eabc0478Schristos } 40584eea345dSchristos 40594eea345dSchristos /* Found insertion point where CMAC before entry? */ 40604eea345dSchristos if (strncmp(CMAC, point, delim - point) < 0) { 40614eea345dSchristos found = 1; 40624eea345dSchristos break; 40634eea345dSchristos } 40644eea345dSchristos 40654eea345dSchristos if (delim < list + len && *delim && 40664eea345dSchristos !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) { 40674eea345dSchristos point += strlen(K_DELIM_STR); 40684eea345dSchristos } else { 40694eea345dSchristos break; 40704eea345dSchristos } 40714eea345dSchristos } /* While digest names on line */ 40724eea345dSchristos } /* While new lines */ 40734eea345dSchristos 40744eea345dSchristos /* If found in list */ 40754eea345dSchristos if (found) { 40764eea345dSchristos /* insert cmac and delim */ 40774eea345dSchristos /* Space for list could move - save offset */ 40784eea345dSchristos ptrdiff_t p_offset = point - list; 40794eea345dSchristos len += strlen(CMAC) + strlen(K_DELIM_STR); 40804eea345dSchristos list = (char *)erealloc(list, len + 1); 40814eea345dSchristos point = list + p_offset; 40824eea345dSchristos /* move to handle src/dest overlap */ 40834eea345dSchristos memmove(point + strlen(CMAC) + strlen(K_DELIM_STR), 40844eea345dSchristos point, strlen(point) + 1); 4085*eabc0478Schristos memcpy(point, CMAC, strlen(CMAC)); 4086*eabc0478Schristos memcpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR)); 40874eea345dSchristos } else { /* End of list */ 40884eea345dSchristos /* append delim and cmac */ 40894eea345dSchristos len += strlen(K_DELIM_STR) + strlen(CMAC); 40904eea345dSchristos list = (char *)erealloc(list, len + 1); 40914eea345dSchristos strcpy(list + strlen(list), K_DELIM_STR); 40924eea345dSchristos strcpy(list + strlen(list), CMAC); 40934eea345dSchristos } 40944eea345dSchristos } /* insert */ 40954eea345dSchristos } /* List not empty */ 409679045f13Schristos #endif /*ENABLE_CMAC*/ 40974eea345dSchristos return list; 40984eea345dSchristos } 409979045f13Schristos # endif /* !defined(BUILD_AS_LIB) */ 41005d681e99Schristos # endif 41015d681e99Schristos #endif 41025d681e99Schristos 41034eea345dSchristos 410479045f13Schristos #ifndef BUILD_AS_LIB 41054eea345dSchristos static char * 41064eea345dSchristos list_digest_names(void) 41075d681e99Schristos { 41085d681e99Schristos char *list = NULL; 41095d681e99Schristos 41105d681e99Schristos #ifdef OPENSSL 41115d681e99Schristos # ifdef HAVE_EVP_MD_DO_ALL_SORTED 41125d681e99Schristos struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 41135d681e99Schristos 41144eea345dSchristos /* replace calloc(1, sizeof(const char *)) */ 4115*eabc0478Schristos hstate.seen = emalloc_zero(sizeof(const char*)); 41165d681e99Schristos 41175d681e99Schristos INIT_SSL(); 41185d681e99Schristos EVP_MD_do_all_sorted(list_md_fn, &hstate); 41195d681e99Schristos list = hstate.list; 4120*eabc0478Schristos free((void *)hstate.seen); 41214eea345dSchristos 41224eea345dSchristos list = insert_cmac(list); /* Insert CMAC into SSL digests list */ 41234eea345dSchristos 41245d681e99Schristos # else 4125af12ab5eSchristos list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 41265d681e99Schristos strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 41275d681e99Schristos # endif 41285d681e99Schristos #else 4129af12ab5eSchristos list = (char *)emalloc(sizeof("md5")); 41305d681e99Schristos strcpy(list, "md5"); 41315d681e99Schristos #endif 41325d681e99Schristos 41335d681e99Schristos return list; 41345d681e99Schristos } 413579045f13Schristos #endif /* !defined(BUILD_AS_LIB) */ 41368b8da087Schristos 41378b8da087Schristos #define CTRLC_STACK_MAX 4 41388b8da087Schristos static volatile size_t ctrlc_stack_len = 0; 41398b8da087Schristos static volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 41408b8da087Schristos 41418b8da087Schristos 41428b8da087Schristos 41438b8da087Schristos int/*BOOL*/ 41448b8da087Schristos push_ctrl_c_handler( 41458b8da087Schristos Ctrl_C_Handler func 41468b8da087Schristos ) 41478b8da087Schristos { 41488b8da087Schristos size_t size = ctrlc_stack_len; 41498b8da087Schristos if (func && (size < CTRLC_STACK_MAX)) { 41508b8da087Schristos ctrlc_stack[size] = func; 41518b8da087Schristos ctrlc_stack_len = size + 1; 41528b8da087Schristos return TRUE; 41538b8da087Schristos } 41548b8da087Schristos return FALSE; 41558b8da087Schristos } 41568b8da087Schristos 41578b8da087Schristos int/*BOOL*/ 41588b8da087Schristos pop_ctrl_c_handler( 41598b8da087Schristos Ctrl_C_Handler func 41608b8da087Schristos ) 41618b8da087Schristos { 41628b8da087Schristos size_t size = ctrlc_stack_len; 41638b8da087Schristos if (size) { 41648b8da087Schristos --size; 41658b8da087Schristos if (func == NULL || func == ctrlc_stack[size]) { 41668b8da087Schristos ctrlc_stack_len = size; 41678b8da087Schristos return TRUE; 41688b8da087Schristos } 41698b8da087Schristos } 41708b8da087Schristos return FALSE; 41718b8da087Schristos } 41728b8da087Schristos 417379045f13Schristos #ifndef BUILD_AS_LIB 41748b8da087Schristos static void 41758b8da087Schristos on_ctrlc(void) 41768b8da087Schristos { 41778b8da087Schristos size_t size = ctrlc_stack_len; 41788b8da087Schristos while (size) 41798b8da087Schristos if ((*ctrlc_stack[--size])()) 41808b8da087Schristos break; 41818b8da087Schristos } 418279045f13Schristos #endif /* !defined(BUILD_AS_LIB) */ 418368dbbb44Schristos 418479045f13Schristos #ifndef BUILD_AS_LIB 418568dbbb44Schristos static int 418668dbbb44Schristos my_easprintf( 418768dbbb44Schristos char ** ppinto, 418868dbbb44Schristos const char * fmt , 418968dbbb44Schristos ... 419068dbbb44Schristos ) 419168dbbb44Schristos { 419268dbbb44Schristos va_list va; 419368dbbb44Schristos int prc; 419468dbbb44Schristos size_t len = 128; 419568dbbb44Schristos char * buf = emalloc(len); 419668dbbb44Schristos 419768dbbb44Schristos again: 419868dbbb44Schristos /* Note: we expect the memory allocation to fail long before the 419968dbbb44Schristos * increment in buffer size actually overflows. 420068dbbb44Schristos */ 420168dbbb44Schristos buf = (buf) ? erealloc(buf, len) : emalloc(len); 420268dbbb44Schristos 420368dbbb44Schristos va_start(va, fmt); 420468dbbb44Schristos prc = vsnprintf(buf, len, fmt, va); 420568dbbb44Schristos va_end(va); 420668dbbb44Schristos 420768dbbb44Schristos if (prc < 0) { 420868dbbb44Schristos /* might be very old vsnprintf. Or actually MSVC... */ 420968dbbb44Schristos len += len >> 1; 421068dbbb44Schristos goto again; 421168dbbb44Schristos } 421268dbbb44Schristos if ((size_t)prc >= len) { 421368dbbb44Schristos /* at least we have the proper size now... */ 421468dbbb44Schristos len = (size_t)prc + 1; 421568dbbb44Schristos goto again; 421668dbbb44Schristos } 421768dbbb44Schristos if ((size_t)prc < (len - 32)) 421868dbbb44Schristos buf = erealloc(buf, (size_t)prc + 1); 421968dbbb44Schristos *ppinto = buf; 422068dbbb44Schristos return prc; 422168dbbb44Schristos } 422279045f13Schristos #endif /* !defined(BUILD_AS_LIB) */ 4223