ntpq.c revision 301256
1219820Sjeff/* 2219820Sjeff * ntpq - query an NTP server using mode 6 commands 3219820Sjeff */ 4219820Sjeff#include <config.h> 5219820Sjeff#include <stdio.h> 6219820Sjeff#include <ctype.h> 7219820Sjeff#include <signal.h> 8309378Sjhb#include <setjmp.h> 9219820Sjeff#include <sys/types.h> 10219820Sjeff#include <sys/time.h> 11219820Sjeff#ifdef HAVE_UNISTD_H 12219820Sjeff# include <unistd.h> 13219820Sjeff#endif 14219820Sjeff#ifdef HAVE_FCNTL_H 15219820Sjeff# include <fcntl.h> 16219820Sjeff#endif 17219820Sjeff#ifdef SYS_WINNT 18219820Sjeff# include <mswsock.h> 19219820Sjeff#endif 20219820Sjeff#include <isc/net.h> 21219820Sjeff#include <isc/result.h> 22219820Sjeff 23219820Sjeff#include "ntpq.h" 24219820Sjeff#include "ntp_assert.h" 25219820Sjeff#include "ntp_stdlib.h" 26219820Sjeff#include "ntp_unixtime.h" 27219820Sjeff#include "ntp_calendar.h" 28219820Sjeff#include "ntp_select.h" 29219820Sjeff#include "ntp_assert.h" 30219820Sjeff#include "lib_strbuf.h" 31219820Sjeff#include "ntp_lineedit.h" 32219820Sjeff#include "ntp_debug.h" 33219820Sjeff#ifdef OPENSSL 34219820Sjeff#include "openssl/evp.h" 35219820Sjeff#include "openssl/objects.h" 36219820Sjeff#include "openssl/err.h" 37219820Sjeff#endif 38219820Sjeff#include <ssl_applink.c> 39309378Sjhb 40309378Sjhb#include "ntp_libopts.h" 41219820Sjeff#include "safecast.h" 42219820Sjeff 43219820Sjeff#ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 44219820Sjeff# define open(name, flags) open(name, flags, 0777) 45219820Sjeff# define SERVER_PORT_NUM 123 46219820Sjeff#endif 47219820Sjeff 48219820Sjeff/* we use COMMAND as an autogen keyword */ 49271127Shselasky#ifdef COMMAND 50309378Sjhb# undef COMMAND 51309378Sjhb#endif 52219820Sjeff 53309378Sjhb/* 54219820Sjeff * Because we potentially understand a lot of commands we will run 55219820Sjeff * interactive if connected to a terminal. 56219820Sjeff */ 57219820Sjeffint interactive = 0; /* set to 1 when we should prompt */ 58219820Sjeffconst char *prompt = "ntpq> "; /* prompt to ask him about */ 59219820Sjeff 60219820Sjeff/* 61219820Sjeff * use old readvars behavior? --old-rv processing in ntpq resets 62219820Sjeff * this value based on the presence or absence of --old-rv. It is 63219820Sjeff * initialized to 1 here to maintain backward compatibility with 64219820Sjeff * libntpq clients such as ntpsnmpd, which are free to reset it as 65219820Sjeff * desired. 66219820Sjeff */ 67219820Sjeffint old_rv = 1; 68219820Sjeff 69219820Sjeff/* 70219820Sjeff * How should we display the refid? 71309378Sjhb * REFID_HASH, REFID_IPV4 72309378Sjhb */ 73309378Sjhbte_Refid drefid = -1; 74309378Sjhb 75219820Sjeff/* 76309378Sjhb * for get_systime() 77309378Sjhb */ 78309378Sjhbs_char sys_precision; /* local clock precision (log2 s) */ 79309378Sjhb 80309378Sjhb/* 81309378Sjhb * Keyid used for authenticated requests. Obtained on the fly. 82309378Sjhb */ 83309378Sjhbu_long info_auth_keyid = 0; 84309378Sjhb 85309378Sjhbstatic int info_auth_keytype = NID_md5; /* MD5 */ 86309378Sjhbstatic size_t info_auth_hashlen = 16; /* MD5 */ 87309378Sjhbu_long current_time; /* needed by authkeys; not used */ 88309378Sjhb 89309378Sjhb/* 90309378Sjhb * Flag which indicates we should always send authenticated requests 91309378Sjhb */ 92309378Sjhbint always_auth = 0; 93309378Sjhb 94309378Sjhb/* 95309378Sjhb * Flag which indicates raw mode output. 96309378Sjhb */ 97309378Sjhbint rawmode = 0; 98309378Sjhb 99309378Sjhb/* 100309378Sjhb * Packet version number we use 101309378Sjhb */ 102309378Sjhbu_char pktversion = NTP_OLDVERSION + 1; 103309378Sjhb 104309378Sjhb/* 105309378Sjhb * Don't jump if no set jmp. 106309378Sjhb */ 107309378Sjhbvolatile int jump = 0; 108309378Sjhb 109309378Sjhb/* 110309378Sjhb * Format values 111309378Sjhb */ 112309378Sjhb#define PADDING 0 113309378Sjhb#define HA 1 /* host address */ 114309378Sjhb#define NA 2 /* network address */ 115309378Sjhb#define LP 3 /* leap (print in binary) */ 116309378Sjhb#define RF 4 /* refid (sometimes string, sometimes not) */ 117309378Sjhb#define AR 5 /* array of times */ 118309378Sjhb#define FX 6 /* test flags */ 119309378Sjhb#define TS 7 /* l_fp timestamp in hex */ 120309378Sjhb#define OC 8 /* integer, print in octal */ 121309378Sjhb#define EOV 255 /* end of table */ 122309378Sjhb 123309378Sjhb/* 124309378Sjhb * For the most part ntpq simply displays what ntpd provides in the 125309378Sjhb * mostly plain-text mode 6 responses. A few variable names are by 126309378Sjhb * default "cooked" to provide more human-friendly output. 127309378Sjhb */ 128309378Sjhbconst var_format cookedvars[] = { 129309378Sjhb { "leap", LP }, 130309378Sjhb { "reach", OC }, 131309378Sjhb { "refid", RF }, 132309378Sjhb { "reftime", TS }, 133309378Sjhb { "clock", TS }, 134309378Sjhb { "org", TS }, 135309378Sjhb { "rec", TS }, 136309378Sjhb { "xmt", TS }, 137309378Sjhb { "flash", FX }, 138309378Sjhb { "srcadr", HA }, 139309378Sjhb { "peeradr", HA }, /* compat with others */ 140309378Sjhb { "dstadr", NA }, 141309378Sjhb { "filtdelay", AR }, 142309378Sjhb { "filtoffset", AR }, 143309378Sjhb { "filtdisp", AR }, 144309378Sjhb { "filterror", AR }, /* compat with others */ 145309378Sjhb}; 146309378Sjhb 147309378Sjhb 148309378Sjhb 149309378Sjhb/* 150219820Sjeff * flasher bits 151219820Sjeff */ 152219820Sjeffstatic const char *tstflagnames[] = { 153219820Sjeff "pkt_dup", /* TEST1 */ 154219820Sjeff "pkt_bogus", /* TEST2 */ 155219820Sjeff "pkt_unsync", /* TEST3 */ 156219820Sjeff "pkt_denied", /* TEST4 */ 157219820Sjeff "pkt_auth", /* TEST5 */ 158219820Sjeff "pkt_stratum", /* TEST6 */ 159219820Sjeff "pkt_header", /* TEST7 */ 160219820Sjeff "pkt_autokey", /* TEST8 */ 161219820Sjeff "pkt_crypto", /* TEST9 */ 162219820Sjeff "peer_stratum", /* TEST10 */ 163219820Sjeff "peer_dist", /* TEST11 */ 164219820Sjeff "peer_loop", /* TEST12 */ 165219820Sjeff "peer_unreach" /* TEST13 */ 166219820Sjeff}; 167219820Sjeff 168219820Sjeff 169219820Sjeffint ntpqmain (int, char **); 170219820Sjeff/* 171219820Sjeff * Built in command handler declarations 172219820Sjeff */ 173219820Sjeffstatic int openhost (const char *, int); 174219820Sjeffstatic void dump_hex_printable(const void *, size_t); 175219820Sjeffstatic int sendpkt (void *, size_t); 176219820Sjeffstatic int getresponse (int, int, u_short *, size_t *, const char **, int); 177219820Sjeffstatic int sendrequest (int, associd_t, int, size_t, const char *); 178219820Sjeffstatic char * tstflags (u_long); 179219820Sjeff#ifndef BUILD_AS_LIB 180219820Sjeffstatic void getcmds (void); 181219820Sjeff#ifndef SYS_WINNT 182219820Sjeffstatic int abortcmd (void); 183219820Sjeff#endif /* SYS_WINNT */ 184219820Sjeffstatic void docmd (const char *); 185219820Sjeffstatic void tokenize (const char *, char **, int *); 186219820Sjeffstatic int getarg (const char *, int, arg_v *); 187219820Sjeff#endif /* BUILD_AS_LIB */ 188219820Sjeffstatic int findcmd (const char *, struct xcmd *, 189219820Sjeff struct xcmd *, struct xcmd **); 190219820Sjeffstatic int rtdatetolfp (char *, l_fp *); 191219820Sjeffstatic int decodearr (char *, int *, l_fp *); 192219820Sjeffstatic void help (struct parse *, FILE *); 193219820Sjeffstatic int helpsort (const void *, const void *); 194219820Sjeffstatic void printusage (struct xcmd *, FILE *); 195219820Sjeffstatic void timeout (struct parse *, FILE *); 196219820Sjeffstatic void auth_delay (struct parse *, FILE *); 197219820Sjeffstatic void host (struct parse *, FILE *); 198219820Sjeffstatic void ntp_poll (struct parse *, FILE *); 199219820Sjeffstatic void keyid (struct parse *, FILE *); 200219820Sjeffstatic void keytype (struct parse *, FILE *); 201219820Sjeffstatic void passwd (struct parse *, FILE *); 202219820Sjeffstatic void hostnames (struct parse *, FILE *); 203219820Sjeffstatic void setdebug (struct parse *, FILE *); 204219820Sjeffstatic void quit (struct parse *, FILE *); 205219820Sjeffstatic void showdrefid (struct parse *, FILE *); 206219820Sjeffstatic void version (struct parse *, FILE *); 207219820Sjeffstatic void raw (struct parse *, FILE *); 208219820Sjeffstatic void cooked (struct parse *, FILE *); 209219820Sjeffstatic void authenticate (struct parse *, FILE *); 210219820Sjeffstatic void ntpversion (struct parse *, FILE *); 211219820Sjeffstatic void warning (const char *, ...) 212219820Sjeff __attribute__((__format__(__printf__, 1, 2))); 213219820Sjeffstatic void error (const char *, ...) 214219820Sjeff __attribute__((__format__(__printf__, 1, 2))); 215219820Sjeffstatic u_long getkeyid (const char *); 216219820Sjeffstatic void atoascii (const char *, size_t, char *, size_t); 217219820Sjeffstatic void cookedprint (int, size_t, const char *, int, int, FILE *); 218219820Sjeffstatic void rawprint (int, size_t, const char *, int, int, FILE *); 219219820Sjeffstatic void startoutput (void); 220219820Sjeffstatic void output (FILE *, const char *, const char *); 221219820Sjeffstatic void endoutput (FILE *); 222219820Sjeffstatic void outputarr (FILE *, char *, int, l_fp *); 223219820Sjeffstatic int assoccmp (const void *, const void *); 224219820Sjeffstatic void on_ctrlc (void); 225219820Sjeff u_short varfmt (const char *); 226219820Sjeffstatic int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 227219820Sjeffvoid ntpq_custom_opt_handler (tOptions *, tOptDesc *); 228219820Sjeff 229219820Sjeff#ifdef OPENSSL 230219820Sjeff# ifdef HAVE_EVP_MD_DO_ALL_SORTED 231219820Sjeffstatic void list_md_fn(const EVP_MD *m, const char *from, 232219820Sjeff const char *to, void *arg ); 233219820Sjeff# endif 234219820Sjeff#endif 235219820Sjeffstatic char *list_digest_names(void); 236219820Sjeff 237219820Sjeff/* 238219820Sjeff * Built-in commands we understand 239219820Sjeff */ 240219820Sjeffstruct xcmd builtins[] = { 241219820Sjeff { "?", help, { OPT|NTP_STR, NO, NO, NO }, 242219820Sjeff { "command", "", "", "" }, 243219820Sjeff "tell the use and syntax of commands" }, 244219820Sjeff { "help", help, { OPT|NTP_STR, NO, NO, NO }, 245219820Sjeff { "command", "", "", "" }, 246219820Sjeff "tell the use and syntax of commands" }, 247219820Sjeff { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 248219820Sjeff { "msec", "", "", "" }, 249219820Sjeff "set the primary receive time out" }, 250219820Sjeff { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 251219820Sjeff { "msec", "", "", "" }, 252219820Sjeff "set the delay added to encryption time stamps" }, 253219820Sjeff { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 254219820Sjeff { "-4|-6", "hostname", "", "" }, 255219820Sjeff "specify the host whose NTP server we talk to" }, 256219820Sjeff { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 257219820Sjeff { "n", "verbose", "", "" }, 258219820Sjeff "poll an NTP server in client mode `n' times" }, 259219820Sjeff { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 260219820Sjeff { "", "", "", "" }, 261219820Sjeff "specify a password to use for authenticated requests"}, 262219820Sjeff { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 263219820Sjeff { "yes|no", "", "", "" }, 264219820Sjeff "specify whether hostnames or net numbers are printed"}, 265219820Sjeff { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 266309378Sjhb { "no|more|less", "", "", "" }, 267309378Sjhb "set/change debugging level" }, 268219820Sjeff { "quit", quit, { NO, NO, NO, NO }, 269309378Sjhb { "", "", "", "" }, 270309378Sjhb "exit ntpq" }, 271309378Sjhb { "exit", quit, { NO, NO, NO, NO }, 272309378Sjhb { "", "", "", "" }, 273309378Sjhb "exit ntpq" }, 274309378Sjhb { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 275309378Sjhb { "key#", "", "", "" }, 276219820Sjeff "set keyid to use for authenticated requests" }, 277219820Sjeff { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 278219820Sjeff { "hash|ipv4", "", "", "" }, 279219820Sjeff "display refid's as IPv4 or hash" }, 280219820Sjeff { "version", version, { NO, NO, NO, NO }, 281219820Sjeff { "", "", "", "" }, 282219820Sjeff "print version number" }, 283219820Sjeff { "raw", raw, { NO, NO, NO, NO }, 284237263Snp { "", "", "", "" }, 285219820Sjeff "do raw mode variable output" }, 286219820Sjeff { "cooked", cooked, { NO, NO, NO, NO }, 287219820Sjeff { "", "", "", "" }, 288219820Sjeff "do cooked mode variable output" }, 289219820Sjeff { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 290219820Sjeff { "yes|no", "", "", "" }, 291219820Sjeff "always authenticate requests to this server" }, 292219820Sjeff { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 293219820Sjeff { "version number", "", "", "" }, 294219820Sjeff "set the NTP version number to use for requests" }, 295219820Sjeff { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 296219820Sjeff { "key type %s", "", "", "" }, 297219820Sjeff NULL }, 298219820Sjeff { 0, 0, { NO, NO, NO, NO }, 299219820Sjeff { "", "", "", "" }, "" } 300219820Sjeff}; 301237263Snp 302219820Sjeff 303219820Sjeff/* 304219820Sjeff * Default values we use. 305219820Sjeff */ 306219820Sjeff#define DEFHOST "localhost" /* default host name */ 307219820Sjeff#define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 308219820Sjeff#define DEFSTIMEOUT 3 /* and 3 more for each additional */ 309219820Sjeff/* 310219820Sjeff * Requests are automatically retried once, so total timeout with no 311219820Sjeff * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 312219820Sjeff * extreme, a request eliciting 32 packets of responses each for some 313219820Sjeff * reason nearly DEFSTIMEOUT seconds after the prior in that series, 314219820Sjeff * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 315219820Sjeff * 93 seconds to fail each of two times, or 186 seconds. 316219820Sjeff * Some commands involve a series of requests, such as "peers" and 317219820Sjeff * "mrulist", so the cumulative timeouts are even longer for those. 318219820Sjeff */ 319219820Sjeff#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 320219820Sjeff#define LENHOSTNAME 256 /* host name is 256 characters long */ 321219820Sjeff#define MAXCMDS 100 /* maximum commands on cmd line */ 322219820Sjeff#define MAXHOSTS 200 /* maximum hosts on cmd line */ 323219820Sjeff#define MAXLINE 512 /* maximum line length */ 324219820Sjeff#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 325219820Sjeff#define MAXVARLEN 256 /* maximum length of a variable name */ 326219820Sjeff#define MAXVALLEN 2048 /* maximum length of a variable value */ 327219820Sjeff#define MAXOUTLINE 72 /* maximum length of an output line */ 328219820Sjeff#define SCREENWIDTH 76 /* nominal screen width in columns */ 329219820Sjeff 330219820Sjeff/* 331219820Sjeff * Some variables used and manipulated locally 332219820Sjeff */ 333219820Sjeffstruct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 334219820Sjeffstruct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 335219820Sjeffl_fp delay_time; /* delay time */ 336219820Sjeffchar currenthost[LENHOSTNAME]; /* current host name */ 337219820Sjeffint currenthostisnum; /* is prior text from IP? */ 338219820Sjeffstruct sockaddr_in hostaddr; /* host address */ 339219820Sjeffint showhostnames = 1; /* show host names by default */ 340219820Sjeffint wideremote = 0; /* show wide remote names? */ 341219820Sjeff 342219820Sjeffint ai_fam_templ; /* address family */ 343219820Sjeffint ai_fam_default; /* default address family */ 344219820SjeffSOCKET sockfd; /* fd socket is opened on */ 345219820Sjeffint havehost = 0; /* set to 1 when host open */ 346219820Sjeffint s_port = 0; 347219820Sjeffstruct servent *server_entry = NULL; /* server entry for ntp */ 348219820Sjeff 349219820Sjeff 350219820Sjeff/* 351219820Sjeff * Sequence number used for requests. It is incremented before 352219820Sjeff * it is used. 353219820Sjeff */ 354219820Sjeffu_short sequence; 355219820Sjeff 356219820Sjeff/* 357219820Sjeff * Holds data returned from queries. Declare buffer long to be sure of 358219820Sjeff * alignment. 359219820Sjeff */ 360219820Sjeff#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 361219820Sjefflong pktdata[DATASIZE/sizeof(long)]; 362219820Sjeff 363219820Sjeff/* 364219820Sjeff * assoc_cache[] is a dynamic array which allows references to 365219820Sjeff * associations using &1 ... &N for n associations, avoiding manual 366219820Sjeff * lookup of the current association IDs for a given ntpd. It also 367219820Sjeff * caches the status word for each association, retrieved incidentally. 368219820Sjeff */ 369219820Sjeffstruct association * assoc_cache; 370219820Sjeffu_int assoc_cache_slots;/* count of allocated array entries */ 371219820Sjeffu_int numassoc; /* number of cached associations */ 372219820Sjeff 373219820Sjeff/* 374219820Sjeff * For commands typed on the command line (with the -c option) 375219820Sjeff */ 376219820Sjeffint numcmds = 0; 377219820Sjeffconst char *ccmds[MAXCMDS]; 378219820Sjeff#define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp) 379219820Sjeff 380219820Sjeff/* 381219820Sjeff * When multiple hosts are specified. 382219820Sjeff */ 383219820Sjeff 384219820Sjeffu_int numhosts; 385219820Sjeff 386219820Sjeffchost chosts[MAXHOSTS]; 387219820Sjeff#define ADDHOST(cp) \ 388219820Sjeff do { \ 389219820Sjeff if (numhosts < MAXHOSTS) { \ 390219820Sjeff chosts[numhosts].name = (cp); \ 391219820Sjeff chosts[numhosts].fam = ai_fam_templ; \ 392219820Sjeff numhosts++; \ 393219820Sjeff } \ 394219820Sjeff } while (0) 395219820Sjeff 396219820Sjeff/* 397219820Sjeff * Macro definitions we use 398219820Sjeff */ 399219820Sjeff#define ISSPACE(c) ((c) == ' ' || (c) == '\t') 400219820Sjeff#define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 401219820Sjeff#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 402219820Sjeff 403219820Sjeff/* 404219820Sjeff * Jump buffer for longjumping back to the command level 405219820Sjeff */ 406219820Sjeffjmp_buf interrupt_buf; 407219820Sjeff 408219820Sjeff/* 409219820Sjeff * Points at file being currently printed into 410219820Sjeff */ 411309378SjhbFILE *current_output; 412309378Sjhb 413309378Sjhb/* 414309378Sjhb * Command table imported from ntpdc_ops.c 415309378Sjhb */ 416309378Sjhbextern struct xcmd opcmds[]; 417309378Sjhb 418309378Sjhbchar const *progname; 419309378Sjhb 420309378Sjhb#ifdef NO_MAIN_ALLOWED 421309378Sjhb#ifndef BUILD_AS_LIB 422309378SjhbCALL(ntpq,"ntpq",ntpqmain); 423309378Sjhb 424309378Sjhbvoid clear_globals(void) 425309378Sjhb{ 426309378Sjhb extern int ntp_optind; 427309378Sjhb showhostnames = 0; /* don'tshow host names by default */ 428309378Sjhb ntp_optind = 0; 429309378Sjhb server_entry = NULL; /* server entry for ntp */ 430309378Sjhb havehost = 0; /* set to 1 when host open */ 431309378Sjhb numassoc = 0; /* number of cached associations */ 432309378Sjhb numcmds = 0; 433309378Sjhb numhosts = 0; 434309378Sjhb} 435309378Sjhb#endif /* !BUILD_AS_LIB */ 436309378Sjhb#endif /* NO_MAIN_ALLOWED */ 437309378Sjhb 438309378Sjhb/* 439309378Sjhb * main - parse arguments and handle options 440309378Sjhb */ 441309378Sjhb#ifndef NO_MAIN_ALLOWED 442309378Sjhbint 443309378Sjhbmain( 444309378Sjhb int argc, 445309378Sjhb char *argv[] 446309378Sjhb ) 447309378Sjhb{ 448309378Sjhb return ntpqmain(argc, argv); 449309378Sjhb} 450309378Sjhb#endif 451309378Sjhb 452309378Sjhb#ifndef BUILD_AS_LIB 453309378Sjhbint 454309378Sjhbntpqmain( 455309378Sjhb int argc, 456309378Sjhb char *argv[] 457309378Sjhb ) 458309378Sjhb{ 459309378Sjhb u_int ihost; 460309378Sjhb int icmd; 461309378Sjhb 462309378Sjhb 463309378Sjhb#ifdef SYS_VXWORKS 464309378Sjhb clear_globals(); 465309378Sjhb taskPrioritySet(taskIdSelf(), 100 ); 466309378Sjhb#endif 467309378Sjhb 468309378Sjhb delay_time.l_ui = 0; 469309378Sjhb delay_time.l_uf = DEFDELAY; 470309378Sjhb 471309378Sjhb init_lib(); /* sets up ipv4_works, ipv6_works */ 472309378Sjhb ssl_applink(); 473309378Sjhb init_auth(); 474309378Sjhb 475309378Sjhb /* Check to see if we have IPv6. Otherwise default to IPv4 */ 476309378Sjhb if (!ipv6_works) 477309378Sjhb ai_fam_default = AF_INET; 478309378Sjhb 479309378Sjhb /* Fixup keytype's help based on available digest names */ 480309378Sjhb 481309378Sjhb { 482309378Sjhb char *list; 483309378Sjhb char *msg; 484309378Sjhb 485309378Sjhb list = list_digest_names(); 486309378Sjhb for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) { 487309378Sjhb if (strcmp("keytype", builtins[icmd].keyword) == 0) 488309378Sjhb break; 489309378Sjhb } 490309378Sjhb 491309378Sjhb /* CID: 1295478 */ 492309378Sjhb /* This should only "trip" if "keytype" is removed from builtins */ 493309378Sjhb INSIST(icmd < sizeof(builtins)/sizeof(builtins[0])); 494309378Sjhb 495309378Sjhb#ifdef OPENSSL 496309378Sjhb builtins[icmd].desc[0] = "digest-name"; 497309378Sjhb my_easprintf(&msg, 498309378Sjhb "set key type to use for authenticated requests, one of:%s", 499309378Sjhb list); 500309378Sjhb#else 501309378Sjhb builtins[icmd].desc[0] = "md5"; 502309378Sjhb my_easprintf(&msg, 503309378Sjhb "set key type to use for authenticated requests (%s)", 504309378Sjhb list); 505309378Sjhb#endif 506309378Sjhb builtins[icmd].comment = msg; 507309378Sjhb free(list); 508309378Sjhb } 509309378Sjhb 510309378Sjhb progname = argv[0]; 511309378Sjhb 512309378Sjhb { 513309378Sjhb int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 514309378Sjhb argc -= optct; 515309378Sjhb argv += optct; 516309378Sjhb } 517309378Sjhb 518309378Sjhb /* 519309378Sjhb * Process options other than -c and -p, which are specially 520309378Sjhb * handled by ntpq_custom_opt_handler(). 521309378Sjhb */ 522309378Sjhb 523309378Sjhb debug = OPT_VALUE_SET_DEBUG_LEVEL; 524309378Sjhb 525309378Sjhb if (HAVE_OPT(IPV4)) 526309378Sjhb ai_fam_templ = AF_INET; 527309378Sjhb else if (HAVE_OPT(IPV6)) 528314606Snp ai_fam_templ = AF_INET6; 529309378Sjhb else 530309378Sjhb ai_fam_templ = ai_fam_default; 531309378Sjhb 532309378Sjhb if (HAVE_OPT(INTERACTIVE)) 533309378Sjhb interactive = 1; 534309378Sjhb 535309378Sjhb if (HAVE_OPT(NUMERIC)) 536314606Snp showhostnames = 0; 537309378Sjhb 538309378Sjhb if (HAVE_OPT(WIDE)) 539309378Sjhb wideremote = 1; 540309378Sjhb 541309378Sjhb old_rv = HAVE_OPT(OLD_RV); 542309378Sjhb 543309378Sjhb drefid = OPT_VALUE_REFID; 544309378Sjhb 545314606Snp if (0 == argc) { 546309378Sjhb ADDHOST(DEFHOST); 547314606Snp } else { 548314606Snp for (ihost = 0; ihost < (u_int)argc; ihost++) { 549309378Sjhb if ('-' == *argv[ihost]) { 550309378Sjhb // 551309378Sjhb // If I really cared I'd also check: 552309378Sjhb // 0 == argv[ihost][2] 553309378Sjhb // 554314606Snp // and there are other cases as well... 555314606Snp // 556309378Sjhb if ('4' == argv[ihost][1]) { 557309378Sjhb ai_fam_templ = AF_INET; 558309378Sjhb continue; 559219820Sjeff } else if ('6' == argv[ihost][1]) { 560219820Sjeff ai_fam_templ = AF_INET6; 561219820Sjeff continue; 562219820Sjeff } else { 563219820Sjeff // XXX Throw a usage error 564219820Sjeff } 565219820Sjeff } 566219820Sjeff ADDHOST(argv[ihost]); 567219820Sjeff } 568219820Sjeff } 569309378Sjhb 570219820Sjeff if (numcmds == 0 && interactive == 0 571219820Sjeff && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 572219820Sjeff interactive = 1; 573219820Sjeff } 574219820Sjeff 575219820Sjeff set_ctrl_c_hook(on_ctrlc); 576219820Sjeff#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 577219820Sjeff if (interactive) 578219820Sjeff push_ctrl_c_handler(abortcmd); 579219820Sjeff#endif /* SYS_WINNT */ 580219820Sjeff 581219820Sjeff if (numcmds == 0) { 582219820Sjeff (void) openhost(chosts[0].name, chosts[0].fam); 583219820Sjeff getcmds(); 584309378Sjhb } else { 585309378Sjhb for (ihost = 0; ihost < numhosts; ihost++) { 586309378Sjhb if (openhost(chosts[ihost].name, chosts[ihost].fam)) 587309378Sjhb for (icmd = 0; icmd < numcmds; icmd++) 588309378Sjhb docmd(ccmds[icmd]); 589309378Sjhb } 590309378Sjhb } 591309378Sjhb#ifdef SYS_WINNT 592309378Sjhb WSACleanup(); 593309378Sjhb#endif /* SYS_WINNT */ 594309378Sjhb return 0; 595309378Sjhb} 596219820Sjeff#endif /* !BUILD_AS_LIB */ 597219820Sjeff 598219820Sjeff/* 599219820Sjeff * openhost - open a socket to a host 600219820Sjeff */ 601219820Sjeffstatic int 602219820Sjeffopenhost( 603219820Sjeff const char *hname, 604219820Sjeff int fam 605219820Sjeff ) 606219820Sjeff{ 607219820Sjeff const char svc[] = "ntp"; 608219820Sjeff char temphost[LENHOSTNAME]; 609219820Sjeff int a_info, i; 610219820Sjeff struct addrinfo hints, *ai; 611219820Sjeff sockaddr_u addr; 612219820Sjeff size_t octets; 613219820Sjeff register const char *cp; 614219820Sjeff char name[LENHOSTNAME]; 615219820Sjeff 616219820Sjeff /* 617219820Sjeff * We need to get by the [] if they were entered 618219820Sjeff */ 619219820Sjeff 620219820Sjeff cp = hname; 621219820Sjeff 622219820Sjeff if (*cp == '[') { 623219820Sjeff cp++; 624219820Sjeff for (i = 0; *cp && *cp != ']'; cp++, i++) 625219820Sjeff name[i] = *cp; 626219820Sjeff if (*cp == ']') { 627219820Sjeff name[i] = '\0'; 628219820Sjeff hname = name; 629219820Sjeff } else { 630219820Sjeff return 0; 631219820Sjeff } 632219820Sjeff } 633219820Sjeff 634219820Sjeff /* 635219820Sjeff * First try to resolve it as an ip address and if that fails, 636219820Sjeff * do a fullblown (dns) lookup. That way we only use the dns 637219820Sjeff * when it is needed and work around some implementations that 638219820Sjeff * will return an "IPv4-mapped IPv6 address" address if you 639219820Sjeff * give it an IPv4 address to lookup. 640219820Sjeff */ 641219820Sjeff ZERO(hints); 642219820Sjeff hints.ai_family = fam; 643219820Sjeff hints.ai_protocol = IPPROTO_UDP; 644219820Sjeff hints.ai_socktype = SOCK_DGRAM; 645219820Sjeff hints.ai_flags = Z_AI_NUMERICHOST; 646219820Sjeff ai = NULL; 647219820Sjeff 648219820Sjeff a_info = getaddrinfo(hname, svc, &hints, &ai); 649219820Sjeff if (a_info == EAI_NONAME 650219820Sjeff#ifdef EAI_NODATA 651219820Sjeff || a_info == EAI_NODATA 652219820Sjeff#endif 653314606Snp ) { 654314606Snp hints.ai_flags = AI_CANONNAME; 655314606Snp#ifdef AI_ADDRCONFIG 656219820Sjeff hints.ai_flags |= AI_ADDRCONFIG; 657219820Sjeff#endif 658219820Sjeff a_info = getaddrinfo(hname, svc, &hints, &ai); 659219820Sjeff } 660219820Sjeff#ifdef AI_ADDRCONFIG 661219820Sjeff /* Some older implementations don't like AI_ADDRCONFIG. */ 662219820Sjeff if (a_info == EAI_BADFLAGS) { 663219820Sjeff hints.ai_flags &= ~AI_ADDRCONFIG; 664219820Sjeff a_info = getaddrinfo(hname, svc, &hints, &ai); 665219820Sjeff } 666219820Sjeff#endif 667219820Sjeff if (a_info != 0) { 668219820Sjeff fprintf(stderr, "%s\n", gai_strerror(a_info)); 669219820Sjeff return 0; 670309378Sjhb } 671219820Sjeff 672219820Sjeff INSIST(ai != NULL); 673219820Sjeff ZERO(addr); 674219820Sjeff octets = min(sizeof(addr), ai->ai_addrlen); 675219820Sjeff memcpy(&addr, ai->ai_addr, octets); 676219820Sjeff 677219820Sjeff if (ai->ai_canonname == NULL) { 678219820Sjeff strlcpy(temphost, stoa(&addr), sizeof(temphost)); 679219820Sjeff currenthostisnum = TRUE; 680219820Sjeff } else { 681219820Sjeff strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 682219820Sjeff currenthostisnum = FALSE; 683309378Sjhb } 684309378Sjhb 685309378Sjhb if (debug > 2) 686309378Sjhb printf("Opening host %s (%s)\n", 687309378Sjhb temphost, 688309378Sjhb (ai->ai_family == AF_INET) 689309378Sjhb ? "AF_INET" 690309378Sjhb : (ai->ai_family == AF_INET6) 691309378Sjhb ? "AF_INET6" 692309378Sjhb : "AF-???" 693309378Sjhb ); 694309378Sjhb 695309378Sjhb if (havehost == 1) { 696309378Sjhb if (debug > 2) 697309378Sjhb printf("Closing old host %s\n", currenthost); 698309378Sjhb closesocket(sockfd); 699309378Sjhb havehost = 0; 700309378Sjhb } 701309378Sjhb strlcpy(currenthost, temphost, sizeof(currenthost)); 702309378Sjhb 703309378Sjhb /* port maps to the same location in both families */ 704309378Sjhb s_port = NSRCPORT(&addr); 705309378Sjhb#ifdef SYS_VXWORKS 706309378Sjhb ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 707309378Sjhb if (ai->ai_family == AF_INET) 708219820Sjeff *(struct sockaddr_in *)&hostaddr= 709309378Sjhb *((struct sockaddr_in *)ai->ai_addr); 710219820Sjeff else 711219820Sjeff *(struct sockaddr_in6 *)&hostaddr= 712219820Sjeff *((struct sockaddr_in6 *)ai->ai_addr); 713219820Sjeff#endif /* SYS_VXWORKS */ 714219820Sjeff 715219820Sjeff#ifdef SYS_WINNT 716219820Sjeff { 717219820Sjeff int optionValue = SO_SYNCHRONOUS_NONALERT; 718219820Sjeff int err; 719219820Sjeff 720219820Sjeff err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 721219820Sjeff (char *)&optionValue, sizeof(optionValue)); 722219820Sjeff if (err) { 723219820Sjeff mfprintf(stderr, 724219820Sjeff "setsockopt(SO_SYNCHRONOUS_NONALERT)" 725219820Sjeff " error: %m\n"); 726219820Sjeff freeaddrinfo(ai); 727219820Sjeff exit(1); 728219820Sjeff } 729219820Sjeff } 730219820Sjeff#endif /* SYS_WINNT */ 731219820Sjeff 732219820Sjeff sockfd = socket(ai->ai_family, ai->ai_socktype, 733219820Sjeff ai->ai_protocol); 734219820Sjeff if (sockfd == INVALID_SOCKET) { 735219820Sjeff error("socket"); 736219820Sjeff freeaddrinfo(ai); 737219820Sjeff return 0; 738219820Sjeff } 739219820Sjeff 740219820Sjeff 741219820Sjeff#ifdef NEED_RCVBUF_SLOP 742219820Sjeff# ifdef SO_RCVBUF 743219820Sjeff { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 744219820Sjeff if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 745219820Sjeff &rbufsize, sizeof(int)) == -1) 746219820Sjeff error("setsockopt"); 747219820Sjeff } 748219820Sjeff# endif 749219820Sjeff#endif 750219820Sjeff 751219820Sjeff if 752219820Sjeff#ifdef SYS_VXWORKS 753219820Sjeff (connect(sockfd, (struct sockaddr *)&hostaddr, 754219820Sjeff sizeof(hostaddr)) == -1) 755219820Sjeff#else 756219820Sjeff (connect(sockfd, (struct sockaddr *)ai->ai_addr, 757219820Sjeff ai->ai_addrlen) == -1) 758219820Sjeff#endif /* SYS_VXWORKS */ 759219820Sjeff { 760219820Sjeff error("connect"); 761219820Sjeff freeaddrinfo(ai); 762219820Sjeff return 0; 763219820Sjeff } 764219820Sjeff freeaddrinfo(ai); 765219820Sjeff havehost = 1; 766219820Sjeff numassoc = 0; 767219820Sjeff 768219820Sjeff return 1; 769219820Sjeff} 770219820Sjeff 771219820Sjeff 772219820Sjeffstatic void 773219820Sjeffdump_hex_printable( 774219820Sjeff const void * data, 775219820Sjeff size_t len 776219820Sjeff ) 777219820Sjeff{ 778219820Sjeff const char * cdata; 779219820Sjeff const char * rowstart; 780219820Sjeff size_t idx; 781219820Sjeff size_t rowlen; 782219820Sjeff u_char uch; 783219820Sjeff 784219820Sjeff cdata = data; 785219820Sjeff while (len > 0) { 786219820Sjeff rowstart = cdata; 787219820Sjeff rowlen = min(16, len); 788219820Sjeff for (idx = 0; idx < rowlen; idx++) { 789219820Sjeff uch = *(cdata++); 790219820Sjeff printf("%02x ", uch); 791219820Sjeff } 792219820Sjeff for ( ; idx < 16 ; idx++) 793219820Sjeff printf(" "); 794219820Sjeff cdata = rowstart; 795219820Sjeff for (idx = 0; idx < rowlen; idx++) { 796219820Sjeff uch = *(cdata++); 797219820Sjeff printf("%c", (isprint(uch)) 798219820Sjeff ? uch 799219820Sjeff : '.'); 800219820Sjeff } 801219820Sjeff printf("\n"); 802219820Sjeff len -= rowlen; 803219820Sjeff } 804219820Sjeff} 805219820Sjeff 806219820Sjeff 807219820Sjeff/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 808219820Sjeff/* 809219820Sjeff * sendpkt - send a packet to the remote host 810219820Sjeff */ 811219820Sjeffstatic int 812219820Sjeffsendpkt( 813219820Sjeff void * xdata, 814219820Sjeff size_t xdatalen 815219820Sjeff ) 816219820Sjeff{ 817219820Sjeff if (debug >= 3) 818219820Sjeff printf("Sending %zu octets\n", xdatalen); 819219820Sjeff 820219820Sjeff if (send(sockfd, xdata, xdatalen, 0) == -1) { 821219820Sjeff warning("write to %s failed", currenthost); 822219820Sjeff return -1; 823219820Sjeff } 824219820Sjeff 825219820Sjeff if (debug >= 4) { 826219820Sjeff printf("Request packet:\n"); 827219820Sjeff dump_hex_printable(xdata, xdatalen); 828219820Sjeff } 829219820Sjeff return 0; 830219820Sjeff} 831219820Sjeff 832219820Sjeff/* 833219820Sjeff * getresponse - get a (series of) response packet(s) and return the data 834219820Sjeff */ 835219820Sjeffstatic int 836219820Sjeffgetresponse( 837219820Sjeff int opcode, 838219820Sjeff int associd, 839219820Sjeff u_short *rstatus, 840219820Sjeff size_t *rsize, 841219820Sjeff const char **rdata, 842219820Sjeff int timeo 843219820Sjeff ) 844219820Sjeff{ 845219820Sjeff struct ntp_control rpkt; 846219820Sjeff struct sock_timeval tvo; 847219820Sjeff u_short offsets[MAXFRAGS+1]; 848219820Sjeff u_short counts[MAXFRAGS+1]; 849219820Sjeff u_short offset; 850219820Sjeff u_short count; 851219820Sjeff size_t numfrags; 852219820Sjeff size_t f; 853219820Sjeff size_t ff; 854219820Sjeff int seenlastfrag; 855219820Sjeff int shouldbesize; 856219820Sjeff fd_set fds; 857219820Sjeff int n; 858219820Sjeff int errcode; 859219820Sjeff /* absolute timeout checks. Not 'time_t' by intention! */ 860219820Sjeff uint32_t tobase; /* base value for timeout */ 861219820Sjeff uint32_t tospan; /* timeout span (max delay) */ 862219820Sjeff uint32_t todiff; /* current delay */ 863219820Sjeff 864219820Sjeff /* 865219820Sjeff * This is pretty tricky. We may get between 1 and MAXFRAG packets 866219820Sjeff * back in response to the request. We peel the data out of 867219820Sjeff * each packet and collect it in one long block. When the last 868219820Sjeff * packet in the sequence is received we'll know how much data we 869219820Sjeff * should have had. Note we use one long time out, should reconsider. 870219820Sjeff */ 871219820Sjeff *rsize = 0; 872219820Sjeff if (rstatus) 873219820Sjeff *rstatus = 0; 874219820Sjeff *rdata = (char *)pktdata; 875219820Sjeff 876219820Sjeff numfrags = 0; 877219820Sjeff seenlastfrag = 0; 878219820Sjeff 879219820Sjeff tobase = (uint32_t)time(NULL); 880219820Sjeff 881219820Sjeff FD_ZERO(&fds); 882219820Sjeff 883219820Sjeff /* 884219820Sjeff * Loop until we have an error or a complete response. Nearly all 885219820Sjeff * code paths to loop again use continue. 886219820Sjeff */ 887219820Sjeff for (;;) { 888219820Sjeff 889219820Sjeff if (numfrags == 0) 890219820Sjeff tvo = tvout; 891219820Sjeff else 892219820Sjeff tvo = tvsout; 893219820Sjeff tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 894219820Sjeff 895219820Sjeff FD_SET(sockfd, &fds); 896219820Sjeff n = select(sockfd+1, &fds, NULL, NULL, &tvo); 897219820Sjeff if (n == -1) { 898219820Sjeff#if !defined(SYS_WINNT) && defined(EINTR) 899219820Sjeff /* Windows does not know about EINTR (until very 900219820Sjeff * recently) and the handling of console events 901219820Sjeff * is *very* different from POSIX/UNIX signal 902219820Sjeff * handling anyway. 903219820Sjeff * 904219820Sjeff * Under non-windows targets we map EINTR as 905219820Sjeff * 'last packet was received' and try to exit 906219820Sjeff * the receive sequence. 907219820Sjeff */ 908219820Sjeff if (errno == EINTR) { 909219820Sjeff seenlastfrag = 1; 910219820Sjeff goto maybe_final; 911237263Snp } 912219820Sjeff#endif 913219820Sjeff warning("select fails"); 914219820Sjeff return -1; 915219820Sjeff } 916219820Sjeff 917219820Sjeff /* 918219820Sjeff * Check if this is already too late. Trash the data and 919219820Sjeff * fake a timeout if this is so. 920219820Sjeff */ 921219820Sjeff todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 922219820Sjeff if ((n > 0) && (todiff > tospan)) { 923219820Sjeff n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 924219820Sjeff n = 0; /* faked timeout return from 'select()'*/ 925219820Sjeff } 926219820Sjeff 927219820Sjeff if (n == 0) { 928219820Sjeff /* 929219820Sjeff * Timed out. Return what we have 930219820Sjeff */ 931219820Sjeff if (numfrags == 0) { 932219820Sjeff if (timeo) 933219820Sjeff fprintf(stderr, 934219820Sjeff "%s: timed out, nothing received\n", 935219820Sjeff currenthost); 936219820Sjeff return ERR_TIMEOUT; 937219820Sjeff } 938219820Sjeff if (timeo) 939219820Sjeff fprintf(stderr, 940219820Sjeff "%s: timed out with incomplete data\n", 941219820Sjeff currenthost); 942219820Sjeff if (debug) { 943219820Sjeff fprintf(stderr, 944219820Sjeff "ERR_INCOMPLETE: Received fragments:\n"); 945219820Sjeff for (f = 0; f < numfrags; f++) 946219820Sjeff fprintf(stderr, 947219820Sjeff "%2u: %5d %5d\t%3d octets\n", 948219820Sjeff (u_int)f, offsets[f], 949219820Sjeff offsets[f] + 950219820Sjeff counts[f], 951219820Sjeff counts[f]); 952219820Sjeff fprintf(stderr, 953219820Sjeff "last fragment %sreceived\n", 954219820Sjeff (seenlastfrag) 955219820Sjeff ? "" 956219820Sjeff : "not "); 957219820Sjeff } 958219820Sjeff return ERR_INCOMPLETE; 959219820Sjeff } 960219820Sjeff 961219820Sjeff n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 962219820Sjeff if (n == -1) { 963219820Sjeff warning("read"); 964219820Sjeff return -1; 965219820Sjeff } 966219820Sjeff 967219820Sjeff if (debug >= 4) { 968219820Sjeff printf("Response packet:\n"); 969219820Sjeff dump_hex_printable(&rpkt, n); 970219820Sjeff } 971219820Sjeff 972219820Sjeff /* 973219820Sjeff * Check for format errors. Bug proofing. 974219820Sjeff */ 975219820Sjeff if (n < (int)CTL_HEADER_LEN) { 976219820Sjeff if (debug) 977219820Sjeff printf("Short (%d byte) packet received\n", n); 978219820Sjeff continue; 979219820Sjeff } 980219820Sjeff if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 981219820Sjeff || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 982219820Sjeff if (debug) 983219820Sjeff printf("Packet received with version %d\n", 984219820Sjeff PKT_VERSION(rpkt.li_vn_mode)); 985219820Sjeff continue; 986219820Sjeff } 987219820Sjeff if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 988219820Sjeff if (debug) 989219820Sjeff printf("Packet received with mode %d\n", 990219820Sjeff PKT_MODE(rpkt.li_vn_mode)); 991219820Sjeff continue; 992219820Sjeff } 993219820Sjeff if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 994219820Sjeff if (debug) 995219820Sjeff printf("Received request packet, wanted response\n"); 996219820Sjeff continue; 997219820Sjeff } 998219820Sjeff 999219820Sjeff /* 1000219820Sjeff * Check opcode and sequence number for a match. 1001219820Sjeff * Could be old data getting to us. 1002219820Sjeff */ 1003219820Sjeff if (ntohs(rpkt.sequence) != sequence) { 1004219820Sjeff if (debug) 1005219820Sjeff printf("Received sequnce number %d, wanted %d\n", 1006219820Sjeff ntohs(rpkt.sequence), sequence); 1007219820Sjeff continue; 1008219820Sjeff } 1009219820Sjeff if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1010219820Sjeff if (debug) 1011219820Sjeff printf( 1012219820Sjeff "Received opcode %d, wanted %d (sequence number okay)\n", 1013219820Sjeff CTL_OP(rpkt.r_m_e_op), opcode); 1014219820Sjeff continue; 1015219820Sjeff } 1016219820Sjeff 1017219820Sjeff /* 1018219820Sjeff * Check the error code. If non-zero, return it. 1019219820Sjeff */ 1020219820Sjeff if (CTL_ISERROR(rpkt.r_m_e_op)) { 1021219820Sjeff errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1022219820Sjeff if (CTL_ISMORE(rpkt.r_m_e_op)) 1023219820Sjeff TRACE(1, ("Error code %d received on not-final packet\n", 1024219820Sjeff errcode)); 1025219820Sjeff if (errcode == CERR_UNSPEC) 1026219820Sjeff return ERR_UNSPEC; 1027219820Sjeff return errcode; 1028219820Sjeff } 1029219820Sjeff 1030219820Sjeff /* 1031219820Sjeff * Check the association ID to make sure it matches what 1032219820Sjeff * we sent. 1033219820Sjeff */ 1034219820Sjeff if (ntohs(rpkt.associd) != associd) { 1035219820Sjeff TRACE(1, ("Association ID %d doesn't match expected %d\n", 1036219820Sjeff ntohs(rpkt.associd), associd)); 1037219820Sjeff /* 1038219820Sjeff * Hack for silly fuzzballs which, at the time of writing, 1039219820Sjeff * return an assID of sys.peer when queried for system variables. 1040219820Sjeff */ 1041219820Sjeff#ifdef notdef 1042219820Sjeff continue; 1043219820Sjeff#endif 1044219820Sjeff } 1045219820Sjeff 1046219820Sjeff /* 1047219820Sjeff * Collect offset and count. Make sure they make sense. 1048219820Sjeff */ 1049219820Sjeff offset = ntohs(rpkt.offset); 1050219820Sjeff count = ntohs(rpkt.count); 1051219820Sjeff 1052219820Sjeff /* 1053219820Sjeff * validate received payload size is padded to next 32-bit 1054219820Sjeff * boundary and no smaller than claimed by rpkt.count 1055219820Sjeff */ 1056219820Sjeff if (n & 0x3) { 1057219820Sjeff TRACE(1, ("Response packet not padded, size = %d\n", 1058219820Sjeff n)); 1059219820Sjeff continue; 1060219820Sjeff } 1061219820Sjeff 1062219820Sjeff shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 1063219820Sjeff 1064219820Sjeff if (n < shouldbesize) { 1065219820Sjeff printf("Response packet claims %u octets payload, above %ld received\n", 1066219820Sjeff count, (long)(n - CTL_HEADER_LEN)); 1067219820Sjeff return ERR_INCOMPLETE; 1068219820Sjeff } 1069219820Sjeff 1070219820Sjeff if (debug >= 3 && shouldbesize > n) { 1071219820Sjeff u_int32 key; 1072219820Sjeff u_int32 *lpkt; 1073219820Sjeff int maclen; 1074219820Sjeff 1075219820Sjeff /* 1076219820Sjeff * Usually we ignore authentication, but for debugging purposes 1077219820Sjeff * we watch it here. 1078219820Sjeff */ 1079219820Sjeff /* round to 8 octet boundary */ 1080219820Sjeff shouldbesize = (shouldbesize + 7) & ~7; 1081219820Sjeff 1082219820Sjeff maclen = n - shouldbesize; 1083219820Sjeff if (maclen >= (int)MIN_MAC_LEN) { 1084219820Sjeff printf( 1085219820Sjeff "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1086219820Sjeff n, shouldbesize, maclen); 1087219820Sjeff lpkt = (u_int32 *)&rpkt; 1088219820Sjeff printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1089219820Sjeff (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1090219820Sjeff (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1091219820Sjeff (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1092219820Sjeff (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1093219820Sjeff (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1094219820Sjeff (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1095219820Sjeff key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1096219820Sjeff printf("Authenticated with keyid %lu\n", (u_long)key); 1097219820Sjeff if (key != 0 && key != info_auth_keyid) { 1098219820Sjeff printf("We don't know that key\n"); 1099219820Sjeff } else { 1100219820Sjeff if (authdecrypt(key, (u_int32 *)&rpkt, 1101219820Sjeff n - maclen, maclen)) { 1102219820Sjeff printf("Auth okay!\n"); 1103219820Sjeff } else { 1104219820Sjeff printf("Auth failed!\n"); 1105219820Sjeff } 1106219820Sjeff } 1107219820Sjeff } 1108219820Sjeff } 1109219820Sjeff 1110219820Sjeff TRACE(2, ("Got packet, size = %d\n", n)); 1111219820Sjeff if (count > (n - CTL_HEADER_LEN)) { 1112219820Sjeff TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1113219820Sjeff count, (long)n - CTL_HEADER_LEN)); 1114219820Sjeff continue; 1115219820Sjeff } 1116219820Sjeff if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1117219820Sjeff TRACE(1, ("Received count of 0 in non-final fragment\n")); 1118219820Sjeff continue; 1119219820Sjeff } 1120219820Sjeff if (offset + count > sizeof(pktdata)) { 1121219820Sjeff TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1122219820Sjeff offset, count)); 1123219820Sjeff return ERR_TOOMUCH; 1124219820Sjeff } 1125219820Sjeff if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1126219820Sjeff TRACE(1, ("Received second last fragment packet\n")); 1127219820Sjeff continue; 1128219820Sjeff } 1129219820Sjeff 1130219820Sjeff /* 1131219820Sjeff * So far, so good. Record this fragment, making sure it doesn't 1132219820Sjeff * overlap anything. 1133219820Sjeff */ 1134219820Sjeff TRACE(2, ("Packet okay\n")); 1135219820Sjeff 1136219820Sjeff if (numfrags > (MAXFRAGS - 1)) { 1137219820Sjeff TRACE(2, ("Number of fragments exceeds maximum %d\n", 1138219820Sjeff MAXFRAGS - 1)); 1139219820Sjeff return ERR_TOOMUCH; 1140219820Sjeff } 1141219820Sjeff 1142219820Sjeff /* 1143219820Sjeff * Find the position for the fragment relative to any 1144219820Sjeff * previously received. 1145219820Sjeff */ 1146219820Sjeff for (f = 0; 1147219820Sjeff f < numfrags && offsets[f] < offset; 1148219820Sjeff f++) { 1149219820Sjeff /* empty body */ ; 1150219820Sjeff } 1151219820Sjeff 1152309378Sjhb if (f < numfrags && offset == offsets[f]) { 1153309378Sjhb TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1154219820Sjeff count, offset, counts[f], offsets[f])); 1155219820Sjeff continue; 1156219820Sjeff } 1157219820Sjeff 1158219820Sjeff if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1159219820Sjeff TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1160219820Sjeff offset, counts[f-1], offsets[f-1])); 1161219820Sjeff continue; 1162219820Sjeff } 1163219820Sjeff 1164219820Sjeff if (f < numfrags && (offset + count) > offsets[f]) { 1165219820Sjeff TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1166219820Sjeff count, offset, offsets[f])); 1167219820Sjeff continue; 1168219820Sjeff } 1169219820Sjeff 1170219820Sjeff for (ff = numfrags; ff > f; ff--) { 1171219820Sjeff offsets[ff] = offsets[ff-1]; 1172219820Sjeff counts[ff] = counts[ff-1]; 1173219820Sjeff } 1174219820Sjeff offsets[f] = offset; 1175219820Sjeff counts[f] = count; 1176219820Sjeff numfrags++; 1177219820Sjeff 1178219820Sjeff /* 1179219820Sjeff * Got that stuffed in right. Figure out if this was the last. 1180219820Sjeff * Record status info out of the last packet. 1181219820Sjeff */ 1182219820Sjeff if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1183219820Sjeff seenlastfrag = 1; 1184219820Sjeff if (rstatus != 0) 1185219820Sjeff *rstatus = ntohs(rpkt.status); 1186219820Sjeff } 1187219820Sjeff 1188219820Sjeff /* 1189219820Sjeff * Copy the data into the data buffer, and bump the 1190219820Sjeff * timout base in case we need more. 1191219820Sjeff */ 1192219820Sjeff memcpy((char *)pktdata + offset, &rpkt.u, count); 1193219820Sjeff tobase = (uint32_t)time(NULL); 1194219820Sjeff 1195219820Sjeff /* 1196219820Sjeff * If we've seen the last fragment, look for holes in the sequence. 1197219820Sjeff * If there aren't any, we're done. 1198219820Sjeff */ 1199219820Sjeff#if !defined(SYS_WINNT) && defined(EINTR) 1200219820Sjeff maybe_final: 1201219820Sjeff#endif 1202219820Sjeff 1203219820Sjeff if (seenlastfrag && offsets[0] == 0) { 1204219820Sjeff for (f = 1; f < numfrags; f++) 1205219820Sjeff if (offsets[f-1] + counts[f-1] != 1206219820Sjeff offsets[f]) 1207219820Sjeff break; 1208219820Sjeff if (f == numfrags) { 1209219820Sjeff *rsize = offsets[f-1] + counts[f-1]; 1210219820Sjeff TRACE(1, ("%lu packets reassembled into response\n", 1211219820Sjeff (u_long)numfrags)); 1212219820Sjeff return 0; 1213219820Sjeff } 1214219820Sjeff } 1215219820Sjeff } /* giant for (;;) collecting response packets */ 1216219820Sjeff} /* getresponse() */ 1217219820Sjeff 1218219820Sjeff 1219219820Sjeff/* 1220219820Sjeff * sendrequest - format and send a request packet 1221219820Sjeff */ 1222219820Sjeffstatic int 1223219820Sjeffsendrequest( 1224219820Sjeff int opcode, 1225219820Sjeff associd_t associd, 1226219820Sjeff int auth, 1227219820Sjeff size_t qsize, 1228219820Sjeff const char *qdata 1229219820Sjeff ) 1230219820Sjeff{ 1231219820Sjeff struct ntp_control qpkt; 1232219820Sjeff size_t pktsize; 1233219820Sjeff u_long key_id; 1234219820Sjeff char * pass; 1235219820Sjeff size_t maclen; 1236219820Sjeff 1237219820Sjeff /* 1238219820Sjeff * Check to make sure the data will fit in one packet 1239219820Sjeff */ 1240219820Sjeff if (qsize > CTL_MAX_DATA_LEN) { 1241219820Sjeff fprintf(stderr, 1242219820Sjeff "***Internal error! qsize (%zu) too large\n", 1243219820Sjeff qsize); 1244219820Sjeff return 1; 1245219820Sjeff } 1246219820Sjeff 1247219820Sjeff /* 1248219820Sjeff * Fill in the packet 1249219820Sjeff */ 1250219820Sjeff qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1251219820Sjeff qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 1252219820Sjeff qpkt.sequence = htons(sequence); 1253219820Sjeff qpkt.status = 0; 1254219820Sjeff qpkt.associd = htons((u_short)associd); 1255219820Sjeff qpkt.offset = 0; 1256219820Sjeff qpkt.count = htons((u_short)qsize); 1257219820Sjeff 1258219820Sjeff pktsize = CTL_HEADER_LEN; 1259219820Sjeff 1260219820Sjeff /* 1261219820Sjeff * If we have data, copy and pad it out to a 32-bit boundary. 1262219820Sjeff */ 1263219820Sjeff if (qsize > 0) { 1264219820Sjeff memcpy(&qpkt.u, qdata, (size_t)qsize); 1265219820Sjeff pktsize += qsize; 1266219820Sjeff while (pktsize & (sizeof(u_int32) - 1)) { 1267219820Sjeff qpkt.u.data[qsize++] = 0; 1268219820Sjeff pktsize++; 1269219820Sjeff } 1270219820Sjeff } 1271219820Sjeff 1272219820Sjeff /* 1273219820Sjeff * If it isn't authenticated we can just send it. Otherwise 1274219820Sjeff * we're going to have to think about it a little. 1275219820Sjeff */ 1276219820Sjeff if (!auth && !always_auth) { 1277219820Sjeff return sendpkt(&qpkt, pktsize); 1278219820Sjeff } 1279219820Sjeff 1280219820Sjeff /* 1281219820Sjeff * Pad out packet to a multiple of 8 octets to be sure 1282219820Sjeff * receiver can handle it. 1283219820Sjeff */ 1284219820Sjeff while (pktsize & 7) { 1285219820Sjeff qpkt.u.data[qsize++] = 0; 1286219820Sjeff pktsize++; 1287219820Sjeff } 1288219820Sjeff 1289219820Sjeff /* 1290219820Sjeff * Get the keyid and the password if we don't have one. 1291219820Sjeff */ 1292219820Sjeff if (info_auth_keyid == 0) { 1293219820Sjeff key_id = getkeyid("Keyid: "); 1294219820Sjeff if (key_id == 0 || key_id > NTP_MAXKEY) { 1295219820Sjeff fprintf(stderr, 1296219820Sjeff "Invalid key identifier\n"); 1297219820Sjeff return 1; 1298219820Sjeff } 1299219820Sjeff info_auth_keyid = key_id; 1300219820Sjeff } 1301219820Sjeff if (!authistrusted(info_auth_keyid)) { 1302219820Sjeff pass = getpass_keytype(info_auth_keytype); 1303219820Sjeff if ('\0' == pass[0]) { 1304219820Sjeff fprintf(stderr, "Invalid password\n"); 1305219820Sjeff return 1; 1306219820Sjeff } 1307219820Sjeff authusekey(info_auth_keyid, info_auth_keytype, 1308 (u_char *)pass); 1309 authtrust(info_auth_keyid, 1); 1310 } 1311 1312 /* 1313 * Do the encryption. 1314 */ 1315 maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1316 if (!maclen) { 1317 fprintf(stderr, "Key not found\n"); 1318 return 1; 1319 } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1320 fprintf(stderr, 1321 "%zu octet MAC, %zu expected with %zu octet digest\n", 1322 maclen, (info_auth_hashlen + sizeof(keyid_t)), 1323 info_auth_hashlen); 1324 return 1; 1325 } 1326 1327 return sendpkt((char *)&qpkt, pktsize + maclen); 1328} 1329 1330 1331/* 1332 * show_error_msg - display the error text for a mode 6 error response. 1333 */ 1334void 1335show_error_msg( 1336 int m6resp, 1337 associd_t associd 1338 ) 1339{ 1340 if (numhosts > 1) 1341 fprintf(stderr, "server=%s ", currenthost); 1342 1343 switch (m6resp) { 1344 1345 case CERR_BADFMT: 1346 fprintf(stderr, 1347 "***Server reports a bad format request packet\n"); 1348 break; 1349 1350 case CERR_PERMISSION: 1351 fprintf(stderr, 1352 "***Server disallowed request (authentication?)\n"); 1353 break; 1354 1355 case CERR_BADOP: 1356 fprintf(stderr, 1357 "***Server reports a bad opcode in request\n"); 1358 break; 1359 1360 case CERR_BADASSOC: 1361 fprintf(stderr, 1362 "***Association ID %d unknown to server\n", 1363 associd); 1364 break; 1365 1366 case CERR_UNKNOWNVAR: 1367 fprintf(stderr, 1368 "***A request variable unknown to the server\n"); 1369 break; 1370 1371 case CERR_BADVALUE: 1372 fprintf(stderr, 1373 "***Server indicates a request variable was bad\n"); 1374 break; 1375 1376 case ERR_UNSPEC: 1377 fprintf(stderr, 1378 "***Server returned an unspecified error\n"); 1379 break; 1380 1381 case ERR_TIMEOUT: 1382 fprintf(stderr, "***Request timed out\n"); 1383 break; 1384 1385 case ERR_INCOMPLETE: 1386 fprintf(stderr, 1387 "***Response from server was incomplete\n"); 1388 break; 1389 1390 case ERR_TOOMUCH: 1391 fprintf(stderr, 1392 "***Buffer size exceeded for returned data\n"); 1393 break; 1394 1395 default: 1396 fprintf(stderr, 1397 "***Server returns unknown error code %d\n", 1398 m6resp); 1399 } 1400} 1401 1402/* 1403 * doquery - send a request and process the response, displaying 1404 * error messages for any error responses. 1405 */ 1406int 1407doquery( 1408 int opcode, 1409 associd_t associd, 1410 int auth, 1411 size_t qsize, 1412 const char *qdata, 1413 u_short *rstatus, 1414 size_t *rsize, 1415 const char **rdata 1416 ) 1417{ 1418 return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1419 rsize, rdata, FALSE); 1420} 1421 1422 1423/* 1424 * doqueryex - send a request and process the response, optionally 1425 * displaying error messages for any error responses. 1426 */ 1427int 1428doqueryex( 1429 int opcode, 1430 associd_t associd, 1431 int auth, 1432 size_t qsize, 1433 const char *qdata, 1434 u_short *rstatus, 1435 size_t *rsize, 1436 const char **rdata, 1437 int quiet 1438 ) 1439{ 1440 int res; 1441 int done; 1442 1443 /* 1444 * Check to make sure host is open 1445 */ 1446 if (!havehost) { 1447 fprintf(stderr, "***No host open, use `host' command\n"); 1448 return -1; 1449 } 1450 1451 done = 0; 1452 sequence++; 1453 1454 again: 1455 /* 1456 * send a request 1457 */ 1458 res = sendrequest(opcode, associd, auth, qsize, qdata); 1459 if (res != 0) 1460 return res; 1461 1462 /* 1463 * Get the response. If we got a standard error, print a message 1464 */ 1465 res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 1466 1467 if (res > 0) { 1468 if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 1469 if (res == ERR_INCOMPLETE) { 1470 /* 1471 * better bump the sequence so we don't 1472 * get confused about differing fragments. 1473 */ 1474 sequence++; 1475 } 1476 done = 1; 1477 goto again; 1478 } 1479 if (!quiet) 1480 show_error_msg(res, associd); 1481 1482 } 1483 return res; 1484} 1485 1486 1487#ifndef BUILD_AS_LIB 1488/* 1489 * getcmds - read commands from the standard input and execute them 1490 */ 1491static void 1492getcmds(void) 1493{ 1494 char * line; 1495 int count; 1496 1497 ntp_readline_init(interactive ? prompt : NULL); 1498 1499 for (;;) { 1500 line = ntp_readline(&count); 1501 if (NULL == line) 1502 break; 1503 docmd(line); 1504 free(line); 1505 } 1506 1507 ntp_readline_uninit(); 1508} 1509#endif /* !BUILD_AS_LIB */ 1510 1511 1512#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 1513/* 1514 * abortcmd - catch interrupts and abort the current command 1515 */ 1516static int 1517abortcmd(void) 1518{ 1519 if (current_output == stdout) 1520 (void) fflush(stdout); 1521 putc('\n', stderr); 1522 (void) fflush(stderr); 1523 if (jump) { 1524 jump = 0; 1525 longjmp(interrupt_buf, 1); 1526 } 1527 return TRUE; 1528} 1529#endif /* !SYS_WINNT && !BUILD_AS_LIB */ 1530 1531 1532#ifndef BUILD_AS_LIB 1533/* 1534 * docmd - decode the command line and execute a command 1535 */ 1536static void 1537docmd( 1538 const char *cmdline 1539 ) 1540{ 1541 char *tokens[1+MAXARGS+2]; 1542 struct parse pcmd; 1543 int ntok; 1544 static int i; 1545 struct xcmd *xcmd; 1546 1547 /* 1548 * Tokenize the command line. If nothing on it, return. 1549 */ 1550 tokenize(cmdline, tokens, &ntok); 1551 if (ntok == 0) 1552 return; 1553 1554 /* 1555 * Find the appropriate command description. 1556 */ 1557 i = findcmd(tokens[0], builtins, opcmds, &xcmd); 1558 if (i == 0) { 1559 (void) fprintf(stderr, "***Command `%s' unknown\n", 1560 tokens[0]); 1561 return; 1562 } else if (i >= 2) { 1563 (void) fprintf(stderr, "***Command `%s' ambiguous\n", 1564 tokens[0]); 1565 return; 1566 } 1567 1568 /* Warn about ignored extra args */ 1569 for (i = MAXARGS + 1; i < ntok ; ++i) { 1570 fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1571 } 1572 1573 /* 1574 * Save the keyword, then walk through the arguments, interpreting 1575 * as we go. 1576 */ 1577 pcmd.keyword = tokens[0]; 1578 pcmd.nargs = 0; 1579 for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 1580 if ((i+1) >= ntok) { 1581 if (!(xcmd->arg[i] & OPT)) { 1582 printusage(xcmd, stderr); 1583 return; 1584 } 1585 break; 1586 } 1587 if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1588 break; 1589 if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1590 return; 1591 pcmd.nargs++; 1592 } 1593 1594 i++; 1595 if (i < ntok && *tokens[i] == '>') { 1596 char *fname; 1597 1598 if (*(tokens[i]+1) != '\0') 1599 fname = tokens[i]+1; 1600 else if ((i+1) < ntok) 1601 fname = tokens[i+1]; 1602 else { 1603 (void) fprintf(stderr, "***No file for redirect\n"); 1604 return; 1605 } 1606 1607 current_output = fopen(fname, "w"); 1608 if (current_output == NULL) { 1609 (void) fprintf(stderr, "***Error opening %s: ", fname); 1610 perror(""); 1611 return; 1612 } 1613 i = 1; /* flag we need a close */ 1614 } else { 1615 current_output = stdout; 1616 i = 0; /* flag no close */ 1617 } 1618 1619 if (interactive && setjmp(interrupt_buf)) { 1620 jump = 0; 1621 return; 1622 } else { 1623 jump++; 1624 (xcmd->handler)(&pcmd, current_output); 1625 jump = 0; /* HMS: 961106: was after fclose() */ 1626 if (i) (void) fclose(current_output); 1627 } 1628 1629 return; 1630} 1631 1632 1633/* 1634 * tokenize - turn a command line into tokens 1635 * 1636 * SK: Modified to allow a quoted string 1637 * 1638 * HMS: If the first character of the first token is a ':' then (after 1639 * eating inter-token whitespace) the 2nd token is the rest of the line. 1640 */ 1641 1642static void 1643tokenize( 1644 const char *line, 1645 char **tokens, 1646 int *ntok 1647 ) 1648{ 1649 register const char *cp; 1650 register char *sp; 1651 static char tspace[MAXLINE]; 1652 1653 sp = tspace; 1654 cp = line; 1655 for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 1656 tokens[*ntok] = sp; 1657 1658 /* Skip inter-token whitespace */ 1659 while (ISSPACE(*cp)) 1660 cp++; 1661 1662 /* If we're at EOL we're done */ 1663 if (ISEOL(*cp)) 1664 break; 1665 1666 /* If this is the 2nd token and the first token begins 1667 * with a ':', then just grab to EOL. 1668 */ 1669 1670 if (*ntok == 1 && tokens[0][0] == ':') { 1671 do { 1672 if (sp - tspace >= MAXLINE) 1673 goto toobig; 1674 *sp++ = *cp++; 1675 } while (!ISEOL(*cp)); 1676 } 1677 1678 /* Check if this token begins with a double quote. 1679 * If yes, continue reading till the next double quote 1680 */ 1681 else if (*cp == '\"') { 1682 ++cp; 1683 do { 1684 if (sp - tspace >= MAXLINE) 1685 goto toobig; 1686 *sp++ = *cp++; 1687 } while ((*cp != '\"') && !ISEOL(*cp)); 1688 /* HMS: a missing closing " should be an error */ 1689 } 1690 else { 1691 do { 1692 if (sp - tspace >= MAXLINE) 1693 goto toobig; 1694 *sp++ = *cp++; 1695 } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1696 /* HMS: Why check for a " in the previous line? */ 1697 } 1698 1699 if (sp - tspace >= MAXLINE) 1700 goto toobig; 1701 *sp++ = '\0'; 1702 } 1703 return; 1704 1705 toobig: 1706 *ntok = 0; 1707 fprintf(stderr, 1708 "***Line `%s' is too big\n", 1709 line); 1710 return; 1711} 1712 1713 1714/* 1715 * getarg - interpret an argument token 1716 */ 1717static int 1718getarg( 1719 const char *str, 1720 int code, 1721 arg_v *argp 1722 ) 1723{ 1724 u_long ul; 1725 1726 switch (code & ~OPT) { 1727 case NTP_STR: 1728 argp->string = str; 1729 break; 1730 1731 case NTP_ADD: 1732 if (!getnetnum(str, &argp->netnum, NULL, 0)) 1733 return 0; 1734 break; 1735 1736 case NTP_UINT: 1737 if ('&' == str[0]) { 1738 if (!atouint(&str[1], &ul)) { 1739 fprintf(stderr, 1740 "***Association index `%s' invalid/undecodable\n", 1741 str); 1742 return 0; 1743 } 1744 if (0 == numassoc) { 1745 dogetassoc(stdout); 1746 if (0 == numassoc) { 1747 fprintf(stderr, 1748 "***No associations found, `%s' unknown\n", 1749 str); 1750 return 0; 1751 } 1752 } 1753 ul = min(ul, numassoc); 1754 argp->uval = assoc_cache[ul - 1].assid; 1755 break; 1756 } 1757 if (!atouint(str, &argp->uval)) { 1758 fprintf(stderr, "***Illegal unsigned value %s\n", 1759 str); 1760 return 0; 1761 } 1762 break; 1763 1764 case NTP_INT: 1765 if (!atoint(str, &argp->ival)) { 1766 fprintf(stderr, "***Illegal integer value %s\n", 1767 str); 1768 return 0; 1769 } 1770 break; 1771 1772 case IP_VERSION: 1773 if (!strcmp("-6", str)) { 1774 argp->ival = 6; 1775 } else if (!strcmp("-4", str)) { 1776 argp->ival = 4; 1777 } else { 1778 fprintf(stderr, "***Version must be either 4 or 6\n"); 1779 return 0; 1780 } 1781 break; 1782 } 1783 1784 return 1; 1785} 1786#endif /* !BUILD_AS_LIB */ 1787 1788 1789/* 1790 * findcmd - find a command in a command description table 1791 */ 1792static int 1793findcmd( 1794 const char * str, 1795 struct xcmd * clist1, 1796 struct xcmd * clist2, 1797 struct xcmd ** cmd 1798 ) 1799{ 1800 struct xcmd *cl; 1801 size_t clen; 1802 int nmatch; 1803 struct xcmd *nearmatch = NULL; 1804 struct xcmd *clist; 1805 1806 clen = strlen(str); 1807 nmatch = 0; 1808 if (clist1 != 0) 1809 clist = clist1; 1810 else if (clist2 != 0) 1811 clist = clist2; 1812 else 1813 return 0; 1814 1815 again: 1816 for (cl = clist; cl->keyword != 0; cl++) { 1817 /* do a first character check, for efficiency */ 1818 if (*str != *(cl->keyword)) 1819 continue; 1820 if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 1821 /* 1822 * Could be extact match, could be approximate. 1823 * Is exact if the length of the keyword is the 1824 * same as the str. 1825 */ 1826 if (*((cl->keyword) + clen) == '\0') { 1827 *cmd = cl; 1828 return 1; 1829 } 1830 nmatch++; 1831 nearmatch = cl; 1832 } 1833 } 1834 1835 /* 1836 * See if there is more to do. If so, go again. Sorry about the 1837 * goto, too much looking at BSD sources... 1838 */ 1839 if (clist == clist1 && clist2 != 0) { 1840 clist = clist2; 1841 goto again; 1842 } 1843 1844 /* 1845 * If we got extactly 1 near match, use it, else return number 1846 * of matches. 1847 */ 1848 if (nmatch == 1) { 1849 *cmd = nearmatch; 1850 return 1; 1851 } 1852 return nmatch; 1853} 1854 1855 1856/* 1857 * getnetnum - given a host name, return its net number 1858 * and (optional) full name 1859 */ 1860int 1861getnetnum( 1862 const char *hname, 1863 sockaddr_u *num, 1864 char *fullhost, 1865 int af 1866 ) 1867{ 1868 struct addrinfo hints, *ai = NULL; 1869 1870 ZERO(hints); 1871 hints.ai_flags = AI_CANONNAME; 1872#ifdef AI_ADDRCONFIG 1873 hints.ai_flags |= AI_ADDRCONFIG; 1874#endif 1875 1876 /* 1877 * decodenetnum only works with addresses, but handles syntax 1878 * that getaddrinfo doesn't: [2001::1]:1234 1879 */ 1880 if (decodenetnum(hname, num)) { 1881 if (fullhost != NULL) 1882 getnameinfo(&num->sa, SOCKLEN(num), fullhost, 1883 LENHOSTNAME, NULL, 0, 0); 1884 return 1; 1885 } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 1886 INSIST(sizeof(*num) >= ai->ai_addrlen); 1887 memcpy(num, ai->ai_addr, ai->ai_addrlen); 1888 if (fullhost != NULL) { 1889 if (ai->ai_canonname != NULL) 1890 strlcpy(fullhost, ai->ai_canonname, 1891 LENHOSTNAME); 1892 else 1893 getnameinfo(&num->sa, SOCKLEN(num), 1894 fullhost, LENHOSTNAME, NULL, 1895 0, 0); 1896 } 1897 freeaddrinfo(ai); 1898 return 1; 1899 } 1900 fprintf(stderr, "***Can't find host %s\n", hname); 1901 1902 return 0; 1903} 1904 1905 1906/* 1907 * nntohost - convert network number to host name. This routine enforces 1908 * the showhostnames setting. 1909 */ 1910const char * 1911nntohost( 1912 sockaddr_u *netnum 1913 ) 1914{ 1915 return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 1916} 1917 1918 1919/* 1920 * nntohost_col - convert network number to host name in fixed width. 1921 * This routine enforces the showhostnames setting. 1922 * When displaying hostnames longer than the width, 1923 * the first part of the hostname is displayed. When 1924 * displaying numeric addresses longer than the width, 1925 * Such as IPv6 addresses, the caller decides whether 1926 * the first or last of the numeric address is used. 1927 */ 1928const char * 1929nntohost_col( 1930 sockaddr_u * addr, 1931 size_t width, 1932 int preserve_lowaddrbits 1933 ) 1934{ 1935 const char * out; 1936 1937 if (!showhostnames || SOCK_UNSPEC(addr)) { 1938 if (preserve_lowaddrbits) 1939 out = trunc_left(stoa(addr), width); 1940 else 1941 out = trunc_right(stoa(addr), width); 1942 } else if (ISREFCLOCKADR(addr)) { 1943 out = refnumtoa(addr); 1944 } else { 1945 out = trunc_right(socktohost(addr), width); 1946 } 1947 return out; 1948} 1949 1950 1951/* 1952 * nntohostp() is the same as nntohost() plus a :port suffix 1953 */ 1954const char * 1955nntohostp( 1956 sockaddr_u *netnum 1957 ) 1958{ 1959 const char * hostn; 1960 char * buf; 1961 1962 if (!showhostnames || SOCK_UNSPEC(netnum)) 1963 return sptoa(netnum); 1964 else if (ISREFCLOCKADR(netnum)) 1965 return refnumtoa(netnum); 1966 1967 hostn = socktohost(netnum); 1968 LIB_GETBUF(buf); 1969 snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 1970 1971 return buf; 1972} 1973 1974/* 1975 * rtdatetolfp - decode an RT-11 date into an l_fp 1976 */ 1977static int 1978rtdatetolfp( 1979 char *str, 1980 l_fp *lfp 1981 ) 1982{ 1983 register char *cp; 1984 register int i; 1985 struct calendar cal; 1986 char buf[4]; 1987 1988 cal.yearday = 0; 1989 1990 /* 1991 * An RT-11 date looks like: 1992 * 1993 * d[d]-Mth-y[y] hh:mm:ss 1994 * 1995 * (No docs, but assume 4-digit years are also legal...) 1996 * 1997 * d[d]-Mth-y[y[y[y]]] hh:mm:ss 1998 */ 1999 cp = str; 2000 if (!isdigit((int)*cp)) { 2001 if (*cp == '-') { 2002 /* 2003 * Catch special case 2004 */ 2005 L_CLR(lfp); 2006 return 1; 2007 } 2008 return 0; 2009 } 2010 2011 cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 2012 if (isdigit((int)*cp)) { 2013 cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2014 cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 2015 } 2016 2017 if (*cp++ != '-') 2018 return 0; 2019 2020 for (i = 0; i < 3; i++) 2021 buf[i] = *cp++; 2022 buf[3] = '\0'; 2023 2024 for (i = 0; i < 12; i++) 2025 if (STREQ(buf, months[i])) 2026 break; 2027 if (i == 12) 2028 return 0; 2029 cal.month = (u_char)(i + 1); 2030 2031 if (*cp++ != '-') 2032 return 0; 2033 2034 if (!isdigit((int)*cp)) 2035 return 0; 2036 cal.year = (u_short)(*cp++ - '0'); 2037 if (isdigit((int)*cp)) { 2038 cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2039 cal.year = (u_short)(*cp++ - '0'); 2040 } 2041 if (isdigit((int)*cp)) { 2042 cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2043 cal.year = (u_short)(cal.year + *cp++ - '0'); 2044 } 2045 if (isdigit((int)*cp)) { 2046 cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2047 cal.year = (u_short)(cal.year + *cp++ - '0'); 2048 } 2049 2050 /* 2051 * Catch special case. If cal.year == 0 this is a zero timestamp. 2052 */ 2053 if (cal.year == 0) { 2054 L_CLR(lfp); 2055 return 1; 2056 } 2057 2058 if (*cp++ != ' ' || !isdigit((int)*cp)) 2059 return 0; 2060 cal.hour = (u_char)(*cp++ - '0'); 2061 if (isdigit((int)*cp)) { 2062 cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2063 cal.hour = (u_char)(cal.hour + *cp++ - '0'); 2064 } 2065 2066 if (*cp++ != ':' || !isdigit((int)*cp)) 2067 return 0; 2068 cal.minute = (u_char)(*cp++ - '0'); 2069 if (isdigit((int)*cp)) { 2070 cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2071 cal.minute = (u_char)(cal.minute + *cp++ - '0'); 2072 } 2073 2074 if (*cp++ != ':' || !isdigit((int)*cp)) 2075 return 0; 2076 cal.second = (u_char)(*cp++ - '0'); 2077 if (isdigit((int)*cp)) { 2078 cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2079 cal.second = (u_char)(cal.second + *cp++ - '0'); 2080 } 2081 2082 /* 2083 * For RT-11, 1972 seems to be the pivot year 2084 */ 2085 if (cal.year < 72) 2086 cal.year += 2000; 2087 if (cal.year < 100) 2088 cal.year += 1900; 2089 2090 lfp->l_ui = caltontp(&cal); 2091 lfp->l_uf = 0; 2092 return 1; 2093} 2094 2095 2096/* 2097 * decodets - decode a timestamp into an l_fp format number, with 2098 * consideration of fuzzball formats. 2099 */ 2100int 2101decodets( 2102 char *str, 2103 l_fp *lfp 2104 ) 2105{ 2106 char *cp; 2107 char buf[30]; 2108 size_t b; 2109 2110 /* 2111 * If it starts with a 0x, decode as hex. 2112 */ 2113 if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2114 return hextolfp(str+2, lfp); 2115 2116 /* 2117 * If it starts with a '"', try it as an RT-11 date. 2118 */ 2119 if (*str == '"') { 2120 cp = str + 1; 2121 b = 0; 2122 while ('"' != *cp && '\0' != *cp && 2123 b < COUNTOF(buf) - 1) 2124 buf[b++] = *cp++; 2125 buf[b] = '\0'; 2126 return rtdatetolfp(buf, lfp); 2127 } 2128 2129 /* 2130 * Might still be hex. Check out the first character. Talk 2131 * about heuristics! 2132 */ 2133 if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2134 return hextolfp(str, lfp); 2135 2136 /* 2137 * Try it as a decimal. If this fails, try as an unquoted 2138 * RT-11 date. This code should go away eventually. 2139 */ 2140 if (atolfp(str, lfp)) 2141 return 1; 2142 2143 return rtdatetolfp(str, lfp); 2144} 2145 2146 2147/* 2148 * decodetime - decode a time value. It should be in milliseconds 2149 */ 2150int 2151decodetime( 2152 char *str, 2153 l_fp *lfp 2154 ) 2155{ 2156 return mstolfp(str, lfp); 2157} 2158 2159 2160/* 2161 * decodeint - decode an integer 2162 */ 2163int 2164decodeint( 2165 char *str, 2166 long *val 2167 ) 2168{ 2169 if (*str == '0') { 2170 if (*(str+1) == 'x' || *(str+1) == 'X') 2171 return hextoint(str+2, (u_long *)val); 2172 return octtoint(str, (u_long *)val); 2173 } 2174 return atoint(str, val); 2175} 2176 2177 2178/* 2179 * decodeuint - decode an unsigned integer 2180 */ 2181int 2182decodeuint( 2183 char *str, 2184 u_long *val 2185 ) 2186{ 2187 if (*str == '0') { 2188 if (*(str + 1) == 'x' || *(str + 1) == 'X') 2189 return (hextoint(str + 2, val)); 2190 return (octtoint(str, val)); 2191 } 2192 return (atouint(str, val)); 2193} 2194 2195 2196/* 2197 * decodearr - decode an array of time values 2198 */ 2199static int 2200decodearr( 2201 char *str, 2202 int *narr, 2203 l_fp *lfparr 2204 ) 2205{ 2206 register char *cp, *bp; 2207 register l_fp *lfp; 2208 char buf[60]; 2209 2210 lfp = lfparr; 2211 cp = str; 2212 *narr = 0; 2213 2214 while (*narr < 8) { 2215 while (isspace((int)*cp)) 2216 cp++; 2217 if (*cp == '\0') 2218 break; 2219 2220 bp = buf; 2221 while (!isspace((int)*cp) && *cp != '\0') 2222 *bp++ = *cp++; 2223 *bp++ = '\0'; 2224 2225 if (!decodetime(buf, lfp)) 2226 return 0; 2227 (*narr)++; 2228 lfp++; 2229 } 2230 return 1; 2231} 2232 2233 2234/* 2235 * Finally, the built in command handlers 2236 */ 2237 2238/* 2239 * help - tell about commands, or details of a particular command 2240 */ 2241static void 2242help( 2243 struct parse *pcmd, 2244 FILE *fp 2245 ) 2246{ 2247 struct xcmd *xcp = NULL; /* quiet warning */ 2248 const char *cmd; 2249 const char *list[100]; 2250 size_t word, words; 2251 size_t row, rows; 2252 size_t col, cols; 2253 size_t length; 2254 2255 if (pcmd->nargs == 0) { 2256 words = 0; 2257 for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2258 if (*(xcp->keyword) != '?' && 2259 words < COUNTOF(list)) 2260 list[words++] = xcp->keyword; 2261 } 2262 for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2263 if (words < COUNTOF(list)) 2264 list[words++] = xcp->keyword; 2265 2266 qsort((void *)list, words, sizeof(list[0]), helpsort); 2267 col = 0; 2268 for (word = 0; word < words; word++) { 2269 length = strlen(list[word]); 2270 col = max(col, length); 2271 } 2272 2273 cols = SCREENWIDTH / ++col; 2274 rows = (words + cols - 1) / cols; 2275 2276 fprintf(fp, "ntpq commands:\n"); 2277 2278 for (row = 0; row < rows; row++) { 2279 for (word = row; word < words; word += rows) 2280 fprintf(fp, "%-*.*s", (int)col, 2281 (int)col - 1, list[word]); 2282 fprintf(fp, "\n"); 2283 } 2284 } else { 2285 cmd = pcmd->argval[0].string; 2286 words = findcmd(cmd, builtins, opcmds, &xcp); 2287 if (words == 0) { 2288 fprintf(stderr, 2289 "Command `%s' is unknown\n", cmd); 2290 return; 2291 } else if (words >= 2) { 2292 fprintf(stderr, 2293 "Command `%s' is ambiguous\n", cmd); 2294 return; 2295 } 2296 fprintf(fp, "function: %s\n", xcp->comment); 2297 printusage(xcp, fp); 2298 } 2299} 2300 2301 2302/* 2303 * helpsort - do hostname qsort comparisons 2304 */ 2305static int 2306helpsort( 2307 const void *t1, 2308 const void *t2 2309 ) 2310{ 2311 const char * const * name1 = t1; 2312 const char * const * name2 = t2; 2313 2314 return strcmp(*name1, *name2); 2315} 2316 2317 2318/* 2319 * printusage - print usage information for a command 2320 */ 2321static void 2322printusage( 2323 struct xcmd *xcp, 2324 FILE *fp 2325 ) 2326{ 2327 register int i; 2328 2329 /* XXX: Do we need to warn about extra args here too? */ 2330 2331 (void) fprintf(fp, "usage: %s", xcp->keyword); 2332 for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 2333 if (xcp->arg[i] & OPT) 2334 (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 2335 else 2336 (void) fprintf(fp, " %s", xcp->desc[i]); 2337 } 2338 (void) fprintf(fp, "\n"); 2339} 2340 2341 2342/* 2343 * timeout - set time out time 2344 */ 2345static void 2346timeout( 2347 struct parse *pcmd, 2348 FILE *fp 2349 ) 2350{ 2351 int val; 2352 2353 if (pcmd->nargs == 0) { 2354 val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 2355 (void) fprintf(fp, "primary timeout %d ms\n", val); 2356 } else { 2357 tvout.tv_sec = pcmd->argval[0].uval / 1000; 2358 tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 2359 * 1000; 2360 } 2361} 2362 2363 2364/* 2365 * auth_delay - set delay for auth requests 2366 */ 2367static void 2368auth_delay( 2369 struct parse *pcmd, 2370 FILE *fp 2371 ) 2372{ 2373 int isneg; 2374 u_long val; 2375 2376 if (pcmd->nargs == 0) { 2377 val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 2378 (void) fprintf(fp, "delay %lu ms\n", val); 2379 } else { 2380 if (pcmd->argval[0].ival < 0) { 2381 isneg = 1; 2382 val = (u_long)(-pcmd->argval[0].ival); 2383 } else { 2384 isneg = 0; 2385 val = (u_long)pcmd->argval[0].ival; 2386 } 2387 2388 delay_time.l_ui = val / 1000; 2389 val %= 1000; 2390 delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 2391 2392 if (isneg) 2393 L_NEG(&delay_time); 2394 } 2395} 2396 2397 2398/* 2399 * host - set the host we are dealing with. 2400 */ 2401static void 2402host( 2403 struct parse *pcmd, 2404 FILE *fp 2405 ) 2406{ 2407 int i; 2408 2409 if (pcmd->nargs == 0) { 2410 if (havehost) 2411 (void) fprintf(fp, "current host is %s\n", 2412 currenthost); 2413 else 2414 (void) fprintf(fp, "no current host\n"); 2415 return; 2416 } 2417 2418 i = 0; 2419 ai_fam_templ = ai_fam_default; 2420 if (pcmd->nargs == 2) { 2421 if (!strcmp("-4", pcmd->argval[i].string)) 2422 ai_fam_templ = AF_INET; 2423 else if (!strcmp("-6", pcmd->argval[i].string)) 2424 ai_fam_templ = AF_INET6; 2425 else 2426 goto no_change; 2427 i = 1; 2428 } 2429 if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2430 fprintf(fp, "current host set to %s\n", currenthost); 2431 } else { 2432 no_change: 2433 if (havehost) 2434 fprintf(fp, "current host remains %s\n", 2435 currenthost); 2436 else 2437 fprintf(fp, "still no current host\n"); 2438 } 2439} 2440 2441 2442/* 2443 * poll - do one (or more) polls of the host via NTP 2444 */ 2445/*ARGSUSED*/ 2446static void 2447ntp_poll( 2448 struct parse *pcmd, 2449 FILE *fp 2450 ) 2451{ 2452 (void) fprintf(fp, "poll not implemented yet\n"); 2453} 2454 2455 2456/* 2457 * showdrefid2str - return a string explanation of the value of drefid 2458 */ 2459static char * 2460showdrefid2str(void) 2461{ 2462 switch (drefid) { 2463 case REFID_HASH: 2464 return "hash"; 2465 case REFID_IPV4: 2466 return "ipv4"; 2467 default: 2468 return "Unknown"; 2469 } 2470} 2471 2472 2473/* 2474 * drefid - display/change "display hash" 2475 */ 2476static void 2477showdrefid( 2478 struct parse *pcmd, 2479 FILE *fp 2480 ) 2481{ 2482 if (pcmd->nargs == 0) { 2483 (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2484 return; 2485 } else if (STREQ(pcmd->argval[0].string, "hash")) { 2486 drefid = REFID_HASH; 2487 } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2488 drefid = REFID_IPV4; 2489 } else { 2490 (void) fprintf(fp, "What?\n"); 2491 return; 2492 } 2493 (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2494} 2495 2496 2497/* 2498 * keyid - get a keyid to use for authenticating requests 2499 */ 2500static void 2501keyid( 2502 struct parse *pcmd, 2503 FILE *fp 2504 ) 2505{ 2506 if (pcmd->nargs == 0) { 2507 if (info_auth_keyid == 0) 2508 (void) fprintf(fp, "no keyid defined\n"); 2509 else 2510 (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 2511 } else { 2512 /* allow zero so that keyid can be cleared. */ 2513 if(pcmd->argval[0].uval > NTP_MAXKEY) 2514 (void) fprintf(fp, "Invalid key identifier\n"); 2515 info_auth_keyid = pcmd->argval[0].uval; 2516 } 2517} 2518 2519/* 2520 * keytype - get type of key to use for authenticating requests 2521 */ 2522static void 2523keytype( 2524 struct parse *pcmd, 2525 FILE *fp 2526 ) 2527{ 2528 const char * digest_name; 2529 size_t digest_len; 2530 int key_type; 2531 2532 if (!pcmd->nargs) { 2533 fprintf(fp, "keytype is %s with %lu octet digests\n", 2534 keytype_name(info_auth_keytype), 2535 (u_long)info_auth_hashlen); 2536 return; 2537 } 2538 2539 digest_name = pcmd->argval[0].string; 2540 digest_len = 0; 2541 key_type = keytype_from_text(digest_name, &digest_len); 2542 2543 if (!key_type) { 2544 fprintf(fp, "keytype is not valid. " 2545#ifdef OPENSSL 2546 "Type \"help keytype\" for the available digest types.\n"); 2547#else 2548 "Only \"md5\" is available.\n"); 2549#endif 2550 return; 2551 } 2552 2553 info_auth_keytype = key_type; 2554 info_auth_hashlen = digest_len; 2555} 2556 2557 2558/* 2559 * passwd - get an authentication key 2560 */ 2561/*ARGSUSED*/ 2562static void 2563passwd( 2564 struct parse *pcmd, 2565 FILE *fp 2566 ) 2567{ 2568 const char *pass; 2569 2570 if (info_auth_keyid == 0) { 2571 info_auth_keyid = getkeyid("Keyid: "); 2572 if (info_auth_keyid == 0) { 2573 (void)fprintf(fp, "Keyid must be defined\n"); 2574 return; 2575 } 2576 } 2577 if (pcmd->nargs >= 1) 2578 pass = pcmd->argval[0].string; 2579 else { 2580 pass = getpass_keytype(info_auth_keytype); 2581 if ('\0' == pass[0]) { 2582 fprintf(fp, "Password unchanged\n"); 2583 return; 2584 } 2585 } 2586 authusekey(info_auth_keyid, info_auth_keytype, 2587 (const u_char *)pass); 2588 authtrust(info_auth_keyid, 1); 2589} 2590 2591 2592/* 2593 * hostnames - set the showhostnames flag 2594 */ 2595static void 2596hostnames( 2597 struct parse *pcmd, 2598 FILE *fp 2599 ) 2600{ 2601 if (pcmd->nargs == 0) { 2602 if (showhostnames) 2603 (void) fprintf(fp, "hostnames being shown\n"); 2604 else 2605 (void) fprintf(fp, "hostnames not being shown\n"); 2606 } else { 2607 if (STREQ(pcmd->argval[0].string, "yes")) 2608 showhostnames = 1; 2609 else if (STREQ(pcmd->argval[0].string, "no")) 2610 showhostnames = 0; 2611 else 2612 (void)fprintf(stderr, "What?\n"); 2613 } 2614} 2615 2616 2617 2618/* 2619 * setdebug - set/change debugging level 2620 */ 2621static void 2622setdebug( 2623 struct parse *pcmd, 2624 FILE *fp 2625 ) 2626{ 2627 if (pcmd->nargs == 0) { 2628 (void) fprintf(fp, "debug level is %d\n", debug); 2629 return; 2630 } else if (STREQ(pcmd->argval[0].string, "no")) { 2631 debug = 0; 2632 } else if (STREQ(pcmd->argval[0].string, "more")) { 2633 debug++; 2634 } else if (STREQ(pcmd->argval[0].string, "less")) { 2635 debug--; 2636 } else { 2637 (void) fprintf(fp, "What?\n"); 2638 return; 2639 } 2640 (void) fprintf(fp, "debug level set to %d\n", debug); 2641} 2642 2643 2644/* 2645 * quit - stop this nonsense 2646 */ 2647/*ARGSUSED*/ 2648static void 2649quit( 2650 struct parse *pcmd, 2651 FILE *fp 2652 ) 2653{ 2654 if (havehost) 2655 closesocket(sockfd); /* cleanliness next to godliness */ 2656 exit(0); 2657} 2658 2659 2660/* 2661 * version - print the current version number 2662 */ 2663/*ARGSUSED*/ 2664static void 2665version( 2666 struct parse *pcmd, 2667 FILE *fp 2668 ) 2669{ 2670 2671 (void) fprintf(fp, "%s\n", Version); 2672 return; 2673} 2674 2675 2676/* 2677 * raw - set raw mode output 2678 */ 2679/*ARGSUSED*/ 2680static void 2681raw( 2682 struct parse *pcmd, 2683 FILE *fp 2684 ) 2685{ 2686 rawmode = 1; 2687 (void) fprintf(fp, "Output set to raw\n"); 2688} 2689 2690 2691/* 2692 * cooked - set cooked mode output 2693 */ 2694/*ARGSUSED*/ 2695static void 2696cooked( 2697 struct parse *pcmd, 2698 FILE *fp 2699 ) 2700{ 2701 rawmode = 0; 2702 (void) fprintf(fp, "Output set to cooked\n"); 2703 return; 2704} 2705 2706 2707/* 2708 * authenticate - always authenticate requests to this host 2709 */ 2710static void 2711authenticate( 2712 struct parse *pcmd, 2713 FILE *fp 2714 ) 2715{ 2716 if (pcmd->nargs == 0) { 2717 if (always_auth) { 2718 (void) fprintf(fp, 2719 "authenticated requests being sent\n"); 2720 } else 2721 (void) fprintf(fp, 2722 "unauthenticated requests being sent\n"); 2723 } else { 2724 if (STREQ(pcmd->argval[0].string, "yes")) { 2725 always_auth = 1; 2726 } else if (STREQ(pcmd->argval[0].string, "no")) { 2727 always_auth = 0; 2728 } else 2729 (void)fprintf(stderr, "What?\n"); 2730 } 2731} 2732 2733 2734/* 2735 * ntpversion - choose the NTP version to use 2736 */ 2737static void 2738ntpversion( 2739 struct parse *pcmd, 2740 FILE *fp 2741 ) 2742{ 2743 if (pcmd->nargs == 0) { 2744 (void) fprintf(fp, 2745 "NTP version being claimed is %d\n", pktversion); 2746 } else { 2747 if (pcmd->argval[0].uval < NTP_OLDVERSION 2748 || pcmd->argval[0].uval > NTP_VERSION) { 2749 (void) fprintf(stderr, "versions %d to %d, please\n", 2750 NTP_OLDVERSION, NTP_VERSION); 2751 } else { 2752 pktversion = (u_char) pcmd->argval[0].uval; 2753 } 2754 } 2755} 2756 2757 2758static void __attribute__((__format__(__printf__, 1, 0))) 2759vwarning(const char *fmt, va_list ap) 2760{ 2761 int serrno = errno; 2762 (void) fprintf(stderr, "%s: ", progname); 2763 vfprintf(stderr, fmt, ap); 2764 (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2765} 2766 2767/* 2768 * warning - print a warning message 2769 */ 2770static void __attribute__((__format__(__printf__, 1, 2))) 2771warning( 2772 const char *fmt, 2773 ... 2774 ) 2775{ 2776 va_list ap; 2777 va_start(ap, fmt); 2778 vwarning(fmt, ap); 2779 va_end(ap); 2780} 2781 2782 2783/* 2784 * error - print a message and exit 2785 */ 2786static void __attribute__((__format__(__printf__, 1, 2))) 2787error( 2788 const char *fmt, 2789 ... 2790 ) 2791{ 2792 va_list ap; 2793 va_start(ap, fmt); 2794 vwarning(fmt, ap); 2795 va_end(ap); 2796 exit(1); 2797} 2798/* 2799 * getkeyid - prompt the user for a keyid to use 2800 */ 2801static u_long 2802getkeyid( 2803 const char *keyprompt 2804 ) 2805{ 2806 int c; 2807 FILE *fi; 2808 char pbuf[20]; 2809 size_t i; 2810 size_t ilim; 2811 2812#ifndef SYS_WINNT 2813 if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 2814#else 2815 if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 2816#endif /* SYS_WINNT */ 2817 fi = stdin; 2818 else 2819 setbuf(fi, (char *)NULL); 2820 fprintf(stderr, "%s", keyprompt); fflush(stderr); 2821 for (i = 0, ilim = COUNTOF(pbuf) - 1; 2822 i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2823 ) 2824 pbuf[i++] = (char)c; 2825 pbuf[i] = '\0'; 2826 if (fi != stdin) 2827 fclose(fi); 2828 2829 return (u_long) atoi(pbuf); 2830} 2831 2832 2833/* 2834 * atoascii - printable-ize possibly ascii data using the character 2835 * transformations cat -v uses. 2836 */ 2837static void 2838atoascii( 2839 const char *in, 2840 size_t in_octets, 2841 char *out, 2842 size_t out_octets 2843 ) 2844{ 2845 const u_char * pchIn; 2846 const u_char * pchInLimit; 2847 u_char * pchOut; 2848 u_char c; 2849 2850 pchIn = (const u_char *)in; 2851 pchInLimit = pchIn + in_octets; 2852 pchOut = (u_char *)out; 2853 2854 if (NULL == pchIn) { 2855 if (0 < out_octets) 2856 *pchOut = '\0'; 2857 return; 2858 } 2859 2860#define ONEOUT(c) \ 2861do { \ 2862 if (0 == --out_octets) { \ 2863 *pchOut = '\0'; \ 2864 return; \ 2865 } \ 2866 *pchOut++ = (c); \ 2867} while (0) 2868 2869 for ( ; pchIn < pchInLimit; pchIn++) { 2870 c = *pchIn; 2871 if ('\0' == c) 2872 break; 2873 if (c & 0x80) { 2874 ONEOUT('M'); 2875 ONEOUT('-'); 2876 c &= 0x7f; 2877 } 2878 if (c < ' ') { 2879 ONEOUT('^'); 2880 ONEOUT((u_char)(c + '@')); 2881 } else if (0x7f == c) { 2882 ONEOUT('^'); 2883 ONEOUT('?'); 2884 } else 2885 ONEOUT(c); 2886 } 2887 ONEOUT('\0'); 2888 2889#undef ONEOUT 2890} 2891 2892 2893/* 2894 * makeascii - print possibly ascii data using the character 2895 * transformations that cat -v uses. 2896 */ 2897void 2898makeascii( 2899 size_t length, 2900 const char *data, 2901 FILE *fp 2902 ) 2903{ 2904 const u_char *data_u_char; 2905 const u_char *cp; 2906 int c; 2907 2908 data_u_char = (const u_char *)data; 2909 2910 for (cp = data_u_char; cp < data_u_char + length; cp++) { 2911 c = (int)*cp; 2912 if (c & 0x80) { 2913 putc('M', fp); 2914 putc('-', fp); 2915 c &= 0x7f; 2916 } 2917 2918 if (c < ' ') { 2919 putc('^', fp); 2920 putc(c + '@', fp); 2921 } else if (0x7f == c) { 2922 putc('^', fp); 2923 putc('?', fp); 2924 } else 2925 putc(c, fp); 2926 } 2927} 2928 2929 2930/* 2931 * asciize - same thing as makeascii except add a newline 2932 */ 2933void 2934asciize( 2935 int length, 2936 char *data, 2937 FILE *fp 2938 ) 2939{ 2940 makeascii(length, data, fp); 2941 putc('\n', fp); 2942} 2943 2944 2945/* 2946 * truncate string to fit clipping excess at end. 2947 * "too long" -> "too l" 2948 * Used for hostnames. 2949 */ 2950const char * 2951trunc_right( 2952 const char * src, 2953 size_t width 2954 ) 2955{ 2956 size_t sl; 2957 char * out; 2958 2959 2960 sl = strlen(src); 2961 if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 2962 LIB_GETBUF(out); 2963 memcpy(out, src, width); 2964 out[width] = '\0'; 2965 2966 return out; 2967 } 2968 2969 return src; 2970} 2971 2972 2973/* 2974 * truncate string to fit by preserving right side and using '_' to hint 2975 * "too long" -> "_long" 2976 * Used for local IPv6 addresses, where low bits differentiate. 2977 */ 2978const char * 2979trunc_left( 2980 const char * src, 2981 size_t width 2982 ) 2983{ 2984 size_t sl; 2985 char * out; 2986 2987 2988 sl = strlen(src); 2989 if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 2990 LIB_GETBUF(out); 2991 out[0] = '_'; 2992 memcpy(&out[1], &src[sl + 1 - width], width); 2993 2994 return out; 2995 } 2996 2997 return src; 2998} 2999 3000 3001/* 3002 * Some circular buffer space 3003 */ 3004#define CBLEN 80 3005#define NUMCB 6 3006 3007char circ_buf[NUMCB][CBLEN]; 3008int nextcb = 0; 3009 3010/* 3011 * nextvar - find the next variable in the buffer 3012 */ 3013int 3014nextvar( 3015 size_t *datalen, 3016 const char **datap, 3017 char **vname, 3018 char **vvalue 3019 ) 3020{ 3021 const char *cp; 3022 const char *np; 3023 const char *cpend; 3024 size_t srclen; 3025 size_t len; 3026 static char name[MAXVARLEN]; 3027 static char value[MAXVALLEN]; 3028 3029 cp = *datap; 3030 cpend = cp + *datalen; 3031 3032 /* 3033 * Space past commas and white space 3034 */ 3035 while (cp < cpend && (*cp == ',' || isspace((int)*cp))) 3036 cp++; 3037 if (cp >= cpend) 3038 return 0; 3039 3040 /* 3041 * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace 3042 * over any white space and terminate it. 3043 */ 3044 srclen = strcspn(cp, ",=\r\n"); 3045 srclen = min(srclen, (size_t)(cpend - cp)); 3046 len = srclen; 3047 while (len > 0 && isspace((unsigned char)cp[len - 1])) 3048 len--; 3049 if (len >= sizeof(name)) 3050 return 0; 3051 if (len > 0) 3052 memcpy(name, cp, len); 3053 name[len] = '\0'; 3054 *vname = name; 3055 cp += srclen; 3056 3057 /* 3058 * Check if we hit the end of the buffer or a ','. If so we are done. 3059 */ 3060 if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') { 3061 if (cp < cpend) 3062 cp++; 3063 *datap = cp; 3064 *datalen = size2int_sat(cpend - cp); 3065 *vvalue = NULL; 3066 return 1; 3067 } 3068 3069 /* 3070 * So far, so good. Copy out the value 3071 */ 3072 cp++; /* past '=' */ 3073 while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n')) 3074 cp++; 3075 np = cp; 3076 if ('"' == *np) { 3077 do { 3078 np++; 3079 } while (np < cpend && '"' != *np); 3080 if (np < cpend && '"' == *np) 3081 np++; 3082 } else { 3083 while (np < cpend && ',' != *np && '\r' != *np) 3084 np++; 3085 } 3086 len = np - cp; 3087 if (np > cpend || len >= sizeof(value) || 3088 (np < cpend && ',' != *np && '\r' != *np)) 3089 return 0; 3090 memcpy(value, cp, len); 3091 /* 3092 * Trim off any trailing whitespace 3093 */ 3094 while (len > 0 && isspace((unsigned char)value[len - 1])) 3095 len--; 3096 value[len] = '\0'; 3097 3098 /* 3099 * Return this. All done. 3100 */ 3101 if (np < cpend && ',' == *np) 3102 np++; 3103 *datap = np; 3104 *datalen = size2int_sat(cpend - np); 3105 *vvalue = value; 3106 return 1; 3107} 3108 3109 3110u_short 3111varfmt(const char * varname) 3112{ 3113 u_int n; 3114 3115 for (n = 0; n < COUNTOF(cookedvars); n++) 3116 if (!strcmp(varname, cookedvars[n].varname)) 3117 return cookedvars[n].fmt; 3118 3119 return PADDING; 3120} 3121 3122 3123/* 3124 * printvars - print variables returned in response packet 3125 */ 3126void 3127printvars( 3128 size_t length, 3129 const char *data, 3130 int status, 3131 int sttype, 3132 int quiet, 3133 FILE *fp 3134 ) 3135{ 3136 if (rawmode) 3137 rawprint(sttype, length, data, status, quiet, fp); 3138 else 3139 cookedprint(sttype, length, data, status, quiet, fp); 3140} 3141 3142 3143/* 3144 * rawprint - do a printout of the data in raw mode 3145 */ 3146static void 3147rawprint( 3148 int datatype, 3149 size_t length, 3150 const char *data, 3151 int status, 3152 int quiet, 3153 FILE *fp 3154 ) 3155{ 3156 const char *cp; 3157 const char *cpend; 3158 3159 /* 3160 * Essentially print the data as is. We reformat unprintables, though. 3161 */ 3162 cp = data; 3163 cpend = data + length; 3164 3165 if (!quiet) 3166 (void) fprintf(fp, "status=0x%04x,\n", status); 3167 3168 while (cp < cpend) { 3169 if (*cp == '\r') { 3170 /* 3171 * If this is a \r and the next character is a 3172 * \n, supress this, else pretty print it. Otherwise 3173 * just output the character. 3174 */ 3175 if (cp == (cpend - 1) || *(cp + 1) != '\n') 3176 makeascii(1, cp, fp); 3177 } else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp)) 3178 putc(*cp, fp); 3179 else 3180 makeascii(1, cp, fp); 3181 cp++; 3182 } 3183} 3184 3185 3186/* 3187 * Global data used by the cooked output routines 3188 */ 3189int out_chars; /* number of characters output */ 3190int out_linecount; /* number of characters output on this line */ 3191 3192 3193/* 3194 * startoutput - get ready to do cooked output 3195 */ 3196static void 3197startoutput(void) 3198{ 3199 out_chars = 0; 3200 out_linecount = 0; 3201} 3202 3203 3204/* 3205 * output - output a variable=value combination 3206 */ 3207static void 3208output( 3209 FILE *fp, 3210 const char *name, 3211 const char *value 3212 ) 3213{ 3214 int len; 3215 3216 /* strlen of "name=value" */ 3217 len = size2int_sat(strlen(name) + 1 + strlen(value)); 3218 3219 if (out_chars != 0) { 3220 out_chars += 2; 3221 if ((out_linecount + len + 2) > MAXOUTLINE) { 3222 fputs(",\n", fp); 3223 out_linecount = 0; 3224 } else { 3225 fputs(", ", fp); 3226 out_linecount += 2; 3227 } 3228 } 3229 3230 fputs(name, fp); 3231 putc('=', fp); 3232 fputs(value, fp); 3233 out_chars += len; 3234 out_linecount += len; 3235} 3236 3237 3238/* 3239 * endoutput - terminate a block of cooked output 3240 */ 3241static void 3242endoutput( 3243 FILE *fp 3244 ) 3245{ 3246 if (out_chars != 0) 3247 putc('\n', fp); 3248} 3249 3250 3251/* 3252 * outputarr - output an array of values 3253 */ 3254static void 3255outputarr( 3256 FILE *fp, 3257 char *name, 3258 int narr, 3259 l_fp *lfp 3260 ) 3261{ 3262 char *bp; 3263 char *cp; 3264 size_t i; 3265 size_t len; 3266 char buf[256]; 3267 3268 bp = buf; 3269 /* 3270 * Hack to align delay and offset values 3271 */ 3272 for (i = (int)strlen(name); i < 11; i++) 3273 *bp++ = ' '; 3274 3275 for (i = narr; i > 0; i--) { 3276 if (i != narr) 3277 *bp++ = ' '; 3278 cp = lfptoms(lfp, 2); 3279 len = strlen(cp); 3280 if (len > 7) { 3281 cp[7] = '\0'; 3282 len = 7; 3283 } 3284 while (len < 7) { 3285 *bp++ = ' '; 3286 len++; 3287 } 3288 while (*cp != '\0') 3289 *bp++ = *cp++; 3290 lfp++; 3291 } 3292 *bp = '\0'; 3293 output(fp, name, buf); 3294} 3295 3296static char * 3297tstflags( 3298 u_long val 3299 ) 3300{ 3301 register char *cp, *s; 3302 size_t cb; 3303 register int i; 3304 register const char *sep; 3305 3306 sep = ""; 3307 s = cp = circ_buf[nextcb]; 3308 if (++nextcb >= NUMCB) 3309 nextcb = 0; 3310 cb = sizeof(circ_buf[0]); 3311 3312 snprintf(cp, cb, "%02lx", val); 3313 cp += strlen(cp); 3314 cb -= strlen(cp); 3315 if (!val) { 3316 strlcat(cp, " ok", cb); 3317 cp += strlen(cp); 3318 cb -= strlen(cp); 3319 } else { 3320 if (cb) { 3321 *cp++ = ' '; 3322 cb--; 3323 } 3324 for (i = 0; i < (int)COUNTOF(tstflagnames); i++) { 3325 if (val & 0x1) { 3326 snprintf(cp, cb, "%s%s", sep, 3327 tstflagnames[i]); 3328 sep = ", "; 3329 cp += strlen(cp); 3330 cb -= strlen(cp); 3331 } 3332 val >>= 1; 3333 } 3334 } 3335 if (cb) 3336 *cp = '\0'; 3337 3338 return s; 3339} 3340 3341/* 3342 * cookedprint - output variables in cooked mode 3343 */ 3344static void 3345cookedprint( 3346 int datatype, 3347 size_t length, 3348 const char *data, 3349 int status, 3350 int quiet, 3351 FILE *fp 3352 ) 3353{ 3354 char *name; 3355 char *value; 3356 char output_raw; 3357 int fmt; 3358 l_fp lfp; 3359 sockaddr_u hval; 3360 u_long uval; 3361 int narr; 3362 size_t len; 3363 l_fp lfparr[8]; 3364 char b[12]; 3365 char bn[2 * MAXVARLEN]; 3366 char bv[2 * MAXVALLEN]; 3367 3368 UNUSED_ARG(datatype); 3369 3370 if (!quiet) 3371 fprintf(fp, "status=%04x %s,\n", status, 3372 statustoa(datatype, status)); 3373 3374 startoutput(); 3375 while (nextvar(&length, &data, &name, &value)) { 3376 fmt = varfmt(name); 3377 output_raw = 0; 3378 switch (fmt) { 3379 3380 case PADDING: 3381 output_raw = '*'; 3382 break; 3383 3384 case TS: 3385 if (!decodets(value, &lfp)) 3386 output_raw = '?'; 3387 else 3388 output(fp, name, prettydate(&lfp)); 3389 break; 3390 3391 case HA: /* fallthru */ 3392 case NA: 3393 if (!decodenetnum(value, &hval)) { 3394 output_raw = '?'; 3395 } else if (fmt == HA){ 3396 output(fp, name, nntohost(&hval)); 3397 } else { 3398 output(fp, name, stoa(&hval)); 3399 } 3400 break; 3401 3402 case RF: 3403 if (decodenetnum(value, &hval)) { 3404 if (ISREFCLOCKADR(&hval)) 3405 output(fp, name, 3406 refnumtoa(&hval)); 3407 else 3408 output(fp, name, stoa(&hval)); 3409 } else if (strlen(value) <= 4) { 3410 output(fp, name, value); 3411 } else { 3412 output_raw = '?'; 3413 } 3414 break; 3415 3416 case LP: 3417 if (!decodeuint(value, &uval) || uval > 3) { 3418 output_raw = '?'; 3419 } else { 3420 b[0] = (0x2 & uval) 3421 ? '1' 3422 : '0'; 3423 b[1] = (0x1 & uval) 3424 ? '1' 3425 : '0'; 3426 b[2] = '\0'; 3427 output(fp, name, b); 3428 } 3429 break; 3430 3431 case OC: 3432 if (!decodeuint(value, &uval)) { 3433 output_raw = '?'; 3434 } else { 3435 snprintf(b, sizeof(b), "%03lo", uval); 3436 output(fp, name, b); 3437 } 3438 break; 3439 3440 case AR: 3441 if (!decodearr(value, &narr, lfparr)) 3442 output_raw = '?'; 3443 else 3444 outputarr(fp, name, narr, lfparr); 3445 break; 3446 3447 case FX: 3448 if (!decodeuint(value, &uval)) 3449 output_raw = '?'; 3450 else 3451 output(fp, name, tstflags(uval)); 3452 break; 3453 3454 default: 3455 fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3456 name, value, fmt); 3457 output_raw = '?'; 3458 break; 3459 } 3460 3461 if (output_raw != 0) { 3462 /* TALOS-CAN-0063: avoid buffer overrun */ 3463 atoascii(name, MAXVARLEN, bn, sizeof(bn)); 3464 if (output_raw != '*') { 3465 atoascii(value, MAXVALLEN, 3466 bv, sizeof(bv) - 1); 3467 len = strlen(bv); 3468 bv[len] = output_raw; 3469 bv[len+1] = '\0'; 3470 } else { 3471 atoascii(value, MAXVALLEN, 3472 bv, sizeof(bv)); 3473 } 3474 output(fp, bn, bv); 3475 } 3476 } 3477 endoutput(fp); 3478} 3479 3480 3481/* 3482 * sortassoc - sort associations in the cache into ascending order 3483 */ 3484void 3485sortassoc(void) 3486{ 3487 if (numassoc > 1) 3488 qsort(assoc_cache, (size_t)numassoc, 3489 sizeof(assoc_cache[0]), &assoccmp); 3490} 3491 3492 3493/* 3494 * assoccmp - compare two associations 3495 */ 3496static int 3497assoccmp( 3498 const void *t1, 3499 const void *t2 3500 ) 3501{ 3502 const struct association *ass1 = t1; 3503 const struct association *ass2 = t2; 3504 3505 if (ass1->assid < ass2->assid) 3506 return -1; 3507 if (ass1->assid > ass2->assid) 3508 return 1; 3509 return 0; 3510} 3511 3512 3513/* 3514 * grow_assoc_cache() - enlarge dynamic assoc_cache array 3515 * 3516 * The strategy is to add an assumed 4k page size at a time, leaving 3517 * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3518 */ 3519void 3520grow_assoc_cache(void) 3521{ 3522 static size_t prior_sz; 3523 size_t new_sz; 3524 3525 new_sz = prior_sz + 4 * 1024; 3526 if (0 == prior_sz) { 3527 new_sz -= 4 * sizeof(void *); 3528 } 3529 assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3530 prior_sz = new_sz; 3531 assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3532} 3533 3534 3535/* 3536 * ntpq_custom_opt_handler - autoopts handler for -c and -p 3537 * 3538 * By default, autoopts loses the relative order of -c and -p options 3539 * on the command line. This routine replaces the default handler for 3540 * those routines and builds a list of commands to execute preserving 3541 * the order. 3542 */ 3543void 3544ntpq_custom_opt_handler( 3545 tOptions *pOptions, 3546 tOptDesc *pOptDesc 3547 ) 3548{ 3549 switch (pOptDesc->optValue) { 3550 3551 default: 3552 fprintf(stderr, 3553 "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3554 pOptDesc->optValue, pOptDesc->optValue); 3555 exit(1); 3556 3557 case 'c': 3558 ADDCMD(pOptDesc->pzLastArg); 3559 break; 3560 3561 case 'p': 3562 ADDCMD("peers"); 3563 break; 3564 } 3565} 3566/* 3567 * Obtain list of digest names 3568 */ 3569 3570#ifdef OPENSSL 3571# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3572struct hstate { 3573 char *list; 3574 const char **seen; 3575 int idx; 3576}; 3577#define K_PER_LINE 8 3578#define K_NL_PFX_STR "\n " 3579#define K_DELIM_STR ", " 3580static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg ) 3581{ 3582 size_t len, n; 3583 const char *name, *cp, **seen; 3584 struct hstate *hstate = arg; 3585 EVP_MD_CTX ctx; 3586 u_int digest_len; 3587 u_char digest[EVP_MAX_MD_SIZE]; 3588 3589 if (!m) 3590 return; /* Ignore aliases */ 3591 3592 name = EVP_MD_name(m); 3593 3594 /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */ 3595 3596 for( cp = name; *cp; cp++ ) { 3597 if( islower(*cp) ) 3598 return; 3599 } 3600 len = (cp - name) + 1; 3601 3602 /* There are duplicates. Discard if name has been seen. */ 3603 3604 for (seen = hstate->seen; *seen; seen++) 3605 if (!strcmp(*seen, name)) 3606 return; 3607 n = (seen - hstate->seen) + 2; 3608 hstate->seen = erealloc(hstate->seen, n * sizeof(*seen)); 3609 hstate->seen[n-2] = name; 3610 hstate->seen[n-1] = NULL; 3611 3612 /* Discard MACs that NTP won't accept. 3613 * Keep this consistent with keytype_from_text() in ssl_init.c. 3614 */ 3615 3616 EVP_DigestInit(&ctx, EVP_get_digestbyname(name)); 3617 EVP_DigestFinal(&ctx, digest, &digest_len); 3618 if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t))) 3619 return; 3620 3621 if (hstate->list != NULL) 3622 len += strlen(hstate->list); 3623 len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR); 3624 3625 if (hstate->list == NULL) { 3626 hstate->list = (char *)emalloc(len); 3627 hstate->list[0] = '\0'; 3628 } else 3629 hstate->list = (char *)erealloc(hstate->list, len); 3630 3631 sprintf(hstate->list + strlen(hstate->list), "%s%s", 3632 ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR), 3633 name); 3634 if (hstate->idx >= K_PER_LINE) 3635 hstate->idx = 1; 3636 else 3637 hstate->idx++; 3638} 3639# endif 3640#endif 3641 3642static char *list_digest_names(void) 3643{ 3644 char *list = NULL; 3645 3646#ifdef OPENSSL 3647# ifdef HAVE_EVP_MD_DO_ALL_SORTED 3648 struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 3649 3650 hstate.seen = (const char **) emalloc_zero(1*sizeof( const char * )); // replaces -> calloc(1, sizeof( const char * )); 3651 3652 INIT_SSL(); 3653 EVP_MD_do_all_sorted(list_md_fn, &hstate); 3654 list = hstate.list; 3655 free(hstate.seen); 3656# else 3657 list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 3658 strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 3659# endif 3660#else 3661 list = (char *)emalloc(sizeof("md5")); 3662 strcpy(list, "md5"); 3663#endif 3664 3665 return list; 3666} 3667 3668#define CTRLC_STACK_MAX 4 3669static volatile size_t ctrlc_stack_len = 0; 3670static volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 3671 3672 3673 3674int/*BOOL*/ 3675push_ctrl_c_handler( 3676 Ctrl_C_Handler func 3677 ) 3678{ 3679 size_t size = ctrlc_stack_len; 3680 if (func && (size < CTRLC_STACK_MAX)) { 3681 ctrlc_stack[size] = func; 3682 ctrlc_stack_len = size + 1; 3683 return TRUE; 3684 } 3685 return FALSE; 3686} 3687 3688int/*BOOL*/ 3689pop_ctrl_c_handler( 3690 Ctrl_C_Handler func 3691 ) 3692{ 3693 size_t size = ctrlc_stack_len; 3694 if (size) { 3695 --size; 3696 if (func == NULL || func == ctrlc_stack[size]) { 3697 ctrlc_stack_len = size; 3698 return TRUE; 3699 } 3700 } 3701 return FALSE; 3702} 3703 3704static void 3705on_ctrlc(void) 3706{ 3707 size_t size = ctrlc_stack_len; 3708 while (size) 3709 if ((*ctrlc_stack[--size])()) 3710 break; 3711} 3712 3713static int 3714my_easprintf( 3715 char ** ppinto, 3716 const char * fmt , 3717 ... 3718 ) 3719{ 3720 va_list va; 3721 int prc; 3722 size_t len = 128; 3723 char * buf = emalloc(len); 3724 3725 again: 3726 /* Note: we expect the memory allocation to fail long before the 3727 * increment in buffer size actually overflows. 3728 */ 3729 buf = (buf) ? erealloc(buf, len) : emalloc(len); 3730 3731 va_start(va, fmt); 3732 prc = vsnprintf(buf, len, fmt, va); 3733 va_end(va); 3734 3735 if (prc < 0) { 3736 /* might be very old vsnprintf. Or actually MSVC... */ 3737 len += len >> 1; 3738 goto again; 3739 } 3740 if ((size_t)prc >= len) { 3741 /* at least we have the proper size now... */ 3742 len = (size_t)prc + 1; 3743 goto again; 3744 } 3745 if ((size_t)prc < (len - 32)) 3746 buf = erealloc(buf, (size_t)prc + 1); 3747 *ppinto = buf; 3748 return prc; 3749} 3750