4 * ntpdc - control and monitor your ntpd daemon
14 #include "ntp_select.h"
16 #include "ntp_stdlib.h"
17 #include "ntp_assert.h"
18 #include "ntp_lineedit.h"
20 #include "isc/result.h"
21 #include <ssl_applink.c>
23 #include "ntpdc-opts.h"
28 #endif /* SYS_WINNT */
31 /* vxWorks needs mode flag -casey*/
32 # define open(name, flags) open(name, flags, 0777)
33 # define SERVER_PORT_NUM 123
36 /* We use COMMAND as an autogen keyword */
42 * Because we now potentially understand a lot of commands (and
43 * it requires a lot of commands to talk to ntpd) we will run
44 * interactive if connected to a terminal.
46 static int interactive
= 0; /* set to 1 when we should prompt */
47 static const char * prompt
= "ntpdc> "; /* prompt to ask him about */
50 * Keyid used for authenticated requests. Obtained on the fly.
52 static u_long info_auth_keyid
;
53 static int keyid_entered
= 0;
55 static int info_auth_keytype
= NID_md5
; /* MD5 */
56 static size_t info_auth_hashlen
= 16; /* MD5 */
57 u_long current_time
; /* needed by authkeys; not used */
62 s_char sys_precision
; /* local clock precision (log2 s) */
65 * Use getpassphrase() if configure.ac detected it, as Suns that
66 * have it truncate the password in getpass() to 8 characters.
68 #ifdef HAVE_GETPASSPHRASE
69 # define getpass(str) getpassphrase(str)
72 int ntpdcmain (int, char **);
74 * Built in command handler declarations
76 static int openhost (const char *);
77 static int sendpkt (void *, size_t);
78 static void growpktdata (void);
79 static int getresponse (int, int, int *, int *, char **, int);
80 static int sendrequest (int, int, int, u_int
, size_t, char *);
81 static void getcmds (void);
82 static RETSIGTYPE
abortcmd (int);
83 static void docmd (const char *);
84 static void tokenize (const char *, char **, int *);
85 static int findcmd (char *, struct xcmd
*, struct xcmd
*, struct xcmd
**);
86 static int getarg (char *, int, arg_v
*);
87 static int getnetnum (const char *, sockaddr_u
*, char *, int);
88 static void help (struct parse
*, FILE *);
89 #ifdef QSORT_USES_VOID_P
90 static int helpsort (const void *, const void *);
92 static int helpsort (char **, char **);
94 static void printusage (struct xcmd
*, FILE *);
95 static void timeout (struct parse
*, FILE *);
96 static void my_delay (struct parse
*, FILE *);
97 static void host (struct parse
*, FILE *);
98 static void keyid (struct parse
*, FILE *);
99 static void keytype (struct parse
*, FILE *);
100 static void passwd (struct parse
*, FILE *);
101 static void hostnames (struct parse
*, FILE *);
102 static void setdebug (struct parse
*, FILE *);
103 static void quit (struct parse
*, FILE *);
104 static void version (struct parse
*, FILE *);
105 static void warning (const char *, const char *, const char *);
106 static void error (const char *, const char *, const char *);
107 static u_long
getkeyid (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 DEFHOST "localhost" /* default host name */
163 #define DEFTIMEOUT (5) /* 5 second time out */
164 #define DEFSTIMEOUT (2) /* 2 second time out after first */
165 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
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 sock_timeval tvout
= { DEFTIMEOUT
, 0 }; /* time out for reads */
177 static struct sock_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 */
189 * Holds data returned from queries. We allocate INITDATASIZE
190 * octets to begin with, increasing this as we need to.
192 #define INITDATASIZE (sizeof(struct resp_pkt) * 16)
193 #define INCDATASIZE (sizeof(struct resp_pkt) * 8)
195 static char *pktdata
;
196 static int pktdatasize
;
199 * These are used to help the magic with old and new versions of ntpd.
201 int impl_ver
= IMPL_XNTPD
;
202 static int req_pkt_size
= REQ_LEN_NOMAC
;
205 * For commands typed on the command line (with the -c option)
207 static int numcmds
= 0;
208 static const char *ccmds
[MAXCMDS
];
209 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
212 * When multiple hosts are specified.
214 static int numhosts
= 0;
215 static const char *chosts
[MAXHOSTS
];
216 #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
219 * Error codes for internal use
221 #define ERR_INCOMPLETE 16
222 #define ERR_TIMEOUT 17
225 * Macro definitions we use
227 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
228 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
229 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
232 * For converting time stamps to dates
234 #define JAN_1970 2208988800 /* 1970 - 1900 in seconds */
237 * Jump buffer for longjumping back to the command level
239 static jmp_buf interrupt_buf
;
240 static volatile int jump
= 0;
243 * Pointer to current output unit
245 static FILE *current_output
;
248 * Command table imported from ntpdc_ops.c
250 extern struct xcmd opcmds
[];
255 #ifdef NO_MAIN_ALLOWED
256 CALL(ntpdc
,"ntpdc",ntpdcmain
);
264 return ntpdcmain(argc
, argv
);
269 void clear_globals(void)
271 showhostnames
= 0; /* show host names by default */
272 havehost
= 0; /* set to 1 when host open */
279 * main - parse arguments and handle options
287 extern int ntp_optind
;
290 delay_time
.l_uf
= DEFDELAY
;
294 taskPrioritySet(taskIdSelf(), 100 );
297 init_lib(); /* sets up ipv4_works, ipv6_works */
300 /* Check to see if we have IPv6. Otherwise default to IPv4 */
302 ai_fam_default
= AF_INET
;
307 int optct
= optionProcess(&ntpdcOptions
, argc
, argv
);
313 ai_fam_templ
= AF_INET
;
314 else if (HAVE_OPT(IPV6
))
315 ai_fam_templ
= AF_INET6
;
317 ai_fam_templ
= ai_fam_default
;
319 if (HAVE_OPT(COMMAND
)) {
320 int cmdct
= STACKCT_OPT( COMMAND
);
321 const char** cmds
= STACKLST_OPT( COMMAND
);
323 while (cmdct
-- > 0) {
328 debug
= DESC(DEBUG_LEVEL
).optOccCt
;
330 if (HAVE_OPT(INTERACTIVE
)) {
334 if (HAVE_OPT(NUMERIC
)) {
338 if (HAVE_OPT(LISTPEERS
)) {
342 if (HAVE_OPT(PEERS
)) {
346 if (HAVE_OPT(SHOWPEERS
)) {
350 if (ntp_optind
== argc
) {
353 for (; ntp_optind
< argc
; ntp_optind
++)
354 ADDHOST(argv
[ntp_optind
]);
357 if (numcmds
== 0 && interactive
== 0
358 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
363 ai_fam_templ
= ai_fam_default
;
364 while ((c
= ntp_getopt(argc
, argv
, "46c:dilnps")) != EOF
)
367 ai_fam_templ
= AF_INET
;
370 ai_fam_templ
= AF_INET6
;
399 (void) fprintf(stderr
,
400 "usage: %s [-46dilnps] [-c cmd] host ...\n",
405 if (ntp_optind
== argc
) {
408 for (; ntp_optind
< argc
; ntp_optind
++)
409 ADDHOST(argv
[ntp_optind
]);
412 if (numcmds
== 0 && interactive
== 0
413 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
418 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
420 (void) signal_no_reset(SIGINT
, abortcmd
);
421 #endif /* SYS_WINNT */
424 * Initialize the packet data buffer
426 pktdatasize
= INITDATASIZE
;
427 pktdata
= emalloc(INITDATASIZE
);
430 (void) openhost(chosts
[0]);
436 for (ihost
= 0; ihost
< numhosts
; ihost
++) {
437 if (openhost(chosts
[ihost
]))
438 for (icmd
= 0; icmd
< numcmds
; icmd
++) {
440 printf ("--- %s ---\n",chosts
[ihost
]);
453 * openhost - open a socket to a host
460 char temphost
[LENHOSTNAME
];
462 struct addrinfo hints
, *ai
= NULL
;
463 register const char *cp
;
464 char name
[LENHOSTNAME
];
468 * We need to get by the [] if they were entered
475 for (i
= 0; *cp
&& *cp
!= ']'; cp
++, i
++)
486 * First try to resolve it as an ip address and if that fails,
487 * do a fullblown (dns) lookup. That way we only use the dns
488 * when it is needed and work around some implementations that
489 * will return an "IPv4-mapped IPv6 address" address if you
490 * give it an IPv4 address to lookup.
492 strcpy(service
, "ntp");
493 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
494 hints
.ai_family
= ai_fam_templ
;
495 hints
.ai_protocol
= IPPROTO_UDP
;
496 hints
.ai_socktype
= SOCK_DGRAM
;
497 hints
.ai_flags
= AI_NUMERICHOST
;
499 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
500 if (a_info
== EAI_NONAME
502 || a_info
== EAI_NODATA
505 hints
.ai_flags
= AI_CANONNAME
;
507 hints
.ai_flags
|= AI_ADDRCONFIG
;
509 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
511 /* Some older implementations don't like AI_ADDRCONFIG. */
512 if (a_info
== EAI_BADFLAGS
) {
513 hints
.ai_flags
= AI_CANONNAME
;
514 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
517 (void) fprintf(stderr
, "%s\n", gai_strerror(a_info
));
524 * getaddrinfo() has returned without error so ai should not
527 NTP_INSIST(ai
!= NULL
);
529 if (ai
->ai_canonname
== NULL
) {
530 strncpy(temphost
, stoa((sockaddr_u
*)ai
->ai_addr
),
532 temphost
[LENHOSTNAME
-1] = '\0';
534 strncpy(temphost
, ai
->ai_canonname
, LENHOSTNAME
);
535 temphost
[LENHOSTNAME
-1] = '\0';
539 printf("Opening host %s\n", temphost
);
543 printf("Closing old host %s\n", currenthost
);
544 (void) closesocket(sockfd
);
547 (void) strcpy(currenthost
, temphost
);
549 /* port maps to the same in both families */
550 s_port
= ((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_port
;
552 ((struct sockaddr_in6
*)&hostaddr
)->sin6_port
= htons(SERVER_PORT_NUM
);
553 if (ai
->ai_family
== AF_INET
)
554 *(struct sockaddr_in
*)&hostaddr
=
555 *((struct sockaddr_in
*)ai
->ai_addr
);
557 *(struct sockaddr_in6
*)&hostaddr
=
558 *((struct sockaddr_in6
*)ai
->ai_addr
);
559 #endif /* SYS_VXWORKS */
563 int optionValue
= SO_SYNCHRONOUS_NONALERT
;
566 err
= setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&optionValue
, sizeof(optionValue
));
567 if (err
!= NO_ERROR
) {
568 (void) fprintf(stderr
, "cannot open nonoverlapped sockets\n");
573 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
574 if (sockfd
== INVALID_SOCKET
) {
575 error("socket", "", "");
579 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
581 error("socket", "", "");
582 #endif /* SYS_WINNT */
585 #ifdef NEED_RCVBUF_SLOP
588 int rbufsize
= INITDATASIZE
+ 2048; /* 2K for slop */
590 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
,
591 &rbufsize
, sizeof(int)) == -1)
592 error("setsockopt", "", "");
598 if (connect(sockfd
, (struct sockaddr
*)&hostaddr
,
599 sizeof(hostaddr
)) == -1)
601 if (connect(sockfd
, (struct sockaddr
*)ai
->ai_addr
,
602 ai
->ai_addrlen
) == -1)
603 #endif /* SYS_VXWORKS */
604 error("connect", "", "");
608 req_pkt_size
= REQ_LEN_NOMAC
;
609 impl_ver
= IMPL_XNTPD
;
614 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
616 * sendpkt - send a packet to the remote host
624 if (send(sockfd
, xdata
, xdatalen
, 0) == -1) {
625 warning("write to %s failed", currenthost
, "");
634 * growpktdata - grow the packet data area
639 pktdatasize
+= INCDATASIZE
;
640 pktdata
= erealloc(pktdata
, (size_t)pktdatasize
);
645 * getresponse - get a (series of) response packet(s) and return the data
657 struct resp_pkt rpkt
;
658 struct sock_timeval tvo
;
665 char haveseq
[MAXSEQ
+1];
675 * This is pretty tricky. We may get between 1 and many packets
676 * back in response to the request. We peel the data out of
677 * each packet and collect it in one long block. When the last
678 * packet in the sequence is received we'll know how many we
679 * should have had. Note we use one long time out, should reconsider.
685 *rdata
= datap
= pktdata
;
686 lastseq
= 999; /* too big to be a sequence number */
687 memset(haveseq
, 0, sizeof(haveseq
));
696 FD_SET(sockfd
, &fds
);
697 n
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvo
);
700 warning("select fails", "", "");
705 * Timed out. Return what we have
708 (void) fprintf(stderr
,
709 "%s: timed out, nothing received\n", currenthost
);
712 (void) fprintf(stderr
,
713 "%s: timed out with incomplete data\n",
716 printf("Received sequence numbers");
717 for (n
= 0; n
<= MAXSEQ
; n
++)
721 printf(" last frame received\n");
723 printf(" last frame not received\n");
725 return ERR_INCOMPLETE
;
729 n
= recv(sockfd
, (char *)&rpkt
, sizeof(rpkt
), 0);
731 warning("read", "", "");
737 * Check for format errors. Bug proofing.
739 if (n
< RESP_HEADER_SIZE
) {
741 printf("Short (%d byte) packet received\n", n
);
744 if (INFO_VERSION(rpkt
.rm_vn_mode
) > NTP_VERSION
||
745 INFO_VERSION(rpkt
.rm_vn_mode
) < NTP_OLDVERSION
) {
747 printf("Packet received with version %d\n",
748 INFO_VERSION(rpkt
.rm_vn_mode
));
751 if (INFO_MODE(rpkt
.rm_vn_mode
) != MODE_PRIVATE
) {
753 printf("Packet received with mode %d\n",
754 INFO_MODE(rpkt
.rm_vn_mode
));
757 if (INFO_IS_AUTH(rpkt
.auth_seq
)) {
759 printf("Encrypted packet received\n");
762 if (!ISRESPONSE(rpkt
.rm_vn_mode
)) {
764 printf("Received request packet, wanted response\n");
767 if (INFO_MBZ(rpkt
.mbz_itemsize
) != 0) {
769 printf("Received packet with nonzero MBZ field!\n");
774 * Check implementation/request. Could be old data getting to us.
776 if (rpkt
.implementation
!= implcode
|| rpkt
.request
!= reqcode
) {
779 "Received implementation/request of %d/%d, wanted %d/%d",
780 rpkt
.implementation
, rpkt
.request
,
786 * Check the error code. If non-zero, return it.
788 if (INFO_ERR(rpkt
.err_nitems
) != INFO_OKAY
) {
789 if (debug
&& ISMORE(rpkt
.rm_vn_mode
)) {
790 printf("Error code %d received on not-final packet\n",
791 INFO_ERR(rpkt
.err_nitems
));
793 return (int)INFO_ERR(rpkt
.err_nitems
);
797 * Collect items and size. Make sure they make sense.
799 items
= INFO_NITEMS(rpkt
.err_nitems
);
800 size
= INFO_ITEMSIZE(rpkt
.mbz_itemsize
);
805 datasize
= items
* size
;
806 if ((size_t)datasize
> (n
-RESP_HEADER_SIZE
)) {
809 "Received items %d, size %d (total %d), data in packet is %d\n",
810 items
, size
, datasize
, n
-RESP_HEADER_SIZE
);
815 * If this isn't our first packet, make sure the size matches
818 if (!firstpkt
&& esize
!= *rsize
) {
820 printf("Received itemsize %d, previous %d\n",
825 * If we've received this before, +toss it
827 seq
= INFO_SEQ(rpkt
.auth_seq
);
830 printf("Received duplicate sequence number %d\n", seq
);
836 * If this is the last in the sequence, record that.
838 if (!ISMORE(rpkt
.rm_vn_mode
)) {
839 if (lastseq
!= 999) {
840 printf("Received second end sequence packet\n");
847 * So far, so good. Copy this data into the output array.
849 if ((datap
+ datasize
+ (pad
* items
)) > (pktdata
+ pktdatasize
)) {
850 int offset
= datap
- pktdata
;
852 *rdata
= pktdata
; /* might have been realloced ! */
853 datap
= pktdata
+ offset
;
856 * We now move the pointer along according to size and number of
857 * items. This is so we can play nice with older implementations
860 tmp_data
= rpkt
.data
;
861 for (i
= 0; i
< items
; i
++) {
862 memcpy(datap
, tmp_data
, (unsigned)size
);
864 memset(datap
+ size
, 0, pad
);
875 * Finally, check the count of received packets. If we've got them
879 if (numrecv
<= lastseq
)
886 * sendrequest - format and send a request packet
888 * Historically, ntpdc has used a fixed-size request packet regardless
889 * of the actual payload size. When authenticating, the timestamp, key
890 * ID, and digest have been placed just before the end of the packet.
891 * With the introduction in late 2009 of support for authenticated
892 * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
893 * come up four bytes short.
895 * To maintain interop while allowing for larger digests, the behavior
896 * is unchanged when using 16-octet digests. For larger digests, the
897 * timestamp, key ID, and digest are placed immediately following the
898 * request payload, with the overall packet size variable. ntpd can
899 * distinguish 16-octet digests by the overall request size being
900 * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled. When using a
901 * longer digest, that request size should be avoided.
903 * With the form used with 20-octet and larger digests, the timestamp,
904 * key ID, and digest are located by ntpd relative to the start of the
905 * packet, and the size of the digest is then implied by the packet
925 char pass_prompt
[32];
928 memset(&qpkt
, 0, sizeof(qpkt
));
930 qpkt
.rm_vn_mode
= RM_VN_MODE(0, 0, 0);
931 qpkt
.implementation
= (u_char
)implcode
;
932 qpkt
.request
= (u_char
)reqcode
;
934 datasize
= qitems
* qsize
;
935 if (datasize
&& qdata
!= NULL
) {
936 memcpy(qpkt
.data
, qdata
, datasize
);
937 qpkt
.err_nitems
= ERR_NITEMS(0, qitems
);
938 qpkt
.mbz_itemsize
= MBZ_ITEMSIZE(qsize
);
940 qpkt
.err_nitems
= ERR_NITEMS(0, 0);
941 qpkt
.mbz_itemsize
= MBZ_ITEMSIZE(qsize
); /* allow for optional first item */
944 if (!auth
|| (keyid_entered
&& info_auth_keyid
== 0)) {
945 qpkt
.auth_seq
= AUTH_SEQ(0, 0);
946 return sendpkt(&qpkt
, req_pkt_size
);
949 if (info_auth_keyid
== 0) {
950 key_id
= getkeyid("Keyid: ");
952 fprintf(stderr
, "Invalid key identifier\n");
955 info_auth_keyid
= key_id
;
957 if (!authistrusted(info_auth_keyid
)) {
958 snprintf(pass_prompt
, sizeof(pass_prompt
),
960 keytype_name(info_auth_keytype
));
961 pass
= getpass(pass_prompt
);
962 if ('\0' == pass
[0]) {
963 fprintf(stderr
, "Invalid password\n");
966 authusekey(info_auth_keyid
, info_auth_keytype
,
968 authtrust(info_auth_keyid
, 1);
970 qpkt
.auth_seq
= AUTH_SEQ(1, 0);
971 if (info_auth_hashlen
> 16) {
973 * Only ntpd which expects REQ_LEN_NOMAC plus maclen
974 * octets in an authenticated request using a 16 octet
975 * digest (that is, a newer ntpd) will handle digests
976 * larger than 16 octets, so for longer digests, do
977 * not attempt to shorten the requests for downlevel
978 * ntpd compatibility.
980 if (REQ_LEN_NOMAC
!= req_pkt_size
)
982 reqsize
= REQ_LEN_HDR
+ datasize
+ sizeof(*ptstamp
);
983 /* align to 32 bits */
984 reqsize
= (reqsize
+ 3) & ~3;
986 reqsize
= req_pkt_size
;
987 ptstamp
= (void *)((char *)&qpkt
+ reqsize
);
990 L_ADD(&ts
, &delay_time
);
991 HTONL_FP(&ts
, ptstamp
);
992 maclen
= authencrypt(info_auth_keyid
, (void *)&qpkt
, reqsize
);
994 fprintf(stderr
, "Key not found\n");
996 } else if (maclen
!= (info_auth_hashlen
+ sizeof(keyid_t
))) {
998 "%d octet MAC, %u expected with %u octet digest\n",
999 maclen
, (info_auth_hashlen
+ sizeof(keyid_t
)),
1003 return sendpkt(&qpkt
, reqsize
+ maclen
);
1008 * doquery - send a request and process the response
1028 struct sock_timeval tvzero
;
1031 * Check to make sure host is open
1034 (void) fprintf(stderr
, "***No host open, use `host' command\n");
1039 * Poll the socket and clear out any pending data
1043 tvzero
.tv_sec
= tvzero
.tv_usec
= 0;
1045 FD_SET(sockfd
, &fds
);
1046 res
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvzero
);
1049 warning("polling select", "", "");
1053 (void) recv(sockfd
, junk
, sizeof junk
, 0);
1060 res
= sendrequest(implcode
, reqcode
, auth
, qitems
, qsize
, qdata
);
1065 * Get the response. If we got a standard error, print a message
1067 res
= getresponse(implcode
, reqcode
, ritems
, rsize
, rdata
, esize
);
1070 * Try to be compatible with older implementations of ntpd.
1072 if (res
== INFO_ERR_FMT
&& req_pkt_size
!= 48) {
1075 oldsize
= req_pkt_size
;
1077 switch(req_pkt_size
) {
1085 if (impl_ver
== IMPL_XNTPD
) {
1087 "***Warning changing to older implementation\n");
1088 return INFO_ERR_IMPL
;
1092 "***Warning changing the request packet size from %d to %d\n",
1093 oldsize
, req_pkt_size
);
1097 /* log error message if not told to be quiet */
1098 if ((res
> 0) && (((1 << res
) & quiet_mask
) == 0)) {
1101 /* Give us a chance to try the older implementation. */
1102 if (implcode
== IMPL_XNTPD
)
1104 (void) fprintf(stderr
,
1105 "***Server implementation incompatable with our own\n");
1108 (void) fprintf(stderr
,
1109 "***Server doesn't implement this request\n");
1112 (void) fprintf(stderr
,
1113 "***Server reports a format error in the received packet (shouldn't happen)\n");
1115 case INFO_ERR_NODATA
:
1116 (void) fprintf(stderr
,
1117 "***Server reports data not found\n");
1120 (void) fprintf(stderr
, "***Permission denied\n");
1123 (void) fprintf(stderr
, "***Request timed out\n");
1125 case ERR_INCOMPLETE
:
1126 (void) fprintf(stderr
,
1127 "***Response from server was incomplete\n");
1130 (void) fprintf(stderr
,
1131 "***Server returns unknown error code %d\n", res
);
1140 * getcmds - read commands from the standard input and execute them
1148 ntp_readline_init(interactive
? prompt
: NULL
);
1151 line
= ntp_readline(&count
);
1158 ntp_readline_uninit();
1162 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
1164 * abortcmd - catch interrupts and abort the current command
1172 if (current_output
== stdout
)
1173 (void) fflush(stdout
);
1175 (void) fflush(stderr
);
1176 if (jump
) longjmp(interrupt_buf
, 1);
1178 #endif /* SYS_WINNT */
1181 * docmd - decode the command line and execute a command
1188 char *tokens
[1+MAXARGS
+MOREARGS
+2];
1195 ai_fam_templ
= ai_fam_default
;
1197 * Tokenize the command line. If nothing on it, return.
1199 tokenize(cmdline
, tokens
, &ntok
);
1204 * Find the appropriate command description.
1206 i
= findcmd(tokens
[0], builtins
, opcmds
, &xcmd
);
1208 (void) fprintf(stderr
, "***Command `%s' unknown\n",
1211 } else if (i
>= 2) {
1212 (void) fprintf(stderr
, "***Command `%s' ambiguous\n",
1218 * Save the keyword, then walk through the arguments, interpreting
1221 pcmd
.keyword
= tokens
[0];
1224 for (i
= 0; i
< MAXARGS
&& xcmd
->arg
[i
] != NO
;) {
1225 if ((i
+ti
) >= ntok
) {
1226 if (!(xcmd
->arg
[i
] & OPT
)) {
1227 printusage(xcmd
, stderr
);
1232 if ((xcmd
->arg
[i
] & OPT
) && (*tokens
[i
+ti
] == '>'))
1234 rval
= getarg(tokens
[i
+ti
], (int)xcmd
->arg
[i
], &pcmd
.argval
[i
]);
1245 /* Any extra args are assumed to be "OPT|NTP_STR". */
1246 for ( ; i
< MAXARGS
+ MOREARGS
;) {
1249 rval
= getarg(tokens
[i
+ti
], (int)(OPT
|NTP_STR
), &pcmd
.argval
[i
]);
1261 if (i
< ntok
&& *tokens
[i
] == '>') {
1264 if (*(tokens
[i
]+1) != '\0')
1265 fname
= tokens
[i
]+1;
1266 else if ((i
+1) < ntok
)
1267 fname
= tokens
[i
+1];
1269 (void) fprintf(stderr
, "***No file for redirect\n");
1273 current_output
= fopen(fname
, "w");
1274 if (current_output
== NULL
) {
1275 (void) fprintf(stderr
, "***Error opening %s: ", fname
);
1280 current_output
= stdout
;
1283 if (interactive
&& setjmp(interrupt_buf
)) {
1287 (xcmd
->handler
)(&pcmd
, current_output
);
1289 if (current_output
!= stdout
)
1290 (void) fclose(current_output
);
1291 current_output
= NULL
;
1297 * tokenize - turn a command line into tokens
1306 register const char *cp
;
1308 static char tspace
[MAXLINE
];
1312 for (*ntok
= 0; *ntok
< MAXTOKENS
; (*ntok
)++) {
1314 while (ISSPACE(*cp
))
1320 } while (!ISSPACE(*cp
) && !ISEOL(*cp
));
1329 * findcmd - find a command in a command description table
1334 struct xcmd
*clist1
,
1335 struct xcmd
*clist2
,
1339 register struct xcmd
*cl
;
1342 struct xcmd
*nearmatch
= NULL
;
1349 else if (clist2
!= 0)
1355 for (cl
= clist
; cl
->keyword
!= 0; cl
++) {
1356 /* do a first character check, for efficiency */
1357 if (*str
!= *(cl
->keyword
))
1359 if (strncmp(str
, cl
->keyword
, (unsigned)clen
) == 0) {
1361 * Could be extact match, could be approximate.
1362 * Is exact if the length of the keyword is the
1365 if (*((cl
->keyword
) + clen
) == '\0') {
1375 * See if there is more to do. If so, go again. Sorry about the
1376 * goto, too much looking at BSD sources...
1378 if (clist
== clist1
&& clist2
!= 0) {
1384 * If we got extactly 1 near match, use it, else return number
1396 * getarg - interpret an argument token
1398 * string is always set.
1399 * type is set to the decoded type.
1401 * return: 0 - failure
1403 * -1 - skip to next token
1414 static const char *digits
= "0123456789";
1416 memset(argp
, 0, sizeof(*argp
));
1419 argp
->type
= code
& ~OPT
;
1421 switch (argp
->type
) {
1425 if (!strcmp("-6", str
)) {
1426 ai_fam_templ
= AF_INET6
;
1428 } else if (!strcmp("-4", str
)) {
1429 ai_fam_templ
= AF_INET
;
1432 if (!getnetnum(str
, &(argp
->netnum
), (char *)0, 0)) {
1447 cp
= strchr(digits
, *np
);
1449 (void) fprintf(stderr
,
1450 "***Illegal integer value %s\n", str
);
1454 argp
->uval
+= (cp
- digits
);
1455 } while (*(++np
) != '\0');
1458 if ((code
& ~OPT
) == NTP_UINT
) {
1459 (void) fprintf(stderr
,
1460 "***Value %s should be unsigned\n", str
);
1463 argp
->ival
= -argp
->ival
;
1467 if (!strcmp("-6", str
))
1469 else if (!strcmp("-4", str
))
1472 (void) fprintf(stderr
,
1473 "***Version must be either 4 or 6\n");
1484 * getnetnum - given a host name, return its net number
1485 * and (optional) full name
1496 struct addrinfo hints
, *ai
= NULL
;
1498 sockaddr_len
= SIZEOF_SOCKADDR(af
);
1499 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
1500 hints
.ai_flags
= AI_CANONNAME
;
1501 #ifdef AI_ADDRCONFIG
1502 hints
.ai_flags
|= AI_ADDRCONFIG
;
1505 /* decodenetnum only works with addresses */
1506 if (decodenetnum(hname
, num
)) {
1507 if (fullhost
!= 0) {
1508 getnameinfo(&num
->sa
, sockaddr_len
,
1509 fullhost
, sizeof(fullhost
), NULL
, 0,
1513 } else if (getaddrinfo(hname
, "ntp", &hints
, &ai
) == 0) {
1514 memmove((char *)num
, ai
->ai_addr
, ai
->ai_addrlen
);
1516 (void) strcpy(fullhost
, ai
->ai_canonname
);
1519 (void) fprintf(stderr
, "***Can't find host %s\n", hname
);
1526 * nntohost - convert network number to host name. This routine enforces
1527 * the showhostnames setting.
1535 return stoa(netnum
);
1537 if (ISREFCLOCKADR(netnum
))
1538 return refnumtoa(netnum
);
1539 return socktohost(netnum
);
1544 * Finally, the built in command handlers
1548 * help - tell about commands, or details of a particular command
1558 const char *list
[100];
1563 if (pcmd
->nargs
== 0) {
1565 for (xcp
= builtins
; xcp
->keyword
!= 0; xcp
++) {
1566 if (*(xcp
->keyword
) != '?')
1567 list
[words
++] = xcp
->keyword
;
1569 for (xcp
= opcmds
; xcp
->keyword
!= 0; xcp
++)
1570 list
[words
++] = xcp
->keyword
;
1573 #ifdef QSORT_USES_VOID_P
1578 (list
), (size_t)(words
), sizeof(char *), helpsort
);
1580 for (word
= 0; word
< words
; word
++) {
1581 int length
= strlen(list
[word
]);
1587 cols
= SCREENWIDTH
/ ++col
;
1588 rows
= (words
+ cols
- 1) / cols
;
1590 (void) fprintf(fp
, "ntpdc commands:\n");
1592 for (row
= 0; row
< rows
; row
++) {
1593 for (word
= row
; word
< words
; word
+= rows
) {
1594 (void) fprintf(fp
, "%-*.*s", col
, col
-1, list
[word
]);
1596 (void) fprintf(fp
, "\n");
1599 cmd
= pcmd
->argval
[0].string
;
1600 words
= findcmd(cmd
, builtins
, opcmds
, &xcp
);
1602 (void) fprintf(stderr
,
1603 "Command `%s' is unknown\n", cmd
);
1605 } else if (words
>= 2) {
1606 (void) fprintf(stderr
,
1607 "Command `%s' is ambiguous\n", cmd
);
1610 (void) fprintf(fp
, "function: %s\n", xcp
->comment
);
1611 printusage(xcp
, fp
);
1617 * helpsort - do hostname qsort comparisons
1619 #ifdef QSORT_USES_VOID_P
1626 char const * const * name1
= (char const * const *)t1
;
1627 char const * const * name2
= (char const * const *)t2
;
1629 return strcmp(*name1
, *name2
);
1638 return strcmp(*name1
, *name2
);
1644 * printusage - print usage information for a command
1655 (void) fprintf(fp
, "usage: %s", xcp
->keyword
);
1656 for (i
= 0; i
< MAXARGS
&& xcp
->arg
[i
] != NO
; i
++) {
1657 if (opt46
== 0 && (xcp
->arg
[i
] & ~OPT
) == NTP_ADD
) {
1658 (void) fprintf(fp
, " [ -4|-6 ]");
1661 if (xcp
->arg
[i
] & OPT
)
1662 (void) fprintf(fp
, " [ %s ]", xcp
->desc
[i
]);
1664 (void) fprintf(fp
, " %s", xcp
->desc
[i
]);
1666 (void) fprintf(fp
, "\n");
1671 * timeout - set time out time
1681 if (pcmd
->nargs
== 0) {
1682 val
= tvout
.tv_sec
* 1000 + tvout
.tv_usec
/ 1000;
1683 (void) fprintf(fp
, "primary timeout %d ms\n", val
);
1685 tvout
.tv_sec
= pcmd
->argval
[0].uval
/ 1000;
1686 tvout
.tv_usec
= (pcmd
->argval
[0].uval
- (tvout
.tv_sec
* 1000))
1693 * my_delay - set delay for auth requests
1704 if (pcmd
->nargs
== 0) {
1705 val
= delay_time
.l_ui
* 1000 + delay_time
.l_uf
/ 4294967;
1706 (void) fprintf(fp
, "delay %lu ms\n", val
);
1708 if (pcmd
->argval
[0].ival
< 0) {
1710 val
= (u_long
)(-pcmd
->argval
[0].ival
);
1713 val
= (u_long
)pcmd
->argval
[0].ival
;
1716 delay_time
.l_ui
= val
/ 1000;
1718 delay_time
.l_uf
= val
* 4294967; /* 2**32/1000 */
1727 * host - set the host we are dealing with.
1737 if (pcmd
->nargs
== 0) {
1739 (void) fprintf(fp
, "current host is %s\n", currenthost
);
1741 (void) fprintf(fp
, "no current host\n");
1746 if (pcmd
->nargs
== 2) {
1747 if (!strcmp("-4", pcmd
->argval
[i
].string
))
1748 ai_fam_templ
= AF_INET
;
1749 else if (!strcmp("-6", pcmd
->argval
[i
].string
))
1750 ai_fam_templ
= AF_INET6
;
1754 "current host remains %s\n", currenthost
);
1756 (void) fprintf(fp
, "still no current host\n");
1761 if (openhost(pcmd
->argval
[i
].string
)) {
1762 (void) fprintf(fp
, "current host set to %s\n", currenthost
);
1766 "current host remains %s\n", currenthost
);
1768 (void) fprintf(fp
, "still no current host\n");
1774 * keyid - get a keyid to use for authenticating requests
1782 if (pcmd
->nargs
== 0) {
1783 if (info_auth_keyid
== 0 && !keyid_entered
)
1784 (void) fprintf(fp
, "no keyid defined\n");
1785 else if (info_auth_keyid
== 0 && keyid_entered
)
1786 (void) fprintf(fp
, "no keyid will be sent\n");
1788 (void) fprintf(fp
, "keyid is %lu\n", (u_long
)info_auth_keyid
);
1790 info_auth_keyid
= pcmd
->argval
[0].uval
;
1797 * keytype - get type of key to use for authenticating requests
1805 const char * digest_name
;
1810 fprintf(fp
, "keytype is %s with %u octet digests\n",
1811 keytype_name(info_auth_keytype
),
1816 digest_name
= pcmd
->argval
[0].string
;
1818 key_type
= keytype_from_text(digest_name
, &digest_len
);
1821 fprintf(fp
, "keytype must be 'md5'%s\n",
1823 " or a digest type provided by OpenSSL");
1830 info_auth_keytype
= key_type
;
1831 info_auth_hashlen
= digest_len
;
1836 * passwd - get an authentication key
1847 if (info_auth_keyid
== 0) {
1848 info_auth_keyid
= getkeyid("Keyid: ");
1849 if (info_auth_keyid
== 0) {
1850 (void)fprintf(fp
, "Keyid must be defined\n");
1855 authusekey(info_auth_keyid
, info_auth_keytype
,
1856 (u_char
*)pcmd
->argval
[0].string
);
1857 authtrust(info_auth_keyid
, 1);
1859 pass
= getpass("MD5 Password: ");
1861 (void) fprintf(fp
, "Password unchanged\n");
1863 authusekey(info_auth_keyid
, info_auth_keytype
,
1865 authtrust(info_auth_keyid
, 1);
1872 * hostnames - set the showhostnames flag
1880 if (pcmd
->nargs
== 0) {
1882 (void) fprintf(fp
, "hostnames being shown\n");
1884 (void) fprintf(fp
, "hostnames not being shown\n");
1886 if (STREQ(pcmd
->argval
[0].string
, "yes"))
1888 else if (STREQ(pcmd
->argval
[0].string
, "no"))
1891 (void)fprintf(stderr
, "What?\n");
1897 * setdebug - set/change debugging level
1905 if (pcmd
->nargs
== 0) {
1906 (void) fprintf(fp
, "debug level is %d\n", debug
);
1908 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
1910 } else if (STREQ(pcmd
->argval
[0].string
, "more")) {
1912 } else if (STREQ(pcmd
->argval
[0].string
, "less")) {
1915 (void) fprintf(fp
, "What?\n");
1918 (void) fprintf(fp
, "debug level set to %d\n", debug
);
1923 * quit - stop this nonsense
1933 closesocket(sockfd
);
1939 * version - print the current version number
1949 (void) fprintf(fp
, "%s\n", Version
);
1955 * warning - print a warning message
1964 (void) fprintf(stderr
, "%s: ", progname
);
1965 (void) fprintf(stderr
, fmt
, st1
, st2
);
1966 (void) fprintf(stderr
, ": ");
1972 * error - print a message and exit
1981 warning(fmt
, st1
, st2
);
1986 * getkeyid - prompt the user for a keyid to use
1990 const char *keyprompt
1999 if ((fi
= fdopen(open("/dev/tty", 2), "r")) == NULL
)
2001 if ((fi
= _fdopen(open("CONIN$", _O_TEXT
), "r")) == NULL
)
2002 #endif /* SYS_WINNT */
2005 setbuf(fi
, (char *)NULL
);
2006 fprintf(stderr
, "%s", keyprompt
); fflush(stderr
);
2007 for (p
=pbuf
; (c
= getc(fi
))!='\n' && c
!=EOF
;) {
2014 return (u_int32
)atoi(pbuf
);