]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/ntpdc/ntpdc.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / ntpdc / ntpdc.c
1 /*
2  * ntpdc - control and monitor your ntpd daemon
3  */
4
5 #include <stdio.h>
6
7 #include <ctype.h>
8 #include <signal.h>
9 #include <setjmp.h>
10
11 #include "ntpdc.h"
12 #include "ntp_select.h"
13 #include "ntp_io.h"
14 #include "ntp_stdlib.h"
15 /* Don't include ISC's version of IPv6 variables and structures */
16 #define ISC_IPV6_H 1
17 #include "isc/net.h"
18 #include "isc/result.h"
19
20 #include "ntpdc-opts.h"
21
22 #ifdef SYS_WINNT
23 # include <Mswsock.h>
24 # include <io.h>
25 #else
26 # define closesocket close
27 #endif /* SYS_WINNT */
28
29 #if defined(HAVE_LIBREADLINE) || defined (HAVE_LIBEDIT)
30 # include <readline/readline.h>
31 # include <readline/history.h>
32 #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
33
34 #ifdef SYS_VXWORKS
35                                 /* vxWorks needs mode flag -casey*/
36 # define open(name, flags)   open(name, flags, 0777)
37 # define SERVER_PORT_NUM     123
38 #endif
39
40 /* We use COMMAND as an autogen keyword */
41 #ifdef COMMAND
42 # undef COMMAND
43 #endif
44
45 /*
46  * Because we now potentially understand a lot of commands (and
47  * it requires a lot of commands to talk to ntpd) we will run
48  * interactive if connected to a terminal.
49  */
50 static  int     interactive = 0;        /* set to 1 when we should prompt */
51 static  const char *    prompt = "ntpdc> ";     /* prompt to ask him about */
52
53 /*
54  * Keyid used for authenticated requests.  Obtained on the fly.
55  */
56 static  u_long  info_auth_keyid;
57 static int keyid_entered = 0;
58
59 /*
60  * Type of key md5
61  */
62 #define KEY_TYPE_MD5    4
63
64 static  int info_auth_keytype = KEY_TYPE_MD5;   /* MD5 */
65 u_long  current_time;           /* needed by authkeys; not used */
66
67 /*
68  * for get_systime()
69  */
70 s_char  sys_precision;          /* local clock precision (log2 s) */
71
72 int             ntpdcmain       P((int, char **));
73 /*
74  * Built in command handler declarations
75  */
76 static  int     openhost        P((const char *));
77 static  int     sendpkt         P((char *, int));
78 static  void    growpktdata     P((void));
79 static  int     getresponse     P((int, int, int *, int *, char **, int));
80 static  int     sendrequest     P((int, int, int, int, int, char *));
81 static  void    getcmds         P((void));
82 static  RETSIGTYPE abortcmd     P((int));
83 static  void    docmd           P((const char *));
84 static  void    tokenize        P((const char *, char **, int *));
85 static  int     findcmd         P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
86 static  int     getarg          P((char *, int, arg_v *));
87 static  int     getnetnum       P((const char *, struct sockaddr_storage *, char *, int));
88 static  void    help            P((struct parse *, FILE *));
89 #ifdef QSORT_USES_VOID_P
90 static  int     helpsort        P((const void *, const void *));
91 #else
92 static  int     helpsort        P((char **, char **));
93 #endif
94 static  void    printusage      P((struct xcmd *, FILE *));
95 static  void    timeout         P((struct parse *, FILE *));
96 static  void    my_delay        P((struct parse *, FILE *));
97 static  void    host            P((struct parse *, FILE *));
98 static  void    keyid           P((struct parse *, FILE *));
99 static  void    keytype         P((struct parse *, FILE *));
100 static  void    passwd          P((struct parse *, FILE *));
101 static  void    hostnames       P((struct parse *, FILE *));
102 static  void    setdebug        P((struct parse *, FILE *));
103 static  void    quit            P((struct parse *, FILE *));
104 static  void    version         P((struct parse *, FILE *));
105 static  void    warning         P((const char *, const char *, const char *));
106 static  void    error           P((const char *, const char *, const char *));
107 static  u_long  getkeyid        P((const char *));
108
109
110
111 /*
112  * Built-in commands we understand
113  */
114 static  struct xcmd builtins[] = {
115         { "?",          help,           {  OPT|NTP_STR, NO, NO, NO },
116           { "command", "", "", "" },
117           "tell the use and syntax of commands" },
118         { "help",       help,           {  OPT|NTP_STR, NO, NO, NO },
119           { "command", "", "", "" },
120           "tell the use and syntax of commands" },
121         { "timeout",    timeout,        { OPT|NTP_UINT, NO, NO, NO },
122           { "msec", "", "", "" },
123           "set the primary receive time out" },
124         { "delay",      my_delay,       { OPT|NTP_INT, NO, NO, NO },
125           { "msec", "", "", "" },
126           "set the delay added to encryption time stamps" },
127         { "host",       host,           { OPT|NTP_STR, OPT|NTP_STR, NO, NO },
128           { "-4|-6", "hostname", "", "" },
129           "specify the host whose NTP server we talk to" },
130         { "passwd",     passwd,         { OPT|NTP_STR, NO, NO, NO },
131           { "", "", "", "" },
132           "specify a password to use for authenticated requests"},
133         { "hostnames",  hostnames,      { OPT|NTP_STR, NO, NO, NO },
134           { "yes|no", "", "", "" },
135           "specify whether hostnames or net numbers are printed"},
136         { "debug",      setdebug,       { OPT|NTP_STR, NO, NO, NO },
137           { "no|more|less", "", "", "" },
138           "set/change debugging level" },
139         { "quit",       quit,           { NO, NO, NO, NO },
140           { "", "", "", "" },
141           "exit ntpdc" },
142         { "exit",       quit,           { NO, NO, NO, NO },
143           { "", "", "", "" },
144           "exit ntpdc" },
145         { "keyid",      keyid,          { OPT|NTP_UINT, NO, NO, NO },
146           { "key#", "", "", "" },
147           "set/show keyid to use for authenticated requests" },
148         { "keytype",    keytype,        { OPT|NTP_STR, NO, NO, NO },
149           { "(md5|des)", "", "", "" },
150           "set/show key authentication type for authenticated requests (des|md5)" },
151         { "version",    version,        { NO, NO, NO, NO },
152           { "", "", "", "" },
153           "print version number" },
154         { 0,            0,              { NO, NO, NO, NO },
155           { "", "", "", "" }, "" }
156 };
157
158
159 /*
160  * Default values we use.
161  */
162 #define DEFTIMEOUT      (5)             /* 5 second time out */
163 #define DEFSTIMEOUT     (2)             /* 2 second time out after first */
164 #define DEFDELAY        0x51EB852       /* 20 milliseconds, l_fp fraction */
165 #define DEFHOST         "localhost"     /* default host name */
166 #define LENHOSTNAME     256             /* host name is 256 characters long */
167 #define MAXCMDS         100             /* maximum commands on cmd line */
168 #define MAXHOSTS        200             /* maximum hosts on cmd line */
169 #define MAXLINE         512             /* maximum line length */
170 #define MAXTOKENS       (1+1+MAXARGS+MOREARGS+2)        /* maximum number of usable tokens */
171 #define SCREENWIDTH     78              /* nominal screen width in columns */
172
173 /*
174  * Some variables used and manipulated locally
175  */
176 static  struct timeval tvout = { DEFTIMEOUT, 0 };       /* time out for reads */
177 static  struct timeval tvsout = { DEFSTIMEOUT, 0 };     /* secondary time out */
178 static  l_fp delay_time;                                /* delay time */
179 static  char currenthost[LENHOSTNAME];                  /* current host name */
180 int showhostnames = 1;                                  /* show host names by default */
181
182 static  int ai_fam_templ;                               /* address family */
183 static  int ai_fam_default;                             /* default address family */
184 static  SOCKET sockfd;                                  /* fd socket is opened on */
185 static  int havehost = 0;                               /* set to 1 when host open */
186 int s_port = 0;
187
188 #if defined (SYS_WINNT) || defined (SYS_VXWORKS)
189 char password[9];
190 #endif /* SYS_WINNT || SYS_VXWORKS */
191
192 #ifdef SYS_WINNT
193 DWORD NumberOfBytesWritten;
194
195 HANDLE  TimerThreadHandle = NULL;       /* 1998/06/03 - Used in ntplib/machines.c */
196 void timer(void)        {  ; }; /* 1998/06/03 - Used in ntplib/machines.c */
197
198 #endif /* SYS_WINNT */
199
200 /*
201  * Holds data returned from queries.  We allocate INITDATASIZE
202  * octets to begin with, increasing this as we need to.
203  */
204 #define INITDATASIZE    (sizeof(struct resp_pkt) * 16)
205 #define INCDATASIZE     (sizeof(struct resp_pkt) * 8)
206
207 static  char *pktdata;
208 static  int pktdatasize;
209
210 /*
211  * These are used to help the magic with old and new versions of ntpd.
212  */
213 int impl_ver = IMPL_XNTPD;
214 static int req_pkt_size = REQ_LEN_NOMAC;
215
216 /*
217  * For commands typed on the command line (with the -c option)
218  */
219 static  int numcmds = 0;
220 static  const char *ccmds[MAXCMDS];
221 #define ADDCMD(cp)      if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
222
223 /*
224  * When multiple hosts are specified.
225  */
226 static  int numhosts = 0;
227 static  const char *chosts[MAXHOSTS];
228 #define ADDHOST(cp)     if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
229
230 /*
231  * Error codes for internal use
232  */
233 #define ERR_INCOMPLETE          16
234 #define ERR_TIMEOUT             17
235
236 /*
237  * Macro definitions we use
238  */
239 #define ISSPACE(c)      ((c) == ' ' || (c) == '\t')
240 #define ISEOL(c)        ((c) == '\n' || (c) == '\r' || (c) == '\0')
241 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
242
243 /*
244  * For converting time stamps to dates
245  */
246 #define JAN_1970        2208988800      /* 1970 - 1900 in seconds */
247
248 /*
249  * Jump buffer for longjumping back to the command level
250  */
251 static  jmp_buf interrupt_buf;
252 static  volatile int jump = 0;
253
254 /*
255  * Pointer to current output unit
256  */
257 static  FILE *current_output;
258
259 /*
260  * Command table imported from ntpdc_ops.c
261  */
262 extern struct xcmd opcmds[];
263
264 char *progname;
265 volatile int debug;
266
267 #ifdef NO_MAIN_ALLOWED
268 CALL(ntpdc,"ntpdc",ntpdcmain);
269 #else
270 int
271 main(
272         int argc,
273         char *argv[]
274         )
275 {
276         return ntpdcmain(argc, argv);
277 }
278 #endif
279
280 #ifdef SYS_VXWORKS
281 void clear_globals(void)
282 {
283     showhostnames = 0;              /* show host names by default */
284     havehost = 0;                   /* set to 1 when host open */
285     numcmds = 0;
286     numhosts = 0;
287 }
288 #endif
289
290 /*
291  * main - parse arguments and handle options
292  */
293 int
294 ntpdcmain(
295         int argc,
296         char *argv[]
297         )
298 {
299         extern int ntp_optind;
300
301         delay_time.l_ui = 0;
302         delay_time.l_uf = DEFDELAY;
303
304 #ifdef SYS_VXWORKS
305         clear_globals();
306         taskPrioritySet(taskIdSelf(), 100 );
307 #endif
308
309 #ifdef SYS_WINNT
310         if (!Win32InitSockets())
311         {
312                 fprintf(stderr, "No useable winsock.dll:");
313                 exit(1);
314         }
315 #endif /* SYS_WINNT */
316
317         /* Check to see if we have IPv6. Otherwise force the -4 flag */
318         if (isc_net_probeipv6() != ISC_R_SUCCESS) {
319                 ai_fam_default = AF_INET;
320         }
321
322         progname = argv[0];
323
324         {
325                 int optct = optionProcess(&ntpdcOptions, argc, argv);
326                 argc -= optct;
327                 argv += optct;
328         }
329
330         switch (WHICH_IDX_IPV4) {
331             case INDEX_OPT_IPV4:
332                 ai_fam_templ = AF_INET;
333                 break;
334             case INDEX_OPT_IPV6:
335                 ai_fam_templ = AF_INET6;
336                 break;
337             default:
338                 ai_fam_templ = ai_fam_default;
339                 break;
340         }
341
342         if (HAVE_OPT(COMMAND)) {
343                 int             cmdct = STACKCT_OPT( COMMAND );
344                 const char**    cmds  = STACKLST_OPT( COMMAND );
345
346                 while (cmdct-- > 0) {
347                         ADDCMD(*cmds++);
348                 }
349         }
350
351         debug = DESC(DEBUG_LEVEL).optOccCt;
352
353         if (HAVE_OPT(INTERACTIVE)) {
354                 interactive = 1;
355         }
356
357         if (HAVE_OPT(NUMERIC)) {
358                 showhostnames = 0;
359         }
360
361         if (HAVE_OPT(LISTPEERS)) {
362                 ADDCMD("listpeers");
363         }
364
365         if (HAVE_OPT(PEERS)) {
366                 ADDCMD("peers");
367         }
368
369         if (HAVE_OPT(SHOWPEERS)) {
370                 ADDCMD("dmpeers");
371         }
372
373         if (ntp_optind == argc) {
374                 ADDHOST(DEFHOST);
375         } else {
376                 for (; ntp_optind < argc; ntp_optind++)
377                     ADDHOST(argv[ntp_optind]);
378         }
379
380         if (numcmds == 0 && interactive == 0
381             && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
382                 interactive = 1;
383         }
384
385 #if 0
386         ai_fam_templ = ai_fam_default;
387         while ((c = ntp_getopt(argc, argv, "46c:dilnps")) != EOF)
388             switch (c) {
389                 case '4':
390                     ai_fam_templ = AF_INET;
391                     break;
392                 case '6':
393                     ai_fam_templ = AF_INET6;
394                     break;
395                 case 'c':
396                     ADDCMD(ntp_optarg);
397                     break;
398                 case 'd':
399                     ++debug;
400                     break;
401                 case 'i':
402                     interactive = 1;
403                     break;
404                 case 'l':
405                     ADDCMD("listpeers");
406                     break;
407                 case 'n':
408                     showhostnames = 0;
409                     break;
410                 case 'p':
411                     ADDCMD("peers");
412                     break;
413                 case 's':
414                     ADDCMD("dmpeers");
415                     break;
416                 default:
417                     errflg++;
418                     break;
419             }
420
421         if (errflg) {
422                 (void) fprintf(stderr,
423                                "usage: %s [-46dilnps] [-c cmd] host ...\n",
424                                progname);
425                 exit(2);
426         }
427
428         if (ntp_optind == argc) {
429                 ADDHOST(DEFHOST);
430         } else {
431                 for (; ntp_optind < argc; ntp_optind++)
432                     ADDHOST(argv[ntp_optind]);
433         }
434
435         if (numcmds == 0 && interactive == 0
436             && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
437                 interactive = 1;
438         }
439 #endif
440
441 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
442         if (interactive)
443             (void) signal_no_reset(SIGINT, abortcmd);
444 #endif /* SYS_WINNT */
445
446         /*
447          * Initialize the packet data buffer
448          */
449         pktdata = (char *)malloc(INITDATASIZE);
450         if (pktdata == NULL) {
451                 (void) fprintf(stderr, "%s: malloc() failed!\n", progname);
452                 exit(1);
453         }
454         pktdatasize = INITDATASIZE;
455
456         if (numcmds == 0) {
457                 (void) openhost(chosts[0]);
458                 getcmds();
459         } else {
460                 int ihost;
461                 int icmd;
462
463                 for (ihost = 0; ihost < numhosts; ihost++) {
464                         if (openhost(chosts[ihost]))
465                             for (icmd = 0; icmd < numcmds; icmd++) {
466                                     if (numhosts > 1) 
467                                         printf ("--- %s ---\n",chosts[ihost]);
468                                     docmd(ccmds[icmd]);
469                             }
470                 }
471         }
472 #ifdef SYS_WINNT
473         WSACleanup();
474 #endif
475         return(0);
476 } /* main end */
477
478
479 /*
480  * openhost - open a socket to a host
481  */
482 static int
483 openhost(
484         const char *hname
485         )
486 {
487         char temphost[LENHOSTNAME];
488         int a_info, i;
489         struct addrinfo hints, *ai = NULL;
490         register const char *cp;
491         char name[LENHOSTNAME];
492         char service[5];
493
494         /*
495          * We need to get by the [] if they were entered 
496          */
497         
498         cp = hname;
499         
500         if (*cp == '[') {
501                 cp++;   
502                 for(i = 0; *cp != ']'; cp++, i++)
503                         name[i] = *cp;  
504                 name[i] = '\0';
505                 hname = name;
506         }       
507
508         /*
509          * First try to resolve it as an ip address and if that fails,
510          * do a fullblown (dns) lookup. That way we only use the dns
511          * when it is needed and work around some implementations that
512          * will return an "IPv4-mapped IPv6 address" address if you
513          * give it an IPv4 address to lookup.
514          */
515         strcpy(service, "ntp");
516         memset((char *)&hints, 0, sizeof(struct addrinfo));
517         hints.ai_family = ai_fam_templ;
518         hints.ai_protocol = IPPROTO_UDP;
519         hints.ai_socktype = SOCK_DGRAM;
520         hints.ai_flags = AI_NUMERICHOST;
521
522         a_info = getaddrinfo(hname, service, &hints, &ai);
523         if (a_info == EAI_NONAME
524 #ifdef EAI_NODATA
525             || a_info == EAI_NODATA
526 #endif
527            ) {
528                 hints.ai_flags = AI_CANONNAME;
529 #ifdef AI_ADDRCONFIG
530                 hints.ai_flags |= AI_ADDRCONFIG;
531 #endif
532                 a_info = getaddrinfo(hname, service, &hints, &ai);      
533         }
534         /* Some older implementations don't like AI_ADDRCONFIG. */
535         if (a_info == EAI_BADFLAGS) {
536                 hints.ai_flags = AI_CANONNAME;
537                 a_info = getaddrinfo(hname, service, &hints, &ai);      
538         }
539         if (a_info != 0) {
540                 (void) fprintf(stderr, "%s\n", gai_strerror(a_info));
541                 if (ai != NULL)
542                         freeaddrinfo(ai);
543                 return 0;
544         }
545
546         if (ai->ai_canonname == NULL) {
547                 strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr),
548                     LENHOSTNAME);
549                 temphost[LENHOSTNAME-1] = '\0';
550         } else {
551                 strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
552                 temphost[LENHOSTNAME-1] = '\0';
553         }
554
555         if (debug > 2)
556             printf("Opening host %s\n", temphost);
557
558         if (havehost == 1) {
559                 if (debug > 2)
560                     printf("Closing old host %s\n", currenthost);
561                 (void) closesocket(sockfd);
562                 havehost = 0;
563         }
564         (void) strcpy(currenthost, temphost);
565         
566         /* port maps to the same in both families */
567         s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port; 
568 #ifdef SYS_VXWORKS
569         ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
570         if (ai->ai_family == AF_INET)
571                 *(struct sockaddr_in *)&hostaddr= 
572                         *((struct sockaddr_in *)ai->ai_addr);
573         else 
574                 *(struct sockaddr_in6 *)&hostaddr= 
575                         *((struct sockaddr_in6 *)ai->ai_addr);
576 #endif /* SYS_VXWORKS */
577
578 #ifdef SYS_WINNT
579         {
580                 int optionValue = SO_SYNCHRONOUS_NONALERT;
581                 int err;
582
583                 err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
584                 if (err != NO_ERROR) {
585                         (void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
586                         exit(1);
587                 }
588         }
589
590         sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
591         if (sockfd == INVALID_SOCKET) {
592                 error("socket", "", "");
593                 exit(-1);
594         }
595 #else
596         sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
597         if (sockfd == -1)
598             error("socket", "", "");
599 #endif /* SYS_WINNT */
600
601         
602 #ifdef NEED_RCVBUF_SLOP
603 # ifdef SO_RCVBUF
604         {
605                 int rbufsize = INITDATASIZE + 2048; /* 2K for slop */
606
607                 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
608                                &rbufsize, sizeof(int)) == -1)
609                     error("setsockopt", "", "");
610         }
611 # endif
612 #endif
613
614 #ifdef SYS_VXWORKS
615         if (connect(sockfd, (struct sockaddr *)&hostaddr, 
616                     sizeof(hostaddr)) == -1)
617 #else
618         if (connect(sockfd, (struct sockaddr *)ai->ai_addr,
619                     ai->ai_addrlen) == -1)
620 #endif /* SYS_VXWORKS */
621             error("connect", "", "");
622         if (ai != NULL)
623                 freeaddrinfo(ai);
624         havehost = 1;
625         req_pkt_size = REQ_LEN_NOMAC;
626         impl_ver = IMPL_XNTPD;
627         return 1;
628 }
629
630
631 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
632 /*
633  * sendpkt - send a packet to the remote host
634  */
635 static int
636 sendpkt(
637         char *xdata,
638         int xdatalen
639         )
640 {
641         if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
642                 warning("write to %s failed", currenthost, "");
643                 return -1;
644         }
645
646         return 0;
647 }
648
649
650 /*
651  * growpktdata - grow the packet data area
652  */
653 static void
654 growpktdata(void)
655 {
656         pktdatasize += INCDATASIZE;
657         pktdata = (char *)realloc(pktdata, (unsigned)pktdatasize);
658         if (pktdata == 0) {
659                 (void) fprintf(stderr, "%s: realloc() failed!\n", progname);
660                 exit(1);
661         }
662 }
663
664
665 /*
666  * getresponse - get a (series of) response packet(s) and return the data
667  */
668 static int
669 getresponse(
670         int implcode,
671         int reqcode,
672         int *ritems,
673         int *rsize,
674         char **rdata,
675         int esize
676         )
677 {
678         struct resp_pkt rpkt;
679         struct timeval tvo;
680         int items;
681         int i;
682         int size;
683         int datasize;
684         char *datap;
685         char *tmp_data;
686         char haveseq[MAXSEQ+1];
687         int firstpkt;
688         int lastseq;
689         int numrecv;
690         int seq;
691         fd_set fds;
692         int n;
693         int pad;
694
695         /*
696          * This is pretty tricky.  We may get between 1 and many packets
697          * back in response to the request.  We peel the data out of
698          * each packet and collect it in one long block.  When the last
699          * packet in the sequence is received we'll know how many we
700          * should have had.  Note we use one long time out, should reconsider.
701          */
702         *ritems = 0;
703         *rsize = 0;
704         firstpkt = 1;
705         numrecv = 0;
706         *rdata = datap = pktdata;
707         lastseq = 999;  /* too big to be a sequence number */
708         memset(haveseq, 0, sizeof(haveseq));
709         FD_ZERO(&fds);
710
711     again:
712         if (firstpkt)
713             tvo = tvout;
714         else
715             tvo = tvsout;
716         
717         FD_SET(sockfd, &fds);
718         n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
719
720         if (n == -1) {
721                 warning("select fails", "", "");
722                 return -1;
723         }
724         if (n == 0) {
725                 /*
726                  * Timed out.  Return what we have
727                  */
728                 if (firstpkt) {
729                         (void) fprintf(stderr,
730                                        "%s: timed out, nothing received\n", currenthost);
731                         return ERR_TIMEOUT;
732                 } else {
733                         (void) fprintf(stderr,
734                                        "%s: timed out with incomplete data\n",
735                                        currenthost);
736                         if (debug) {
737                                 printf("Received sequence numbers");
738                                 for (n = 0; n <= MAXSEQ; n++)
739                                     if (haveseq[n])
740                                         printf(" %d,", n);
741                                 if (lastseq != 999)
742                                     printf(" last frame received\n");
743                                 else
744                                     printf(" last frame not received\n");
745                         }
746                         return ERR_INCOMPLETE;
747                 }
748         }
749
750         n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
751         if (n == -1) {
752                 warning("read", "", "");
753                 return -1;
754         }
755
756
757         /*
758          * Check for format errors.  Bug proofing.
759          */
760         if (n < RESP_HEADER_SIZE) {
761                 if (debug)
762                     printf("Short (%d byte) packet received\n", n);
763                 goto again;
764         }
765         if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION ||
766             INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) {
767                 if (debug)
768                     printf("Packet received with version %d\n",
769                            INFO_VERSION(rpkt.rm_vn_mode));
770                 goto again;
771         }
772         if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) {
773                 if (debug)
774                     printf("Packet received with mode %d\n",
775                            INFO_MODE(rpkt.rm_vn_mode));
776                 goto again;
777         }
778         if (INFO_IS_AUTH(rpkt.auth_seq)) {
779                 if (debug)
780                     printf("Encrypted packet received\n");
781                 goto again;
782         }
783         if (!ISRESPONSE(rpkt.rm_vn_mode)) {
784                 if (debug)
785                     printf("Received request packet, wanted response\n");
786                 goto again;
787         }
788         if (INFO_MBZ(rpkt.mbz_itemsize) != 0) {
789                 if (debug)
790                     printf("Received packet with nonzero MBZ field!\n");
791                 goto again;
792         }
793
794         /*
795          * Check implementation/request.  Could be old data getting to us.
796          */
797         if (rpkt.implementation != implcode || rpkt.request != reqcode) {
798                 if (debug)
799                     printf(
800                             "Received implementation/request of %d/%d, wanted %d/%d",
801                             rpkt.implementation, rpkt.request,
802                             implcode, reqcode);
803                 goto again;
804         }
805
806         /*
807          * Check the error code.  If non-zero, return it.
808          */
809         if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) {
810                 if (debug && ISMORE(rpkt.rm_vn_mode)) {
811                         printf("Error code %d received on not-final packet\n",
812                                INFO_ERR(rpkt.err_nitems));
813                 }
814                 return (int)INFO_ERR(rpkt.err_nitems);
815         }
816
817         /*
818          * Collect items and size.  Make sure they make sense.
819          */
820         items = INFO_NITEMS(rpkt.err_nitems);
821         size = INFO_ITEMSIZE(rpkt.mbz_itemsize);
822         if (esize > size)
823                 pad = esize - size;
824         else 
825                 pad = 0;
826         if ((datasize = items*size) > (n-RESP_HEADER_SIZE)) {
827                 if (debug)
828                     printf(
829                             "Received items %d, size %d (total %d), data in packet is %d\n",
830                             items, size, datasize, n-RESP_HEADER_SIZE);
831                 goto again;
832         }
833
834         /*
835          * If this isn't our first packet, make sure the size matches
836          * the other ones.
837          */
838         if (!firstpkt && esize != *rsize) {
839                 if (debug)
840                     printf("Received itemsize %d, previous %d\n",
841                            size, *rsize);
842                 goto again;
843         }
844         /*
845          * If we've received this before, +toss it
846          */
847         seq = INFO_SEQ(rpkt.auth_seq);
848         if (haveseq[seq]) {
849                 if (debug)
850                     printf("Received duplicate sequence number %d\n", seq);
851                 goto again;
852         }
853         haveseq[seq] = 1;
854
855         /*
856          * If this is the last in the sequence, record that.
857          */
858         if (!ISMORE(rpkt.rm_vn_mode)) {
859                 if (lastseq != 999) {
860                         printf("Received second end sequence packet\n");
861                         goto again;
862                 }
863                 lastseq = seq;
864         }
865
866         /*
867          * So far, so good.  Copy this data into the output array.
868          */
869         if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
870                 int offset = datap - pktdata;
871                 growpktdata();
872                 *rdata = pktdata; /* might have been realloced ! */
873                 datap = pktdata + offset;
874         }
875         /* 
876          * We now move the pointer along according to size and number of
877          * items.  This is so we can play nice with older implementations
878          */
879
880         tmp_data = (char *)rpkt.data;
881         for(i = 0; i <items; i++){
882                 memmove(datap, tmp_data, (unsigned)size);
883                 tmp_data += size;
884                 memset(datap + size, 0, pad);
885                 datap += size + pad;
886         }
887
888         if (firstpkt) {
889                 firstpkt = 0;
890                 *rsize = size + pad;
891         }
892         *ritems += items;
893
894         /*
895          * Finally, check the count of received packets.  If we've got them
896          * all, return
897          */
898         ++numrecv;
899         if (numrecv <= lastseq)
900             goto again;
901         return INFO_OKAY;
902 }
903
904
905 /*
906  * sendrequest - format and send a request packet
907  */
908 static int
909 sendrequest(
910         int implcode,
911         int reqcode,
912         int auth,
913         int qitems,
914         int qsize,
915         char *qdata
916         )
917 {
918         struct req_pkt qpkt;
919         int datasize;
920
921         memset((char *)&qpkt, 0, sizeof qpkt);
922
923         qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
924         qpkt.implementation = (u_char)implcode;
925         qpkt.request = (u_char)reqcode;
926
927         datasize = qitems * qsize;
928         if (datasize != 0 && qdata != NULL) {
929                 memmove((char *)qpkt.data, qdata, (unsigned)datasize);
930                 qpkt.err_nitems = ERR_NITEMS(0, qitems);
931                 qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
932         } else {
933                 qpkt.err_nitems = ERR_NITEMS(0, 0);
934                 qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);  /* allow for optional first item */
935         }
936
937         if (!auth || (keyid_entered && info_auth_keyid == 0)) {
938                 qpkt.auth_seq = AUTH_SEQ(0, 0);
939                 return sendpkt((char *)&qpkt, req_pkt_size);
940         } else {
941                 l_fp ts;
942                 int maclen = 0;
943                 const char *pass = "\0";
944                 struct req_pkt_tail *qpktail;
945
946                 qpktail = (struct req_pkt_tail *)((char *)&qpkt + req_pkt_size
947                     + MAX_MAC_LEN - sizeof(struct req_pkt_tail));
948
949                 if (info_auth_keyid == 0) {
950                         if (((struct conf_peer *)qpkt.data)->keyid > 0)
951                                 info_auth_keyid = ((struct conf_peer *)qpkt.data)->keyid;
952                         else {
953                                 maclen = getkeyid("Keyid: ");
954                                 if (maclen == 0) {
955                                         (void) fprintf(stderr,
956                                             "Invalid key identifier\n");
957                                         return 1;
958                                 }
959                                 info_auth_keyid = maclen;
960                         }
961                 }
962                 if (!authistrusted(info_auth_keyid)) {
963                         pass = getpass("MD5 Password: ");
964                         if (*pass == '\0') {
965                                 (void) fprintf(stderr,
966                                     "Invalid password\n");
967                                 return (1);
968                         }
969                 }
970                 authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
971                 authtrust(info_auth_keyid, 1);
972                 qpkt.auth_seq = AUTH_SEQ(1, 0);
973                 qpktail->keyid = htonl(info_auth_keyid);
974                 get_systime(&ts);
975                 L_ADD(&ts, &delay_time);
976                 HTONL_FP(&ts, &qpktail->tstamp);
977                 maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
978                     req_pkt_size);
979                 if (maclen == 0) {  
980                         (void) fprintf(stderr, "Key not found\n");
981                         return (1);
982                 }
983                 return sendpkt((char *)&qpkt, (int)(req_pkt_size + maclen));
984         }
985         /*NOTREACHED*/
986 }
987
988
989 /*
990  * doquery - send a request and process the response
991  */
992 int
993 doquery(
994         int implcode,
995         int reqcode,
996         int auth,
997         int qitems,
998         int qsize,
999         char *qdata,
1000         int *ritems,
1001         int *rsize,
1002         char **rdata,
1003         int quiet_mask,
1004         int esize
1005         )
1006 {
1007         int res;
1008         char junk[512];
1009         fd_set fds;
1010         struct timeval tvzero;
1011
1012         /*
1013          * Check to make sure host is open
1014          */
1015         if (!havehost) {
1016                 (void) fprintf(stderr, "***No host open, use `host' command\n");
1017                 return -1;
1018         }
1019
1020         /*
1021          * Poll the socket and clear out any pending data
1022          */
1023 again:
1024         do {
1025                 tvzero.tv_sec = tvzero.tv_usec = 0;
1026                 FD_ZERO(&fds);
1027                 FD_SET(sockfd, &fds);
1028                 res = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
1029
1030                 if (res == -1) {
1031                         warning("polling select", "", "");
1032                         return -1;
1033                 } else if (res > 0)
1034
1035                     (void) recv(sockfd, junk, sizeof junk, 0);
1036         } while (res > 0);
1037
1038
1039         /*
1040          * send a request
1041          */
1042         res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
1043         if (res != 0)
1044             return res;
1045         
1046         /*
1047          * Get the response.  If we got a standard error, print a message
1048          */
1049         res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize);
1050
1051         /*
1052          * Try to be compatible with older implementations of ntpd.
1053          */
1054         if (res == INFO_ERR_FMT && req_pkt_size != 48) {
1055                 int oldsize;
1056
1057                 oldsize = req_pkt_size;
1058
1059                 switch(req_pkt_size) {
1060                 case REQ_LEN_NOMAC:
1061                         req_pkt_size = 160;
1062                         break;
1063                 case 160:
1064                         req_pkt_size = 48;
1065                         break;
1066                 }
1067                 if (impl_ver == IMPL_XNTPD) {
1068                         fprintf(stderr,
1069                             "***Warning changing to older implementation\n");
1070                         return INFO_ERR_IMPL;
1071                 }
1072
1073                 fprintf(stderr,
1074                     "***Warning changing the request packet size from %d to %d\n",
1075                     oldsize, req_pkt_size);
1076                 goto again;
1077         }
1078
1079         /* log error message if not told to be quiet */
1080         if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
1081                 switch(res) {
1082                     case INFO_ERR_IMPL:
1083                         /* Give us a chance to try the older implementation. */
1084                         if (implcode == IMPL_XNTPD)
1085                                 break;
1086                         (void) fprintf(stderr,
1087                                        "***Server implementation incompatable with our own\n");
1088                         break;
1089                     case INFO_ERR_REQ:
1090                         (void) fprintf(stderr,
1091                                        "***Server doesn't implement this request\n");
1092                         break;
1093                     case INFO_ERR_FMT:
1094                         (void) fprintf(stderr,
1095                                        "***Server reports a format error in the received packet (shouldn't happen)\n");
1096                         break;
1097                     case INFO_ERR_NODATA:
1098                         (void) fprintf(stderr,
1099                                        "***Server reports data not found\n");
1100                         break;
1101                     case INFO_ERR_AUTH:
1102                         (void) fprintf(stderr, "***Permission denied\n");
1103                         break;
1104                     case ERR_TIMEOUT:
1105                         (void) fprintf(stderr, "***Request timed out\n");
1106                         break;
1107                     case ERR_INCOMPLETE:
1108                         (void) fprintf(stderr,
1109                                        "***Response from server was incomplete\n");
1110                         break;
1111                     default:
1112                         (void) fprintf(stderr,
1113                                        "***Server returns unknown error code %d\n", res);
1114                         break;
1115                 }
1116         }
1117         return res;
1118 }
1119
1120
1121 /*
1122  * getcmds - read commands from the standard input and execute them
1123  */
1124 static void
1125 getcmds(void)
1126 {
1127 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
1128         char *line;
1129
1130         for (;;) {
1131                 if ((line = readline(interactive?prompt:"")) == NULL) return;
1132                 if (*line) add_history(line);
1133                 docmd(line);
1134                 free(line);
1135         }
1136 #else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
1137         char line[MAXLINE];
1138
1139         for (;;) {
1140                 if (interactive) {
1141 #ifdef VMS      /* work around a problem with mixing stdout & stderr */
1142                         fputs("",stdout);
1143 #endif
1144                         (void) fputs(prompt, stderr);
1145                         (void) fflush(stderr);
1146                 }
1147
1148                 if (fgets(line, sizeof line, stdin) == NULL)
1149                     return;
1150
1151                 docmd(line);
1152         }
1153 #endif /* not HAVE_LIBREADLINE || HAVE_LIBEDIT */
1154 }
1155
1156
1157 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1158 /*
1159  * abortcmd - catch interrupts and abort the current command
1160  */
1161 static RETSIGTYPE
1162 abortcmd(
1163         int sig
1164         )
1165 {
1166
1167         if (current_output == stdout)
1168             (void) fflush(stdout);
1169         putc('\n', stderr);
1170         (void) fflush(stderr);
1171         if (jump) longjmp(interrupt_buf, 1);
1172 }
1173 #endif /* SYS_WINNT */
1174
1175 /*
1176  * docmd - decode the command line and execute a command
1177  */
1178 static void
1179 docmd(
1180         const char *cmdline
1181         )
1182 {
1183         char *tokens[1+MAXARGS+MOREARGS+2];
1184         struct parse pcmd;
1185         int ntok;
1186         int i, ti;
1187         int rval;
1188         struct xcmd *xcmd;
1189
1190         ai_fam_templ = ai_fam_default;
1191         /*
1192          * Tokenize the command line.  If nothing on it, return.
1193          */
1194         tokenize(cmdline, tokens, &ntok);
1195         if (ntok == 0)
1196             return;
1197         
1198         /*
1199          * Find the appropriate command description.
1200          */
1201         i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1202         if (i == 0) {
1203                 (void) fprintf(stderr, "***Command `%s' unknown\n",
1204                                tokens[0]);
1205                 return;
1206         } else if (i >= 2) {
1207                 (void) fprintf(stderr, "***Command `%s' ambiguous\n",
1208                                tokens[0]);
1209                 return;
1210         }
1211         
1212         /*
1213          * Save the keyword, then walk through the arguments, interpreting
1214          * as we go.
1215          */
1216         pcmd.keyword = tokens[0];
1217         pcmd.nargs = 0;
1218         ti = 1;
1219         for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) {
1220                 if ((i+ti) >= ntok) {
1221                         if (!(xcmd->arg[i] & OPT)) {
1222                                 printusage(xcmd, stderr);
1223                                 return;
1224                         }
1225                         break;
1226                 }
1227                 if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>'))
1228                         break;
1229                 rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]);
1230                 if (rval == -1) {
1231                         ti++;
1232                         continue;
1233                 }
1234                 if (rval == 0)
1235                         return;
1236                 pcmd.nargs++;
1237                 i++;
1238         }
1239
1240         /* Any extra args are assumed to be "OPT|NTP_STR". */
1241         for ( ; i < MAXARGS + MOREARGS;) {
1242              if ((i+ti) >= ntok)
1243                   break;
1244                 rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]);
1245                 if (rval == -1) {
1246                         ti++;
1247                         continue;
1248                 }
1249                 if (rval == 0)
1250                         return;
1251                 pcmd.nargs++;
1252                 i++;
1253         }
1254
1255         i += ti;
1256         if (i < ntok && *tokens[i] == '>') {
1257                 char *fname;
1258
1259                 if (*(tokens[i]+1) != '\0')
1260                     fname = tokens[i]+1;
1261                 else if ((i+1) < ntok)
1262                     fname = tokens[i+1];
1263                 else {
1264                         (void) fprintf(stderr, "***No file for redirect\n");
1265                         return;
1266                 }
1267
1268                 current_output = fopen(fname, "w");
1269                 if (current_output == NULL) {
1270                         (void) fprintf(stderr, "***Error opening %s: ", fname);
1271                         perror("");
1272                         return;
1273                 }
1274         } else {
1275                 current_output = stdout;
1276         }
1277
1278         if (interactive && setjmp(interrupt_buf)) {
1279                 return;
1280         } else {
1281                 jump = 1;
1282                 (xcmd->handler)(&pcmd, current_output);
1283                 jump = 0;
1284                 if (current_output != stdout)
1285                         (void) fclose(current_output);
1286                 current_output = NULL;
1287         }
1288 }
1289
1290
1291 /*
1292  * tokenize - turn a command line into tokens
1293  */
1294 static void
1295 tokenize(
1296         const char *line,
1297         char **tokens,
1298         int *ntok
1299         )
1300 {
1301         register const char *cp;
1302         register char *sp;
1303         static char tspace[MAXLINE];
1304
1305         sp = tspace;
1306         cp = line;
1307         for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1308                 tokens[*ntok] = sp;
1309                 while (ISSPACE(*cp))
1310                     cp++;
1311                 if (ISEOL(*cp))
1312                     break;
1313                 do {
1314                         *sp++ = *cp++;
1315                 } while (!ISSPACE(*cp) && !ISEOL(*cp));
1316
1317                 *sp++ = '\0';
1318         }
1319 }
1320
1321
1322
1323 /*
1324  * findcmd - find a command in a command description table
1325  */
1326 static int
1327 findcmd(
1328         register char *str,
1329         struct xcmd *clist1,
1330         struct xcmd *clist2,
1331         struct xcmd **cmd
1332         )
1333 {
1334         register struct xcmd *cl;
1335         register int clen;
1336         int nmatch;
1337         struct xcmd *nearmatch = NULL;
1338         struct xcmd *clist;
1339
1340         clen = strlen(str);
1341         nmatch = 0;
1342         if (clist1 != 0)
1343             clist = clist1;
1344         else if (clist2 != 0)
1345             clist = clist2;
1346         else
1347             return 0;
1348
1349     again:
1350         for (cl = clist; cl->keyword != 0; cl++) {
1351                 /* do a first character check, for efficiency */
1352                 if (*str != *(cl->keyword))
1353                     continue;
1354                 if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1355                         /*
1356                          * Could be extact match, could be approximate.
1357                          * Is exact if the length of the keyword is the
1358                          * same as the str.
1359                          */
1360                         if (*((cl->keyword) + clen) == '\0') {
1361                                 *cmd = cl;
1362                                 return 1;
1363                         }
1364                         nmatch++;
1365                         nearmatch = cl;
1366                 }
1367         }
1368
1369                                 /*
1370                                  * See if there is more to do.  If so, go again.  Sorry about the
1371                                  * goto, too much looking at BSD sources...
1372                                  */
1373         if (clist == clist1 && clist2 != 0) {
1374                 clist = clist2;
1375                 goto again;
1376         }
1377
1378                                 /*
1379                                  * If we got extactly 1 near match, use it, else return number
1380                                  * of matches.
1381                                  */
1382         if (nmatch == 1) {
1383                 *cmd = nearmatch;
1384                 return 1;
1385         }
1386         return nmatch;
1387 }
1388
1389
1390 /*
1391  * getarg - interpret an argument token
1392  *
1393  * string is always set.
1394  * type is set to the decoded type.
1395  *
1396  * return:       0 - failure
1397  *               1 - success
1398  *              -1 - skip to next token
1399  */
1400 static int
1401 getarg(
1402         char *str,
1403         int code,
1404         arg_v *argp
1405         )
1406 {
1407         int isneg;
1408         char *cp, *np;
1409         static const char *digits = "0123456789";
1410
1411         memset(argp, 0, sizeof(*argp));
1412
1413         argp->string = str;
1414         argp->type   = code & ~OPT;
1415
1416         switch (argp->type) {
1417             case NTP_STR:
1418                 break;
1419             case NTP_ADD:
1420                 if (!strcmp("-6", str)) {
1421                         ai_fam_templ = AF_INET6;
1422                         return -1;
1423                 } else if (!strcmp("-4", str)) {
1424                         ai_fam_templ = AF_INET;
1425                         return -1;
1426                 }
1427                 if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
1428                         return 0;
1429                 }
1430                 break;
1431             case NTP_INT:
1432             case NTP_UINT:
1433                 isneg = 0;
1434                 np = str;
1435                 if (*np == '-') {
1436                         np++;
1437                         isneg = 1;
1438                 }
1439
1440                 argp->uval = 0;
1441                 do {
1442                         cp = strchr(digits, *np);
1443                         if (cp == NULL) {
1444                                 (void) fprintf(stderr,
1445                                                "***Illegal integer value %s\n", str);
1446                                 return 0;
1447                         }
1448                         argp->uval *= 10;
1449                         argp->uval += (cp - digits);
1450                 } while (*(++np) != '\0');
1451
1452                 if (isneg) {
1453                         if ((code & ~OPT) == NTP_UINT) {
1454                                 (void) fprintf(stderr,
1455                                                "***Value %s should be unsigned\n", str);
1456                                 return 0;
1457                         }
1458                         argp->ival = -argp->ival;
1459                 }
1460                 break;
1461             case IP_VERSION:
1462                 if (!strcmp("-6", str))
1463                         argp->ival = 6 ;
1464                 else if (!strcmp("-4", str))
1465                         argp->ival = 4 ;
1466                 else {
1467                         (void) fprintf(stderr,
1468                             "***Version must be either 4 or 6\n");
1469                         return 0;
1470                 }
1471                 break;
1472         }
1473
1474         return 1;
1475 }
1476
1477
1478 /*
1479  * getnetnum - given a host name, return its net number
1480  *             and (optional) full name
1481  */
1482 static int
1483 getnetnum(
1484         const char *hname,
1485         struct sockaddr_storage *num,
1486         char *fullhost,
1487         int af
1488         )
1489 {
1490         int sockaddr_len;
1491         struct addrinfo hints, *ai = NULL;
1492
1493         sockaddr_len = (af == AF_INET)
1494                            ? sizeof(struct sockaddr_in)
1495                            : sizeof(struct sockaddr_in6);
1496         memset((char *)&hints, 0, sizeof(struct addrinfo));
1497         hints.ai_flags = AI_CANONNAME;
1498 #ifdef AI_ADDRCONFIG
1499         hints.ai_flags |= AI_ADDRCONFIG;
1500 #endif
1501         
1502         /* decodenetnum only works with addresses */
1503         if (decodenetnum(hname, num)) {
1504                 if (fullhost != 0) {
1505                         getnameinfo((struct sockaddr *)num, sockaddr_len, 
1506                                     fullhost, sizeof(fullhost), NULL, 0, 
1507                                     NI_NUMERICHOST); 
1508                 }
1509                 return 1;
1510         } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1511                 memmove((char *)num, ai->ai_addr, ai->ai_addrlen);
1512                 if (fullhost != 0)
1513                         (void) strcpy(fullhost, ai->ai_canonname);
1514                 return 1;
1515         } else {
1516                 (void) fprintf(stderr, "***Can't find host %s\n", hname);
1517                 return 0;
1518         }
1519         /*NOTREACHED*/
1520 }
1521
1522 /*
1523  * nntohost - convert network number to host name.  This routine enforces
1524  *             the showhostnames setting.
1525  */
1526 char *
1527 nntohost(
1528         struct sockaddr_storage *netnum
1529         )
1530 {
1531         if (!showhostnames)
1532             return stoa(netnum);
1533
1534         if ((netnum->ss_family == AF_INET) && ISREFCLOCKADR(netnum))
1535                 return refnumtoa(netnum);
1536         return socktohost(netnum);
1537 }
1538
1539
1540 /*
1541  * Finally, the built in command handlers
1542  */
1543
1544 /*
1545  * help - tell about commands, or details of a particular command
1546  */
1547 static void
1548 help(
1549         struct parse *pcmd,
1550         FILE *fp
1551         )
1552 {
1553         struct xcmd *xcp;
1554         char *cmd;
1555         const char *list[100];
1556         int word, words;     
1557         int row, rows;
1558         int col, cols;
1559
1560         if (pcmd->nargs == 0) {
1561                 words = 0;
1562                 for (xcp = builtins; xcp->keyword != 0; xcp++) {
1563                         if (*(xcp->keyword) != '?')
1564                             list[words++] = xcp->keyword;
1565                 }
1566                 for (xcp = opcmds; xcp->keyword != 0; xcp++)
1567                     list[words++] = xcp->keyword;
1568
1569                 qsort(
1570 #ifdef QSORT_USES_VOID_P
1571                     (void *)
1572 #else
1573                     (char *)
1574 #endif
1575                         (list), (size_t)(words), sizeof(char *), helpsort);
1576                 col = 0;
1577                 for (word = 0; word < words; word++) {
1578                         int length = strlen(list[word]);
1579                         if (col < length) {
1580                             col = length;
1581                         }
1582                 }
1583
1584                 cols = SCREENWIDTH / ++col;
1585                 rows = (words + cols - 1) / cols;
1586
1587                 (void) fprintf(fp, "ntpdc commands:\n");
1588
1589                 for (row = 0; row < rows; row++) {
1590                         for (word = row; word < words; word += rows) {
1591                                 (void) fprintf(fp, "%-*.*s", col, col-1, list[word]);
1592                         }
1593                         (void) fprintf(fp, "\n");
1594                 }
1595         } else {
1596                 cmd = pcmd->argval[0].string;
1597                 words = findcmd(cmd, builtins, opcmds, &xcp);
1598                 if (words == 0) {
1599                         (void) fprintf(stderr,
1600                                        "Command `%s' is unknown\n", cmd);
1601                         return;
1602                 } else if (words >= 2) {
1603                         (void) fprintf(stderr,
1604                                        "Command `%s' is ambiguous\n", cmd);
1605                         return;
1606                 }
1607                 (void) fprintf(fp, "function: %s\n", xcp->comment);
1608                 printusage(xcp, fp);
1609         }
1610 }
1611
1612
1613 /*
1614  * helpsort - do hostname qsort comparisons
1615  */
1616 #ifdef QSORT_USES_VOID_P
1617 static int
1618 helpsort(
1619         const void *t1,
1620         const void *t2
1621         )
1622 {
1623         char const * const * name1 = (char const * const *)t1;
1624         char const * const * name2 = (char const * const *)t2;
1625
1626         return strcmp(*name1, *name2);
1627 }
1628 #else
1629 static int
1630 helpsort(
1631         char **name1,
1632         char **name2
1633         )
1634 {
1635         return strcmp(*name1, *name2);
1636 }
1637 #endif
1638
1639
1640 /*
1641  * printusage - print usage information for a command
1642  */
1643 static void
1644 printusage(
1645         struct xcmd *xcp,
1646         FILE *fp
1647         )
1648 {
1649         int i, opt46;
1650
1651         opt46 = 0;
1652         (void) fprintf(fp, "usage: %s", xcp->keyword);
1653         for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
1654                 if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) {
1655                         (void) fprintf(fp, " [ -4|-6 ]");
1656                         opt46 = 1;
1657                 }
1658                 if (xcp->arg[i] & OPT)
1659                     (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
1660                 else
1661                     (void) fprintf(fp, " %s", xcp->desc[i]);
1662         }
1663         (void) fprintf(fp, "\n");
1664 }
1665
1666
1667 /*
1668  * timeout - set time out time
1669  */
1670 static void
1671 timeout(
1672         struct parse *pcmd,
1673         FILE *fp
1674         )
1675 {
1676         int val;
1677
1678         if (pcmd->nargs == 0) {
1679                 val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
1680                 (void) fprintf(fp, "primary timeout %d ms\n", val);
1681         } else {
1682                 tvout.tv_sec = pcmd->argval[0].uval / 1000;
1683                 tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
1684                         * 1000;
1685         }
1686 }
1687
1688
1689 /*
1690  * my_delay - set delay for auth requests
1691  */
1692 static void
1693 my_delay(
1694         struct parse *pcmd,
1695         FILE *fp
1696         )
1697 {
1698         int isneg;
1699         u_long val;
1700
1701         if (pcmd->nargs == 0) {
1702                 val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
1703                 (void) fprintf(fp, "delay %lu ms\n", val);
1704         } else {
1705                 if (pcmd->argval[0].ival < 0) {
1706                         isneg = 1;
1707                         val = (u_long)(-pcmd->argval[0].ival);
1708                 } else {
1709                         isneg = 0;
1710                         val = (u_long)pcmd->argval[0].ival;
1711                 }
1712
1713                 delay_time.l_ui = val / 1000;
1714                 val %= 1000;
1715                 delay_time.l_uf = val * 4294967;        /* 2**32/1000 */
1716
1717                 if (isneg)
1718                     L_NEG(&delay_time);
1719         }
1720 }
1721
1722
1723 /*
1724  * host - set the host we are dealing with.
1725  */
1726 static void
1727 host(
1728         struct parse *pcmd,
1729         FILE *fp
1730         )
1731 {
1732         int i;
1733
1734         if (pcmd->nargs == 0) {
1735                 if (havehost)
1736                     (void) fprintf(fp, "current host is %s\n", currenthost);
1737                 else
1738                     (void) fprintf(fp, "no current host\n");
1739                 return;
1740         }
1741
1742         i = 0;
1743         if (pcmd->nargs == 2) {
1744                 if (!strcmp("-4", pcmd->argval[i].string))
1745                         ai_fam_templ = AF_INET;
1746                 else if (!strcmp("-6", pcmd->argval[i].string))
1747                         ai_fam_templ = AF_INET6;
1748                 else {
1749                         if (havehost)
1750                                 (void) fprintf(fp,
1751                                     "current host remains %s\n", currenthost);
1752                         else
1753                                 (void) fprintf(fp, "still no current host\n");
1754                         return;
1755                 }
1756                 i = 1;
1757         }
1758         if (openhost(pcmd->argval[i].string)) {
1759                 (void) fprintf(fp, "current host set to %s\n", currenthost);
1760         } else {
1761                 if (havehost)
1762                     (void) fprintf(fp,
1763                                    "current host remains %s\n", currenthost);
1764                 else
1765                     (void) fprintf(fp, "still no current host\n");
1766         }
1767 }
1768
1769
1770 /*
1771  * keyid - get a keyid to use for authenticating requests
1772  */
1773 static void
1774 keyid(
1775         struct parse *pcmd,
1776         FILE *fp
1777         )
1778 {
1779         if (pcmd->nargs == 0) {
1780                 if (info_auth_keyid == 0 && !keyid_entered)
1781                     (void) fprintf(fp, "no keyid defined\n");
1782                 else if (info_auth_keyid == 0 && keyid_entered)
1783                     (void) fprintf(fp, "no keyid will be sent\n");
1784                 else
1785                     (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
1786         } else {
1787                 info_auth_keyid = pcmd->argval[0].uval;
1788                 keyid_entered = 1;
1789         }
1790 }
1791
1792
1793 /*
1794  * keytype - get type of key to use for authenticating requests
1795  */
1796 static void
1797 keytype(
1798         struct parse *pcmd,
1799         FILE *fp
1800         )
1801 {
1802         if (pcmd->nargs == 0)
1803             fprintf(fp, "keytype is %s\n",
1804                     (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "???");
1805         else
1806             switch (*(pcmd->argval[0].string)) {
1807                 case 'm':
1808                 case 'M':
1809                     info_auth_keytype = KEY_TYPE_MD5;
1810                     break;
1811
1812                 default:
1813                     fprintf(fp, "keytype must be 'md5'\n");
1814             }
1815 }
1816
1817
1818
1819 /*
1820  * passwd - get an authentication key
1821  */
1822 /*ARGSUSED*/
1823 static void
1824 passwd(
1825         struct parse *pcmd,
1826         FILE *fp
1827         )
1828 {
1829         char *pass;
1830
1831         if (info_auth_keyid == 0) {
1832                 info_auth_keyid = getkeyid("Keyid: ");
1833                 if (info_auth_keyid == 0) {
1834                         (void)fprintf(fp, "Keyid must be defined\n");
1835                         return;
1836                 }
1837         }
1838         if (!interactive) {
1839                 authusekey(info_auth_keyid, info_auth_keytype,
1840                            (u_char *)pcmd->argval[0].string);
1841                 authtrust(info_auth_keyid, 1);
1842         } else {
1843                 pass = getpass("MD5 Password: ");
1844                 if (*pass == '\0')
1845                     (void) fprintf(fp, "Password unchanged\n");
1846                 else {
1847                     authusekey(info_auth_keyid, info_auth_keytype,
1848                                (u_char *)pass);
1849                     authtrust(info_auth_keyid, 1);
1850                 }
1851         }
1852 }
1853
1854
1855 /*
1856  * hostnames - set the showhostnames flag
1857  */
1858 static void
1859 hostnames(
1860         struct parse *pcmd,
1861         FILE *fp
1862         )
1863 {
1864         if (pcmd->nargs == 0) {
1865                 if (showhostnames)
1866                     (void) fprintf(fp, "hostnames being shown\n");
1867                 else
1868                     (void) fprintf(fp, "hostnames not being shown\n");
1869         } else {
1870                 if (STREQ(pcmd->argval[0].string, "yes"))
1871                     showhostnames = 1;
1872                 else if (STREQ(pcmd->argval[0].string, "no"))
1873                     showhostnames = 0;
1874                 else
1875                     (void)fprintf(stderr, "What?\n");
1876         }
1877 }
1878
1879
1880 /*
1881  * setdebug - set/change debugging level
1882  */
1883 static void
1884 setdebug(
1885         struct parse *pcmd,
1886         FILE *fp
1887         )
1888 {
1889         if (pcmd->nargs == 0) {
1890                 (void) fprintf(fp, "debug level is %d\n", debug);
1891                 return;
1892         } else if (STREQ(pcmd->argval[0].string, "no")) {
1893                 debug = 0;
1894         } else if (STREQ(pcmd->argval[0].string, "more")) {
1895                 debug++;
1896         } else if (STREQ(pcmd->argval[0].string, "less")) {
1897                 debug--;
1898         } else {
1899                 (void) fprintf(fp, "What?\n");
1900                 return;
1901         }
1902         (void) fprintf(fp, "debug level set to %d\n", debug);
1903 }
1904
1905
1906 /*
1907  * quit - stop this nonsense
1908  */
1909 /*ARGSUSED*/
1910 static void
1911 quit(
1912         struct parse *pcmd,
1913         FILE *fp
1914         )
1915 {
1916         if (havehost)
1917             closesocket(sockfd);
1918         exit(0);
1919 }
1920
1921
1922 /*
1923  * version - print the current version number
1924  */
1925 /*ARGSUSED*/
1926 static void
1927 version(
1928         struct parse *pcmd,
1929         FILE *fp
1930         )
1931 {
1932
1933         (void) fprintf(fp, "%s\n", Version);
1934         return;
1935 }
1936
1937
1938 /*
1939  * warning - print a warning message
1940  */
1941 static void
1942 warning(
1943         const char *fmt,
1944         const char *st1,
1945         const char *st2
1946         )
1947 {
1948         (void) fprintf(stderr, "%s: ", progname);
1949         (void) fprintf(stderr, fmt, st1, st2);
1950         (void) fprintf(stderr, ": ");
1951         perror("");
1952 }
1953
1954
1955 /*
1956  * error - print a message and exit
1957  */
1958 static void
1959 error(
1960         const char *fmt,
1961         const char *st1,
1962         const char *st2
1963         )
1964 {
1965         warning(fmt, st1, st2);
1966         exit(1);
1967 }
1968
1969 /*
1970  * getkeyid - prompt the user for a keyid to use
1971  */
1972 static u_long
1973 getkeyid(
1974         const char *keyprompt
1975         )
1976 {
1977         register char *p;
1978         register int c;
1979         FILE *fi;
1980         char pbuf[20];
1981
1982 #ifndef SYS_WINNT
1983         if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
1984 #else
1985             if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL)
1986 #endif /* SYS_WINNT */
1987                 fi = stdin;
1988             else
1989                 setbuf(fi, (char *)NULL);
1990         fprintf(stderr, "%s", keyprompt); fflush(stderr);
1991         for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
1992                 if (p < &pbuf[18])
1993                     *p++ = (char) c;
1994         }
1995         *p = '\0';
1996         if (fi != stdin)
1997             fclose(fi);
1998         return (u_int32)atoi(pbuf);
1999 }