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