1 1.22 christos /* $NetBSD: ntpq.c,v 1.23 2024/08/18 20:47:19 christos Exp $ */ 2 1.1 kardel 3 1.1 kardel /* 4 1.1 kardel * ntpq - query an NTP server using mode 6 commands 5 1.1 kardel */ 6 1.9 christos #include <config.h> 7 1.1 kardel #include <ctype.h> 8 1.1 kardel #include <signal.h> 9 1.1 kardel #include <setjmp.h> 10 1.19 christos #include <stddef.h> 11 1.19 christos #include <stdio.h> 12 1.1 kardel #include <sys/types.h> 13 1.1 kardel #include <sys/time.h> 14 1.9 christos #ifdef HAVE_UNISTD_H 15 1.9 christos # include <unistd.h> 16 1.9 christos #endif 17 1.9 christos #ifdef HAVE_FCNTL_H 18 1.9 christos # include <fcntl.h> 19 1.9 christos #endif 20 1.9 christos #ifdef SYS_WINNT 21 1.9 christos # include <mswsock.h> 22 1.23 christos # define PATH_DEVNULL "NUL:" 23 1.23 christos #else 24 1.23 christos # define PATH_DEVNULL "/dev/null" 25 1.9 christos #endif 26 1.9 christos #include <isc/net.h> 27 1.9 christos #include <isc/result.h> 28 1.1 kardel 29 1.1 kardel #include "ntpq.h" 30 1.1 kardel #include "ntp_unixtime.h" 31 1.1 kardel #include "ntp_calendar.h" 32 1.1 kardel #include "ntp_select.h" 33 1.1 kardel #include "ntp_lineedit.h" 34 1.1 kardel #include "ntp_debug.h" 35 1.9 christos #ifdef OPENSSL 36 1.20 christos # include "openssl/evp.h" 37 1.20 christos # include "openssl/objects.h" 38 1.20 christos # include "openssl/err.h" 39 1.20 christos # ifdef SYS_WINNT 40 1.20 christos # include "openssl/opensslv.h" 41 1.20 christos # if !defined(HAVE_EVP_MD_DO_ALL_SORTED) && OPENSSL_VERSION_NUMBER > 0x10000000L 42 1.20 christos # define HAVE_EVP_MD_DO_ALL_SORTED 1 43 1.20 christos # endif 44 1.20 christos # endif 45 1.20 christos # include "libssl_compat.h" 46 1.20 christos # ifdef HAVE_OPENSSL_CMAC_H 47 1.20 christos # include <openssl/cmac.h> 48 1.20 christos # define CMAC "AES128CMAC" 49 1.19 christos # endif 50 1.19 christos #endif 51 1.1 kardel #include <ssl_applink.c> 52 1.1 kardel 53 1.4 kardel #include "ntp_libopts.h" 54 1.14 christos #include "safecast.h" 55 1.1 kardel 56 1.9 christos #ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/ 57 1.1 kardel # define open(name, flags) open(name, flags, 0777) 58 1.1 kardel # define SERVER_PORT_NUM 123 59 1.1 kardel #endif 60 1.1 kardel 61 1.1 kardel /* we use COMMAND as an autogen keyword */ 62 1.1 kardel #ifdef COMMAND 63 1.1 kardel # undef COMMAND 64 1.1 kardel #endif 65 1.1 kardel 66 1.1 kardel /* 67 1.1 kardel * Because we potentially understand a lot of commands we will run 68 1.1 kardel * interactive if connected to a terminal. 69 1.1 kardel */ 70 1.1 kardel int interactive = 0; /* set to 1 when we should prompt */ 71 1.1 kardel const char *prompt = "ntpq> "; /* prompt to ask him about */ 72 1.1 kardel 73 1.1 kardel /* 74 1.1 kardel * use old readvars behavior? --old-rv processing in ntpq resets 75 1.1 kardel * this value based on the presence or absence of --old-rv. It is 76 1.1 kardel * initialized to 1 here to maintain backward compatibility with 77 1.1 kardel * libntpq clients such as ntpsnmpd, which are free to reset it as 78 1.1 kardel * desired. 79 1.1 kardel */ 80 1.1 kardel int old_rv = 1; 81 1.1 kardel 82 1.15 christos /* 83 1.15 christos * How should we display the refid? 84 1.15 christos * REFID_HASH, REFID_IPV4 85 1.15 christos */ 86 1.15 christos te_Refid drefid = -1; 87 1.1 kardel 88 1.1 kardel /* 89 1.1 kardel * for get_systime() 90 1.1 kardel */ 91 1.1 kardel s_char sys_precision; /* local clock precision (log2 s) */ 92 1.1 kardel 93 1.1 kardel /* 94 1.1 kardel * Keyid used for authenticated requests. Obtained on the fly. 95 1.1 kardel */ 96 1.1 kardel u_long info_auth_keyid = 0; 97 1.1 kardel 98 1.1 kardel static int info_auth_keytype = NID_md5; /* MD5 */ 99 1.1 kardel static size_t info_auth_hashlen = 16; /* MD5 */ 100 1.1 kardel u_long current_time; /* needed by authkeys; not used */ 101 1.1 kardel 102 1.1 kardel /* 103 1.1 kardel * Flag which indicates we should always send authenticated requests 104 1.1 kardel */ 105 1.1 kardel int always_auth = 0; 106 1.1 kardel 107 1.1 kardel /* 108 1.1 kardel * Flag which indicates raw mode output. 109 1.1 kardel */ 110 1.1 kardel int rawmode = 0; 111 1.1 kardel 112 1.1 kardel /* 113 1.1 kardel * Packet version number we use 114 1.1 kardel */ 115 1.1 kardel u_char pktversion = NTP_OLDVERSION + 1; 116 1.1 kardel 117 1.1 kardel 118 1.1 kardel /* 119 1.1 kardel * Format values 120 1.1 kardel */ 121 1.1 kardel #define PADDING 0 122 1.9 christos #define HA 1 /* host address */ 123 1.9 christos #define NA 2 /* network address */ 124 1.9 christos #define LP 3 /* leap (print in binary) */ 125 1.9 christos #define RF 4 /* refid (sometimes string, sometimes not) */ 126 1.21 christos #define AU 5 /* array of unsigned times */ 127 1.9 christos #define FX 6 /* test flags */ 128 1.9 christos #define TS 7 /* l_fp timestamp in hex */ 129 1.9 christos #define OC 8 /* integer, print in octal */ 130 1.21 christos #define AS 9 /* array of signed times */ 131 1.21 christos #define SN 10 /* signed number: must display +/- sign */ 132 1.1 kardel #define EOV 255 /* end of table */ 133 1.1 kardel 134 1.1 kardel /* 135 1.9 christos * For the most part ntpq simply displays what ntpd provides in the 136 1.9 christos * mostly plain-text mode 6 responses. A few variable names are by 137 1.9 christos * default "cooked" to provide more human-friendly output. 138 1.9 christos */ 139 1.9 christos const var_format cookedvars[] = { 140 1.9 christos { "leap", LP }, 141 1.9 christos { "reach", OC }, 142 1.9 christos { "refid", RF }, 143 1.9 christos { "reftime", TS }, 144 1.9 christos { "clock", TS }, 145 1.9 christos { "org", TS }, 146 1.9 christos { "rec", TS }, 147 1.9 christos { "xmt", TS }, 148 1.9 christos { "flash", FX }, 149 1.9 christos { "srcadr", HA }, 150 1.9 christos { "peeradr", HA }, /* compat with others */ 151 1.9 christos { "dstadr", NA }, 152 1.21 christos { "filtdelay", AU }, 153 1.21 christos { "filtoffset", AS }, 154 1.21 christos { "filtdisp", AU }, 155 1.21 christos { "filterror", AU }, /* compat with others */ 156 1.21 christos { "offset", SN }, 157 1.21 christos { "frequency", SN } 158 1.1 kardel }; 159 1.1 kardel 160 1.1 kardel 161 1.1 kardel 162 1.1 kardel /* 163 1.1 kardel * flasher bits 164 1.1 kardel */ 165 1.1 kardel static const char *tstflagnames[] = { 166 1.1 kardel "pkt_dup", /* TEST1 */ 167 1.1 kardel "pkt_bogus", /* TEST2 */ 168 1.1 kardel "pkt_unsync", /* TEST3 */ 169 1.1 kardel "pkt_denied", /* TEST4 */ 170 1.1 kardel "pkt_auth", /* TEST5 */ 171 1.1 kardel "pkt_stratum", /* TEST6 */ 172 1.1 kardel "pkt_header", /* TEST7 */ 173 1.1 kardel "pkt_autokey", /* TEST8 */ 174 1.1 kardel "pkt_crypto", /* TEST9 */ 175 1.1 kardel "peer_stratum", /* TEST10 */ 176 1.1 kardel "peer_dist", /* TEST11 */ 177 1.1 kardel "peer_loop", /* TEST12 */ 178 1.1 kardel "peer_unreach" /* TEST13 */ 179 1.1 kardel }; 180 1.1 kardel 181 1.1 kardel 182 1.1 kardel int ntpqmain (int, char **); 183 1.1 kardel /* 184 1.1 kardel * Built in command handler declarations 185 1.1 kardel */ 186 1.9 christos static int openhost (const char *, int); 187 1.9 christos static void dump_hex_printable(const void *, size_t); 188 1.1 kardel static int sendpkt (void *, size_t); 189 1.14 christos static int getresponse (int, int, u_short *, size_t *, const char **, int); 190 1.14 christos static int sendrequest (int, associd_t, int, size_t, const char *); 191 1.1 kardel static char * tstflags (u_long); 192 1.1 kardel #ifndef BUILD_AS_LIB 193 1.1 kardel static void getcmds (void); 194 1.1 kardel #ifndef SYS_WINNT 195 1.14 christos static int abortcmd (void); 196 1.1 kardel #endif /* SYS_WINNT */ 197 1.1 kardel static void docmd (const char *); 198 1.1 kardel static void tokenize (const char *, char **, int *); 199 1.9 christos static int getarg (const char *, int, arg_v *); 200 1.1 kardel #endif /* BUILD_AS_LIB */ 201 1.9 christos static int findcmd (const char *, struct xcmd *, 202 1.9 christos struct xcmd *, struct xcmd **); 203 1.1 kardel static int rtdatetolfp (char *, l_fp *); 204 1.19 christos static int decodearr (char *, int *, l_fp *, int); 205 1.1 kardel static void help (struct parse *, FILE *); 206 1.1 kardel static int helpsort (const void *, const void *); 207 1.1 kardel static void printusage (struct xcmd *, FILE *); 208 1.1 kardel static void timeout (struct parse *, FILE *); 209 1.1 kardel static void auth_delay (struct parse *, FILE *); 210 1.1 kardel static void host (struct parse *, FILE *); 211 1.1 kardel static void ntp_poll (struct parse *, FILE *); 212 1.1 kardel static void keyid (struct parse *, FILE *); 213 1.1 kardel static void keytype (struct parse *, FILE *); 214 1.1 kardel static void passwd (struct parse *, FILE *); 215 1.1 kardel static void hostnames (struct parse *, FILE *); 216 1.1 kardel static void setdebug (struct parse *, FILE *); 217 1.1 kardel static void quit (struct parse *, FILE *); 218 1.15 christos static void showdrefid (struct parse *, FILE *); 219 1.1 kardel static void version (struct parse *, FILE *); 220 1.1 kardel static void raw (struct parse *, FILE *); 221 1.1 kardel static void cooked (struct parse *, FILE *); 222 1.1 kardel static void authenticate (struct parse *, FILE *); 223 1.1 kardel static void ntpversion (struct parse *, FILE *); 224 1.20 christos static void warning (const char *, ...) NTP_PRINTF(1, 2); 225 1.20 christos static void error (const char *, ...) NTP_PRINTF(1, 2); 226 1.1 kardel static u_long getkeyid (const char *); 227 1.1 kardel static void atoascii (const char *, size_t, char *, size_t); 228 1.14 christos static void cookedprint (int, size_t, const char *, int, int, FILE *); 229 1.14 christos static void rawprint (int, size_t, const char *, int, int, FILE *); 230 1.1 kardel static void startoutput (void); 231 1.9 christos static void output (FILE *, const char *, const char *); 232 1.1 kardel static void endoutput (FILE *); 233 1.21 christos static void outputarr (FILE *, char *, int, l_fp *, int); 234 1.1 kardel static int assoccmp (const void *, const void *); 235 1.20 christos u_short varfmt (const char *); 236 1.20 christos void ntpq_custom_opt_handler(tOptions *, tOptDesc *); 237 1.20 christos 238 1.20 christos #ifndef BUILD_AS_LIB 239 1.20 christos static char *list_digest_names(void); 240 1.14 christos static void on_ctrlc (void); 241 1.15 christos static int my_easprintf (char**, const char *, ...) NTP_PRINTF(2, 3); 242 1.23 christos #ifdef OPENSSL 243 1.23 christos static char *insert_cmac (char *list); 244 1.23 christos # ifdef HAVE_EVP_MD_DO_ALL_SORTED 245 1.20 christos static void list_md_fn (const EVP_MD *m, const char *from, 246 1.20 christos const char *to, void *arg); 247 1.23 christos # endif /* HAVE_EVP_MD_DO_ALL_SORTED */ 248 1.23 christos #endif /* OPENSSL */ 249 1.20 christos #endif /* !defined(BUILD_AS_LIB) */ 250 1.20 christos 251 1.1 kardel 252 1.19 christos /* read a character from memory and expand to integer */ 253 1.19 christos static inline int 254 1.19 christos pgetc( 255 1.19 christos const char *cp 256 1.19 christos ) 257 1.19 christos { 258 1.19 christos return (int)*(const unsigned char*)cp; 259 1.19 christos } 260 1.19 christos 261 1.19 christos 262 1.1 kardel 263 1.1 kardel /* 264 1.1 kardel * Built-in commands we understand 265 1.1 kardel */ 266 1.1 kardel struct xcmd builtins[] = { 267 1.1 kardel { "?", help, { OPT|NTP_STR, NO, NO, NO }, 268 1.1 kardel { "command", "", "", "" }, 269 1.1 kardel "tell the use and syntax of commands" }, 270 1.1 kardel { "help", help, { OPT|NTP_STR, NO, NO, NO }, 271 1.1 kardel { "command", "", "", "" }, 272 1.1 kardel "tell the use and syntax of commands" }, 273 1.1 kardel { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO }, 274 1.1 kardel { "msec", "", "", "" }, 275 1.1 kardel "set the primary receive time out" }, 276 1.1 kardel { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO }, 277 1.1 kardel { "msec", "", "", "" }, 278 1.1 kardel "set the delay added to encryption time stamps" }, 279 1.1 kardel { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO }, 280 1.1 kardel { "-4|-6", "hostname", "", "" }, 281 1.1 kardel "specify the host whose NTP server we talk to" }, 282 1.1 kardel { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 283 1.1 kardel { "n", "verbose", "", "" }, 284 1.1 kardel "poll an NTP server in client mode `n' times" }, 285 1.9 christos { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO }, 286 1.1 kardel { "", "", "", "" }, 287 1.1 kardel "specify a password to use for authenticated requests"}, 288 1.1 kardel { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO }, 289 1.1 kardel { "yes|no", "", "", "" }, 290 1.1 kardel "specify whether hostnames or net numbers are printed"}, 291 1.1 kardel { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO }, 292 1.1 kardel { "no|more|less", "", "", "" }, 293 1.1 kardel "set/change debugging level" }, 294 1.1 kardel { "quit", quit, { NO, NO, NO, NO }, 295 1.1 kardel { "", "", "", "" }, 296 1.1 kardel "exit ntpq" }, 297 1.1 kardel { "exit", quit, { NO, NO, NO, NO }, 298 1.1 kardel { "", "", "", "" }, 299 1.1 kardel "exit ntpq" }, 300 1.1 kardel { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO }, 301 1.1 kardel { "key#", "", "", "" }, 302 1.1 kardel "set keyid to use for authenticated requests" }, 303 1.15 christos { "drefid", showdrefid, { OPT|NTP_STR, NO, NO, NO }, 304 1.15 christos { "hash|ipv4", "", "", "" }, 305 1.15 christos "display refid's as IPv4 or hash" }, 306 1.1 kardel { "version", version, { NO, NO, NO, NO }, 307 1.1 kardel { "", "", "", "" }, 308 1.1 kardel "print version number" }, 309 1.1 kardel { "raw", raw, { NO, NO, NO, NO }, 310 1.1 kardel { "", "", "", "" }, 311 1.1 kardel "do raw mode variable output" }, 312 1.1 kardel { "cooked", cooked, { NO, NO, NO, NO }, 313 1.1 kardel { "", "", "", "" }, 314 1.1 kardel "do cooked mode variable output" }, 315 1.1 kardel { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO }, 316 1.1 kardel { "yes|no", "", "", "" }, 317 1.1 kardel "always authenticate requests to this server" }, 318 1.1 kardel { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO }, 319 1.1 kardel { "version number", "", "", "" }, 320 1.1 kardel "set the NTP version number to use for requests" }, 321 1.1 kardel { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO }, 322 1.12 christos { "key type %s", "", "", "" }, 323 1.12 christos NULL }, 324 1.1 kardel { 0, 0, { NO, NO, NO, NO }, 325 1.1 kardel { "", "", "", "" }, "" } 326 1.1 kardel }; 327 1.1 kardel 328 1.1 kardel 329 1.1 kardel /* 330 1.1 kardel * Default values we use. 331 1.1 kardel */ 332 1.1 kardel #define DEFHOST "localhost" /* default host name */ 333 1.9 christos #define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */ 334 1.9 christos #define DEFSTIMEOUT 3 /* and 3 more for each additional */ 335 1.9 christos /* 336 1.9 christos * Requests are automatically retried once, so total timeout with no 337 1.9 christos * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other 338 1.9 christos * extreme, a request eliciting 32 packets of responses each for some 339 1.9 christos * reason nearly DEFSTIMEOUT seconds after the prior in that series, 340 1.9 christos * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or 341 1.9 christos * 93 seconds to fail each of two times, or 186 seconds. 342 1.9 christos * Some commands involve a series of requests, such as "peers" and 343 1.9 christos * "mrulist", so the cumulative timeouts are even longer for those. 344 1.9 christos */ 345 1.1 kardel #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */ 346 1.1 kardel #define LENHOSTNAME 256 /* host name is 256 characters long */ 347 1.1 kardel #define MAXCMDS 100 /* maximum commands on cmd line */ 348 1.1 kardel #define MAXHOSTS 200 /* maximum hosts on cmd line */ 349 1.1 kardel #define MAXLINE 512 /* maximum line length */ 350 1.1 kardel #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */ 351 1.1 kardel #define MAXVARLEN 256 /* maximum length of a variable name */ 352 1.9 christos #define MAXVALLEN 2048 /* maximum length of a variable value */ 353 1.1 kardel #define MAXOUTLINE 72 /* maximum length of an output line */ 354 1.1 kardel #define SCREENWIDTH 76 /* nominal screen width in columns */ 355 1.1 kardel 356 1.1 kardel /* 357 1.1 kardel * Some variables used and manipulated locally 358 1.1 kardel */ 359 1.1 kardel struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */ 360 1.1 kardel struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */ 361 1.1 kardel l_fp delay_time; /* delay time */ 362 1.1 kardel char currenthost[LENHOSTNAME]; /* current host name */ 363 1.4 kardel int currenthostisnum; /* is prior text from IP? */ 364 1.5 kardel struct sockaddr_in hostaddr; /* host address */ 365 1.1 kardel int showhostnames = 1; /* show host names by default */ 366 1.10 christos int wideremote = 0; /* show wide remote names? */ 367 1.1 kardel 368 1.1 kardel int ai_fam_templ; /* address family */ 369 1.1 kardel int ai_fam_default; /* default address family */ 370 1.1 kardel SOCKET sockfd; /* fd socket is opened on */ 371 1.1 kardel int havehost = 0; /* set to 1 when host open */ 372 1.1 kardel int s_port = 0; 373 1.1 kardel struct servent *server_entry = NULL; /* server entry for ntp */ 374 1.1 kardel 375 1.1 kardel 376 1.1 kardel /* 377 1.1 kardel * Sequence number used for requests. It is incremented before 378 1.1 kardel * it is used. 379 1.1 kardel */ 380 1.1 kardel u_short sequence; 381 1.1 kardel 382 1.1 kardel /* 383 1.1 kardel * Holds data returned from queries. Declare buffer long to be sure of 384 1.1 kardel * alignment. 385 1.1 kardel */ 386 1.1 kardel #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */ 387 1.1 kardel long pktdata[DATASIZE/sizeof(long)]; 388 1.1 kardel 389 1.1 kardel /* 390 1.9 christos * assoc_cache[] is a dynamic array which allows references to 391 1.9 christos * associations using &1 ... &N for n associations, avoiding manual 392 1.9 christos * lookup of the current association IDs for a given ntpd. It also 393 1.9 christos * caches the status word for each association, retrieved incidentally. 394 1.9 christos */ 395 1.9 christos struct association * assoc_cache; 396 1.9 christos u_int assoc_cache_slots;/* count of allocated array entries */ 397 1.9 christos u_int numassoc; /* number of cached associations */ 398 1.1 kardel 399 1.1 kardel /* 400 1.1 kardel * For commands typed on the command line (with the -c option) 401 1.1 kardel */ 402 1.12 christos size_t numcmds = 0; 403 1.23 christos size_t defcmds = 0; /* Options on the command line are 'defined'! */ 404 1.23 christos char *ccmds[MAXCMDS]; 405 1.23 christos #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = estrdup(cp) 406 1.1 kardel 407 1.1 kardel /* 408 1.1 kardel * When multiple hosts are specified. 409 1.1 kardel */ 410 1.1 kardel 411 1.9 christos u_int numhosts; 412 1.9 christos 413 1.9 christos chost chosts[MAXHOSTS]; 414 1.9 christos #define ADDHOST(cp) \ 415 1.9 christos do { \ 416 1.9 christos if (numhosts < MAXHOSTS) { \ 417 1.9 christos chosts[numhosts].name = (cp); \ 418 1.9 christos chosts[numhosts].fam = ai_fam_templ; \ 419 1.9 christos numhosts++; \ 420 1.9 christos } \ 421 1.9 christos } while (0) 422 1.1 kardel 423 1.1 kardel /* 424 1.1 kardel * Macro definitions we use 425 1.1 kardel */ 426 1.1 kardel #define ISSPACE(c) ((c) == ' ' || (c) == '\t') 427 1.1 kardel #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 428 1.1 kardel #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 429 1.1 kardel 430 1.1 kardel /* 431 1.20 christos * Jump buffer for longjumping back to the command level. 432 1.20 christos * 433 1.20 christos * Since we do this from a signal handler, we use 'sig{set,long}jmp()' 434 1.20 christos * if available. The signal is blocked by default during the excution of 435 1.20 christos * a signal handler, and it is unspecified if '{set,long}jmp()' save and 436 1.20 christos * restore the signal mask. They do on BSD, it depends on the GLIBC 437 1.20 christos * version on Linux, and the gods know what happens on other OSes... 438 1.20 christos * 439 1.20 christos * So we use the 'sig{set,long}jmp()' functions where available, because 440 1.20 christos * for them the semantics are well-defined. If we have to fall back to 441 1.20 christos * '{set,long}jmp()', the CTRL-C handling might be a bit erratic. 442 1.20 christos */ 443 1.20 christos #if HAVE_DECL_SIGSETJMP && HAVE_DECL_SIGLONGJMP 444 1.20 christos # define JMP_BUF sigjmp_buf 445 1.20 christos # define SETJMP(x) sigsetjmp((x), 1) 446 1.20 christos # define LONGJMP(x, v) siglongjmp((x),(v)) 447 1.20 christos #else 448 1.20 christos # define JMP_BUF jmp_buf 449 1.20 christos # define SETJMP(x) setjmp((x)) 450 1.20 christos # define LONGJMP(x, v) longjmp((x),(v)) 451 1.20 christos #endif 452 1.23 christos 453 1.23 christos #ifndef BUILD_AS_LIB 454 1.20 christos static JMP_BUF interrupt_buf; 455 1.20 christos static volatile int jump = 0; 456 1.23 christos #endif 457 1.1 kardel 458 1.1 kardel /* 459 1.1 kardel * Points at file being currently printed into 460 1.1 kardel */ 461 1.20 christos FILE *current_output = NULL; 462 1.1 kardel 463 1.1 kardel /* 464 1.1 kardel * Command table imported from ntpdc_ops.c 465 1.1 kardel */ 466 1.1 kardel extern struct xcmd opcmds[]; 467 1.1 kardel 468 1.13 christos char const *progname; 469 1.1 kardel 470 1.1 kardel #ifdef NO_MAIN_ALLOWED 471 1.1 kardel #ifndef BUILD_AS_LIB 472 1.1 kardel CALL(ntpq,"ntpq",ntpqmain); 473 1.1 kardel 474 1.1 kardel void clear_globals(void) 475 1.1 kardel { 476 1.1 kardel extern int ntp_optind; 477 1.1 kardel showhostnames = 0; /* don'tshow host names by default */ 478 1.1 kardel ntp_optind = 0; 479 1.1 kardel server_entry = NULL; /* server entry for ntp */ 480 1.1 kardel havehost = 0; /* set to 1 when host open */ 481 1.1 kardel numassoc = 0; /* number of cached associations */ 482 1.1 kardel numcmds = 0; 483 1.1 kardel numhosts = 0; 484 1.1 kardel } 485 1.1 kardel #endif /* !BUILD_AS_LIB */ 486 1.1 kardel #endif /* NO_MAIN_ALLOWED */ 487 1.1 kardel 488 1.1 kardel /* 489 1.1 kardel * main - parse arguments and handle options 490 1.1 kardel */ 491 1.1 kardel #ifndef NO_MAIN_ALLOWED 492 1.1 kardel int 493 1.1 kardel main( 494 1.1 kardel int argc, 495 1.1 kardel char *argv[] 496 1.1 kardel ) 497 1.1 kardel { 498 1.1 kardel return ntpqmain(argc, argv); 499 1.1 kardel } 500 1.1 kardel #endif 501 1.1 kardel 502 1.19 christos 503 1.1 kardel #ifndef BUILD_AS_LIB 504 1.1 kardel int 505 1.1 kardel ntpqmain( 506 1.1 kardel int argc, 507 1.1 kardel char *argv[] 508 1.1 kardel ) 509 1.1 kardel { 510 1.9 christos u_int ihost; 511 1.12 christos size_t icmd; 512 1.9 christos 513 1.1 kardel 514 1.1 kardel #ifdef SYS_VXWORKS 515 1.1 kardel clear_globals(); 516 1.1 kardel taskPrioritySet(taskIdSelf(), 100 ); 517 1.1 kardel #endif 518 1.1 kardel 519 1.1 kardel delay_time.l_ui = 0; 520 1.1 kardel delay_time.l_uf = DEFDELAY; 521 1.1 kardel 522 1.1 kardel init_lib(); /* sets up ipv4_works, ipv6_works */ 523 1.1 kardel ssl_applink(); 524 1.9 christos init_auth(); 525 1.1 kardel 526 1.1 kardel /* Check to see if we have IPv6. Otherwise default to IPv4 */ 527 1.1 kardel if (!ipv6_works) 528 1.1 kardel ai_fam_default = AF_INET; 529 1.1 kardel 530 1.12 christos /* Fixup keytype's help based on available digest names */ 531 1.12 christos 532 1.12 christos { 533 1.12 christos char *list; 534 1.12 christos char *msg; 535 1.12 christos 536 1.12 christos list = list_digest_names(); 537 1.19 christos 538 1.19 christos for (icmd = 0; icmd < sizeof(builtins)/sizeof(*builtins); icmd++) { 539 1.19 christos if (strcmp("keytype", builtins[icmd].keyword) == 0) { 540 1.12 christos break; 541 1.19 christos } 542 1.12 christos } 543 1.12 christos 544 1.12 christos /* CID: 1295478 */ 545 1.12 christos /* This should only "trip" if "keytype" is removed from builtins */ 546 1.19 christos INSIST(icmd < sizeof(builtins)/sizeof(*builtins)); 547 1.12 christos 548 1.12 christos #ifdef OPENSSL 549 1.12 christos builtins[icmd].desc[0] = "digest-name"; 550 1.15 christos my_easprintf(&msg, 551 1.15 christos "set key type to use for authenticated requests, one of:%s", 552 1.15 christos list); 553 1.12 christos #else 554 1.12 christos builtins[icmd].desc[0] = "md5"; 555 1.15 christos my_easprintf(&msg, 556 1.15 christos "set key type to use for authenticated requests (%s)", 557 1.15 christos list); 558 1.12 christos #endif 559 1.12 christos builtins[icmd].comment = msg; 560 1.12 christos free(list); 561 1.12 christos } 562 1.12 christos 563 1.1 kardel progname = argv[0]; 564 1.1 kardel 565 1.1 kardel { 566 1.4 kardel int optct = ntpOptionProcess(&ntpqOptions, argc, argv); 567 1.1 kardel argc -= optct; 568 1.1 kardel argv += optct; 569 1.1 kardel } 570 1.1 kardel 571 1.1 kardel /* 572 1.1 kardel * Process options other than -c and -p, which are specially 573 1.1 kardel * handled by ntpq_custom_opt_handler(). 574 1.1 kardel */ 575 1.1 kardel 576 1.9 christos debug = OPT_VALUE_SET_DEBUG_LEVEL; 577 1.1 kardel 578 1.1 kardel if (HAVE_OPT(IPV4)) 579 1.1 kardel ai_fam_templ = AF_INET; 580 1.1 kardel else if (HAVE_OPT(IPV6)) 581 1.1 kardel ai_fam_templ = AF_INET6; 582 1.1 kardel else 583 1.1 kardel ai_fam_templ = ai_fam_default; 584 1.1 kardel 585 1.1 kardel if (HAVE_OPT(INTERACTIVE)) 586 1.1 kardel interactive = 1; 587 1.1 kardel 588 1.1 kardel if (HAVE_OPT(NUMERIC)) 589 1.1 kardel showhostnames = 0; 590 1.1 kardel 591 1.10 christos if (HAVE_OPT(WIDE)) 592 1.10 christos wideremote = 1; 593 1.10 christos 594 1.1 kardel old_rv = HAVE_OPT(OLD_RV); 595 1.1 kardel 596 1.15 christos drefid = OPT_VALUE_REFID; 597 1.15 christos 598 1.9 christos if (0 == argc) { 599 1.1 kardel ADDHOST(DEFHOST); 600 1.1 kardel } else { 601 1.9 christos for (ihost = 0; ihost < (u_int)argc; ihost++) { 602 1.9 christos if ('-' == *argv[ihost]) { 603 1.9 christos // 604 1.9 christos // If I really cared I'd also check: 605 1.9 christos // 0 == argv[ihost][2] 606 1.9 christos // 607 1.9 christos // and there are other cases as well... 608 1.9 christos // 609 1.9 christos if ('4' == argv[ihost][1]) { 610 1.9 christos ai_fam_templ = AF_INET; 611 1.9 christos continue; 612 1.9 christos } else if ('6' == argv[ihost][1]) { 613 1.9 christos ai_fam_templ = AF_INET6; 614 1.9 christos continue; 615 1.9 christos } else { 616 1.9 christos // XXX Throw a usage error 617 1.9 christos } 618 1.9 christos } 619 1.9 christos ADDHOST(argv[ihost]); 620 1.9 christos } 621 1.1 kardel } 622 1.1 kardel 623 1.23 christos if (defcmds == 0 && interactive == 0 624 1.1 kardel && isatty(fileno(stdin)) && isatty(fileno(stderr))) { 625 1.1 kardel interactive = 1; 626 1.1 kardel } 627 1.1 kardel 628 1.14 christos set_ctrl_c_hook(on_ctrlc); 629 1.1 kardel #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */ 630 1.1 kardel if (interactive) 631 1.14 christos push_ctrl_c_handler(abortcmd); 632 1.1 kardel #endif /* SYS_WINNT */ 633 1.1 kardel 634 1.23 christos if (numcmds > 0) { 635 1.1 kardel for (ihost = 0; ihost < numhosts; ihost++) { 636 1.19 christos if (openhost(chosts[ihost].name, chosts[ihost].fam)) { 637 1.20 christos if (ihost && current_output) 638 1.19 christos fputc('\n', current_output); 639 1.19 christos for (icmd = 0; icmd < numcmds; icmd++) { 640 1.20 christos if (icmd && current_output) 641 1.19 christos fputc('\n', current_output); 642 1.1 kardel docmd(ccmds[icmd]); 643 1.19 christos } 644 1.19 christos } 645 1.1 kardel } 646 1.23 christos /* Release memory allocated in ADDCMD */ 647 1.23 christos for (icmd = 0; icmd < numcmds; icmd++) 648 1.23 christos free(ccmds[icmd]); 649 1.23 christos } 650 1.23 christos 651 1.23 christos if (defcmds == 0) { /* No command line commands, so go interactive */ 652 1.23 christos (void) openhost(chosts[0].name, chosts[0].fam); 653 1.23 christos getcmds(); 654 1.1 kardel } 655 1.1 kardel #ifdef SYS_WINNT 656 1.1 kardel WSACleanup(); 657 1.1 kardel #endif /* SYS_WINNT */ 658 1.1 kardel return 0; 659 1.1 kardel } 660 1.1 kardel #endif /* !BUILD_AS_LIB */ 661 1.1 kardel 662 1.1 kardel /* 663 1.1 kardel * openhost - open a socket to a host 664 1.1 kardel */ 665 1.1 kardel static int 666 1.1 kardel openhost( 667 1.9 christos const char *hname, 668 1.9 christos int fam 669 1.1 kardel ) 670 1.1 kardel { 671 1.9 christos const char svc[] = "ntp"; 672 1.1 kardel char temphost[LENHOSTNAME]; 673 1.20 christos int a_info; 674 1.9 christos struct addrinfo hints, *ai; 675 1.9 christos sockaddr_u addr; 676 1.9 christos size_t octets; 677 1.20 christos const char *cp; 678 1.1 kardel char name[LENHOSTNAME]; 679 1.1 kardel 680 1.1 kardel /* 681 1.1 kardel * We need to get by the [] if they were entered 682 1.1 kardel */ 683 1.20 christos if (*hname == '[') { 684 1.20 christos cp = strchr(hname + 1, ']'); 685 1.20 christos if (!cp || (octets = (size_t)(cp - hname) - 1) >= sizeof(name)) { 686 1.20 christos errno = EINVAL; 687 1.20 christos warning("%s", "bad hostname/address"); 688 1.1 kardel return 0; 689 1.1 kardel } 690 1.20 christos memcpy(name, hname + 1, octets); 691 1.20 christos name[octets] = '\0'; 692 1.20 christos hname = name; 693 1.1 kardel } 694 1.1 kardel 695 1.1 kardel /* 696 1.1 kardel * First try to resolve it as an ip address and if that fails, 697 1.1 kardel * do a fullblown (dns) lookup. That way we only use the dns 698 1.1 kardel * when it is needed and work around some implementations that 699 1.1 kardel * will return an "IPv4-mapped IPv6 address" address if you 700 1.1 kardel * give it an IPv4 address to lookup. 701 1.1 kardel */ 702 1.4 kardel ZERO(hints); 703 1.9 christos hints.ai_family = fam; 704 1.1 kardel hints.ai_protocol = IPPROTO_UDP; 705 1.1 kardel hints.ai_socktype = SOCK_DGRAM; 706 1.4 kardel hints.ai_flags = Z_AI_NUMERICHOST; 707 1.9 christos ai = NULL; 708 1.1 kardel 709 1.9 christos a_info = getaddrinfo(hname, svc, &hints, &ai); 710 1.1 kardel if (a_info == EAI_NONAME 711 1.1 kardel #ifdef EAI_NODATA 712 1.1 kardel || a_info == EAI_NODATA 713 1.1 kardel #endif 714 1.1 kardel ) { 715 1.1 kardel hints.ai_flags = AI_CANONNAME; 716 1.1 kardel #ifdef AI_ADDRCONFIG 717 1.1 kardel hints.ai_flags |= AI_ADDRCONFIG; 718 1.1 kardel #endif 719 1.9 christos a_info = getaddrinfo(hname, svc, &hints, &ai); 720 1.1 kardel } 721 1.1 kardel #ifdef AI_ADDRCONFIG 722 1.23 christos /* 723 1.23 christos * Some older implementations don't like AI_ADDRCONFIG. 724 1.23 christos * Some versions of Windows return WSANO_DATA when there is no 725 1.23 christos * global address and AI_ADDRCONFIG is used. AI_ADDRCONFIG 726 1.23 christos * is useful to short-circuit DNS lookups for IP protocols 727 1.23 christos * for which the host has no local addresses. Windows 728 1.23 christos * unfortunately instead interprets AI_ADDRCONFIG to relate 729 1.23 christos * to off-host connectivity and so fails lookup when 730 1.23 christos * localhost works. 731 1.23 christos * To further muddy matters, some versions of WS2tcpip.h 732 1.23 christos * comment out #define EAI_NODATA WSANODATA claiming it 733 1.23 christos * was removed from RFC 2553bis and mentioning a need to 734 1.23 christos * contact the authors to find out why, but "helpfully" 735 1.23 christos * #defines EAI_NODATA EAI_NONAME (== WSAHOST_NOT_FOUND) 736 1.23 christos * So we get more ugly platform-specific workarounds. 737 1.23 christos */ 738 1.23 christos if ( 739 1.23 christos #if defined(WIN32) 740 1.23 christos WSANO_DATA == a_info || EAI_NONAME == a_info || 741 1.23 christos #endif 742 1.23 christos EAI_BADFLAGS == a_info) { 743 1.9 christos hints.ai_flags &= ~AI_ADDRCONFIG; 744 1.9 christos a_info = getaddrinfo(hname, svc, &hints, &ai); 745 1.1 kardel } 746 1.1 kardel #endif 747 1.1 kardel if (a_info != 0) { 748 1.9 christos fprintf(stderr, "%s\n", gai_strerror(a_info)); 749 1.1 kardel return 0; 750 1.1 kardel } 751 1.1 kardel 752 1.9 christos INSIST(ai != NULL); 753 1.9 christos ZERO(addr); 754 1.9 christos octets = min(sizeof(addr), ai->ai_addrlen); 755 1.9 christos memcpy(&addr, ai->ai_addr, octets); 756 1.9 christos 757 1.9 christos if (ai->ai_canonname == NULL) { 758 1.9 christos strlcpy(temphost, stoa(&addr), sizeof(temphost)); 759 1.4 kardel currenthostisnum = TRUE; 760 1.1 kardel } else { 761 1.9 christos strlcpy(temphost, ai->ai_canonname, sizeof(temphost)); 762 1.4 kardel currenthostisnum = FALSE; 763 1.1 kardel } 764 1.1 kardel 765 1.1 kardel if (debug > 2) 766 1.9 christos printf("Opening host %s (%s)\n", 767 1.9 christos temphost, 768 1.9 christos (ai->ai_family == AF_INET) 769 1.9 christos ? "AF_INET" 770 1.9 christos : (ai->ai_family == AF_INET6) 771 1.9 christos ? "AF_INET6" 772 1.9 christos : "AF-???" 773 1.9 christos ); 774 1.1 kardel 775 1.1 kardel if (havehost == 1) { 776 1.1 kardel if (debug > 2) 777 1.1 kardel printf("Closing old host %s\n", currenthost); 778 1.9 christos closesocket(sockfd); 779 1.1 kardel havehost = 0; 780 1.1 kardel } 781 1.9 christos strlcpy(currenthost, temphost, sizeof(currenthost)); 782 1.1 kardel 783 1.1 kardel /* port maps to the same location in both families */ 784 1.9 christos s_port = NSRCPORT(&addr); 785 1.1 kardel #ifdef SYS_VXWORKS 786 1.1 kardel ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); 787 1.1 kardel if (ai->ai_family == AF_INET) 788 1.1 kardel *(struct sockaddr_in *)&hostaddr= 789 1.1 kardel *((struct sockaddr_in *)ai->ai_addr); 790 1.1 kardel else 791 1.1 kardel *(struct sockaddr_in6 *)&hostaddr= 792 1.1 kardel *((struct sockaddr_in6 *)ai->ai_addr); 793 1.1 kardel #endif /* SYS_VXWORKS */ 794 1.1 kardel 795 1.1 kardel #ifdef SYS_WINNT 796 1.1 kardel { 797 1.1 kardel int optionValue = SO_SYNCHRONOUS_NONALERT; 798 1.1 kardel int err; 799 1.1 kardel 800 1.1 kardel err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 801 1.19 christos (void *)&optionValue, sizeof(optionValue)); 802 1.1 kardel if (err) { 803 1.9 christos mfprintf(stderr, 804 1.9 christos "setsockopt(SO_SYNCHRONOUS_NONALERT)" 805 1.9 christos " error: %m\n"); 806 1.9 christos freeaddrinfo(ai); 807 1.1 kardel exit(1); 808 1.1 kardel } 809 1.1 kardel } 810 1.1 kardel #endif /* SYS_WINNT */ 811 1.1 kardel 812 1.9 christos sockfd = socket(ai->ai_family, ai->ai_socktype, 813 1.9 christos ai->ai_protocol); 814 1.1 kardel if (sockfd == INVALID_SOCKET) { 815 1.3 christos error("socket"); 816 1.9 christos freeaddrinfo(ai); 817 1.9 christos return 0; 818 1.1 kardel } 819 1.1 kardel 820 1.9 christos 821 1.1 kardel #ifdef NEED_RCVBUF_SLOP 822 1.1 kardel # ifdef SO_RCVBUF 823 1.1 kardel { int rbufsize = DATASIZE + 2048; /* 2K for slop */ 824 1.1 kardel if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, 825 1.19 christos (void *)&rbufsize, sizeof(int)) == -1) 826 1.9 christos error("setsockopt"); 827 1.1 kardel } 828 1.1 kardel # endif 829 1.1 kardel #endif 830 1.1 kardel 831 1.9 christos if 832 1.1 kardel #ifdef SYS_VXWORKS 833 1.9 christos (connect(sockfd, (struct sockaddr *)&hostaddr, 834 1.1 kardel sizeof(hostaddr)) == -1) 835 1.1 kardel #else 836 1.9 christos (connect(sockfd, (struct sockaddr *)ai->ai_addr, 837 1.14 christos ai->ai_addrlen) == -1) 838 1.1 kardel #endif /* SYS_VXWORKS */ 839 1.14 christos { 840 1.9 christos error("connect"); 841 1.1 kardel freeaddrinfo(ai); 842 1.9 christos return 0; 843 1.9 christos } 844 1.9 christos freeaddrinfo(ai); 845 1.1 kardel havehost = 1; 846 1.9 christos numassoc = 0; 847 1.9 christos 848 1.1 kardel return 1; 849 1.1 kardel } 850 1.1 kardel 851 1.1 kardel 852 1.9 christos static void 853 1.9 christos dump_hex_printable( 854 1.9 christos const void * data, 855 1.9 christos size_t len 856 1.9 christos ) 857 1.9 christos { 858 1.18 christos /* every line shows at most 16 bytes, so we need a buffer of 859 1.18 christos * 4 * 16 (2 xdigits, 1 char, one sep for xdigits) 860 1.18 christos * + 2 * 1 (block separators) 861 1.18 christos * + <LF> + <NUL> 862 1.18 christos *--------------- 863 1.18 christos * 68 bytes 864 1.18 christos */ 865 1.18 christos static const char s_xdig[16] = "0123456789ABCDEF"; 866 1.18 christos 867 1.18 christos char lbuf[68]; 868 1.18 christos int ch, rowlen; 869 1.18 christos const u_char * cdata = data; 870 1.18 christos char *xptr, *pptr; 871 1.18 christos 872 1.18 christos while (len) { 873 1.18 christos memset(lbuf, ' ', sizeof(lbuf)); 874 1.18 christos xptr = lbuf; 875 1.18 christos pptr = lbuf + 3*16 + 2; 876 1.18 christos 877 1.18 christos rowlen = (len > 16) ? 16 : (int)len; 878 1.9 christos len -= rowlen; 879 1.23 christos 880 1.18 christos do { 881 1.18 christos ch = *cdata++; 882 1.23 christos 883 1.18 christos *xptr++ = s_xdig[ch >> 4 ]; 884 1.18 christos *xptr++ = s_xdig[ch & 0x0F]; 885 1.18 christos if (++xptr == lbuf + 3*8) 886 1.18 christos ++xptr; 887 1.18 christos 888 1.18 christos *pptr++ = isprint(ch) ? (char)ch : '.'; 889 1.18 christos } while (--rowlen); 890 1.18 christos 891 1.18 christos *pptr++ = '\n'; 892 1.18 christos *pptr = '\0'; 893 1.18 christos fputs(lbuf, stdout); 894 1.9 christos } 895 1.9 christos } 896 1.9 christos 897 1.9 christos 898 1.1 kardel /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */ 899 1.1 kardel /* 900 1.1 kardel * sendpkt - send a packet to the remote host 901 1.1 kardel */ 902 1.1 kardel static int 903 1.1 kardel sendpkt( 904 1.1 kardel void * xdata, 905 1.1 kardel size_t xdatalen 906 1.1 kardel ) 907 1.1 kardel { 908 1.1 kardel if (debug >= 3) 909 1.2 christos printf("Sending %zu octets\n", xdatalen); 910 1.1 kardel 911 1.14 christos if (send(sockfd, xdata, xdatalen, 0) == -1) { 912 1.3 christos warning("write to %s failed", currenthost); 913 1.1 kardel return -1; 914 1.1 kardel } 915 1.1 kardel 916 1.1 kardel if (debug >= 4) { 917 1.9 christos printf("Request packet:\n"); 918 1.9 christos dump_hex_printable(xdata, xdatalen); 919 1.1 kardel } 920 1.1 kardel return 0; 921 1.1 kardel } 922 1.1 kardel 923 1.1 kardel /* 924 1.1 kardel * getresponse - get a (series of) response packet(s) and return the data 925 1.1 kardel */ 926 1.1 kardel static int 927 1.1 kardel getresponse( 928 1.1 kardel int opcode, 929 1.1 kardel int associd, 930 1.1 kardel u_short *rstatus, 931 1.14 christos size_t *rsize, 932 1.4 kardel const char **rdata, 933 1.1 kardel int timeo 934 1.1 kardel ) 935 1.1 kardel { 936 1.1 kardel struct ntp_control rpkt; 937 1.1 kardel struct sock_timeval tvo; 938 1.1 kardel u_short offsets[MAXFRAGS+1]; 939 1.1 kardel u_short counts[MAXFRAGS+1]; 940 1.1 kardel u_short offset; 941 1.1 kardel u_short count; 942 1.4 kardel size_t numfrags; 943 1.4 kardel size_t f; 944 1.4 kardel size_t ff; 945 1.1 kardel int seenlastfrag; 946 1.1 kardel int shouldbesize; 947 1.1 kardel fd_set fds; 948 1.1 kardel int n; 949 1.9 christos int errcode; 950 1.15 christos /* absolute timeout checks. Not 'time_t' by intention! */ 951 1.15 christos uint32_t tobase; /* base value for timeout */ 952 1.15 christos uint32_t tospan; /* timeout span (max delay) */ 953 1.15 christos uint32_t todiff; /* current delay */ 954 1.1 kardel 955 1.18 christos memset(offsets, 0, sizeof(offsets)); 956 1.18 christos memset(counts , 0, sizeof(counts )); 957 1.23 christos 958 1.1 kardel /* 959 1.1 kardel * This is pretty tricky. We may get between 1 and MAXFRAG packets 960 1.1 kardel * back in response to the request. We peel the data out of 961 1.1 kardel * each packet and collect it in one long block. When the last 962 1.1 kardel * packet in the sequence is received we'll know how much data we 963 1.1 kardel * should have had. Note we use one long time out, should reconsider. 964 1.1 kardel */ 965 1.1 kardel *rsize = 0; 966 1.1 kardel if (rstatus) 967 1.4 kardel *rstatus = 0; 968 1.1 kardel *rdata = (char *)pktdata; 969 1.1 kardel 970 1.1 kardel numfrags = 0; 971 1.1 kardel seenlastfrag = 0; 972 1.1 kardel 973 1.15 christos tobase = (uint32_t)time(NULL); 974 1.23 christos 975 1.1 kardel FD_ZERO(&fds); 976 1.1 kardel 977 1.1 kardel /* 978 1.1 kardel * Loop until we have an error or a complete response. Nearly all 979 1.4 kardel * code paths to loop again use continue. 980 1.1 kardel */ 981 1.1 kardel for (;;) { 982 1.1 kardel 983 1.1 kardel if (numfrags == 0) 984 1.4 kardel tvo = tvout; 985 1.1 kardel else 986 1.4 kardel tvo = tvsout; 987 1.15 christos tospan = (uint32_t)tvo.tv_sec + (tvo.tv_usec != 0); 988 1.9 christos 989 1.1 kardel FD_SET(sockfd, &fds); 990 1.14 christos n = select(sockfd+1, &fds, NULL, NULL, &tvo); 991 1.1 kardel if (n == -1) { 992 1.15 christos #if !defined(SYS_WINNT) && defined(EINTR) 993 1.15 christos /* Windows does not know about EINTR (until very 994 1.15 christos * recently) and the handling of console events 995 1.15 christos * is *very* different from POSIX/UNIX signal 996 1.15 christos * handling anyway. 997 1.15 christos * 998 1.15 christos * Under non-windows targets we map EINTR as 999 1.15 christos * 'last packet was received' and try to exit 1000 1.15 christos * the receive sequence. 1001 1.15 christos */ 1002 1.15 christos if (errno == EINTR) { 1003 1.15 christos seenlastfrag = 1; 1004 1.15 christos goto maybe_final; 1005 1.15 christos } 1006 1.15 christos #endif 1007 1.3 christos warning("select fails"); 1008 1.1 kardel return -1; 1009 1.1 kardel } 1010 1.15 christos 1011 1.15 christos /* 1012 1.15 christos * Check if this is already too late. Trash the data and 1013 1.15 christos * fake a timeout if this is so. 1014 1.15 christos */ 1015 1.15 christos todiff = (((uint32_t)time(NULL)) - tobase) & 0x7FFFFFFFu; 1016 1.15 christos if ((n > 0) && (todiff > tospan)) { 1017 1.15 christos n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 1018 1.18 christos n -= n; /* faked timeout return from 'select()', 1019 1.18 christos * execute RMW cycle on 'n' 1020 1.18 christos */ 1021 1.15 christos } 1022 1.23 christos 1023 1.18 christos if (n <= 0) { 1024 1.1 kardel /* 1025 1.1 kardel * Timed out. Return what we have 1026 1.1 kardel */ 1027 1.1 kardel if (numfrags == 0) { 1028 1.1 kardel if (timeo) 1029 1.4 kardel fprintf(stderr, 1030 1.4 kardel "%s: timed out, nothing received\n", 1031 1.4 kardel currenthost); 1032 1.1 kardel return ERR_TIMEOUT; 1033 1.1 kardel } 1034 1.4 kardel if (timeo) 1035 1.4 kardel fprintf(stderr, 1036 1.4 kardel "%s: timed out with incomplete data\n", 1037 1.4 kardel currenthost); 1038 1.4 kardel if (debug) { 1039 1.4 kardel fprintf(stderr, 1040 1.4 kardel "ERR_INCOMPLETE: Received fragments:\n"); 1041 1.4 kardel for (f = 0; f < numfrags; f++) 1042 1.4 kardel fprintf(stderr, 1043 1.9 christos "%2u: %5d %5d\t%3d octets\n", 1044 1.9 christos (u_int)f, offsets[f], 1045 1.4 kardel offsets[f] + 1046 1.4 kardel counts[f], 1047 1.4 kardel counts[f]); 1048 1.4 kardel fprintf(stderr, 1049 1.4 kardel "last fragment %sreceived\n", 1050 1.4 kardel (seenlastfrag) 1051 1.4 kardel ? "" 1052 1.4 kardel : "not "); 1053 1.4 kardel } 1054 1.4 kardel return ERR_INCOMPLETE; 1055 1.1 kardel } 1056 1.1 kardel 1057 1.1 kardel n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); 1058 1.18 christos if (n < 0) { 1059 1.3 christos warning("read"); 1060 1.1 kardel return -1; 1061 1.1 kardel } 1062 1.1 kardel 1063 1.1 kardel if (debug >= 4) { 1064 1.9 christos printf("Response packet:\n"); 1065 1.9 christos dump_hex_printable(&rpkt, n); 1066 1.1 kardel } 1067 1.1 kardel 1068 1.1 kardel /* 1069 1.1 kardel * Check for format errors. Bug proofing. 1070 1.1 kardel */ 1071 1.5 kardel if (n < (int)CTL_HEADER_LEN) { 1072 1.1 kardel if (debug) 1073 1.4 kardel printf("Short (%d byte) packet received\n", n); 1074 1.1 kardel continue; 1075 1.1 kardel } 1076 1.1 kardel if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION 1077 1.1 kardel || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { 1078 1.1 kardel if (debug) 1079 1.4 kardel printf("Packet received with version %d\n", 1080 1.4 kardel PKT_VERSION(rpkt.li_vn_mode)); 1081 1.1 kardel continue; 1082 1.1 kardel } 1083 1.1 kardel if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { 1084 1.1 kardel if (debug) 1085 1.4 kardel printf("Packet received with mode %d\n", 1086 1.4 kardel PKT_MODE(rpkt.li_vn_mode)); 1087 1.1 kardel continue; 1088 1.1 kardel } 1089 1.1 kardel if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { 1090 1.1 kardel if (debug) 1091 1.4 kardel printf("Received request packet, wanted response\n"); 1092 1.1 kardel continue; 1093 1.1 kardel } 1094 1.1 kardel 1095 1.1 kardel /* 1096 1.1 kardel * Check opcode and sequence number for a match. 1097 1.1 kardel * Could be old data getting to us. 1098 1.1 kardel */ 1099 1.1 kardel if (ntohs(rpkt.sequence) != sequence) { 1100 1.1 kardel if (debug) 1101 1.4 kardel printf("Received sequnce number %d, wanted %d\n", 1102 1.4 kardel ntohs(rpkt.sequence), sequence); 1103 1.1 kardel continue; 1104 1.1 kardel } 1105 1.1 kardel if (CTL_OP(rpkt.r_m_e_op) != opcode) { 1106 1.1 kardel if (debug) 1107 1.1 kardel printf( 1108 1.1 kardel "Received opcode %d, wanted %d (sequence number okay)\n", 1109 1.1 kardel CTL_OP(rpkt.r_m_e_op), opcode); 1110 1.1 kardel continue; 1111 1.1 kardel } 1112 1.1 kardel 1113 1.1 kardel /* 1114 1.1 kardel * Check the error code. If non-zero, return it. 1115 1.1 kardel */ 1116 1.1 kardel if (CTL_ISERROR(rpkt.r_m_e_op)) { 1117 1.1 kardel errcode = (ntohs(rpkt.status) >> 8) & 0xff; 1118 1.9 christos if (CTL_ISMORE(rpkt.r_m_e_op)) 1119 1.9 christos TRACE(1, ("Error code %d received on not-final packet\n", 1120 1.9 christos errcode)); 1121 1.1 kardel if (errcode == CERR_UNSPEC) 1122 1.9 christos return ERR_UNSPEC; 1123 1.1 kardel return errcode; 1124 1.1 kardel } 1125 1.1 kardel 1126 1.1 kardel /* 1127 1.1 kardel * Check the association ID to make sure it matches what 1128 1.1 kardel * we sent. 1129 1.1 kardel */ 1130 1.1 kardel if (ntohs(rpkt.associd) != associd) { 1131 1.9 christos TRACE(1, ("Association ID %d doesn't match expected %d\n", 1132 1.9 christos ntohs(rpkt.associd), associd)); 1133 1.1 kardel /* 1134 1.1 kardel * Hack for silly fuzzballs which, at the time of writing, 1135 1.1 kardel * return an assID of sys.peer when queried for system variables. 1136 1.1 kardel */ 1137 1.1 kardel #ifdef notdef 1138 1.1 kardel continue; 1139 1.1 kardel #endif 1140 1.1 kardel } 1141 1.1 kardel 1142 1.1 kardel /* 1143 1.1 kardel * Collect offset and count. Make sure they make sense. 1144 1.1 kardel */ 1145 1.1 kardel offset = ntohs(rpkt.offset); 1146 1.1 kardel count = ntohs(rpkt.count); 1147 1.1 kardel 1148 1.1 kardel /* 1149 1.1 kardel * validate received payload size is padded to next 32-bit 1150 1.1 kardel * boundary and no smaller than claimed by rpkt.count 1151 1.1 kardel */ 1152 1.1 kardel if (n & 0x3) { 1153 1.9 christos TRACE(1, ("Response packet not padded, size = %d\n", 1154 1.9 christos n)); 1155 1.1 kardel continue; 1156 1.1 kardel } 1157 1.1 kardel 1158 1.1 kardel shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3; 1159 1.1 kardel 1160 1.1 kardel if (n < shouldbesize) { 1161 1.9 christos printf("Response packet claims %u octets payload, above %ld received\n", 1162 1.16 christos count, (long)(n - CTL_HEADER_LEN)); 1163 1.1 kardel return ERR_INCOMPLETE; 1164 1.1 kardel } 1165 1.1 kardel 1166 1.1 kardel if (debug >= 3 && shouldbesize > n) { 1167 1.1 kardel u_int32 key; 1168 1.1 kardel u_int32 *lpkt; 1169 1.1 kardel int maclen; 1170 1.1 kardel 1171 1.1 kardel /* 1172 1.1 kardel * Usually we ignore authentication, but for debugging purposes 1173 1.1 kardel * we watch it here. 1174 1.1 kardel */ 1175 1.1 kardel /* round to 8 octet boundary */ 1176 1.1 kardel shouldbesize = (shouldbesize + 7) & ~7; 1177 1.1 kardel 1178 1.1 kardel maclen = n - shouldbesize; 1179 1.2 christos if (maclen >= (int)MIN_MAC_LEN) { 1180 1.1 kardel printf( 1181 1.1 kardel "Packet shows signs of authentication (total %d, data %d, mac %d)\n", 1182 1.1 kardel n, shouldbesize, maclen); 1183 1.1 kardel lpkt = (u_int32 *)&rpkt; 1184 1.1 kardel printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", 1185 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]), 1186 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]), 1187 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]), 1188 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]), 1189 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]), 1190 1.1 kardel (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2])); 1191 1.1 kardel key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]); 1192 1.1 kardel printf("Authenticated with keyid %lu\n", (u_long)key); 1193 1.1 kardel if (key != 0 && key != info_auth_keyid) { 1194 1.1 kardel printf("We don't know that key\n"); 1195 1.1 kardel } else { 1196 1.1 kardel if (authdecrypt(key, (u_int32 *)&rpkt, 1197 1.1 kardel n - maclen, maclen)) { 1198 1.1 kardel printf("Auth okay!\n"); 1199 1.1 kardel } else { 1200 1.1 kardel printf("Auth failed!\n"); 1201 1.1 kardel } 1202 1.1 kardel } 1203 1.1 kardel } 1204 1.1 kardel } 1205 1.1 kardel 1206 1.9 christos TRACE(2, ("Got packet, size = %d\n", n)); 1207 1.9 christos if (count > (n - CTL_HEADER_LEN)) { 1208 1.9 christos TRACE(1, ("Received count of %u octets, data in packet is %ld\n", 1209 1.9 christos count, (long)n - CTL_HEADER_LEN)); 1210 1.1 kardel continue; 1211 1.1 kardel } 1212 1.1 kardel if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { 1213 1.9 christos TRACE(1, ("Received count of 0 in non-final fragment\n")); 1214 1.1 kardel continue; 1215 1.1 kardel } 1216 1.1 kardel if (offset + count > sizeof(pktdata)) { 1217 1.9 christos TRACE(1, ("Offset %u, count %u, too big for buffer\n", 1218 1.9 christos offset, count)); 1219 1.1 kardel return ERR_TOOMUCH; 1220 1.1 kardel } 1221 1.1 kardel if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { 1222 1.9 christos TRACE(1, ("Received second last fragment packet\n")); 1223 1.1 kardel continue; 1224 1.1 kardel } 1225 1.1 kardel 1226 1.1 kardel /* 1227 1.1 kardel * So far, so good. Record this fragment, making sure it doesn't 1228 1.1 kardel * overlap anything. 1229 1.1 kardel */ 1230 1.9 christos TRACE(2, ("Packet okay\n")); 1231 1.1 kardel 1232 1.1 kardel if (numfrags > (MAXFRAGS - 1)) { 1233 1.9 christos TRACE(2, ("Number of fragments exceeds maximum %d\n", 1234 1.9 christos MAXFRAGS - 1)); 1235 1.1 kardel return ERR_TOOMUCH; 1236 1.1 kardel } 1237 1.1 kardel 1238 1.1 kardel /* 1239 1.1 kardel * Find the position for the fragment relative to any 1240 1.1 kardel * previously received. 1241 1.1 kardel */ 1242 1.9 christos for (f = 0; 1243 1.9 christos f < numfrags && offsets[f] < offset; 1244 1.4 kardel f++) { 1245 1.1 kardel /* empty body */ ; 1246 1.1 kardel } 1247 1.1 kardel 1248 1.4 kardel if (f < numfrags && offset == offsets[f]) { 1249 1.9 christos TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n", 1250 1.9 christos count, offset, counts[f], offsets[f])); 1251 1.1 kardel continue; 1252 1.1 kardel } 1253 1.1 kardel 1254 1.4 kardel if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) { 1255 1.9 christos TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n", 1256 1.9 christos offset, counts[f-1], offsets[f-1])); 1257 1.1 kardel continue; 1258 1.1 kardel } 1259 1.1 kardel 1260 1.4 kardel if (f < numfrags && (offset + count) > offsets[f]) { 1261 1.9 christos TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n", 1262 1.9 christos count, offset, offsets[f])); 1263 1.1 kardel continue; 1264 1.1 kardel } 1265 1.1 kardel 1266 1.4 kardel for (ff = numfrags; ff > f; ff--) { 1267 1.4 kardel offsets[ff] = offsets[ff-1]; 1268 1.4 kardel counts[ff] = counts[ff-1]; 1269 1.1 kardel } 1270 1.4 kardel offsets[f] = offset; 1271 1.4 kardel counts[f] = count; 1272 1.1 kardel numfrags++; 1273 1.1 kardel 1274 1.1 kardel /* 1275 1.1 kardel * Got that stuffed in right. Figure out if this was the last. 1276 1.1 kardel * Record status info out of the last packet. 1277 1.1 kardel */ 1278 1.1 kardel if (!CTL_ISMORE(rpkt.r_m_e_op)) { 1279 1.1 kardel seenlastfrag = 1; 1280 1.1 kardel if (rstatus != 0) 1281 1.4 kardel *rstatus = ntohs(rpkt.status); 1282 1.1 kardel } 1283 1.1 kardel 1284 1.1 kardel /* 1285 1.15 christos * Copy the data into the data buffer, and bump the 1286 1.15 christos * timout base in case we need more. 1287 1.1 kardel */ 1288 1.9 christos memcpy((char *)pktdata + offset, &rpkt.u, count); 1289 1.15 christos tobase = (uint32_t)time(NULL); 1290 1.23 christos 1291 1.1 kardel /* 1292 1.1 kardel * If we've seen the last fragment, look for holes in the sequence. 1293 1.1 kardel * If there aren't any, we're done. 1294 1.1 kardel */ 1295 1.16 christos #if !defined(SYS_WINNT) && defined(EINTR) 1296 1.16 christos maybe_final: 1297 1.16 christos #endif 1298 1.16 christos 1299 1.1 kardel if (seenlastfrag && offsets[0] == 0) { 1300 1.4 kardel for (f = 1; f < numfrags; f++) 1301 1.4 kardel if (offsets[f-1] + counts[f-1] != 1302 1.4 kardel offsets[f]) 1303 1.1 kardel break; 1304 1.4 kardel if (f == numfrags) { 1305 1.4 kardel *rsize = offsets[f-1] + counts[f-1]; 1306 1.9 christos TRACE(1, ("%lu packets reassembled into response\n", 1307 1.9 christos (u_long)numfrags)); 1308 1.1 kardel return 0; 1309 1.1 kardel } 1310 1.1 kardel } 1311 1.1 kardel } /* giant for (;;) collecting response packets */ 1312 1.1 kardel } /* getresponse() */ 1313 1.1 kardel 1314 1.1 kardel 1315 1.1 kardel /* 1316 1.1 kardel * sendrequest - format and send a request packet 1317 1.1 kardel */ 1318 1.1 kardel static int 1319 1.1 kardel sendrequest( 1320 1.1 kardel int opcode, 1321 1.9 christos associd_t associd, 1322 1.1 kardel int auth, 1323 1.14 christos size_t qsize, 1324 1.9 christos const char *qdata 1325 1.1 kardel ) 1326 1.1 kardel { 1327 1.1 kardel struct ntp_control qpkt; 1328 1.14 christos size_t pktsize; 1329 1.1 kardel u_long key_id; 1330 1.1 kardel char * pass; 1331 1.14 christos size_t maclen; 1332 1.1 kardel 1333 1.1 kardel /* 1334 1.1 kardel * Check to make sure the data will fit in one packet 1335 1.1 kardel */ 1336 1.1 kardel if (qsize > CTL_MAX_DATA_LEN) { 1337 1.1 kardel fprintf(stderr, 1338 1.14 christos "***Internal error! qsize (%zu) too large\n", 1339 1.1 kardel qsize); 1340 1.1 kardel return 1; 1341 1.1 kardel } 1342 1.1 kardel 1343 1.1 kardel /* 1344 1.1 kardel * Fill in the packet 1345 1.1 kardel */ 1346 1.1 kardel qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); 1347 1.1 kardel qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); 1348 1.1 kardel qpkt.sequence = htons(sequence); 1349 1.1 kardel qpkt.status = 0; 1350 1.1 kardel qpkt.associd = htons((u_short)associd); 1351 1.1 kardel qpkt.offset = 0; 1352 1.1 kardel qpkt.count = htons((u_short)qsize); 1353 1.1 kardel 1354 1.1 kardel pktsize = CTL_HEADER_LEN; 1355 1.1 kardel 1356 1.1 kardel /* 1357 1.1 kardel * If we have data, copy and pad it out to a 32-bit boundary. 1358 1.1 kardel */ 1359 1.1 kardel if (qsize > 0) { 1360 1.9 christos memcpy(&qpkt.u, qdata, (size_t)qsize); 1361 1.1 kardel pktsize += qsize; 1362 1.1 kardel while (pktsize & (sizeof(u_int32) - 1)) { 1363 1.9 christos qpkt.u.data[qsize++] = 0; 1364 1.1 kardel pktsize++; 1365 1.1 kardel } 1366 1.1 kardel } 1367 1.1 kardel 1368 1.1 kardel /* 1369 1.1 kardel * If it isn't authenticated we can just send it. Otherwise 1370 1.1 kardel * we're going to have to think about it a little. 1371 1.1 kardel */ 1372 1.1 kardel if (!auth && !always_auth) { 1373 1.1 kardel return sendpkt(&qpkt, pktsize); 1374 1.9 christos } 1375 1.1 kardel 1376 1.1 kardel /* 1377 1.1 kardel * Pad out packet to a multiple of 8 octets to be sure 1378 1.1 kardel * receiver can handle it. 1379 1.1 kardel */ 1380 1.1 kardel while (pktsize & 7) { 1381 1.9 christos qpkt.u.data[qsize++] = 0; 1382 1.1 kardel pktsize++; 1383 1.1 kardel } 1384 1.1 kardel 1385 1.1 kardel /* 1386 1.1 kardel * Get the keyid and the password if we don't have one. 1387 1.1 kardel */ 1388 1.1 kardel if (info_auth_keyid == 0) { 1389 1.1 kardel key_id = getkeyid("Keyid: "); 1390 1.1 kardel if (key_id == 0 || key_id > NTP_MAXKEY) { 1391 1.9 christos fprintf(stderr, 1392 1.1 kardel "Invalid key identifier\n"); 1393 1.1 kardel return 1; 1394 1.1 kardel } 1395 1.1 kardel info_auth_keyid = key_id; 1396 1.1 kardel } 1397 1.1 kardel if (!authistrusted(info_auth_keyid)) { 1398 1.4 kardel pass = getpass_keytype(info_auth_keytype); 1399 1.1 kardel if ('\0' == pass[0]) { 1400 1.1 kardel fprintf(stderr, "Invalid password\n"); 1401 1.1 kardel return 1; 1402 1.1 kardel } 1403 1.1 kardel authusekey(info_auth_keyid, info_auth_keytype, 1404 1.1 kardel (u_char *)pass); 1405 1.1 kardel authtrust(info_auth_keyid, 1); 1406 1.1 kardel } 1407 1.1 kardel 1408 1.1 kardel /* 1409 1.1 kardel * Do the encryption. 1410 1.1 kardel */ 1411 1.1 kardel maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize); 1412 1.9 christos if (!maclen) { 1413 1.1 kardel fprintf(stderr, "Key not found\n"); 1414 1.1 kardel return 1; 1415 1.1 kardel } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) { 1416 1.1 kardel fprintf(stderr, 1417 1.14 christos "%zu octet MAC, %zu expected with %zu octet digest\n", 1418 1.1 kardel maclen, (info_auth_hashlen + sizeof(keyid_t)), 1419 1.1 kardel info_auth_hashlen); 1420 1.1 kardel return 1; 1421 1.1 kardel } 1422 1.9 christos 1423 1.1 kardel return sendpkt((char *)&qpkt, pktsize + maclen); 1424 1.1 kardel } 1425 1.1 kardel 1426 1.1 kardel 1427 1.1 kardel /* 1428 1.4 kardel * show_error_msg - display the error text for a mode 6 error response. 1429 1.4 kardel */ 1430 1.4 kardel void 1431 1.4 kardel show_error_msg( 1432 1.4 kardel int m6resp, 1433 1.4 kardel associd_t associd 1434 1.4 kardel ) 1435 1.4 kardel { 1436 1.4 kardel if (numhosts > 1) 1437 1.4 kardel fprintf(stderr, "server=%s ", currenthost); 1438 1.4 kardel 1439 1.15 christos switch (m6resp) { 1440 1.4 kardel 1441 1.4 kardel case CERR_BADFMT: 1442 1.4 kardel fprintf(stderr, 1443 1.4 kardel "***Server reports a bad format request packet\n"); 1444 1.4 kardel break; 1445 1.4 kardel 1446 1.4 kardel case CERR_PERMISSION: 1447 1.4 kardel fprintf(stderr, 1448 1.4 kardel "***Server disallowed request (authentication?)\n"); 1449 1.4 kardel break; 1450 1.4 kardel 1451 1.4 kardel case CERR_BADOP: 1452 1.4 kardel fprintf(stderr, 1453 1.4 kardel "***Server reports a bad opcode in request\n"); 1454 1.4 kardel break; 1455 1.4 kardel 1456 1.4 kardel case CERR_BADASSOC: 1457 1.4 kardel fprintf(stderr, 1458 1.4 kardel "***Association ID %d unknown to server\n", 1459 1.4 kardel associd); 1460 1.4 kardel break; 1461 1.4 kardel 1462 1.4 kardel case CERR_UNKNOWNVAR: 1463 1.4 kardel fprintf(stderr, 1464 1.4 kardel "***A request variable unknown to the server\n"); 1465 1.4 kardel break; 1466 1.4 kardel 1467 1.4 kardel case CERR_BADVALUE: 1468 1.4 kardel fprintf(stderr, 1469 1.4 kardel "***Server indicates a request variable was bad\n"); 1470 1.4 kardel break; 1471 1.4 kardel 1472 1.4 kardel case ERR_UNSPEC: 1473 1.4 kardel fprintf(stderr, 1474 1.4 kardel "***Server returned an unspecified error\n"); 1475 1.4 kardel break; 1476 1.4 kardel 1477 1.4 kardel case ERR_TIMEOUT: 1478 1.4 kardel fprintf(stderr, "***Request timed out\n"); 1479 1.4 kardel break; 1480 1.4 kardel 1481 1.4 kardel case ERR_INCOMPLETE: 1482 1.4 kardel fprintf(stderr, 1483 1.4 kardel "***Response from server was incomplete\n"); 1484 1.4 kardel break; 1485 1.4 kardel 1486 1.4 kardel case ERR_TOOMUCH: 1487 1.4 kardel fprintf(stderr, 1488 1.4 kardel "***Buffer size exceeded for returned data\n"); 1489 1.4 kardel break; 1490 1.4 kardel 1491 1.4 kardel default: 1492 1.4 kardel fprintf(stderr, 1493 1.4 kardel "***Server returns unknown error code %d\n", 1494 1.4 kardel m6resp); 1495 1.4 kardel } 1496 1.4 kardel } 1497 1.4 kardel 1498 1.4 kardel /* 1499 1.4 kardel * doquery - send a request and process the response, displaying 1500 1.4 kardel * error messages for any error responses. 1501 1.1 kardel */ 1502 1.1 kardel int 1503 1.1 kardel doquery( 1504 1.1 kardel int opcode, 1505 1.4 kardel associd_t associd, 1506 1.4 kardel int auth, 1507 1.14 christos size_t qsize, 1508 1.9 christos const char *qdata, 1509 1.4 kardel u_short *rstatus, 1510 1.14 christos size_t *rsize, 1511 1.4 kardel const char **rdata 1512 1.4 kardel ) 1513 1.4 kardel { 1514 1.4 kardel return doqueryex(opcode, associd, auth, qsize, qdata, rstatus, 1515 1.4 kardel rsize, rdata, FALSE); 1516 1.4 kardel } 1517 1.4 kardel 1518 1.4 kardel 1519 1.4 kardel /* 1520 1.4 kardel * doqueryex - send a request and process the response, optionally 1521 1.4 kardel * displaying error messages for any error responses. 1522 1.4 kardel */ 1523 1.4 kardel int 1524 1.4 kardel doqueryex( 1525 1.4 kardel int opcode, 1526 1.4 kardel associd_t associd, 1527 1.1 kardel int auth, 1528 1.14 christos size_t qsize, 1529 1.9 christos const char *qdata, 1530 1.1 kardel u_short *rstatus, 1531 1.14 christos size_t *rsize, 1532 1.4 kardel const char **rdata, 1533 1.4 kardel int quiet 1534 1.1 kardel ) 1535 1.1 kardel { 1536 1.1 kardel int res; 1537 1.1 kardel int done; 1538 1.1 kardel 1539 1.1 kardel /* 1540 1.1 kardel * Check to make sure host is open 1541 1.1 kardel */ 1542 1.1 kardel if (!havehost) { 1543 1.4 kardel fprintf(stderr, "***No host open, use `host' command\n"); 1544 1.1 kardel return -1; 1545 1.1 kardel } 1546 1.1 kardel 1547 1.1 kardel done = 0; 1548 1.1 kardel sequence++; 1549 1.1 kardel 1550 1.1 kardel again: 1551 1.1 kardel /* 1552 1.1 kardel * send a request 1553 1.1 kardel */ 1554 1.1 kardel res = sendrequest(opcode, associd, auth, qsize, qdata); 1555 1.1 kardel if (res != 0) 1556 1.4 kardel return res; 1557 1.9 christos 1558 1.1 kardel /* 1559 1.1 kardel * Get the response. If we got a standard error, print a message 1560 1.1 kardel */ 1561 1.1 kardel res = getresponse(opcode, associd, rstatus, rsize, rdata, done); 1562 1.1 kardel 1563 1.1 kardel if (res > 0) { 1564 1.1 kardel if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) { 1565 1.1 kardel if (res == ERR_INCOMPLETE) { 1566 1.1 kardel /* 1567 1.1 kardel * better bump the sequence so we don't 1568 1.1 kardel * get confused about differing fragments. 1569 1.1 kardel */ 1570 1.1 kardel sequence++; 1571 1.1 kardel } 1572 1.1 kardel done = 1; 1573 1.1 kardel goto again; 1574 1.1 kardel } 1575 1.4 kardel if (!quiet) 1576 1.4 kardel show_error_msg(res, associd); 1577 1.4 kardel 1578 1.1 kardel } 1579 1.1 kardel return res; 1580 1.1 kardel } 1581 1.1 kardel 1582 1.1 kardel 1583 1.1 kardel #ifndef BUILD_AS_LIB 1584 1.1 kardel /* 1585 1.1 kardel * getcmds - read commands from the standard input and execute them 1586 1.1 kardel */ 1587 1.1 kardel static void 1588 1.1 kardel getcmds(void) 1589 1.1 kardel { 1590 1.1 kardel char * line; 1591 1.1 kardel int count; 1592 1.1 kardel 1593 1.1 kardel ntp_readline_init(interactive ? prompt : NULL); 1594 1.1 kardel 1595 1.1 kardel for (;;) { 1596 1.1 kardel line = ntp_readline(&count); 1597 1.1 kardel if (NULL == line) 1598 1.1 kardel break; 1599 1.1 kardel docmd(line); 1600 1.1 kardel free(line); 1601 1.1 kardel } 1602 1.1 kardel 1603 1.1 kardel ntp_readline_uninit(); 1604 1.1 kardel } 1605 1.1 kardel #endif /* !BUILD_AS_LIB */ 1606 1.1 kardel 1607 1.1 kardel 1608 1.1 kardel #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB) 1609 1.1 kardel /* 1610 1.1 kardel * abortcmd - catch interrupts and abort the current command 1611 1.1 kardel */ 1612 1.14 christos static int 1613 1.14 christos abortcmd(void) 1614 1.1 kardel { 1615 1.1 kardel if (current_output == stdout) 1616 1.14 christos (void) fflush(stdout); 1617 1.1 kardel putc('\n', stderr); 1618 1.1 kardel (void) fflush(stderr); 1619 1.14 christos if (jump) { 1620 1.14 christos jump = 0; 1621 1.20 christos LONGJMP(interrupt_buf, 1); 1622 1.14 christos } 1623 1.14 christos return TRUE; 1624 1.1 kardel } 1625 1.1 kardel #endif /* !SYS_WINNT && !BUILD_AS_LIB */ 1626 1.1 kardel 1627 1.1 kardel 1628 1.1 kardel #ifndef BUILD_AS_LIB 1629 1.1 kardel /* 1630 1.1 kardel * docmd - decode the command line and execute a command 1631 1.1 kardel */ 1632 1.1 kardel static void 1633 1.1 kardel docmd( 1634 1.1 kardel const char *cmdline 1635 1.1 kardel ) 1636 1.1 kardel { 1637 1.1 kardel char *tokens[1+MAXARGS+2]; 1638 1.1 kardel struct parse pcmd; 1639 1.1 kardel int ntok; 1640 1.1 kardel static int i; 1641 1.1 kardel struct xcmd *xcmd; 1642 1.23 christos int executeonly = 0; 1643 1.1 kardel 1644 1.1 kardel /* 1645 1.1 kardel * Tokenize the command line. If nothing on it, return. 1646 1.1 kardel */ 1647 1.1 kardel tokenize(cmdline, tokens, &ntok); 1648 1.1 kardel if (ntok == 0) 1649 1.1 kardel return; 1650 1.9 christos 1651 1.1 kardel /* 1652 1.23 christos * If command prefixed by '~', then quiet output 1653 1.23 christos */ 1654 1.23 christos if (*tokens[0] == '~') { 1655 1.23 christos executeonly++; 1656 1.23 christos tokens[0]++; 1657 1.23 christos } 1658 1.23 christos 1659 1.23 christos /* 1660 1.1 kardel * Find the appropriate command description. 1661 1.1 kardel */ 1662 1.1 kardel i = findcmd(tokens[0], builtins, opcmds, &xcmd); 1663 1.1 kardel if (i == 0) { 1664 1.1 kardel (void) fprintf(stderr, "***Command `%s' unknown\n", 1665 1.1 kardel tokens[0]); 1666 1.1 kardel return; 1667 1.1 kardel } else if (i >= 2) { 1668 1.1 kardel (void) fprintf(stderr, "***Command `%s' ambiguous\n", 1669 1.1 kardel tokens[0]); 1670 1.1 kardel return; 1671 1.1 kardel } 1672 1.9 christos 1673 1.9 christos /* Warn about ignored extra args */ 1674 1.9 christos for (i = MAXARGS + 1; i < ntok ; ++i) { 1675 1.9 christos fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]); 1676 1.9 christos } 1677 1.9 christos 1678 1.1 kardel /* 1679 1.1 kardel * Save the keyword, then walk through the arguments, interpreting 1680 1.1 kardel * as we go. 1681 1.1 kardel */ 1682 1.1 kardel pcmd.keyword = tokens[0]; 1683 1.1 kardel pcmd.nargs = 0; 1684 1.1 kardel for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) { 1685 1.1 kardel if ((i+1) >= ntok) { 1686 1.1 kardel if (!(xcmd->arg[i] & OPT)) { 1687 1.1 kardel printusage(xcmd, stderr); 1688 1.1 kardel return; 1689 1.1 kardel } 1690 1.1 kardel break; 1691 1.1 kardel } 1692 1.1 kardel if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>')) 1693 1.1 kardel break; 1694 1.1 kardel if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i])) 1695 1.1 kardel return; 1696 1.1 kardel pcmd.nargs++; 1697 1.1 kardel } 1698 1.1 kardel 1699 1.1 kardel i++; 1700 1.1 kardel if (i < ntok && *tokens[i] == '>') { 1701 1.1 kardel char *fname; 1702 1.1 kardel 1703 1.1 kardel if (*(tokens[i]+1) != '\0') 1704 1.1 kardel fname = tokens[i]+1; 1705 1.1 kardel else if ((i+1) < ntok) 1706 1.1 kardel fname = tokens[i+1]; 1707 1.1 kardel else { 1708 1.1 kardel (void) fprintf(stderr, "***No file for redirect\n"); 1709 1.1 kardel return; 1710 1.1 kardel } 1711 1.1 kardel 1712 1.1 kardel current_output = fopen(fname, "w"); 1713 1.1 kardel if (current_output == NULL) { 1714 1.1 kardel (void) fprintf(stderr, "***Error opening %s: ", fname); 1715 1.1 kardel perror(""); 1716 1.1 kardel return; 1717 1.1 kardel } 1718 1.23 christos } else if (executeonly) { /* Redirect all output to null */ 1719 1.23 christos current_output = fopen(PATH_DEVNULL, "w"); 1720 1.23 christos if (current_output == NULL) { 1721 1.23 christos (void) fprintf(stderr, "***Error redirecting output to /dev/null: "); 1722 1.23 christos perror(""); 1723 1.23 christos return; 1724 1.23 christos } 1725 1.1 kardel } else { 1726 1.1 kardel current_output = stdout; 1727 1.1 kardel } 1728 1.1 kardel 1729 1.20 christos if (interactive) { 1730 1.20 christos if ( ! SETJMP(interrupt_buf)) { 1731 1.20 christos jump = 1; 1732 1.20 christos (xcmd->handler)(&pcmd, current_output); 1733 1.20 christos jump = 0; 1734 1.20 christos } else { 1735 1.20 christos fflush(current_output); 1736 1.20 christos fputs("\n >>> command aborted <<<\n", stderr); 1737 1.20 christos fflush(stderr); 1738 1.20 christos } 1739 1.20 christos 1740 1.20 christos } else { 1741 1.1 kardel jump = 0; 1742 1.1 kardel (xcmd->handler)(&pcmd, current_output); 1743 1.1 kardel } 1744 1.20 christos if ((NULL != current_output) && (stdout != current_output)) { 1745 1.20 christos (void)fclose(current_output); 1746 1.20 christos current_output = NULL; 1747 1.20 christos } 1748 1.1 kardel } 1749 1.1 kardel 1750 1.1 kardel 1751 1.1 kardel /* 1752 1.1 kardel * tokenize - turn a command line into tokens 1753 1.1 kardel * 1754 1.9 christos * SK: Modified to allow a quoted string 1755 1.1 kardel * 1756 1.1 kardel * HMS: If the first character of the first token is a ':' then (after 1757 1.1 kardel * eating inter-token whitespace) the 2nd token is the rest of the line. 1758 1.1 kardel */ 1759 1.1 kardel 1760 1.1 kardel static void 1761 1.1 kardel tokenize( 1762 1.1 kardel const char *line, 1763 1.1 kardel char **tokens, 1764 1.1 kardel int *ntok 1765 1.1 kardel ) 1766 1.1 kardel { 1767 1.1 kardel register const char *cp; 1768 1.1 kardel register char *sp; 1769 1.1 kardel static char tspace[MAXLINE]; 1770 1.1 kardel 1771 1.1 kardel sp = tspace; 1772 1.1 kardel cp = line; 1773 1.1 kardel for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) { 1774 1.1 kardel tokens[*ntok] = sp; 1775 1.1 kardel 1776 1.1 kardel /* Skip inter-token whitespace */ 1777 1.1 kardel while (ISSPACE(*cp)) 1778 1.1 kardel cp++; 1779 1.1 kardel 1780 1.1 kardel /* If we're at EOL we're done */ 1781 1.1 kardel if (ISEOL(*cp)) 1782 1.1 kardel break; 1783 1.1 kardel 1784 1.1 kardel /* If this is the 2nd token and the first token begins 1785 1.1 kardel * with a ':', then just grab to EOL. 1786 1.1 kardel */ 1787 1.1 kardel 1788 1.1 kardel if (*ntok == 1 && tokens[0][0] == ':') { 1789 1.1 kardel do { 1790 1.10 christos if (sp - tspace >= MAXLINE) 1791 1.10 christos goto toobig; 1792 1.1 kardel *sp++ = *cp++; 1793 1.1 kardel } while (!ISEOL(*cp)); 1794 1.1 kardel } 1795 1.1 kardel 1796 1.1 kardel /* Check if this token begins with a double quote. 1797 1.1 kardel * If yes, continue reading till the next double quote 1798 1.1 kardel */ 1799 1.1 kardel else if (*cp == '\"') { 1800 1.1 kardel ++cp; 1801 1.1 kardel do { 1802 1.10 christos if (sp - tspace >= MAXLINE) 1803 1.10 christos goto toobig; 1804 1.1 kardel *sp++ = *cp++; 1805 1.1 kardel } while ((*cp != '\"') && !ISEOL(*cp)); 1806 1.1 kardel /* HMS: a missing closing " should be an error */ 1807 1.1 kardel } 1808 1.1 kardel else { 1809 1.1 kardel do { 1810 1.10 christos if (sp - tspace >= MAXLINE) 1811 1.10 christos goto toobig; 1812 1.1 kardel *sp++ = *cp++; 1813 1.1 kardel } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp)); 1814 1.1 kardel /* HMS: Why check for a " in the previous line? */ 1815 1.1 kardel } 1816 1.1 kardel 1817 1.10 christos if (sp - tspace >= MAXLINE) 1818 1.10 christos goto toobig; 1819 1.1 kardel *sp++ = '\0'; 1820 1.1 kardel } 1821 1.10 christos return; 1822 1.10 christos 1823 1.10 christos toobig: 1824 1.10 christos *ntok = 0; 1825 1.10 christos fprintf(stderr, 1826 1.10 christos "***Line `%s' is too big\n", 1827 1.10 christos line); 1828 1.10 christos return; 1829 1.1 kardel } 1830 1.1 kardel 1831 1.1 kardel 1832 1.1 kardel /* 1833 1.1 kardel * getarg - interpret an argument token 1834 1.1 kardel */ 1835 1.1 kardel static int 1836 1.1 kardel getarg( 1837 1.9 christos const char *str, 1838 1.1 kardel int code, 1839 1.1 kardel arg_v *argp 1840 1.1 kardel ) 1841 1.1 kardel { 1842 1.9 christos u_long ul; 1843 1.1 kardel 1844 1.1 kardel switch (code & ~OPT) { 1845 1.9 christos case NTP_STR: 1846 1.1 kardel argp->string = str; 1847 1.1 kardel break; 1848 1.9 christos 1849 1.9 christos case NTP_ADD: 1850 1.9 christos if (!getnetnum(str, &argp->netnum, NULL, 0)) 1851 1.1 kardel return 0; 1852 1.1 kardel break; 1853 1.9 christos 1854 1.9 christos case NTP_UINT: 1855 1.9 christos if ('&' == str[0]) { 1856 1.9 christos if (!atouint(&str[1], &ul)) { 1857 1.9 christos fprintf(stderr, 1858 1.9 christos "***Association index `%s' invalid/undecodable\n", 1859 1.9 christos str); 1860 1.1 kardel return 0; 1861 1.1 kardel } 1862 1.9 christos if (0 == numassoc) { 1863 1.9 christos dogetassoc(stdout); 1864 1.9 christos if (0 == numassoc) { 1865 1.9 christos fprintf(stderr, 1866 1.9 christos "***No associations found, `%s' unknown\n", 1867 1.9 christos str); 1868 1.1 kardel return 0; 1869 1.1 kardel } 1870 1.1 kardel } 1871 1.9 christos ul = min(ul, numassoc); 1872 1.9 christos argp->uval = assoc_cache[ul - 1].assid; 1873 1.1 kardel break; 1874 1.1 kardel } 1875 1.9 christos if (!atouint(str, &argp->uval)) { 1876 1.9 christos fprintf(stderr, "***Illegal unsigned value %s\n", 1877 1.9 christos str); 1878 1.9 christos return 0; 1879 1.1 kardel } 1880 1.9 christos break; 1881 1.1 kardel 1882 1.9 christos case NTP_INT: 1883 1.9 christos if (!atoint(str, &argp->ival)) { 1884 1.9 christos fprintf(stderr, "***Illegal integer value %s\n", 1885 1.9 christos str); 1886 1.9 christos return 0; 1887 1.1 kardel } 1888 1.1 kardel break; 1889 1.9 christos 1890 1.9 christos case IP_VERSION: 1891 1.9 christos if (!strcmp("-6", str)) { 1892 1.9 christos argp->ival = 6; 1893 1.9 christos } else if (!strcmp("-4", str)) { 1894 1.9 christos argp->ival = 4; 1895 1.9 christos } else { 1896 1.9 christos fprintf(stderr, "***Version must be either 4 or 6\n"); 1897 1.1 kardel return 0; 1898 1.1 kardel } 1899 1.1 kardel break; 1900 1.1 kardel } 1901 1.1 kardel 1902 1.1 kardel return 1; 1903 1.1 kardel } 1904 1.1 kardel #endif /* !BUILD_AS_LIB */ 1905 1.1 kardel 1906 1.1 kardel 1907 1.1 kardel /* 1908 1.1 kardel * findcmd - find a command in a command description table 1909 1.1 kardel */ 1910 1.1 kardel static int 1911 1.1 kardel findcmd( 1912 1.9 christos const char * str, 1913 1.9 christos struct xcmd * clist1, 1914 1.9 christos struct xcmd * clist2, 1915 1.9 christos struct xcmd ** cmd 1916 1.1 kardel ) 1917 1.1 kardel { 1918 1.9 christos struct xcmd *cl; 1919 1.14 christos size_t clen; 1920 1.1 kardel int nmatch; 1921 1.1 kardel struct xcmd *nearmatch = NULL; 1922 1.1 kardel struct xcmd *clist; 1923 1.1 kardel 1924 1.1 kardel clen = strlen(str); 1925 1.1 kardel nmatch = 0; 1926 1.1 kardel if (clist1 != 0) 1927 1.1 kardel clist = clist1; 1928 1.1 kardel else if (clist2 != 0) 1929 1.1 kardel clist = clist2; 1930 1.1 kardel else 1931 1.1 kardel return 0; 1932 1.1 kardel 1933 1.1 kardel again: 1934 1.1 kardel for (cl = clist; cl->keyword != 0; cl++) { 1935 1.1 kardel /* do a first character check, for efficiency */ 1936 1.1 kardel if (*str != *(cl->keyword)) 1937 1.1 kardel continue; 1938 1.1 kardel if (strncmp(str, cl->keyword, (unsigned)clen) == 0) { 1939 1.1 kardel /* 1940 1.1 kardel * Could be extact match, could be approximate. 1941 1.1 kardel * Is exact if the length of the keyword is the 1942 1.1 kardel * same as the str. 1943 1.1 kardel */ 1944 1.1 kardel if (*((cl->keyword) + clen) == '\0') { 1945 1.1 kardel *cmd = cl; 1946 1.1 kardel return 1; 1947 1.1 kardel } 1948 1.1 kardel nmatch++; 1949 1.1 kardel nearmatch = cl; 1950 1.1 kardel } 1951 1.1 kardel } 1952 1.1 kardel 1953 1.1 kardel /* 1954 1.1 kardel * See if there is more to do. If so, go again. Sorry about the 1955 1.1 kardel * goto, too much looking at BSD sources... 1956 1.1 kardel */ 1957 1.1 kardel if (clist == clist1 && clist2 != 0) { 1958 1.1 kardel clist = clist2; 1959 1.1 kardel goto again; 1960 1.1 kardel } 1961 1.1 kardel 1962 1.1 kardel /* 1963 1.1 kardel * If we got extactly 1 near match, use it, else return number 1964 1.1 kardel * of matches. 1965 1.1 kardel */ 1966 1.1 kardel if (nmatch == 1) { 1967 1.1 kardel *cmd = nearmatch; 1968 1.1 kardel return 1; 1969 1.1 kardel } 1970 1.1 kardel return nmatch; 1971 1.1 kardel } 1972 1.1 kardel 1973 1.1 kardel 1974 1.1 kardel /* 1975 1.1 kardel * getnetnum - given a host name, return its net number 1976 1.1 kardel * and (optional) full name 1977 1.1 kardel */ 1978 1.1 kardel int 1979 1.1 kardel getnetnum( 1980 1.1 kardel const char *hname, 1981 1.1 kardel sockaddr_u *num, 1982 1.1 kardel char *fullhost, 1983 1.1 kardel int af 1984 1.1 kardel ) 1985 1.1 kardel { 1986 1.1 kardel struct addrinfo hints, *ai = NULL; 1987 1.1 kardel 1988 1.4 kardel ZERO(hints); 1989 1.1 kardel hints.ai_flags = AI_CANONNAME; 1990 1.1 kardel #ifdef AI_ADDRCONFIG 1991 1.1 kardel hints.ai_flags |= AI_ADDRCONFIG; 1992 1.1 kardel #endif 1993 1.9 christos 1994 1.4 kardel /* 1995 1.4 kardel * decodenetnum only works with addresses, but handles syntax 1996 1.4 kardel * that getaddrinfo doesn't: [2001::1]:1234 1997 1.4 kardel */ 1998 1.1 kardel if (decodenetnum(hname, num)) { 1999 1.4 kardel if (fullhost != NULL) 2000 1.4 kardel getnameinfo(&num->sa, SOCKLEN(num), fullhost, 2001 1.4 kardel LENHOSTNAME, NULL, 0, 0); 2002 1.1 kardel return 1; 2003 1.1 kardel } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) { 2004 1.9 christos INSIST(sizeof(*num) >= ai->ai_addrlen); 2005 1.4 kardel memcpy(num, ai->ai_addr, ai->ai_addrlen); 2006 1.4 kardel if (fullhost != NULL) { 2007 1.9 christos if (ai->ai_canonname != NULL) 2008 1.9 christos strlcpy(fullhost, ai->ai_canonname, 2009 1.4 kardel LENHOSTNAME); 2010 1.9 christos else 2011 1.4 kardel getnameinfo(&num->sa, SOCKLEN(num), 2012 1.4 kardel fullhost, LENHOSTNAME, NULL, 2013 1.4 kardel 0, 0); 2014 1.4 kardel } 2015 1.9 christos freeaddrinfo(ai); 2016 1.1 kardel return 1; 2017 1.1 kardel } 2018 1.4 kardel fprintf(stderr, "***Can't find host %s\n", hname); 2019 1.4 kardel 2020 1.4 kardel return 0; 2021 1.1 kardel } 2022 1.1 kardel 2023 1.9 christos 2024 1.1 kardel /* 2025 1.1 kardel * nntohost - convert network number to host name. This routine enforces 2026 1.1 kardel * the showhostnames setting. 2027 1.1 kardel */ 2028 1.4 kardel const char * 2029 1.1 kardel nntohost( 2030 1.1 kardel sockaddr_u *netnum 2031 1.1 kardel ) 2032 1.1 kardel { 2033 1.4 kardel return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE); 2034 1.4 kardel } 2035 1.4 kardel 2036 1.4 kardel 2037 1.4 kardel /* 2038 1.4 kardel * nntohost_col - convert network number to host name in fixed width. 2039 1.4 kardel * This routine enforces the showhostnames setting. 2040 1.4 kardel * When displaying hostnames longer than the width, 2041 1.4 kardel * the first part of the hostname is displayed. When 2042 1.4 kardel * displaying numeric addresses longer than the width, 2043 1.4 kardel * Such as IPv6 addresses, the caller decides whether 2044 1.4 kardel * the first or last of the numeric address is used. 2045 1.4 kardel */ 2046 1.4 kardel const char * 2047 1.4 kardel nntohost_col( 2048 1.4 kardel sockaddr_u * addr, 2049 1.4 kardel size_t width, 2050 1.4 kardel int preserve_lowaddrbits 2051 1.4 kardel ) 2052 1.4 kardel { 2053 1.4 kardel const char * out; 2054 1.4 kardel 2055 1.9 christos if (!showhostnames || SOCK_UNSPEC(addr)) { 2056 1.4 kardel if (preserve_lowaddrbits) 2057 1.4 kardel out = trunc_left(stoa(addr), width); 2058 1.4 kardel else 2059 1.4 kardel out = trunc_right(stoa(addr), width); 2060 1.4 kardel } else if (ISREFCLOCKADR(addr)) { 2061 1.4 kardel out = refnumtoa(addr); 2062 1.4 kardel } else { 2063 1.4 kardel out = trunc_right(socktohost(addr), width); 2064 1.4 kardel } 2065 1.4 kardel return out; 2066 1.1 kardel } 2067 1.1 kardel 2068 1.1 kardel 2069 1.1 kardel /* 2070 1.9 christos * nntohostp() is the same as nntohost() plus a :port suffix 2071 1.9 christos */ 2072 1.9 christos const char * 2073 1.9 christos nntohostp( 2074 1.9 christos sockaddr_u *netnum 2075 1.9 christos ) 2076 1.9 christos { 2077 1.9 christos const char * hostn; 2078 1.9 christos char * buf; 2079 1.9 christos 2080 1.9 christos if (!showhostnames || SOCK_UNSPEC(netnum)) 2081 1.9 christos return sptoa(netnum); 2082 1.9 christos else if (ISREFCLOCKADR(netnum)) 2083 1.9 christos return refnumtoa(netnum); 2084 1.9 christos 2085 1.9 christos hostn = socktohost(netnum); 2086 1.9 christos LIB_GETBUF(buf); 2087 1.9 christos snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum)); 2088 1.9 christos 2089 1.9 christos return buf; 2090 1.9 christos } 2091 1.9 christos 2092 1.9 christos /* 2093 1.1 kardel * rtdatetolfp - decode an RT-11 date into an l_fp 2094 1.1 kardel */ 2095 1.1 kardel static int 2096 1.1 kardel rtdatetolfp( 2097 1.1 kardel char *str, 2098 1.1 kardel l_fp *lfp 2099 1.1 kardel ) 2100 1.1 kardel { 2101 1.1 kardel register char *cp; 2102 1.1 kardel register int i; 2103 1.1 kardel struct calendar cal; 2104 1.1 kardel char buf[4]; 2105 1.1 kardel 2106 1.1 kardel cal.yearday = 0; 2107 1.1 kardel 2108 1.1 kardel /* 2109 1.1 kardel * An RT-11 date looks like: 2110 1.1 kardel * 2111 1.1 kardel * d[d]-Mth-y[y] hh:mm:ss 2112 1.1 kardel * 2113 1.1 kardel * (No docs, but assume 4-digit years are also legal...) 2114 1.1 kardel * 2115 1.1 kardel * d[d]-Mth-y[y[y[y]]] hh:mm:ss 2116 1.1 kardel */ 2117 1.1 kardel cp = str; 2118 1.19 christos if (!isdigit(pgetc(cp))) { 2119 1.1 kardel if (*cp == '-') { 2120 1.1 kardel /* 2121 1.1 kardel * Catch special case 2122 1.1 kardel */ 2123 1.1 kardel L_CLR(lfp); 2124 1.1 kardel return 1; 2125 1.1 kardel } 2126 1.1 kardel return 0; 2127 1.1 kardel } 2128 1.1 kardel 2129 1.1 kardel cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */ 2130 1.19 christos if (isdigit(pgetc(cp))) { 2131 1.1 kardel cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1)); 2132 1.1 kardel cal.monthday = (u_char)(cal.monthday + *cp++ - '0'); 2133 1.1 kardel } 2134 1.1 kardel 2135 1.1 kardel if (*cp++ != '-') 2136 1.1 kardel return 0; 2137 1.9 christos 2138 1.1 kardel for (i = 0; i < 3; i++) 2139 1.1 kardel buf[i] = *cp++; 2140 1.1 kardel buf[3] = '\0'; 2141 1.1 kardel 2142 1.1 kardel for (i = 0; i < 12; i++) 2143 1.1 kardel if (STREQ(buf, months[i])) 2144 1.1 kardel break; 2145 1.1 kardel if (i == 12) 2146 1.1 kardel return 0; 2147 1.1 kardel cal.month = (u_char)(i + 1); 2148 1.1 kardel 2149 1.1 kardel if (*cp++ != '-') 2150 1.1 kardel return 0; 2151 1.9 christos 2152 1.19 christos if (!isdigit(pgetc(cp))) 2153 1.1 kardel return 0; 2154 1.1 kardel cal.year = (u_short)(*cp++ - '0'); 2155 1.19 christos if (isdigit(pgetc(cp))) { 2156 1.1 kardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2157 1.1 kardel cal.year = (u_short)(*cp++ - '0'); 2158 1.1 kardel } 2159 1.19 christos if (isdigit(pgetc(cp))) { 2160 1.1 kardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2161 1.1 kardel cal.year = (u_short)(cal.year + *cp++ - '0'); 2162 1.1 kardel } 2163 1.19 christos if (isdigit(pgetc(cp))) { 2164 1.1 kardel cal.year = (u_short)((cal.year << 3) + (cal.year << 1)); 2165 1.1 kardel cal.year = (u_short)(cal.year + *cp++ - '0'); 2166 1.1 kardel } 2167 1.1 kardel 2168 1.1 kardel /* 2169 1.1 kardel * Catch special case. If cal.year == 0 this is a zero timestamp. 2170 1.1 kardel */ 2171 1.1 kardel if (cal.year == 0) { 2172 1.1 kardel L_CLR(lfp); 2173 1.1 kardel return 1; 2174 1.1 kardel } 2175 1.1 kardel 2176 1.19 christos if (*cp++ != ' ' || !isdigit(pgetc(cp))) 2177 1.1 kardel return 0; 2178 1.1 kardel cal.hour = (u_char)(*cp++ - '0'); 2179 1.19 christos if (isdigit(pgetc(cp))) { 2180 1.1 kardel cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1)); 2181 1.1 kardel cal.hour = (u_char)(cal.hour + *cp++ - '0'); 2182 1.1 kardel } 2183 1.1 kardel 2184 1.19 christos if (*cp++ != ':' || !isdigit(pgetc(cp))) 2185 1.1 kardel return 0; 2186 1.1 kardel cal.minute = (u_char)(*cp++ - '0'); 2187 1.19 christos if (isdigit(pgetc(cp))) { 2188 1.1 kardel cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1)); 2189 1.1 kardel cal.minute = (u_char)(cal.minute + *cp++ - '0'); 2190 1.1 kardel } 2191 1.1 kardel 2192 1.19 christos if (*cp++ != ':' || !isdigit(pgetc(cp))) 2193 1.1 kardel return 0; 2194 1.1 kardel cal.second = (u_char)(*cp++ - '0'); 2195 1.19 christos if (isdigit(pgetc(cp))) { 2196 1.1 kardel cal.second = (u_char)((cal.second << 3) + (cal.second << 1)); 2197 1.1 kardel cal.second = (u_char)(cal.second + *cp++ - '0'); 2198 1.1 kardel } 2199 1.1 kardel 2200 1.1 kardel /* 2201 1.1 kardel * For RT-11, 1972 seems to be the pivot year 2202 1.1 kardel */ 2203 1.1 kardel if (cal.year < 72) 2204 1.1 kardel cal.year += 2000; 2205 1.1 kardel if (cal.year < 100) 2206 1.1 kardel cal.year += 1900; 2207 1.1 kardel 2208 1.23 christos /* check for complaints from 'caltontp()'! */ 2209 1.23 christos lfp->l_uf = 0; 2210 1.23 christos errno = 0; 2211 1.1 kardel lfp->l_ui = caltontp(&cal); 2212 1.23 christos return (errno == 0); 2213 1.1 kardel } 2214 1.1 kardel 2215 1.1 kardel 2216 1.1 kardel /* 2217 1.1 kardel * decodets - decode a timestamp into an l_fp format number, with 2218 1.1 kardel * consideration of fuzzball formats. 2219 1.1 kardel */ 2220 1.1 kardel int 2221 1.1 kardel decodets( 2222 1.1 kardel char *str, 2223 1.1 kardel l_fp *lfp 2224 1.1 kardel ) 2225 1.1 kardel { 2226 1.4 kardel char *cp; 2227 1.4 kardel char buf[30]; 2228 1.4 kardel size_t b; 2229 1.4 kardel 2230 1.1 kardel /* 2231 1.1 kardel * If it starts with a 0x, decode as hex. 2232 1.1 kardel */ 2233 1.1 kardel if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) 2234 1.1 kardel return hextolfp(str+2, lfp); 2235 1.1 kardel 2236 1.1 kardel /* 2237 1.1 kardel * If it starts with a '"', try it as an RT-11 date. 2238 1.1 kardel */ 2239 1.1 kardel if (*str == '"') { 2240 1.4 kardel cp = str + 1; 2241 1.4 kardel b = 0; 2242 1.4 kardel while ('"' != *cp && '\0' != *cp && 2243 1.4 kardel b < COUNTOF(buf) - 1) 2244 1.4 kardel buf[b++] = *cp++; 2245 1.4 kardel buf[b] = '\0'; 2246 1.1 kardel return rtdatetolfp(buf, lfp); 2247 1.1 kardel } 2248 1.1 kardel 2249 1.1 kardel /* 2250 1.1 kardel * Might still be hex. Check out the first character. Talk 2251 1.1 kardel * about heuristics! 2252 1.1 kardel */ 2253 1.1 kardel if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f')) 2254 1.1 kardel return hextolfp(str, lfp); 2255 1.1 kardel 2256 1.1 kardel /* 2257 1.1 kardel * Try it as a decimal. If this fails, try as an unquoted 2258 1.1 kardel * RT-11 date. This code should go away eventually. 2259 1.1 kardel */ 2260 1.1 kardel if (atolfp(str, lfp)) 2261 1.1 kardel return 1; 2262 1.1 kardel 2263 1.1 kardel return rtdatetolfp(str, lfp); 2264 1.1 kardel } 2265 1.1 kardel 2266 1.1 kardel 2267 1.1 kardel /* 2268 1.1 kardel * decodetime - decode a time value. It should be in milliseconds 2269 1.1 kardel */ 2270 1.1 kardel int 2271 1.1 kardel decodetime( 2272 1.1 kardel char *str, 2273 1.1 kardel l_fp *lfp 2274 1.1 kardel ) 2275 1.1 kardel { 2276 1.1 kardel return mstolfp(str, lfp); 2277 1.1 kardel } 2278 1.1 kardel 2279 1.1 kardel 2280 1.1 kardel /* 2281 1.1 kardel * decodeint - decode an integer 2282 1.1 kardel */ 2283 1.1 kardel int 2284 1.1 kardel decodeint( 2285 1.1 kardel char *str, 2286 1.1 kardel long *val 2287 1.1 kardel ) 2288 1.1 kardel { 2289 1.1 kardel if (*str == '0') { 2290 1.1 kardel if (*(str+1) == 'x' || *(str+1) == 'X') 2291 1.1 kardel return hextoint(str+2, (u_long *)val); 2292 1.1 kardel return octtoint(str, (u_long *)val); 2293 1.1 kardel } 2294 1.1 kardel return atoint(str, val); 2295 1.1 kardel } 2296 1.1 kardel 2297 1.1 kardel 2298 1.1 kardel /* 2299 1.1 kardel * decodeuint - decode an unsigned integer 2300 1.1 kardel */ 2301 1.1 kardel int 2302 1.1 kardel decodeuint( 2303 1.1 kardel char *str, 2304 1.1 kardel u_long *val 2305 1.1 kardel ) 2306 1.1 kardel { 2307 1.1 kardel if (*str == '0') { 2308 1.1 kardel if (*(str + 1) == 'x' || *(str + 1) == 'X') 2309 1.1 kardel return (hextoint(str + 2, val)); 2310 1.1 kardel return (octtoint(str, val)); 2311 1.1 kardel } 2312 1.1 kardel return (atouint(str, val)); 2313 1.1 kardel } 2314 1.1 kardel 2315 1.1 kardel 2316 1.1 kardel /* 2317 1.1 kardel * decodearr - decode an array of time values 2318 1.1 kardel */ 2319 1.1 kardel static int 2320 1.1 kardel decodearr( 2321 1.19 christos char *cp, 2322 1.19 christos int *narr, 2323 1.19 christos l_fp *lfpa, 2324 1.19 christos int amax 2325 1.1 kardel ) 2326 1.1 kardel { 2327 1.19 christos char *bp; 2328 1.1 kardel char buf[60]; 2329 1.1 kardel 2330 1.1 kardel *narr = 0; 2331 1.1 kardel 2332 1.19 christos while (*narr < amax && *cp) { 2333 1.19 christos if (isspace(pgetc(cp))) { 2334 1.19 christos do 2335 1.19 christos ++cp; 2336 1.19 christos while (*cp && isspace(pgetc(cp))); 2337 1.19 christos } else { 2338 1.19 christos bp = buf; 2339 1.19 christos do { 2340 1.19 christos if (bp != (buf + sizeof(buf) - 1)) 2341 1.19 christos *bp++ = *cp; 2342 1.19 christos ++cp; 2343 1.19 christos } while (*cp && !isspace(pgetc(cp))); 2344 1.19 christos *bp = '\0'; 2345 1.1 kardel 2346 1.19 christos if (!decodetime(buf, lfpa)) 2347 1.19 christos return 0; 2348 1.19 christos ++(*narr); 2349 1.19 christos ++lfpa; 2350 1.19 christos } 2351 1.1 kardel } 2352 1.1 kardel return 1; 2353 1.1 kardel } 2354 1.1 kardel 2355 1.1 kardel 2356 1.1 kardel /* 2357 1.1 kardel * Finally, the built in command handlers 2358 1.1 kardel */ 2359 1.1 kardel 2360 1.1 kardel /* 2361 1.1 kardel * help - tell about commands, or details of a particular command 2362 1.1 kardel */ 2363 1.1 kardel static void 2364 1.1 kardel help( 2365 1.1 kardel struct parse *pcmd, 2366 1.1 kardel FILE *fp 2367 1.1 kardel ) 2368 1.1 kardel { 2369 1.1 kardel struct xcmd *xcp = NULL; /* quiet warning */ 2370 1.9 christos const char *cmd; 2371 1.1 kardel const char *list[100]; 2372 1.4 kardel size_t word, words; 2373 1.4 kardel size_t row, rows; 2374 1.4 kardel size_t col, cols; 2375 1.4 kardel size_t length; 2376 1.1 kardel 2377 1.1 kardel if (pcmd->nargs == 0) { 2378 1.1 kardel words = 0; 2379 1.4 kardel for (xcp = builtins; xcp->keyword != NULL; xcp++) { 2380 1.9 christos if (*(xcp->keyword) != '?' && 2381 1.9 christos words < COUNTOF(list)) 2382 1.1 kardel list[words++] = xcp->keyword; 2383 1.1 kardel } 2384 1.4 kardel for (xcp = opcmds; xcp->keyword != NULL; xcp++) 2385 1.9 christos if (words < COUNTOF(list)) 2386 1.9 christos list[words++] = xcp->keyword; 2387 1.1 kardel 2388 1.9 christos qsort((void *)list, words, sizeof(list[0]), helpsort); 2389 1.1 kardel col = 0; 2390 1.1 kardel for (word = 0; word < words; word++) { 2391 1.9 christos length = strlen(list[word]); 2392 1.4 kardel col = max(col, length); 2393 1.1 kardel } 2394 1.1 kardel 2395 1.1 kardel cols = SCREENWIDTH / ++col; 2396 1.1 kardel rows = (words + cols - 1) / cols; 2397 1.1 kardel 2398 1.4 kardel fprintf(fp, "ntpq commands:\n"); 2399 1.1 kardel 2400 1.1 kardel for (row = 0; row < rows; row++) { 2401 1.4 kardel for (word = row; word < words; word += rows) 2402 1.9 christos fprintf(fp, "%-*.*s", (int)col, 2403 1.9 christos (int)col - 1, list[word]); 2404 1.4 kardel fprintf(fp, "\n"); 2405 1.1 kardel } 2406 1.1 kardel } else { 2407 1.1 kardel cmd = pcmd->argval[0].string; 2408 1.1 kardel words = findcmd(cmd, builtins, opcmds, &xcp); 2409 1.1 kardel if (words == 0) { 2410 1.4 kardel fprintf(stderr, 2411 1.4 kardel "Command `%s' is unknown\n", cmd); 2412 1.1 kardel return; 2413 1.1 kardel } else if (words >= 2) { 2414 1.4 kardel fprintf(stderr, 2415 1.4 kardel "Command `%s' is ambiguous\n", cmd); 2416 1.1 kardel return; 2417 1.1 kardel } 2418 1.4 kardel fprintf(fp, "function: %s\n", xcp->comment); 2419 1.1 kardel printusage(xcp, fp); 2420 1.1 kardel } 2421 1.1 kardel } 2422 1.1 kardel 2423 1.1 kardel 2424 1.1 kardel /* 2425 1.1 kardel * helpsort - do hostname qsort comparisons 2426 1.1 kardel */ 2427 1.1 kardel static int 2428 1.1 kardel helpsort( 2429 1.1 kardel const void *t1, 2430 1.1 kardel const void *t2 2431 1.1 kardel ) 2432 1.1 kardel { 2433 1.4 kardel const char * const * name1 = t1; 2434 1.4 kardel const char * const * name2 = t2; 2435 1.1 kardel 2436 1.1 kardel return strcmp(*name1, *name2); 2437 1.1 kardel } 2438 1.1 kardel 2439 1.1 kardel 2440 1.1 kardel /* 2441 1.1 kardel * printusage - print usage information for a command 2442 1.1 kardel */ 2443 1.1 kardel static void 2444 1.1 kardel printusage( 2445 1.1 kardel struct xcmd *xcp, 2446 1.1 kardel FILE *fp 2447 1.1 kardel ) 2448 1.1 kardel { 2449 1.1 kardel register int i; 2450 1.1 kardel 2451 1.9 christos /* XXX: Do we need to warn about extra args here too? */ 2452 1.9 christos 2453 1.1 kardel (void) fprintf(fp, "usage: %s", xcp->keyword); 2454 1.1 kardel for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) { 2455 1.1 kardel if (xcp->arg[i] & OPT) 2456 1.1 kardel (void) fprintf(fp, " [ %s ]", xcp->desc[i]); 2457 1.1 kardel else 2458 1.1 kardel (void) fprintf(fp, " %s", xcp->desc[i]); 2459 1.1 kardel } 2460 1.1 kardel (void) fprintf(fp, "\n"); 2461 1.1 kardel } 2462 1.1 kardel 2463 1.1 kardel 2464 1.1 kardel /* 2465 1.1 kardel * timeout - set time out time 2466 1.1 kardel */ 2467 1.1 kardel static void 2468 1.1 kardel timeout( 2469 1.1 kardel struct parse *pcmd, 2470 1.1 kardel FILE *fp 2471 1.1 kardel ) 2472 1.1 kardel { 2473 1.1 kardel int val; 2474 1.1 kardel 2475 1.1 kardel if (pcmd->nargs == 0) { 2476 1.1 kardel val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000; 2477 1.1 kardel (void) fprintf(fp, "primary timeout %d ms\n", val); 2478 1.1 kardel } else { 2479 1.1 kardel tvout.tv_sec = pcmd->argval[0].uval / 1000; 2480 1.1 kardel tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000)) 2481 1.1 kardel * 1000; 2482 1.1 kardel } 2483 1.1 kardel } 2484 1.1 kardel 2485 1.1 kardel 2486 1.1 kardel /* 2487 1.1 kardel * auth_delay - set delay for auth requests 2488 1.1 kardel */ 2489 1.1 kardel static void 2490 1.1 kardel auth_delay( 2491 1.1 kardel struct parse *pcmd, 2492 1.1 kardel FILE *fp 2493 1.1 kardel ) 2494 1.1 kardel { 2495 1.1 kardel int isneg; 2496 1.1 kardel u_long val; 2497 1.1 kardel 2498 1.1 kardel if (pcmd->nargs == 0) { 2499 1.1 kardel val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967; 2500 1.1 kardel (void) fprintf(fp, "delay %lu ms\n", val); 2501 1.1 kardel } else { 2502 1.1 kardel if (pcmd->argval[0].ival < 0) { 2503 1.1 kardel isneg = 1; 2504 1.1 kardel val = (u_long)(-pcmd->argval[0].ival); 2505 1.1 kardel } else { 2506 1.1 kardel isneg = 0; 2507 1.1 kardel val = (u_long)pcmd->argval[0].ival; 2508 1.1 kardel } 2509 1.1 kardel 2510 1.1 kardel delay_time.l_ui = val / 1000; 2511 1.1 kardel val %= 1000; 2512 1.1 kardel delay_time.l_uf = val * 4294967; /* 2**32/1000 */ 2513 1.1 kardel 2514 1.1 kardel if (isneg) 2515 1.1 kardel L_NEG(&delay_time); 2516 1.1 kardel } 2517 1.1 kardel } 2518 1.1 kardel 2519 1.1 kardel 2520 1.1 kardel /* 2521 1.1 kardel * host - set the host we are dealing with. 2522 1.1 kardel */ 2523 1.1 kardel static void 2524 1.1 kardel host( 2525 1.1 kardel struct parse *pcmd, 2526 1.1 kardel FILE *fp 2527 1.1 kardel ) 2528 1.1 kardel { 2529 1.1 kardel int i; 2530 1.1 kardel 2531 1.1 kardel if (pcmd->nargs == 0) { 2532 1.1 kardel if (havehost) 2533 1.1 kardel (void) fprintf(fp, "current host is %s\n", 2534 1.1 kardel currenthost); 2535 1.1 kardel else 2536 1.1 kardel (void) fprintf(fp, "no current host\n"); 2537 1.1 kardel return; 2538 1.1 kardel } 2539 1.1 kardel 2540 1.1 kardel i = 0; 2541 1.1 kardel ai_fam_templ = ai_fam_default; 2542 1.1 kardel if (pcmd->nargs == 2) { 2543 1.1 kardel if (!strcmp("-4", pcmd->argval[i].string)) 2544 1.1 kardel ai_fam_templ = AF_INET; 2545 1.1 kardel else if (!strcmp("-6", pcmd->argval[i].string)) 2546 1.1 kardel ai_fam_templ = AF_INET6; 2547 1.9 christos else 2548 1.9 christos goto no_change; 2549 1.1 kardel i = 1; 2550 1.1 kardel } 2551 1.9 christos if (openhost(pcmd->argval[i].string, ai_fam_templ)) { 2552 1.9 christos fprintf(fp, "current host set to %s\n", currenthost); 2553 1.1 kardel } else { 2554 1.9 christos no_change: 2555 1.1 kardel if (havehost) 2556 1.9 christos fprintf(fp, "current host remains %s\n", 2557 1.9 christos currenthost); 2558 1.1 kardel else 2559 1.9 christos fprintf(fp, "still no current host\n"); 2560 1.1 kardel } 2561 1.1 kardel } 2562 1.1 kardel 2563 1.1 kardel 2564 1.1 kardel /* 2565 1.1 kardel * poll - do one (or more) polls of the host via NTP 2566 1.1 kardel */ 2567 1.1 kardel /*ARGSUSED*/ 2568 1.1 kardel static void 2569 1.1 kardel ntp_poll( 2570 1.1 kardel struct parse *pcmd, 2571 1.1 kardel FILE *fp 2572 1.1 kardel ) 2573 1.1 kardel { 2574 1.1 kardel (void) fprintf(fp, "poll not implemented yet\n"); 2575 1.1 kardel } 2576 1.1 kardel 2577 1.1 kardel 2578 1.1 kardel /* 2579 1.15 christos * showdrefid2str - return a string explanation of the value of drefid 2580 1.15 christos */ 2581 1.15 christos static const char * 2582 1.15 christos showdrefid2str(void) 2583 1.15 christos { 2584 1.15 christos switch (drefid) { 2585 1.15 christos case REFID_HASH: 2586 1.15 christos return "hash"; 2587 1.15 christos case REFID_IPV4: 2588 1.15 christos return "ipv4"; 2589 1.15 christos default: 2590 1.15 christos return "Unknown"; 2591 1.15 christos } 2592 1.15 christos } 2593 1.15 christos 2594 1.15 christos 2595 1.15 christos /* 2596 1.23 christos * drefid - display/change "display hash" 2597 1.15 christos */ 2598 1.15 christos static void 2599 1.15 christos showdrefid( 2600 1.15 christos struct parse *pcmd, 2601 1.15 christos FILE *fp 2602 1.15 christos ) 2603 1.15 christos { 2604 1.15 christos if (pcmd->nargs == 0) { 2605 1.15 christos (void) fprintf(fp, "drefid value is %s\n", showdrefid2str()); 2606 1.15 christos return; 2607 1.15 christos } else if (STREQ(pcmd->argval[0].string, "hash")) { 2608 1.15 christos drefid = REFID_HASH; 2609 1.15 christos } else if (STREQ(pcmd->argval[0].string, "ipv4")) { 2610 1.15 christos drefid = REFID_IPV4; 2611 1.15 christos } else { 2612 1.15 christos (void) fprintf(fp, "What?\n"); 2613 1.15 christos return; 2614 1.15 christos } 2615 1.15 christos (void) fprintf(fp, "drefid value set to %s\n", showdrefid2str()); 2616 1.15 christos } 2617 1.15 christos 2618 1.15 christos 2619 1.15 christos /* 2620 1.1 kardel * keyid - get a keyid to use for authenticating requests 2621 1.1 kardel */ 2622 1.1 kardel static void 2623 1.1 kardel keyid( 2624 1.1 kardel struct parse *pcmd, 2625 1.1 kardel FILE *fp 2626 1.1 kardel ) 2627 1.1 kardel { 2628 1.1 kardel if (pcmd->nargs == 0) { 2629 1.1 kardel if (info_auth_keyid == 0) 2630 1.1 kardel (void) fprintf(fp, "no keyid defined\n"); 2631 1.1 kardel else 2632 1.1 kardel (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid); 2633 1.1 kardel } else { 2634 1.1 kardel /* allow zero so that keyid can be cleared. */ 2635 1.1 kardel if(pcmd->argval[0].uval > NTP_MAXKEY) 2636 1.1 kardel (void) fprintf(fp, "Invalid key identifier\n"); 2637 1.1 kardel info_auth_keyid = pcmd->argval[0].uval; 2638 1.1 kardel } 2639 1.1 kardel } 2640 1.1 kardel 2641 1.1 kardel /* 2642 1.1 kardel * keytype - get type of key to use for authenticating requests 2643 1.1 kardel */ 2644 1.1 kardel static void 2645 1.1 kardel keytype( 2646 1.1 kardel struct parse *pcmd, 2647 1.1 kardel FILE *fp 2648 1.1 kardel ) 2649 1.1 kardel { 2650 1.1 kardel const char * digest_name; 2651 1.1 kardel size_t digest_len; 2652 1.1 kardel int key_type; 2653 1.1 kardel 2654 1.1 kardel if (!pcmd->nargs) { 2655 1.6 kardel fprintf(fp, "keytype is %s with %lu octet digests\n", 2656 1.1 kardel keytype_name(info_auth_keytype), 2657 1.4 kardel (u_long)info_auth_hashlen); 2658 1.1 kardel return; 2659 1.1 kardel } 2660 1.1 kardel 2661 1.1 kardel digest_name = pcmd->argval[0].string; 2662 1.1 kardel digest_len = 0; 2663 1.1 kardel key_type = keytype_from_text(digest_name, &digest_len); 2664 1.1 kardel 2665 1.1 kardel if (!key_type) { 2666 1.12 christos fprintf(fp, "keytype is not valid. " 2667 1.1 kardel #ifdef OPENSSL 2668 1.12 christos "Type \"help keytype\" for the available digest types.\n"); 2669 1.1 kardel #else 2670 1.12 christos "Only \"md5\" is available.\n"); 2671 1.1 kardel #endif 2672 1.1 kardel return; 2673 1.1 kardel } 2674 1.1 kardel 2675 1.1 kardel info_auth_keytype = key_type; 2676 1.1 kardel info_auth_hashlen = digest_len; 2677 1.1 kardel } 2678 1.1 kardel 2679 1.1 kardel 2680 1.1 kardel /* 2681 1.1 kardel * passwd - get an authentication key 2682 1.1 kardel */ 2683 1.1 kardel /*ARGSUSED*/ 2684 1.1 kardel static void 2685 1.1 kardel passwd( 2686 1.1 kardel struct parse *pcmd, 2687 1.1 kardel FILE *fp 2688 1.1 kardel ) 2689 1.1 kardel { 2690 1.9 christos const char *pass; 2691 1.1 kardel 2692 1.1 kardel if (info_auth_keyid == 0) { 2693 1.9 christos info_auth_keyid = getkeyid("Keyid: "); 2694 1.9 christos if (info_auth_keyid == 0) { 2695 1.9 christos (void)fprintf(fp, "Keyid must be defined\n"); 2696 1.1 kardel return; 2697 1.1 kardel } 2698 1.1 kardel } 2699 1.4 kardel if (pcmd->nargs >= 1) 2700 1.4 kardel pass = pcmd->argval[0].string; 2701 1.1 kardel else { 2702 1.4 kardel pass = getpass_keytype(info_auth_keytype); 2703 1.4 kardel if ('\0' == pass[0]) { 2704 1.4 kardel fprintf(fp, "Password unchanged\n"); 2705 1.4 kardel return; 2706 1.4 kardel } 2707 1.1 kardel } 2708 1.9 christos authusekey(info_auth_keyid, info_auth_keytype, 2709 1.9 christos (const u_char *)pass); 2710 1.4 kardel authtrust(info_auth_keyid, 1); 2711 1.1 kardel } 2712 1.1 kardel 2713 1.1 kardel 2714 1.1 kardel /* 2715 1.1 kardel * hostnames - set the showhostnames flag 2716 1.1 kardel */ 2717 1.1 kardel static void 2718 1.1 kardel hostnames( 2719 1.1 kardel struct parse *pcmd, 2720 1.1 kardel FILE *fp 2721 1.1 kardel ) 2722 1.1 kardel { 2723 1.1 kardel if (pcmd->nargs == 0) { 2724 1.1 kardel if (showhostnames) 2725 1.1 kardel (void) fprintf(fp, "hostnames being shown\n"); 2726 1.1 kardel else 2727 1.1 kardel (void) fprintf(fp, "hostnames not being shown\n"); 2728 1.1 kardel } else { 2729 1.1 kardel if (STREQ(pcmd->argval[0].string, "yes")) 2730 1.1 kardel showhostnames = 1; 2731 1.1 kardel else if (STREQ(pcmd->argval[0].string, "no")) 2732 1.1 kardel showhostnames = 0; 2733 1.1 kardel else 2734 1.1 kardel (void)fprintf(stderr, "What?\n"); 2735 1.1 kardel } 2736 1.1 kardel } 2737 1.1 kardel 2738 1.1 kardel 2739 1.1 kardel 2740 1.1 kardel /* 2741 1.1 kardel * setdebug - set/change debugging level 2742 1.1 kardel */ 2743 1.1 kardel static void 2744 1.1 kardel setdebug( 2745 1.1 kardel struct parse *pcmd, 2746 1.1 kardel FILE *fp 2747 1.1 kardel ) 2748 1.1 kardel { 2749 1.1 kardel if (pcmd->nargs == 0) { 2750 1.1 kardel (void) fprintf(fp, "debug level is %d\n", debug); 2751 1.1 kardel return; 2752 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "no")) { 2753 1.1 kardel debug = 0; 2754 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "more")) { 2755 1.1 kardel debug++; 2756 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "less")) { 2757 1.1 kardel debug--; 2758 1.1 kardel } else { 2759 1.1 kardel (void) fprintf(fp, "What?\n"); 2760 1.1 kardel return; 2761 1.1 kardel } 2762 1.1 kardel (void) fprintf(fp, "debug level set to %d\n", debug); 2763 1.1 kardel } 2764 1.1 kardel 2765 1.1 kardel 2766 1.1 kardel /* 2767 1.1 kardel * quit - stop this nonsense 2768 1.1 kardel */ 2769 1.1 kardel /*ARGSUSED*/ 2770 1.1 kardel static void 2771 1.1 kardel quit( 2772 1.1 kardel struct parse *pcmd, 2773 1.1 kardel FILE *fp 2774 1.1 kardel ) 2775 1.1 kardel { 2776 1.1 kardel if (havehost) 2777 1.1 kardel closesocket(sockfd); /* cleanliness next to godliness */ 2778 1.1 kardel exit(0); 2779 1.1 kardel } 2780 1.1 kardel 2781 1.1 kardel 2782 1.1 kardel /* 2783 1.1 kardel * version - print the current version number 2784 1.1 kardel */ 2785 1.1 kardel /*ARGSUSED*/ 2786 1.1 kardel static void 2787 1.1 kardel version( 2788 1.1 kardel struct parse *pcmd, 2789 1.1 kardel FILE *fp 2790 1.1 kardel ) 2791 1.1 kardel { 2792 1.1 kardel 2793 1.1 kardel (void) fprintf(fp, "%s\n", Version); 2794 1.1 kardel return; 2795 1.1 kardel } 2796 1.1 kardel 2797 1.1 kardel 2798 1.1 kardel /* 2799 1.1 kardel * raw - set raw mode output 2800 1.1 kardel */ 2801 1.1 kardel /*ARGSUSED*/ 2802 1.1 kardel static void 2803 1.1 kardel raw( 2804 1.1 kardel struct parse *pcmd, 2805 1.1 kardel FILE *fp 2806 1.1 kardel ) 2807 1.1 kardel { 2808 1.1 kardel rawmode = 1; 2809 1.1 kardel (void) fprintf(fp, "Output set to raw\n"); 2810 1.1 kardel } 2811 1.1 kardel 2812 1.1 kardel 2813 1.1 kardel /* 2814 1.1 kardel * cooked - set cooked mode output 2815 1.1 kardel */ 2816 1.1 kardel /*ARGSUSED*/ 2817 1.1 kardel static void 2818 1.1 kardel cooked( 2819 1.1 kardel struct parse *pcmd, 2820 1.1 kardel FILE *fp 2821 1.1 kardel ) 2822 1.1 kardel { 2823 1.1 kardel rawmode = 0; 2824 1.1 kardel (void) fprintf(fp, "Output set to cooked\n"); 2825 1.1 kardel return; 2826 1.1 kardel } 2827 1.1 kardel 2828 1.1 kardel 2829 1.1 kardel /* 2830 1.1 kardel * authenticate - always authenticate requests to this host 2831 1.1 kardel */ 2832 1.1 kardel static void 2833 1.1 kardel authenticate( 2834 1.1 kardel struct parse *pcmd, 2835 1.1 kardel FILE *fp 2836 1.1 kardel ) 2837 1.1 kardel { 2838 1.1 kardel if (pcmd->nargs == 0) { 2839 1.1 kardel if (always_auth) { 2840 1.1 kardel (void) fprintf(fp, 2841 1.1 kardel "authenticated requests being sent\n"); 2842 1.1 kardel } else 2843 1.1 kardel (void) fprintf(fp, 2844 1.1 kardel "unauthenticated requests being sent\n"); 2845 1.1 kardel } else { 2846 1.1 kardel if (STREQ(pcmd->argval[0].string, "yes")) { 2847 1.1 kardel always_auth = 1; 2848 1.1 kardel } else if (STREQ(pcmd->argval[0].string, "no")) { 2849 1.1 kardel always_auth = 0; 2850 1.1 kardel } else 2851 1.1 kardel (void)fprintf(stderr, "What?\n"); 2852 1.1 kardel } 2853 1.1 kardel } 2854 1.1 kardel 2855 1.1 kardel 2856 1.1 kardel /* 2857 1.1 kardel * ntpversion - choose the NTP version to use 2858 1.1 kardel */ 2859 1.1 kardel static void 2860 1.1 kardel ntpversion( 2861 1.1 kardel struct parse *pcmd, 2862 1.1 kardel FILE *fp 2863 1.1 kardel ) 2864 1.1 kardel { 2865 1.1 kardel if (pcmd->nargs == 0) { 2866 1.1 kardel (void) fprintf(fp, 2867 1.1 kardel "NTP version being claimed is %d\n", pktversion); 2868 1.1 kardel } else { 2869 1.1 kardel if (pcmd->argval[0].uval < NTP_OLDVERSION 2870 1.1 kardel || pcmd->argval[0].uval > NTP_VERSION) { 2871 1.1 kardel (void) fprintf(stderr, "versions %d to %d, please\n", 2872 1.1 kardel NTP_OLDVERSION, NTP_VERSION); 2873 1.1 kardel } else { 2874 1.1 kardel pktversion = (u_char) pcmd->argval[0].uval; 2875 1.1 kardel } 2876 1.1 kardel } 2877 1.1 kardel } 2878 1.1 kardel 2879 1.1 kardel 2880 1.3 christos static void __attribute__((__format__(__printf__, 1, 0))) 2881 1.3 christos vwarning(const char *fmt, va_list ap) 2882 1.3 christos { 2883 1.3 christos int serrno = errno; 2884 1.3 christos (void) fprintf(stderr, "%s: ", progname); 2885 1.3 christos vfprintf(stderr, fmt, ap); 2886 1.14 christos (void) fprintf(stderr, ": %s\n", strerror(serrno)); 2887 1.3 christos } 2888 1.3 christos 2889 1.1 kardel /* 2890 1.1 kardel * warning - print a warning message 2891 1.1 kardel */ 2892 1.3 christos static void __attribute__((__format__(__printf__, 1, 2))) 2893 1.1 kardel warning( 2894 1.1 kardel const char *fmt, 2895 1.3 christos ... 2896 1.1 kardel ) 2897 1.1 kardel { 2898 1.3 christos va_list ap; 2899 1.3 christos va_start(ap, fmt); 2900 1.3 christos vwarning(fmt, ap); 2901 1.3 christos va_end(ap); 2902 1.1 kardel } 2903 1.1 kardel 2904 1.1 kardel 2905 1.1 kardel /* 2906 1.1 kardel * error - print a message and exit 2907 1.1 kardel */ 2908 1.3 christos static void __attribute__((__format__(__printf__, 1, 2))) 2909 1.1 kardel error( 2910 1.1 kardel const char *fmt, 2911 1.3 christos ... 2912 1.1 kardel ) 2913 1.1 kardel { 2914 1.3 christos va_list ap; 2915 1.3 christos va_start(ap, fmt); 2916 1.3 christos vwarning(fmt, ap); 2917 1.3 christos va_end(ap); 2918 1.1 kardel exit(1); 2919 1.1 kardel } 2920 1.1 kardel /* 2921 1.1 kardel * getkeyid - prompt the user for a keyid to use 2922 1.1 kardel */ 2923 1.1 kardel static u_long 2924 1.1 kardel getkeyid( 2925 1.1 kardel const char *keyprompt 2926 1.1 kardel ) 2927 1.1 kardel { 2928 1.4 kardel int c; 2929 1.1 kardel FILE *fi; 2930 1.1 kardel char pbuf[20]; 2931 1.4 kardel size_t i; 2932 1.4 kardel size_t ilim; 2933 1.1 kardel 2934 1.1 kardel #ifndef SYS_WINNT 2935 1.1 kardel if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL) 2936 1.1 kardel #else 2937 1.1 kardel if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL) 2938 1.1 kardel #endif /* SYS_WINNT */ 2939 1.1 kardel fi = stdin; 2940 1.4 kardel else 2941 1.1 kardel setbuf(fi, (char *)NULL); 2942 1.1 kardel fprintf(stderr, "%s", keyprompt); fflush(stderr); 2943 1.4 kardel for (i = 0, ilim = COUNTOF(pbuf) - 1; 2944 1.4 kardel i < ilim && (c = getc(fi)) != '\n' && c != EOF; 2945 1.4 kardel ) 2946 1.4 kardel pbuf[i++] = (char)c; 2947 1.4 kardel pbuf[i] = '\0'; 2948 1.1 kardel if (fi != stdin) 2949 1.4 kardel fclose(fi); 2950 1.1 kardel 2951 1.1 kardel return (u_long) atoi(pbuf); 2952 1.1 kardel } 2953 1.1 kardel 2954 1.1 kardel 2955 1.1 kardel /* 2956 1.1 kardel * atoascii - printable-ize possibly ascii data using the character 2957 1.1 kardel * transformations cat -v uses. 2958 1.1 kardel */ 2959 1.1 kardel static void 2960 1.1 kardel atoascii( 2961 1.1 kardel const char *in, 2962 1.1 kardel size_t in_octets, 2963 1.1 kardel char *out, 2964 1.1 kardel size_t out_octets 2965 1.1 kardel ) 2966 1.1 kardel { 2967 1.9 christos const u_char * pchIn; 2968 1.9 christos const u_char * pchInLimit; 2969 1.9 christos u_char * pchOut; 2970 1.9 christos u_char c; 2971 1.1 kardel 2972 1.1 kardel pchIn = (const u_char *)in; 2973 1.1 kardel pchInLimit = pchIn + in_octets; 2974 1.1 kardel pchOut = (u_char *)out; 2975 1.1 kardel 2976 1.1 kardel if (NULL == pchIn) { 2977 1.1 kardel if (0 < out_octets) 2978 1.1 kardel *pchOut = '\0'; 2979 1.1 kardel return; 2980 1.1 kardel } 2981 1.1 kardel 2982 1.1 kardel #define ONEOUT(c) \ 2983 1.1 kardel do { \ 2984 1.1 kardel if (0 == --out_octets) { \ 2985 1.1 kardel *pchOut = '\0'; \ 2986 1.1 kardel return; \ 2987 1.1 kardel } \ 2988 1.1 kardel *pchOut++ = (c); \ 2989 1.1 kardel } while (0) 2990 1.1 kardel 2991 1.1 kardel for ( ; pchIn < pchInLimit; pchIn++) { 2992 1.1 kardel c = *pchIn; 2993 1.1 kardel if ('\0' == c) 2994 1.1 kardel break; 2995 1.1 kardel if (c & 0x80) { 2996 1.1 kardel ONEOUT('M'); 2997 1.1 kardel ONEOUT('-'); 2998 1.1 kardel c &= 0x7f; 2999 1.1 kardel } 3000 1.1 kardel if (c < ' ') { 3001 1.1 kardel ONEOUT('^'); 3002 1.1 kardel ONEOUT((u_char)(c + '@')); 3003 1.1 kardel } else if (0x7f == c) { 3004 1.1 kardel ONEOUT('^'); 3005 1.1 kardel ONEOUT('?'); 3006 1.1 kardel } else 3007 1.1 kardel ONEOUT(c); 3008 1.1 kardel } 3009 1.1 kardel ONEOUT('\0'); 3010 1.1 kardel 3011 1.1 kardel #undef ONEOUT 3012 1.1 kardel } 3013 1.1 kardel 3014 1.1 kardel 3015 1.1 kardel /* 3016 1.1 kardel * makeascii - print possibly ascii data using the character 3017 1.1 kardel * transformations that cat -v uses. 3018 1.1 kardel */ 3019 1.4 kardel void 3020 1.1 kardel makeascii( 3021 1.14 christos size_t length, 3022 1.4 kardel const char *data, 3023 1.1 kardel FILE *fp 3024 1.1 kardel ) 3025 1.1 kardel { 3026 1.4 kardel const u_char *data_u_char; 3027 1.4 kardel const u_char *cp; 3028 1.4 kardel int c; 3029 1.4 kardel 3030 1.4 kardel data_u_char = (const u_char *)data; 3031 1.1 kardel 3032 1.4 kardel for (cp = data_u_char; cp < data_u_char + length; cp++) { 3033 1.1 kardel c = (int)*cp; 3034 1.1 kardel if (c & 0x80) { 3035 1.1 kardel putc('M', fp); 3036 1.1 kardel putc('-', fp); 3037 1.1 kardel c &= 0x7f; 3038 1.1 kardel } 3039 1.1 kardel 3040 1.1 kardel if (c < ' ') { 3041 1.1 kardel putc('^', fp); 3042 1.1 kardel putc(c + '@', fp); 3043 1.1 kardel } else if (0x7f == c) { 3044 1.1 kardel putc('^', fp); 3045 1.1 kardel putc('?', fp); 3046 1.1 kardel } else 3047 1.1 kardel putc(c, fp); 3048 1.1 kardel } 3049 1.1 kardel } 3050 1.1 kardel 3051 1.1 kardel 3052 1.1 kardel /* 3053 1.1 kardel * asciize - same thing as makeascii except add a newline 3054 1.1 kardel */ 3055 1.1 kardel void 3056 1.1 kardel asciize( 3057 1.1 kardel int length, 3058 1.1 kardel char *data, 3059 1.1 kardel FILE *fp 3060 1.1 kardel ) 3061 1.1 kardel { 3062 1.1 kardel makeascii(length, data, fp); 3063 1.1 kardel putc('\n', fp); 3064 1.1 kardel } 3065 1.1 kardel 3066 1.1 kardel 3067 1.1 kardel /* 3068 1.4 kardel * truncate string to fit clipping excess at end. 3069 1.4 kardel * "too long" -> "too l" 3070 1.4 kardel * Used for hostnames. 3071 1.4 kardel */ 3072 1.4 kardel const char * 3073 1.4 kardel trunc_right( 3074 1.4 kardel const char * src, 3075 1.4 kardel size_t width 3076 1.4 kardel ) 3077 1.4 kardel { 3078 1.4 kardel size_t sl; 3079 1.4 kardel char * out; 3080 1.4 kardel 3081 1.9 christos 3082 1.4 kardel sl = strlen(src); 3083 1.4 kardel if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) { 3084 1.4 kardel LIB_GETBUF(out); 3085 1.4 kardel memcpy(out, src, width); 3086 1.4 kardel out[width] = '\0'; 3087 1.4 kardel 3088 1.4 kardel return out; 3089 1.4 kardel } 3090 1.4 kardel 3091 1.4 kardel return src; 3092 1.4 kardel } 3093 1.4 kardel 3094 1.4 kardel 3095 1.4 kardel /* 3096 1.4 kardel * truncate string to fit by preserving right side and using '_' to hint 3097 1.4 kardel * "too long" -> "_long" 3098 1.4 kardel * Used for local IPv6 addresses, where low bits differentiate. 3099 1.4 kardel */ 3100 1.4 kardel const char * 3101 1.4 kardel trunc_left( 3102 1.4 kardel const char * src, 3103 1.4 kardel size_t width 3104 1.4 kardel ) 3105 1.4 kardel { 3106 1.4 kardel size_t sl; 3107 1.4 kardel char * out; 3108 1.4 kardel 3109 1.4 kardel 3110 1.4 kardel sl = strlen(src); 3111 1.4 kardel if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) { 3112 1.4 kardel LIB_GETBUF(out); 3113 1.4 kardel out[0] = '_'; 3114 1.4 kardel memcpy(&out[1], &src[sl + 1 - width], width); 3115 1.4 kardel 3116 1.4 kardel return out; 3117 1.4 kardel } 3118 1.4 kardel 3119 1.4 kardel return src; 3120 1.4 kardel } 3121 1.4 kardel 3122 1.4 kardel 3123 1.4 kardel /* 3124 1.1 kardel * Some circular buffer space 3125 1.1 kardel */ 3126 1.1 kardel #define CBLEN 80 3127 1.1 kardel #define NUMCB 6 3128 1.1 kardel 3129 1.1 kardel char circ_buf[NUMCB][CBLEN]; 3130 1.1 kardel int nextcb = 0; 3131 1.1 kardel 3132 1.20 christos /* -------------------------------------------------------------------- 3133 1.20 christos * Parsing a response value list 3134 1.20 christos * 3135 1.20 christos * This sounds simple (and it actually is not really hard) but it has 3136 1.20 christos * some pitfalls. 3137 1.20 christos * 3138 1.20 christos * Rule1: CR/LF is never embedded in an item 3139 1.20 christos * Rule2: An item is a name, optionally followed by a value 3140 1.20 christos * Rule3: The value is separated from the name by a '=' 3141 1.20 christos * Rule4: Items are separated by a ',' 3142 1.20 christos * Rule5: values can be quoted by '"', in which case they can contain 3143 1.20 christos * arbitrary characters but *not* '"', CR and LF 3144 1.20 christos * 3145 1.20 christos * There are a few implementations out there that require a somewhat 3146 1.20 christos * relaxed attitude when parsing a value list, especially since we want 3147 1.20 christos * to copy names and values into local buffers. If these would overflow, 3148 1.20 christos * the item should be skipped without terminating the parsing sequence. 3149 1.20 christos * 3150 1.20 christos * Also, for empty values, there might be a '=' after the name or not; 3151 1.20 christos * we treat that equivalent. 3152 1.20 christos * 3153 1.20 christos * Parsing an item definitely breaks on a CR/LF. If an item is not 3154 1.20 christos * followed by a comma (','), parsing stops. In the middle of a quoted 3155 1.20 christos * character sequence CR/LF terminates the parsing finally without 3156 1.20 christos * returning a value. 3157 1.20 christos * 3158 1.20 christos * White space and other noise is ignored when parsing the data buffer; 3159 1.20 christos * only CR, LF, ',', '=' and '"' are characters with a special meaning. 3160 1.20 christos * White space is stripped from the names and values *after* working 3161 1.20 christos * through the buffer, before making the local copies. If whitespace 3162 1.20 christos * stripping results in an empty name, parsing resumes. 3163 1.20 christos */ 3164 1.20 christos 3165 1.20 christos /* 3166 1.20 christos * nextvar parsing helpers 3167 1.20 christos */ 3168 1.20 christos 3169 1.20 christos /* predicate: allowed chars inside a quoted string */ 3170 1.20 christos static int/*BOOL*/ cp_qschar(int ch) 3171 1.20 christos { 3172 1.20 christos return ch && (ch != '"' && ch != '\r' && ch != '\n'); 3173 1.20 christos } 3174 1.20 christos 3175 1.20 christos /* predicate: allowed chars inside an unquoted string */ 3176 1.20 christos static int/*BOOL*/ cp_uqchar(int ch) 3177 1.20 christos { 3178 1.20 christos return ch && (ch != ',' && ch != '"' && ch != '\r' && ch != '\n'); 3179 1.20 christos } 3180 1.20 christos 3181 1.20 christos /* predicate: allowed chars inside a value name */ 3182 1.20 christos static int/*BOOL*/ cp_namechar(int ch) 3183 1.20 christos { 3184 1.23 christos return ch && (ch != ',' && ch != '=' && ch != '\r' && ch != '\n'); 3185 1.20 christos } 3186 1.20 christos 3187 1.20 christos /* predicate: characters *between* list items. We're relaxed here. */ 3188 1.20 christos static int/*BOOL*/ cp_ivspace(int ch) 3189 1.20 christos { 3190 1.23 christos return (ch == ',' || (ch > 0 && ch <= ' ')); 3191 1.20 christos } 3192 1.20 christos 3193 1.20 christos /* get current character (or NUL when on end) */ 3194 1.20 christos static inline int 3195 1.20 christos pf_getch( 3196 1.20 christos const char ** datap, 3197 1.20 christos const char * endp 3198 1.20 christos ) 3199 1.20 christos { 3200 1.20 christos return (*datap != endp) 3201 1.20 christos ? *(const unsigned char*)*datap 3202 1.20 christos : '\0'; 3203 1.20 christos } 3204 1.20 christos 3205 1.20 christos /* get next character (or NUL when on end) */ 3206 1.20 christos static inline int 3207 1.20 christos pf_nextch( 3208 1.20 christos const char ** datap, 3209 1.20 christos const char * endp 3210 1.20 christos ) 3211 1.20 christos { 3212 1.20 christos return (*datap != endp && ++(*datap) != endp) 3213 1.20 christos ? *(const unsigned char*)*datap 3214 1.20 christos : '\0'; 3215 1.20 christos } 3216 1.20 christos 3217 1.20 christos static size_t 3218 1.20 christos str_strip( 3219 1.20 christos const char ** datap, 3220 1.20 christos size_t len 3221 1.20 christos ) 3222 1.20 christos { 3223 1.20 christos static const char empty[] = ""; 3224 1.23 christos 3225 1.20 christos if (*datap && len) { 3226 1.20 christos const char * cpl = *datap; 3227 1.20 christos const char * cpr = cpl + len; 3228 1.23 christos 3229 1.20 christos while (cpl != cpr && *(const unsigned char*)cpl <= ' ') 3230 1.20 christos ++cpl; 3231 1.20 christos while (cpl != cpr && *(const unsigned char*)(cpr - 1) <= ' ') 3232 1.20 christos --cpr; 3233 1.23 christos *datap = cpl; 3234 1.20 christos len = (size_t)(cpr - cpl); 3235 1.20 christos } else { 3236 1.20 christos *datap = empty; 3237 1.20 christos len = 0; 3238 1.20 christos } 3239 1.20 christos return len; 3240 1.20 christos } 3241 1.20 christos 3242 1.20 christos static void 3243 1.20 christos pf_error( 3244 1.20 christos const char * what, 3245 1.20 christos const char * where, 3246 1.20 christos const char * whend 3247 1.20 christos ) 3248 1.20 christos { 3249 1.20 christos # ifndef BUILD_AS_LIB 3250 1.23 christos 3251 1.20 christos FILE * ofp = (debug > 0) ? stdout : stderr; 3252 1.20 christos size_t len = (size_t)(whend - where); 3253 1.23 christos 3254 1.20 christos if (len > 50) /* *must* fit into an 'int'! */ 3255 1.20 christos len = 50; 3256 1.20 christos fprintf(ofp, "nextvar: %s: '%.*s'\n", 3257 1.20 christos what, (int)len, where); 3258 1.23 christos 3259 1.20 christos # else /*defined(BUILD_AS_LIB)*/ 3260 1.20 christos 3261 1.20 christos UNUSED_ARG(what); 3262 1.20 christos UNUSED_ARG(where); 3263 1.20 christos UNUSED_ARG(whend); 3264 1.23 christos 3265 1.20 christos # endif /*defined(BUILD_AS_LIB)*/ 3266 1.20 christos } 3267 1.20 christos 3268 1.1 kardel /* 3269 1.1 kardel * nextvar - find the next variable in the buffer 3270 1.1 kardel */ 3271 1.20 christos int/*BOOL*/ 3272 1.1 kardel nextvar( 3273 1.14 christos size_t *datalen, 3274 1.4 kardel const char **datap, 3275 1.1 kardel char **vname, 3276 1.1 kardel char **vvalue 3277 1.1 kardel ) 3278 1.1 kardel { 3279 1.20 christos enum PState { sDone, sInit, sName, sValU, sValQ }; 3280 1.23 christos 3281 1.20 christos static char name[MAXVARLEN], value[MAXVALLEN]; 3282 1.1 kardel 3283 1.20 christos const char *cp, *cpend; 3284 1.20 christos const char *np, *vp; 3285 1.20 christos size_t nlen, vlen; 3286 1.20 christos int ch; 3287 1.20 christos enum PState st; 3288 1.23 christos 3289 1.20 christos cpend = *datap + *datalen; 3290 1.1 kardel 3291 1.20 christos again: 3292 1.20 christos np = vp = NULL; 3293 1.20 christos nlen = vlen = 0; 3294 1.23 christos 3295 1.20 christos st = sInit; 3296 1.20 christos ch = pf_getch(datap, cpend); 3297 1.9 christos 3298 1.20 christos while (st != sDone) { 3299 1.20 christos switch (st) 3300 1.20 christos { 3301 1.20 christos case sInit: /* handle inter-item chars */ 3302 1.20 christos while (cp_ivspace(ch)) 3303 1.20 christos ch = pf_nextch(datap, cpend); 3304 1.20 christos if (cp_namechar(ch)) { 3305 1.20 christos np = *datap; 3306 1.20 christos cp = np; 3307 1.20 christos st = sName; 3308 1.20 christos ch = pf_nextch(datap, cpend); 3309 1.20 christos } else { 3310 1.20 christos goto final_done; 3311 1.20 christos } 3312 1.20 christos break; 3313 1.23 christos 3314 1.20 christos case sName: /* collect name */ 3315 1.20 christos while (cp_namechar(ch)) 3316 1.20 christos ch = pf_nextch(datap, cpend); 3317 1.20 christos nlen = (size_t)(*datap - np); 3318 1.20 christos if (ch == '=') { 3319 1.20 christos ch = pf_nextch(datap, cpend); 3320 1.20 christos vp = *datap; 3321 1.20 christos st = sValU; 3322 1.20 christos } else { 3323 1.20 christos if (ch != ',') 3324 1.20 christos *datap = cpend; 3325 1.20 christos st = sDone; 3326 1.20 christos } 3327 1.20 christos break; 3328 1.23 christos 3329 1.20 christos case sValU: /* collect unquoted part(s) of value */ 3330 1.20 christos while (cp_uqchar(ch)) 3331 1.20 christos ch = pf_nextch(datap, cpend); 3332 1.20 christos if (ch == '"') { 3333 1.20 christos ch = pf_nextch(datap, cpend); 3334 1.20 christos st = sValQ; 3335 1.20 christos } else { 3336 1.20 christos vlen = (size_t)(*datap - vp); 3337 1.20 christos if (ch != ',') 3338 1.20 christos *datap = cpend; 3339 1.20 christos st = sDone; 3340 1.20 christos } 3341 1.20 christos break; 3342 1.23 christos 3343 1.20 christos case sValQ: /* collect quoted part(s) of value */ 3344 1.20 christos while (cp_qschar(ch)) 3345 1.20 christos ch = pf_nextch(datap, cpend); 3346 1.20 christos if (ch == '"') { 3347 1.20 christos ch = pf_nextch(datap, cpend); 3348 1.20 christos st = sValU; 3349 1.20 christos } else { 3350 1.20 christos pf_error("no closing quote, stop", cp, cpend); 3351 1.20 christos goto final_done; 3352 1.20 christos } 3353 1.20 christos break; 3354 1.23 christos 3355 1.20 christos default: 3356 1.20 christos pf_error("state machine error, stop", *datap, cpend); 3357 1.20 christos goto final_done; 3358 1.20 christos } 3359 1.20 christos } 3360 1.1 kardel 3361 1.20 christos /* If name or value do not fit their buffer, croak and start 3362 1.20 christos * over. If there's no name at all after whitespace stripping, 3363 1.20 christos * redo silently. 3364 1.1 kardel */ 3365 1.20 christos nlen = str_strip(&np, nlen); 3366 1.20 christos vlen = str_strip(&vp, vlen); 3367 1.23 christos 3368 1.20 christos if (nlen == 0) { 3369 1.20 christos goto again; 3370 1.20 christos } 3371 1.20 christos if (nlen >= sizeof(name)) { 3372 1.20 christos pf_error("runaway name", np, cpend); 3373 1.20 christos goto again; 3374 1.1 kardel } 3375 1.20 christos if (vlen >= sizeof(value)) { 3376 1.20 christos pf_error("runaway value", vp, cpend); 3377 1.20 christos goto again; 3378 1.1 kardel } 3379 1.1 kardel 3380 1.20 christos /* copy name and value into NUL-terminated buffers */ 3381 1.20 christos memcpy(name, np, nlen); 3382 1.20 christos name[nlen] = '\0'; 3383 1.20 christos *vname = name; 3384 1.23 christos 3385 1.20 christos memcpy(value, vp, vlen); 3386 1.20 christos value[vlen] = '\0'; 3387 1.1 kardel *vvalue = value; 3388 1.20 christos 3389 1.20 christos /* check if there's more to do or if we are finshed */ 3390 1.20 christos *datalen = (size_t)(cpend - *datap); 3391 1.20 christos return TRUE; 3392 1.20 christos 3393 1.20 christos final_done: 3394 1.20 christos *datap = cpend; 3395 1.20 christos *datalen = 0; 3396 1.20 christos return FALSE; 3397 1.1 kardel } 3398 1.1 kardel 3399 1.1 kardel 3400 1.9 christos u_short 3401 1.9 christos varfmt(const char * varname) 3402 1.9 christos { 3403 1.9 christos u_int n; 3404 1.9 christos 3405 1.9 christos for (n = 0; n < COUNTOF(cookedvars); n++) 3406 1.9 christos if (!strcmp(varname, cookedvars[n].varname)) 3407 1.9 christos return cookedvars[n].fmt; 3408 1.9 christos 3409 1.9 christos return PADDING; 3410 1.1 kardel } 3411 1.1 kardel 3412 1.1 kardel 3413 1.1 kardel /* 3414 1.1 kardel * printvars - print variables returned in response packet 3415 1.1 kardel */ 3416 1.1 kardel void 3417 1.1 kardel printvars( 3418 1.14 christos size_t length, 3419 1.4 kardel const char *data, 3420 1.1 kardel int status, 3421 1.1 kardel int sttype, 3422 1.1 kardel int quiet, 3423 1.1 kardel FILE *fp 3424 1.1 kardel ) 3425 1.1 kardel { 3426 1.1 kardel if (rawmode) 3427 1.1 kardel rawprint(sttype, length, data, status, quiet, fp); 3428 1.1 kardel else 3429 1.1 kardel cookedprint(sttype, length, data, status, quiet, fp); 3430 1.1 kardel } 3431 1.1 kardel 3432 1.1 kardel 3433 1.1 kardel /* 3434 1.1 kardel * rawprint - do a printout of the data in raw mode 3435 1.1 kardel */ 3436 1.1 kardel static void 3437 1.1 kardel rawprint( 3438 1.1 kardel int datatype, 3439 1.14 christos size_t length, 3440 1.4 kardel const char *data, 3441 1.1 kardel int status, 3442 1.1 kardel int quiet, 3443 1.1 kardel FILE *fp 3444 1.1 kardel ) 3445 1.1 kardel { 3446 1.4 kardel const char *cp; 3447 1.4 kardel const char *cpend; 3448 1.1 kardel 3449 1.1 kardel /* 3450 1.1 kardel * Essentially print the data as is. We reformat unprintables, though. 3451 1.1 kardel */ 3452 1.1 kardel cp = data; 3453 1.1 kardel cpend = data + length; 3454 1.1 kardel 3455 1.1 kardel if (!quiet) 3456 1.1 kardel (void) fprintf(fp, "status=0x%04x,\n", status); 3457 1.1 kardel 3458 1.1 kardel while (cp < cpend) { 3459 1.1 kardel if (*cp == '\r') { 3460 1.1 kardel /* 3461 1.1 kardel * If this is a \r and the next character is a 3462 1.1 kardel * \n, supress this, else pretty print it. Otherwise 3463 1.1 kardel * just output the character. 3464 1.1 kardel */ 3465 1.1 kardel if (cp == (cpend - 1) || *(cp + 1) != '\n') 3466 1.1 kardel makeascii(1, cp, fp); 3467 1.19 christos } else if (isspace(pgetc(cp)) || isprint(pgetc(cp))) 3468 1.1 kardel putc(*cp, fp); 3469 1.1 kardel else 3470 1.1 kardel makeascii(1, cp, fp); 3471 1.1 kardel cp++; 3472 1.1 kardel } 3473 1.1 kardel } 3474 1.1 kardel 3475 1.1 kardel 3476 1.1 kardel /* 3477 1.1 kardel * Global data used by the cooked output routines 3478 1.1 kardel */ 3479 1.1 kardel int out_chars; /* number of characters output */ 3480 1.1 kardel int out_linecount; /* number of characters output on this line */ 3481 1.1 kardel 3482 1.1 kardel 3483 1.1 kardel /* 3484 1.1 kardel * startoutput - get ready to do cooked output 3485 1.1 kardel */ 3486 1.1 kardel static void 3487 1.1 kardel startoutput(void) 3488 1.1 kardel { 3489 1.1 kardel out_chars = 0; 3490 1.1 kardel out_linecount = 0; 3491 1.1 kardel } 3492 1.1 kardel 3493 1.1 kardel 3494 1.1 kardel /* 3495 1.1 kardel * output - output a variable=value combination 3496 1.1 kardel */ 3497 1.1 kardel static void 3498 1.1 kardel output( 3499 1.1 kardel FILE *fp, 3500 1.9 christos const char *name, 3501 1.4 kardel const char *value 3502 1.1 kardel ) 3503 1.1 kardel { 3504 1.14 christos int len; 3505 1.1 kardel 3506 1.1 kardel /* strlen of "name=value" */ 3507 1.14 christos len = size2int_sat(strlen(name) + 1 + strlen(value)); 3508 1.1 kardel 3509 1.1 kardel if (out_chars != 0) { 3510 1.1 kardel out_chars += 2; 3511 1.1 kardel if ((out_linecount + len + 2) > MAXOUTLINE) { 3512 1.1 kardel fputs(",\n", fp); 3513 1.1 kardel out_linecount = 0; 3514 1.1 kardel } else { 3515 1.1 kardel fputs(", ", fp); 3516 1.1 kardel out_linecount += 2; 3517 1.1 kardel } 3518 1.1 kardel } 3519 1.1 kardel 3520 1.1 kardel fputs(name, fp); 3521 1.1 kardel putc('=', fp); 3522 1.1 kardel fputs(value, fp); 3523 1.1 kardel out_chars += len; 3524 1.1 kardel out_linecount += len; 3525 1.1 kardel } 3526 1.1 kardel 3527 1.1 kardel 3528 1.1 kardel /* 3529 1.1 kardel * endoutput - terminate a block of cooked output 3530 1.1 kardel */ 3531 1.1 kardel static void 3532 1.1 kardel endoutput( 3533 1.1 kardel FILE *fp 3534 1.1 kardel ) 3535 1.1 kardel { 3536 1.1 kardel if (out_chars != 0) 3537 1.1 kardel putc('\n', fp); 3538 1.1 kardel } 3539 1.1 kardel 3540 1.1 kardel 3541 1.1 kardel /* 3542 1.1 kardel * outputarr - output an array of values 3543 1.1 kardel */ 3544 1.1 kardel static void 3545 1.1 kardel outputarr( 3546 1.1 kardel FILE *fp, 3547 1.1 kardel char *name, 3548 1.1 kardel int narr, 3549 1.21 christos l_fp *lfp, 3550 1.21 christos int issigned 3551 1.1 kardel ) 3552 1.1 kardel { 3553 1.14 christos char *bp; 3554 1.14 christos char *cp; 3555 1.14 christos size_t i; 3556 1.14 christos size_t len; 3557 1.1 kardel char buf[256]; 3558 1.1 kardel 3559 1.1 kardel bp = buf; 3560 1.1 kardel /* 3561 1.1 kardel * Hack to align delay and offset values 3562 1.1 kardel */ 3563 1.1 kardel for (i = (int)strlen(name); i < 11; i++) 3564 1.20 christos *bp++ = ' '; 3565 1.9 christos 3566 1.1 kardel for (i = narr; i > 0; i--) { 3567 1.14 christos if (i != (size_t)narr) 3568 1.20 christos *bp++ = ' '; 3569 1.21 christos cp = (issigned ? lfptoms(lfp, 2) : ulfptoms(lfp, 2)); 3570 1.1 kardel len = strlen(cp); 3571 1.1 kardel if (len > 7) { 3572 1.1 kardel cp[7] = '\0'; 3573 1.1 kardel len = 7; 3574 1.1 kardel } 3575 1.1 kardel while (len < 7) { 3576 1.1 kardel *bp++ = ' '; 3577 1.1 kardel len++; 3578 1.1 kardel } 3579 1.1 kardel while (*cp != '\0') 3580 1.1 kardel *bp++ = *cp++; 3581 1.1 kardel lfp++; 3582 1.1 kardel } 3583 1.1 kardel *bp = '\0'; 3584 1.1 kardel output(fp, name, buf); 3585 1.1 kardel } 3586 1.1 kardel 3587 1.1 kardel static char * 3588 1.1 kardel tstflags( 3589 1.1 kardel u_long val 3590 1.1 kardel ) 3591 1.1 kardel { 3592 1.20 christos # if CBLEN < 10 3593 1.23 christos # error CBLEN is too small -- increase! 3594 1.20 christos # endif 3595 1.20 christos 3596 1.20 christos char *cp, *s; 3597 1.20 christos size_t cb, i; 3598 1.20 christos int l; 3599 1.1 kardel 3600 1.4 kardel s = cp = circ_buf[nextcb]; 3601 1.1 kardel if (++nextcb >= NUMCB) 3602 1.4 kardel nextcb = 0; 3603 1.4 kardel cb = sizeof(circ_buf[0]); 3604 1.1 kardel 3605 1.20 christos l = snprintf(cp, cb, "%02lx", val); 3606 1.20 christos if (l < 0 || (size_t)l >= cb) 3607 1.20 christos goto fail; 3608 1.20 christos cp += l; 3609 1.20 christos cb -= l; 3610 1.1 kardel if (!val) { 3611 1.20 christos l = strlcat(cp, " ok", cb); 3612 1.20 christos if ((size_t)l >= cb) 3613 1.20 christos goto fail; 3614 1.20 christos cp += l; 3615 1.20 christos cb -= l; 3616 1.1 kardel } else { 3617 1.20 christos const char *sep; 3618 1.23 christos 3619 1.20 christos sep = " "; 3620 1.20 christos for (i = 0; i < COUNTOF(tstflagnames); i++) { 3621 1.1 kardel if (val & 0x1) { 3622 1.20 christos l = snprintf(cp, cb, "%s%s", sep, 3623 1.20 christos tstflagnames[i]); 3624 1.20 christos if (l < 0) 3625 1.20 christos goto fail; 3626 1.20 christos if ((size_t)l >= cb) { 3627 1.20 christos cp += cb - 4; 3628 1.20 christos cb = 4; 3629 1.20 christos l = strlcpy (cp, "...", cb); 3630 1.20 christos cp += l; 3631 1.20 christos cb -= l; 3632 1.20 christos break; 3633 1.20 christos } 3634 1.1 kardel sep = ", "; 3635 1.20 christos cp += l; 3636 1.20 christos cb -= l; 3637 1.1 kardel } 3638 1.1 kardel val >>= 1; 3639 1.1 kardel } 3640 1.1 kardel } 3641 1.4 kardel 3642 1.1 kardel return s; 3643 1.20 christos 3644 1.20 christos fail: 3645 1.20 christos *cp = '\0'; 3646 1.20 christos return s; 3647 1.1 kardel } 3648 1.1 kardel 3649 1.1 kardel /* 3650 1.1 kardel * cookedprint - output variables in cooked mode 3651 1.1 kardel */ 3652 1.1 kardel static void 3653 1.1 kardel cookedprint( 3654 1.1 kardel int datatype, 3655 1.14 christos size_t length, 3656 1.4 kardel const char *data, 3657 1.1 kardel int status, 3658 1.1 kardel int quiet, 3659 1.1 kardel FILE *fp 3660 1.1 kardel ) 3661 1.1 kardel { 3662 1.1 kardel char *name; 3663 1.1 kardel char *value; 3664 1.1 kardel char output_raw; 3665 1.1 kardel int fmt; 3666 1.1 kardel l_fp lfp; 3667 1.1 kardel sockaddr_u hval; 3668 1.1 kardel u_long uval; 3669 1.9 christos int narr; 3670 1.9 christos size_t len; 3671 1.1 kardel l_fp lfparr[8]; 3672 1.9 christos char b[12]; 3673 1.9 christos char bn[2 * MAXVARLEN]; 3674 1.9 christos char bv[2 * MAXVALLEN]; 3675 1.1 kardel 3676 1.9 christos UNUSED_ARG(datatype); 3677 1.1 kardel 3678 1.1 kardel if (!quiet) 3679 1.1 kardel fprintf(fp, "status=%04x %s,\n", status, 3680 1.1 kardel statustoa(datatype, status)); 3681 1.1 kardel 3682 1.1 kardel startoutput(); 3683 1.1 kardel while (nextvar(&length, &data, &name, &value)) { 3684 1.9 christos fmt = varfmt(name); 3685 1.9 christos output_raw = 0; 3686 1.9 christos switch (fmt) { 3687 1.9 christos 3688 1.9 christos case PADDING: 3689 1.1 kardel output_raw = '*'; 3690 1.9 christos break; 3691 1.9 christos 3692 1.9 christos case TS: 3693 1.19 christos if (!value || !decodets(value, &lfp)) 3694 1.9 christos output_raw = '?'; 3695 1.9 christos else 3696 1.9 christos output(fp, name, prettydate(&lfp)); 3697 1.9 christos break; 3698 1.9 christos 3699 1.9 christos case HA: /* fallthru */ 3700 1.9 christos case NA: 3701 1.19 christos if (!value || !decodenetnum(value, &hval)) { 3702 1.9 christos output_raw = '?'; 3703 1.9 christos } else if (fmt == HA){ 3704 1.9 christos output(fp, name, nntohost(&hval)); 3705 1.9 christos } else { 3706 1.9 christos output(fp, name, stoa(&hval)); 3707 1.9 christos } 3708 1.9 christos break; 3709 1.1 kardel 3710 1.9 christos case RF: 3711 1.19 christos if (!value) { 3712 1.19 christos output_raw = '?'; 3713 1.19 christos } else if (decodenetnum(value, &hval)) { 3714 1.21 christos if (datatype == TYPE_CLOCK && IS_IPV4(&hval)) { 3715 1.21 christos /* 3716 1.23 christos * Workaround to override numeric refid formats 3717 1.23 christos * for refclocks received from faulty nptd servers 3718 1.21 christos * and output them as text. 3719 1.21 christos */ 3720 1.21 christos int i; 3721 1.21 christos unsigned char *str = (unsigned char *)&(hval.sa4).sin_addr; 3722 1.21 christos char refid_buf[5]; 3723 1.21 christos for (i=0; i<4 && str[i]; i++) 3724 1.21 christos refid_buf[i] = (isprint(str[i]) ? str[i] : '?'); 3725 1.21 christos refid_buf[i] = 0; /* Null terminator */ 3726 1.21 christos output(fp, name, refid_buf); 3727 1.21 christos } else if (ISREFCLOCKADR(&hval)) { 3728 1.21 christos output(fp, name, refnumtoa(&hval)); 3729 1.21 christos } else { 3730 1.21 christos if (drefid == REFID_IPV4) { 3731 1.21 christos output(fp, name, stoa(&hval)); 3732 1.21 christos } else { 3733 1.21 christos char refid_buf[12]; 3734 1.23 christos snprintf (refid_buf, sizeof(refid_buf), 3735 1.21 christos "0x%08x", ntohl(addr2refid(&hval))); 3736 1.21 christos output(fp, name, refid_buf); 3737 1.21 christos } 3738 1.21 christos } 3739 1.9 christos } else if (strlen(value) <= 4) { 3740 1.9 christos output(fp, name, value); 3741 1.9 christos } else { 3742 1.9 christos output_raw = '?'; 3743 1.9 christos } 3744 1.9 christos break; 3745 1.1 kardel 3746 1.9 christos case LP: 3747 1.19 christos if (!value || !decodeuint(value, &uval) || uval > 3) { 3748 1.9 christos output_raw = '?'; 3749 1.9 christos } else { 3750 1.9 christos b[0] = (0x2 & uval) 3751 1.9 christos ? '1' 3752 1.9 christos : '0'; 3753 1.9 christos b[1] = (0x1 & uval) 3754 1.9 christos ? '1' 3755 1.9 christos : '0'; 3756 1.9 christos b[2] = '\0'; 3757 1.9 christos output(fp, name, b); 3758 1.9 christos } 3759 1.9 christos break; 3760 1.1 kardel 3761 1.9 christos case OC: 3762 1.19 christos if (!value || !decodeuint(value, &uval)) { 3763 1.9 christos output_raw = '?'; 3764 1.9 christos } else { 3765 1.9 christos snprintf(b, sizeof(b), "%03lo", uval); 3766 1.9 christos output(fp, name, b); 3767 1.9 christos } 3768 1.9 christos break; 3769 1.1 kardel 3770 1.21 christos case AU: 3771 1.21 christos case AS: 3772 1.19 christos if (!value || !decodearr(value, &narr, lfparr, 8)) 3773 1.9 christos output_raw = '?'; 3774 1.9 christos else 3775 1.21 christos outputarr(fp, name, narr, lfparr, (fmt==AS)); 3776 1.9 christos break; 3777 1.1 kardel 3778 1.9 christos case FX: 3779 1.19 christos if (!value || !decodeuint(value, &uval)) 3780 1.9 christos output_raw = '?'; 3781 1.9 christos else 3782 1.9 christos output(fp, name, tstflags(uval)); 3783 1.9 christos break; 3784 1.1 kardel 3785 1.21 christos case SN: 3786 1.21 christos if (!value) 3787 1.21 christos output_raw = '?'; 3788 1.22 christos else if (isdigit(*(const unsigned char *)value)) { /* number without sign */ 3789 1.21 christos bv[0] = '+'; 3790 1.21 christos atoascii (value, MAXVALLEN, bv+1, sizeof(bv)-1); 3791 1.21 christos output(fp, name, bv); 3792 1.21 christos } else 3793 1.21 christos output_raw = '*'; /* output as-is */ 3794 1.21 christos break; 3795 1.21 christos 3796 1.9 christos default: 3797 1.9 christos fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n", 3798 1.9 christos name, value, fmt); 3799 1.9 christos output_raw = '?'; 3800 1.9 christos break; 3801 1.1 kardel } 3802 1.9 christos 3803 1.1 kardel if (output_raw != 0) { 3804 1.13 christos /* TALOS-CAN-0063: avoid buffer overrun */ 3805 1.1 kardel atoascii(name, MAXVARLEN, bn, sizeof(bn)); 3806 1.1 kardel if (output_raw != '*') { 3807 1.13 christos atoascii(value, MAXVALLEN, 3808 1.13 christos bv, sizeof(bv) - 1); 3809 1.1 kardel len = strlen(bv); 3810 1.1 kardel bv[len] = output_raw; 3811 1.1 kardel bv[len+1] = '\0'; 3812 1.13 christos } else { 3813 1.13 christos atoascii(value, MAXVALLEN, 3814 1.13 christos bv, sizeof(bv)); 3815 1.1 kardel } 3816 1.1 kardel output(fp, bn, bv); 3817 1.1 kardel } 3818 1.1 kardel } 3819 1.1 kardel endoutput(fp); 3820 1.1 kardel } 3821 1.1 kardel 3822 1.1 kardel 3823 1.1 kardel /* 3824 1.1 kardel * sortassoc - sort associations in the cache into ascending order 3825 1.1 kardel */ 3826 1.1 kardel void 3827 1.1 kardel sortassoc(void) 3828 1.1 kardel { 3829 1.1 kardel if (numassoc > 1) 3830 1.9 christos qsort(assoc_cache, (size_t)numassoc, 3831 1.9 christos sizeof(assoc_cache[0]), &assoccmp); 3832 1.1 kardel } 3833 1.1 kardel 3834 1.1 kardel 3835 1.1 kardel /* 3836 1.1 kardel * assoccmp - compare two associations 3837 1.1 kardel */ 3838 1.1 kardel static int 3839 1.1 kardel assoccmp( 3840 1.1 kardel const void *t1, 3841 1.1 kardel const void *t2 3842 1.1 kardel ) 3843 1.1 kardel { 3844 1.4 kardel const struct association *ass1 = t1; 3845 1.4 kardel const struct association *ass2 = t2; 3846 1.1 kardel 3847 1.1 kardel if (ass1->assid < ass2->assid) 3848 1.1 kardel return -1; 3849 1.1 kardel if (ass1->assid > ass2->assid) 3850 1.1 kardel return 1; 3851 1.1 kardel return 0; 3852 1.1 kardel } 3853 1.4 kardel 3854 1.1 kardel 3855 1.1 kardel /* 3856 1.9 christos * grow_assoc_cache() - enlarge dynamic assoc_cache array 3857 1.9 christos * 3858 1.9 christos * The strategy is to add an assumed 4k page size at a time, leaving 3859 1.9 christos * room for malloc() bookkeeping overhead equivalent to 4 pointers. 3860 1.9 christos */ 3861 1.9 christos void 3862 1.9 christos grow_assoc_cache(void) 3863 1.9 christos { 3864 1.9 christos static size_t prior_sz; 3865 1.9 christos size_t new_sz; 3866 1.9 christos 3867 1.9 christos new_sz = prior_sz + 4 * 1024; 3868 1.9 christos if (0 == prior_sz) { 3869 1.9 christos new_sz -= 4 * sizeof(void *); 3870 1.9 christos } 3871 1.23 christos assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz); 3872 1.9 christos prior_sz = new_sz; 3873 1.14 christos assoc_cache_slots = (u_int)(new_sz / sizeof(assoc_cache[0])); 3874 1.9 christos } 3875 1.9 christos 3876 1.9 christos 3877 1.9 christos /* 3878 1.1 kardel * ntpq_custom_opt_handler - autoopts handler for -c and -p 3879 1.1 kardel * 3880 1.1 kardel * By default, autoopts loses the relative order of -c and -p options 3881 1.1 kardel * on the command line. This routine replaces the default handler for 3882 1.1 kardel * those routines and builds a list of commands to execute preserving 3883 1.1 kardel * the order. 3884 1.1 kardel */ 3885 1.1 kardel void 3886 1.1 kardel ntpq_custom_opt_handler( 3887 1.1 kardel tOptions *pOptions, 3888 1.1 kardel tOptDesc *pOptDesc 3889 1.1 kardel ) 3890 1.1 kardel { 3891 1.1 kardel switch (pOptDesc->optValue) { 3892 1.9 christos 3893 1.1 kardel default: 3894 1.9 christos fprintf(stderr, 3895 1.1 kardel "ntpq_custom_opt_handler unexpected option '%c' (%d)\n", 3896 1.1 kardel pOptDesc->optValue, pOptDesc->optValue); 3897 1.9 christos exit(1); 3898 1.1 kardel 3899 1.1 kardel case 'c': 3900 1.23 christos if ((pOptDesc->fOptState & OPTST_SET_MASK) == OPTST_DEFINED) 3901 1.23 christos defcmds++; 3902 1.1 kardel ADDCMD(pOptDesc->pzLastArg); 3903 1.1 kardel break; 3904 1.1 kardel 3905 1.1 kardel case 'p': 3906 1.23 christos if ((pOptDesc->fOptState & OPTST_SET_MASK) == OPTST_DEFINED) 3907 1.23 christos defcmds++; 3908 1.1 kardel ADDCMD("peers"); 3909 1.1 kardel break; 3910 1.1 kardel } 3911 1.1 kardel } 3912 1.12 christos /* 3913 1.12 christos * Obtain list of digest names 3914 1.12 christos */ 3915 1.12 christos 3916 1.19 christos #if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED) 3917 1.19 christos # if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L 3918 1.19 christos # define HAVE_EVP_MD_DO_ALL_SORTED 3919 1.19 christos # endif 3920 1.19 christos #endif 3921 1.19 christos 3922 1.12 christos #ifdef OPENSSL 3923 1.12 christos # ifdef HAVE_EVP_MD_DO_ALL_SORTED 3924 1.19 christos # define K_PER_LINE 8 3925 1.19 christos # define K_NL_PFX_STR "\n " 3926 1.19 christos # define K_DELIM_STR ", " 3927 1.19 christos 3928 1.12 christos struct hstate { 3929 1.20 christos char *list; 3930 1.23 christos char const **seen; 3931 1.20 christos int idx; 3932 1.12 christos }; 3933 1.19 christos 3934 1.19 christos 3935 1.20 christos # ifndef BUILD_AS_LIB 3936 1.19 christos static void 3937 1.19 christos list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg) 3938 1.12 christos { 3939 1.20 christos size_t len, n; 3940 1.20 christos const char *name, **seen; 3941 1.20 christos struct hstate *hstate = arg; 3942 1.23 christos 3943 1.20 christos /* m is MD obj, from is name or alias, to is base name for alias */ 3944 1.23 christos if (!m || !from || to) { 3945 1.20 christos return; /* Ignore aliases */ 3946 1.23 christos } 3947 1.20 christos 3948 1.20 christos /* Discard MACs that NTP won't accept. */ 3949 1.20 christos /* Keep this consistent with keytype_from_text() in ssl_init.c. */ 3950 1.23 christos if ((size_t)EVP_MD_size(m) > MAX_MDG_LEN) { 3951 1.20 christos return; 3952 1.23 christos } 3953 1.23 christos 3954 1.20 christos name = EVP_MD_name(m); 3955 1.23 christos len = strlen(name) + 1; 3956 1.12 christos 3957 1.20 christos /* There are duplicates. Discard if name has been seen. */ 3958 1.23 christos 3959 1.20 christos for (seen = hstate->seen; *seen; seen++) 3960 1.23 christos if (!strcasecmp(*seen, name)) 3961 1.20 christos return; 3962 1.12 christos 3963 1.20 christos n = (seen - hstate->seen) + 2; 3964 1.23 christos hstate->seen = erealloc((void *)hstate->seen, n * sizeof(*seen)); 3965 1.20 christos hstate->seen[n-2] = name; 3966 1.20 christos hstate->seen[n-1] = NULL; 3967 1.23 christos 3968 1.20 christos if (hstate->list != NULL) 3969 1.20 christos len += strlen(hstate->list); 3970 1.12 christos 3971 1.20 christos len += (hstate->idx >= K_PER_LINE) 3972 1.20 christos ? strlen(K_NL_PFX_STR) 3973 1.20 christos : strlen(K_DELIM_STR); 3974 1.20 christos 3975 1.20 christos if (hstate->list == NULL) { 3976 1.20 christos hstate->list = (char *)emalloc(len); 3977 1.20 christos hstate->list[0] = '\0'; 3978 1.20 christos } else { 3979 1.20 christos hstate->list = (char *)erealloc(hstate->list, len); 3980 1.19 christos } 3981 1.23 christos 3982 1.20 christos sprintf(hstate->list + strlen(hstate->list), "%s%s", 3983 1.20 christos ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR), 3984 1.20 christos name); 3985 1.23 christos 3986 1.20 christos if (hstate->idx >= K_PER_LINE) 3987 1.20 christos hstate->idx = 1; 3988 1.20 christos else 3989 1.20 christos hstate->idx++; 3990 1.19 christos } 3991 1.20 christos # endif /* !defined(BUILD_AS_LIB) */ 3992 1.19 christos 3993 1.20 christos # ifndef BUILD_AS_LIB 3994 1.19 christos /* Insert CMAC into SSL digests list */ 3995 1.19 christos static char * 3996 1.19 christos insert_cmac(char *list) 3997 1.19 christos { 3998 1.20 christos #ifdef ENABLE_CMAC 3999 1.20 christos int insert; 4000 1.20 christos size_t len; 4001 1.19 christos 4002 1.19 christos 4003 1.20 christos /* If list empty, we need to insert CMAC on new line */ 4004 1.20 christos insert = (!list || !*list); 4005 1.23 christos 4006 1.19 christos if (insert) { 4007 1.20 christos len = strlen(K_NL_PFX_STR) + strlen(CMAC); 4008 1.19 christos list = (char *)erealloc(list, len + 1); 4009 1.20 christos sprintf(list, "%s%s", K_NL_PFX_STR, CMAC); 4010 1.20 christos } else { /* List not empty */ 4011 1.20 christos /* Check if CMAC already in list - future proofing */ 4012 1.20 christos const char *cmac_sn; 4013 1.20 christos char *cmac_p; 4014 1.23 christos 4015 1.20 christos cmac_sn = OBJ_nid2sn(NID_cmac); 4016 1.20 christos cmac_p = list; 4017 1.20 christos insert = cmac_sn != NULL && *cmac_sn != '\0'; 4018 1.23 christos 4019 1.20 christos /* CMAC in list if found, followed by nul char or ',' */ 4020 1.20 christos while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) { 4021 1.20 christos cmac_p += strlen(cmac_sn); 4022 1.20 christos /* Still need to insert if not nul and not ',' */ 4023 1.20 christos insert = *cmac_p && ',' != *cmac_p; 4024 1.20 christos } 4025 1.23 christos 4026 1.20 christos /* Find proper insertion point */ 4027 1.20 christos if (insert) { 4028 1.20 christos char *last_nl; 4029 1.20 christos char *point; 4030 1.20 christos char *delim; 4031 1.20 christos int found; 4032 1.23 christos 4033 1.20 christos /* Default to start if list empty */ 4034 1.20 christos found = 0; 4035 1.20 christos delim = list; 4036 1.20 christos len = strlen(list); 4037 1.23 christos 4038 1.20 christos /* While new lines */ 4039 1.20 christos while (delim < list + len && *delim && 4040 1.20 christos !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) { 4041 1.20 christos point = delim + strlen(K_NL_PFX_STR); 4042 1.23 christos 4043 1.20 christos /* While digest names on line */ 4044 1.20 christos while (point < list + len && *point) { 4045 1.20 christos /* Another digest after on same or next line? */ 4046 1.20 christos delim = strstr( point, K_DELIM_STR); 4047 1.20 christos last_nl = strstr( point, K_NL_PFX_STR); 4048 1.23 christos 4049 1.20 christos /* No - end of list */ 4050 1.20 christos if (!delim && !last_nl) { 4051 1.20 christos delim = list + len; 4052 1.23 christos } else { 4053 1.20 christos /* New line and no delim or before delim? */ 4054 1.20 christos if (last_nl && (!delim || last_nl < delim)) { 4055 1.20 christos delim = last_nl; 4056 1.20 christos } 4057 1.23 christos } 4058 1.23 christos 4059 1.20 christos /* Found insertion point where CMAC before entry? */ 4060 1.20 christos if (strncmp(CMAC, point, delim - point) < 0) { 4061 1.20 christos found = 1; 4062 1.20 christos break; 4063 1.20 christos } 4064 1.23 christos 4065 1.20 christos if (delim < list + len && *delim && 4066 1.20 christos !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) { 4067 1.20 christos point += strlen(K_DELIM_STR); 4068 1.20 christos } else { 4069 1.20 christos break; 4070 1.20 christos } 4071 1.20 christos } /* While digest names on line */ 4072 1.20 christos } /* While new lines */ 4073 1.23 christos 4074 1.20 christos /* If found in list */ 4075 1.20 christos if (found) { 4076 1.20 christos /* insert cmac and delim */ 4077 1.20 christos /* Space for list could move - save offset */ 4078 1.20 christos ptrdiff_t p_offset = point - list; 4079 1.20 christos len += strlen(CMAC) + strlen(K_DELIM_STR); 4080 1.20 christos list = (char *)erealloc(list, len + 1); 4081 1.20 christos point = list + p_offset; 4082 1.20 christos /* move to handle src/dest overlap */ 4083 1.20 christos memmove(point + strlen(CMAC) + strlen(K_DELIM_STR), 4084 1.19 christos point, strlen(point) + 1); 4085 1.23 christos memcpy(point, CMAC, strlen(CMAC)); 4086 1.23 christos memcpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR)); 4087 1.20 christos } else { /* End of list */ 4088 1.20 christos /* append delim and cmac */ 4089 1.20 christos len += strlen(K_DELIM_STR) + strlen(CMAC); 4090 1.20 christos list = (char *)erealloc(list, len + 1); 4091 1.20 christos strcpy(list + strlen(list), K_DELIM_STR); 4092 1.20 christos strcpy(list + strlen(list), CMAC); 4093 1.20 christos } 4094 1.20 christos } /* insert */ 4095 1.20 christos } /* List not empty */ 4096 1.20 christos #endif /*ENABLE_CMAC*/ 4097 1.20 christos return list; 4098 1.12 christos } 4099 1.20 christos # endif /* !defined(BUILD_AS_LIB) */ 4100 1.12 christos # endif 4101 1.12 christos #endif 4102 1.12 christos 4103 1.19 christos 4104 1.20 christos #ifndef BUILD_AS_LIB 4105 1.19 christos static char * 4106 1.19 christos list_digest_names(void) 4107 1.12 christos { 4108 1.20 christos char *list = NULL; 4109 1.23 christos 4110 1.12 christos #ifdef OPENSSL 4111 1.12 christos # ifdef HAVE_EVP_MD_DO_ALL_SORTED 4112 1.20 christos struct hstate hstate = { NULL, NULL, K_PER_LINE+1 }; 4113 1.23 christos 4114 1.20 christos /* replace calloc(1, sizeof(const char *)) */ 4115 1.23 christos hstate.seen = emalloc_zero(sizeof(const char*)); 4116 1.23 christos 4117 1.20 christos INIT_SSL(); 4118 1.20 christos EVP_MD_do_all_sorted(list_md_fn, &hstate); 4119 1.20 christos list = hstate.list; 4120 1.23 christos free((void *)hstate.seen); 4121 1.23 christos 4122 1.20 christos list = insert_cmac(list); /* Insert CMAC into SSL digests list */ 4123 1.23 christos 4124 1.12 christos # else 4125 1.20 christos list = (char *)emalloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)")); 4126 1.20 christos strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)"); 4127 1.12 christos # endif 4128 1.12 christos #else 4129 1.20 christos list = (char *)emalloc(sizeof("md5")); 4130 1.20 christos strcpy(list, "md5"); 4131 1.12 christos #endif 4132 1.23 christos 4133 1.20 christos return list; 4134 1.12 christos } 4135 1.20 christos #endif /* !defined(BUILD_AS_LIB) */ 4136 1.14 christos 4137 1.14 christos #define CTRLC_STACK_MAX 4 4138 1.14 christos static volatile size_t ctrlc_stack_len = 0; 4139 1.14 christos static volatile Ctrl_C_Handler ctrlc_stack[CTRLC_STACK_MAX]; 4140 1.14 christos 4141 1.14 christos 4142 1.14 christos 4143 1.14 christos int/*BOOL*/ 4144 1.14 christos push_ctrl_c_handler( 4145 1.14 christos Ctrl_C_Handler func 4146 1.14 christos ) 4147 1.14 christos { 4148 1.14 christos size_t size = ctrlc_stack_len; 4149 1.14 christos if (func && (size < CTRLC_STACK_MAX)) { 4150 1.14 christos ctrlc_stack[size] = func; 4151 1.14 christos ctrlc_stack_len = size + 1; 4152 1.14 christos return TRUE; 4153 1.14 christos } 4154 1.23 christos return FALSE; 4155 1.14 christos } 4156 1.14 christos 4157 1.14 christos int/*BOOL*/ 4158 1.14 christos pop_ctrl_c_handler( 4159 1.14 christos Ctrl_C_Handler func 4160 1.14 christos ) 4161 1.14 christos { 4162 1.14 christos size_t size = ctrlc_stack_len; 4163 1.14 christos if (size) { 4164 1.14 christos --size; 4165 1.14 christos if (func == NULL || func == ctrlc_stack[size]) { 4166 1.14 christos ctrlc_stack_len = size; 4167 1.14 christos return TRUE; 4168 1.14 christos } 4169 1.14 christos } 4170 1.14 christos return FALSE; 4171 1.14 christos } 4172 1.14 christos 4173 1.20 christos #ifndef BUILD_AS_LIB 4174 1.14 christos static void 4175 1.14 christos on_ctrlc(void) 4176 1.14 christos { 4177 1.14 christos size_t size = ctrlc_stack_len; 4178 1.14 christos while (size) 4179 1.14 christos if ((*ctrlc_stack[--size])()) 4180 1.14 christos break; 4181 1.14 christos } 4182 1.20 christos #endif /* !defined(BUILD_AS_LIB) */ 4183 1.15 christos 4184 1.20 christos #ifndef BUILD_AS_LIB 4185 1.15 christos static int 4186 1.15 christos my_easprintf( 4187 1.15 christos char ** ppinto, 4188 1.15 christos const char * fmt , 4189 1.15 christos ... 4190 1.15 christos ) 4191 1.15 christos { 4192 1.15 christos va_list va; 4193 1.15 christos int prc; 4194 1.15 christos size_t len = 128; 4195 1.15 christos char * buf = emalloc(len); 4196 1.15 christos 4197 1.15 christos again: 4198 1.15 christos /* Note: we expect the memory allocation to fail long before the 4199 1.15 christos * increment in buffer size actually overflows. 4200 1.15 christos */ 4201 1.15 christos buf = (buf) ? erealloc(buf, len) : emalloc(len); 4202 1.15 christos 4203 1.15 christos va_start(va, fmt); 4204 1.15 christos prc = vsnprintf(buf, len, fmt, va); 4205 1.15 christos va_end(va); 4206 1.15 christos 4207 1.15 christos if (prc < 0) { 4208 1.15 christos /* might be very old vsnprintf. Or actually MSVC... */ 4209 1.15 christos len += len >> 1; 4210 1.15 christos goto again; 4211 1.15 christos } 4212 1.15 christos if ((size_t)prc >= len) { 4213 1.15 christos /* at least we have the proper size now... */ 4214 1.15 christos len = (size_t)prc + 1; 4215 1.15 christos goto again; 4216 1.15 christos } 4217 1.15 christos if ((size_t)prc < (len - 32)) 4218 1.15 christos buf = erealloc(buf, (size_t)prc + 1); 4219 1.15 christos *ppinto = buf; 4220 1.15 christos return prc; 4221 1.15 christos } 4222 1.20 christos #endif /* !defined(BUILD_AS_LIB) */ 4223