2 * ntpq - query an NTP server using mode 6 commands
21 #include <isc/result.h>
24 #include "ntp_stdlib.h"
25 #include "ntp_unixtime.h"
26 #include "ntp_calendar.h"
27 #include "ntp_select.h"
28 #include "ntp_assert.h"
29 #include "lib_strbuf.h"
30 #include "ntp_lineedit.h"
31 #include "ntp_debug.h"
33 #include "openssl/evp.h"
34 #include "openssl/objects.h"
36 #include <ssl_applink.c>
38 #include "ntp_libopts.h"
39 #include "ntpq-opts.h"
42 #ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/
43 # define open(name, flags) open(name, flags, 0777)
44 # define SERVER_PORT_NUM 123
47 /* we use COMMAND as an autogen keyword */
53 * Because we potentially understand a lot of commands we will run
54 * interactive if connected to a terminal.
56 int interactive = 0; /* set to 1 when we should prompt */
57 const char *prompt = "ntpq> "; /* prompt to ask him about */
60 * use old readvars behavior? --old-rv processing in ntpq resets
61 * this value based on the presence or absence of --old-rv. It is
62 * initialized to 1 here to maintain backward compatibility with
63 * libntpq clients such as ntpsnmpd, which are free to reset it as
72 s_char sys_precision; /* local clock precision (log2 s) */
75 * Keyid used for authenticated requests. Obtained on the fly.
77 u_long info_auth_keyid = 0;
79 static int info_auth_keytype = NID_md5; /* MD5 */
80 static size_t info_auth_hashlen = 16; /* MD5 */
81 u_long current_time; /* needed by authkeys; not used */
84 * Flag which indicates we should always send authenticated requests
89 * Flag which indicates raw mode output.
94 * Packet version number we use
96 u_char pktversion = NTP_OLDVERSION + 1;
99 * Don't jump if no set jmp.
101 volatile int jump = 0;
107 #define HA 1 /* host address */
108 #define NA 2 /* network address */
109 #define LP 3 /* leap (print in binary) */
110 #define RF 4 /* refid (sometimes string, sometimes not) */
111 #define AR 5 /* array of times */
112 #define FX 6 /* test flags */
113 #define TS 7 /* l_fp timestamp in hex */
114 #define OC 8 /* integer, print in octal */
115 #define EOV 255 /* end of table */
118 * For the most part ntpq simply displays what ntpd provides in the
119 * mostly plain-text mode 6 responses. A few variable names are by
120 * default "cooked" to provide more human-friendly output.
122 const var_format cookedvars[] = {
133 { "peeradr", HA }, /* compat with others */
136 { "filtoffset", AR },
138 { "filterror", AR }, /* compat with others */
146 static const char *tstflagnames[] = {
147 "pkt_dup", /* TEST1 */
148 "pkt_bogus", /* TEST2 */
149 "pkt_unsync", /* TEST3 */
150 "pkt_denied", /* TEST4 */
151 "pkt_auth", /* TEST5 */
152 "pkt_stratum", /* TEST6 */
153 "pkt_header", /* TEST7 */
154 "pkt_autokey", /* TEST8 */
155 "pkt_crypto", /* TEST9 */
156 "peer_stratum", /* TEST10 */
157 "peer_dist", /* TEST11 */
158 "peer_loop", /* TEST12 */
159 "peer_unreach" /* TEST13 */
163 int ntpqmain (int, char **);
165 * Built in command handler declarations
167 static int openhost (const char *, int);
168 static void dump_hex_printable(const void *, size_t);
169 static int sendpkt (void *, size_t);
170 static int getresponse (int, int, u_short *, int *, const char **, int);
171 static int sendrequest (int, associd_t, int, int, const char *);
172 static char * tstflags (u_long);
174 static void getcmds (void);
176 static RETSIGTYPE abortcmd (int);
177 #endif /* SYS_WINNT */
178 static void docmd (const char *);
179 static void tokenize (const char *, char **, int *);
180 static int getarg (const char *, int, arg_v *);
181 #endif /* BUILD_AS_LIB */
182 static int findcmd (const char *, struct xcmd *,
183 struct xcmd *, struct xcmd **);
184 static int rtdatetolfp (char *, l_fp *);
185 static int decodearr (char *, int *, l_fp *);
186 static void help (struct parse *, FILE *);
187 static int helpsort (const void *, const void *);
188 static void printusage (struct xcmd *, FILE *);
189 static void timeout (struct parse *, FILE *);
190 static void auth_delay (struct parse *, FILE *);
191 static void host (struct parse *, FILE *);
192 static void ntp_poll (struct parse *, FILE *);
193 static void keyid (struct parse *, FILE *);
194 static void keytype (struct parse *, FILE *);
195 static void passwd (struct parse *, FILE *);
196 static void hostnames (struct parse *, FILE *);
197 static void setdebug (struct parse *, FILE *);
198 static void quit (struct parse *, FILE *);
199 static void version (struct parse *, FILE *);
200 static void raw (struct parse *, FILE *);
201 static void cooked (struct parse *, FILE *);
202 static void authenticate (struct parse *, FILE *);
203 static void ntpversion (struct parse *, FILE *);
204 static void warning (const char *, ...)
205 __attribute__((__format__(__printf__, 1, 2)));
206 static void error (const char *, ...)
207 __attribute__((__format__(__printf__, 1, 2)));
208 static u_long getkeyid (const char *);
209 static void atoascii (const char *, size_t, char *, size_t);
210 static void cookedprint (int, int, const char *, int, int, FILE *);
211 static void rawprint (int, int, const char *, int, int, FILE *);
212 static void startoutput (void);
213 static void output (FILE *, const char *, const char *);
214 static void endoutput (FILE *);
215 static void outputarr (FILE *, char *, int, l_fp *);
216 static int assoccmp (const void *, const void *);
217 u_short varfmt (const char *);
219 void ntpq_custom_opt_handler (tOptions *, tOptDesc *);
223 * Built-in commands we understand
225 struct xcmd builtins[] = {
226 { "?", help, { OPT|NTP_STR, NO, NO, NO },
227 { "command", "", "", "" },
228 "tell the use and syntax of commands" },
229 { "help", help, { OPT|NTP_STR, NO, NO, NO },
230 { "command", "", "", "" },
231 "tell the use and syntax of commands" },
232 { "timeout", timeout, { OPT|NTP_UINT, NO, NO, NO },
233 { "msec", "", "", "" },
234 "set the primary receive time out" },
235 { "delay", auth_delay, { OPT|NTP_INT, NO, NO, NO },
236 { "msec", "", "", "" },
237 "set the delay added to encryption time stamps" },
238 { "host", host, { OPT|NTP_STR, OPT|NTP_STR, NO, NO },
239 { "-4|-6", "hostname", "", "" },
240 "specify the host whose NTP server we talk to" },
241 { "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
242 { "n", "verbose", "", "" },
243 "poll an NTP server in client mode `n' times" },
244 { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO },
246 "specify a password to use for authenticated requests"},
247 { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO },
248 { "yes|no", "", "", "" },
249 "specify whether hostnames or net numbers are printed"},
250 { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO },
251 { "no|more|less", "", "", "" },
252 "set/change debugging level" },
253 { "quit", quit, { NO, NO, NO, NO },
256 { "exit", quit, { NO, NO, NO, NO },
259 { "keyid", keyid, { OPT|NTP_UINT, NO, NO, NO },
260 { "key#", "", "", "" },
261 "set keyid to use for authenticated requests" },
262 { "version", version, { NO, NO, NO, NO },
264 "print version number" },
265 { "raw", raw, { NO, NO, NO, NO },
267 "do raw mode variable output" },
268 { "cooked", cooked, { NO, NO, NO, NO },
270 "do cooked mode variable output" },
271 { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO },
272 { "yes|no", "", "", "" },
273 "always authenticate requests to this server" },
274 { "ntpversion", ntpversion, { OPT|NTP_UINT, NO, NO, NO },
275 { "version number", "", "", "" },
276 "set the NTP version number to use for requests" },
277 { "keytype", keytype, { OPT|NTP_STR, NO, NO, NO },
278 { "key type (md5|des)", "", "", "" },
279 "set key type to use for authenticated requests (des|md5)" },
280 { 0, 0, { NO, NO, NO, NO },
281 { "", "", "", "" }, "" }
286 * Default values we use.
288 #define DEFHOST "localhost" /* default host name */
289 #define DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */
290 #define DEFSTIMEOUT 3 /* and 3 more for each additional */
292 * Requests are automatically retried once, so total timeout with no
293 * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other
294 * extreme, a request eliciting 32 packets of responses each for some
295 * reason nearly DEFSTIMEOUT seconds after the prior in that series,
296 * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
297 * 93 seconds to fail each of two times, or 186 seconds.
298 * Some commands involve a series of requests, such as "peers" and
299 * "mrulist", so the cumulative timeouts are even longer for those.
301 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
302 #define LENHOSTNAME 256 /* host name is 256 characters long */
303 #define MAXCMDS 100 /* maximum commands on cmd line */
304 #define MAXHOSTS 200 /* maximum hosts on cmd line */
305 #define MAXLINE 512 /* maximum line length */
306 #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
307 #define MAXVARLEN 256 /* maximum length of a variable name */
308 #define MAXVALLEN 2048 /* maximum length of a variable value */
309 #define MAXOUTLINE 72 /* maximum length of an output line */
310 #define SCREENWIDTH 76 /* nominal screen width in columns */
313 * Some variables used and manipulated locally
315 struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
316 struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
317 l_fp delay_time; /* delay time */
318 char currenthost[LENHOSTNAME]; /* current host name */
319 int currenthostisnum; /* is prior text from IP? */
320 struct sockaddr_in hostaddr; /* host address */
321 int showhostnames = 1; /* show host names by default */
322 int wideremote = 0; /* show wide remote names? */
324 int ai_fam_templ; /* address family */
325 int ai_fam_default; /* default address family */
326 SOCKET sockfd; /* fd socket is opened on */
327 int havehost = 0; /* set to 1 when host open */
329 struct servent *server_entry = NULL; /* server entry for ntp */
333 * Sequence number used for requests. It is incremented before
339 * Holds data returned from queries. Declare buffer long to be sure of
342 #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
343 long pktdata[DATASIZE/sizeof(long)];
346 * assoc_cache[] is a dynamic array which allows references to
347 * associations using &1 ... &N for n associations, avoiding manual
348 * lookup of the current association IDs for a given ntpd. It also
349 * caches the status word for each association, retrieved incidentally.
351 struct association * assoc_cache;
352 u_int assoc_cache_slots;/* count of allocated array entries */
353 u_int numassoc; /* number of cached associations */
356 * For commands typed on the command line (with the -c option)
359 const char *ccmds[MAXCMDS];
360 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
363 * When multiple hosts are specified.
368 chost chosts[MAXHOSTS];
369 #define ADDHOST(cp) \
371 if (numhosts < MAXHOSTS) { \
372 chosts[numhosts].name = (cp); \
373 chosts[numhosts].fam = ai_fam_templ; \
379 * Macro definitions we use
381 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
382 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
383 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
386 * Jump buffer for longjumping back to the command level
388 jmp_buf interrupt_buf;
391 * Points at file being currently printed into
393 FILE *current_output;
396 * Command table imported from ntpdc_ops.c
398 extern struct xcmd opcmds[];
402 #ifdef NO_MAIN_ALLOWED
404 CALL(ntpq,"ntpq",ntpqmain);
406 void clear_globals(void)
408 extern int ntp_optind;
409 showhostnames = 0; /* don'tshow host names by default */
411 server_entry = NULL; /* server entry for ntp */
412 havehost = 0; /* set to 1 when host open */
413 numassoc = 0; /* number of cached associations */
417 #endif /* !BUILD_AS_LIB */
418 #endif /* NO_MAIN_ALLOWED */
421 * main - parse arguments and handle options
423 #ifndef NO_MAIN_ALLOWED
430 return ntpqmain(argc, argv);
447 taskPrioritySet(taskIdSelf(), 100 );
451 delay_time.l_uf = DEFDELAY;
453 init_lib(); /* sets up ipv4_works, ipv6_works */
457 /* Check to see if we have IPv6. Otherwise default to IPv4 */
459 ai_fam_default = AF_INET;
464 int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
470 * Process options other than -c and -p, which are specially
471 * handled by ntpq_custom_opt_handler().
474 debug = OPT_VALUE_SET_DEBUG_LEVEL;
477 ai_fam_templ = AF_INET;
478 else if (HAVE_OPT(IPV6))
479 ai_fam_templ = AF_INET6;
481 ai_fam_templ = ai_fam_default;
483 if (HAVE_OPT(INTERACTIVE))
486 if (HAVE_OPT(NUMERIC))
492 old_rv = HAVE_OPT(OLD_RV);
497 for (ihost = 0; ihost < (u_int)argc; ihost++) {
498 if ('-' == *argv[ihost]) {
500 // If I really cared I'd also check:
501 // 0 == argv[ihost][2]
503 // and there are other cases as well...
505 if ('4' == argv[ihost][1]) {
506 ai_fam_templ = AF_INET;
508 } else if ('6' == argv[ihost][1]) {
509 ai_fam_templ = AF_INET6;
512 // XXX Throw a usage error
515 ADDHOST(argv[ihost]);
519 if (numcmds == 0 && interactive == 0
520 && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
524 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
526 (void) signal_no_reset(SIGINT, abortcmd);
527 #endif /* SYS_WINNT */
530 (void) openhost(chosts[0].name, chosts[0].fam);
533 for (ihost = 0; ihost < numhosts; ihost++) {
534 if (openhost(chosts[ihost].name, chosts[ihost].fam))
535 for (icmd = 0; icmd < numcmds; icmd++)
541 #endif /* SYS_WINNT */
544 #endif /* !BUILD_AS_LIB */
547 * openhost - open a socket to a host
555 const char svc[] = "ntp";
556 char temphost[LENHOSTNAME];
558 struct addrinfo hints, *ai;
561 register const char *cp;
562 char name[LENHOSTNAME];
565 * We need to get by the [] if they were entered
572 for (i = 0; *cp && *cp != ']'; cp++, i++)
583 * First try to resolve it as an ip address and if that fails,
584 * do a fullblown (dns) lookup. That way we only use the dns
585 * when it is needed and work around some implementations that
586 * will return an "IPv4-mapped IPv6 address" address if you
587 * give it an IPv4 address to lookup.
590 hints.ai_family = fam;
591 hints.ai_protocol = IPPROTO_UDP;
592 hints.ai_socktype = SOCK_DGRAM;
593 hints.ai_flags = Z_AI_NUMERICHOST;
596 a_info = getaddrinfo(hname, svc, &hints, &ai);
597 if (a_info == EAI_NONAME
599 || a_info == EAI_NODATA
602 hints.ai_flags = AI_CANONNAME;
604 hints.ai_flags |= AI_ADDRCONFIG;
606 a_info = getaddrinfo(hname, svc, &hints, &ai);
609 /* Some older implementations don't like AI_ADDRCONFIG. */
610 if (a_info == EAI_BADFLAGS) {
611 hints.ai_flags &= ~AI_ADDRCONFIG;
612 a_info = getaddrinfo(hname, svc, &hints, &ai);
616 fprintf(stderr, "%s\n", gai_strerror(a_info));
622 octets = min(sizeof(addr), ai->ai_addrlen);
623 memcpy(&addr, ai->ai_addr, octets);
625 if (ai->ai_canonname == NULL) {
626 strlcpy(temphost, stoa(&addr), sizeof(temphost));
627 currenthostisnum = TRUE;
629 strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
630 currenthostisnum = FALSE;
634 printf("Opening host %s (%s)\n",
636 (ai->ai_family == AF_INET)
638 : (ai->ai_family == AF_INET6)
645 printf("Closing old host %s\n", currenthost);
649 strlcpy(currenthost, temphost, sizeof(currenthost));
651 /* port maps to the same location in both families */
652 s_port = NSRCPORT(&addr);
654 ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
655 if (ai->ai_family == AF_INET)
656 *(struct sockaddr_in *)&hostaddr=
657 *((struct sockaddr_in *)ai->ai_addr);
659 *(struct sockaddr_in6 *)&hostaddr=
660 *((struct sockaddr_in6 *)ai->ai_addr);
661 #endif /* SYS_VXWORKS */
665 int optionValue = SO_SYNCHRONOUS_NONALERT;
668 err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
669 (char *)&optionValue, sizeof(optionValue));
672 "setsockopt(SO_SYNCHRONOUS_NONALERT)"
678 #endif /* SYS_WINNT */
680 sockfd = socket(ai->ai_family, ai->ai_socktype,
682 if (sockfd == INVALID_SOCKET) {
689 #ifdef NEED_RCVBUF_SLOP
691 { int rbufsize = DATASIZE + 2048; /* 2K for slop */
692 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
693 &rbufsize, sizeof(int)) == -1)
701 (connect(sockfd, (struct sockaddr *)&hostaddr,
702 sizeof(hostaddr)) == -1)
704 (connect(sockfd, (struct sockaddr *)ai->ai_addr,
705 ai->ai_addrlen) == -1)
706 #endif /* SYS_VXWORKS */
727 const char * rowstart;
735 rowlen = min(16, len);
736 for (idx = 0; idx < rowlen; idx++) {
738 printf("%02x ", uch);
740 for ( ; idx < 16 ; idx++)
743 for (idx = 0; idx < rowlen; idx++) {
745 printf("%c", (isprint(uch))
755 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
757 * sendpkt - send a packet to the remote host
766 printf("Sending %zu octets\n", xdatalen);
768 if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
769 warning("write to %s failed", currenthost);
774 printf("Request packet:\n");
775 dump_hex_printable(xdata, xdatalen);
781 * getresponse - get a (series of) response packet(s) and return the data
793 struct ntp_control rpkt;
794 struct sock_timeval tvo;
795 u_short offsets[MAXFRAGS+1];
796 u_short counts[MAXFRAGS+1];
809 * This is pretty tricky. We may get between 1 and MAXFRAG packets
810 * back in response to the request. We peel the data out of
811 * each packet and collect it in one long block. When the last
812 * packet in the sequence is received we'll know how much data we
813 * should have had. Note we use one long time out, should reconsider.
818 *rdata = (char *)pktdata;
826 * Loop until we have an error or a complete response. Nearly all
827 * code paths to loop again use continue.
836 FD_SET(sockfd, &fds);
837 n = select(sockfd + 1, &fds, NULL, NULL, &tvo);
840 warning("select fails");
845 * Timed out. Return what we have
850 "%s: timed out, nothing received\n",
856 "%s: timed out with incomplete data\n",
860 "ERR_INCOMPLETE: Received fragments:\n");
861 for (f = 0; f < numfrags; f++)
863 "%2u: %5d %5d\t%3d octets\n",
864 (u_int)f, offsets[f],
869 "last fragment %sreceived\n",
874 return ERR_INCOMPLETE;
877 n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
884 printf("Response packet:\n");
885 dump_hex_printable(&rpkt, n);
889 * Check for format errors. Bug proofing.
891 if (n < (int)CTL_HEADER_LEN) {
893 printf("Short (%d byte) packet received\n", n);
896 if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
897 || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
899 printf("Packet received with version %d\n",
900 PKT_VERSION(rpkt.li_vn_mode));
903 if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
905 printf("Packet received with mode %d\n",
906 PKT_MODE(rpkt.li_vn_mode));
909 if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
911 printf("Received request packet, wanted response\n");
916 * Check opcode and sequence number for a match.
917 * Could be old data getting to us.
919 if (ntohs(rpkt.sequence) != sequence) {
921 printf("Received sequnce number %d, wanted %d\n",
922 ntohs(rpkt.sequence), sequence);
925 if (CTL_OP(rpkt.r_m_e_op) != opcode) {
928 "Received opcode %d, wanted %d (sequence number okay)\n",
929 CTL_OP(rpkt.r_m_e_op), opcode);
934 * Check the error code. If non-zero, return it.
936 if (CTL_ISERROR(rpkt.r_m_e_op)) {
937 errcode = (ntohs(rpkt.status) >> 8) & 0xff;
938 if (CTL_ISMORE(rpkt.r_m_e_op))
939 TRACE(1, ("Error code %d received on not-final packet\n",
941 if (errcode == CERR_UNSPEC)
947 * Check the association ID to make sure it matches what
950 if (ntohs(rpkt.associd) != associd) {
951 TRACE(1, ("Association ID %d doesn't match expected %d\n",
952 ntohs(rpkt.associd), associd));
954 * Hack for silly fuzzballs which, at the time of writing,
955 * return an assID of sys.peer when queried for system variables.
963 * Collect offset and count. Make sure they make sense.
965 offset = ntohs(rpkt.offset);
966 count = ntohs(rpkt.count);
969 * validate received payload size is padded to next 32-bit
970 * boundary and no smaller than claimed by rpkt.count
973 TRACE(1, ("Response packet not padded, size = %d\n",
978 shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
980 if (n < shouldbesize) {
981 printf("Response packet claims %u octets payload, above %ld received\n",
982 count, (long)n - CTL_HEADER_LEN);
983 return ERR_INCOMPLETE;
986 if (debug >= 3 && shouldbesize > n) {
992 * Usually we ignore authentication, but for debugging purposes
995 /* round to 8 octet boundary */
996 shouldbesize = (shouldbesize + 7) & ~7;
998 maclen = n - shouldbesize;
999 if (maclen >= (int)MIN_MAC_LEN) {
1001 "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1002 n, shouldbesize, maclen);
1003 lpkt = (u_int32 *)&rpkt;
1004 printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1005 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
1006 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
1007 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
1008 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
1009 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
1010 (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
1011 key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
1012 printf("Authenticated with keyid %lu\n", (u_long)key);
1013 if (key != 0 && key != info_auth_keyid) {
1014 printf("We don't know that key\n");
1016 if (authdecrypt(key, (u_int32 *)&rpkt,
1017 n - maclen, maclen)) {
1018 printf("Auth okay!\n");
1020 printf("Auth failed!\n");
1026 TRACE(2, ("Got packet, size = %d\n", n));
1027 if (count > (n - CTL_HEADER_LEN)) {
1028 TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
1029 count, (long)n - CTL_HEADER_LEN));
1032 if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
1033 TRACE(1, ("Received count of 0 in non-final fragment\n"));
1036 if (offset + count > sizeof(pktdata)) {
1037 TRACE(1, ("Offset %u, count %u, too big for buffer\n",
1041 if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
1042 TRACE(1, ("Received second last fragment packet\n"));
1047 * So far, so good. Record this fragment, making sure it doesn't
1050 TRACE(2, ("Packet okay\n"));
1052 if (numfrags > (MAXFRAGS - 1)) {
1053 TRACE(2, ("Number of fragments exceeds maximum %d\n",
1059 * Find the position for the fragment relative to any
1060 * previously received.
1063 f < numfrags && offsets[f] < offset;
1068 if (f < numfrags && offset == offsets[f]) {
1069 TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
1070 count, offset, counts[f], offsets[f]));
1074 if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
1075 TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
1076 offset, counts[f-1], offsets[f-1]));
1080 if (f < numfrags && (offset + count) > offsets[f]) {
1081 TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
1082 count, offset, offsets[f]));
1086 for (ff = numfrags; ff > f; ff--) {
1087 offsets[ff] = offsets[ff-1];
1088 counts[ff] = counts[ff-1];
1090 offsets[f] = offset;
1095 * Got that stuffed in right. Figure out if this was the last.
1096 * Record status info out of the last packet.
1098 if (!CTL_ISMORE(rpkt.r_m_e_op)) {
1101 *rstatus = ntohs(rpkt.status);
1105 * Copy the data into the data buffer.
1107 memcpy((char *)pktdata + offset, &rpkt.u, count);
1110 * If we've seen the last fragment, look for holes in the sequence.
1111 * If there aren't any, we're done.
1113 if (seenlastfrag && offsets[0] == 0) {
1114 for (f = 1; f < numfrags; f++)
1115 if (offsets[f-1] + counts[f-1] !=
1118 if (f == numfrags) {
1119 *rsize = offsets[f-1] + counts[f-1];
1120 TRACE(1, ("%lu packets reassembled into response\n",
1125 } /* giant for (;;) collecting response packets */
1126 } /* getresponse() */
1130 * sendrequest - format and send a request packet
1141 struct ntp_control qpkt;
1148 * Check to make sure the data will fit in one packet
1150 if (qsize > CTL_MAX_DATA_LEN) {
1152 "***Internal error! qsize (%d) too large\n",
1158 * Fill in the packet
1160 qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
1161 qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
1162 qpkt.sequence = htons(sequence);
1164 qpkt.associd = htons((u_short)associd);
1166 qpkt.count = htons((u_short)qsize);
1168 pktsize = CTL_HEADER_LEN;
1171 * If we have data, copy and pad it out to a 32-bit boundary.
1174 memcpy(&qpkt.u, qdata, (size_t)qsize);
1176 while (pktsize & (sizeof(u_int32) - 1)) {
1177 qpkt.u.data[qsize++] = 0;
1183 * If it isn't authenticated we can just send it. Otherwise
1184 * we're going to have to think about it a little.
1186 if (!auth && !always_auth) {
1187 return sendpkt(&qpkt, pktsize);
1191 * Pad out packet to a multiple of 8 octets to be sure
1192 * receiver can handle it.
1194 while (pktsize & 7) {
1195 qpkt.u.data[qsize++] = 0;
1200 * Get the keyid and the password if we don't have one.
1202 if (info_auth_keyid == 0) {
1203 key_id = getkeyid("Keyid: ");
1204 if (key_id == 0 || key_id > NTP_MAXKEY) {
1206 "Invalid key identifier\n");
1209 info_auth_keyid = key_id;
1211 if (!authistrusted(info_auth_keyid)) {
1212 pass = getpass_keytype(info_auth_keytype);
1213 if ('\0' == pass[0]) {
1214 fprintf(stderr, "Invalid password\n");
1217 authusekey(info_auth_keyid, info_auth_keytype,
1219 authtrust(info_auth_keyid, 1);
1223 * Do the encryption.
1225 maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
1227 fprintf(stderr, "Key not found\n");
1229 } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
1231 "%d octet MAC, %zu expected with %zu octet digest\n",
1232 maclen, (info_auth_hashlen + sizeof(keyid_t)),
1237 return sendpkt((char *)&qpkt, pktsize + maclen);
1242 * show_error_msg - display the error text for a mode 6 error response.
1251 fprintf(stderr, "server=%s ", currenthost);
1257 "***Server reports a bad format request packet\n");
1260 case CERR_PERMISSION:
1262 "***Server disallowed request (authentication?)\n");
1267 "***Server reports a bad opcode in request\n");
1272 "***Association ID %d unknown to server\n",
1276 case CERR_UNKNOWNVAR:
1278 "***A request variable unknown to the server\n");
1283 "***Server indicates a request variable was bad\n");
1288 "***Server returned an unspecified error\n");
1292 fprintf(stderr, "***Request timed out\n");
1295 case ERR_INCOMPLETE:
1297 "***Response from server was incomplete\n");
1302 "***Buffer size exceeded for returned data\n");
1307 "***Server returns unknown error code %d\n",
1313 * doquery - send a request and process the response, displaying
1314 * error messages for any error responses.
1328 return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
1329 rsize, rdata, FALSE);
1334 * doqueryex - send a request and process the response, optionally
1335 * displaying error messages for any error responses.
1354 * Check to make sure host is open
1357 fprintf(stderr, "***No host open, use `host' command\n");
1368 res = sendrequest(opcode, associd, auth, qsize, qdata);
1373 * Get the response. If we got a standard error, print a message
1375 res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
1378 if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
1379 if (res == ERR_INCOMPLETE) {
1381 * better bump the sequence so we don't
1382 * get confused about differing fragments.
1390 show_error_msg(res, associd);
1397 #ifndef BUILD_AS_LIB
1399 * getcmds - read commands from the standard input and execute them
1407 ntp_readline_init(interactive ? prompt : NULL);
1410 line = ntp_readline(&count);
1417 ntp_readline_uninit();
1419 #endif /* !BUILD_AS_LIB */
1422 #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1424 * abortcmd - catch interrupts and abort the current command
1431 if (current_output == stdout)
1432 (void) fflush(stdout);
1434 (void) fflush(stderr);
1435 if (jump) longjmp(interrupt_buf, 1);
1437 #endif /* !SYS_WINNT && !BUILD_AS_LIB */
1440 #ifndef BUILD_AS_LIB
1442 * docmd - decode the command line and execute a command
1449 char *tokens[1+MAXARGS+2];
1456 * Tokenize the command line. If nothing on it, return.
1458 tokenize(cmdline, tokens, &ntok);
1463 * Find the appropriate command description.
1465 i = findcmd(tokens[0], builtins, opcmds, &xcmd);
1467 (void) fprintf(stderr, "***Command `%s' unknown\n",
1470 } else if (i >= 2) {
1471 (void) fprintf(stderr, "***Command `%s' ambiguous\n",
1476 /* Warn about ignored extra args */
1477 for (i = MAXARGS + 1; i < ntok ; ++i) {
1478 fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
1482 * Save the keyword, then walk through the arguments, interpreting
1485 pcmd.keyword = tokens[0];
1487 for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
1488 if ((i+1) >= ntok) {
1489 if (!(xcmd->arg[i] & OPT)) {
1490 printusage(xcmd, stderr);
1495 if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
1497 if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
1503 if (i < ntok && *tokens[i] == '>') {
1506 if (*(tokens[i]+1) != '\0')
1507 fname = tokens[i]+1;
1508 else if ((i+1) < ntok)
1509 fname = tokens[i+1];
1511 (void) fprintf(stderr, "***No file for redirect\n");
1515 current_output = fopen(fname, "w");
1516 if (current_output == NULL) {
1517 (void) fprintf(stderr, "***Error opening %s: ", fname);
1521 i = 1; /* flag we need a close */
1523 current_output = stdout;
1524 i = 0; /* flag no close */
1527 if (interactive && setjmp(interrupt_buf)) {
1532 (xcmd->handler)(&pcmd, current_output);
1533 jump = 0; /* HMS: 961106: was after fclose() */
1534 if (i) (void) fclose(current_output);
1542 * tokenize - turn a command line into tokens
1544 * SK: Modified to allow a quoted string
1546 * HMS: If the first character of the first token is a ':' then (after
1547 * eating inter-token whitespace) the 2nd token is the rest of the line.
1557 register const char *cp;
1559 static char tspace[MAXLINE];
1563 for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
1566 /* Skip inter-token whitespace */
1567 while (ISSPACE(*cp))
1570 /* If we're at EOL we're done */
1574 /* If this is the 2nd token and the first token begins
1575 * with a ':', then just grab to EOL.
1578 if (*ntok == 1 && tokens[0][0] == ':') {
1580 if (sp - tspace >= MAXLINE)
1583 } while (!ISEOL(*cp));
1586 /* Check if this token begins with a double quote.
1587 * If yes, continue reading till the next double quote
1589 else if (*cp == '\"') {
1592 if (sp - tspace >= MAXLINE)
1595 } while ((*cp != '\"') && !ISEOL(*cp));
1596 /* HMS: a missing closing " should be an error */
1600 if (sp - tspace >= MAXLINE)
1603 } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
1604 /* HMS: Why check for a " in the previous line? */
1607 if (sp - tspace >= MAXLINE)
1616 "***Line `%s' is too big\n",
1623 * getarg - interpret an argument token
1634 switch (code & ~OPT) {
1640 if (!getnetnum(str, &argp->netnum, NULL, 0))
1645 if ('&' == str[0]) {
1646 if (!atouint(&str[1], &ul)) {
1648 "***Association index `%s' invalid/undecodable\n",
1652 if (0 == numassoc) {
1654 if (0 == numassoc) {
1656 "***No associations found, `%s' unknown\n",
1661 ul = min(ul, numassoc);
1662 argp->uval = assoc_cache[ul - 1].assid;
1665 if (!atouint(str, &argp->uval)) {
1666 fprintf(stderr, "***Illegal unsigned value %s\n",
1673 if (!atoint(str, &argp->ival)) {
1674 fprintf(stderr, "***Illegal integer value %s\n",
1681 if (!strcmp("-6", str)) {
1683 } else if (!strcmp("-4", str)) {
1686 fprintf(stderr, "***Version must be either 4 or 6\n");
1694 #endif /* !BUILD_AS_LIB */
1698 * findcmd - find a command in a command description table
1703 struct xcmd * clist1,
1704 struct xcmd * clist2,
1711 struct xcmd *nearmatch = NULL;
1718 else if (clist2 != 0)
1724 for (cl = clist; cl->keyword != 0; cl++) {
1725 /* do a first character check, for efficiency */
1726 if (*str != *(cl->keyword))
1728 if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
1730 * Could be extact match, could be approximate.
1731 * Is exact if the length of the keyword is the
1734 if (*((cl->keyword) + clen) == '\0') {
1744 * See if there is more to do. If so, go again. Sorry about the
1745 * goto, too much looking at BSD sources...
1747 if (clist == clist1 && clist2 != 0) {
1753 * If we got extactly 1 near match, use it, else return number
1765 * getnetnum - given a host name, return its net number
1766 * and (optional) full name
1776 struct addrinfo hints, *ai = NULL;
1779 hints.ai_flags = AI_CANONNAME;
1780 #ifdef AI_ADDRCONFIG
1781 hints.ai_flags |= AI_ADDRCONFIG;
1785 * decodenetnum only works with addresses, but handles syntax
1786 * that getaddrinfo doesn't: [2001::1]:1234
1788 if (decodenetnum(hname, num)) {
1789 if (fullhost != NULL)
1790 getnameinfo(&num->sa, SOCKLEN(num), fullhost,
1791 LENHOSTNAME, NULL, 0, 0);
1793 } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
1794 INSIST(sizeof(*num) >= ai->ai_addrlen);
1795 memcpy(num, ai->ai_addr, ai->ai_addrlen);
1796 if (fullhost != NULL) {
1797 if (ai->ai_canonname != NULL)
1798 strlcpy(fullhost, ai->ai_canonname,
1801 getnameinfo(&num->sa, SOCKLEN(num),
1802 fullhost, LENHOSTNAME, NULL,
1808 fprintf(stderr, "***Can't find host %s\n", hname);
1815 * nntohost - convert network number to host name. This routine enforces
1816 * the showhostnames setting.
1823 return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
1828 * nntohost_col - convert network number to host name in fixed width.
1829 * This routine enforces the showhostnames setting.
1830 * When displaying hostnames longer than the width,
1831 * the first part of the hostname is displayed. When
1832 * displaying numeric addresses longer than the width,
1833 * Such as IPv6 addresses, the caller decides whether
1834 * the first or last of the numeric address is used.
1840 int preserve_lowaddrbits
1845 if (!showhostnames || SOCK_UNSPEC(addr)) {
1846 if (preserve_lowaddrbits)
1847 out = trunc_left(stoa(addr), width);
1849 out = trunc_right(stoa(addr), width);
1850 } else if (ISREFCLOCKADR(addr)) {
1851 out = refnumtoa(addr);
1853 out = trunc_right(socktohost(addr), width);
1860 * nntohostp() is the same as nntohost() plus a :port suffix
1870 if (!showhostnames || SOCK_UNSPEC(netnum))
1871 return sptoa(netnum);
1872 else if (ISREFCLOCKADR(netnum))
1873 return refnumtoa(netnum);
1875 hostn = socktohost(netnum);
1877 snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
1883 * rtdatetolfp - decode an RT-11 date into an l_fp
1893 struct calendar cal;
1899 * An RT-11 date looks like:
1901 * d[d]-Mth-y[y] hh:mm:ss
1903 * (No docs, but assume 4-digit years are also legal...)
1905 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1908 if (!isdigit((int)*cp)) {
1911 * Catch special case
1919 cal.monthday = (u_char) (*cp++ - '0'); /* ascii dependent */
1920 if (isdigit((int)*cp)) {
1921 cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
1922 cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
1928 for (i = 0; i < 3; i++)
1932 for (i = 0; i < 12; i++)
1933 if (STREQ(buf, months[i]))
1937 cal.month = (u_char)(i + 1);
1942 if (!isdigit((int)*cp))
1944 cal.year = (u_short)(*cp++ - '0');
1945 if (isdigit((int)*cp)) {
1946 cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1947 cal.year = (u_short)(*cp++ - '0');
1949 if (isdigit((int)*cp)) {
1950 cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1951 cal.year = (u_short)(cal.year + *cp++ - '0');
1953 if (isdigit((int)*cp)) {
1954 cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
1955 cal.year = (u_short)(cal.year + *cp++ - '0');
1959 * Catch special case. If cal.year == 0 this is a zero timestamp.
1961 if (cal.year == 0) {
1966 if (*cp++ != ' ' || !isdigit((int)*cp))
1968 cal.hour = (u_char)(*cp++ - '0');
1969 if (isdigit((int)*cp)) {
1970 cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
1971 cal.hour = (u_char)(cal.hour + *cp++ - '0');
1974 if (*cp++ != ':' || !isdigit((int)*cp))
1976 cal.minute = (u_char)(*cp++ - '0');
1977 if (isdigit((int)*cp)) {
1978 cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
1979 cal.minute = (u_char)(cal.minute + *cp++ - '0');
1982 if (*cp++ != ':' || !isdigit((int)*cp))
1984 cal.second = (u_char)(*cp++ - '0');
1985 if (isdigit((int)*cp)) {
1986 cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
1987 cal.second = (u_char)(cal.second + *cp++ - '0');
1991 * For RT-11, 1972 seems to be the pivot year
1998 lfp->l_ui = caltontp(&cal);
2005 * decodets - decode a timestamp into an l_fp format number, with
2006 * consideration of fuzzball formats.
2019 * If it starts with a 0x, decode as hex.
2021 if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
2022 return hextolfp(str+2, lfp);
2025 * If it starts with a '"', try it as an RT-11 date.
2030 while ('"' != *cp && '\0' != *cp &&
2031 b < COUNTOF(buf) - 1)
2034 return rtdatetolfp(buf, lfp);
2038 * Might still be hex. Check out the first character. Talk
2041 if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
2042 return hextolfp(str, lfp);
2045 * Try it as a decimal. If this fails, try as an unquoted
2046 * RT-11 date. This code should go away eventually.
2048 if (atolfp(str, lfp))
2051 return rtdatetolfp(str, lfp);
2056 * decodetime - decode a time value. It should be in milliseconds
2064 return mstolfp(str, lfp);
2069 * decodeint - decode an integer
2078 if (*(str+1) == 'x' || *(str+1) == 'X')
2079 return hextoint(str+2, (u_long *)val);
2080 return octtoint(str, (u_long *)val);
2082 return atoint(str, val);
2087 * decodeuint - decode an unsigned integer
2096 if (*(str + 1) == 'x' || *(str + 1) == 'X')
2097 return (hextoint(str + 2, val));
2098 return (octtoint(str, val));
2100 return (atouint(str, val));
2105 * decodearr - decode an array of time values
2114 register char *cp, *bp;
2123 while (isspace((int)*cp))
2129 while (!isspace((int)*cp) && *cp != '\0')
2133 if (!decodetime(buf, lfp))
2143 * Finally, the built in command handlers
2147 * help - tell about commands, or details of a particular command
2155 struct xcmd *xcp = NULL; /* quiet warning */
2157 const char *list[100];
2163 if (pcmd->nargs == 0) {
2165 for (xcp = builtins; xcp->keyword != NULL; xcp++) {
2166 if (*(xcp->keyword) != '?' &&
2167 words < COUNTOF(list))
2168 list[words++] = xcp->keyword;
2170 for (xcp = opcmds; xcp->keyword != NULL; xcp++)
2171 if (words < COUNTOF(list))
2172 list[words++] = xcp->keyword;
2174 qsort((void *)list, words, sizeof(list[0]), helpsort);
2176 for (word = 0; word < words; word++) {
2177 length = strlen(list[word]);
2178 col = max(col, length);
2181 cols = SCREENWIDTH / ++col;
2182 rows = (words + cols - 1) / cols;
2184 fprintf(fp, "ntpq commands:\n");
2186 for (row = 0; row < rows; row++) {
2187 for (word = row; word < words; word += rows)
2188 fprintf(fp, "%-*.*s", (int)col,
2189 (int)col - 1, list[word]);
2193 cmd = pcmd->argval[0].string;
2194 words = findcmd(cmd, builtins, opcmds, &xcp);
2197 "Command `%s' is unknown\n", cmd);
2199 } else if (words >= 2) {
2201 "Command `%s' is ambiguous\n", cmd);
2204 fprintf(fp, "function: %s\n", xcp->comment);
2205 printusage(xcp, fp);
2211 * helpsort - do hostname qsort comparisons
2219 const char * const * name1 = t1;
2220 const char * const * name2 = t2;
2222 return strcmp(*name1, *name2);
2227 * printusage - print usage information for a command
2237 /* XXX: Do we need to warn about extra args here too? */
2239 (void) fprintf(fp, "usage: %s", xcp->keyword);
2240 for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
2241 if (xcp->arg[i] & OPT)
2242 (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
2244 (void) fprintf(fp, " %s", xcp->desc[i]);
2246 (void) fprintf(fp, "\n");
2251 * timeout - set time out time
2261 if (pcmd->nargs == 0) {
2262 val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
2263 (void) fprintf(fp, "primary timeout %d ms\n", val);
2265 tvout.tv_sec = pcmd->argval[0].uval / 1000;
2266 tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
2273 * auth_delay - set delay for auth requests
2284 if (pcmd->nargs == 0) {
2285 val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
2286 (void) fprintf(fp, "delay %lu ms\n", val);
2288 if (pcmd->argval[0].ival < 0) {
2290 val = (u_long)(-pcmd->argval[0].ival);
2293 val = (u_long)pcmd->argval[0].ival;
2296 delay_time.l_ui = val / 1000;
2298 delay_time.l_uf = val * 4294967; /* 2**32/1000 */
2307 * host - set the host we are dealing with.
2317 if (pcmd->nargs == 0) {
2319 (void) fprintf(fp, "current host is %s\n",
2322 (void) fprintf(fp, "no current host\n");
2327 ai_fam_templ = ai_fam_default;
2328 if (pcmd->nargs == 2) {
2329 if (!strcmp("-4", pcmd->argval[i].string))
2330 ai_fam_templ = AF_INET;
2331 else if (!strcmp("-6", pcmd->argval[i].string))
2332 ai_fam_templ = AF_INET6;
2337 if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
2338 fprintf(fp, "current host set to %s\n", currenthost);
2342 fprintf(fp, "current host remains %s\n",
2345 fprintf(fp, "still no current host\n");
2351 * poll - do one (or more) polls of the host via NTP
2360 (void) fprintf(fp, "poll not implemented yet\n");
2365 * keyid - get a keyid to use for authenticating requests
2373 if (pcmd->nargs == 0) {
2374 if (info_auth_keyid == 0)
2375 (void) fprintf(fp, "no keyid defined\n");
2377 (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
2379 /* allow zero so that keyid can be cleared. */
2380 if(pcmd->argval[0].uval > NTP_MAXKEY)
2381 (void) fprintf(fp, "Invalid key identifier\n");
2382 info_auth_keyid = pcmd->argval[0].uval;
2387 * keytype - get type of key to use for authenticating requests
2395 const char * digest_name;
2400 fprintf(fp, "keytype is %s with %lu octet digests\n",
2401 keytype_name(info_auth_keytype),
2402 (u_long)info_auth_hashlen);
2406 digest_name = pcmd->argval[0].string;
2408 key_type = keytype_from_text(digest_name, &digest_len);
2411 fprintf(fp, "keytype must be 'md5'%s\n",
2413 " or a digest type provided by OpenSSL");
2420 info_auth_keytype = key_type;
2421 info_auth_hashlen = digest_len;
2426 * passwd - get an authentication key
2437 if (info_auth_keyid == 0) {
2438 info_auth_keyid = getkeyid("Keyid: ");
2439 if (info_auth_keyid == 0) {
2440 (void)fprintf(fp, "Keyid must be defined\n");
2444 if (pcmd->nargs >= 1)
2445 pass = pcmd->argval[0].string;
2447 pass = getpass_keytype(info_auth_keytype);
2448 if ('\0' == pass[0]) {
2449 fprintf(fp, "Password unchanged\n");
2453 authusekey(info_auth_keyid, info_auth_keytype,
2454 (const u_char *)pass);
2455 authtrust(info_auth_keyid, 1);
2460 * hostnames - set the showhostnames flag
2468 if (pcmd->nargs == 0) {
2470 (void) fprintf(fp, "hostnames being shown\n");
2472 (void) fprintf(fp, "hostnames not being shown\n");
2474 if (STREQ(pcmd->argval[0].string, "yes"))
2476 else if (STREQ(pcmd->argval[0].string, "no"))
2479 (void)fprintf(stderr, "What?\n");
2486 * setdebug - set/change debugging level
2494 if (pcmd->nargs == 0) {
2495 (void) fprintf(fp, "debug level is %d\n", debug);
2497 } else if (STREQ(pcmd->argval[0].string, "no")) {
2499 } else if (STREQ(pcmd->argval[0].string, "more")) {
2501 } else if (STREQ(pcmd->argval[0].string, "less")) {
2504 (void) fprintf(fp, "What?\n");
2507 (void) fprintf(fp, "debug level set to %d\n", debug);
2512 * quit - stop this nonsense
2522 closesocket(sockfd); /* cleanliness next to godliness */
2528 * version - print the current version number
2538 (void) fprintf(fp, "%s\n", Version);
2544 * raw - set raw mode output
2554 (void) fprintf(fp, "Output set to raw\n");
2559 * cooked - set cooked mode output
2569 (void) fprintf(fp, "Output set to cooked\n");
2575 * authenticate - always authenticate requests to this host
2583 if (pcmd->nargs == 0) {
2586 "authenticated requests being sent\n");
2589 "unauthenticated requests being sent\n");
2591 if (STREQ(pcmd->argval[0].string, "yes")) {
2593 } else if (STREQ(pcmd->argval[0].string, "no")) {
2596 (void)fprintf(stderr, "What?\n");
2602 * ntpversion - choose the NTP version to use
2610 if (pcmd->nargs == 0) {
2612 "NTP version being claimed is %d\n", pktversion);
2614 if (pcmd->argval[0].uval < NTP_OLDVERSION
2615 || pcmd->argval[0].uval > NTP_VERSION) {
2616 (void) fprintf(stderr, "versions %d to %d, please\n",
2617 NTP_OLDVERSION, NTP_VERSION);
2619 pktversion = (u_char) pcmd->argval[0].uval;
2625 static void __attribute__((__format__(__printf__, 1, 0)))
2626 vwarning(const char *fmt, va_list ap)
2629 (void) fprintf(stderr, "%s: ", progname);
2630 vfprintf(stderr, fmt, ap);
2631 (void) fprintf(stderr, ": %s", strerror(serrno));
2635 * warning - print a warning message
2637 static void __attribute__((__format__(__printf__, 1, 2)))
2651 * error - print a message and exit
2653 static void __attribute__((__format__(__printf__, 1, 2)))
2666 * getkeyid - prompt the user for a keyid to use
2670 const char *keyprompt
2680 if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
2682 if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
2683 #endif /* SYS_WINNT */
2686 setbuf(fi, (char *)NULL);
2687 fprintf(stderr, "%s", keyprompt); fflush(stderr);
2688 for (i = 0, ilim = COUNTOF(pbuf) - 1;
2689 i < ilim && (c = getc(fi)) != '\n' && c != EOF;
2691 pbuf[i++] = (char)c;
2696 return (u_long) atoi(pbuf);
2701 * atoascii - printable-ize possibly ascii data using the character
2702 * transformations cat -v uses.
2712 const u_char * pchIn;
2713 const u_char * pchInLimit;
2717 pchIn = (const u_char *)in;
2718 pchInLimit = pchIn + in_octets;
2719 pchOut = (u_char *)out;
2721 if (NULL == pchIn) {
2729 if (0 == --out_octets) { \
2736 for ( ; pchIn < pchInLimit; pchIn++) {
2747 ONEOUT((u_char)(c + '@'));
2748 } else if (0x7f == c) {
2761 * makeascii - print possibly ascii data using the character
2762 * transformations that cat -v uses.
2771 const u_char *data_u_char;
2775 data_u_char = (const u_char *)data;
2777 for (cp = data_u_char; cp < data_u_char + length; cp++) {
2788 } else if (0x7f == c) {
2798 * asciize - same thing as makeascii except add a newline
2807 makeascii(length, data, fp);
2813 * truncate string to fit clipping excess at end.
2814 * "too long" -> "too l"
2815 * Used for hostnames.
2828 if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
2830 memcpy(out, src, width);
2841 * truncate string to fit by preserving right side and using '_' to hint
2842 * "too long" -> "_long"
2843 * Used for local IPv6 addresses, where low bits differentiate.
2856 if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
2859 memcpy(&out[1], &src[sl + 1 - width], width);
2869 * Some circular buffer space
2874 char circ_buf[NUMCB][CBLEN];
2878 * nextvar - find the next variable in the buffer
2893 static char name[MAXVARLEN];
2894 static char value[MAXVALLEN];
2897 cpend = cp + *datalen;
2900 * Space past commas and white space
2902 while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
2908 * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
2909 * over any white space and terminate it.
2911 srclen = strcspn(cp, ",=\r\n");
2912 srclen = min(srclen, (size_t)(cpend - cp));
2914 while (len > 0 && isspace((unsigned char)cp[len - 1]))
2917 memcpy(name, cp, len);
2923 * Check if we hit the end of the buffer or a ','. If so we are done.
2925 if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
2929 *datalen = cpend - cp;
2935 * So far, so good. Copy out the value
2937 cp++; /* past '=' */
2938 while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n'))
2944 } while (np < cpend && '"' != *np);
2945 if (np < cpend && '"' == *np)
2948 while (np < cpend && ',' != *np && '\r' != *np)
2952 if (np > cpend || len >= sizeof(value) ||
2953 (np < cpend && ',' != *np && '\r' != *np))
2955 memcpy(value, cp, len);
2957 * Trim off any trailing whitespace
2959 while (len > 0 && isspace((unsigned char)value[len - 1]))
2964 * Return this. All done.
2966 if (np < cpend && ',' == *np)
2969 *datalen = cpend - np;
2976 varfmt(const char * varname)
2980 for (n = 0; n < COUNTOF(cookedvars); n++)
2981 if (!strcmp(varname, cookedvars[n].varname))
2982 return cookedvars[n].fmt;
2989 * printvars - print variables returned in response packet
3002 rawprint(sttype, length, data, status, quiet, fp);
3004 cookedprint(sttype, length, data, status, quiet, fp);
3009 * rawprint - do a printout of the data in raw mode
3025 * Essentially print the data as is. We reformat unprintables, though.
3028 cpend = data + length;
3031 (void) fprintf(fp, "status=0x%04x,\n", status);
3033 while (cp < cpend) {
3036 * If this is a \r and the next character is a
3037 * \n, supress this, else pretty print it. Otherwise
3038 * just output the character.
3040 if (cp == (cpend - 1) || *(cp + 1) != '\n')
3041 makeascii(1, cp, fp);
3042 } else if (isspace((unsigned char)*cp) || isprint((unsigned char)*cp))
3045 makeascii(1, cp, fp);
3052 * Global data used by the cooked output routines
3054 int out_chars; /* number of characters output */
3055 int out_linecount; /* number of characters output on this line */
3059 * startoutput - get ready to do cooked output
3070 * output - output a variable=value combination
3081 /* strlen of "name=value" */
3082 len = strlen(name) + 1 + strlen(value);
3084 if (out_chars != 0) {
3086 if ((out_linecount + len + 2) > MAXOUTLINE) {
3099 out_linecount += len;
3104 * endoutput - terminate a block of cooked output
3117 * outputarr - output an array of values
3135 * Hack to align delay and offset values
3137 for (i = (int)strlen(name); i < 11; i++)
3140 for (i = narr; i > 0; i--) {
3143 cp = lfptoms(lfp, 2);
3158 output(fp, name, buf);
3166 register char *cp, *s;
3169 register const char *sep;
3173 s = cp = circ_buf[nextcb];
3174 if (++nextcb >= NUMCB)
3176 cb = sizeof(circ_buf[0]);
3178 snprintf(cp, cb, "%02lx", val);
3182 strlcat(cp, " ok", cb);
3190 for (i = 0; i < (int)COUNTOF(tstflagnames); i++) {
3192 snprintf(cp, cb, "%s%s", sep,
3208 * cookedprint - output variables in cooked mode
3231 char bn[2 * MAXVARLEN];
3232 char bv[2 * MAXVALLEN];
3234 UNUSED_ARG(datatype);
3237 fprintf(fp, "status=%04x %s,\n", status,
3238 statustoa(datatype, status));
3241 while (nextvar(&length, &data, &name, &value)) {
3251 if (!decodets(value, &lfp))
3254 output(fp, name, prettydate(&lfp));
3257 case HA: /* fallthru */
3259 if (!decodenetnum(value, &hval)) {
3261 } else if (fmt == HA){
3262 output(fp, name, nntohost(&hval));
3264 output(fp, name, stoa(&hval));
3269 if (decodenetnum(value, &hval)) {
3270 if (ISREFCLOCKADR(&hval))
3274 output(fp, name, stoa(&hval));
3275 } else if (strlen(value) <= 4) {
3276 output(fp, name, value);
3283 if (!decodeuint(value, &uval) || uval > 3) {
3293 output(fp, name, b);
3298 if (!decodeuint(value, &uval)) {
3301 snprintf(b, sizeof(b), "%03lo", uval);
3302 output(fp, name, b);
3307 if (!decodearr(value, &narr, lfparr))
3310 outputarr(fp, name, narr, lfparr);
3314 if (!decodeuint(value, &uval))
3317 output(fp, name, tstflags(uval));
3321 fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
3327 if (output_raw != 0) {
3328 atoascii(name, MAXVARLEN, bn, sizeof(bn));
3329 atoascii(value, MAXVALLEN, bv, sizeof(bv));
3330 if (output_raw != '*') {
3332 bv[len] = output_raw;
3343 * sortassoc - sort associations in the cache into ascending order
3349 qsort(assoc_cache, (size_t)numassoc,
3350 sizeof(assoc_cache[0]), &assoccmp);
3355 * assoccmp - compare two associations
3363 const struct association *ass1 = t1;
3364 const struct association *ass2 = t2;
3366 if (ass1->assid < ass2->assid)
3368 if (ass1->assid > ass2->assid)
3375 * grow_assoc_cache() - enlarge dynamic assoc_cache array
3377 * The strategy is to add an assumed 4k page size at a time, leaving
3378 * room for malloc() bookkeeping overhead equivalent to 4 pointers.
3381 grow_assoc_cache(void)
3383 static size_t prior_sz;
3386 new_sz = prior_sz + 4 * 1024;
3387 if (0 == prior_sz) {
3388 new_sz -= 4 * sizeof(void *);
3390 assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
3392 assoc_cache_slots = new_sz / sizeof(assoc_cache[0]);
3397 * ntpq_custom_opt_handler - autoopts handler for -c and -p
3399 * By default, autoopts loses the relative order of -c and -p options
3400 * on the command line. This routine replaces the default handler for
3401 * those routines and builds a list of commands to execute preserving
3405 ntpq_custom_opt_handler(
3410 switch (pOptDesc->optValue) {
3414 "ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3415 pOptDesc->optValue, pOptDesc->optValue);
3419 ADDCMD(pOptDesc->pzLastArg);