2 * ntpdc - control and monitor your ntpd daemon
12 #include "ntp_select.h"
14 #include "ntp_stdlib.h"
15 /* Don't include ISC's version of IPv6 variables and structures */
18 #include "isc/result.h"
20 #include "ntpdc-opts.h"
26 # define closesocket close
27 #endif /* SYS_WINNT */
29 #if defined(HAVE_LIBREADLINE) || defined (HAVE_LIBEDIT)
30 # include <readline/readline.h>
31 # include <readline/history.h>
32 #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
35 /* vxWorks needs mode flag -casey*/
36 # define open(name, flags) open(name, flags, 0777)
37 # define SERVER_PORT_NUM 123
40 /* We use COMMAND as an autogen keyword */
46 * Because we now potentially understand a lot of commands (and
47 * it requires a lot of commands to talk to ntpd) we will run
48 * interactive if connected to a terminal.
50 static int interactive
= 0; /* set to 1 when we should prompt */
51 static const char * prompt
= "ntpdc> "; /* prompt to ask him about */
54 * Keyid used for authenticated requests. Obtained on the fly.
56 static u_long info_auth_keyid
;
57 static int keyid_entered
= 0;
62 #define KEY_TYPE_MD5 4
64 static int info_auth_keytype
= KEY_TYPE_MD5
; /* MD5 */
65 u_long current_time
; /* needed by authkeys; not used */
70 s_char sys_precision
; /* local clock precision (log2 s) */
72 int ntpdcmain
P((int, char **));
74 * Built in command handler declarations
76 static int openhost
P((const char *));
77 static int sendpkt
P((char *, int));
78 static void growpktdata
P((void));
79 static int getresponse
P((int, int, int *, int *, char **, int));
80 static int sendrequest
P((int, int, int, int, int, char *));
81 static void getcmds
P((void));
82 static RETSIGTYPE abortcmd
P((int));
83 static void docmd
P((const char *));
84 static void tokenize
P((const char *, char **, int *));
85 static int findcmd
P((char *, struct xcmd
*, struct xcmd
*, struct xcmd
**));
86 static int getarg
P((char *, int, arg_v
*));
87 static int getnetnum
P((const char *, struct sockaddr_storage
*, char *, int));
88 static void help
P((struct parse
*, FILE *));
89 #ifdef QSORT_USES_VOID_P
90 static int helpsort
P((const void *, const void *));
92 static int helpsort
P((char **, char **));
94 static void printusage
P((struct xcmd
*, FILE *));
95 static void timeout
P((struct parse
*, FILE *));
96 static void my_delay
P((struct parse
*, FILE *));
97 static void host
P((struct parse
*, FILE *));
98 static void keyid
P((struct parse
*, FILE *));
99 static void keytype
P((struct parse
*, FILE *));
100 static void passwd
P((struct parse
*, FILE *));
101 static void hostnames
P((struct parse
*, FILE *));
102 static void setdebug
P((struct parse
*, FILE *));
103 static void quit
P((struct parse
*, FILE *));
104 static void version
P((struct parse
*, FILE *));
105 static void warning
P((const char *, const char *, const char *));
106 static void error
P((const char *, const char *, const char *));
107 static u_long getkeyid
P((const char *));
112 * Built-in commands we understand
114 static struct xcmd builtins
[] = {
115 { "?", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
116 { "command", "", "", "" },
117 "tell the use and syntax of commands" },
118 { "help", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
119 { "command", "", "", "" },
120 "tell the use and syntax of commands" },
121 { "timeout", timeout
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
122 { "msec", "", "", "" },
123 "set the primary receive time out" },
124 { "delay", my_delay
, { OPT
|NTP_INT
, NO
, NO
, NO
},
125 { "msec", "", "", "" },
126 "set the delay added to encryption time stamps" },
127 { "host", host
, { OPT
|NTP_STR
, OPT
|NTP_STR
, NO
, NO
},
128 { "-4|-6", "hostname", "", "" },
129 "specify the host whose NTP server we talk to" },
130 { "passwd", passwd
, { OPT
|NTP_STR
, NO
, NO
, NO
},
132 "specify a password to use for authenticated requests"},
133 { "hostnames", hostnames
, { OPT
|NTP_STR
, NO
, NO
, NO
},
134 { "yes|no", "", "", "" },
135 "specify whether hostnames or net numbers are printed"},
136 { "debug", setdebug
, { OPT
|NTP_STR
, NO
, NO
, NO
},
137 { "no|more|less", "", "", "" },
138 "set/change debugging level" },
139 { "quit", quit
, { NO
, NO
, NO
, NO
},
142 { "exit", quit
, { NO
, NO
, NO
, NO
},
145 { "keyid", keyid
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
146 { "key#", "", "", "" },
147 "set/show keyid to use for authenticated requests" },
148 { "keytype", keytype
, { OPT
|NTP_STR
, NO
, NO
, NO
},
149 { "(md5|des)", "", "", "" },
150 "set/show key authentication type for authenticated requests (des|md5)" },
151 { "version", version
, { NO
, NO
, NO
, NO
},
153 "print version number" },
154 { 0, 0, { NO
, NO
, NO
, NO
},
155 { "", "", "", "" }, "" }
160 * Default values we use.
162 #define DEFTIMEOUT (5) /* 5 second time out */
163 #define DEFSTIMEOUT (2) /* 2 second time out after first */
164 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
165 #define DEFHOST "localhost" /* default host name */
166 #define LENHOSTNAME 256 /* host name is 256 characters long */
167 #define MAXCMDS 100 /* maximum commands on cmd line */
168 #define MAXHOSTS 200 /* maximum hosts on cmd line */
169 #define MAXLINE 512 /* maximum line length */
170 #define MAXTOKENS (1+1+MAXARGS+MOREARGS+2) /* maximum number of usable tokens */
171 #define SCREENWIDTH 78 /* nominal screen width in columns */
174 * Some variables used and manipulated locally
176 static struct timeval tvout
= { DEFTIMEOUT
, 0 }; /* time out for reads */
177 static struct timeval tvsout
= { DEFSTIMEOUT
, 0 }; /* secondary time out */
178 static l_fp delay_time
; /* delay time */
179 static char currenthost
[LENHOSTNAME
]; /* current host name */
180 int showhostnames
= 1; /* show host names by default */
182 static int ai_fam_templ
; /* address family */
183 static int ai_fam_default
; /* default address family */
184 static SOCKET sockfd
; /* fd socket is opened on */
185 static int havehost
= 0; /* set to 1 when host open */
188 #if defined (SYS_WINNT) || defined (SYS_VXWORKS)
190 #endif /* SYS_WINNT || SYS_VXWORKS */
193 DWORD NumberOfBytesWritten
;
195 HANDLE TimerThreadHandle
= NULL
; /* 1998/06/03 - Used in ntplib/machines.c */
196 void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
198 #endif /* SYS_WINNT */
201 * Holds data returned from queries. We allocate INITDATASIZE
202 * octets to begin with, increasing this as we need to.
204 #define INITDATASIZE (sizeof(struct resp_pkt) * 16)
205 #define INCDATASIZE (sizeof(struct resp_pkt) * 8)
207 static char *pktdata
;
208 static int pktdatasize
;
211 * These are used to help the magic with old and new versions of ntpd.
213 int impl_ver
= IMPL_XNTPD
;
214 static int req_pkt_size
= REQ_LEN_NOMAC
;
217 * For commands typed on the command line (with the -c option)
219 static int numcmds
= 0;
220 static const char *ccmds
[MAXCMDS
];
221 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
224 * When multiple hosts are specified.
226 static int numhosts
= 0;
227 static const char *chosts
[MAXHOSTS
];
228 #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
231 * Error codes for internal use
233 #define ERR_INCOMPLETE 16
234 #define ERR_TIMEOUT 17
237 * Macro definitions we use
239 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
240 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
241 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
244 * For converting time stamps to dates
246 #define JAN_1970 2208988800 /* 1970 - 1900 in seconds */
249 * Jump buffer for longjumping back to the command level
251 static jmp_buf interrupt_buf
;
252 static volatile int jump
= 0;
255 * Pointer to current output unit
257 static FILE *current_output
;
260 * Command table imported from ntpdc_ops.c
262 extern struct xcmd opcmds
[];
267 #ifdef NO_MAIN_ALLOWED
268 CALL(ntpdc
,"ntpdc",ntpdcmain
);
276 return ntpdcmain(argc
, argv
);
281 void clear_globals(void)
283 showhostnames
= 0; /* show host names by default */
284 havehost
= 0; /* set to 1 when host open */
291 * main - parse arguments and handle options
299 extern int ntp_optind
;
302 delay_time
.l_uf
= DEFDELAY
;
306 taskPrioritySet(taskIdSelf(), 100 );
310 if (!Win32InitSockets())
312 fprintf(stderr
, "No useable winsock.dll:");
315 #endif /* SYS_WINNT */
317 /* Check to see if we have IPv6. Otherwise force the -4 flag */
318 if (isc_net_probeipv6() != ISC_R_SUCCESS
) {
319 ai_fam_default
= AF_INET
;
325 int optct
= optionProcess(&ntpdcOptions
, argc
, argv
);
330 switch (WHICH_IDX_IPV4
) {
332 ai_fam_templ
= AF_INET
;
335 ai_fam_templ
= AF_INET6
;
338 ai_fam_templ
= ai_fam_default
;
342 if (HAVE_OPT(COMMAND
)) {
343 int cmdct
= STACKCT_OPT( COMMAND
);
344 const char** cmds
= STACKLST_OPT( COMMAND
);
346 while (cmdct
-- > 0) {
351 debug
= DESC(DEBUG_LEVEL
).optOccCt
;
353 if (HAVE_OPT(INTERACTIVE
)) {
357 if (HAVE_OPT(NUMERIC
)) {
361 if (HAVE_OPT(LISTPEERS
)) {
365 if (HAVE_OPT(PEERS
)) {
369 if (HAVE_OPT(SHOWPEERS
)) {
373 if (ntp_optind
== argc
) {
376 for (; ntp_optind
< argc
; ntp_optind
++)
377 ADDHOST(argv
[ntp_optind
]);
380 if (numcmds
== 0 && interactive
== 0
381 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
386 ai_fam_templ
= ai_fam_default
;
387 while ((c
= ntp_getopt(argc
, argv
, "46c:dilnps")) != EOF
)
390 ai_fam_templ
= AF_INET
;
393 ai_fam_templ
= AF_INET6
;
422 (void) fprintf(stderr
,
423 "usage: %s [-46dilnps] [-c cmd] host ...\n",
428 if (ntp_optind
== argc
) {
431 for (; ntp_optind
< argc
; ntp_optind
++)
432 ADDHOST(argv
[ntp_optind
]);
435 if (numcmds
== 0 && interactive
== 0
436 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
441 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
443 (void) signal_no_reset(SIGINT
, abortcmd
);
444 #endif /* SYS_WINNT */
447 * Initialize the packet data buffer
449 pktdata
= (char *)malloc(INITDATASIZE
);
450 if (pktdata
== NULL
) {
451 (void) fprintf(stderr
, "%s: malloc() failed!\n", progname
);
454 pktdatasize
= INITDATASIZE
;
457 (void) openhost(chosts
[0]);
463 for (ihost
= 0; ihost
< numhosts
; ihost
++) {
464 if (openhost(chosts
[ihost
]))
465 for (icmd
= 0; icmd
< numcmds
; icmd
++) {
467 printf ("--- %s ---\n",chosts
[ihost
]);
480 * openhost - open a socket to a host
487 char temphost
[LENHOSTNAME
];
489 struct addrinfo hints
, *ai
= NULL
;
490 register const char *cp
;
491 char name
[LENHOSTNAME
];
495 * We need to get by the [] if they were entered
502 for(i
= 0; *cp
!= ']'; cp
++, i
++)
509 * First try to resolve it as an ip address and if that fails,
510 * do a fullblown (dns) lookup. That way we only use the dns
511 * when it is needed and work around some implementations that
512 * will return an "IPv4-mapped IPv6 address" address if you
513 * give it an IPv4 address to lookup.
515 strcpy(service
, "ntp");
516 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
517 hints
.ai_family
= ai_fam_templ
;
518 hints
.ai_protocol
= IPPROTO_UDP
;
519 hints
.ai_socktype
= SOCK_DGRAM
;
520 hints
.ai_flags
= AI_NUMERICHOST
;
522 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
523 if (a_info
== EAI_NONAME
525 || a_info
== EAI_NODATA
528 hints
.ai_flags
= AI_CANONNAME
;
530 hints
.ai_flags
|= AI_ADDRCONFIG
;
532 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
534 /* Some older implementations don't like AI_ADDRCONFIG. */
535 if (a_info
== EAI_BADFLAGS
) {
536 hints
.ai_flags
= AI_CANONNAME
;
537 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
540 (void) fprintf(stderr
, "%s\n", gai_strerror(a_info
));
546 if (ai
->ai_canonname
== NULL
) {
547 strncpy(temphost
, stoa((struct sockaddr_storage
*)ai
->ai_addr
),
549 temphost
[LENHOSTNAME
-1] = '\0';
551 strncpy(temphost
, ai
->ai_canonname
, LENHOSTNAME
);
552 temphost
[LENHOSTNAME
-1] = '\0';
556 printf("Opening host %s\n", temphost
);
560 printf("Closing old host %s\n", currenthost
);
561 (void) closesocket(sockfd
);
564 (void) strcpy(currenthost
, temphost
);
566 /* port maps to the same in both families */
567 s_port
= ((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_port
;
569 ((struct sockaddr_in6
*)&hostaddr
)->sin6_port
= htons(SERVER_PORT_NUM
);
570 if (ai
->ai_family
== AF_INET
)
571 *(struct sockaddr_in
*)&hostaddr
=
572 *((struct sockaddr_in
*)ai
->ai_addr
);
574 *(struct sockaddr_in6
*)&hostaddr
=
575 *((struct sockaddr_in6
*)ai
->ai_addr
);
576 #endif /* SYS_VXWORKS */
580 int optionValue
= SO_SYNCHRONOUS_NONALERT
;
583 err
= setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&optionValue
, sizeof(optionValue
));
584 if (err
!= NO_ERROR
) {
585 (void) fprintf(stderr
, "cannot open nonoverlapped sockets\n");
590 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
591 if (sockfd
== INVALID_SOCKET
) {
592 error("socket", "", "");
596 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
598 error("socket", "", "");
599 #endif /* SYS_WINNT */
602 #ifdef NEED_RCVBUF_SLOP
605 int rbufsize
= INITDATASIZE
+ 2048; /* 2K for slop */
607 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
,
608 &rbufsize
, sizeof(int)) == -1)
609 error("setsockopt", "", "");
615 if (connect(sockfd
, (struct sockaddr
*)&hostaddr
,
616 sizeof(hostaddr
)) == -1)
618 if (connect(sockfd
, (struct sockaddr
*)ai
->ai_addr
,
619 ai
->ai_addrlen
) == -1)
620 #endif /* SYS_VXWORKS */
621 error("connect", "", "");
625 req_pkt_size
= REQ_LEN_NOMAC
;
626 impl_ver
= IMPL_XNTPD
;
631 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
633 * sendpkt - send a packet to the remote host
641 if (send(sockfd
, xdata
, (size_t)xdatalen
, 0) == -1) {
642 warning("write to %s failed", currenthost
, "");
651 * growpktdata - grow the packet data area
656 pktdatasize
+= INCDATASIZE
;
657 pktdata
= (char *)realloc(pktdata
, (unsigned)pktdatasize
);
659 (void) fprintf(stderr
, "%s: realloc() failed!\n", progname
);
666 * getresponse - get a (series of) response packet(s) and return the data
678 struct resp_pkt rpkt
;
686 char haveseq
[MAXSEQ
+1];
696 * This is pretty tricky. We may get between 1 and many packets
697 * back in response to the request. We peel the data out of
698 * each packet and collect it in one long block. When the last
699 * packet in the sequence is received we'll know how many we
700 * should have had. Note we use one long time out, should reconsider.
706 *rdata
= datap
= pktdata
;
707 lastseq
= 999; /* too big to be a sequence number */
708 memset(haveseq
, 0, sizeof(haveseq
));
717 FD_SET(sockfd
, &fds
);
718 n
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvo
);
721 warning("select fails", "", "");
726 * Timed out. Return what we have
729 (void) fprintf(stderr
,
730 "%s: timed out, nothing received\n", currenthost
);
733 (void) fprintf(stderr
,
734 "%s: timed out with incomplete data\n",
737 printf("Received sequence numbers");
738 for (n
= 0; n
<= MAXSEQ
; n
++)
742 printf(" last frame received\n");
744 printf(" last frame not received\n");
746 return ERR_INCOMPLETE
;
750 n
= recv(sockfd
, (char *)&rpkt
, sizeof(rpkt
), 0);
752 warning("read", "", "");
758 * Check for format errors. Bug proofing.
760 if (n
< RESP_HEADER_SIZE
) {
762 printf("Short (%d byte) packet received\n", n
);
765 if (INFO_VERSION(rpkt
.rm_vn_mode
) > NTP_VERSION
||
766 INFO_VERSION(rpkt
.rm_vn_mode
) < NTP_OLDVERSION
) {
768 printf("Packet received with version %d\n",
769 INFO_VERSION(rpkt
.rm_vn_mode
));
772 if (INFO_MODE(rpkt
.rm_vn_mode
) != MODE_PRIVATE
) {
774 printf("Packet received with mode %d\n",
775 INFO_MODE(rpkt
.rm_vn_mode
));
778 if (INFO_IS_AUTH(rpkt
.auth_seq
)) {
780 printf("Encrypted packet received\n");
783 if (!ISRESPONSE(rpkt
.rm_vn_mode
)) {
785 printf("Received request packet, wanted response\n");
788 if (INFO_MBZ(rpkt
.mbz_itemsize
) != 0) {
790 printf("Received packet with nonzero MBZ field!\n");
795 * Check implementation/request. Could be old data getting to us.
797 if (rpkt
.implementation
!= implcode
|| rpkt
.request
!= reqcode
) {
800 "Received implementation/request of %d/%d, wanted %d/%d",
801 rpkt
.implementation
, rpkt
.request
,
807 * Check the error code. If non-zero, return it.
809 if (INFO_ERR(rpkt
.err_nitems
) != INFO_OKAY
) {
810 if (debug
&& ISMORE(rpkt
.rm_vn_mode
)) {
811 printf("Error code %d received on not-final packet\n",
812 INFO_ERR(rpkt
.err_nitems
));
814 return (int)INFO_ERR(rpkt
.err_nitems
);
818 * Collect items and size. Make sure they make sense.
820 items
= INFO_NITEMS(rpkt
.err_nitems
);
821 size
= INFO_ITEMSIZE(rpkt
.mbz_itemsize
);
826 if ((datasize
= items
*size
) > (n
-RESP_HEADER_SIZE
)) {
829 "Received items %d, size %d (total %d), data in packet is %d\n",
830 items
, size
, datasize
, n
-RESP_HEADER_SIZE
);
835 * If this isn't our first packet, make sure the size matches
838 if (!firstpkt
&& esize
!= *rsize
) {
840 printf("Received itemsize %d, previous %d\n",
845 * If we've received this before, +toss it
847 seq
= INFO_SEQ(rpkt
.auth_seq
);
850 printf("Received duplicate sequence number %d\n", seq
);
856 * If this is the last in the sequence, record that.
858 if (!ISMORE(rpkt
.rm_vn_mode
)) {
859 if (lastseq
!= 999) {
860 printf("Received second end sequence packet\n");
867 * So far, so good. Copy this data into the output array.
869 if ((datap
+ datasize
+ (pad
* items
)) > (pktdata
+ pktdatasize
)) {
870 int offset
= datap
- pktdata
;
872 *rdata
= pktdata
; /* might have been realloced ! */
873 datap
= pktdata
+ offset
;
876 * We now move the pointer along according to size and number of
877 * items. This is so we can play nice with older implementations
880 tmp_data
= (char *)rpkt
.data
;
881 for(i
= 0; i
<items
; i
++){
882 memmove(datap
, tmp_data
, (unsigned)size
);
884 memset(datap
+ size
, 0, pad
);
895 * Finally, check the count of received packets. If we've got them
899 if (numrecv
<= lastseq
)
906 * sendrequest - format and send a request packet
921 memset((char *)&qpkt
, 0, sizeof qpkt
);
923 qpkt
.rm_vn_mode
= RM_VN_MODE(0, 0, 0);
924 qpkt
.implementation
= (u_char
)implcode
;
925 qpkt
.request
= (u_char
)reqcode
;
927 datasize
= qitems
* qsize
;
928 if (datasize
!= 0 && qdata
!= NULL
) {
929 memmove((char *)qpkt
.data
, qdata
, (unsigned)datasize
);
930 qpkt
.err_nitems
= ERR_NITEMS(0, qitems
);
931 qpkt
.mbz_itemsize
= MBZ_ITEMSIZE(qsize
);
933 qpkt
.err_nitems
= ERR_NITEMS(0, 0);
934 qpkt
.mbz_itemsize
= MBZ_ITEMSIZE(qsize
); /* allow for optional first item */
937 if (!auth
|| (keyid_entered
&& info_auth_keyid
== 0)) {
938 qpkt
.auth_seq
= AUTH_SEQ(0, 0);
939 return sendpkt((char *)&qpkt
, req_pkt_size
);
943 const char *pass
= "\0";
944 struct req_pkt_tail
*qpktail
;
946 qpktail
= (struct req_pkt_tail
*)((char *)&qpkt
+ req_pkt_size
947 + MAX_MAC_LEN
- sizeof(struct req_pkt_tail
));
949 if (info_auth_keyid
== 0) {
950 if (((struct conf_peer
*)qpkt
.data
)->keyid
> 0)
951 info_auth_keyid
= ((struct conf_peer
*)qpkt
.data
)->keyid
;
953 maclen
= getkeyid("Keyid: ");
955 (void) fprintf(stderr
,
956 "Invalid key identifier\n");
959 info_auth_keyid
= maclen
;
962 if (!authistrusted(info_auth_keyid
)) {
963 pass
= getpass("MD5 Password: ");
965 (void) fprintf(stderr
,
966 "Invalid password\n");
970 authusekey(info_auth_keyid
, info_auth_keytype
, (const u_char
*)pass
);
971 authtrust(info_auth_keyid
, 1);
972 qpkt
.auth_seq
= AUTH_SEQ(1, 0);
973 qpktail
->keyid
= htonl(info_auth_keyid
);
975 L_ADD(&ts
, &delay_time
);
976 HTONL_FP(&ts
, &qpktail
->tstamp
);
977 maclen
= authencrypt(info_auth_keyid
, (u_int32
*)&qpkt
,
980 (void) fprintf(stderr
, "Key not found\n");
983 return sendpkt((char *)&qpkt
, (int)(req_pkt_size
+ maclen
));
990 * doquery - send a request and process the response
1010 struct timeval tvzero
;
1013 * Check to make sure host is open
1016 (void) fprintf(stderr
, "***No host open, use `host' command\n");
1021 * Poll the socket and clear out any pending data
1025 tvzero
.tv_sec
= tvzero
.tv_usec
= 0;
1027 FD_SET(sockfd
, &fds
);
1028 res
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvzero
);
1031 warning("polling select", "", "");
1035 (void) recv(sockfd
, junk
, sizeof junk
, 0);
1042 res
= sendrequest(implcode
, reqcode
, auth
, qitems
, qsize
, qdata
);
1047 * Get the response. If we got a standard error, print a message
1049 res
= getresponse(implcode
, reqcode
, ritems
, rsize
, rdata
, esize
);
1052 * Try to be compatible with older implementations of ntpd.
1054 if (res
== INFO_ERR_FMT
&& req_pkt_size
!= 48) {
1057 oldsize
= req_pkt_size
;
1059 switch(req_pkt_size
) {
1067 if (impl_ver
== IMPL_XNTPD
) {
1069 "***Warning changing to older implementation\n");
1070 return INFO_ERR_IMPL
;
1074 "***Warning changing the request packet size from %d to %d\n",
1075 oldsize
, req_pkt_size
);
1079 /* log error message if not told to be quiet */
1080 if ((res
> 0) && (((1 << res
) & quiet_mask
) == 0)) {
1083 /* Give us a chance to try the older implementation. */
1084 if (implcode
== IMPL_XNTPD
)
1086 (void) fprintf(stderr
,
1087 "***Server implementation incompatable with our own\n");
1090 (void) fprintf(stderr
,
1091 "***Server doesn't implement this request\n");
1094 (void) fprintf(stderr
,
1095 "***Server reports a format error in the received packet (shouldn't happen)\n");
1097 case INFO_ERR_NODATA
:
1098 (void) fprintf(stderr
,
1099 "***Server reports data not found\n");
1102 (void) fprintf(stderr
, "***Permission denied\n");
1105 (void) fprintf(stderr
, "***Request timed out\n");
1107 case ERR_INCOMPLETE
:
1108 (void) fprintf(stderr
,
1109 "***Response from server was incomplete\n");
1112 (void) fprintf(stderr
,
1113 "***Server returns unknown error code %d\n", res
);
1122 * getcmds - read commands from the standard input and execute them
1127 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
1131 if ((line
= readline(interactive
?prompt
:"")) == NULL
) return;
1132 if (*line
) add_history(line
);
1136 #else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
1141 #ifdef VMS /* work around a problem with mixing stdout & stderr */
1144 (void) fputs(prompt
, stderr
);
1145 (void) fflush(stderr
);
1148 if (fgets(line
, sizeof line
, stdin
) == NULL
)
1153 #endif /* not HAVE_LIBREADLINE || HAVE_LIBEDIT */
1157 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1159 * abortcmd - catch interrupts and abort the current command
1167 if (current_output
== stdout
)
1168 (void) fflush(stdout
);
1170 (void) fflush(stderr
);
1171 if (jump
) longjmp(interrupt_buf
, 1);
1173 #endif /* SYS_WINNT */
1176 * docmd - decode the command line and execute a command
1183 char *tokens
[1+MAXARGS
+MOREARGS
+2];
1190 ai_fam_templ
= ai_fam_default
;
1192 * Tokenize the command line. If nothing on it, return.
1194 tokenize(cmdline
, tokens
, &ntok
);
1199 * Find the appropriate command description.
1201 i
= findcmd(tokens
[0], builtins
, opcmds
, &xcmd
);
1203 (void) fprintf(stderr
, "***Command `%s' unknown\n",
1206 } else if (i
>= 2) {
1207 (void) fprintf(stderr
, "***Command `%s' ambiguous\n",
1213 * Save the keyword, then walk through the arguments, interpreting
1216 pcmd
.keyword
= tokens
[0];
1219 for (i
= 0; i
< MAXARGS
&& xcmd
->arg
[i
] != NO
;) {
1220 if ((i
+ti
) >= ntok
) {
1221 if (!(xcmd
->arg
[i
] & OPT
)) {
1222 printusage(xcmd
, stderr
);
1227 if ((xcmd
->arg
[i
] & OPT
) && (*tokens
[i
+ti
] == '>'))
1229 rval
= getarg(tokens
[i
+ti
], (int)xcmd
->arg
[i
], &pcmd
.argval
[i
]);
1240 /* Any extra args are assumed to be "OPT|NTP_STR". */
1241 for ( ; i
< MAXARGS
+ MOREARGS
;) {
1244 rval
= getarg(tokens
[i
+ti
], (int)(OPT
|NTP_STR
), &pcmd
.argval
[i
]);
1256 if (i
< ntok
&& *tokens
[i
] == '>') {
1259 if (*(tokens
[i
]+1) != '\0')
1260 fname
= tokens
[i
]+1;
1261 else if ((i
+1) < ntok
)
1262 fname
= tokens
[i
+1];
1264 (void) fprintf(stderr
, "***No file for redirect\n");
1268 current_output
= fopen(fname
, "w");
1269 if (current_output
== NULL
) {
1270 (void) fprintf(stderr
, "***Error opening %s: ", fname
);
1275 current_output
= stdout
;
1278 if (interactive
&& setjmp(interrupt_buf
)) {
1282 (xcmd
->handler
)(&pcmd
, current_output
);
1284 if (current_output
!= stdout
)
1285 (void) fclose(current_output
);
1286 current_output
= NULL
;
1292 * tokenize - turn a command line into tokens
1301 register const char *cp
;
1303 static char tspace
[MAXLINE
];
1307 for (*ntok
= 0; *ntok
< MAXTOKENS
; (*ntok
)++) {
1309 while (ISSPACE(*cp
))
1315 } while (!ISSPACE(*cp
) && !ISEOL(*cp
));
1324 * findcmd - find a command in a command description table
1329 struct xcmd
*clist1
,
1330 struct xcmd
*clist2
,
1334 register struct xcmd
*cl
;
1337 struct xcmd
*nearmatch
= NULL
;
1344 else if (clist2
!= 0)
1350 for (cl
= clist
; cl
->keyword
!= 0; cl
++) {
1351 /* do a first character check, for efficiency */
1352 if (*str
!= *(cl
->keyword
))
1354 if (strncmp(str
, cl
->keyword
, (unsigned)clen
) == 0) {
1356 * Could be extact match, could be approximate.
1357 * Is exact if the length of the keyword is the
1360 if (*((cl
->keyword
) + clen
) == '\0') {
1370 * See if there is more to do. If so, go again. Sorry about the
1371 * goto, too much looking at BSD sources...
1373 if (clist
== clist1
&& clist2
!= 0) {
1379 * If we got extactly 1 near match, use it, else return number
1391 * getarg - interpret an argument token
1393 * string is always set.
1394 * type is set to the decoded type.
1396 * return: 0 - failure
1398 * -1 - skip to next token
1409 static const char *digits
= "0123456789";
1411 memset(argp
, 0, sizeof(*argp
));
1414 argp
->type
= code
& ~OPT
;
1416 switch (argp
->type
) {
1420 if (!strcmp("-6", str
)) {
1421 ai_fam_templ
= AF_INET6
;
1423 } else if (!strcmp("-4", str
)) {
1424 ai_fam_templ
= AF_INET
;
1427 if (!getnetnum(str
, &(argp
->netnum
), (char *)0, 0)) {
1442 cp
= strchr(digits
, *np
);
1444 (void) fprintf(stderr
,
1445 "***Illegal integer value %s\n", str
);
1449 argp
->uval
+= (cp
- digits
);
1450 } while (*(++np
) != '\0');
1453 if ((code
& ~OPT
) == NTP_UINT
) {
1454 (void) fprintf(stderr
,
1455 "***Value %s should be unsigned\n", str
);
1458 argp
->ival
= -argp
->ival
;
1462 if (!strcmp("-6", str
))
1464 else if (!strcmp("-4", str
))
1467 (void) fprintf(stderr
,
1468 "***Version must be either 4 or 6\n");
1479 * getnetnum - given a host name, return its net number
1480 * and (optional) full name
1485 struct sockaddr_storage
*num
,
1491 struct addrinfo hints
, *ai
= NULL
;
1493 sockaddr_len
= (af
== AF_INET
)
1494 ? sizeof(struct sockaddr_in
)
1495 : sizeof(struct sockaddr_in6
);
1496 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
1497 hints
.ai_flags
= AI_CANONNAME
;
1498 #ifdef AI_ADDRCONFIG
1499 hints
.ai_flags
|= AI_ADDRCONFIG
;
1502 /* decodenetnum only works with addresses */
1503 if (decodenetnum(hname
, num
)) {
1504 if (fullhost
!= 0) {
1505 getnameinfo((struct sockaddr
*)num
, sockaddr_len
,
1506 fullhost
, sizeof(fullhost
), NULL
, 0,
1510 } else if (getaddrinfo(hname
, "ntp", &hints
, &ai
) == 0) {
1511 memmove((char *)num
, ai
->ai_addr
, ai
->ai_addrlen
);
1513 (void) strcpy(fullhost
, ai
->ai_canonname
);
1516 (void) fprintf(stderr
, "***Can't find host %s\n", hname
);
1523 * nntohost - convert network number to host name. This routine enforces
1524 * the showhostnames setting.
1528 struct sockaddr_storage
*netnum
1532 return stoa(netnum
);
1534 if ((netnum
->ss_family
== AF_INET
) && ISREFCLOCKADR(netnum
))
1535 return refnumtoa(netnum
);
1536 return socktohost(netnum
);
1541 * Finally, the built in command handlers
1545 * help - tell about commands, or details of a particular command
1555 const char *list
[100];
1560 if (pcmd
->nargs
== 0) {
1562 for (xcp
= builtins
; xcp
->keyword
!= 0; xcp
++) {
1563 if (*(xcp
->keyword
) != '?')
1564 list
[words
++] = xcp
->keyword
;
1566 for (xcp
= opcmds
; xcp
->keyword
!= 0; xcp
++)
1567 list
[words
++] = xcp
->keyword
;
1570 #ifdef QSORT_USES_VOID_P
1575 (list
), (size_t)(words
), sizeof(char *), helpsort
);
1577 for (word
= 0; word
< words
; word
++) {
1578 int length
= strlen(list
[word
]);
1584 cols
= SCREENWIDTH
/ ++col
;
1585 rows
= (words
+ cols
- 1) / cols
;
1587 (void) fprintf(fp
, "ntpdc commands:\n");
1589 for (row
= 0; row
< rows
; row
++) {
1590 for (word
= row
; word
< words
; word
+= rows
) {
1591 (void) fprintf(fp
, "%-*.*s", col
, col
-1, list
[word
]);
1593 (void) fprintf(fp
, "\n");
1596 cmd
= pcmd
->argval
[0].string
;
1597 words
= findcmd(cmd
, builtins
, opcmds
, &xcp
);
1599 (void) fprintf(stderr
,
1600 "Command `%s' is unknown\n", cmd
);
1602 } else if (words
>= 2) {
1603 (void) fprintf(stderr
,
1604 "Command `%s' is ambiguous\n", cmd
);
1607 (void) fprintf(fp
, "function: %s\n", xcp
->comment
);
1608 printusage(xcp
, fp
);
1614 * helpsort - do hostname qsort comparisons
1616 #ifdef QSORT_USES_VOID_P
1623 char const * const * name1
= (char const * const *)t1
;
1624 char const * const * name2
= (char const * const *)t2
;
1626 return strcmp(*name1
, *name2
);
1635 return strcmp(*name1
, *name2
);
1641 * printusage - print usage information for a command
1652 (void) fprintf(fp
, "usage: %s", xcp
->keyword
);
1653 for (i
= 0; i
< MAXARGS
&& xcp
->arg
[i
] != NO
; i
++) {
1654 if (opt46
== 0 && (xcp
->arg
[i
] & ~OPT
) == NTP_ADD
) {
1655 (void) fprintf(fp
, " [ -4|-6 ]");
1658 if (xcp
->arg
[i
] & OPT
)
1659 (void) fprintf(fp
, " [ %s ]", xcp
->desc
[i
]);
1661 (void) fprintf(fp
, " %s", xcp
->desc
[i
]);
1663 (void) fprintf(fp
, "\n");
1668 * timeout - set time out time
1678 if (pcmd
->nargs
== 0) {
1679 val
= tvout
.tv_sec
* 1000 + tvout
.tv_usec
/ 1000;
1680 (void) fprintf(fp
, "primary timeout %d ms\n", val
);
1682 tvout
.tv_sec
= pcmd
->argval
[0].uval
/ 1000;
1683 tvout
.tv_usec
= (pcmd
->argval
[0].uval
- (tvout
.tv_sec
* 1000))
1690 * my_delay - set delay for auth requests
1701 if (pcmd
->nargs
== 0) {
1702 val
= delay_time
.l_ui
* 1000 + delay_time
.l_uf
/ 4294967;
1703 (void) fprintf(fp
, "delay %lu ms\n", val
);
1705 if (pcmd
->argval
[0].ival
< 0) {
1707 val
= (u_long
)(-pcmd
->argval
[0].ival
);
1710 val
= (u_long
)pcmd
->argval
[0].ival
;
1713 delay_time
.l_ui
= val
/ 1000;
1715 delay_time
.l_uf
= val
* 4294967; /* 2**32/1000 */
1724 * host - set the host we are dealing with.
1734 if (pcmd
->nargs
== 0) {
1736 (void) fprintf(fp
, "current host is %s\n", currenthost
);
1738 (void) fprintf(fp
, "no current host\n");
1743 if (pcmd
->nargs
== 2) {
1744 if (!strcmp("-4", pcmd
->argval
[i
].string
))
1745 ai_fam_templ
= AF_INET
;
1746 else if (!strcmp("-6", pcmd
->argval
[i
].string
))
1747 ai_fam_templ
= AF_INET6
;
1751 "current host remains %s\n", currenthost
);
1753 (void) fprintf(fp
, "still no current host\n");
1758 if (openhost(pcmd
->argval
[i
].string
)) {
1759 (void) fprintf(fp
, "current host set to %s\n", currenthost
);
1763 "current host remains %s\n", currenthost
);
1765 (void) fprintf(fp
, "still no current host\n");
1771 * keyid - get a keyid to use for authenticating requests
1779 if (pcmd
->nargs
== 0) {
1780 if (info_auth_keyid
== 0 && !keyid_entered
)
1781 (void) fprintf(fp
, "no keyid defined\n");
1782 else if (info_auth_keyid
== 0 && keyid_entered
)
1783 (void) fprintf(fp
, "no keyid will be sent\n");
1785 (void) fprintf(fp
, "keyid is %lu\n", (u_long
)info_auth_keyid
);
1787 info_auth_keyid
= pcmd
->argval
[0].uval
;
1794 * keytype - get type of key to use for authenticating requests
1802 if (pcmd
->nargs
== 0)
1803 fprintf(fp
, "keytype is %s\n",
1804 (info_auth_keytype
== KEY_TYPE_MD5
) ? "MD5" : "???");
1806 switch (*(pcmd
->argval
[0].string
)) {
1809 info_auth_keytype
= KEY_TYPE_MD5
;
1813 fprintf(fp
, "keytype must be 'md5'\n");
1820 * passwd - get an authentication key
1831 if (info_auth_keyid
== 0) {
1832 info_auth_keyid
= getkeyid("Keyid: ");
1833 if (info_auth_keyid
== 0) {
1834 (void)fprintf(fp
, "Keyid must be defined\n");
1839 authusekey(info_auth_keyid
, info_auth_keytype
,
1840 (u_char
*)pcmd
->argval
[0].string
);
1841 authtrust(info_auth_keyid
, 1);
1843 pass
= getpass("MD5 Password: ");
1845 (void) fprintf(fp
, "Password unchanged\n");
1847 authusekey(info_auth_keyid
, info_auth_keytype
,
1849 authtrust(info_auth_keyid
, 1);
1856 * hostnames - set the showhostnames flag
1864 if (pcmd
->nargs
== 0) {
1866 (void) fprintf(fp
, "hostnames being shown\n");
1868 (void) fprintf(fp
, "hostnames not being shown\n");
1870 if (STREQ(pcmd
->argval
[0].string
, "yes"))
1872 else if (STREQ(pcmd
->argval
[0].string
, "no"))
1875 (void)fprintf(stderr
, "What?\n");
1881 * setdebug - set/change debugging level
1889 if (pcmd
->nargs
== 0) {
1890 (void) fprintf(fp
, "debug level is %d\n", debug
);
1892 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
1894 } else if (STREQ(pcmd
->argval
[0].string
, "more")) {
1896 } else if (STREQ(pcmd
->argval
[0].string
, "less")) {
1899 (void) fprintf(fp
, "What?\n");
1902 (void) fprintf(fp
, "debug level set to %d\n", debug
);
1907 * quit - stop this nonsense
1917 closesocket(sockfd
);
1923 * version - print the current version number
1933 (void) fprintf(fp
, "%s\n", Version
);
1939 * warning - print a warning message
1948 (void) fprintf(stderr
, "%s: ", progname
);
1949 (void) fprintf(stderr
, fmt
, st1
, st2
);
1950 (void) fprintf(stderr
, ": ");
1956 * error - print a message and exit
1965 warning(fmt
, st1
, st2
);
1970 * getkeyid - prompt the user for a keyid to use
1974 const char *keyprompt
1983 if ((fi
= fdopen(open("/dev/tty", 2), "r")) == NULL
)
1985 if ((fi
= _fdopen((int)GetStdHandle(STD_INPUT_HANDLE
), "r")) == NULL
)
1986 #endif /* SYS_WINNT */
1989 setbuf(fi
, (char *)NULL
);
1990 fprintf(stderr
, "%s", keyprompt
); fflush(stderr
);
1991 for (p
=pbuf
; (c
= getc(fi
))!='\n' && c
!=EOF
;) {
1998 return (u_int32
)atoi(pbuf
);