Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / ntp / ntpq / ntpq.c
1 /*
2  * ntpq - query an NTP server using mode 6 commands
3  */
4
5 #include <stdio.h>
6
7 #include "ntpq.h"
8 #include "ntp_unixtime.h"
9 #include "ntp_calendar.h"
10 #include "ntp_io.h"
11 #include "ntp_select.h"
12 #include "ntp_stdlib.h"
13
14 #include <ctype.h>
15 #include <signal.h>
16 #include <setjmp.h>
17 #include <netdb.h>
18 #ifdef SYS_WINNT
19 # include <io.h>
20 #else
21 #define closesocket close
22 #endif /* SYS_WINNT */
23
24 #ifdef SYS_VXWORKS
25 /* vxWorks needs mode flag -casey*/
26 #define open(name, flags)   open(name, flags, 0777)
27 #define SERVER_PORT_NUM     123
28 #endif
29
30 /*
31  * Because we potentially understand a lot of commands we will run
32  * interactive if connected to a terminal.
33  */
34 int interactive = 0;            /* set to 1 when we should prompt */
35 const char *prompt = "ntpq> ";  /* prompt to ask him about */
36
37
38 /*
39  * Keyid used for authenticated requests.  Obtained on the fly.
40  */
41 u_long info_auth_keyid = NTP_MAXKEY;
42
43 /*
44  * Type of key md5 or des
45  */
46 #define KEY_TYPE_DES    3
47 #define KEY_TYPE_MD5    4
48
49 static  int info_auth_keytype = KEY_TYPE_MD5;   /* MD5 */
50 u_long  current_time;           /* needed by authkeys; not used */
51
52 /*
53  * Flag which indicates we should always send authenticated requests
54  */
55 int always_auth = 0;
56
57 /*
58  * Flag which indicates raw mode output.
59  */
60 int rawmode = 0;
61
62 /*
63  * Packet version number we use
64  */
65 u_char pktversion = NTP_OLDVERSION + 1;
66
67 /*
68  * Don't jump if no set jmp.
69  */
70 volatile int jump = 0;
71
72 /*
73  * Format values
74  */
75 #define PADDING 0
76 #define TS      1       /* time stamp */
77 #define FL      2       /* l_fp type value */
78 #define FU      3       /* u_fp type value */
79 #define FS      4       /* s_fp type value */
80 #define UI      5       /* unsigned integer value */
81 #define SI      6       /* signed integer value */
82 #define HA      7       /* host address */
83 #define NA      8       /* network address */
84 #define ST      9       /* string value */
85 #define RF      10      /* refid (sometimes string, sometimes not) */
86 #define LP      11      /* leap (print in binary) */
87 #define OC      12      /* integer, print in octal */
88 #define MD      13      /* mode */
89 #define AR      14      /* array of times */
90 #define FX      15      /* test flags */
91 #define EOV     255     /* end of table */
92
93
94 /*
95  * System variable values.  The array can be indexed by
96  * the variable index to find the textual name.
97  */
98 struct ctl_var sys_var[] = {
99         { 0,            PADDING, "" },          /* 0 */
100         { CS_LEAP,      LP,     "leap" },       /* 1 */
101         { CS_STRATUM,   UI,     "stratum" },    /* 2 */
102         { CS_PRECISION, SI,     "precision" },  /* 3 */
103         { CS_ROOTDELAY, FS,     "rootdelay" },  /* 4 */
104         { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
105         { CS_REFID,     RF,     "refid" },      /* 6 */
106         { CS_REFTIME,   TS,     "reftime" },    /* 7 */
107         { CS_POLL,      UI,     "poll" },       /* 8 */
108         { CS_PEERID,    UI,     "peer" },       /* 9 */
109         { CS_STATE,     UI,     "state" },      /* 10 */
110         { CS_OFFSET,    FL,     "offset" },     /* 11 */
111         { CS_DRIFT,     FS,     "frequency" },  /* 12 */
112         { CS_JITTER,    FU,     "jitter" },     /* 13 */
113         { CS_CLOCK,     TS,     "clock" },      /* 14 */
114         { CS_PROCESSOR, ST,     "processor" },  /* 15 */
115         { CS_SYSTEM,    ST,     "system" },     /* 16 */
116         { CS_VERSION,   ST,     "version" },    /* 17 */
117         { CS_STABIL,    FS,     "stability" },  /* 18 */
118         { CS_VARLIST,   ST,     "sys_var_list" }, /* 19 */
119         { 0,            EOV,    ""      }
120 };
121
122
123 /*
124  * Peer variable list
125  */
126 struct ctl_var peer_var[] = {
127         { 0,            PADDING, "" },          /* 0 */
128         { CP_CONFIG,    UI,     "config" },     /* 1 */
129         { CP_AUTHENABLE, UI,    "authenable" }, /* 2 */
130         { CP_AUTHENTIC, UI,     "authentic" },  /* 3 */
131         { CP_SRCADR,    HA,     "srcadr" },     /* 4 */
132         { CP_SRCPORT,   UI,     "srcport" },    /* 5 */
133         { CP_DSTADR,    NA,     "dstadr" },     /* 6 */
134         { CP_DSTPORT,   UI,     "dstport" },    /* 7 */
135         { CP_LEAP,      LP,     "leap" },       /* 8 */
136         { CP_HMODE,     MD,     "hmode" },      /* 9 */
137         { CP_STRATUM,   UI,     "stratum" },    /* 10 */
138         { CP_PPOLL,     UI,     "ppoll" },      /* 11 */
139         { CP_HPOLL,     UI,     "hpoll" },      /* 12 */
140         { CP_PRECISION, SI,     "precision" },  /* 13 */
141         { CP_ROOTDELAY, FS,     "rootdelay" },  /* 14 */
142         { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */
143         { CP_REFID,     RF,     "refid" },      /* 16 */
144         { CP_REFTIME,   TS,     "reftime" },    /* 17 */
145         { CP_ORG,       TS,     "org" },        /* 18 */
146         { CP_REC,       TS,     "rec" },        /* 19 */
147         { CP_XMT,       TS,     "xmt" },        /* 20 */
148         { CP_REACH,     OC,     "reach" },      /* 21 */
149         { CP_VALID,     UI,     "valid" },      /* 22 */
150         { CP_TIMER,     UI,     "timer" },      /* 23 */
151         { CP_DELAY,     FS,     "delay" },      /* 24 */
152         { CP_OFFSET,    FL,     "offset" },     /* 25 */
153         { CP_JITTER,    FU,     "jitter" },     /* 26 */
154         { CP_DISPERSION, FU,    "dispersion" }, /* 27 */
155         { CP_KEYID,     UI,     "keyid" },      /* 28 */
156         { CP_FILTDELAY, AR,     "filtdelay" },  /* 29 */
157         { CP_FILTOFFSET, AR,    "filtoffset" }, /* 30 */
158         { CP_PMODE,     ST,     "pmode" },      /* 31 */
159         { CP_RECEIVED,  UI,     "received" },   /* 32 */
160         { CP_SENT,      UI,     "sent" },       /* 33 */
161         { CP_FILTERROR, AR,     "filtdisp" },   /* 34 */
162         { CP_FLASH,     FX,     "flash" },      /* 35 */ 
163         { CP_TTL,       UI,     "ttl" },        /* 36 */
164         { CP_TTLMAX,    UI,     "ttlmax" },     /* 37 */
165         /*
166          * These are duplicate entries so that we can
167          * process deviant version of the ntp protocol.
168          */
169         { CP_SRCADR,    HA,     "peeraddr" },   /* 4 */
170         { CP_SRCPORT,   UI,     "peerport" },   /* 5 */
171         { CP_PPOLL,     UI,     "peerpoll" },   /* 11 */
172         { CP_HPOLL,     UI,     "hostpoll" },   /* 12 */
173         { CP_FILTERROR, AR,     "filterror" },  /* 34 */
174         { 0,            EOV,    ""      }
175 };
176
177
178 /*
179  * Clock variable list
180  */
181 struct ctl_var clock_var[] = {
182         { 0,            PADDING, "" },          /* 0 */
183         { CC_TYPE,      UI,     "type" },       /* 1 */
184         { CC_TIMECODE,  ST,     "timecode" },   /* 2 */
185         { CC_POLL,      UI,     "poll" },       /* 3 */
186         { CC_NOREPLY,   UI,     "noreply" },    /* 4 */
187         { CC_BADFORMAT, UI,     "badformat" },  /* 5 */
188         { CC_BADDATA,   UI,     "baddata" },    /* 6 */
189         { CC_FUDGETIME1, FL,    "fudgetime1" }, /* 7 */
190         { CC_FUDGETIME2, FL,    "fudgetime2" }, /* 8 */
191         { CC_FUDGEVAL1, UI,     "stratum" },    /* 9 */
192         { CC_FUDGEVAL2, RF,     "refid" },      /* 10 */
193         { CC_FLAGS,     UI,     "flags" },      /* 11 */
194         { CC_DEVICE,    ST,     "device" },     /* 12 */
195         { 0,            EOV,    ""      }
196 };
197
198
199 /*
200  * flasher bits
201  */
202 static const char *tstflagnames[] = {
203         "dup_pkt",              /* TEST1 */
204         "bogus_pkt",            /* TEST2 */
205         "proto_unsync",         /* TEST3 */
206         "no_access",            /* TEST4 */
207         "bad_auth",                     /* TEST5 */
208         "peer_unsync",          /* TEST6 */
209         "peer_stratum",         /* TEST7 */
210         "root_bounds",          /* TEST8 */
211         "peer_bounds",          /* TEST9 */
212         "bad_autokey",          /* TEST10 */
213         "not_proventic"         /* TEST11*/
214 };
215
216
217 int             ntpqmain        P((int, char **));
218 /*
219  * Built in command handler declarations
220  */
221 static  int     openhost        P((const char *));
222 static  int     sendpkt         P((char *, int));
223 static  int     getresponse     P((int, int, u_short *, int *, char **, int));
224 static  int     sendrequest     P((int, int, int, int, char *));
225 static  char *  tstflags        P((u_long));
226 static  void    getcmds         P((void));
227 static  RETSIGTYPE abortcmd     P((int));
228 static  void    docmd           P((const char *));
229 static  void    tokenize        P((const char *, char **, int *));
230 static  int     findcmd         P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
231 static  int     getarg          P((char *, int, arg_v *));
232 static  int     rtdatetolfp     P((char *, l_fp *));
233 static  int     decodearr       P((char *, int *, l_fp *));
234 static  void    help            P((struct parse *, FILE *));
235 #ifdef QSORT_USES_VOID_P
236 static  int     helpsort        P((const void *, const void *));
237 #else
238 static  int     helpsort        P((char **, char **));
239 #endif
240 static  void    printusage      P((struct xcmd *, FILE *));
241 static  void    timeout         P((struct parse *, FILE *));
242 static  void    auth_delay      P((struct parse *, FILE *));
243 static  void    host            P((struct parse *, FILE *));
244 static  void    ntp_poll        P((struct parse *, FILE *));
245 static  void    keyid           P((struct parse *, FILE *));
246 static  void    keytype         P((struct parse *, FILE *));
247 static  void    passwd          P((struct parse *, FILE *));
248 static  void    hostnames       P((struct parse *, FILE *));
249 static  void    setdebug        P((struct parse *, FILE *));
250 static  void    quit            P((struct parse *, FILE *));
251 static  void    version         P((struct parse *, FILE *));
252 static  void    raw             P((struct parse *, FILE *));
253 static  void    cooked          P((struct parse *, FILE *));
254 static  void    authenticate    P((struct parse *, FILE *));
255 static  void    ntpversion      P((struct parse *, FILE *));
256 static  void    warning         P((const char *, const char *, const char *));
257 static  void    error           P((const char *, const char *, const char *));
258 static  u_long  getkeyid        P((const char *));
259 static  void    atoascii        P((int, char *, char *));
260 static  void    makeascii       P((int, char *, FILE *));
261 static  void    rawprint        P((int, int, char *, int, FILE *));
262 static  void    startoutput     P((void));
263 static  void    output          P((FILE *, char *, char *));
264 static  void    endoutput       P((FILE *));
265 static  void    outputarr       P((FILE *, char *, int, l_fp *));
266 static  void    cookedprint     P((int, int, char *, int, FILE *));
267 #ifdef QSORT_USES_VOID_P
268 static  int     assoccmp        P((const void *, const void *));
269 #else
270 static  int     assoccmp        P((struct association *, struct association *));
271 #endif /* sgi || bsdi */
272
273
274 /*
275  * Built-in commands we understand
276  */
277 struct xcmd builtins[] = {
278         { "?",          help,           {  OPT|STR, NO, NO, NO },
279           { "command", "", "", "" },
280           "tell the use and syntax of commands" },
281         { "help",       help,           {  OPT|STR, NO, NO, NO },
282           { "command", "", "", "" },
283           "tell the use and syntax of commands" },
284         { "timeout",    timeout,        { OPT|UINT, NO, NO, NO },
285           { "msec", "", "", "" },
286           "set the primary receive time out" },
287         { "delay",      auth_delay,     { OPT|INT, NO, NO, NO },
288           { "msec", "", "", "" },
289           "set the delay added to encryption time stamps" },
290         { "host",       host,           { OPT|STR, NO, NO, NO },
291           { "hostname", "", "", "" },
292           "specify the host whose NTP server we talk to" },
293         { "poll",       ntp_poll,       { OPT|UINT, OPT|STR, NO, NO },
294           { "n", "verbose", "", "" },
295           "poll an NTP server in client mode `n' times" },
296         { "passwd",     passwd,         { NO, NO, NO, NO },
297           { "", "", "", "" },
298           "specify a password to use for authenticated requests"},
299         { "hostnames",  hostnames,      { OPT|STR, NO, NO, NO },
300           { "yes|no", "", "", "" },
301           "specify whether hostnames or net numbers are printed"},
302         { "debug",      setdebug,       { OPT|STR, NO, NO, NO },
303           { "no|more|less", "", "", "" },
304           "set/change debugging level" },
305         { "quit",       quit,           { NO, NO, NO, NO },
306           { "", "", "", "" },
307           "exit ntpq" },
308         { "exit",       quit,           { NO, NO, NO, NO },
309           { "", "", "", "" },
310           "exit ntpq" },
311         { "keyid",      keyid,          { OPT|UINT, NO, NO, NO },
312           { "key#", "", "", "" },
313           "set keyid to use for authenticated requests" },
314         { "version",    version,        { NO, NO, NO, NO },
315           { "", "", "", "" },
316           "print version number" },
317         { "raw",        raw,            { NO, NO, NO, NO },
318           { "", "", "", "" },
319           "do raw mode variable output" },
320         { "cooked",     cooked,         { NO, NO, NO, NO },
321           { "", "", "", "" },
322           "do cooked mode variable output" },
323         { "authenticate", authenticate, { OPT|STR, NO, NO, NO },
324           { "yes|no", "", "", "" },
325           "always authenticate requests to this server" },
326         { "ntpversion", ntpversion,     { OPT|UINT, NO, NO, NO },
327           { "version number", "", "", "" },
328           "set the NTP version number to use for requests" },
329         { "keytype",    keytype,        { OPT|STR, NO, NO, NO },
330           { "key type (md5|des)", "", "", "" },
331           "set key type to use for authenticated requests (des|md5)" },
332         { 0,            0,              { NO, NO, NO, NO },
333           { "", "", "", "" }, "" }
334 };
335
336
337 /*
338  * Default values we use.
339  */
340 #define DEFTIMEOUT      (5)             /* 5 second time out */
341 #define DEFSTIMEOUT     (2)             /* 2 second time out after first */
342 #define DEFDELAY        0x51EB852       /* 20 milliseconds, l_fp fraction */
343 #define DEFHOST         "127.0.0.1"     /* default host name */
344 #define LENHOSTNAME     256             /* host name is 256 characters long */
345 #define MAXCMDS         100             /* maximum commands on cmd line */
346 #define MAXHOSTS        200             /* maximum hosts on cmd line */
347 #define MAXLINE         512             /* maximum line length */
348 #define MAXTOKENS       (1+MAXARGS+2)   /* maximum number of usable tokens */
349 #define MAXVARLEN       256             /* maximum length of a variable name */
350 #define MAXVALLEN       400             /* maximum length of a variable value */
351 #define MAXOUTLINE      72              /* maximum length of an output line */
352
353 /*
354  * Some variables used and manipulated locally
355  */
356 struct timeval tvout = { DEFTIMEOUT, 0 };       /* time out for reads */
357 struct timeval tvsout = { DEFSTIMEOUT, 0 };     /* secondary time out */
358 l_fp delay_time;                                /* delay time */
359 char currenthost[LENHOSTNAME];                  /* current host name */
360 struct sockaddr_in hostaddr = { 0 };            /* host address */
361 int showhostnames = 1;                          /* show host names by default */
362
363 int sockfd;                                     /* fd socket is opened on */
364 int havehost = 0;                               /* set to 1 when host open */
365 struct servent *server_entry = NULL;            /* server entry for ntp */
366
367 #ifdef SYS_WINNT
368 WORD wVersionRequested;
369 WSADATA wsaData;
370 DWORD NumberOfBytesWritten;
371
372 HANDLE  TimerThreadHandle = NULL;       /* 1998/06/03 - Used in ntplib/machines.c */
373 void timer(void)        {  ; }; /* 1998/06/03 - Used in ntplib/machines.c */
374
375 #endif /* SYS_WINNT */
376
377 /*
378  * Sequence number used for requests.  It is incremented before
379  * it is used.
380  */
381 u_short sequence;
382
383 /*
384  * Holds data returned from queries.  Declare buffer long to be sure of
385  * alignment.
386  */
387 #define MAXFRAGS        24              /* maximum number of fragments */
388 #define DATASIZE        (MAXFRAGS*480)  /* maximum amount of data */
389 long pktdata[DATASIZE/sizeof(long)];
390
391 /*
392  * Holds association data for use with the &n operator.
393  */
394 struct association assoc_cache[MAXASSOC];
395 int numassoc = 0;               /* number of cached associations */
396
397 /*
398  * For commands typed on the command line (with the -c option)
399  */
400 int numcmds = 0;
401 const char *ccmds[MAXCMDS];
402 #define ADDCMD(cp)      if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
403
404 /*
405  * When multiple hosts are specified.
406  */
407 int numhosts = 0;
408 const char *chosts[MAXHOSTS];
409 #define ADDHOST(cp)     if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
410
411 /*
412  * Error codes for internal use
413  */
414 #define ERR_UNSPEC              256
415 #define ERR_INCOMPLETE  257
416 #define ERR_TIMEOUT             258
417 #define ERR_TOOMUCH             259
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 jmp_buf interrupt_buf;
430
431 /*
432  * Points at file being currently printed into
433  */
434 FILE *current_output;
435
436 /*
437  * Command table imported from ntpdc_ops.c
438  */
439 extern struct xcmd opcmds[];
440
441 char *progname;
442 volatile int debug;
443
444 #ifdef NO_MAIN_ALLOWED
445 CALL(ntpq,"ntpq",ntpqmain);
446
447 void clear_globals(void)
448 {
449     extern int ntp_optind;
450     extern char *ntp_optarg;
451     showhostnames = 0;                          /* don'tshow host names by default */
452     ntp_optind = 0;
453     ntp_optarg = 0;
454     server_entry = NULL;            /* server entry for ntp */
455     havehost = 0;                               /* set to 1 when host open */
456     numassoc = 0;               /* number of cached associations */
457     numcmds = 0;
458     numhosts = 0;
459 }
460 #endif
461
462 /*
463  * main - parse arguments and handle options
464  */
465 #ifndef NO_MAIN_ALLOWED
466 int
467 main(
468         int argc,
469         char *argv[]
470         )
471 {
472         return ntpqmain(argc, argv);
473 }
474 #endif
475
476 int
477 ntpqmain(
478         int argc,
479         char *argv[]
480         )
481 {
482         int c;
483         int errflg = 0;
484         extern int ntp_optind;
485         extern char *ntp_optarg;
486
487 #ifdef NO_MAIN_ALLOWED
488     clear_globals();
489     taskPrioritySet(taskIdSelf(), 100 );
490 #endif
491         delay_time.l_ui = 0;
492         delay_time.l_uf = DEFDELAY;
493
494         progname = argv[0];
495         while ((c = ntp_getopt(argc, argv, "c:dinp")) != EOF)
496             switch (c) {
497                 case 'c':
498                     ADDCMD(ntp_optarg);
499                     break;
500                 case 'd':
501                     ++debug;
502                     break;
503                 case 'i':
504                     interactive = 1;
505                     break;
506                 case 'n':
507                     showhostnames = 0;
508                     break;
509                 case 'p':
510                     ADDCMD("peers");
511                     break;
512                 default:
513                     errflg++;
514                     break;
515             }
516         if (errflg) {
517                 (void) fprintf(stderr,
518                                "usage: %s [-dinp] [-c cmd] host ...\n",
519                                progname);
520                 exit(2);
521         }
522         if (ntp_optind == argc) {
523                 ADDHOST(DEFHOST);
524         } else {
525                 for (; ntp_optind < argc; ntp_optind++)
526                     ADDHOST(argv[ntp_optind]);
527         }
528
529         if (numcmds == 0 && interactive == 0
530             && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
531                 interactive = 1;
532         }
533
534 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
535         if (interactive)
536             (void) signal_no_reset(SIGINT, abortcmd);
537 #endif /* SYS_WINNT */
538
539 #ifdef SYS_WINNT
540         wVersionRequested = MAKEWORD(1,1);
541         if (WSAStartup(wVersionRequested, &wsaData)) {
542                 fprintf(stderr, "No useable winsock.dll");
543                 exit(1);
544         }
545 #endif /* SYS_WINNT */
546
547         if (numcmds == 0) {
548                 (void) openhost(chosts[0]);
549                 getcmds();
550         } else {
551                 int ihost;
552                 int icmd;
553
554                 for (ihost = 0; ihost < numhosts; ihost++) {
555                         if (openhost(chosts[ihost]))
556                             for (icmd = 0; icmd < numcmds; icmd++)
557                                 docmd(ccmds[icmd]);
558                 }
559         }
560 #ifdef SYS_WINNT
561         WSACleanup();
562 #endif /* SYS_WINNT */
563         return 0;
564 }
565
566
567 /*
568  * openhost - open a socket to a host
569  */
570 static int
571 openhost(
572         const char *hname
573         )
574 {
575         u_int32 netnum;
576         char temphost[LENHOSTNAME];
577
578         if (server_entry == NULL) {
579                 server_entry = getservbyname("ntp", "udp");
580                 if (server_entry == NULL) {
581 #ifdef VMS /* UCX getservbyname() doesn't work [yet], but we do know better */
582                         server_entry = (struct servent *)
583                                 malloc(sizeof(struct servent));
584                         server_entry->s_port = htons(NTP_PORT);
585 #else
586                         (void) fprintf(stderr, "%s: ntp/udp: unknown service\n",
587                                        progname);
588                         exit(1);
589 #endif /* VMS & UCX */
590                 }
591                 if (debug > 2)
592                     printf("Got ntp/udp service entry\n");
593         }
594
595         if (!getnetnum(hname, &netnum, temphost))
596             return 0;
597         
598         if (debug > 2)
599             printf("Opening host %s\n", temphost);
600
601         if (havehost == 1) {
602                 if (debug > 2)
603                     printf("Closing old host %s\n", currenthost);
604                 (void) closesocket(sockfd);
605                 havehost = 0;
606         }
607         (void) strcpy(currenthost, temphost);
608
609         hostaddr.sin_family = AF_INET;
610 #ifndef SYS_VXWORKS
611         hostaddr.sin_port = server_entry->s_port;
612 #else
613     hostaddr.sin_port = htons(SERVER_PORT_NUM);
614 #endif
615         hostaddr.sin_addr.s_addr = netnum;
616
617 #ifdef SYS_WINNT
618         {
619                 int optionValue = SO_SYNCHRONOUS_NONALERT;
620                 int err;
621                 err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
622                 if (err != NO_ERROR) {
623                         (void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
624                         exit(1);
625                 }
626         }
627
628
629         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
630         if (sockfd == INVALID_SOCKET) {
631                 error("socket", "", "");
632                 exit(-1);
633         }
634 #else
635         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
636         if (sockfd == -1)
637             error("socket", "", "");
638 #endif /* SYS_WINNT */
639
640         
641 #ifdef NEED_RCVBUF_SLOP
642 # ifdef SO_RCVBUF
643         { int rbufsize = DATASIZE + 2048;       /* 2K for slop */
644         if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
645                        &rbufsize, sizeof(int)) == -1)
646             error("setsockopt", "", "");
647         }
648 # endif
649 #endif
650
651         if (connect(sockfd, (struct sockaddr *)&hostaddr,
652                     sizeof(hostaddr)) == -1)
653             error("connect", "", "");
654         
655         havehost = 1;
656         return 1;
657 }
658
659
660 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
661 /*
662  * sendpkt - send a packet to the remote host
663  */
664 static int
665 sendpkt(
666         char *xdata,
667         int xdatalen
668         )
669 {
670         if (debug >= 3)
671             printf("Sending %d octets\n", xdatalen);
672
673
674         if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
675                 warning("write to %s failed", currenthost, "");
676                 return -1;
677         }
678
679         if (debug >= 4) {
680                 int first = 8;
681                 printf("Packet data:\n");
682                 while (xdatalen-- > 0) {
683                         if (first-- == 0) {
684                                 printf("\n");
685                                 first = 7;
686                         }
687                         printf(" %02x", *xdata++ & 0xff);
688                 }
689                 printf("\n");
690         }
691         return 0;
692 }
693
694
695
696 /*
697  * getresponse - get a (series of) response packet(s) and return the data
698  */
699 static int
700 getresponse(
701         int opcode,
702         int associd,
703         u_short *rstatus,
704         int *rsize,
705         char **rdata,
706         int timeo
707         )
708 {
709         struct ntp_control rpkt;
710         struct timeval tvo;
711         u_short offsets[MAXFRAGS+1];
712         u_short counts[MAXFRAGS+1];
713         u_short offset;
714         u_short count;
715         int numfrags;
716         int seenlastfrag;
717         fd_set fds;
718         int n;
719
720         /*
721          * This is pretty tricky.  We may get between 1 and MAXFRAG packets
722          * back in response to the request.  We peel the data out of
723          * each packet and collect it in one long block.  When the last
724          * packet in the sequence is received we'll know how much data we
725          * should have had.  Note we use one long time out, should reconsider.
726          */
727         *rsize = 0;
728         if (rstatus)
729             *rstatus = 0;
730         *rdata = (char *)pktdata;
731
732         numfrags = 0;
733         seenlastfrag = 0;
734
735         FD_ZERO(&fds);
736
737     again:
738         if (numfrags == 0)
739             tvo = tvout;
740         else
741             tvo = tvsout;
742         
743         FD_SET(sockfd, &fds);
744         n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
745
746 #if 0
747         if (debug >= 1)
748             printf("select() returns %d\n", n);
749 #endif
750
751         if (n == -1) {
752                 warning("select fails", "", "");
753                 return -1;
754         }
755         if (n == 0) {
756                 /*
757                  * Timed out.  Return what we have
758                  */
759                 if (numfrags == 0) {
760                         if (timeo)
761                             (void) fprintf(stderr,
762                                            "%s: timed out, nothing received\n",
763                                            currenthost);
764                         return ERR_TIMEOUT;
765                 } else {
766                         if (timeo)
767                             (void) fprintf(stderr,
768                                            "%s: timed out with incomplete data\n",
769                                            currenthost);
770                         if (debug) {
771                                 printf("Received fragments:\n");
772                                 for (n = 0; n < numfrags; n++)
773                                     printf("%4d %d\n", offsets[n],
774                                            counts[n]);
775                                 if (seenlastfrag)
776                                     printf("last fragment received\n");
777                                 else
778                                     printf("last fragment not received\n");
779                         }
780                         return ERR_INCOMPLETE;
781                 }
782         }
783
784         n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
785         if (n == -1) {
786                 warning("read", "", "");
787                 return -1;
788         }
789
790         if (debug >= 4) {
791                 int len = n, first = 8;
792                 char *data = (char *)&rpkt;
793
794                 printf("Packet data:\n");
795                 while (len-- > 0) {
796                         if (first-- == 0) {
797                                 printf("\n");
798                                 first = 7;
799                         }
800                         printf(" %02x", *data++ & 0xff);
801                 }
802                 printf("\n");
803         }
804
805         /*
806          * Check for format errors.  Bug proofing.
807          */
808         if (n < CTL_HEADER_LEN) {
809                 if (debug)
810                     printf("Short (%d byte) packet received\n", n);
811                 goto again;
812         }
813         if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
814             || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
815                 if (debug)
816                     printf("Packet received with version %d\n",
817                            PKT_VERSION(rpkt.li_vn_mode));
818                 goto again;
819         }
820         if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
821                 if (debug)
822                     printf("Packet received with mode %d\n",
823                            PKT_MODE(rpkt.li_vn_mode));
824                 goto again;
825         }
826         if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
827                 if (debug)
828                     printf("Received request packet, wanted response\n");
829                 goto again;
830         }
831
832         /*
833          * Check opcode and sequence number for a match.
834          * Could be old data getting to us.
835          */
836         if (ntohs(rpkt.sequence) != sequence) {
837                 if (debug)
838                     printf(
839                             "Received sequnce number %d, wanted %d\n",
840                             ntohs(rpkt.sequence), sequence);
841                 goto again;
842         }
843         if (CTL_OP(rpkt.r_m_e_op) != opcode) {
844                 if (debug)
845                     printf(
846                             "Received opcode %d, wanted %d (sequence number okay)\n",
847                             CTL_OP(rpkt.r_m_e_op), opcode);
848                 goto again;
849         }
850
851         /*
852          * Check the error code.  If non-zero, return it.
853          */
854         if (CTL_ISERROR(rpkt.r_m_e_op)) {
855                 int errcode;
856
857                 errcode = (ntohs(rpkt.status) >> 8) & 0xff;
858                 if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
859                         printf("Error code %d received on not-final packet\n",
860                                errcode);
861                 }
862                 if (errcode == CERR_UNSPEC)
863                     return ERR_UNSPEC;
864                 return errcode;
865         }
866
867         /*
868          * Check the association ID to make sure it matches what
869          * we sent.
870          */
871         if (ntohs(rpkt.associd) != associd) {
872                 if (debug)
873                     printf("Association ID %d doesn't match expected %d\n",
874                            ntohs(rpkt.associd), associd);
875                 /*
876                  * Hack for silly fuzzballs which, at the time of writing,
877                  * return an assID of sys.peer when queried for system variables.
878                  */
879 #ifdef notdef
880                 goto again;
881 #endif
882         }
883
884         /*
885          * Collect offset and count.  Make sure they make sense.
886          */
887         offset = ntohs(rpkt.offset);
888         count = ntohs(rpkt.count);
889
890         if (debug >= 3) {
891                 int shouldbesize;
892                 u_long key;
893                 u_long *lpkt;
894                 int maclen;
895
896                 /*
897                  * Usually we ignore authentication, but for debugging purposes
898                  * we watch it here.
899                  */
900                 shouldbesize = CTL_HEADER_LEN + count;
901
902                 /* round to 8 octet boundary */
903                 shouldbesize = (shouldbesize + 7) & ~7;
904
905                 if (n & 0x3) {
906                         printf("Packet not padded, size = %d\n", n);
907                 } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) {
908                         printf(
909                                 "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
910                                 n, shouldbesize, maclen);
911                         lpkt = (u_long *)&rpkt;
912                         printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
913                                (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]),
914                                (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]),
915                                (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]),
916                                (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]),
917                                (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]),
918                                (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2]));
919                         key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]);
920                         printf("Authenticated with keyid %lu\n", (u_long)key);
921                         if (key != 0 && key != info_auth_keyid) {
922                                 printf("We don't know that key\n");
923                         } else {
924                                 if (authdecrypt(key, (u_int32 *)&rpkt,
925                                     n - maclen, maclen)) {
926                                         printf("Auth okay!\n");
927                                 } else {
928                                         printf("Auth failed!\n");
929                                 }
930                         }
931                 }
932         }
933
934         if (debug >= 2)
935             printf("Got packet, size = %d\n", n);
936         if (count > (u_short)(n-CTL_HEADER_LEN)) {
937                 if (debug)
938                     printf(
939                             "Received count of %d octets, data in packet is %d\n",
940                             count, n-CTL_HEADER_LEN);
941                 goto again;
942         }
943         if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
944                 if (debug)
945                     printf("Received count of 0 in non-final fragment\n");
946                 goto again;
947         }
948         if (offset + count > sizeof(pktdata)) {
949                 if (debug)
950                     printf("Offset %d, count %d, too big for buffer\n",
951                            offset, count);
952                 return ERR_TOOMUCH;
953         }
954         if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
955                 if (debug)
956                     printf("Received second last fragment packet\n");
957                 goto again;
958         }
959
960         /*
961          * So far, so good.  Record this fragment, making sure it doesn't
962          * overlap anything.
963          */
964         if (debug >= 2)
965             printf("Packet okay\n");;
966
967         if (numfrags == MAXFRAGS) {
968                 if (debug)
969                     printf("Number of fragments exceeds maximum\n");
970                 return ERR_TOOMUCH;
971         }
972         
973         for (n = 0; n < numfrags; n++) {
974                 if (offset == offsets[n])
975                     goto again; /* duplicate */
976                 if (offset < offsets[n])
977                     break;
978         }
979         
980         if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset)
981             goto overlap;
982         if (n < numfrags && (u_short)(offset + count) > offsets[n])
983             goto overlap;
984         
985         {
986                 register int i;
987                 
988                 for (i = numfrags; i > n; i--) {
989                         offsets[i] = offsets[i-1];
990                         counts[i] = counts[i-1];
991                 }
992         }
993         offsets[n] = offset;
994         counts[n] = count;
995         numfrags++;
996
997         /*
998          * Got that stuffed in right.  Figure out if this was the last.
999          * Record status info out of the last packet.
1000          */
1001         if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1002                 seenlastfrag = 1;
1003                 if (rstatus != 0)
1004                     *rstatus = ntohs(rpkt.status);
1005         }
1006
1007         /*
1008          * Copy the data into the data buffer.
1009          */
1010         memmove((char *)pktdata + offset, (char *)rpkt.data, count);
1011
1012         /*
1013          * If we've seen the last fragment, look for holes in the sequence.
1014          * If there aren't any, we're done.
1015          */
1016         if (seenlastfrag && offsets[0] == 0) {
1017                 for (n = 1; n < numfrags; n++) {
1018                         if (offsets[n-1] + counts[n-1] != offsets[n])
1019                             break;
1020                 }
1021                 if (n == numfrags) {
1022                         *rsize = offsets[numfrags-1] + counts[numfrags-1];
1023                         return 0;
1024                 }
1025         }
1026         goto again;
1027
1028     overlap:
1029         /*
1030          * Print debugging message about overlapping fragments
1031          */
1032         if (debug)
1033             printf("Overlapping fragments returned in response\n");
1034         goto again;
1035 }
1036
1037
1038 /*
1039  * sendrequest - format and send a request packet
1040  */
1041 static int
1042 sendrequest(
1043         int opcode,
1044         int associd,
1045         int auth,
1046         int qsize,
1047         char *qdata
1048         )
1049 {
1050         struct ntp_control qpkt;
1051         int pktsize;
1052
1053         /*
1054          * Check to make sure the data will fit in one packet
1055          */
1056         if (qsize > CTL_MAX_DATA_LEN) {
1057                 (void) fprintf(stderr,
1058                                "***Internal error!  qsize (%d) too large\n",
1059                                qsize);
1060                 return 1;
1061         }
1062
1063         /*
1064          * Fill in the packet
1065          */
1066         qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1067         qpkt.r_m_e_op = (u_char)opcode & CTL_OP_MASK;
1068         qpkt.sequence = htons(sequence);
1069         qpkt.status = 0;
1070         qpkt.associd = htons((u_short)associd);
1071         qpkt.offset = 0;
1072         qpkt.count = htons((u_short)qsize);
1073
1074         /*
1075          * If we have data, copy it in and pad it out to a 64
1076          * bit boundary.
1077          */
1078         if (qsize > 0) {
1079                 memmove((char *)qpkt.data, qdata, (unsigned)qsize);
1080                 pktsize = qsize + CTL_HEADER_LEN;
1081                 while (pktsize & (sizeof(u_long) - 1)) {
1082                         qpkt.data[qsize++] = 0;
1083                         pktsize++;
1084                 }
1085         } else {
1086                 pktsize = CTL_HEADER_LEN;
1087         }
1088
1089         /*
1090          * If it isn't authenticated we can just send it.  Otherwise
1091          * we're going to have to think about it a little.
1092          */
1093         if (!auth && !always_auth) {
1094                 return sendpkt((char *)&qpkt, pktsize);
1095         } else {
1096                 const char *pass = "\0";
1097                 int maclen = 0;
1098                 u_long my_keyid;
1099
1100                 /*
1101                  * Pad out packet to a multiple of 8 octets to be sure
1102                  * receiver can handle it.
1103                  */
1104                 while (pktsize & 7) {
1105                         qpkt.data[qsize++] = 0;
1106                         pktsize++;
1107                 }
1108
1109                 /*
1110                  * Get the keyid and the password if we don't have one.
1111                  */
1112                 if (info_auth_keyid == 0) {
1113                         maclen = getkeyid("Keyid: ");
1114                         if (maclen == 0) {
1115                                 (void) fprintf(stderr,
1116                                    "Invalid key identifier\n");
1117                                 return 1;
1118                         }
1119                 }
1120                 if (!authistrusted(info_auth_keyid)) {
1121                         pass = getpass((info_auth_keytype == KEY_TYPE_DES)
1122                             ? "DES Password: " : "MD5 Password: ");
1123                         if (*pass == '\0') {
1124                                 (void) fprintf(stderr,
1125                                   "Invalid password\n");
1126                                 return (1);
1127                         }
1128                 }
1129                 info_auth_keyid = maclen;
1130                 authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
1131                 authtrust(info_auth_keyid, 1);
1132
1133                 /*
1134                  * Stick the keyid in the packet where
1135                  * cp currently points.  Cp should be aligned
1136                  * properly.  Then do the encryptions.
1137                  */
1138                 my_keyid = htonl(info_auth_keyid);
1139                 memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid);
1140                 maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
1141                     pktsize);
1142                 if (maclen == 0) {
1143                         (void) fprintf(stderr, "Key not found\n");
1144                         return (1);
1145                 }
1146                 return sendpkt((char *)&qpkt, pktsize + maclen);
1147         }
1148         /*NOTREACHED*/
1149 }
1150
1151
1152 /*
1153  * doquery - send a request and process the response
1154  */
1155 int
1156 doquery(
1157         int opcode,
1158         int associd,
1159         int auth,
1160         int qsize,
1161         char *qdata,
1162         u_short *rstatus,
1163         int *rsize,
1164         char **rdata
1165         )
1166 {
1167         int res;
1168         int done;
1169
1170         /*
1171          * Check to make sure host is open
1172          */
1173         if (!havehost) {
1174                 (void) fprintf(stderr, "***No host open, use `host' command\n");
1175                 return -1;
1176         }
1177
1178         done = 0;
1179         sequence++;
1180
1181     again:
1182         /*
1183          * send a request
1184          */
1185         res = sendrequest(opcode, associd, auth, qsize, qdata);
1186         if (res != 0)
1187             return res;
1188         
1189         /*
1190          * Get the response.  If we got a standard error, print a message
1191          */
1192         res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1193
1194         if (res > 0) {
1195                 if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1196                         if (res == ERR_INCOMPLETE) {
1197                                 /*
1198                                  * better bump the sequence so we don't
1199                                  * get confused about differing fragments.
1200                                  */
1201                                 sequence++;
1202                         }
1203                         done = 1;
1204                         goto again;
1205                 }
1206                 switch(res) {
1207                     case CERR_BADFMT:
1208                         (void) fprintf(stderr,
1209                             "***Server reports a bad format request packet\n");
1210                         break;
1211                     case CERR_PERMISSION:
1212                         (void) fprintf(stderr,
1213                             "***Server disallowed request (authentication?)\n");
1214                         break;
1215                     case CERR_BADOP:
1216                         (void) fprintf(stderr,
1217                             "***Server reports a bad opcode in request\n");
1218                         break;
1219                     case CERR_BADASSOC:
1220                         (void) fprintf(stderr,
1221                             "***Association ID %d unknown to server\n",associd);
1222                         break;
1223                     case CERR_UNKNOWNVAR:
1224                         (void) fprintf(stderr,
1225                             "***A request variable unknown to the server\n");
1226                         break;
1227                     case CERR_BADVALUE:
1228                         (void) fprintf(stderr,
1229                             "***Server indicates a request variable was bad\n");
1230                         break;
1231                     case ERR_UNSPEC:
1232                         (void) fprintf(stderr,
1233                             "***Server returned an unspecified error\n");
1234                         break;
1235                     case ERR_TIMEOUT:
1236                         (void) fprintf(stderr, "***Request timed out\n");
1237                         break;
1238                     case ERR_INCOMPLETE:
1239                         (void) fprintf(stderr,
1240                             "***Response from server was incomplete\n");
1241                         break;
1242                     case ERR_TOOMUCH:
1243                         (void) fprintf(stderr,
1244                             "***Buffer size exceeded for returned data\n");
1245                         break;
1246                     default:
1247                         (void) fprintf(stderr,
1248                             "***Server returns unknown error code %d\n", res);
1249                         break;
1250                 }
1251         }
1252         return res;
1253 }
1254
1255
1256 /*
1257  * getcmds - read commands from the standard input and execute them
1258  */
1259 static void
1260 getcmds(void)
1261 {
1262         char line[MAXLINE];
1263
1264         for (;;) {
1265                 if (interactive) {
1266 #ifdef VMS      /* work around a problem with mixing stdout & stderr */
1267                         fputs("",stdout);
1268 #endif
1269                         (void) fputs(prompt, stderr);
1270                         (void) fflush(stderr);
1271                 }
1272
1273                 if (fgets(line, sizeof line, stdin) == NULL)
1274                     return;
1275
1276                 docmd(line);
1277         }
1278 }
1279
1280
1281 /*
1282  * abortcmd - catch interrupts and abort the current command
1283  */
1284 static RETSIGTYPE
1285 abortcmd(
1286         int sig
1287         )
1288 {
1289         if (current_output == stdout)
1290             (void) fflush(stdout);
1291         putc('\n', stderr);
1292         (void) fflush(stderr);
1293         if (jump) longjmp(interrupt_buf, 1);
1294 }
1295
1296
1297 /*
1298  * docmd - decode the command line and execute a command
1299  */
1300 static void
1301 docmd(
1302         const char *cmdline
1303         )
1304 {
1305         char *tokens[1+MAXARGS+2];
1306         struct parse pcmd;
1307         int ntok;
1308         static int i;
1309         struct xcmd *xcmd;
1310
1311         /*
1312          * Tokenize the command line.  If nothing on it, return.
1313          */
1314         tokenize(cmdline, tokens, &ntok);
1315         if (ntok == 0)
1316             return;
1317         
1318         /*
1319          * Find the appropriate command description.
1320          */
1321         i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1322         if (i == 0) {
1323                 (void) fprintf(stderr, "***Command `%s' unknown\n",
1324                                tokens[0]);
1325                 return;
1326         } else if (i >= 2) {
1327                 (void) fprintf(stderr, "***Command `%s' ambiguous\n",
1328                                tokens[0]);
1329                 return;
1330         }
1331         
1332         /*
1333          * Save the keyword, then walk through the arguments, interpreting
1334          * as we go.
1335          */
1336         pcmd.keyword = tokens[0];
1337         pcmd.nargs = 0;
1338         for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1339                 if ((i+1) >= ntok) {
1340                         if (!(xcmd->arg[i] & OPT)) {
1341                                 printusage(xcmd, stderr);
1342                                 return;
1343                         }
1344                         break;
1345                 }
1346                 if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1347                     break;
1348                 if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1349                     return;
1350                 pcmd.nargs++;
1351         }
1352
1353         i++;
1354         if (i < ntok && *tokens[i] == '>') {
1355                 char *fname;
1356
1357                 if (*(tokens[i]+1) != '\0')
1358                     fname = tokens[i]+1;
1359                 else if ((i+1) < ntok)
1360                     fname = tokens[i+1];
1361                 else {
1362                         (void) fprintf(stderr, "***No file for redirect\n");
1363                         return;
1364                 }
1365
1366                 current_output = fopen(fname, "w");
1367                 if (current_output == NULL) {
1368                         (void) fprintf(stderr, "***Error opening %s: ", fname);
1369                         perror("");
1370                         return;
1371                 }
1372                 i = 1;          /* flag we need a close */
1373         } else {
1374                 current_output = stdout;
1375                 i = 0;          /* flag no close */
1376         }
1377
1378         if (interactive && setjmp(interrupt_buf)) {
1379                 jump = 0;
1380                 return;
1381         } else {
1382                 jump++;
1383                 (xcmd->handler)(&pcmd, current_output);
1384                 jump = 0;       /* HMS: 961106: was after fclose() */
1385                 if (i) (void) fclose(current_output);
1386         }
1387 }
1388
1389
1390 /*
1391  * tokenize - turn a command line into tokens
1392  */
1393 static void
1394 tokenize(
1395         const char *line,
1396         char **tokens,
1397         int *ntok
1398         )
1399 {
1400         register const char *cp;
1401         register char *sp;
1402         static char tspace[MAXLINE];
1403
1404         sp = tspace;
1405         cp = line;
1406         for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1407                 tokens[*ntok] = sp;
1408                 while (ISSPACE(*cp))
1409                     cp++;
1410                 if (ISEOL(*cp))
1411                     break;
1412                 do {
1413                         *sp++ = *cp++;
1414                 } while (!ISSPACE(*cp) && !ISEOL(*cp));
1415
1416                 *sp++ = '\0';
1417         }
1418 }
1419
1420
1421
1422 /*
1423  * findcmd - find a command in a command description table
1424  */
1425 static int
1426 findcmd(
1427         register char *str,
1428         struct xcmd *clist1,
1429         struct xcmd *clist2,
1430         struct xcmd **cmd
1431         )
1432 {
1433         register struct xcmd *cl;
1434         register int clen;
1435         int nmatch;
1436         struct xcmd *nearmatch = NULL;
1437         struct xcmd *clist;
1438
1439         clen = strlen(str);
1440         nmatch = 0;
1441         if (clist1 != 0)
1442             clist = clist1;
1443         else if (clist2 != 0)
1444             clist = clist2;
1445         else
1446             return 0;
1447
1448     again:
1449         for (cl = clist; cl->keyword != 0; cl++) {
1450                 /* do a first character check, for efficiency */
1451                 if (*str != *(cl->keyword))
1452                     continue;
1453                 if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1454                         /*
1455                          * Could be extact match, could be approximate.
1456                          * Is exact if the length of the keyword is the
1457                          * same as the str.
1458                          */
1459                         if (*((cl->keyword) + clen) == '\0') {
1460                                 *cmd = cl;
1461                                 return 1;
1462                         }
1463                         nmatch++;
1464                         nearmatch = cl;
1465                 }
1466         }
1467
1468         /*
1469          * See if there is more to do.  If so, go again.  Sorry about the
1470          * goto, too much looking at BSD sources...
1471          */
1472         if (clist == clist1 && clist2 != 0) {
1473                 clist = clist2;
1474                 goto again;
1475         }
1476
1477         /*
1478          * If we got extactly 1 near match, use it, else return number
1479          * of matches.
1480          */
1481         if (nmatch == 1) {
1482                 *cmd = nearmatch;
1483                 return 1;
1484         }
1485         return nmatch;
1486 }
1487
1488
1489 /*
1490  * getarg - interpret an argument token
1491  */
1492 static int
1493 getarg(
1494         char *str,
1495         int code,
1496         arg_v *argp
1497         )
1498 {
1499         int isneg;
1500         char *cp, *np;
1501         static const char *digits = "0123456789";
1502
1503         switch (code & ~OPT) {
1504             case STR:
1505                 argp->string = str;
1506                 break;
1507             case ADD:
1508                 if (!getnetnum(str, &(argp->netnum), (char *)0)) {
1509                         return 0;
1510                 }
1511                 break;
1512             case INT:
1513             case UINT:
1514                 isneg = 0;
1515                 np = str;
1516                 if (*np == '&') {
1517                         np++;
1518                         isneg = atoi(np);
1519                         if (isneg <= 0) {
1520                                 (void) fprintf(stderr,
1521                                                "***Association value `%s' invalid/undecodable\n", str);
1522                                 return 0;
1523                         }
1524                         if (isneg > numassoc) {
1525                                 (void) fprintf(stderr,
1526                                                "***Association for `%s' unknown (max &%d)\n",
1527                                                str, numassoc);
1528                                 return 0;
1529                         }
1530                         argp->uval = assoc_cache[isneg-1].assid;
1531                         break;
1532                 }
1533
1534                 if (*np == '-') {
1535                         np++;
1536                         isneg = 1;
1537                 }
1538
1539                 argp->uval = 0;
1540                 do {
1541                         cp = strchr(digits, *np);
1542                         if (cp == NULL) {
1543                                 (void) fprintf(stderr,
1544                                                "***Illegal integer value %s\n", str);
1545                                 return 0;
1546                         }
1547                         argp->uval *= 10;
1548                         argp->uval += (cp - digits);
1549                 } while (*(++np) != '\0');
1550
1551                 if (isneg) {
1552                         if ((code & ~OPT) == UINT) {
1553                                 (void) fprintf(stderr,
1554                                                "***Value %s should be unsigned\n", str);
1555                                 return 0;
1556                         }
1557                         argp->ival = -argp->ival;
1558                 }
1559                 break;
1560         }
1561
1562         return 1;
1563 }
1564
1565
1566 /*
1567  * getnetnum - given a host name, return its net number
1568  *             and (optional) full name
1569  */
1570 int
1571 getnetnum(
1572         const char *hname,
1573         u_int32 *num,
1574         char *fullhost
1575         )
1576 {
1577         struct hostent *hp;
1578
1579         if (decodenetnum(hname, num)) {
1580                 if (fullhost != 0) {
1581                         (void) sprintf(fullhost, "%lu.%lu.%lu.%lu",
1582                                        (u_long)((htonl(*num) >> 24) & 0xff),
1583                                        (u_long)((htonl(*num) >> 16) & 0xff),
1584                                        (u_long)((htonl(*num) >> 8) & 0xff),
1585                                        (u_long)(htonl(*num) & 0xff));
1586                 }
1587                 return 1;
1588         } else if ((hp = gethostbyname(hname)) != 0) {
1589                 memmove((char *)num, hp->h_addr, sizeof(u_int32));
1590                 if (fullhost != 0)
1591                     (void) strcpy(fullhost, hp->h_name);
1592                 return 1;
1593         } else {
1594                 (void) fprintf(stderr, "***Can't find host %s\n", hname);
1595                 return 0;
1596         }
1597         /*NOTREACHED*/
1598 }
1599
1600 /*
1601  * nntohost - convert network number to host name.  This routine enforces
1602  *             the showhostnames setting.
1603  */
1604 char *
1605 nntohost(
1606         u_int32 netnum
1607         )
1608 {
1609         if (!showhostnames)
1610             return numtoa(netnum);
1611         if ((ntohl(netnum) & REFCLOCK_MASK) == REFCLOCK_ADDR)
1612             return refnumtoa(netnum);
1613         return numtohost(netnum);
1614 }
1615
1616
1617 /*
1618  * rtdatetolfp - decode an RT-11 date into an l_fp
1619  */
1620 static int
1621 rtdatetolfp(
1622         char *str,
1623         l_fp *lfp
1624         )
1625 {
1626         register char *cp;
1627         register int i;
1628         struct calendar cal;
1629         char buf[4];
1630         static const char *months[12] = {
1631                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1632                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1633         };
1634
1635         cal.yearday = 0;
1636
1637         /*
1638          * An RT-11 date looks like:
1639          *
1640          * d[d]-Mth-y[y] hh:mm:ss
1641          *
1642          * (No docs, but assume 4-digit years are also legal...)
1643          *
1644          * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1645          */
1646         cp = str;
1647         if (!isdigit((int)*cp)) {
1648                 if (*cp == '-') {
1649                         /*
1650                          * Catch special case
1651                          */
1652                         L_CLR(lfp);
1653                         return 1;
1654                 }
1655                 return 0;
1656         }
1657
1658         cal.monthday = *cp++ - '0';     /* ascii dependent */
1659         if (isdigit((int)*cp)) {
1660                 cal.monthday = (cal.monthday << 3) + (cal.monthday << 1);
1661                 cal.monthday += *cp++ - '0';
1662         }
1663
1664         if (*cp++ != '-')
1665             return 0;
1666         
1667         for (i = 0; i < 3; i++)
1668             buf[i] = *cp++;
1669         buf[3] = '\0';
1670
1671         for (i = 0; i < 12; i++)
1672             if (STREQ(buf, months[i]))
1673                 break;
1674         if (i == 12)
1675             return 0;
1676         cal.month = i + 1;
1677
1678         if (*cp++ != '-')
1679             return 0;
1680         
1681         if (!isdigit((int)*cp))
1682             return 0;
1683         cal.year = *cp++ - '0';
1684         if (isdigit((int)*cp)) {
1685                 cal.year = (cal.year << 3) + (cal.year << 1);
1686                 cal.year += *cp++ - '0';
1687         }
1688         if (isdigit((int)*cp)) {
1689                 cal.year = (cal.year << 3) + (cal.year << 1);
1690                 cal.year += *cp++ - '0';
1691         }
1692         if (isdigit((int)*cp)) {
1693                 cal.year = (cal.year << 3) + (cal.year << 1);
1694                 cal.year += *cp++ - '0';
1695         }
1696
1697         /*
1698          * Catch special case.  If cal.year == 0 this is a zero timestamp.
1699          */
1700         if (cal.year == 0) {
1701                 L_CLR(lfp);
1702                 return 1;
1703         }
1704
1705         if (*cp++ != ' ' || !isdigit((int)*cp))
1706             return 0;
1707         cal.hour = *cp++ - '0';
1708         if (isdigit((int)*cp)) {
1709                 cal.hour = (cal.hour << 3) + (cal.hour << 1);
1710                 cal.hour += *cp++ - '0';
1711         }
1712
1713         if (*cp++ != ':' || !isdigit((int)*cp))
1714             return 0;
1715         cal.minute = *cp++ - '0';
1716         if (isdigit((int)*cp)) {
1717                 cal.minute = (cal.minute << 3) + (cal.minute << 1);
1718                 cal.minute += *cp++ - '0';
1719         }
1720
1721         if (*cp++ != ':' || !isdigit((int)*cp))
1722             return 0;
1723         cal.second = *cp++ - '0';
1724         if (isdigit((int)*cp)) {
1725                 cal.second = (cal.second << 3) + (cal.second << 1);
1726                 cal.second += *cp++ - '0';
1727         }
1728
1729         /*
1730          * For RT-11, 1972 seems to be the pivot year
1731          */
1732         if (cal.year < 72)
1733                 cal.year += 2000;
1734         if (cal.year < 100)
1735                 cal.year += 1900;
1736
1737         lfp->l_ui = caltontp(&cal);
1738         lfp->l_uf = 0;
1739         return 1;
1740 }
1741
1742
1743 /*
1744  * decodets - decode a timestamp into an l_fp format number, with
1745  *            consideration of fuzzball formats.
1746  */
1747 int
1748 decodets(
1749         char *str,
1750         l_fp *lfp
1751         )
1752 {
1753         /*
1754          * If it starts with a 0x, decode as hex.
1755          */
1756         if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
1757             return hextolfp(str+2, lfp);
1758
1759         /*
1760          * If it starts with a '"', try it as an RT-11 date.
1761          */
1762         if (*str == '"') {
1763                 register char *cp = str+1;
1764                 register char *bp;
1765                 char buf[30];
1766
1767                 bp = buf;
1768                 while (*cp != '"' && *cp != '\0' && bp < &buf[29])
1769                     *bp++ = *cp++;
1770                 *bp = '\0';
1771                 return rtdatetolfp(buf, lfp);
1772         }
1773
1774         /*
1775          * Might still be hex.  Check out the first character.  Talk
1776          * about heuristics!
1777          */
1778         if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
1779             return hextolfp(str, lfp);
1780
1781         /*
1782          * Try it as a decimal.  If this fails, try as an unquoted
1783          * RT-11 date.  This code should go away eventually.
1784          */
1785         if (atolfp(str, lfp))
1786             return 1;
1787         return rtdatetolfp(str, lfp);
1788 }
1789
1790
1791 /*
1792  * decodetime - decode a time value.  It should be in milliseconds
1793  */
1794 int
1795 decodetime(
1796         char *str,
1797         l_fp *lfp
1798         )
1799 {
1800         return mstolfp(str, lfp);
1801 }
1802
1803
1804 /*
1805  * decodeint - decode an integer
1806  */
1807 int
1808 decodeint(
1809         char *str,
1810         long *val
1811         )
1812 {
1813         if (*str == '0') {
1814                 if (*(str+1) == 'x' || *(str+1) == 'X')
1815                     return hextoint(str+2, (u_long *)&val);
1816                 return octtoint(str, (u_long *)&val);
1817         }
1818         return atoint(str, val);
1819 }
1820
1821
1822 /*
1823  * decodeuint - decode an unsigned integer
1824  */
1825 int
1826 decodeuint(
1827         char *str,
1828         u_long *val
1829         )
1830 {
1831         if (*str == '0') {
1832                 if (*(str + 1) == 'x' || *(str + 1) == 'X')
1833                         return (hextoint(str + 2, val));
1834                 return (octtoint(str, val));
1835         }
1836         return (atouint(str, val));
1837 }
1838
1839
1840 /*
1841  * decodearr - decode an array of time values
1842  */
1843 static int
1844 decodearr(
1845         char *str,
1846         int *narr,
1847         l_fp *lfparr
1848         )
1849 {
1850         register char *cp, *bp;
1851         register l_fp *lfp;
1852         char buf[60];
1853
1854         lfp = lfparr;
1855         cp = str;
1856         *narr = 0;
1857
1858         while (*narr < 8) {
1859                 while (isspace((int)*cp))
1860                     cp++;
1861                 if (*cp == '\0')
1862                     break;
1863
1864                 bp = buf;
1865                 while (!isspace((int)*cp) && *cp != '\0')
1866                     *bp++ = *cp++;
1867                 *bp++ = '\0';
1868
1869                 if (!decodetime(buf, lfp))
1870                     return 0;
1871                 (*narr)++;
1872                 lfp++;
1873         }
1874         return 1;
1875 }
1876
1877
1878 /*
1879  * Finally, the built in command handlers
1880  */
1881
1882 /*
1883  * help - tell about commands, or details of a particular command
1884  */
1885 static void
1886 help(
1887         struct parse *pcmd,
1888         FILE *fp
1889         )
1890 {
1891         int i;
1892         int n;
1893         struct xcmd *xcp;
1894         char *cmd;
1895         const char *cmdsort[100];
1896         int length[100];
1897         int maxlength;
1898         int numperline;
1899         static const char *spaces = "                    ";     /* 20 spaces */
1900
1901         if (pcmd->nargs == 0) {
1902                 n = 0;
1903                 for (xcp = builtins; xcp->keyword != 0; xcp++) {
1904                         if (*(xcp->keyword) != '?')
1905                             cmdsort[n++] = xcp->keyword;
1906                 }
1907                 for (xcp = opcmds; xcp->keyword != 0; xcp++)
1908                     cmdsort[n++] = xcp->keyword;
1909
1910 #ifdef QSORT_USES_VOID_P
1911                 qsort(cmdsort, (size_t)n, sizeof(char *), helpsort);
1912 #else
1913                 qsort((char *)cmdsort, (size_t)n, sizeof(char *), helpsort);
1914 #endif
1915
1916                 maxlength = 0;
1917                 for (i = 0; i < n; i++) {
1918                         length[i] = strlen(cmdsort[i]);
1919                         if (length[i] > maxlength)
1920                             maxlength = length[i];
1921                 }
1922                 maxlength++;
1923                 numperline = 76 / maxlength;
1924
1925                 (void) fprintf(fp, "Commands available:\n");
1926                 for (i = 0; i < n; i++) {
1927                         if ((i % numperline) == (numperline-1)
1928                             || i == (n-1))
1929                             (void) fprintf(fp, "%s\n", cmdsort[i]);
1930                         else
1931                             (void) fprintf(fp, "%s%s", cmdsort[i],
1932                                            spaces+20-maxlength+length[i]);
1933                 }
1934         } else {
1935                 cmd = pcmd->argval[0].string;
1936                 n = findcmd(cmd, builtins, opcmds, &xcp);
1937                 if (n == 0) {
1938                         (void) fprintf(stderr,
1939                                        "Command `%s' is unknown\n", cmd);
1940                         return;
1941                 } else if (n >= 2) {
1942                         (void) fprintf(stderr,
1943                                        "Command `%s' is ambiguous\n", cmd);
1944                         return;
1945                 }
1946                 (void) fprintf(fp, "function: %s\n", xcp->comment);
1947                 printusage(xcp, fp);
1948         }
1949 }
1950
1951
1952 /*
1953  * helpsort - do hostname qsort comparisons
1954  */
1955 #ifdef QSORT_USES_VOID_P
1956 static int
1957 helpsort(
1958         const void *t1,
1959         const void *t2
1960         )
1961 {
1962         const char **name1 = (const char **)t1;
1963         const char **name2 = (const char **)t2;
1964
1965         return strcmp(*name1, *name2);
1966 }
1967
1968 #else
1969 static int
1970 helpsort(
1971         char **name1,
1972         char **name2
1973         )
1974 {
1975         return strcmp(*name1, *name2);
1976 }
1977 #endif
1978
1979 /*
1980  * printusage - print usage information for a command
1981  */
1982 static void
1983 printusage(
1984         struct xcmd *xcp,
1985         FILE *fp
1986         )
1987 {
1988         register int i;
1989
1990         (void) fprintf(fp, "usage: %s", xcp->keyword);
1991         for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
1992                 if (xcp->arg[i] & OPT)
1993                     (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
1994                 else
1995                     (void) fprintf(fp, " %s", xcp->desc[i]);
1996         }
1997         (void) fprintf(fp, "\n");
1998 }
1999
2000
2001 /*
2002  * timeout - set time out time
2003  */
2004 static void
2005 timeout(
2006         struct parse *pcmd,
2007         FILE *fp
2008         )
2009 {
2010         int val;
2011
2012         if (pcmd->nargs == 0) {
2013                 val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2014                 (void) fprintf(fp, "primary timeout %d ms\n", val);
2015         } else {
2016                 tvout.tv_sec = pcmd->argval[0].uval / 1000;
2017                 tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
2018                         * 1000;
2019         }
2020 }
2021
2022
2023 /*
2024  * auth_delay - set delay for auth requests
2025  */
2026 static void
2027 auth_delay(
2028         struct parse *pcmd,
2029         FILE *fp
2030         )
2031 {
2032         int isneg;
2033         u_long val;
2034
2035         if (pcmd->nargs == 0) {
2036                 val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2037                 (void) fprintf(fp, "delay %lu ms\n", val);
2038         } else {
2039                 if (pcmd->argval[0].ival < 0) {
2040                         isneg = 1;
2041                         val = (u_long)(-pcmd->argval[0].ival);
2042                 } else {
2043                         isneg = 0;
2044                         val = (u_long)pcmd->argval[0].ival;
2045                 }
2046
2047                 delay_time.l_ui = val / 1000;
2048                 val %= 1000;
2049                 delay_time.l_uf = val * 4294967;        /* 2**32/1000 */
2050
2051                 if (isneg)
2052                     L_NEG(&delay_time);
2053         }
2054 }
2055
2056
2057 /*
2058  * host - set the host we are dealing with.
2059  */
2060 static void
2061 host(
2062         struct parse *pcmd,
2063         FILE *fp
2064         )
2065 {
2066         if (pcmd->nargs == 0) {
2067                 if (havehost)
2068                     (void) fprintf(fp, "current host is %s\n", currenthost);
2069                 else
2070                     (void) fprintf(fp, "no current host\n");
2071         } else if (openhost(pcmd->argval[0].string)) {
2072                 (void) fprintf(fp, "current host set to %s\n", currenthost);
2073                 numassoc = 0;
2074         } else {
2075                 if (havehost)
2076                     (void) fprintf(fp,
2077                                    "current host remains %s\n", currenthost);
2078                 else
2079                     (void) fprintf(fp, "still no current host\n");
2080         }
2081 }
2082
2083
2084 /*
2085  * poll - do one (or more) polls of the host via NTP
2086  */
2087 /*ARGSUSED*/
2088 static void
2089 ntp_poll(
2090         struct parse *pcmd,
2091         FILE *fp
2092         )
2093 {
2094         (void) fprintf(fp, "poll not implemented yet\n");
2095 }
2096
2097
2098 /*
2099  * keyid - get a keyid to use for authenticating requests
2100  */
2101 static void
2102 keyid(
2103         struct parse *pcmd,
2104         FILE *fp
2105         )
2106 {
2107         if (pcmd->nargs == 0) {
2108                 if (info_auth_keyid > NTP_MAXKEY)
2109                     (void) fprintf(fp, "no keyid defined\n");
2110                 else
2111                     (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2112         } else {
2113                 info_auth_keyid = pcmd->argval[0].uval;
2114         }
2115 }
2116
2117 /*
2118  * keytype - get type of key to use for authenticating requests
2119  */
2120 static void
2121 keytype(
2122         struct parse *pcmd,
2123         FILE *fp
2124         )
2125 {
2126         if (pcmd->nargs == 0)
2127             fprintf(fp, "keytype is %s\n",
2128                     (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "DES");
2129         else
2130             switch (*(pcmd->argval[0].string)) {
2131                 case 'm':
2132                 case 'M':
2133                     info_auth_keytype = KEY_TYPE_MD5;
2134                     break;
2135
2136                 case 'd':
2137                 case 'D':
2138                     info_auth_keytype = KEY_TYPE_DES;
2139                     break;
2140
2141                 default:
2142                     fprintf(fp, "keytype must be 'md5' or 'des'\n");
2143             }
2144 }
2145
2146
2147
2148 /*
2149  * passwd - get an authentication key
2150  */
2151 /*ARGSUSED*/
2152 static void
2153 passwd(
2154         struct parse *pcmd,
2155         FILE *fp
2156         )
2157 {
2158         char *pass;
2159
2160         if (info_auth_keyid > NTP_MAXKEY) {
2161                 info_auth_keyid = getkeyid("Keyid: ");
2162                 if (info_auth_keyid > NTP_MAXKEY) {
2163                         (void)fprintf(fp, "Keyid must be defined\n");
2164                         return;
2165                 }
2166         }
2167         pass = getpass((info_auth_keytype == KEY_TYPE_DES)
2168                        ? "DES Password: "
2169                        : "MD5 Password: "
2170                        );
2171         if (*pass == '\0')
2172             (void) fprintf(fp, "Password unchanged\n");
2173         else
2174             authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
2175 }
2176
2177
2178 /*
2179  * hostnames - set the showhostnames flag
2180  */
2181 static void
2182 hostnames(
2183         struct parse *pcmd,
2184         FILE *fp
2185         )
2186 {
2187         if (pcmd->nargs == 0) {
2188                 if (showhostnames)
2189                     (void) fprintf(fp, "hostnames being shown\n");
2190                 else
2191                     (void) fprintf(fp, "hostnames not being shown\n");
2192         } else {
2193                 if (STREQ(pcmd->argval[0].string, "yes"))
2194                     showhostnames = 1;
2195                 else if (STREQ(pcmd->argval[0].string, "no"))
2196                     showhostnames = 0;
2197                 else
2198                     (void)fprintf(stderr, "What?\n");
2199         }
2200 }
2201
2202
2203
2204 /*
2205  * setdebug - set/change debugging level
2206  */
2207 static void
2208 setdebug(
2209         struct parse *pcmd,
2210         FILE *fp
2211         )
2212 {
2213         if (pcmd->nargs == 0) {
2214                 (void) fprintf(fp, "debug level is %d\n", debug);
2215                 return;
2216         } else if (STREQ(pcmd->argval[0].string, "no")) {
2217                 debug = 0;
2218         } else if (STREQ(pcmd->argval[0].string, "more")) {
2219                 debug++;
2220         } else if (STREQ(pcmd->argval[0].string, "less")) {
2221                 debug--;
2222         } else {
2223                 (void) fprintf(fp, "What?\n");
2224                 return;
2225         }
2226         (void) fprintf(fp, "debug level set to %d\n", debug);
2227 }
2228
2229
2230 /*
2231  * quit - stop this nonsense
2232  */
2233 /*ARGSUSED*/
2234 static void
2235 quit(
2236         struct parse *pcmd,
2237         FILE *fp
2238         )
2239 {
2240         if (havehost)
2241             closesocket(sockfd);        /* cleanliness next to godliness */
2242         exit(0);
2243 }
2244
2245
2246 /*
2247  * version - print the current version number
2248  */
2249 /*ARGSUSED*/
2250 static void
2251 version(
2252         struct parse *pcmd,
2253         FILE *fp
2254         )
2255 {
2256
2257         (void) fprintf(fp, "%s\n", Version);
2258         return;
2259 }
2260
2261
2262 /*
2263  * raw - set raw mode output
2264  */
2265 /*ARGSUSED*/
2266 static void
2267 raw(
2268         struct parse *pcmd,
2269         FILE *fp
2270         )
2271 {
2272         rawmode = 1;
2273         (void) fprintf(fp, "Output set to raw\n");
2274 }
2275
2276
2277 /*
2278  * cooked - set cooked mode output
2279  */
2280 /*ARGSUSED*/
2281 static void
2282 cooked(
2283         struct parse *pcmd,
2284         FILE *fp
2285         )
2286 {
2287         rawmode = 0;
2288         (void) fprintf(fp, "Output set to cooked\n");
2289         return;
2290 }
2291
2292
2293 /*
2294  * authenticate - always authenticate requests to this host
2295  */
2296 static void
2297 authenticate(
2298         struct parse *pcmd,
2299         FILE *fp
2300         )
2301 {
2302         if (pcmd->nargs == 0) {
2303                 if (always_auth) {
2304                         (void) fprintf(fp,
2305                                        "authenticated requests being sent\n");
2306                 } else
2307                     (void) fprintf(fp,
2308                                    "unauthenticated requests being sent\n");
2309         } else {
2310                 if (STREQ(pcmd->argval[0].string, "yes")) {
2311                         always_auth = 1;
2312                 } else if (STREQ(pcmd->argval[0].string, "no")) {
2313                         always_auth = 0;
2314                 } else
2315                     (void)fprintf(stderr, "What?\n");
2316         }
2317 }
2318
2319
2320 /*
2321  * ntpversion - choose the NTP version to use
2322  */
2323 static void
2324 ntpversion(
2325         struct parse *pcmd,
2326         FILE *fp
2327         )
2328 {
2329         if (pcmd->nargs == 0) {
2330                 (void) fprintf(fp,
2331                                "NTP version being claimed is %d\n", pktversion);
2332         } else {
2333                 if (pcmd->argval[0].uval < NTP_OLDVERSION
2334                     || pcmd->argval[0].uval > NTP_VERSION) {
2335                         (void) fprintf(stderr, "versions %d to %d, please\n",
2336                                        NTP_OLDVERSION, NTP_VERSION);
2337                 } else {
2338                         pktversion = (u_char) pcmd->argval[0].uval;
2339                 }
2340         }
2341 }
2342
2343
2344 /*
2345  * warning - print a warning message
2346  */
2347 static void
2348 warning(
2349         const char *fmt,
2350         const char *st1,
2351         const char *st2
2352         )
2353 {
2354         (void) fprintf(stderr, "%s: ", progname);
2355         (void) fprintf(stderr, fmt, st1, st2);
2356         (void) fprintf(stderr, ": ");
2357         perror("");
2358 }
2359
2360
2361 /*
2362  * error - print a message and exit
2363  */
2364 static void
2365 error(
2366         const char *fmt,
2367         const char *st1,
2368         const char *st2
2369         )
2370 {
2371         warning(fmt, st1, st2);
2372         exit(1);
2373 }
2374
2375 /*
2376  * getkeyid - prompt the user for a keyid to use
2377  */
2378 static u_long
2379 getkeyid(
2380         const char *keyprompt
2381         )
2382 {
2383         register char *p;
2384         register int c;
2385         FILE *fi;
2386         char pbuf[20];
2387
2388 #ifndef SYS_WINNT
2389         if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2390 #else
2391             if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL)
2392 #endif /* SYS_WINNT */
2393                 fi = stdin;
2394             else
2395                 setbuf(fi, (char *)NULL);
2396         fprintf(stderr, "%s", keyprompt); fflush(stderr);
2397         for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
2398                 if (p < &pbuf[18])
2399                     *p++ = c;
2400         }
2401         *p = '\0';
2402         if (fi != stdin)
2403             fclose(fi);
2404         if (strcmp(pbuf, "0") == 0)
2405             return 0;
2406
2407         return (u_long) atoi(pbuf);
2408 }
2409
2410
2411 /*
2412  * atoascii - printable-ize possibly ascii data using the character
2413  *            transformations cat -v uses.
2414  */
2415 static void
2416 atoascii(
2417         int length,
2418         char *data,
2419         char *outdata
2420         )
2421 {
2422         register u_char *cp;
2423         register u_char *ocp;
2424         register u_char c;
2425
2426         if (!data)
2427         {
2428                 *outdata = '\0';
2429                 return;
2430         }
2431
2432         ocp = (u_char *)outdata;
2433         for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
2434                 c = *cp;
2435                 if (c == '\0')
2436                     break;
2437                 if (c == '\0')
2438                     break;
2439                 if (c > 0177) {
2440                         *ocp++ = 'M';
2441                         *ocp++ = '-';
2442                         c &= 0177;
2443                 }
2444
2445                 if (c < ' ') {
2446                         *ocp++ = '^';
2447                         *ocp++ = c + '@';
2448                 } else if (c == 0177) {
2449                         *ocp++ = '^';
2450                         *ocp++ = '?';
2451                 } else {
2452                         *ocp++ = c;
2453                 }
2454                 if (ocp >= ((u_char *)outdata + length - 4))
2455                     break;
2456         }
2457         *ocp++ = '\0';
2458 }
2459
2460
2461
2462 /*
2463  * makeascii - print possibly ascii data using the character
2464  *             transformations that cat -v uses.
2465  */
2466 static void
2467 makeascii(
2468         int length,
2469         char *data,
2470         FILE *fp
2471         )
2472 {
2473         register u_char *cp;
2474         register int c;
2475
2476         for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
2477                 c = (int)*cp;
2478                 if (c > 0177) {
2479                         putc('M', fp);
2480                         putc('-', fp);
2481                         c &= 0177;
2482                 }
2483
2484                 if (c < ' ') {
2485                         putc('^', fp);
2486                         putc(c+'@', fp);
2487                 } else if (c == 0177) {
2488                         putc('^', fp);
2489                         putc('?', fp);
2490                 } else {
2491                         putc(c, fp);
2492                 }
2493         }
2494 }
2495
2496
2497 /*
2498  * asciize - same thing as makeascii except add a newline
2499  */
2500 void
2501 asciize(
2502         int length,
2503         char *data,
2504         FILE *fp
2505         )
2506 {
2507         makeascii(length, data, fp);
2508         putc('\n', fp);
2509 }
2510
2511
2512 /*
2513  * Some circular buffer space
2514  */
2515 #define CBLEN   80
2516 #define NUMCB   6
2517
2518 char circ_buf[NUMCB][CBLEN];
2519 int nextcb = 0;
2520
2521 /*
2522  * nextvar - find the next variable in the buffer
2523  */
2524 int
2525 nextvar(
2526         int *datalen,
2527         char **datap,
2528         char **vname,
2529         char **vvalue
2530         )
2531 {
2532         register char *cp;
2533         register char *np;
2534         register char *cpend;
2535         register char *npend;   /* character after last */
2536         int quoted = 0;
2537         static char name[MAXVARLEN];
2538         static char value[MAXVALLEN];
2539
2540         cp = *datap;
2541         cpend = cp + *datalen;
2542
2543         /*
2544          * Space past commas and white space
2545          */
2546         while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
2547             cp++;
2548         if (cp == cpend)
2549             return 0;
2550         
2551         /*
2552          * Copy name until we hit a ',', an '=', a '\r' or a '\n'.  Backspace
2553          * over any white space and terminate it.
2554          */
2555         np = name;
2556         npend = &name[MAXVARLEN];
2557         while (cp < cpend && np < npend && *cp != ',' && *cp != '='
2558                && *cp != '\r' && *cp != '\n')
2559             *np++ = *cp++;
2560         /*
2561          * Check if we ran out of name space, without reaching the end or a
2562          * terminating character
2563          */
2564         if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
2565                              *cp == '\r' || *cp == '\n'))
2566             return 0;
2567         while (isspace((int)(*(np-1))))
2568             np--;
2569         *np = '\0';
2570         *vname = name;
2571
2572         /*
2573          * Check if we hit the end of the buffer or a ','.  If so we are done.
2574          */
2575         if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
2576                 if (cp != cpend)
2577                     cp++;
2578                 *datap = cp;
2579                 *datalen = cpend - cp;
2580                 *vvalue = (char *)0;
2581                 return 1;
2582         }
2583
2584         /*
2585          * So far, so good.  Copy out the value
2586          */
2587         cp++;   /* past '=' */
2588         while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
2589             cp++;
2590         np = value;
2591         npend = &value[MAXVALLEN];
2592         while (cp < cpend && np < npend && ((*cp != ',') || quoted))
2593         {
2594                 quoted ^= ((*np++ = *cp++) == '"');
2595         }
2596
2597         /*
2598          * Check if we overran the value buffer while still in a quoted string
2599          * or without finding a comma
2600          */
2601         if (np == npend && (quoted || *cp != ','))
2602             return 0;
2603         /*
2604          * Trim off any trailing whitespace
2605          */
2606         while (np > value && isspace((int)(*(np-1))))
2607             np--;
2608         *np = '\0';
2609
2610         /*
2611          * Return this.  All done.
2612          */
2613         if (cp != cpend)
2614             cp++;
2615         *datap = cp;
2616         *datalen = cpend - cp;
2617         *vvalue = value;
2618         return 1;
2619 }
2620
2621
2622 /*
2623  * findvar - see if this variable is known to us
2624  */
2625 int
2626 findvar(
2627         char *varname,
2628         struct ctl_var *varlist
2629         )
2630 {
2631         register char *np;
2632         register struct ctl_var *vl;
2633
2634         vl = varlist;
2635         np = varname;
2636         while (vl->fmt != EOV) {
2637                 if (vl->fmt != PADDING && STREQ(np, vl->text))
2638                     return vl->code;
2639                 vl++;
2640         }
2641         return 0;
2642 }
2643
2644
2645
2646 /*
2647  * printvars - print variables returned in response packet
2648  */
2649 void
2650 printvars(
2651         int length,
2652         char *data,
2653         int status,
2654         int sttype,
2655         FILE *fp
2656         )
2657 {
2658         if (rawmode)
2659             rawprint(sttype, length, data, status, fp);
2660         else
2661             cookedprint(sttype, length, data, status, fp);
2662 }
2663
2664
2665 /*
2666  * rawprint - do a printout of the data in raw mode
2667  */
2668 static void
2669 rawprint(
2670         int datatype,
2671         int length,
2672         char *data,
2673         int status,
2674         FILE *fp
2675         )
2676 {
2677         register char *cp;
2678         register char *cpend;
2679
2680         /*
2681          * Essentially print the data as is.  We reformat unprintables, though.
2682          */
2683         cp = data;
2684         cpend = data + length;
2685
2686         (void) fprintf(fp, "status=0x%04x,\n", status);
2687
2688         while (cp < cpend) {
2689                 if (*cp == '\r') {
2690                         /*
2691                          * If this is a \r and the next character is a
2692                          * \n, supress this, else pretty print it.  Otherwise
2693                          * just output the character.
2694                          */
2695                         if (cp == (cpend-1) || *(cp+1) != '\n')
2696                             makeascii(1, cp, fp);
2697                 } else if (isspace((int)*cp) || isprint((int)*cp)) {
2698                         putc(*cp, fp);
2699                 } else {
2700                         makeascii(1, cp, fp);
2701                 }
2702                 cp++;
2703         }
2704 }
2705
2706
2707 /*
2708  * Global data used by the cooked output routines
2709  */
2710 int out_chars;          /* number of characters output */
2711 int out_linecount;      /* number of characters output on this line */
2712
2713
2714 /*
2715  * startoutput - get ready to do cooked output
2716  */
2717 static void
2718 startoutput(void)
2719 {
2720         out_chars = 0;
2721         out_linecount = 0;
2722 }
2723
2724
2725 /*
2726  * output - output a variable=value combination
2727  */
2728 static void
2729 output(
2730         FILE *fp,
2731         char *name,
2732         char *value
2733         )
2734 {
2735         int lenname;
2736         int lenvalue;
2737
2738         lenname = strlen(name);
2739         lenvalue = strlen(value);
2740
2741         if (out_chars != 0) {
2742                 putc(',', fp);
2743                 out_chars++;
2744                 out_linecount++;
2745                 if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) {
2746                         putc('\n', fp);
2747                         out_chars++;
2748                         out_linecount = 0;
2749                 } else {
2750                         putc(' ', fp);
2751                         out_chars++;
2752                         out_linecount++;
2753                 }
2754         }
2755
2756         fputs(name, fp);
2757         putc('=', fp);
2758         fputs(value, fp);
2759         out_chars += lenname + 1 + lenvalue;
2760         out_linecount += lenname + 1 + lenvalue;
2761 }
2762
2763
2764 /*
2765  * endoutput - terminate a block of cooked output
2766  */
2767 static void
2768 endoutput(
2769         FILE *fp
2770         )
2771 {
2772         if (out_chars != 0)
2773             putc('\n', fp);
2774 }
2775
2776
2777 /*
2778  * outputarr - output an array of values
2779  */
2780 static void
2781 outputarr(
2782         FILE *fp,
2783         char *name,
2784         int narr,
2785         l_fp *lfp
2786         )
2787 {
2788         register char *bp;
2789         register char *cp;
2790         register int i;
2791         register int len;
2792         char buf[256];
2793
2794         bp = buf;
2795         /*
2796          * Hack to align delay and offset values
2797          */
2798         for (i = (int)strlen(name); i < 11; i++)
2799             *bp++ = ' ';
2800         
2801         for (i = narr; i > 0; i--) {
2802                 if (i != narr)
2803                     *bp++ = ' ';
2804                 cp = lfptoms(lfp, 2);
2805                 len = strlen(cp);
2806                 if (len > 7) {
2807                         cp[7] = '\0';
2808                         len = 7;
2809                 }
2810                 while (len < 7) {
2811                         *bp++ = ' ';
2812                         len++;
2813                 }
2814                 while (*cp != '\0')
2815                     *bp++ = *cp++;
2816                 lfp++;
2817         }
2818         *bp = '\0';
2819         output(fp, name, buf);
2820 }
2821
2822 static char *
2823 tstflags(
2824         u_long val
2825         )
2826 {
2827         register char *cb, *s;
2828         register int i;
2829         register const char *sep;
2830
2831         sep = "";
2832         i = 0;
2833         s = cb = &circ_buf[nextcb][0];
2834         if (++nextcb >= NUMCB)
2835             nextcb = 0;
2836
2837         sprintf(cb, "%02lx", val);
2838         cb += strlen(cb);
2839         if (!val) {
2840                 strcat(cb, " ok");
2841                 cb += strlen(cb);
2842         } else {
2843                 *cb++ = ' ';
2844                 for (i = 0; i < 11; i++) {
2845                         if (val & 0x1) {
2846                                 sprintf(cb, "%s%s", sep, tstflagnames[i]);
2847                                 sep = ", ";
2848                                 cb += strlen(cb);
2849                         }
2850                         val >>= 1;
2851                 }
2852         }
2853         *cb = '\0';
2854         return s;
2855 }
2856
2857 /*
2858  * cookedprint - output variables in cooked mode
2859  */
2860 static void
2861 cookedprint(
2862         int datatype,
2863         int length,
2864         char *data,
2865         int status,
2866         FILE *fp
2867         )
2868 {
2869         register int varid;
2870         char *name;
2871         char *value;
2872         int output_raw;
2873         int fmt;
2874         struct ctl_var *varlist;
2875         l_fp lfp;
2876         long ival;
2877         u_int32 hval;
2878         u_long uval;
2879         l_fp lfparr[8];
2880         int narr;
2881
2882         switch (datatype) {
2883             case TYPE_PEER:
2884                 varlist = peer_var;
2885                 break;
2886             case TYPE_SYS:
2887                 varlist = sys_var;
2888                 break;
2889             case TYPE_CLOCK:
2890                 varlist = clock_var;
2891                 break;
2892             default:
2893                 (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype);
2894                 return;
2895         }
2896
2897         (void) fprintf(fp, "status=%04x %s,\n", status,
2898                        statustoa(datatype, status));
2899
2900         startoutput();
2901         while (nextvar(&length, &data, &name, &value)) {
2902                 varid = findvar(name, varlist);
2903                 if (varid == 0) {
2904                         output_raw = '*';
2905                 } else {
2906                         output_raw = 0;
2907                         fmt = varlist[varid].fmt;
2908                         switch(fmt) {
2909                             case TS:
2910                                 if (!decodets(value, &lfp))
2911                                     output_raw = '?';
2912                                 else
2913                                     output(fp, name, prettydate(&lfp));
2914                                 break;
2915                             case FL:
2916                             case FU:
2917                             case FS:
2918                                 if (!decodetime(value, &lfp))
2919                                     output_raw = '?';
2920                                 else {
2921                                         switch (fmt) {
2922                                             case FL:
2923                                                 output(fp, name,
2924                                                        lfptoms(&lfp, 3));
2925                                                 break;
2926                                             case FU:
2927                                                 output(fp, name,
2928                                                        ulfptoms(&lfp, 3));
2929                                                 break;
2930                                             case FS:
2931                                                 output(fp, name,
2932                                                        lfptoms(&lfp, 3));
2933                                                 break;
2934                                         }
2935                                 }
2936                                 break;
2937                         
2938                             case UI:
2939                                 if (!decodeuint(value, &uval))
2940                                     output_raw = '?';
2941                                 else
2942                                     output(fp, name, uinttoa(uval));
2943                                 break;
2944                         
2945                             case SI:
2946                                 if (!decodeint(value, &ival))
2947                                     output_raw = '?';
2948                                 else
2949                                     output(fp, name, inttoa(ival));
2950                                 break;
2951
2952                             case HA:
2953                             case NA:
2954                                 if (!decodenetnum(value, &hval))
2955                                     output_raw = '?';
2956                                 else if (fmt == HA)
2957                                     output(fp, name, nntohost(hval));
2958                                 else
2959                                     output(fp, name, numtoa(hval));
2960                                 break;
2961                         
2962                             case ST:
2963                                 output_raw = '*';
2964                                 break;
2965                         
2966                             case RF:
2967                                 if (decodenetnum(value, &hval))
2968                                     output(fp, name, nntohost(hval));
2969                                 else if ((int)strlen(value) <= 4)
2970                                     output(fp, name, value);
2971                                 else
2972                                     output_raw = '?';
2973                                 break;
2974
2975                             case LP:
2976                                 if (!decodeuint(value, &uval) || uval > 3)
2977                                     output_raw = '?';
2978                                 else {
2979                                         char b[3];
2980                                         b[0] = b[1] = '0';
2981                                         if (uval & 0x2)
2982                                             b[0] = '1';
2983                                         if (uval & 0x1)
2984                                             b[1] = '1';
2985                                         b[2] = '\0';
2986                                         output(fp, name, b);
2987                                 }
2988                                 break;
2989
2990                             case OC:
2991                                 if (!decodeuint(value, &uval))
2992                                     output_raw = '?';
2993                                 else {
2994                                         char b[10];
2995
2996                                         (void) sprintf(b, "%03lo", uval);
2997                                         output(fp, name, b);
2998                                 }
2999                                 break;
3000                         
3001                             case MD:
3002                                 if (!decodeuint(value, &uval))
3003                                     output_raw = '?';
3004                                 else
3005                                     output(fp, name, uinttoa(uval));
3006                                 break;
3007                         
3008                             case AR:
3009                                 if (!decodearr(value, &narr, lfparr))
3010                                     output_raw = '?';
3011                                 else
3012                                     outputarr(fp, name, narr, lfparr);
3013                                 break;
3014
3015                             case FX:
3016                                 if (!decodeuint(value, &uval))
3017                                     output_raw = '?';
3018                                 else
3019                                     output(fp, name, tstflags(uval));
3020                                 break;
3021                         
3022                             default:
3023                                 (void) fprintf(stderr,
3024                                     "Internal error in cookedprint, %s=%s, fmt %d\n",
3025                                     name, value, fmt);
3026                                 break;
3027                         }
3028
3029                 }
3030                 if (output_raw != 0) {
3031                         char bn[401];
3032                         char bv[401];
3033                         int len;
3034
3035                         atoascii(400, name, bn);
3036                         atoascii(400, value, bv);
3037                         if (output_raw != '*') {
3038                                 len = strlen(bv);
3039                                 bv[len] = output_raw;
3040                                 bv[len+1] = '\0';
3041                         }
3042                         output(fp, bn, bv);
3043                 }
3044         }
3045         endoutput(fp);
3046 }
3047
3048
3049 /*
3050  * sortassoc - sort associations in the cache into ascending order
3051  */
3052 void
3053 sortassoc(void)
3054 {
3055         if (numassoc > 1)
3056             qsort(
3057 #ifdef QSORT_USES_VOID_P
3058                     (void *)
3059 #else
3060                     (char *)
3061 #endif
3062                     assoc_cache, (size_t)numassoc,
3063                     sizeof(struct association), assoccmp);
3064 }
3065
3066
3067 /*
3068  * assoccmp - compare two associations
3069  */
3070 #ifdef QSORT_USES_VOID_P
3071 static int
3072 assoccmp(
3073         const void *t1,
3074         const void *t2
3075         )
3076 {
3077         const struct association *ass1 = (const struct association *)t1;
3078         const struct association *ass2 = (const struct association *)t2;
3079
3080         if (ass1->assid < ass2->assid)
3081             return -1;
3082         if (ass1->assid > ass2->assid)
3083             return 1;
3084         return 0;
3085 }
3086 #else
3087 static int
3088 assoccmp(
3089         struct association *ass1,
3090         struct association *ass2
3091         )
3092 {
3093         if (ass1->assid < ass2->assid)
3094             return -1;
3095         if (ass1->assid > ass2->assid)
3096             return 1;
3097         return 0;
3098 }
3099 #endif /* not QSORT_USES_VOID_P */