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