summaryrefslogtreecommitdiffstats
path: root/ntpq/ntpq.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpq/ntpq.c')
-rw-r--r--ntpq/ntpq.c2002
1 files changed, 1118 insertions, 884 deletions
diff --git a/ntpq/ntpq.c b/ntpq/ntpq.c
index 2e51b35..bc1acc6 100644
--- a/ntpq/ntpq.c
+++ b/ntpq/ntpq.c
@@ -16,25 +16,21 @@
#include "ntp_io.h"
#include "ntp_select.h"
#include "ntp_stdlib.h"
-/* Don't include ISC's version of IPv6 variables and structures */
-#define ISC_IPV6_H 1
+#include "ntp_assert.h"
+#include "ntp_lineedit.h"
+#include "ntp_debug.h"
#include "isc/net.h"
#include "isc/result.h"
+#include <ssl_applink.c>
+#include "ntp_libopts.h"
#include "ntpq-opts.h"
#ifdef SYS_WINNT
# include <Mswsock.h>
# include <io.h>
-#else
-# define closesocket close
#endif /* SYS_WINNT */
-#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
-# include <readline/readline.h>
-# include <readline/history.h>
-#endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */
-
#ifdef SYS_VXWORKS
/* vxWorks needs mode flag -casey*/
# define open(name, flags) open(name, flags, 0777)
@@ -53,6 +49,15 @@
int interactive = 0; /* set to 1 when we should prompt */
const char *prompt = "ntpq> "; /* prompt to ask him about */
+/*
+ * use old readvars behavior? --old-rv processing in ntpq resets
+ * this value based on the presence or absence of --old-rv. It is
+ * initialized to 1 here to maintain backward compatibility with
+ * libntpq clients such as ntpsnmpd, which are free to reset it as
+ * desired.
+ */
+int old_rv = 1;
+
/*
* for get_systime()
@@ -64,12 +69,8 @@ s_char sys_precision; /* local clock precision (log2 s) */
*/
u_long info_auth_keyid = 0;
-/*
- * Type of key md5
- */
-#define KEY_TYPE_MD5 4
-
-static int info_auth_keytype = KEY_TYPE_MD5; /* MD5 */
+static int info_auth_keytype = NID_md5; /* MD5 */
+static size_t info_auth_hashlen = 16; /* MD5 */
u_long current_time; /* needed by authkeys; not used */
/*
@@ -129,16 +130,15 @@ struct ctl_var sys_var[] = {
{ CS_REFTIME, TS, "reftime" }, /* 7 */
{ CS_POLL, UI, "poll" }, /* 8 */
{ CS_PEERID, UI, "peer" }, /* 9 */
- { CS_STATE, UI, "state" }, /* 10 */
- { CS_OFFSET, FL, "offset" }, /* 11 */
- { CS_DRIFT, FS, "frequency" }, /* 12 */
- { CS_JITTER, FU, "jitter" }, /* 13 */
- { CS_CLOCK, TS, "clock" }, /* 14 */
- { CS_PROCESSOR, ST, "processor" }, /* 15 */
- { CS_SYSTEM, ST, "system" }, /* 16 */
- { CS_VERSION, ST, "version" }, /* 17 */
- { CS_STABIL, FS, "stability" }, /* 18 */
- { CS_VARLIST, ST, "sys_var_list" }, /* 19 */
+ { CS_OFFSET, FL, "offset" }, /* 10 */
+ { CS_DRIFT, FS, "frequency" }, /* 11 */
+ { CS_JITTER, FU, "jitter" }, /* 12 */
+ { CS_CLOCK, TS, "clock" }, /* 13 */
+ { CS_PROCESSOR, ST, "processor" }, /* 14 */
+ { CS_SYSTEM, ST, "system" }, /* 15 */
+ { CS_VERSION, ST, "version" }, /* 16 */
+ { CS_STABIL, FS, "stability" }, /* 17 */
+ { CS_VARLIST, ST, "sys_var_list" }, /* 18 */
{ 0, EOV, "" }
};
@@ -162,7 +162,7 @@ struct ctl_var peer_var[] = {
{ CP_HPOLL, UI, "hpoll" }, /* 12 */
{ CP_PRECISION, SI, "precision" }, /* 13 */
{ CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */
- { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */
+ { CP_ROOTDISPERSION, FU, "rootdisp" }, /* 15 */
{ CP_REFID, RF, "refid" }, /* 16 */
{ CP_REFTIME, TS, "reftime" }, /* 17 */
{ CP_ORG, TS, "org" }, /* 18 */
@@ -224,75 +224,72 @@ struct ctl_var clock_var[] = {
static const char *tstflagnames[] = {
"pkt_dup", /* TEST1 */
"pkt_bogus", /* TEST2 */
- "pkt_proto", /* TEST3 */
+ "pkt_unsync", /* TEST3 */
"pkt_denied", /* TEST4 */
"pkt_auth", /* TEST5 */
- "pkt_synch", /* TEST6 */
- "pkt_dist", /* TEST7 */
+ "pkt_stratum", /* TEST6 */
+ "pkt_header", /* TEST7 */
"pkt_autokey", /* TEST8 */
"pkt_crypto", /* TEST9 */
"peer_stratum", /* TEST10 */
"peer_dist", /* TEST11 */
"peer_loop", /* TEST12 */
- "peer_unfit" /* TEST13 */
+ "peer_unreach" /* TEST13 */
};
-int ntpqmain P((int, char **));
+int ntpqmain (int, char **);
/*
* Built in command handler declarations
*/
-static int openhost P((const char *));
-static int sendpkt P((char *, int));
-static int getresponse P((int, int, u_short *, int *, char **, int));
-static int sendrequest P((int, int, int, int, char *));
-static char * tstflags P((u_long));
-static void getcmds P((void));
-static RETSIGTYPE abortcmd P((int));
-static void docmd P((const char *));
-static void tokenize P((const char *, char **, int *));
-static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
-static int getarg P((char *, int, arg_v *));
-static int rtdatetolfp P((char *, l_fp *));
-static int decodearr P((char *, int *, l_fp *));
-static void help P((struct parse *, FILE *));
-#ifdef QSORT_USES_VOID_P
-static int helpsort P((const void *, const void *));
-#else
-static int helpsort P((char **, char **));
-#endif
-static void printusage P((struct xcmd *, FILE *));
-static void timeout P((struct parse *, FILE *));
-static void auth_delay P((struct parse *, FILE *));
-static void host P((struct parse *, FILE *));
-static void ntp_poll P((struct parse *, FILE *));
-static void keyid P((struct parse *, FILE *));
-static void keytype P((struct parse *, FILE *));
-static void passwd P((struct parse *, FILE *));
-static void hostnames P((struct parse *, FILE *));
-static void setdebug P((struct parse *, FILE *));
-static void quit P((struct parse *, FILE *));
-static void version P((struct parse *, FILE *));
-static void raw P((struct parse *, FILE *));
-static void cooked P((struct parse *, FILE *));
-static void authenticate P((struct parse *, FILE *));
-static void ntpversion P((struct parse *, FILE *));
-static void warning P((const char *, const char *, const char *));
-static void error P((const char *, const char *, const char *));
-static u_long getkeyid P((const char *));
-static void atoascii P((int, char *, char *));
-static void makeascii P((int, char *, FILE *));
-static void rawprint P((int, int, char *, int, FILE *));
-static void startoutput P((void));
-static void output P((FILE *, char *, char *));
-static void endoutput P((FILE *));
-static void outputarr P((FILE *, char *, int, l_fp *));
-static void cookedprint P((int, int, char *, int, FILE *));
-#ifdef QSORT_USES_VOID_P
-static int assoccmp P((const void *, const void *));
-#else
-static int assoccmp P((struct association *, struct association *));
-#endif /* sgi || bsdi */
+static int openhost (const char *);
+
+static int sendpkt (void *, size_t);
+static int getresponse (int, int, u_short *, int *, const char **, int);
+static int sendrequest (int, int, int, int, char *);
+static char * tstflags (u_long);
+#ifndef BUILD_AS_LIB
+static void getcmds (void);
+#ifndef SYS_WINNT
+static RETSIGTYPE abortcmd (int);
+#endif /* SYS_WINNT */
+static void docmd (const char *);
+static void tokenize (const char *, char **, int *);
+static int getarg (char *, int, arg_v *);
+#endif /* BUILD_AS_LIB */
+static int findcmd (char *, struct xcmd *, struct xcmd *, struct xcmd **);
+static int rtdatetolfp (char *, l_fp *);
+static int decodearr (char *, int *, l_fp *);
+static void help (struct parse *, FILE *);
+static int helpsort (const void *, const void *);
+static void printusage (struct xcmd *, FILE *);
+static void timeout (struct parse *, FILE *);
+static void auth_delay (struct parse *, FILE *);
+static void host (struct parse *, FILE *);
+static void ntp_poll (struct parse *, FILE *);
+static void keyid (struct parse *, FILE *);
+static void keytype (struct parse *, FILE *);
+static void passwd (struct parse *, FILE *);
+static void hostnames (struct parse *, FILE *);
+static void setdebug (struct parse *, FILE *);
+static void quit (struct parse *, FILE *);
+static void version (struct parse *, FILE *);
+static void raw (struct parse *, FILE *);
+static void cooked (struct parse *, FILE *);
+static void authenticate (struct parse *, FILE *);
+static void ntpversion (struct parse *, FILE *);
+static void warning (const char *, const char *, const char *);
+static void error (const char *, const char *, const char *);
+static u_long getkeyid (const char *);
+static void atoascii (const char *, size_t, char *, size_t);
+static void cookedprint (int, int, const char *, int, int, FILE *);
+static void rawprint (int, int, const char *, int, int, FILE *);
+static void startoutput (void);
+static void output (FILE *, char *, char *);
+static void endoutput (FILE *);
+static void outputarr (FILE *, char *, int, l_fp *);
+static int assoccmp (const void *, const void *);
+void ntpq_custom_opt_handler (tOptions *, tOptDesc *);
/*
@@ -361,10 +358,10 @@ struct xcmd builtins[] = {
/*
* Default values we use.
*/
+#define DEFHOST "localhost" /* default host name */
#define DEFTIMEOUT (5) /* 5 second time out */
#define DEFSTIMEOUT (2) /* 2 second time out after first */
#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
-#define DEFHOST "localhost" /* default host name */
#define LENHOSTNAME 256 /* host name is 256 characters long */
#define MAXCMDS 100 /* maximum commands on cmd line */
#define MAXHOSTS 200 /* maximum hosts on cmd line */
@@ -373,15 +370,16 @@ struct xcmd builtins[] = {
#define MAXVARLEN 256 /* maximum length of a variable name */
#define MAXVALLEN 400 /* maximum length of a variable value */
#define MAXOUTLINE 72 /* maximum length of an output line */
-#define SCREENWIDTH 76 /* nominal screen width in columns */
+#define SCREENWIDTH 76 /* nominal screen width in columns */
/*
* Some variables used and manipulated locally
*/
-struct timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
-struct timeval tvsout = { DEFSTIMEOUT, 0 }; /* secondary time out */
+struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
+struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
l_fp delay_time; /* delay time */
char currenthost[LENHOSTNAME]; /* current host name */
+int currenthostisnum; /* is prior text from IP? */
struct sockaddr_in hostaddr = { 0 }; /* host address */
int showhostnames = 1; /* show host names by default */
@@ -392,13 +390,6 @@ int havehost = 0; /* set to 1 when host open */
int s_port = 0;
struct servent *server_entry = NULL; /* server entry for ntp */
-#ifdef SYS_WINNT
-DWORD NumberOfBytesWritten;
-
-HANDLE TimerThreadHandle = NULL; /* 1998/06/03 - Used in ntplib/machines.c */
-void timer(void) { ; }; /* 1998/06/03 - Used in ntplib/machines.c */
-
-#endif /* SYS_WINNT */
/*
* Sequence number used for requests. It is incremented before
@@ -468,20 +459,22 @@ char *progname;
volatile int debug;
#ifdef NO_MAIN_ALLOWED
+#ifndef BUILD_AS_LIB
CALL(ntpq,"ntpq",ntpqmain);
void clear_globals(void)
{
- extern int ntp_optind;
- showhostnames = 0; /* don'tshow host names by default */
- ntp_optind = 0;
- server_entry = NULL; /* server entry for ntp */
- havehost = 0; /* set to 1 when host open */
- numassoc = 0; /* number of cached associations */
- numcmds = 0;
- numhosts = 0;
+ extern int ntp_optind;
+ showhostnames = 0; /* don'tshow host names by default */
+ ntp_optind = 0;
+ server_entry = NULL; /* server entry for ntp */
+ havehost = 0; /* set to 1 when host open */
+ numassoc = 0; /* number of cached associations */
+ numcmds = 0;
+ numhosts = 0;
}
-#endif
+#endif /* !BUILD_AS_LIB */
+#endif /* NO_MAIN_ALLOWED */
/*
* main - parse arguments and handle options
@@ -497,6 +490,7 @@ main(
}
#endif
+#ifndef BUILD_AS_LIB
int
ntpqmain(
int argc,
@@ -513,61 +507,42 @@ ntpqmain(
delay_time.l_ui = 0;
delay_time.l_uf = DEFDELAY;
-#ifdef SYS_WINNT
- if (!Win32InitSockets())
- {
- fprintf(stderr, "No useable winsock.dll:");
- exit(1);
- }
-#endif /* SYS_WINNT */
+ init_lib(); /* sets up ipv4_works, ipv6_works */
+ ssl_applink();
- /* Check to see if we have IPv6. Otherwise force the -4 flag */
- if (isc_net_probeipv6() != ISC_R_SUCCESS) {
+ /* Check to see if we have IPv6. Otherwise default to IPv4 */
+ if (!ipv6_works)
ai_fam_default = AF_INET;
- }
progname = argv[0];
{
- int optct = optionProcess(&ntpqOptions, argc, argv);
+ int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
argc -= optct;
argv += optct;
}
- switch (WHICH_IDX_IPV4) {
- case INDEX_OPT_IPV4:
+ /*
+ * Process options other than -c and -p, which are specially
+ * handled by ntpq_custom_opt_handler().
+ */
+
+ debug = DESC(DEBUG_LEVEL).optOccCt;
+
+ if (HAVE_OPT(IPV4))
ai_fam_templ = AF_INET;
- break;
- case INDEX_OPT_IPV6:
+ else if (HAVE_OPT(IPV6))
ai_fam_templ = AF_INET6;
- break;
- default:
+ else
ai_fam_templ = ai_fam_default;
- break;
- }
-
- if (HAVE_OPT(COMMAND)) {
- int cmdct = STACKCT_OPT( COMMAND );
- const char** cmds = STACKLST_OPT( COMMAND );
- while (cmdct-- > 0) {
- ADDCMD(*cmds++);
- }
- }
-
- debug = DESC(DEBUG_LEVEL).optOccCt;
-
- if (HAVE_OPT(INTERACTIVE)) {
+ if (HAVE_OPT(INTERACTIVE))
interactive = 1;
- }
- if (HAVE_OPT(NUMERIC)) {
+ if (HAVE_OPT(NUMERIC))
showhostnames = 0;
- }
- if (HAVE_OPT(PEERS)) {
- ADDCMD("peers");
- }
+ old_rv = HAVE_OPT(OLD_RV);
#if 0
while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF)
@@ -604,11 +579,12 @@ ntpqmain(
exit(2);
}
#endif
+ NTP_INSIST(ntp_optind <= argc);
if (ntp_optind == argc) {
ADDHOST(DEFHOST);
} else {
for (; ntp_optind < argc; ntp_optind++)
- ADDHOST(argv[ntp_optind]);
+ ADDHOST(argv[ntp_optind]);
}
if (numcmds == 0 && interactive == 0
@@ -630,8 +606,8 @@ ntpqmain(
for (ihost = 0; ihost < numhosts; ihost++) {
if (openhost(chosts[ihost]))
- for (icmd = 0; icmd < numcmds; icmd++)
- docmd(ccmds[icmd]);
+ for (icmd = 0; icmd < numcmds; icmd++)
+ docmd(ccmds[icmd]);
}
}
#ifdef SYS_WINNT
@@ -639,12 +615,12 @@ ntpqmain(
#endif /* SYS_WINNT */
return 0;
}
-
+#endif /* !BUILD_AS_LIB */
/*
* openhost - open a socket to a host
*/
-static int
+static int
openhost(
const char *hname
)
@@ -662,12 +638,16 @@ openhost(
cp = hname;
- if(*cp == '[') {
+ if (*cp == '[') {
cp++;
- for(i = 0; *cp != ']'; cp++, i++)
+ for (i = 0; *cp && *cp != ']'; cp++, i++)
name[i] = *cp;
- name[i] = '\0';
- hname = name;
+ if (*cp == ']') {
+ name[i] = '\0';
+ hname = name;
+ } else {
+ return 0;
+ }
}
/*
@@ -678,11 +658,11 @@ openhost(
* give it an IPv4 address to lookup.
*/
strcpy(service, "ntp");
- memset((char *)&hints, 0, sizeof(struct addrinfo));
+ ZERO(hints);
hints.ai_family = ai_fam_templ;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_flags = Z_AI_NUMERICHOST;
a_info = getaddrinfo(hname, service, &hints, &ai);
if (a_info == EAI_NONAME
@@ -696,32 +676,35 @@ openhost(
#endif
a_info = getaddrinfo(hname, service, &hints, &ai);
}
+#ifdef AI_ADDRCONFIG
/* Some older implementations don't like AI_ADDRCONFIG. */
if (a_info == EAI_BADFLAGS) {
hints.ai_flags = AI_CANONNAME;
a_info = getaddrinfo(hname, service, &hints, &ai);
}
+#endif
if (a_info != 0) {
(void) fprintf(stderr, "%s\n", gai_strerror(a_info));
return 0;
}
- if (ai->ai_canonname == NULL) {
- strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr),
- LENHOSTNAME);
- temphost[LENHOSTNAME-1] = '\0';
-
+ if (!showhostnames || ai->ai_canonname == NULL) {
+ strncpy(temphost,
+ stoa((sockaddr_u *)ai->ai_addr),
+ LENHOSTNAME);
+ currenthostisnum = TRUE;
} else {
strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
- temphost[LENHOSTNAME-1] = '\0';
+ currenthostisnum = FALSE;
}
+ temphost[LENHOSTNAME-1] = '\0';
if (debug > 2)
- printf("Opening host %s\n", temphost);
+ printf("Opening host %s\n", temphost);
if (havehost == 1) {
if (debug > 2)
- printf("Closing old host %s\n", currenthost);
+ printf("Closing old host %s\n", currenthost);
(void) closesocket(sockfd);
havehost = 0;
}
@@ -744,9 +727,13 @@ openhost(
int optionValue = SO_SYNCHRONOUS_NONALERT;
int err;
- err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
- if (err != NO_ERROR) {
- (void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
+ err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
+ (char *)&optionValue, sizeof(optionValue));
+ if (err) {
+ err = WSAGetLastError();
+ fprintf(stderr,
+ "setsockopt(SO_SYNCHRONOUS_NONALERT) "
+ "error: %s\n", strerror(err));
exit(1);
}
}
@@ -789,13 +776,12 @@ openhost(
*/
static int
sendpkt(
- char *xdata,
- int xdatalen
+ void * xdata,
+ size_t xdatalen
)
{
if (debug >= 3)
- printf("Sending %d octets\n", xdatalen);
-
+ printf("Sending %lu octets\n", (u_long)xdatalen);
if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
warning("write to %s failed", currenthost, "");
@@ -804,13 +790,15 @@ sendpkt(
if (debug >= 4) {
int first = 8;
+ char *cdata = xdata;
+
printf("Packet data:\n");
while (xdatalen-- > 0) {
if (first-- == 0) {
printf("\n");
first = 7;
}
- printf(" %02x", *xdata++ & 0xff);
+ printf(" %02x", *cdata++ & 0xff);
}
printf("\n");
}
@@ -828,20 +816,26 @@ getresponse(
int associd,
u_short *rstatus,
int *rsize,
- char **rdata,
+ const char **rdata,
int timeo
)
{
struct ntp_control rpkt;
- struct timeval tvo;
+ struct sock_timeval tvo;
u_short offsets[MAXFRAGS+1];
u_short counts[MAXFRAGS+1];
u_short offset;
u_short count;
- int numfrags;
+ size_t numfrags;
+ size_t f;
+ size_t ff;
int seenlastfrag;
+ int shouldbesize;
fd_set fds;
int n;
+ int len;
+ int first;
+ char *data;
/*
* This is pretty tricky. We may get between 1 and MAXFRAG packets
@@ -852,7 +846,7 @@ getresponse(
*/
*rsize = 0;
if (rstatus)
- *rstatus = 0;
+ *rstatus = 0;
*rdata = (char *)pktdata;
numfrags = 0;
@@ -860,305 +854,342 @@ getresponse(
FD_ZERO(&fds);
- again:
- if (numfrags == 0)
- tvo = tvout;
- else
- tvo = tvsout;
-
- FD_SET(sockfd, &fds);
- n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
+ /*
+ * Loop until we have an error or a complete response. Nearly all
+ * code paths to loop again use continue.
+ */
+ for (;;) {
-#if 0
- if (debug >= 1)
- printf("select() returns %d\n", n);
-#endif
+ if (numfrags == 0)
+ tvo = tvout;
+ else
+ tvo = tvsout;
+
+ FD_SET(sockfd, &fds);
+ n = select(sockfd + 1, &fds, NULL, NULL, &tvo);
- if (n == -1) {
- warning("select fails", "", "");
- return -1;
- }
- if (n == 0) {
- /*
- * Timed out. Return what we have
- */
- if (numfrags == 0) {
- if (timeo)
- (void) fprintf(stderr,
- "%s: timed out, nothing received\n",
- currenthost);
- return ERR_TIMEOUT;
- } else {
+ if (n == -1) {
+ warning("select fails", "", "");
+ return -1;
+ }
+ if (n == 0) {
+ /*
+ * Timed out. Return what we have
+ */
+ if (numfrags == 0) {
+ if (timeo)
+ fprintf(stderr,
+ "%s: timed out, nothing received\n",
+ currenthost);
+ return ERR_TIMEOUT;
+ }
if (timeo)
- (void) fprintf(stderr,
- "%s: timed out with incomplete data\n",
- currenthost);
+ fprintf(stderr,
+ "%s: timed out with incomplete data\n",
+ currenthost);
if (debug) {
- printf("Received fragments:\n");
- for (n = 0; n < numfrags; n++)
- printf("%4d %d\n", offsets[n],
- counts[n]);
- if (seenlastfrag)
- printf("last fragment received\n");
- else
- printf("last fragment not received\n");
+ fprintf(stderr,
+ "ERR_INCOMPLETE: Received fragments:\n");
+ for (f = 0; f < numfrags; f++)
+ fprintf(stderr,
+ "%2u: %5d %5d\t%3d octets\n",
+ f, offsets[f],
+ offsets[f] +
+ counts[f],
+ counts[f]);
+ fprintf(stderr,
+ "last fragment %sreceived\n",
+ (seenlastfrag)
+ ? ""
+ : "not ");
}
return ERR_INCOMPLETE;
}
- }
- n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
- if (n == -1) {
- warning("read", "", "");
- return -1;
- }
+ n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
+ if (n == -1) {
+ warning("read", "", "");
+ return -1;
+ }
- if (debug >= 4) {
- int len = n, first = 8;
- char *data = (char *)&rpkt;
+ if (debug >= 4) {
+ len = n;
+ first = 8;
+ data = (char *)&rpkt;
- printf("Packet data:\n");
- while (len-- > 0) {
- if (first-- == 0) {
- printf("\n");
- first = 7;
+ printf("Packet data:\n");
+ while (len-- > 0) {
+ if (first-- == 0) {
+ printf("\n");
+ first = 7;
+ }
+ printf(" %02x", *data++ & 0xff);
}
- printf(" %02x", *data++ & 0xff);
+ printf("\n");
}
- printf("\n");
- }
- /*
- * Check for format errors. Bug proofing.
- */
- if (n < CTL_HEADER_LEN) {
- if (debug)
- printf("Short (%d byte) packet received\n", n);
- goto again;
- }
- if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
- || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
- if (debug)
- printf("Packet received with version %d\n",
- PKT_VERSION(rpkt.li_vn_mode));
- goto again;
- }
- if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
- if (debug)
- printf("Packet received with mode %d\n",
- PKT_MODE(rpkt.li_vn_mode));
- goto again;
- }
- if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
- if (debug)
- printf("Received request packet, wanted response\n");
- goto again;
- }
+ /*
+ * Check for format errors. Bug proofing.
+ */
+ if (n < CTL_HEADER_LEN) {
+ if (debug)
+ printf("Short (%d byte) packet received\n", n);
+ continue;
+ }
+ if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
+ || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
+ if (debug)
+ printf("Packet received with version %d\n",
+ PKT_VERSION(rpkt.li_vn_mode));
+ continue;
+ }
+ if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
+ if (debug)
+ printf("Packet received with mode %d\n",
+ PKT_MODE(rpkt.li_vn_mode));
+ continue;
+ }
+ if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
+ if (debug)
+ printf("Received request packet, wanted response\n");
+ continue;
+ }
- /*
- * Check opcode and sequence number for a match.
- * Could be old data getting to us.
- */
- if (ntohs(rpkt.sequence) != sequence) {
- if (debug)
- printf(
- "Received sequnce number %d, wanted %d\n",
- ntohs(rpkt.sequence), sequence);
- goto again;
- }
- if (CTL_OP(rpkt.r_m_e_op) != opcode) {
- if (debug)
- printf(
- "Received opcode %d, wanted %d (sequence number okay)\n",
- CTL_OP(rpkt.r_m_e_op), opcode);
- goto again;
- }
+ /*
+ * Check opcode and sequence number for a match.
+ * Could be old data getting to us.
+ */
+ if (ntohs(rpkt.sequence) != sequence) {
+ if (debug)
+ printf("Received sequnce number %d, wanted %d\n",
+ ntohs(rpkt.sequence), sequence);
+ continue;
+ }
+ if (CTL_OP(rpkt.r_m_e_op) != opcode) {
+ if (debug)
+ printf(
+ "Received opcode %d, wanted %d (sequence number okay)\n",
+ CTL_OP(rpkt.r_m_e_op), opcode);
+ continue;
+ }
- /*
- * Check the error code. If non-zero, return it.
- */
- if (CTL_ISERROR(rpkt.r_m_e_op)) {
- int errcode;
+ /*
+ * Check the error code. If non-zero, return it.
+ */
+ if (CTL_ISERROR(rpkt.r_m_e_op)) {
+ int errcode;
- errcode = (ntohs(rpkt.status) >> 8) & 0xff;
- if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
- printf("Error code %d received on not-final packet\n",
- errcode);
+ errcode = (ntohs(rpkt.status) >> 8) & 0xff;
+ if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
+ printf("Error code %d received on not-final packet\n",
+ errcode);
+ }
+ if (errcode == CERR_UNSPEC)
+ return ERR_UNSPEC;
+ return errcode;
}
- if (errcode == CERR_UNSPEC)
- return ERR_UNSPEC;
- return errcode;
- }
- /*
- * Check the association ID to make sure it matches what
- * we sent.
- */
- if (ntohs(rpkt.associd) != associd) {
- if (debug)
- printf("Association ID %d doesn't match expected %d\n",
- ntohs(rpkt.associd), associd);
/*
- * Hack for silly fuzzballs which, at the time of writing,
- * return an assID of sys.peer when queried for system variables.
+ * Check the association ID to make sure it matches what
+ * we sent.
*/
+ if (ntohs(rpkt.associd) != associd) {
+ if (debug)
+ printf("Association ID %d doesn't match expected %d\n",
+ ntohs(rpkt.associd), associd);
+ /*
+ * Hack for silly fuzzballs which, at the time of writing,
+ * return an assID of sys.peer when queried for system variables.
+ */
#ifdef notdef
- goto again;
+ continue;
#endif
- }
-
- /*
- * Collect offset and count. Make sure they make sense.
- */
- offset = ntohs(rpkt.offset);
- count = ntohs(rpkt.count);
+ }
- if (debug >= 3) {
- int shouldbesize;
- u_long key;
- u_long *lpkt;
- int maclen;
+ /*
+ * Collect offset and count. Make sure they make sense.
+ */
+ offset = ntohs(rpkt.offset);
+ count = ntohs(rpkt.count);
/*
- * Usually we ignore authentication, but for debugging purposes
- * we watch it here.
+ * validate received payload size is padded to next 32-bit
+ * boundary and no smaller than claimed by rpkt.count
*/
- shouldbesize = CTL_HEADER_LEN + count;
+ if (n & 0x3) {
+ if (debug)
+ printf("Response packet not padded, "
+ "size = %d\n", n);
+ continue;
+ }
- /* round to 8 octet boundary */
- shouldbesize = (shouldbesize + 7) & ~7;
+ shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
- if (n & 0x3) {
- printf("Packet not padded, size = %d\n", n);
- } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) {
- printf(
- "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
- n, shouldbesize, maclen);
- lpkt = (u_long *)&rpkt;
- printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2]));
- key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]);
- printf("Authenticated with keyid %lu\n", (u_long)key);
- if (key != 0 && key != info_auth_keyid) {
- printf("We don't know that key\n");
- } else {
- if (authdecrypt(key, (u_int32 *)&rpkt,
- n - maclen, maclen)) {
- printf("Auth okay!\n");
+ if (n < shouldbesize) {
+ printf("Response packet claims %u octets "
+ "payload, above %d received\n",
+ count,
+ n - CTL_HEADER_LEN
+ );
+ return ERR_INCOMPLETE;
+ }
+
+ if (debug >= 3 && shouldbesize > n) {
+ u_int32 key;
+ u_int32 *lpkt;
+ int maclen;
+
+ /*
+ * Usually we ignore authentication, but for debugging purposes
+ * we watch it here.
+ */
+ /* round to 8 octet boundary */
+ shouldbesize = (shouldbesize + 7) & ~7;
+
+ maclen = n - shouldbesize;
+ if (maclen >= MIN_MAC_LEN) {
+ printf(
+ "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
+ n, shouldbesize, maclen);
+ lpkt = (u_int32 *)&rpkt;
+ printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
+ (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
+ key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
+ printf("Authenticated with keyid %lu\n", (u_long)key);
+ if (key != 0 && key != info_auth_keyid) {
+ printf("We don't know that key\n");
} else {
- printf("Auth failed!\n");
+ if (authdecrypt(key, (u_int32 *)&rpkt,
+ n - maclen, maclen)) {
+ printf("Auth okay!\n");
+ } else {
+ printf("Auth failed!\n");
+ }
}
}
}
- }
- if (debug >= 2)
- printf("Got packet, size = %d\n", n);
- if (count > (u_short)(n-CTL_HEADER_LEN)) {
- if (debug)
- printf(
- "Received count of %d octets, data in packet is %d\n",
- count, n-CTL_HEADER_LEN);
- goto again;
- }
- if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
- if (debug)
- printf("Received count of 0 in non-final fragment\n");
- goto again;
- }
- if (offset + count > sizeof(pktdata)) {
- if (debug)
- printf("Offset %d, count %d, too big for buffer\n",
- offset, count);
- return ERR_TOOMUCH;
- }
- if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
- if (debug)
- printf("Received second last fragment packet\n");
- goto again;
- }
+ if (debug >= 2)
+ printf("Got packet, size = %d\n", n);
+ if ((int)count > (n - CTL_HEADER_LEN)) {
+ if (debug)
+ printf("Received count of %d octets, "
+ "data in packet is %d\n",
+ count, n-CTL_HEADER_LEN);
+ continue;
+ }
+ if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
+ if (debug)
+ printf("Received count of 0 in non-final fragment\n");
+ continue;
+ }
+ if (offset + count > sizeof(pktdata)) {
+ if (debug)
+ printf("Offset %d, count %d, too big for buffer\n",
+ offset, count);
+ return ERR_TOOMUCH;
+ }
+ if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
+ if (debug)
+ printf("Received second last fragment packet\n");
+ continue;
+ }
- /*
- * So far, so good. Record this fragment, making sure it doesn't
- * overlap anything.
- */
- if (debug >= 2)
- printf("Packet okay\n");;
+ /*
+ * So far, so good. Record this fragment, making sure it doesn't
+ * overlap anything.
+ */
+ if (debug >= 2)
+ printf("Packet okay\n");;
+
+ if (numfrags > (MAXFRAGS - 1)) {
+ if (debug)
+ printf("Number of fragments exceeds maximum %d\n",
+ MAXFRAGS - 1);
+ return ERR_TOOMUCH;
+ }
- if (numfrags == MAXFRAGS) {
- if (debug)
- printf("Number of fragments exceeds maximum\n");
- return ERR_TOOMUCH;
- }
-
- for (n = 0; n < numfrags; n++) {
- if (offset == offsets[n])
- goto again; /* duplicate */
- if (offset < offsets[n])
- break;
- }
-
- if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset)
- goto overlap;
- if (n < numfrags && (u_short)(offset + count) > offsets[n])
- goto overlap;
-
- {
- register int i;
-
- for (i = numfrags; i > n; i--) {
- offsets[i] = offsets[i-1];
- counts[i] = counts[i-1];
+ /*
+ * Find the position for the fragment relative to any
+ * previously received.
+ */
+ for (f = 0;
+ f < numfrags && offsets[f] < offset;
+ f++) {
+ /* empty body */ ;
}
- }
- offsets[n] = offset;
- counts[n] = count;
- numfrags++;
- /*
- * Got that stuffed in right. Figure out if this was the last.
- * Record status info out of the last packet.
- */
- if (!CTL_ISMORE(rpkt.r_m_e_op)) {
- seenlastfrag = 1;
- if (rstatus != 0)
- *rstatus = ntohs(rpkt.status);
- }
+ if (f < numfrags && offset == offsets[f]) {
+ if (debug)
+ printf("duplicate %u octets at %u ignored, prior %u at %u\n",
+ count, offset, counts[f],
+ offsets[f]);
+ continue;
+ }
- /*
- * Copy the data into the data buffer.
- */
- memmove((char *)pktdata + offset, (char *)rpkt.data, count);
+ if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
+ if (debug)
+ printf("received frag at %u overlaps with %u octet frag at %u\n",
+ offset, counts[f-1],
+ offsets[f-1]);
+ continue;
+ }
- /*
- * If we've seen the last fragment, look for holes in the sequence.
- * If there aren't any, we're done.
- */
- if (seenlastfrag && offsets[0] == 0) {
- for (n = 1; n < numfrags; n++) {
- if (offsets[n-1] + counts[n-1] != offsets[n])
- break;
+ if (f < numfrags && (offset + count) > offsets[f]) {
+ if (debug)
+ printf("received %u octet frag at %u overlaps with frag at %u\n",
+ count, offset, offsets[f]);
+ continue;
}
- if (n == numfrags) {
- *rsize = offsets[numfrags-1] + counts[numfrags-1];
- return 0;
+
+ for (ff = numfrags; ff > f; ff--) {
+ offsets[ff] = offsets[ff-1];
+ counts[ff] = counts[ff-1];
}
- }
- goto again;
+ offsets[f] = offset;
+ counts[f] = count;
+ numfrags++;
- overlap:
- /*
- * Print debugging message about overlapping fragments
- */
- if (debug)
- printf("Overlapping fragments returned in response\n");
- goto again;
-}
+ /*
+ * Got that stuffed in right. Figure out if this was the last.
+ * Record status info out of the last packet.
+ */
+ if (!CTL_ISMORE(rpkt.r_m_e_op)) {
+ seenlastfrag = 1;
+ if (rstatus != 0)
+ *rstatus = ntohs(rpkt.status);
+ }
+
+ /*
+ * Copy the data into the data buffer.
+ */
+ memcpy((char *)pktdata + offset, rpkt.data, count);
+
+ /*
+ * If we've seen the last fragment, look for holes in the sequence.
+ * If there aren't any, we're done.
+ */
+ if (seenlastfrag && offsets[0] == 0) {
+ for (f = 1; f < numfrags; f++)
+ if (offsets[f-1] + counts[f-1] !=
+ offsets[f])
+ break;
+ if (f == numfrags) {
+ *rsize = offsets[f-1] + counts[f-1];
+ if (debug)
+ fprintf(stderr,
+ "%u packets reassembled into response\n",
+ numfrags);
+ return 0;
+ }
+ }
+ } /* giant for (;;) collecting response packets */
+} /* getresponse() */
/*
@@ -1174,15 +1205,18 @@ sendrequest(
)
{
struct ntp_control qpkt;
- int pktsize;
+ int pktsize;
+ u_long key_id;
+ char * pass;
+ int maclen;
/*
* Check to make sure the data will fit in one packet
*/
if (qsize > CTL_MAX_DATA_LEN) {
- (void) fprintf(stderr,
- "***Internal error! qsize (%d) too large\n",
- qsize);
+ fprintf(stderr,
+ "***Internal error! qsize (%d) too large\n",
+ qsize);
return 1;
}
@@ -1197,19 +1231,18 @@ sendrequest(
qpkt.offset = 0;
qpkt.count = htons((u_short)qsize);
+ pktsize = CTL_HEADER_LEN;
+
/*
- * If we have data, copy it in and pad it out to a 64
- * bit boundary.
+ * If we have data, copy and pad it out to a 32-bit boundary.
*/
if (qsize > 0) {
- memmove((char *)qpkt.data, qdata, (unsigned)qsize);
- pktsize = qsize + CTL_HEADER_LEN;
- while (pktsize & (sizeof(u_long) - 1)) {
+ memcpy(qpkt.data, qdata, (size_t)qsize);
+ pktsize += qsize;
+ while (pktsize & (sizeof(u_int32) - 1)) {
qpkt.data[qsize++] = 0;
pktsize++;
}
- } else {
- pktsize = CTL_HEADER_LEN;
}
/*
@@ -1217,76 +1250,167 @@ sendrequest(
* we're going to have to think about it a little.
*/
if (!auth && !always_auth) {
- return sendpkt((char *)&qpkt, pktsize);
- } else {
- const char *pass = "\0";
- int maclen = 0;
- u_long my_keyid;
+ return sendpkt(&qpkt, pktsize);
+ }
- /*
- * Pad out packet to a multiple of 8 octets to be sure
- * receiver can handle it.
- */
- while (pktsize & 7) {
- qpkt.data[qsize++] = 0;
- pktsize++;
- }
+ /*
+ * Pad out packet to a multiple of 8 octets to be sure
+ * receiver can handle it.
+ */
+ while (pktsize & 7) {
+ qpkt.data[qsize++] = 0;
+ pktsize++;
+ }
- /*
- * Get the keyid and the password if we don't have one.
- */
- if (info_auth_keyid == 0) {
- int u_keyid = getkeyid("Keyid: ");
- if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
- (void) fprintf(stderr,
- "Invalid key identifier\n");
- return 1;
- }
- info_auth_keyid = u_keyid;
+ /*
+ * Get the keyid and the password if we don't have one.
+ */
+ if (info_auth_keyid == 0) {
+ key_id = getkeyid("Keyid: ");
+ if (key_id == 0 || key_id > NTP_MAXKEY) {
+ fprintf(stderr,
+ "Invalid key identifier\n");
+ return 1;
}
- if (!authistrusted(info_auth_keyid)) {
- pass = getpass("MD5 Password: ");
- if (*pass == '\0') {
- (void) fprintf(stderr,
- "Invalid password\n");
- return (1);
- }
+ info_auth_keyid = key_id;
+ }
+ if (!authistrusted(info_auth_keyid)) {
+ pass = getpass_keytype(info_auth_keytype);
+ if ('\0' == pass[0]) {
+ fprintf(stderr, "Invalid password\n");
+ return 1;
}
- authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
+ authusekey(info_auth_keyid, info_auth_keytype,
+ (u_char *)pass);
authtrust(info_auth_keyid, 1);
+ }
- /*
- * Stick the keyid in the packet where
- * cp currently points. Cp should be aligned
- * properly. Then do the encryptions.
- */
- my_keyid = htonl(info_auth_keyid);
- memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid);
- maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
- pktsize);
- if (maclen == 0) {
- (void) fprintf(stderr, "Key not found\n");
- return (1);
- }
- return sendpkt((char *)&qpkt, pktsize + maclen);
+ /*
+ * Do the encryption.
+ */
+ maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
+ if (!maclen) {
+ fprintf(stderr, "Key not found\n");
+ return 1;
+ } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
+ fprintf(stderr,
+ "%d octet MAC, %lu expected with %lu octet digest\n",
+ maclen, (u_long)(info_auth_hashlen + sizeof(keyid_t)),
+ (u_long)info_auth_hashlen);
+ return 1;
}
- /*NOTREACHED*/
+
+ return sendpkt((char *)&qpkt, pktsize + maclen);
}
/*
- * doquery - send a request and process the response
+ * show_error_msg - display the error text for a mode 6 error response.
+ */
+void
+show_error_msg(
+ int m6resp,
+ associd_t associd
+ )
+{
+ if (numhosts > 1)
+ fprintf(stderr, "server=%s ", currenthost);
+
+ switch(m6resp) {
+
+ case CERR_BADFMT:
+ fprintf(stderr,
+ "***Server reports a bad format request packet\n");
+ break;
+
+ case CERR_PERMISSION:
+ fprintf(stderr,
+ "***Server disallowed request (authentication?)\n");
+ break;
+
+ case CERR_BADOP:
+ fprintf(stderr,
+ "***Server reports a bad opcode in request\n");
+ break;
+
+ case CERR_BADASSOC:
+ fprintf(stderr,
+ "***Association ID %d unknown to server\n",
+ associd);
+ break;
+
+ case CERR_UNKNOWNVAR:
+ fprintf(stderr,
+ "***A request variable unknown to the server\n");
+ break;
+
+ case CERR_BADVALUE:
+ fprintf(stderr,
+ "***Server indicates a request variable was bad\n");
+ break;
+
+ case ERR_UNSPEC:
+ fprintf(stderr,
+ "***Server returned an unspecified error\n");
+ break;
+
+ case ERR_TIMEOUT:
+ fprintf(stderr, "***Request timed out\n");
+ break;
+
+ case ERR_INCOMPLETE:
+ fprintf(stderr,
+ "***Response from server was incomplete\n");
+ break;
+
+ case ERR_TOOMUCH:
+ fprintf(stderr,
+ "***Buffer size exceeded for returned data\n");
+ break;
+
+ default:
+ fprintf(stderr,
+ "***Server returns unknown error code %d\n",
+ m6resp);
+ }
+}
+
+/*
+ * doquery - send a request and process the response, displaying
+ * error messages for any error responses.
*/
int
doquery(
int opcode,
- int associd,
+ associd_t associd,
int auth,
int qsize,
char *qdata,
u_short *rstatus,
int *rsize,
- char **rdata
+ const char **rdata
+ )
+{
+ return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
+ rsize, rdata, FALSE);
+}
+
+
+/*
+ * doqueryex - send a request and process the response, optionally
+ * displaying error messages for any error responses.
+ */
+int
+doqueryex(
+ int opcode,
+ associd_t associd,
+ int auth,
+ int qsize,
+ char *qdata,
+ u_short *rstatus,
+ int *rsize,
+ const char **rdata,
+ int quiet
)
{
int res;
@@ -1296,7 +1420,7 @@ doquery(
* Check to make sure host is open
*/
if (!havehost) {
- (void) fprintf(stderr, "***No host open, use `host' command\n");
+ fprintf(stderr, "***No host open, use `host' command\n");
return -1;
}
@@ -1309,7 +1433,7 @@ doquery(
*/
res = sendrequest(opcode, associd, auth, qsize, qdata);
if (res != 0)
- return res;
+ return res;
/*
* Get the response. If we got a standard error, print a message
@@ -1328,94 +1452,40 @@ doquery(
done = 1;
goto again;
}
- if (numhosts > 1)
- (void) fprintf(stderr, "server=%s ", currenthost);
- switch(res) {
- case CERR_BADFMT:
- (void) fprintf(stderr,
- "***Server reports a bad format request packet\n");
- break;
- case CERR_PERMISSION:
- (void) fprintf(stderr,
- "***Server disallowed request (authentication?)\n");
- break;
- case CERR_BADOP:
- (void) fprintf(stderr,
- "***Server reports a bad opcode in request\n");
- break;
- case CERR_BADASSOC:
- (void) fprintf(stderr,
- "***Association ID %d unknown to server\n",associd);
- break;
- case CERR_UNKNOWNVAR:
- (void) fprintf(stderr,
- "***A request variable unknown to the server\n");
- break;
- case CERR_BADVALUE:
- (void) fprintf(stderr,
- "***Server indicates a request variable was bad\n");
- break;
- case ERR_UNSPEC:
- (void) fprintf(stderr,
- "***Server returned an unspecified error\n");
- break;
- case ERR_TIMEOUT:
- (void) fprintf(stderr, "***Request timed out\n");
- break;
- case ERR_INCOMPLETE:
- (void) fprintf(stderr,
- "***Response from server was incomplete\n");
- break;
- case ERR_TOOMUCH:
- (void) fprintf(stderr,
- "***Buffer size exceeded for returned data\n");
- break;
- default:
- (void) fprintf(stderr,
- "***Server returns unknown error code %d\n", res);
- break;
- }
+ if (!quiet)
+ show_error_msg(res, associd);
+
}
return res;
}
+#ifndef BUILD_AS_LIB
/*
* getcmds - read commands from the standard input and execute them
*/
static void
getcmds(void)
{
-#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
- char *line;
-
- for (;;) {
- if ((line = readline(interactive?prompt:"")) == NULL) return;
- if (*line) add_history(line);
- docmd(line);
- free(line);
- }
-#else /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
- char line[MAXLINE];
-
- for (;;) {
- if (interactive) {
-#ifdef VMS /* work around a problem with mixing stdout & stderr */
- fputs("",stdout);
-#endif
- (void) fputs(prompt, stderr);
- (void) fflush(stderr);
- }
+ char * line;
+ int count;
- if (fgets(line, sizeof line, stdin) == NULL)
- return;
+ ntp_readline_init(interactive ? prompt : NULL);
+
+ for (;;) {
+ line = ntp_readline(&count);
+ if (NULL == line)
+ break;
+ docmd(line);
+ free(line);
+ }
- docmd(line);
- }
-#endif /* not (HAVE_LIBREADLINE || HAVE_LIBEDIT) */
+ ntp_readline_uninit();
}
+#endif /* !BUILD_AS_LIB */
-#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
+
+#if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
/*
* abortcmd - catch interrupts and abort the current command
*/
@@ -1430,8 +1500,10 @@ abortcmd(
(void) fflush(stderr);
if (jump) longjmp(interrupt_buf, 1);
}
-#endif /* SYS_WINNT */
+#endif /* !SYS_WINNT && !BUILD_AS_LIB */
+
+#ifndef BUILD_AS_LIB
/*
* docmd - decode the command line and execute a command
*/
@@ -1482,9 +1554,9 @@ docmd(
break;
}
if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
- break;
+ break;
if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
- return;
+ return;
pcmd.nargs++;
}
@@ -1493,9 +1565,9 @@ docmd(
char *fname;
if (*(tokens[i]+1) != '\0')
- fname = tokens[i]+1;
+ fname = tokens[i]+1;
else if ((i+1) < ntok)
- fname = tokens[i+1];
+ fname = tokens[i+1];
else {
(void) fprintf(stderr, "***No file for redirect\n");
return;
@@ -1527,7 +1599,13 @@ docmd(
/*
* tokenize - turn a command line into tokens
+ *
+ * SK: Modified to allow a quoted string
+ *
+ * HMS: If the first character of the first token is a ':' then (after
+ * eating inter-token whitespace) the 2nd token is the rest of the line.
*/
+
static void
tokenize(
const char *line,
@@ -1543,84 +1621,44 @@ tokenize(
cp = line;
for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
tokens[*ntok] = sp;
+
+ /* Skip inter-token whitespace */
while (ISSPACE(*cp))
cp++;
+
+ /* If we're at EOL we're done */
if (ISEOL(*cp))
break;
- do {
- *sp++ = *cp++;
- } while (!ISSPACE(*cp) && !ISEOL(*cp));
-
- *sp++ = '\0';
- }
-}
-
-
-
-/*
- * findcmd - find a command in a command description table
- */
-static int
-findcmd(
- register char *str,
- struct xcmd *clist1,
- struct xcmd *clist2,
- struct xcmd **cmd
- )
-{
- register struct xcmd *cl;
- register int clen;
- int nmatch;
- struct xcmd *nearmatch = NULL;
- struct xcmd *clist;
- clen = strlen(str);
- nmatch = 0;
- if (clist1 != 0)
- clist = clist1;
- else if (clist2 != 0)
- clist = clist2;
- else
- return 0;
+ /* If this is the 2nd token and the first token begins
+ * with a ':', then just grab to EOL.
+ */
- again:
- for (cl = clist; cl->keyword != 0; cl++) {
- /* do a first character check, for efficiency */
- if (*str != *(cl->keyword))
- continue;
- if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
- /*
- * Could be extact match, could be approximate.
- * Is exact if the length of the keyword is the
- * same as the str.
- */
- if (*((cl->keyword) + clen) == '\0') {
- *cmd = cl;
- return 1;
- }
- nmatch++;
- nearmatch = cl;
+ if (*ntok == 1 && tokens[0][0] == ':') {
+ do {
+ *sp++ = *cp++;
+ } while (!ISEOL(*cp));
}
- }
- /*
- * See if there is more to do. If so, go again. Sorry about the
- * goto, too much looking at BSD sources...
- */
- if (clist == clist1 && clist2 != 0) {
- clist = clist2;
- goto again;
- }
+ /* Check if this token begins with a double quote.
+ * If yes, continue reading till the next double quote
+ */
+ else if (*cp == '\"') {
+ ++cp;
+ do {
+ *sp++ = *cp++;
+ } while ((*cp != '\"') && !ISEOL(*cp));
+ /* HMS: a missing closing " should be an error */
+ }
+ else {
+ do {
+ *sp++ = *cp++;
+ } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
+ /* HMS: Why check for a " in the previous line? */
+ }
- /*
- * If we got extactly 1 near match, use it, else return number
- * of matches.
- */
- if (nmatch == 1) {
- *cmd = nearmatch;
- return 1;
+ *sp++ = '\0';
}
- return nmatch;
}
@@ -1714,6 +1752,74 @@ getarg(
return 1;
}
+#endif /* !BUILD_AS_LIB */
+
+
+/*
+ * findcmd - find a command in a command description table
+ */
+static int
+findcmd(
+ register char *str,
+ struct xcmd *clist1,
+ struct xcmd *clist2,
+ struct xcmd **cmd
+ )
+{
+ register struct xcmd *cl;
+ register int clen;
+ int nmatch;
+ struct xcmd *nearmatch = NULL;
+ struct xcmd *clist;
+
+ clen = strlen(str);
+ nmatch = 0;
+ if (clist1 != 0)
+ clist = clist1;
+ else if (clist2 != 0)
+ clist = clist2;
+ else
+ return 0;
+
+ again:
+ for (cl = clist; cl->keyword != 0; cl++) {
+ /* do a first character check, for efficiency */
+ if (*str != *(cl->keyword))
+ continue;
+ if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
+ /*
+ * Could be extact match, could be approximate.
+ * Is exact if the length of the keyword is the
+ * same as the str.
+ */
+ if (*((cl->keyword) + clen) == '\0') {
+ *cmd = cl;
+ return 1;
+ }
+ nmatch++;
+ nearmatch = cl;
+ }
+ }
+
+ /*
+ * See if there is more to do. If so, go again. Sorry about the
+ * goto, too much looking at BSD sources...
+ */
+ if (clist == clist1 && clist2 != 0) {
+ clist = clist2;
+ goto again;
+ }
+
+ /*
+ * If we got extactly 1 near match, use it, else return number
+ * of matches.
+ */
+ if (nmatch == 1) {
+ *cmd = nearmatch;
+ return 1;
+ }
+ return nmatch;
+}
/*
@@ -1723,41 +1829,47 @@ getarg(
int
getnetnum(
const char *hname,
- struct sockaddr_storage *num,
+ sockaddr_u *num,
char *fullhost,
int af
)
{
- int sockaddr_len;
struct addrinfo hints, *ai = NULL;
- sockaddr_len = (af == AF_INET)
- ? sizeof(struct sockaddr_in)
- : sizeof(struct sockaddr_in6);
- memset((char *)&hints, 0, sizeof(struct addrinfo));
+ ZERO(hints);
hints.ai_flags = AI_CANONNAME;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif
- /* decodenetnum works with addresses only */
+ /*
+ * decodenetnum only works with addresses, but handles syntax
+ * that getaddrinfo doesn't: [2001::1]:1234
+ */
if (decodenetnum(hname, num)) {
- if (fullhost != 0) {
- getnameinfo((struct sockaddr *)num, sockaddr_len,
- fullhost, sizeof(fullhost), NULL, 0,
- NI_NUMERICHOST);
- }
+ if (fullhost != NULL)
+ getnameinfo(&num->sa, SOCKLEN(num), fullhost,
+ LENHOSTNAME, NULL, 0, 0);
return 1;
} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
- memmove((char *)num, ai->ai_addr, ai->ai_addrlen);
- if (ai->ai_canonname != 0)
- (void) strcpy(fullhost, ai->ai_canonname);
+ NTP_INSIST(sizeof(*num) >= ai->ai_addrlen);
+ memcpy(num, ai->ai_addr, ai->ai_addrlen);
+ if (fullhost != NULL) {
+ if (ai->ai_canonname != NULL) {
+ strncpy(fullhost, ai->ai_canonname,
+ LENHOSTNAME);
+ fullhost[LENHOSTNAME - 1] = '\0';
+ } else {
+ getnameinfo(&num->sa, SOCKLEN(num),
+ fullhost, LENHOSTNAME, NULL,
+ 0, 0);
+ }
+ }
return 1;
- } else {
- (void) fprintf(stderr, "***Can't find host %s\n", hname);
- return 0;
}
- /*NOTREACHED*/
+ fprintf(stderr, "***Can't find host %s\n", hname);
+
+ return 0;
}
/*
@@ -1766,14 +1878,42 @@ getnetnum(
*/
char *
nntohost(
- struct sockaddr_storage *netnum
+ sockaddr_u *netnum
+ )
+{
+ return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
+}
+
+
+/*
+ * nntohost_col - convert network number to host name in fixed width.
+ * This routine enforces the showhostnames setting.
+ * When displaying hostnames longer than the width,
+ * the first part of the hostname is displayed. When
+ * displaying numeric addresses longer than the width,
+ * Such as IPv6 addresses, the caller decides whether
+ * the first or last of the numeric address is used.
+ */
+char *
+nntohost_col(
+ sockaddr_u * addr,
+ size_t width,
+ int preserve_lowaddrbits
)
{
- if (!showhostnames)
- return stoa(netnum);
- if ((netnum->ss_family == AF_INET) && ISREFCLOCKADR(netnum))
- return refnumtoa(netnum);
- return socktohost(netnum);
+ const char * out;
+
+ if (!showhostnames) {
+ if (preserve_lowaddrbits)
+ out = trunc_left(stoa(addr), width);
+ else
+ out = trunc_right(stoa(addr), width);
+ } else if (ISREFCLOCKADR(addr)) {
+ out = refnumtoa(addr);
+ } else {
+ out = trunc_right(socktohost(addr), width);
+ }
+ return out;
}
@@ -1913,24 +2053,26 @@ decodets(
l_fp *lfp
)
{
+ char *cp;
+ char buf[30];
+ size_t b;
+
/*
* If it starts with a 0x, decode as hex.
*/
if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
- return hextolfp(str+2, lfp);
+ return hextolfp(str+2, lfp);
/*
* If it starts with a '"', try it as an RT-11 date.
*/
if (*str == '"') {
- register char *cp = str+1;
- register char *bp;
- char buf[30];
-
- bp = buf;
- while (*cp != '"' && *cp != '\0' && bp < &buf[29])
- *bp++ = *cp++;
- *bp = '\0';
+ cp = str + 1;
+ b = 0;
+ while ('"' != *cp && '\0' != *cp &&
+ b < COUNTOF(buf) - 1)
+ buf[b++] = *cp++;
+ buf[b] = '\0';
return rtdatetolfp(buf, lfp);
}
@@ -1939,14 +2081,15 @@ decodets(
* about heuristics!
*/
if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
- return hextolfp(str, lfp);
+ return hextolfp(str, lfp);
/*
* Try it as a decimal. If this fails, try as an unquoted
* RT-11 date. This code should go away eventually.
*/
if (atolfp(str, lfp))
- return 1;
+ return 1;
+
return rtdatetolfp(str, lfp);
}
@@ -1975,8 +2118,8 @@ decodeint(
{
if (*str == '0') {
if (*(str+1) == 'x' || *(str+1) == 'X')
- return hextoint(str+2, val);
- return octtoint(str, val);
+ return hextoint(str+2, (u_long *)val);
+ return octtoint(str, (u_long *)val);
}
return atoint(str, val);
}
@@ -2051,61 +2194,55 @@ help(
FILE *fp
)
{
- struct xcmd *xcp;
+ struct xcmd *xcp = NULL; /* quiet warning */
char *cmd;
const char *list[100];
- int word, words;
- int row, rows;
- int col, cols;
+ size_t word, words;
+ size_t row, rows;
+ size_t col, cols;
+ size_t length;
if (pcmd->nargs == 0) {
words = 0;
- for (xcp = builtins; xcp->keyword != 0; xcp++) {
+ for (xcp = builtins; xcp->keyword != NULL; xcp++) {
if (*(xcp->keyword) != '?')
- list[words++] = xcp->keyword;
+ list[words++] = xcp->keyword;
}
- for (xcp = opcmds; xcp->keyword != 0; xcp++)
- list[words++] = xcp->keyword;
+ for (xcp = opcmds; xcp->keyword != NULL; xcp++)
+ list[words++] = xcp->keyword;
- qsort(
-#ifdef QSORT_USES_VOID_P
- (void *)
-#else
- (char *)
-#endif
- (list), (size_t)(words), sizeof(char *), helpsort);
+ qsort((void *)list, (size_t)words, sizeof(list[0]),
+ helpsort);
col = 0;
for (word = 0; word < words; word++) {
- int length = strlen(list[word]);
- if (col < length) {
- col = length;
- }
+ length = strlen(list[word]);
+ col = max(col, length);
}
cols = SCREENWIDTH / ++col;
- rows = (words + cols - 1) / cols;
+ rows = (words + cols - 1) / cols;
- (void) fprintf(fp, "ntpq commands:\n");
+ fprintf(fp, "ntpq commands:\n");
for (row = 0; row < rows; row++) {
- for (word = row; word < words; word += rows) {
- (void) fprintf(fp, "%-*.*s", col, col-1, list[word]);
- }
- (void) fprintf(fp, "\n");
- }
+ for (word = row; word < words; word += rows)
+ fprintf(fp, "%-*.*s", col, col-1,
+ list[word]);
+ fprintf(fp, "\n");
+ }
} else {
cmd = pcmd->argval[0].string;
words = findcmd(cmd, builtins, opcmds, &xcp);
if (words == 0) {
- (void) fprintf(stderr,
- "Command `%s' is unknown\n", cmd);
+ fprintf(stderr,
+ "Command `%s' is unknown\n", cmd);
return;
} else if (words >= 2) {
- (void) fprintf(stderr,
- "Command `%s' is ambiguous\n", cmd);
+ fprintf(stderr,
+ "Command `%s' is ambiguous\n", cmd);
return;
}
- (void) fprintf(fp, "function: %s\n", xcp->comment);
+ fprintf(fp, "function: %s\n", xcp->comment);
printusage(xcp, fp);
}
}
@@ -2114,29 +2251,18 @@ help(
/*
* helpsort - do hostname qsort comparisons
*/
-#ifdef QSORT_USES_VOID_P
static int
helpsort(
const void *t1,
const void *t2
)
{
- char const * const * name1 = (char const * const *)t1;
- char const * const * name2 = (char const * const *)t2;
+ const char * const * name1 = t1;
+ const char * const * name2 = t2;
return strcmp(*name1, *name2);
}
-#else
-static int
-helpsort(
- char **name1,
- char **name2
- )
-{
- return strcmp(*name1, *name2);
-}
-#endif
/*
* printusage - print usage information for a command
@@ -2172,11 +2298,11 @@ timeout(
int val;
if (pcmd->nargs == 0) {
- val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
+ val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
(void) fprintf(fp, "primary timeout %d ms\n", val);
} else {
tvout.tv_sec = pcmd->argval[0].uval / 1000;
- tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
+ tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
* 1000;
}
}
@@ -2229,9 +2355,10 @@ host(
if (pcmd->nargs == 0) {
if (havehost)
- (void) fprintf(fp, "current host is %s\n", currenthost);
+ (void) fprintf(fp, "current host is %s\n",
+ currenthost);
else
- (void) fprintf(fp, "no current host\n");
+ (void) fprintf(fp, "no current host\n");
return;
}
@@ -2245,7 +2372,8 @@ host(
else {
if (havehost)
(void) fprintf(fp,
- "current host remains %s\n", currenthost);
+ "current host remains %s\n",
+ currenthost);
else
(void) fprintf(fp, "still no current host\n");
return;
@@ -2257,10 +2385,11 @@ host(
numassoc = 0;
} else {
if (havehost)
- (void) fprintf(fp,
- "current host remains %s\n", currenthost);
+ (void) fprintf(fp,
+ "current host remains %s\n",
+ currenthost);
else
- (void) fprintf(fp, "still no current host\n");
+ (void) fprintf(fp, "still no current host\n");
}
}
@@ -2310,21 +2439,34 @@ keytype(
FILE *fp
)
{
- if (pcmd->nargs == 0)
- fprintf(fp, "keytype is %s\n",
- (info_auth_keytype == KEY_TYPE_MD5) ? "MD5" : "???");
- else
- switch (*(pcmd->argval[0].string)) {
- case 'm':
- case 'M':
- info_auth_keytype = KEY_TYPE_MD5;
- break;
+ const char * digest_name;
+ size_t digest_len;
+ int key_type;
+
+ if (!pcmd->nargs) {
+ fprintf(fp, "keytype is %s with %lu octet digests\n",
+ keytype_name(info_auth_keytype),
+ (u_long)info_auth_hashlen);
+ return;
+ }
- default:
- fprintf(fp, "keytype must be 'md5'\n");
- }
-}
+ digest_name = pcmd->argval[0].string;
+ digest_len = 0;
+ key_type = keytype_from_text(digest_name, &digest_len);
+ if (!key_type) {
+ fprintf(fp, "keytype must be 'md5'%s\n",
+#ifdef OPENSSL
+ " or a digest type provided by OpenSSL");
+#else
+ "");
+#endif
+ return;
+ }
+
+ info_auth_keytype = key_type;
+ info_auth_hashlen = digest_len;
+}
/*
@@ -2347,13 +2489,17 @@ passwd(
}
info_auth_keyid = u_keyid;
}
- pass = getpass("MD5 Password: ");
- if (*pass == '\0')
- (void) fprintf(fp, "Password unchanged\n");
+ if (pcmd->nargs >= 1)
+ pass = pcmd->argval[0].string;
else {
- authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
- authtrust(info_auth_keyid, 1);
+ pass = getpass_keytype(info_auth_keytype);
+ if ('\0' == pass[0]) {
+ fprintf(fp, "Password unchanged\n");
+ return;
+ }
}
+ authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
+ authtrust(info_auth_keyid, 1);
}
@@ -2562,29 +2708,28 @@ getkeyid(
const char *keyprompt
)
{
- register char *p;
- register int c;
+ int c;
FILE *fi;
char pbuf[20];
+ size_t i;
+ size_t ilim;
#ifndef SYS_WINNT
if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
#else
- if ((fi = _fdopen((int)GetStdHandle(STD_INPUT_HANDLE), "r")) == NULL)
+ if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
#endif /* SYS_WINNT */
fi = stdin;
- else
+ else
setbuf(fi, (char *)NULL);
fprintf(stderr, "%s", keyprompt); fflush(stderr);
- for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
- if (p < &pbuf[18])
- *p++ = (char)c;
- }
- *p = '\0';
+ for (i = 0, ilim = COUNTOF(pbuf) - 1;
+ i < ilim && (c = getc(fi)) != '\n' && c != EOF;
+ )
+ pbuf[i++] = (char)c;
+ pbuf[i] = '\0';
if (fi != stdin)
- fclose(fi);
- if (strcmp(pbuf, "0") == 0)
- return 0;
+ fclose(fi);
return (u_long) atoi(pbuf);
}
@@ -2596,82 +2741,93 @@ getkeyid(
*/
static void
atoascii(
- int length,
- char *data,
- char *outdata
+ const char *in,
+ size_t in_octets,
+ char *out,
+ size_t out_octets
)
{
- register u_char *cp;
- register u_char *ocp;
- register u_char c;
-
- if (!data)
- {
- *outdata = '\0';
+ register const u_char * pchIn;
+ const u_char * pchInLimit;
+ register u_char * pchOut;
+ register u_char c;
+
+ pchIn = (const u_char *)in;
+ pchInLimit = pchIn + in_octets;
+ pchOut = (u_char *)out;
+
+ if (NULL == pchIn) {
+ if (0 < out_octets)
+ *pchOut = '\0';
return;
}
- ocp = (u_char *)outdata;
- for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
- c = *cp;
- if (c == '\0')
- break;
- if (c == '\0')
- break;
- if (c > 0177) {
- *ocp++ = 'M';
- *ocp++ = '-';
- c &= 0177;
- }
+#define ONEOUT(c) \
+do { \
+ if (0 == --out_octets) { \
+ *pchOut = '\0'; \
+ return; \
+ } \
+ *pchOut++ = (c); \
+} while (0)
- if (c < ' ') {
- *ocp++ = '^';
- *ocp++ = (u_char)(c + '@');
- } else if (c == 0177) {
- *ocp++ = '^';
- *ocp++ = '?';
- } else {
- *ocp++ = c;
+ for ( ; pchIn < pchInLimit; pchIn++) {
+ c = *pchIn;
+ if ('\0' == c)
+ break;
+ if (c & 0x80) {
+ ONEOUT('M');
+ ONEOUT('-');
+ c &= 0x7f;
}
- if (ocp >= ((u_char *)outdata + length - 4))
- break;
+ if (c < ' ') {
+ ONEOUT('^');
+ ONEOUT((u_char)(c + '@'));
+ } else if (0x7f == c) {
+ ONEOUT('^');
+ ONEOUT('?');
+ } else
+ ONEOUT(c);
}
- *ocp++ = '\0';
-}
+ ONEOUT('\0');
+#undef ONEOUT
+}
/*
* makeascii - print possibly ascii data using the character
* transformations that cat -v uses.
*/
-static void
+void
makeascii(
int length,
- char *data,
+ const char *data,
FILE *fp
)
{
- register u_char *cp;
- register int c;
+ const u_char *data_u_char;
+ const u_char *cp;
+ int c;
+
+ data_u_char = (const u_char *)data;
- for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
+ for (cp = data_u_char; cp < data_u_char + length; cp++) {
c = (int)*cp;
- if (c > 0177) {
+ if (c & 0x80) {
putc('M', fp);
putc('-', fp);
- c &= 0177;
+ c &= 0x7f;
}
if (c < ' ') {
putc('^', fp);
- putc(c+'@', fp);
- } else if (c == 0177) {
+ putc(c + '@', fp);
+ } else if (0x7f == c) {
putc('^', fp);
putc('?', fp);
- } else {
+ } else
putc(c, fp);
- }
}
}
@@ -2692,6 +2848,62 @@ asciize(
/*
+ * truncate string to fit clipping excess at end.
+ * "too long" -> "too l"
+ * Used for hostnames.
+ */
+char *
+trunc_right(
+ const char * src,
+ size_t width
+ )
+{
+ size_t sl;
+ char * out;
+
+
+ sl = strlen(src);
+ if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
+ LIB_GETBUF(out);
+ memcpy(out, src, width);
+ out[width] = '\0';
+
+ return out;
+ }
+
+ return src;
+}
+
+
+/*
+ * truncate string to fit by preserving right side and using '_' to hint
+ * "too long" -> "_long"
+ * Used for local IPv6 addresses, where low bits differentiate.
+ */
+char *
+trunc_left(
+ const char * src,
+ size_t width
+ )
+{
+ size_t sl;
+ char * out;
+
+
+ sl = strlen(src);
+ if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
+ LIB_GETBUF(out);
+ out[0] = '_';
+ memcpy(&out[1], &src[sl + 1 - width], width);
+
+ return out;
+ }
+
+ return src;
+}
+
+
+/*
* Some circular buffer space
*/
#define CBLEN 80
@@ -2706,15 +2918,15 @@ int nextcb = 0;
int
nextvar(
int *datalen,
- char **datap,
+ const char **datap,
char **vname,
char **vvalue
)
{
- register char *cp;
- register char *np;
- register char *cpend;
- register char *npend; /* character after last */
+ const char *cp;
+ char *np;
+ const char *cpend;
+ char *npend; /* character after last */
int quoted = 0;
static char name[MAXVARLEN];
static char value[MAXVALLEN];
@@ -2726,9 +2938,9 @@ nextvar(
* Space past commas and white space
*/
while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
- cp++;
+ cp++;
if (cp == cpend)
- return 0;
+ return 0;
/*
* Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
@@ -2837,16 +3049,17 @@ findvar(
void
printvars(
int length,
- char *data,
+ const char *data,
int status,
int sttype,
+ int quiet,
FILE *fp
)
{
if (rawmode)
- rawprint(sttype, length, data, status, fp);
+ rawprint(sttype, length, data, status, quiet, fp);
else
- cookedprint(sttype, length, data, status, fp);
+ cookedprint(sttype, length, data, status, quiet, fp);
}
@@ -2857,13 +3070,14 @@ static void
rawprint(
int datatype,
int length,
- char *data,
+ const char *data,
int status,
+ int quiet,
FILE *fp
)
{
- register char *cp;
- register char *cpend;
+ const char *cp;
+ const char *cpend;
/*
* Essentially print the data as is. We reformat unprintables, though.
@@ -2871,7 +3085,8 @@ rawprint(
cp = data;
cpend = data + length;
- (void) fprintf(fp, "status=0x%04x,\n", status);
+ if (!quiet)
+ (void) fprintf(fp, "status=0x%04x,\n", status);
while (cp < cpend) {
if (*cp == '\r') {
@@ -2880,13 +3095,12 @@ rawprint(
* \n, supress this, else pretty print it. Otherwise
* just output the character.
*/
- if (cp == (cpend-1) || *(cp+1) != '\n')
+ if (cp == (cpend - 1) || *(cp + 1) != '\n')
makeascii(1, cp, fp);
- } else if (isspace((int)*cp) || isprint((int)*cp)) {
+ } else if (isspace(*cp) || isprint(*cp))
putc(*cp, fp);
- } else {
+ else
makeascii(1, cp, fp);
- }
cp++;
}
}
@@ -2920,32 +3134,27 @@ output(
char *value
)
{
- int lenname;
- int lenvalue;
+ size_t len;
- lenname = strlen(name);
- lenvalue = strlen(value);
+ /* strlen of "name=value" */
+ len = strlen(name) + 1 + strlen(value);
if (out_chars != 0) {
- putc(',', fp);
- out_chars++;
- out_linecount++;
- if ((out_linecount + lenname + lenvalue + 3) > MAXOUTLINE) {
- putc('\n', fp);
- out_chars++;
+ out_chars += 2;
+ if ((out_linecount + len + 2) > MAXOUTLINE) {
+ fputs(",\n", fp);
out_linecount = 0;
} else {
- putc(' ', fp);
- out_chars++;
- out_linecount++;
+ fputs(", ", fp);
+ out_linecount += 2;
}
}
fputs(name, fp);
putc('=', fp);
fputs(value, fp);
- out_chars += lenname + 1 + lenvalue;
- out_linecount += lenname + 1 + lenvalue;
+ out_chars += len;
+ out_linecount += len;
}
@@ -2958,7 +3167,7 @@ endoutput(
)
{
if (out_chars != 0)
- putc('\n', fp);
+ putc('\n', fp);
}
@@ -3012,33 +3221,44 @@ tstflags(
u_long val
)
{
- register char *cb, *s;
+ register char *cp, *s;
+ size_t cb;
register int i;
register const char *sep;
sep = "";
i = 0;
- s = cb = &circ_buf[nextcb][0];
+ s = cp = circ_buf[nextcb];
if (++nextcb >= NUMCB)
- nextcb = 0;
+ nextcb = 0;
+ cb = sizeof(circ_buf[0]);
- sprintf(cb, "%02lx", val);
- cb += strlen(cb);
+ snprintf(cp, cb, "%02lx", val);
+ cp += strlen(cp);
+ cb -= strlen(cp);
if (!val) {
- strcat(cb, " ok");
- cb += strlen(cb);
+ strncat(cp, " ok", cb);
+ cp += strlen(cp);
+ cb -= strlen(cp);
} else {
- *cb++ = ' ';
- for (i = 0; i < 13; i++) {
+ if (cb) {
+ *cp++ = ' ';
+ cb--;
+ }
+ for (i = 0; i < COUNTOF(tstflagnames); i++) {
if (val & 0x1) {
- sprintf(cb, "%s%s", sep, tstflagnames[i]);
+ snprintf(cp, cb, "%s%s", sep,
+ tstflagnames[i]);
sep = ", ";
- cb += strlen(cb);
+ cp += strlen(cp);
+ cb -= strlen(cp);
}
val >>= 1;
}
}
- *cb = '\0';
+ if (cb)
+ *cp = '\0';
+
return s;
}
@@ -3049,8 +3269,9 @@ static void
cookedprint(
int datatype,
int length,
- char *data,
+ const char *data,
int status,
+ int quiet,
FILE *fp
)
{
@@ -3062,28 +3283,30 @@ cookedprint(
struct ctl_var *varlist;
l_fp lfp;
long ival;
- struct sockaddr_storage hval;
+ sockaddr_u hval;
u_long uval;
l_fp lfparr[8];
int narr;
switch (datatype) {
- case TYPE_PEER:
+ case TYPE_PEER:
varlist = peer_var;
break;
- case TYPE_SYS:
+ case TYPE_SYS:
varlist = sys_var;
break;
- case TYPE_CLOCK:
+ case TYPE_CLOCK:
varlist = clock_var;
break;
- default:
- (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype);
+ default:
+ fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n",
+ datatype);
return;
}
- (void) fprintf(fp, "status=%04x %s,\n", status,
- statustoa(datatype, status));
+ if (!quiet)
+ fprintf(fp, "status=%04x %s,\n", status,
+ statustoa(datatype, status));
startoutput();
while (nextvar(&length, &data, &name, &value)) {
@@ -3154,8 +3377,7 @@ cookedprint(
case RF:
if (decodenetnum(value, &hval)) {
- if ((hval.ss_family == AF_INET) &&
- ISREFCLOCKADR(&hval))
+ if (ISREFCLOCKADR(&hval))
output(fp, name,
refnumtoa(&hval));
else
@@ -3226,8 +3448,8 @@ cookedprint(
char bv[401];
int len;
- atoascii(400, name, bn);
- atoascii(400, value, bv);
+ atoascii(name, MAXVARLEN, bn, sizeof(bn));
+ atoascii(value, MAXVARLEN, bv, sizeof(bv));
if (output_raw != '*') {
len = strlen(bv);
bv[len] = output_raw;
@@ -3247,47 +3469,59 @@ void
sortassoc(void)
{
if (numassoc > 1)
- qsort(
-#ifdef QSORT_USES_VOID_P
- (void *)
-#else
- (char *)
-#endif
- assoc_cache, (size_t)numassoc,
- sizeof(struct association), assoccmp);
+ qsort((void *)assoc_cache, (size_t)numassoc,
+ sizeof(assoc_cache[0]), assoccmp);
}
/*
* assoccmp - compare two associations
*/
-#ifdef QSORT_USES_VOID_P
static int
assoccmp(
const void *t1,
const void *t2
)
{
- const struct association *ass1 = (const struct association *)t1;
- const struct association *ass2 = (const struct association *)t2;
+ const struct association *ass1 = t1;
+ const struct association *ass2 = t2;
if (ass1->assid < ass2->assid)
- return -1;
+ return -1;
if (ass1->assid > ass2->assid)
- return 1;
+ return 1;
return 0;
}
-#else
-static int
-assoccmp(
- struct association *ass1,
- struct association *ass2
+
+
+/*
+ * ntpq_custom_opt_handler - autoopts handler for -c and -p
+ *
+ * By default, autoopts loses the relative order of -c and -p options
+ * on the command line. This routine replaces the default handler for
+ * those routines and builds a list of commands to execute preserving
+ * the order.
+ */
+void
+ntpq_custom_opt_handler(
+ tOptions *pOptions,
+ tOptDesc *pOptDesc
)
{
- if (ass1->assid < ass2->assid)
- return -1;
- if (ass1->assid > ass2->assid)
- return 1;
- return 0;
+ switch (pOptDesc->optValue) {
+
+ default:
+ fprintf(stderr,
+ "ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
+ pOptDesc->optValue, pOptDesc->optValue);
+ exit(-1);
+
+ case 'c':
+ ADDCMD(pOptDesc->pzLastArg);
+ break;
+
+ case 'p':
+ ADDCMD("peers");
+ break;
+ }
}
-#endif /* not QSORT_USES_VOID_P */
OpenPOWER on IntegriCloud