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