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