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