1 /* $NetBSD: ntpdc.c,v 1.9 2006/06/11 19:34:21 kardel Exp $ */
4 * ntpdc - control and monitor your ntpd daemon
14 #include "ntp_select.h"
16 #include "ntp_stdlib.h"
17 /* Don't include ISC's version of IPv6 variables and structures */
20 #include "isc/result.h"
22 #include "ntpdc-opts.h"
28 # define closesocket close
29 #endif /* SYS_WINNT */
31 #if defined(HAVE_LIBREADLINE) || defined (HAVE_LIBEDIT)
32 # include <readline/readline.h>
33 # include <readline/history.h>
34 #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
37 /* vxWorks needs mode flag -casey*/
38 # define open(name, flags) open(name, flags, 0777)
39 # define SERVER_PORT_NUM 123
42 /* We use COMMAND as an autogen keyword */
48 * Because we now potentially understand a lot of commands (and
49 * it requires a lot of commands to talk to ntpd) we will run
50 * interactive if connected to a terminal.
52 static int interactive
= 0; /* set to 1 when we should prompt */
53 static const char * prompt
= "ntpdc> "; /* prompt to ask him about */
56 * Keyid used for authenticated requests. Obtained on the fly.
58 static u_long info_auth_keyid
;
59 static int keyid_entered
= 0;
64 #define KEY_TYPE_MD5 4
66 static int info_auth_keytype
= KEY_TYPE_MD5
; /* MD5 */
67 u_long current_time
; /* needed by authkeys; not used */
72 s_char sys_precision
; /* local clock precision (log2 s) */
74 int ntpdcmain
P((int, char **));
76 * Built in command handler declarations
78 static int openhost
P((const char *));
79 static int sendpkt
P((char *, int));
80 static void growpktdata
P((void));
81 static int getresponse
P((int, int, int *, int *, char **, int));
82 static int sendrequest
P((int, int, int, int, int, char *));
83 static void getcmds
P((void));
84 static RETSIGTYPE abortcmd
P((int));
85 static void docmd
P((const char *));
86 static void tokenize
P((const char *, char **, int *));
87 static int findcmd
P((char *, struct xcmd
*, struct xcmd
*, struct xcmd
**));
88 static int getarg
P((char *, int, arg_v
*));
89 static int getnetnum
P((const char *, struct sockaddr_storage
*, char *, int));
90 static void help
P((struct parse
*, FILE *));
91 #ifdef QSORT_USES_VOID_P
92 static int helpsort
P((const void *, const void *));
94 static int helpsort
P((char **, char **));
96 static void printusage
P((struct xcmd
*, FILE *));
97 static void timeout
P((struct parse
*, FILE *));
98 static void my_delay
P((struct parse
*, FILE *));
99 static void host
P((struct parse
*, FILE *));
100 static void keyid
P((struct parse
*, FILE *));
101 static void keytype
P((struct parse
*, FILE *));
102 static void passwd
P((struct parse
*, FILE *));
103 static void hostnames
P((struct parse
*, FILE *));
104 static void setdebug
P((struct parse
*, FILE *));
105 static void quit
P((struct parse
*, FILE *));
106 static void version
P((struct parse
*, FILE *));
107 static void warning
P((const char *, const char *, const char *));
108 static void error
P((const char *, const char *, const char *));
109 static u_long getkeyid
P((const char *));
114 * Built-in commands we understand
116 static struct xcmd builtins
[] = {
117 { "?", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
118 { "command", "", "", "" },
119 "tell the use and syntax of commands" },
120 { "help", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
121 { "command", "", "", "" },
122 "tell the use and syntax of commands" },
123 { "timeout", timeout
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
124 { "msec", "", "", "" },
125 "set the primary receive time out" },
126 { "delay", my_delay
, { OPT
|NTP_INT
, NO
, NO
, NO
},
127 { "msec", "", "", "" },
128 "set the delay added to encryption time stamps" },
129 { "host", host
, { OPT
|NTP_STR
, OPT
|NTP_STR
, NO
, NO
},
130 { "-4|-6", "hostname", "", "" },
131 "specify the host whose NTP server we talk to" },
132 { "passwd", passwd
, { OPT
|NTP_STR
, NO
, NO
, NO
},
134 "specify a password to use for authenticated requests"},
135 { "hostnames", hostnames
, { OPT
|NTP_STR
, NO
, NO
, NO
},
136 { "yes|no", "", "", "" },
137 "specify whether hostnames or net numbers are printed"},
138 { "debug", setdebug
, { OPT
|NTP_STR
, NO
, NO
, NO
},
139 { "no|more|less", "", "", "" },
140 "set/change debugging level" },
141 { "quit", quit
, { NO
, NO
, NO
, NO
},
144 { "exit", quit
, { NO
, NO
, NO
, NO
},
147 { "keyid", keyid
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
148 { "key#", "", "", "" },
149 "set/show keyid to use for authenticated requests" },
150 { "keytype", keytype
, { OPT
|NTP_STR
, NO
, NO
, NO
},
151 { "(md5|des)", "", "", "" },
152 "set/show key authentication type for authenticated requests (des|md5)" },
153 { "version", version
, { NO
, NO
, NO
, NO
},
155 "print version number" },
156 { 0, 0, { NO
, NO
, NO
, NO
},
157 { "", "", "", "" }, "" }
162 * Default values we use.
164 #define DEFTIMEOUT (5) /* 5 second time out */
165 #define DEFSTIMEOUT (2) /* 2 second time out after first */
166 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
167 #define DEFHOST "localhost" /* default host name */
168 #define LENHOSTNAME 256 /* host name is 256 characters long */
169 #define MAXCMDS 100 /* maximum commands on cmd line */
170 #define MAXHOSTS 200 /* maximum hosts on cmd line */
171 #define MAXLINE 512 /* maximum line length */
172 #define MAXTOKENS (1+1+MAXARGS+MOREARGS+2) /* maximum number of usable tokens */
173 #define SCREENWIDTH 78 /* nominal screen width in columns */
176 * Some variables used and manipulated locally
178 static struct timeval tvout
= { DEFTIMEOUT
, 0 }; /* time out for reads */
179 static struct timeval tvsout
= { DEFSTIMEOUT
, 0 }; /* secondary time out */
180 static l_fp delay_time
; /* delay time */
181 static char currenthost
[LENHOSTNAME
]; /* current host name */
182 int showhostnames
= 1; /* show host names by default */
184 static int ai_fam_templ
; /* address family */
185 static int ai_fam_default
; /* default address family */
186 static SOCKET sockfd
; /* fd socket is opened on */
187 static int havehost
= 0; /* set to 1 when host open */
190 #if defined (SYS_WINNT) || defined (SYS_VXWORKS)
192 #endif /* SYS_WINNT || SYS_VXWORKS */
195 DWORD NumberOfBytesWritten
;
197 HANDLE TimerThreadHandle
= NULL
; /* 1998/06/03 - Used in ntplib/machines.c */
198 void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
200 #endif /* SYS_WINNT */
203 * Holds data returned from queries. We allocate INITDATASIZE
204 * octets to begin with, increasing this as we need to.
206 #define INITDATASIZE (sizeof(struct resp_pkt) * 16)
207 #define INCDATASIZE (sizeof(struct resp_pkt) * 8)
209 static char *pktdata
;
210 static int pktdatasize
;
213 * These are used to help the magic with old and new versions of ntpd.
215 int impl_ver
= IMPL_XNTPD
;
216 static int req_pkt_size
= REQ_LEN_NOMAC
;
219 * For commands typed on the command line (with the -c option)
221 static int numcmds
= 0;
222 static const char *ccmds
[MAXCMDS
];
223 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
226 * When multiple hosts are specified.
228 static int numhosts
= 0;
229 static const char *chosts
[MAXHOSTS
];
230 #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
233 * Error codes for internal use
235 #define ERR_INCOMPLETE 16
236 #define ERR_TIMEOUT 17
239 * Macro definitions we use
241 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
242 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
243 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
246 * For converting time stamps to dates
248 #define JAN_1970 2208988800 /* 1970 - 1900 in seconds */
251 * Jump buffer for longjumping back to the command level
253 static jmp_buf interrupt_buf
;
254 static volatile int jump
= 0;
257 * Pointer to current output unit
259 static FILE *current_output
;
262 * Command table imported from ntpdc_ops.c
264 extern struct xcmd opcmds
[];
269 #ifdef NO_MAIN_ALLOWED
270 CALL(ntpdc
,"ntpdc",ntpdcmain
);
278 return ntpdcmain(argc
, argv
);
283 void clear_globals(void)
285 showhostnames
= 0; /* show host names by default */
286 havehost
= 0; /* set to 1 when host open */
293 * main - parse arguments and handle options
301 extern int ntp_optind
;
304 delay_time
.l_uf
= DEFDELAY
;
308 taskPrioritySet(taskIdSelf(), 100 );
312 if (!Win32InitSockets())
314 fprintf(stderr
, "No useable winsock.dll:");
317 #endif /* SYS_WINNT */
319 /* Check to see if we have IPv6. Otherwise force the -4 flag */
320 if (isc_net_probeipv6() != ISC_R_SUCCESS
) {
321 ai_fam_default
= AF_INET
;
327 int optct
= optionProcess(&ntpdcOptions
, argc
, argv
);
332 switch (WHICH_IDX_IPV4
) {
334 ai_fam_templ
= AF_INET
;
337 ai_fam_templ
= AF_INET6
;
340 ai_fam_templ
= ai_fam_default
;
344 if (HAVE_OPT(COMMAND
)) {
345 int cmdct
= STACKCT_OPT( COMMAND
);
346 const char** cmds
= STACKLST_OPT( COMMAND
);
348 while (cmdct
-- > 0) {
353 debug
= DESC(DEBUG_LEVEL
).optOccCt
;
355 if (HAVE_OPT(INTERACTIVE
)) {
359 if (HAVE_OPT(NUMERIC
)) {
363 if (HAVE_OPT(LISTPEERS
)) {
367 if (HAVE_OPT(PEERS
)) {
371 if (HAVE_OPT(SHOWPEERS
)) {
375 if (ntp_optind
== argc
) {
378 for (; ntp_optind
< argc
; ntp_optind
++)
379 ADDHOST(argv
[ntp_optind
]);
382 if (numcmds
== 0 && interactive
== 0
383 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
388 ai_fam_templ
= ai_fam_default
;
389 while ((c
= ntp_getopt(argc
, argv
, "46c:dilnps")) != EOF
)
392 ai_fam_templ
= AF_INET
;
395 ai_fam_templ
= AF_INET6
;
424 (void) fprintf(stderr
,
425 "usage: %s [-46dilnps] [-c cmd] host ...\n",
430 if (ntp_optind
== argc
) {
433 for (; ntp_optind
< argc
; ntp_optind
++)
434 ADDHOST(argv
[ntp_optind
]);
437 if (numcmds
== 0 && interactive
== 0
438 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
443 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
445 (void) signal_no_reset(SIGINT
, abortcmd
);
446 #endif /* SYS_WINNT */
449 * Initialize the packet data buffer
451 pktdata
= (char *)malloc(INITDATASIZE
);
452 if (pktdata
== NULL
) {
453 (void) fprintf(stderr
, "%s: malloc() failed!\n", progname
);
456 pktdatasize
= INITDATASIZE
;
459 (void) openhost(chosts
[0]);
465 for (ihost
= 0; ihost
< numhosts
; ihost
++) {
466 if (openhost(chosts
[ihost
]))
467 for (icmd
= 0; icmd
< numcmds
; icmd
++) {
469 printf ("--- %s ---\n",chosts
[ihost
]);
482 * openhost - open a socket to a host
489 char temphost
[LENHOSTNAME
];
491 struct addrinfo hints
, *ai
= NULL
;
492 register const char *cp
;
493 char name
[LENHOSTNAME
];
497 * We need to get by the [] if they were entered
504 for(i
= 0; *cp
!= ']'; cp
++, i
++)
511 * First try to resolve it as an ip address and if that fails,
512 * do a fullblown (dns) lookup. That way we only use the dns
513 * when it is needed and work around some implementations that
514 * will return an "IPv4-mapped IPv6 address" address if you
515 * give it an IPv4 address to lookup.
517 strcpy(service
, "ntp");
518 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
519 hints
.ai_family
= ai_fam_templ
;
520 hints
.ai_protocol
= IPPROTO_UDP
;
521 hints
.ai_socktype
= SOCK_DGRAM
;
522 hints
.ai_flags
= AI_NUMERICHOST
;
524 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
525 if (a_info
== EAI_NONAME
527 || a_info
== EAI_NODATA
530 hints
.ai_flags
= AI_CANONNAME
;
532 hints
.ai_flags
|= AI_ADDRCONFIG
;
534 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
536 /* Some older implementations don't like AI_ADDRCONFIG. */
537 if (a_info
== EAI_BADFLAGS
) {
538 hints
.ai_flags
= AI_CANONNAME
;
539 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
542 (void) fprintf(stderr
, "%s\n", gai_strerror(a_info
));
548 if (ai
->ai_canonname
== NULL
) {
549 strncpy(temphost
, stoa((struct sockaddr_storage
*)ai
->ai_addr
),
551 temphost
[LENHOSTNAME
-1] = '\0';
553 strncpy(temphost
, ai
->ai_canonname
, LENHOSTNAME
);
554 temphost
[LENHOSTNAME
-1] = '\0';
558 printf("Opening host %s\n", temphost
);
562 printf("Closing old host %s\n", currenthost
);
563 (void) closesocket(sockfd
);
566 (void) strcpy(currenthost
, temphost
);
568 /* port maps to the same in both families */
569 s_port
= ((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_port
;
571 ((struct sockaddr_in6
*)&hostaddr
)->sin6_port
= htons(SERVER_PORT_NUM
);
572 if (ai
->ai_family
== AF_INET
)
573 *(struct sockaddr_in
*)&hostaddr
=
574 *((struct sockaddr_in
*)ai
->ai_addr
);
576 *(struct sockaddr_in6
*)&hostaddr
=
577 *((struct sockaddr_in6
*)ai
->ai_addr
);
578 #endif /* SYS_VXWORKS */
582 int optionValue
= SO_SYNCHRONOUS_NONALERT
;
585 err
= setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&optionValue
, sizeof(optionValue
));
586 if (err
!= NO_ERROR
) {
587 (void) fprintf(stderr
, "cannot open nonoverlapped sockets\n");
592 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
593 if (sockfd
== INVALID_SOCKET
) {
594 error("socket", "", "");
598 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
600 error("socket", "", "");
601 #endif /* SYS_WINNT */
604 #ifdef NEED_RCVBUF_SLOP
607 int rbufsize
= INITDATASIZE
+ 2048; /* 2K for slop */
609 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
,
610 &rbufsize
, sizeof(int)) == -1)
611 error("setsockopt", "", "");
617 if (connect(sockfd
, (struct sockaddr
*)&hostaddr
,
618 sizeof(hostaddr
)) == -1)
620 if (connect(sockfd
, (struct sockaddr
*)ai
->ai_addr
,
621 ai
->ai_addrlen
) == -1)
622 #endif /* SYS_VXWORKS */
623 error("connect", "", "");
627 req_pkt_size
= REQ_LEN_NOMAC
;
628 impl_ver
= IMPL_XNTPD
;
633 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
635 * sendpkt - send a packet to the remote host
643 if (send(sockfd
, xdata
, (size_t)xdatalen
, 0) == -1) {
644 warning("write to %s failed", currenthost
, "");
653 * growpktdata - grow the packet data area
658 pktdatasize
+= INCDATASIZE
;
659 pktdata
= (char *)realloc(pktdata
, (unsigned)pktdatasize
);
661 (void) fprintf(stderr
, "%s: realloc() failed!\n", progname
);
668 * getresponse - get a (series of) response packet(s) and return the data
680 struct resp_pkt rpkt
;
688 char haveseq
[MAXSEQ
+1];
698 * This is pretty tricky. We may get between 1 and many packets
699 * back in response to the request. We peel the data out of
700 * each packet and collect it in one long block. When the last
701 * packet in the sequence is received we'll know how many we
702 * should have had. Note we use one long time out, should reconsider.
708 *rdata
= datap
= pktdata
;
709 lastseq
= 999; /* too big to be a sequence number */
710 memset(haveseq
, 0, sizeof(haveseq
));
719 FD_SET(sockfd
, &fds
);
720 n
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvo
);
723 warning("select fails", "", "");
728 * Timed out. Return what we have
731 (void) fprintf(stderr
,
732 "%s: timed out, nothing received\n", currenthost
);
735 (void) fprintf(stderr
,
736 "%s: timed out with incomplete data\n",
739 printf("Received sequence numbers");
740 for (n
= 0; n
<= MAXSEQ
; n
++)
744 printf(" last frame received\n");
746 printf(" last frame not received\n");
748 return ERR_INCOMPLETE
;
752 n
= recv(sockfd
, (char *)&rpkt
, sizeof(rpkt
), 0);
754 warning("read", "", "");
760 * Check for format errors. Bug proofing.
762 if (n
< RESP_HEADER_SIZE
) {
764 printf("Short (%d byte) packet received\n", n
);
767 if (INFO_VERSION(rpkt
.rm_vn_mode
) > NTP_VERSION
||
768 INFO_VERSION(rpkt
.rm_vn_mode
) < NTP_OLDVERSION
) {
770 printf("Packet received with version %d\n",
771 INFO_VERSION(rpkt
.rm_vn_mode
));
774 if (INFO_MODE(rpkt
.rm_vn_mode
) != MODE_PRIVATE
) {
776 printf("Packet received with mode %d\n",
777 INFO_MODE(rpkt
.rm_vn_mode
));
780 if (INFO_IS_AUTH(rpkt
.auth_seq
)) {
782 printf("Encrypted packet received\n");
785 if (!ISRESPONSE(rpkt
.rm_vn_mode
)) {
787 printf("Received request packet, wanted response\n");
790 if (INFO_MBZ(rpkt
.mbz_itemsize
) != 0) {
792 printf("Received packet with nonzero MBZ field!\n");
797 * Check implementation/request. Could be old data getting to us.
799 if (rpkt
.implementation
!= implcode
|| rpkt
.request
!= reqcode
) {
802 "Received implementation/request of %d/%d, wanted %d/%d",
803 rpkt
.implementation
, rpkt
.request
,
809 * Check the error code. If non-zero, return it.
811 if (INFO_ERR(rpkt
.err_nitems
) != INFO_OKAY
) {
812 if (debug
&& ISMORE(rpkt
.rm_vn_mode
)) {
813 printf("Error code %d received on not-final packet\n",
814 INFO_ERR(rpkt
.err_nitems
));
816 return (int)INFO_ERR(rpkt
.err_nitems
);
820 * Collect items and size. Make sure they make sense.
822 items
= INFO_NITEMS(rpkt
.err_nitems
);
823 size
= INFO_ITEMSIZE(rpkt
.mbz_itemsize
);
828 if ((datasize
= items
*size
) > (n
-RESP_HEADER_SIZE
)) {
831 "Received items %d, size %d (total %d), data in packet is %d\n",
832 items
, size
, datasize
, n
-RESP_HEADER_SIZE
);
837 * If this isn't our first packet, make sure the size matches
840 if (!firstpkt
&& esize
!= *rsize
) {
842 printf("Received itemsize %d, previous %d\n",
847 * If we've received this before, +toss it
849 seq
= INFO_SEQ(rpkt
.auth_seq
);
852 printf("Received duplicate sequence number %d\n", seq
);
858 * If this is the last in the sequence, record that.
860 if (!ISMORE(rpkt
.rm_vn_mode
)) {
861 if (lastseq
!= 999) {
862 printf("Received second end sequence packet\n");
869 * So far, so good. Copy this data into the output array.
871 if ((datap
+ datasize
+ (pad
* items
)) > (pktdata
+ pktdatasize
)) {
872 int offset
= datap
- pktdata
;
874 *rdata
= pktdata
; /* might have been realloced ! */
875 datap
= pktdata
+ offset
;
878 * We now move the pointer along according to size and number of
879 * items. This is so we can play nice with older implementations
882 tmp_data
= (char *)rpkt
.data
;
883 for(i
= 0; i
<items
; i
++){
884 memmove(datap
, tmp_data
, (unsigned)size
);
886 memset(datap
+ size
, 0, pad
);
897 * Finally, check the count of received packets. If we've got them
901 if (numrecv
<= lastseq
)
908 * sendrequest - format and send a request packet
923 memset((char *)&qpkt
, 0, sizeof qpkt
);
925 qpkt
.rm_vn_mode
= RM_VN_MODE(0, 0, 0);
926 qpkt
.implementation
= (u_char
)implcode
;
927 qpkt
.request
= (u_char
)reqcode
;
929 datasize
= qitems
* qsize
;
930 if (datasize
!= 0 && qdata
!= NULL
) {
931 memmove((char *)qpkt
.data
, qdata
, (unsigned)datasize
);
932 qpkt
.err_nitems
= ERR_NITEMS(0, qitems
);
933 qpkt
.mbz_itemsize
= MBZ_ITEMSIZE(qsize
);
935 qpkt
.err_nitems
= ERR_NITEMS(0, 0);
936 qpkt
.mbz_itemsize
= MBZ_ITEMSIZE(qsize
); /* allow for optional first item */
939 if (!auth
|| (keyid_entered
&& info_auth_keyid
== 0)) {
940 qpkt
.auth_seq
= AUTH_SEQ(0, 0);
941 return sendpkt((char *)&qpkt
, req_pkt_size
);
945 const char *pass
= "\0";
946 struct req_pkt_tail
*qpktail
;
948 qpktail
= (struct req_pkt_tail
*)((char *)&qpkt
+ req_pkt_size
949 + MAX_MAC_LEN
- sizeof(struct req_pkt_tail
));
951 if (info_auth_keyid
== 0) {
952 if (((struct conf_peer
*)qpkt
.data
)->keyid
> 0)
953 info_auth_keyid
= ((struct conf_peer
*)qpkt
.data
)->keyid
;
955 maclen
= getkeyid("Keyid: ");
957 (void) fprintf(stderr
,
958 "Invalid key identifier\n");
961 info_auth_keyid
= maclen
;
964 if (!authistrusted(info_auth_keyid
)) {
965 pass
= getpass("MD5 Password: ");
967 (void) fprintf(stderr
,
968 "Invalid password\n");
972 authusekey(info_auth_keyid
, info_auth_keytype
, (const u_char
*)pass
);
973 authtrust(info_auth_keyid
, 1);
974 qpkt
.auth_seq
= AUTH_SEQ(1, 0);
975 qpktail
->keyid
= htonl(info_auth_keyid
);
977 L_ADD(&ts
, &delay_time
);
978 HTONL_FP(&ts
, &qpktail
->tstamp
);
979 maclen
= authencrypt(info_auth_keyid
, (u_int32
*)&qpkt
,
982 (void) fprintf(stderr
, "Key not found\n");
985 return sendpkt((char *)&qpkt
, (int)(req_pkt_size
+ maclen
));
992 * doquery - send a request and process the response
1012 struct timeval tvzero
;
1015 * Check to make sure host is open
1018 (void) fprintf(stderr
, "***No host open, use `host' command\n");
1023 * Poll the socket and clear out any pending data
1027 tvzero
.tv_sec
= tvzero
.tv_usec
= 0;
1029 FD_SET(sockfd
, &fds
);
1030 res
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvzero
);
1033 warning("polling select", "", "");
1037 (void) recv(sockfd
, junk
, sizeof junk
, 0);
1044 res
= sendrequest(implcode
, reqcode
, auth
, qitems
, qsize
, qdata
);
1049 * Get the response. If we got a standard error, print a message
1051 res
= getresponse(implcode
, reqcode
, ritems
, rsize
, rdata
, esize
);
1054 * Try to be compatible with older implementations of ntpd.
1056 if (res
== INFO_ERR_FMT
&& req_pkt_size
!= 48) {
1059 oldsize
= req_pkt_size
;
1061 switch(req_pkt_size
) {
1069 if (impl_ver
== IMPL_XNTPD
) {
1071 "***Warning changing to older implementation\n");
1072 return INFO_ERR_IMPL
;
1076 "***Warning changing the request packet size from %d to %d\n",
1077 oldsize
, req_pkt_size
);
1081 /* log error message if not told to be quiet */
1082 if ((res
> 0) && (((1 << res
) & quiet_mask
) == 0)) {
1085 /* Give us a chance to try the older implementation. */
1086 if (implcode
== IMPL_XNTPD
)
1088 (void) fprintf(stderr
,
1089 "***Server implementation incompatable with our own\n");
1092 (void) fprintf(stderr
,
1093 "***Server doesn't implement this request\n");
1096 (void) fprintf(stderr
,
1097 "***Server reports a format error in the received packet (shouldn't happen)\n");
1099 case INFO_ERR_NODATA
:
1100 (void) fprintf(stderr
,
1101 "***Server reports data not found\n");
1104 (void) fprintf(stderr
, "***Permission denied\n");
1107 (void) fprintf(stderr
, "***Request timed out\n");
1109 case ERR_INCOMPLETE
:
1110 (void) fprintf(stderr
,
1111 "***Response from server was incomplete\n");
1114 (void) fprintf(stderr
,
1115 "***Server returns unknown error code %d\n", res
);
1124 * getcmds - read commands from the standard input and execute them
1129 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
1133 if ((line
= readline(interactive
?prompt
:"")) == NULL
) return;
1134 if (*line
) add_history(line
);
1138 #else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
1143 #ifdef VMS /* work around a problem with mixing stdout & stderr */
1146 (void) fputs(prompt
, stderr
);
1147 (void) fflush(stderr
);
1150 if (fgets(line
, sizeof line
, stdin
) == NULL
)
1155 #endif /* not HAVE_LIBREADLINE || HAVE_LIBEDIT */
1159 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1161 * abortcmd - catch interrupts and abort the current command
1169 if (current_output
== stdout
)
1170 (void) fflush(stdout
);
1172 (void) fflush(stderr
);
1173 if (jump
) longjmp(interrupt_buf
, 1);
1175 #endif /* SYS_WINNT */
1178 * docmd - decode the command line and execute a command
1185 char *tokens
[1+MAXARGS
+MOREARGS
+2];
1190 struct xcmd
*xcmd
= NULL
; /* XXX: GCC */
1192 ai_fam_templ
= ai_fam_default
;
1194 * Tokenize the command line. If nothing on it, return.
1196 tokenize(cmdline
, tokens
, &ntok
);
1201 * Find the appropriate command description.
1203 i
= findcmd(tokens
[0], builtins
, opcmds
, &xcmd
);
1205 (void) fprintf(stderr
, "***Command `%s' unknown\n",
1208 } else if (i
>= 2) {
1209 (void) fprintf(stderr
, "***Command `%s' ambiguous\n",
1215 * Save the keyword, then walk through the arguments, interpreting
1218 pcmd
.keyword
= tokens
[0];
1221 for (i
= 0; i
< MAXARGS
&& xcmd
->arg
[i
] != NO
;) {
1222 if ((i
+ti
) >= ntok
) {
1223 if (!(xcmd
->arg
[i
] & OPT
)) {
1224 printusage(xcmd
, stderr
);
1229 if ((xcmd
->arg
[i
] & OPT
) && (*tokens
[i
+ti
] == '>'))
1231 rval
= getarg(tokens
[i
+ti
], (int)xcmd
->arg
[i
], &pcmd
.argval
[i
]);
1242 /* Any extra args are assumed to be "OPT|NTP_STR". */
1243 for ( ; i
< MAXARGS
+ MOREARGS
;) {
1246 rval
= getarg(tokens
[i
+ti
], (int)(OPT
|NTP_STR
), &pcmd
.argval
[i
]);
1258 if (i
< ntok
&& *tokens
[i
] == '>') {
1261 if (*(tokens
[i
]+1) != '\0')
1262 fname
= tokens
[i
]+1;
1263 else if ((i
+1) < ntok
)
1264 fname
= tokens
[i
+1];
1266 (void) fprintf(stderr
, "***No file for redirect\n");
1270 current_output
= fopen(fname
, "w");
1271 if (current_output
== NULL
) {
1272 (void) fprintf(stderr
, "***Error opening %s: ", fname
);
1277 current_output
= stdout
;
1280 if (interactive
&& setjmp(interrupt_buf
)) {
1284 (xcmd
->handler
)(&pcmd
, current_output
);
1286 if (current_output
!= stdout
)
1287 (void) fclose(current_output
);
1288 current_output
= NULL
;
1294 * tokenize - turn a command line into tokens
1303 register const char *cp
;
1305 static char tspace
[MAXLINE
];
1309 for (*ntok
= 0; *ntok
< MAXTOKENS
; (*ntok
)++) {
1311 while (ISSPACE(*cp
))
1317 } while (!ISSPACE(*cp
) && !ISEOL(*cp
));
1326 * findcmd - find a command in a command description table
1331 struct xcmd
*clist1
,
1332 struct xcmd
*clist2
,
1336 register struct xcmd
*cl
;
1339 struct xcmd
*nearmatch
= NULL
;
1346 else if (clist2
!= 0)
1352 for (cl
= clist
; cl
->keyword
!= 0; cl
++) {
1353 /* do a first character check, for efficiency */
1354 if (*str
!= *(cl
->keyword
))
1356 if (strncmp(str
, cl
->keyword
, (unsigned)clen
) == 0) {
1358 * Could be extact match, could be approximate.
1359 * Is exact if the length of the keyword is the
1362 if (*((cl
->keyword
) + clen
) == '\0') {
1372 * See if there is more to do. If so, go again. Sorry about the
1373 * goto, too much looking at BSD sources...
1375 if (clist
== clist1
&& clist2
!= 0) {
1381 * If we got extactly 1 near match, use it, else return number
1393 * getarg - interpret an argument token
1395 * string is always set.
1396 * type is set to the decoded type.
1398 * return: 0 - failure
1400 * -1 - skip to next token
1411 static const char *digits
= "0123456789";
1413 memset(argp
, 0, sizeof(*argp
));
1416 argp
->type
= code
& ~OPT
;
1418 switch (argp
->type
) {
1422 if (!strcmp("-6", str
)) {
1423 ai_fam_templ
= AF_INET6
;
1425 } else if (!strcmp("-4", str
)) {
1426 ai_fam_templ
= AF_INET
;
1429 if (!getnetnum(str
, &(argp
->netnum
), (char *)0, 0)) {
1444 cp
= strchr(digits
, *np
);
1446 (void) fprintf(stderr
,
1447 "***Illegal integer value %s\n", str
);
1451 argp
->uval
+= (cp
- digits
);
1452 } while (*(++np
) != '\0');
1455 if ((code
& ~OPT
) == NTP_UINT
) {
1456 (void) fprintf(stderr
,
1457 "***Value %s should be unsigned\n", str
);
1460 argp
->ival
= -argp
->ival
;
1464 if (!strcmp("-6", str
))
1466 else if (!strcmp("-4", str
))
1469 (void) fprintf(stderr
,
1470 "***Version must be either 4 or 6\n");
1481 * getnetnum - given a host name, return its net number
1482 * and (optional) full name
1487 struct sockaddr_storage
*num
,
1493 struct addrinfo hints
, *ai
= NULL
;
1495 sockaddr_len
= (af
== AF_INET
)
1496 ? sizeof(struct sockaddr_in
)
1497 : sizeof(struct sockaddr_in6
);
1498 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
1499 hints
.ai_flags
= AI_CANONNAME
;
1500 #ifdef AI_ADDRCONFIG
1501 hints
.ai_flags
|= AI_ADDRCONFIG
;
1504 /* decodenetnum only works with addresses */
1505 if (decodenetnum(hname
, num
)) {
1506 if (fullhost
!= 0) {
1507 getnameinfo((struct sockaddr
*)num
, sockaddr_len
,
1508 fullhost
, sizeof(fullhost
), NULL
, 0,
1512 } else if (getaddrinfo(hname
, "ntp", &hints
, &ai
) == 0) {
1513 memmove((char *)num
, ai
->ai_addr
, ai
->ai_addrlen
);
1515 (void) strcpy(fullhost
, ai
->ai_canonname
);
1518 (void) fprintf(stderr
, "***Can't find host %s\n", hname
);
1525 * nntohost - convert network number to host name. This routine enforces
1526 * the showhostnames setting.
1530 struct sockaddr_storage
*netnum
1534 return stoa(netnum
);
1536 if ((netnum
->ss_family
== AF_INET
) && ISREFCLOCKADR(netnum
))
1537 return refnumtoa(netnum
);
1538 return socktohost(netnum
);
1543 * Finally, the built in command handlers
1547 * help - tell about commands, or details of a particular command
1557 const char *list
[100];
1562 if (pcmd
->nargs
== 0) {
1564 for (xcp
= builtins
; xcp
->keyword
!= 0; xcp
++) {
1565 if (*(xcp
->keyword
) != '?')
1566 list
[words
++] = xcp
->keyword
;
1568 for (xcp
= opcmds
; xcp
->keyword
!= 0; xcp
++)
1569 list
[words
++] = xcp
->keyword
;
1572 #ifdef QSORT_USES_VOID_P
1577 (list
), (size_t)(words
), sizeof(char *), helpsort
);
1579 for (word
= 0; word
< words
; word
++) {
1580 int length
= strlen(list
[word
]);
1586 cols
= SCREENWIDTH
/ ++col
;
1587 rows
= (words
+ cols
- 1) / cols
;
1589 (void) fprintf(fp
, "ntpdc commands:\n");
1591 for (row
= 0; row
< rows
; row
++) {
1592 for (word
= row
; word
< words
; word
+= rows
) {
1593 (void) fprintf(fp
, "%-*.*s", col
, col
-1, list
[word
]);
1595 (void) fprintf(fp
, "\n");
1598 cmd
= pcmd
->argval
[0].string
;
1599 words
= findcmd(cmd
, builtins
, opcmds
, &xcp
);
1601 (void) fprintf(stderr
,
1602 "Command `%s' is unknown\n", cmd
);
1604 } else if (words
>= 2) {
1605 (void) fprintf(stderr
,
1606 "Command `%s' is ambiguous\n", cmd
);
1609 (void) fprintf(fp
, "function: %s\n", xcp
->comment
);
1610 printusage(xcp
, fp
);
1616 * helpsort - do hostname qsort comparisons
1618 #ifdef QSORT_USES_VOID_P
1625 char const * const * name1
= (char const * const *)t1
;
1626 char const * const * name2
= (char const * const *)t2
;
1628 return strcmp(*name1
, *name2
);
1637 return strcmp(*name1
, *name2
);
1643 * printusage - print usage information for a command
1654 (void) fprintf(fp
, "usage: %s", xcp
->keyword
);
1655 for (i
= 0; i
< MAXARGS
&& xcp
->arg
[i
] != NO
; i
++) {
1656 if (opt46
== 0 && (xcp
->arg
[i
] & ~OPT
) == NTP_ADD
) {
1657 (void) fprintf(fp
, " [ -4|-6 ]");
1660 if (xcp
->arg
[i
] & OPT
)
1661 (void) fprintf(fp
, " [ %s ]", xcp
->desc
[i
]);
1663 (void) fprintf(fp
, " %s", xcp
->desc
[i
]);
1665 (void) fprintf(fp
, "\n");
1670 * timeout - set time out time
1680 if (pcmd
->nargs
== 0) {
1681 val
= tvout
.tv_sec
* 1000 + tvout
.tv_usec
/ 1000;
1682 (void) fprintf(fp
, "primary timeout %d ms\n", val
);
1684 tvout
.tv_sec
= pcmd
->argval
[0].uval
/ 1000;
1685 tvout
.tv_usec
= (pcmd
->argval
[0].uval
- (tvout
.tv_sec
* 1000))
1692 * my_delay - set delay for auth requests
1703 if (pcmd
->nargs
== 0) {
1704 val
= delay_time
.l_ui
* 1000 + delay_time
.l_uf
/ 4294967;
1705 (void) fprintf(fp
, "delay %lu ms\n", val
);
1707 if (pcmd
->argval
[0].ival
< 0) {
1709 val
= (u_long
)(-pcmd
->argval
[0].ival
);
1712 val
= (u_long
)pcmd
->argval
[0].ival
;
1715 delay_time
.l_ui
= val
/ 1000;
1717 delay_time
.l_uf
= val
* 4294967; /* 2**32/1000 */
1726 * host - set the host we are dealing with.
1736 if (pcmd
->nargs
== 0) {
1738 (void) fprintf(fp
, "current host is %s\n", currenthost
);
1740 (void) fprintf(fp
, "no current host\n");
1745 if (pcmd
->nargs
== 2) {
1746 if (!strcmp("-4", pcmd
->argval
[i
].string
))
1747 ai_fam_templ
= AF_INET
;
1748 else if (!strcmp("-6", pcmd
->argval
[i
].string
))
1749 ai_fam_templ
= AF_INET6
;
1753 "current host remains %s\n", currenthost
);
1755 (void) fprintf(fp
, "still no current host\n");
1760 if (openhost(pcmd
->argval
[i
].string
)) {
1761 (void) fprintf(fp
, "current host set to %s\n", currenthost
);
1765 "current host remains %s\n", currenthost
);
1767 (void) fprintf(fp
, "still no current host\n");
1773 * keyid - get a keyid to use for authenticating requests
1781 if (pcmd
->nargs
== 0) {
1782 if (info_auth_keyid
== 0 && !keyid_entered
)
1783 (void) fprintf(fp
, "no keyid defined\n");
1784 else if (info_auth_keyid
== 0 && keyid_entered
)
1785 (void) fprintf(fp
, "no keyid will be sent\n");
1787 (void) fprintf(fp
, "keyid is %lu\n", (u_long
)info_auth_keyid
);
1789 info_auth_keyid
= pcmd
->argval
[0].uval
;
1796 * keytype - get type of key to use for authenticating requests
1804 if (pcmd
->nargs
== 0)
1805 fprintf(fp
, "keytype is %s\n",
1806 (info_auth_keytype
== KEY_TYPE_MD5
) ? "MD5" : "???");
1808 switch (*(pcmd
->argval
[0].string
)) {
1811 info_auth_keytype
= KEY_TYPE_MD5
;
1815 fprintf(fp
, "keytype must be 'md5'\n");
1822 * passwd - get an authentication key
1833 if (info_auth_keyid
== 0) {
1834 info_auth_keyid
= getkeyid("Keyid: ");
1835 if (info_auth_keyid
== 0) {
1836 (void)fprintf(fp
, "Keyid must be defined\n");
1841 authusekey(info_auth_keyid
, info_auth_keytype
,
1842 (u_char
*)pcmd
->argval
[0].string
);
1843 authtrust(info_auth_keyid
, 1);
1845 pass
= getpass("MD5 Password: ");
1847 (void) fprintf(fp
, "Password unchanged\n");
1849 authusekey(info_auth_keyid
, info_auth_keytype
,
1851 authtrust(info_auth_keyid
, 1);
1858 * hostnames - set the showhostnames flag
1866 if (pcmd
->nargs
== 0) {
1868 (void) fprintf(fp
, "hostnames being shown\n");
1870 (void) fprintf(fp
, "hostnames not being shown\n");
1872 if (STREQ(pcmd
->argval
[0].string
, "yes"))
1874 else if (STREQ(pcmd
->argval
[0].string
, "no"))
1877 (void)fprintf(stderr
, "What?\n");
1883 * setdebug - set/change debugging level
1891 if (pcmd
->nargs
== 0) {
1892 (void) fprintf(fp
, "debug level is %d\n", debug
);
1894 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
1896 } else if (STREQ(pcmd
->argval
[0].string
, "more")) {
1898 } else if (STREQ(pcmd
->argval
[0].string
, "less")) {
1901 (void) fprintf(fp
, "What?\n");
1904 (void) fprintf(fp
, "debug level set to %d\n", debug
);
1909 * quit - stop this nonsense
1919 closesocket(sockfd
);
1925 * version - print the current version number
1935 (void) fprintf(fp
, "%s\n", Version
);
1941 * warning - print a warning message
1950 (void) fprintf(stderr
, "%s: ", progname
);
1951 (void) fprintf(stderr
, fmt
, st1
, st2
);
1952 (void) fprintf(stderr
, ": ");
1958 * error - print a message and exit
1967 warning(fmt
, st1
, st2
);
1972 * getkeyid - prompt the user for a keyid to use
1976 const char *keyprompt
1985 if ((fi
= fdopen(open("/dev/tty", 2), "r")) == NULL
)
1987 if ((fi
= _fdopen((int)GetStdHandle(STD_INPUT_HANDLE
), "r")) == NULL
)
1988 #endif /* SYS_WINNT */
1991 setbuf(fi
, (char *)NULL
);
1992 fprintf(stderr
, "%s", keyprompt
); fflush(stderr
);
1993 for (p
=pbuf
; (c
= getc(fi
))!='\n' && c
!=EOF
;) {
2000 return (u_int32
)atoi(pbuf
);