summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpq/ntpq.c
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
committerdelphij <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
commit2a25cee78ab1d37e7d2bc40ae675646974d99f56 (patch)
treeb0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/ntpq/ntpq.c
parenta0741a75537b2e0514472ac3b28afc55a7846c30 (diff)
downloadFreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.zip
FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.tar.gz
MFC r280849,280915-280916,281015-281016,282097,282408,282415,283542,
284864,285169-285170,285435: ntp 4.2.8p3. Relnotes: yes Approved by: re (?)
Diffstat (limited to 'contrib/ntp/ntpq/ntpq.c')
-rw-r--r--contrib/ntp/ntpq/ntpq.c3061
1 files changed, 1666 insertions, 1395 deletions
diff --git a/contrib/ntp/ntpq/ntpq.c b/contrib/ntp/ntpq/ntpq.c
index 2e51b35..af5f681 100644
--- a/contrib/ntp/ntpq/ntpq.c
+++ b/contrib/ntp/ntpq/ntpq.c
@@ -1,42 +1,46 @@
/*
* ntpq - query an NTP server using mode 6 commands
*/
-
+#include <config.h>
#include <stdio.h>
-
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef SYS_WINNT
+# include <mswsock.h>
+#endif
+#include <isc/net.h>
+#include <isc/result.h>
#include "ntpq.h"
+#include "ntp_assert.h"
+#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "ntp_calendar.h"
-#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 "isc/net.h"
-#include "isc/result.h"
+#include "ntp_assert.h"
+#include "lib_strbuf.h"
+#include "ntp_lineedit.h"
+#include "ntp_debug.h"
+#ifdef OPENSSL
+#include "openssl/evp.h"
+#include "openssl/objects.h"
+#include "openssl/err.h"
+#endif
+#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*/
+#ifdef SYS_VXWORKS /* vxWorks needs mode flag -casey*/
# define open(name, flags) open(name, flags, 0777)
# define SERVER_PORT_NUM 123
#endif
@@ -53,6 +57,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 +77,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 */
/*
@@ -96,127 +105,41 @@ volatile int jump = 0;
* Format values
*/
#define PADDING 0
-#define TS 1 /* time stamp */
-#define FL 2 /* l_fp type value */
-#define FU 3 /* u_fp type value */
-#define FS 4 /* s_fp type value */
-#define UI 5 /* unsigned integer value */
-#define SI 6 /* signed integer value */
-#define HA 7 /* host address */
-#define NA 8 /* network address */
-#define ST 9 /* string value */
-#define RF 10 /* refid (sometimes string, sometimes not) */
-#define LP 11 /* leap (print in binary) */
-#define OC 12 /* integer, print in octal */
-#define MD 13 /* mode */
-#define AR 14 /* array of times */
-#define FX 15 /* test flags */
+#define HA 1 /* host address */
+#define NA 2 /* network address */
+#define LP 3 /* leap (print in binary) */
+#define RF 4 /* refid (sometimes string, sometimes not) */
+#define AR 5 /* array of times */
+#define FX 6 /* test flags */
+#define TS 7 /* l_fp timestamp in hex */
+#define OC 8 /* integer, print in octal */
#define EOV 255 /* end of table */
-
-/*
- * System variable values. The array can be indexed by
- * the variable index to find the textual name.
- */
-struct ctl_var sys_var[] = {
- { 0, PADDING, "" }, /* 0 */
- { CS_LEAP, LP, "leap" }, /* 1 */
- { CS_STRATUM, UI, "stratum" }, /* 2 */
- { CS_PRECISION, SI, "precision" }, /* 3 */
- { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */
- { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
- { CS_REFID, RF, "refid" }, /* 6 */
- { 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 */
- { 0, EOV, "" }
-};
-
-
/*
- * Peer variable list
- */
-struct ctl_var peer_var[] = {
- { 0, PADDING, "" }, /* 0 */
- { CP_CONFIG, UI, "config" }, /* 1 */
- { CP_AUTHENABLE, UI, "authenable" }, /* 2 */
- { CP_AUTHENTIC, UI, "authentic" }, /* 3 */
- { CP_SRCADR, HA, "srcadr" }, /* 4 */
- { CP_SRCPORT, UI, "srcport" }, /* 5 */
- { CP_DSTADR, NA, "dstadr" }, /* 6 */
- { CP_DSTPORT, UI, "dstport" }, /* 7 */
- { CP_LEAP, LP, "leap" }, /* 8 */
- { CP_HMODE, MD, "hmode" }, /* 9 */
- { CP_STRATUM, UI, "stratum" }, /* 10 */
- { CP_PPOLL, UI, "ppoll" }, /* 11 */
- { CP_HPOLL, UI, "hpoll" }, /* 12 */
- { CP_PRECISION, SI, "precision" }, /* 13 */
- { CP_ROOTDELAY, FS, "rootdelay" }, /* 14 */
- { CP_ROOTDISPERSION, FU, "rootdispersion" }, /* 15 */
- { CP_REFID, RF, "refid" }, /* 16 */
- { CP_REFTIME, TS, "reftime" }, /* 17 */
- { CP_ORG, TS, "org" }, /* 18 */
- { CP_REC, TS, "rec" }, /* 19 */
- { CP_XMT, TS, "xmt" }, /* 20 */
- { CP_REACH, OC, "reach" }, /* 21 */
- { CP_UNREACH, UI, "unreach" }, /* 22 */
- { CP_TIMER, UI, "timer" }, /* 23 */
- { CP_DELAY, FS, "delay" }, /* 24 */
- { CP_OFFSET, FL, "offset" }, /* 25 */
- { CP_JITTER, FU, "jitter" }, /* 26 */
- { CP_DISPERSION, FU, "dispersion" }, /* 27 */
- { CP_KEYID, UI, "keyid" }, /* 28 */
- { CP_FILTDELAY, AR, "filtdelay" }, /* 29 */
- { CP_FILTOFFSET, AR, "filtoffset" }, /* 30 */
- { CP_PMODE, ST, "pmode" }, /* 31 */
- { CP_RECEIVED, UI, "received" }, /* 32 */
- { CP_SENT, UI, "sent" }, /* 33 */
- { CP_FILTERROR, AR, "filtdisp" }, /* 34 */
- { CP_FLASH, FX, "flash" }, /* 35 */
- { CP_TTL, UI, "ttl" }, /* 36 */
- /*
- * These are duplicate entries so that we can
- * process deviant version of the ntp protocol.
- */
- { CP_SRCADR, HA, "peeraddr" }, /* 4 */
- { CP_SRCPORT, UI, "peerport" }, /* 5 */
- { CP_PPOLL, UI, "peerpoll" }, /* 11 */
- { CP_HPOLL, UI, "hostpoll" }, /* 12 */
- { CP_FILTERROR, AR, "filterror" }, /* 34 */
- { 0, EOV, "" }
+ * For the most part ntpq simply displays what ntpd provides in the
+ * mostly plain-text mode 6 responses. A few variable names are by
+ * default "cooked" to provide more human-friendly output.
+ */
+const var_format cookedvars[] = {
+ { "leap", LP },
+ { "reach", OC },
+ { "refid", RF },
+ { "reftime", TS },
+ { "clock", TS },
+ { "org", TS },
+ { "rec", TS },
+ { "xmt", TS },
+ { "flash", FX },
+ { "srcadr", HA },
+ { "peeradr", HA }, /* compat with others */
+ { "dstadr", NA },
+ { "filtdelay", AR },
+ { "filtoffset", AR },
+ { "filtdisp", AR },
+ { "filterror", AR }, /* compat with others */
};
-/*
- * Clock variable list
- */
-struct ctl_var clock_var[] = {
- { 0, PADDING, "" }, /* 0 */
- { CC_TYPE, UI, "type" }, /* 1 */
- { CC_TIMECODE, ST, "timecode" }, /* 2 */
- { CC_POLL, UI, "poll" }, /* 3 */
- { CC_NOREPLY, UI, "noreply" }, /* 4 */
- { CC_BADFORMAT, UI, "badformat" }, /* 5 */
- { CC_BADDATA, UI, "baddata" }, /* 6 */
- { CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */
- { CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */
- { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */
- { CC_FUDGEVAL2, RF, "refid" }, /* 10 */
- { CC_FLAGS, UI, "flags" }, /* 11 */
- { CC_DEVICE, ST, "device" }, /* 12 */
- { 0, EOV, "" }
-};
-
/*
* flasher bits
@@ -224,76 +147,85 @@ 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 **));
+static int openhost (const char *, int);
+static void dump_hex_printable(const void *, size_t);
+static int sendpkt (void *, size_t);
+static int getresponse (int, int, u_short *, int *, const char **, int);
+static int sendrequest (int, associd_t, int, int, const 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 (const char *, int, arg_v *);
+#endif /* BUILD_AS_LIB */
+static int findcmd (const 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 *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+static void error (const char *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+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 *, const char *, const char *);
+static void endoutput (FILE *);
+static void outputarr (FILE *, char *, int, l_fp *);
+static int assoccmp (const void *, const void *);
+ u_short varfmt (const char *);
+
+void ntpq_custom_opt_handler (tOptions *, tOptDesc *);
+
+#ifdef OPENSSL
+# ifdef HAVE_EVP_MD_DO_ALL_SORTED
+static void list_md_fn(const EVP_MD *m, const char *from,
+ const char *to, void *arg );
+# endif
#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 char *list_digest_names(void);
/*
* Built-in commands we understand
@@ -317,7 +249,7 @@ struct xcmd builtins[] = {
{ "poll", ntp_poll, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
{ "n", "verbose", "", "" },
"poll an NTP server in client mode `n' times" },
- { "passwd", passwd, { NO, NO, NO, NO },
+ { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO },
{ "", "", "", "" },
"specify a password to use for authenticated requests"},
{ "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO },
@@ -351,8 +283,8 @@ struct xcmd builtins[] = {
{ "version number", "", "", "" },
"set the NTP version number to use for requests" },
{ "keytype", keytype, { OPT|NTP_STR, NO, NO, NO },
- { "key type (md5|des)", "", "", "" },
- "set key type to use for authenticated requests (des|md5)" },
+ { "key type %s", "", "", "" },
+ NULL },
{ 0, 0, { NO, NO, NO, NO },
{ "", "", "", "" }, "" }
};
@@ -361,29 +293,41 @@ struct xcmd builtins[] = {
/*
* Default values we use.
*/
-#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 DEFTIMEOUT 5 /* wait 5 seconds for 1st pkt */
+#define DEFSTIMEOUT 3 /* and 3 more for each additional */
+/*
+ * Requests are automatically retried once, so total timeout with no
+ * response is a bit over 2 * DEFTIMEOUT, or 10 seconds. At the other
+ * extreme, a request eliciting 32 packets of responses each for some
+ * reason nearly DEFSTIMEOUT seconds after the prior in that series,
+ * with a single packet dropped, would take around 32 * DEFSTIMEOUT, or
+ * 93 seconds to fail each of two times, or 186 seconds.
+ * Some commands involve a series of requests, such as "peers" and
+ * "mrulist", so the cumulative timeouts are even longer for those.
+ */
+#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
#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 */
#define MAXLINE 512 /* maximum line length */
#define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
#define MAXVARLEN 256 /* maximum length of a variable name */
-#define MAXVALLEN 400 /* maximum length of a variable value */
+#define MAXVALLEN 2048 /* 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 */
-struct sockaddr_in hostaddr = { 0 }; /* host address */
+int currenthostisnum; /* is prior text from IP? */
+struct sockaddr_in hostaddr; /* host address */
int showhostnames = 1; /* show host names by default */
+int wideremote = 0; /* show wide remote names? */
int ai_fam_templ; /* address family */
int ai_fam_default; /* default address family */
@@ -392,13 +336,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
@@ -410,15 +347,18 @@ u_short sequence;
* Holds data returned from queries. Declare buffer long to be sure of
* alignment.
*/
-#define MAXFRAGS 24 /* maximum number of fragments */
#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
long pktdata[DATASIZE/sizeof(long)];
/*
- * Holds association data for use with the &n operator.
+ * assoc_cache[] is a dynamic array which allows references to
+ * associations using &1 ... &N for n associations, avoiding manual
+ * lookup of the current association IDs for a given ntpd. It also
+ * caches the status word for each association, retrieved incidentally.
*/
-struct association assoc_cache[MAXASSOC];
-int numassoc = 0; /* number of cached associations */
+struct association * assoc_cache;
+u_int assoc_cache_slots;/* count of allocated array entries */
+u_int numassoc; /* number of cached associations */
/*
* For commands typed on the command line (with the -c option)
@@ -430,17 +370,18 @@ const char *ccmds[MAXCMDS];
/*
* When multiple hosts are specified.
*/
-int numhosts = 0;
-const char *chosts[MAXHOSTS];
-#define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
-/*
- * Error codes for internal use
- */
-#define ERR_UNSPEC 256
-#define ERR_INCOMPLETE 257
-#define ERR_TIMEOUT 258
-#define ERR_TOOMUCH 259
+u_int numhosts;
+
+chost chosts[MAXHOSTS];
+#define ADDHOST(cp) \
+ do { \
+ if (numhosts < MAXHOSTS) { \
+ chosts[numhosts].name = (cp); \
+ chosts[numhosts].fam = ai_fam_templ; \
+ numhosts++; \
+ } \
+ } while (0)
/*
* Macro definitions we use
@@ -465,23 +406,24 @@ FILE *current_output;
extern struct xcmd opcmds[];
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,13 +439,16 @@ main(
}
#endif
+#ifndef BUILD_AS_LIB
int
ntpqmain(
int argc,
char *argv[]
)
{
- extern int ntp_optind;
+ u_int ihost;
+ int icmd;
+
#ifdef SYS_VXWORKS
clear_globals();
@@ -513,102 +458,99 @@ 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();
+ init_auth();
- /* 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;
+
+ /* Fixup keytype's help based on available digest names */
+
+ {
+ char *list;
+ char *msg, *fmt;
+
+ list = list_digest_names();
+ for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) {
+ if (strcmp("keytype", builtins[icmd].keyword) == 0)
+ break;
+ }
+
+ /* CID: 1295478 */
+ /* This should only "trip" if "keytype" is removed from builtins */
+ INSIST(icmd < sizeof(builtins)/sizeof(builtins[0]));
+
+#ifdef OPENSSL
+ builtins[icmd].desc[0] = "digest-name";
+ fmt = "set key type to use for authenticated requests, one of:%s";
+#else
+ builtins[icmd].desc[0] = "md5";
+ fmt = "set key type to use for authenticated requests (%s)";
+#endif
+ msg = malloc(strlen(fmt) + strlen(list) - strlen("%s") +1);
+ sprintf(msg, fmt, list);
+ builtins[icmd].comment = msg;
+ free(list);
}
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 = OPT_VALUE_SET_DEBUG_LEVEL;
+
+ 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");
- }
+ if (HAVE_OPT(WIDE))
+ wideremote = 1;
-#if 0
- while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF)
- switch (c) {
- case '4':
- ai_fam_templ = AF_INET;
- break;
- case '6':
- ai_fam_templ = AF_INET6;
- break;
- case 'c':
- ADDCMD(ntp_optarg);
- break;
- case 'd':
- ++debug;
- break;
- case 'i':
- interactive = 1;
- break;
- case 'n':
- showhostnames = 0;
- break;
- case 'p':
- ADDCMD("peers");
- break;
- default:
- errflg++;
- break;
- }
- if (errflg) {
- (void) fprintf(stderr,
- "usage: %s [-46dinp] [-c cmd] host ...\n",
- progname);
- exit(2);
- }
-#endif
- if (ntp_optind == argc) {
+ old_rv = HAVE_OPT(OLD_RV);
+
+ if (0 == argc) {
ADDHOST(DEFHOST);
} else {
- for (; ntp_optind < argc; ntp_optind++)
- ADDHOST(argv[ntp_optind]);
+ for (ihost = 0; ihost < (u_int)argc; ihost++) {
+ if ('-' == *argv[ihost]) {
+ //
+ // If I really cared I'd also check:
+ // 0 == argv[ihost][2]
+ //
+ // and there are other cases as well...
+ //
+ if ('4' == argv[ihost][1]) {
+ ai_fam_templ = AF_INET;
+ continue;
+ } else if ('6' == argv[ihost][1]) {
+ ai_fam_templ = AF_INET6;
+ continue;
+ } else {
+ // XXX Throw a usage error
+ }
+ }
+ ADDHOST(argv[ihost]);
+ }
}
if (numcmds == 0 && interactive == 0
@@ -622,16 +564,13 @@ ntpqmain(
#endif /* SYS_WINNT */
if (numcmds == 0) {
- (void) openhost(chosts[0]);
+ (void) openhost(chosts[0].name, chosts[0].fam);
getcmds();
} else {
- int ihost;
- int icmd;
-
for (ihost = 0; ihost < numhosts; ihost++) {
- if (openhost(chosts[ihost]))
- for (icmd = 0; icmd < numcmds; icmd++)
- docmd(ccmds[icmd]);
+ if (openhost(chosts[ihost].name, chosts[ihost].fam))
+ for (icmd = 0; icmd < numcmds; icmd++)
+ docmd(ccmds[icmd]);
}
}
#ifdef SYS_WINNT
@@ -639,35 +578,42 @@ 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
+ const char *hname,
+ int fam
)
{
+ const char svc[] = "ntp";
char temphost[LENHOSTNAME];
int a_info, i;
- struct addrinfo hints, *ai = NULL;
+ struct addrinfo hints, *ai;
+ sockaddr_u addr;
+ size_t octets;
register const char *cp;
char name[LENHOSTNAME];
- char service[5];
/*
* We need to get by the [] if they were entered
*/
-
+
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;
+ }
}
/*
@@ -677,14 +623,14 @@ openhost(
* will return an "IPv4-mapped IPv6 address" address if you
* give it an IPv4 address to lookup.
*/
- strcpy(service, "ntp");
- memset((char *)&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = ai_fam_templ;
+ ZERO(hints);
+ hints.ai_family = fam;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_flags = Z_AI_NUMERICHOST;
+ ai = NULL;
- a_info = getaddrinfo(hname, service, &hints, &ai);
+ a_info = getaddrinfo(hname, svc, &hints, &ai);
if (a_info == EAI_NONAME
#ifdef EAI_NODATA
|| a_info == EAI_NODATA
@@ -694,41 +640,53 @@ openhost(
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif
- a_info = getaddrinfo(hname, service, &hints, &ai);
+ a_info = getaddrinfo(hname, svc, &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);
+ hints.ai_flags &= ~AI_ADDRCONFIG;
+ a_info = getaddrinfo(hname, svc, &hints, &ai);
}
+#endif
if (a_info != 0) {
- (void) fprintf(stderr, "%s\n", gai_strerror(a_info));
+ 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';
+ INSIST(ai != NULL);
+ ZERO(addr);
+ octets = min(sizeof(addr), ai->ai_addrlen);
+ memcpy(&addr, ai->ai_addr, octets);
+ if (ai->ai_canonname == NULL) {
+ strlcpy(temphost, stoa(&addr), sizeof(temphost));
+ currenthostisnum = TRUE;
} else {
- strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
- temphost[LENHOSTNAME-1] = '\0';
+ strlcpy(temphost, ai->ai_canonname, sizeof(temphost));
+ currenthostisnum = FALSE;
}
if (debug > 2)
- printf("Opening host %s\n", temphost);
+ printf("Opening host %s (%s)\n",
+ temphost,
+ (ai->ai_family == AF_INET)
+ ? "AF_INET"
+ : (ai->ai_family == AF_INET6)
+ ? "AF_INET6"
+ : "AF-???"
+ );
if (havehost == 1) {
if (debug > 2)
- printf("Closing old host %s\n", currenthost);
- (void) closesocket(sockfd);
+ printf("Closing old host %s\n", currenthost);
+ closesocket(sockfd);
havehost = 0;
}
- (void) strcpy(currenthost, temphost);
+ strlcpy(currenthost, temphost, sizeof(currenthost));
/* port maps to the same location in both families */
- s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;
+ s_port = NSRCPORT(&addr);
#ifdef SYS_VXWORKS
((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
if (ai->ai_family == AF_INET)
@@ -744,81 +702,118 @@ 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) {
+ mfprintf(stderr,
+ "setsockopt(SO_SYNCHRONOUS_NONALERT)"
+ " error: %m\n");
+ freeaddrinfo(ai);
exit(1);
}
}
#endif /* SYS_WINNT */
- sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
+ sockfd = socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
if (sockfd == INVALID_SOCKET) {
- error("socket", "", "");
+ error("socket");
+ freeaddrinfo(ai);
+ return 0;
}
-
+
#ifdef NEED_RCVBUF_SLOP
# ifdef SO_RCVBUF
{ int rbufsize = DATASIZE + 2048; /* 2K for slop */
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
&rbufsize, sizeof(int)) == -1)
- error("setsockopt", "", "");
+ error("setsockopt");
}
# endif
#endif
+ if
#ifdef SYS_VXWORKS
- if (connect(sockfd, (struct sockaddr *)&hostaddr,
+ (connect(sockfd, (struct sockaddr *)&hostaddr,
sizeof(hostaddr)) == -1)
#else
- if (connect(sockfd, (struct sockaddr *)ai->ai_addr,
+ (connect(sockfd, (struct sockaddr *)ai->ai_addr,
ai->ai_addrlen) == -1)
#endif /* SYS_VXWORKS */
- error("connect", "", "");
- if (a_info == 0)
+ {
+ error("connect");
freeaddrinfo(ai);
+ return 0;
+ }
+ freeaddrinfo(ai);
havehost = 1;
+ numassoc = 0;
+
return 1;
}
+static void
+dump_hex_printable(
+ const void * data,
+ size_t len
+ )
+{
+ const char * cdata;
+ const char * rowstart;
+ size_t idx;
+ size_t rowlen;
+ u_char uch;
+
+ cdata = data;
+ while (len > 0) {
+ rowstart = cdata;
+ rowlen = min(16, len);
+ for (idx = 0; idx < rowlen; idx++) {
+ uch = *(cdata++);
+ printf("%02x ", uch);
+ }
+ for ( ; idx < 16 ; idx++)
+ printf(" ");
+ cdata = rowstart;
+ for (idx = 0; idx < rowlen; idx++) {
+ uch = *(cdata++);
+ printf("%c", (isprint(uch))
+ ? uch
+ : '.');
+ }
+ printf("\n");
+ len -= rowlen;
+ }
+}
+
+
/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
/*
* sendpkt - send a packet to the remote host
*/
static int
sendpkt(
- char *xdata,
- int xdatalen
+ void * xdata,
+ size_t xdatalen
)
{
if (debug >= 3)
- printf("Sending %d octets\n", xdatalen);
-
+ printf("Sending %zu octets\n", xdatalen);
if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
- warning("write to %s failed", currenthost, "");
+ warning("write to %s failed", currenthost);
return -1;
}
if (debug >= 4) {
- int first = 8;
- printf("Packet data:\n");
- while (xdatalen-- > 0) {
- if (first-- == 0) {
- printf("\n");
- first = 7;
- }
- printf(" %02x", *xdata++ & 0xff);
- }
- printf("\n");
+ printf("Request packet:\n");
+ dump_hex_printable(xdata, xdatalen);
}
return 0;
}
-
-
/*
* getresponse - get a (series of) response packet(s) and return the data
*/
@@ -828,20 +823,24 @@ 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 errcode;
/*
* This is pretty tricky. We may get between 1 and MAXFRAG packets
@@ -852,7 +851,7 @@ getresponse(
*/
*rsize = 0;
if (rstatus)
- *rstatus = 0;
+ *rstatus = 0;
*rdata = (char *)pktdata;
numfrags = 0;
@@ -860,305 +859,308 @@ 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);
-
-#if 0
- if (debug >= 1)
- printf("select() returns %d\n", n);
-#endif
+ /*
+ * Loop until we have an error or a complete response. Nearly all
+ * code paths to loop again use continue.
+ */
+ for (;;) {
- 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 (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)
+ 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",
+ (u_int)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;
- }
- if (debug >= 4) {
- int len = n, first = 8;
- char *data = (char *)&rpkt;
-
- printf("Packet data:\n");
- while (len-- > 0) {
- if (first-- == 0) {
- printf("\n");
- first = 7;
- }
- printf(" %02x", *data++ & 0xff);
+ n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
+ if (n == -1) {
+ warning("read");
+ return -1;
}
- 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;
- }
+ if (debug >= 4) {
+ printf("Response packet:\n");
+ dump_hex_printable(&rpkt, n);
+ }
- /*
- * 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 for format errors. Bug proofing.
+ */
+ if (n < (int)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 the error code. If non-zero, return it.
- */
- if (CTL_ISERROR(rpkt.r_m_e_op)) {
- int errcode;
+ /*
+ * 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;
+ }
- 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);
+ /*
+ * Check the error code. If non-zero, return it.
+ */
+ if (CTL_ISERROR(rpkt.r_m_e_op)) {
+ errcode = (ntohs(rpkt.status) >> 8) & 0xff;
+ if (CTL_ISMORE(rpkt.r_m_e_op))
+ TRACE(1, ("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) {
+ TRACE(1, ("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) {
+ TRACE(1, ("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 %ld received\n",
+ count, (long)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 >= (int)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;
- }
+ TRACE(2, ("Got packet, size = %d\n", n));
+ if (count > (n - CTL_HEADER_LEN)) {
+ TRACE(1, ("Received count of %u octets, data in packet is %ld\n",
+ count, (long)n - CTL_HEADER_LEN));
+ continue;
+ }
+ if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
+ TRACE(1, ("Received count of 0 in non-final fragment\n"));
+ continue;
+ }
+ if (offset + count > sizeof(pktdata)) {
+ TRACE(1, ("Offset %u, count %u, too big for buffer\n",
+ offset, count));
+ return ERR_TOOMUCH;
+ }
+ if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
+ TRACE(1, ("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");;
-
- 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];
+ /*
+ * So far, so good. Record this fragment, making sure it doesn't
+ * overlap anything.
+ */
+ TRACE(2, ("Packet okay\n"));
+
+ if (numfrags > (MAXFRAGS - 1)) {
+ TRACE(2, ("Number of fragments exceeds maximum %d\n",
+ MAXFRAGS - 1));
+ return ERR_TOOMUCH;
}
- }
- 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);
- }
+ /*
+ * Find the position for the fragment relative to any
+ * previously received.
+ */
+ for (f = 0;
+ f < numfrags && offsets[f] < offset;
+ f++) {
+ /* empty body */ ;
+ }
- /*
- * Copy the data into the data buffer.
- */
- memmove((char *)pktdata + offset, (char *)rpkt.data, count);
+ if (f < numfrags && offset == offsets[f]) {
+ TRACE(1, ("duplicate %u octets at %u ignored, prior %u at %u\n",
+ count, offset, counts[f], offsets[f]));
+ 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 > 0 && (offsets[f-1] + counts[f-1]) > offset) {
+ TRACE(1, ("received frag at %u overlaps with %u octet frag at %u\n",
+ offset, counts[f-1], offsets[f-1]));
+ continue;
}
- if (n == numfrags) {
- *rsize = offsets[numfrags-1] + counts[numfrags-1];
- return 0;
+
+ if (f < numfrags && (offset + count) > offsets[f]) {
+ TRACE(1, ("received %u octet frag at %u overlaps with frag at %u\n",
+ count, offset, offsets[f]));
+ continue;
}
- }
- goto again;
- overlap:
- /*
- * Print debugging message about overlapping fragments
- */
- if (debug)
- printf("Overlapping fragments returned in response\n");
- goto again;
-}
+ for (ff = numfrags; ff > f; ff--) {
+ offsets[ff] = offsets[ff-1];
+ counts[ff] = counts[ff-1];
+ }
+ offsets[f] = offset;
+ counts[f] = 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);
+ }
+
+ /*
+ * Copy the data into the data buffer.
+ */
+ memcpy((char *)pktdata + offset, &rpkt.u, 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];
+ TRACE(1, ("%lu packets reassembled into response\n",
+ (u_long)numfrags));
+ return 0;
+ }
+ }
+ } /* giant for (;;) collecting response packets */
+} /* getresponse() */
/*
@@ -1167,22 +1169,25 @@ getresponse(
static int
sendrequest(
int opcode,
- int associd,
+ associd_t associd,
int auth,
int qsize,
- char *qdata
+ const char *qdata
)
{
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 +1202,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)) {
- qpkt.data[qsize++] = 0;
+ memcpy(&qpkt.u, qdata, (size_t)qsize);
+ pktsize += qsize;
+ while (pktsize & (sizeof(u_int32) - 1)) {
+ qpkt.u.data[qsize++] = 0;
pktsize++;
}
- } else {
- pktsize = CTL_HEADER_LEN;
}
/*
@@ -1217,76 +1221,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.u.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;
- }
- if (!authistrusted(info_auth_keyid)) {
- pass = getpass("MD5 Password: ");
- if (*pass == '\0') {
- (void) fprintf(stderr,
- "Invalid password\n");
- return (1);
- }
+ /*
+ * 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;
+ }
+ 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, %zu expected with %zu octet digest\n",
+ maclen, (info_auth_hashlen + sizeof(keyid_t)),
+ 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,
+ const char *qdata,
+ u_short *rstatus,
+ int *rsize,
+ 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,
+ const char *qdata,
u_short *rstatus,
int *rsize,
- char **rdata
+ const char **rdata,
+ int quiet
)
{
int res;
@@ -1296,7 +1391,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,8 +1404,8 @@ 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 +1423,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;
+
+ ntp_readline_init(interactive ? prompt : NULL);
- if (fgets(line, sizeof line, stdin) == NULL)
- return;
+ 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 +1471,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
*/
@@ -1452,7 +1495,7 @@ docmd(
tokenize(cmdline, tokens, &ntok);
if (ntok == 0)
return;
-
+
/*
* Find the appropriate command description.
*/
@@ -1466,7 +1509,12 @@ docmd(
tokens[0]);
return;
}
-
+
+ /* Warn about ignored extra args */
+ for (i = MAXARGS + 1; i < ntok ; ++i) {
+ fprintf(stderr, "***Extra arg `%s' ignored\n", tokens[i]);
+ }
+
/*
* Save the keyword, then walk through the arguments, interpreting
* as we go.
@@ -1482,9 +1530,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 +1541,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;
@@ -1522,12 +1570,20 @@ docmd(
jump = 0; /* HMS: 961106: was after fclose() */
if (i) (void) fclose(current_output);
}
+
+ return;
}
/*
* 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,33 +1599,151 @@ 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));
+ /* If this is the 2nd token and the first token begins
+ * with a ':', then just grab to EOL.
+ */
+
+ if (*ntok == 1 && tokens[0][0] == ':') {
+ do {
+ if (sp - tspace >= MAXLINE)
+ goto toobig;
+ *sp++ = *cp++;
+ } while (!ISEOL(*cp));
+ }
+
+ /* Check if this token begins with a double quote.
+ * If yes, continue reading till the next double quote
+ */
+ else if (*cp == '\"') {
+ ++cp;
+ do {
+ if (sp - tspace >= MAXLINE)
+ goto toobig;
+ *sp++ = *cp++;
+ } while ((*cp != '\"') && !ISEOL(*cp));
+ /* HMS: a missing closing " should be an error */
+ }
+ else {
+ do {
+ if (sp - tspace >= MAXLINE)
+ goto toobig;
+ *sp++ = *cp++;
+ } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
+ /* HMS: Why check for a " in the previous line? */
+ }
+
+ if (sp - tspace >= MAXLINE)
+ goto toobig;
*sp++ = '\0';
}
+ return;
+
+ toobig:
+ *ntok = 0;
+ fprintf(stderr,
+ "***Line `%s' is too big\n",
+ line);
+ return;
}
+/*
+ * getarg - interpret an argument token
+ */
+static int
+getarg(
+ const char *str,
+ int code,
+ arg_v *argp
+ )
+{
+ u_long ul;
+
+ switch (code & ~OPT) {
+ case NTP_STR:
+ argp->string = str;
+ break;
+
+ case NTP_ADD:
+ if (!getnetnum(str, &argp->netnum, NULL, 0))
+ return 0;
+ break;
+
+ case NTP_UINT:
+ if ('&' == str[0]) {
+ if (!atouint(&str[1], &ul)) {
+ fprintf(stderr,
+ "***Association index `%s' invalid/undecodable\n",
+ str);
+ return 0;
+ }
+ if (0 == numassoc) {
+ dogetassoc(stdout);
+ if (0 == numassoc) {
+ fprintf(stderr,
+ "***No associations found, `%s' unknown\n",
+ str);
+ return 0;
+ }
+ }
+ ul = min(ul, numassoc);
+ argp->uval = assoc_cache[ul - 1].assid;
+ break;
+ }
+ if (!atouint(str, &argp->uval)) {
+ fprintf(stderr, "***Illegal unsigned value %s\n",
+ str);
+ return 0;
+ }
+ break;
+
+ case NTP_INT:
+ if (!atoint(str, &argp->ival)) {
+ fprintf(stderr, "***Illegal integer value %s\n",
+ str);
+ return 0;
+ }
+ break;
+
+ case IP_VERSION:
+ if (!strcmp("-6", str)) {
+ argp->ival = 6;
+ } else if (!strcmp("-4", str)) {
+ argp->ival = 4;
+ } else {
+ fprintf(stderr, "***Version must be either 4 or 6\n");
+ return 0;
+ }
+ break;
+ }
+
+ 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
+ const char * str,
+ struct xcmd * clist1,
+ struct xcmd * clist2,
+ struct xcmd ** cmd
)
{
- register struct xcmd *cl;
- register int clen;
+ struct xcmd *cl;
+ int clen;
int nmatch;
struct xcmd *nearmatch = NULL;
struct xcmd *clist;
@@ -1625,159 +1799,124 @@ findcmd(
/*
- * getarg - interpret an argument token
- */
-static int
-getarg(
- char *str,
- int code,
- arg_v *argp
- )
-{
- int isneg;
- char *cp, *np;
- static const char *digits = "0123456789";
-
- switch (code & ~OPT) {
- case NTP_STR:
- argp->string = str;
- break;
- case NTP_ADD:
- if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
- return 0;
- }
- break;
- case NTP_INT:
- case NTP_UINT:
- isneg = 0;
- np = str;
- if (*np == '&') {
- np++;
- isneg = atoi(np);
- if (isneg <= 0) {
- (void) fprintf(stderr,
- "***Association value `%s' invalid/undecodable\n", str);
- return 0;
- }
- if (isneg > numassoc) {
- if (numassoc == 0) {
- (void) fprintf(stderr,
- "***Association for `%s' unknown (max &%d)\n",
- str, numassoc);
- return 0;
- } else {
- isneg = numassoc;
- }
- }
- argp->uval = assoc_cache[isneg-1].assid;
- break;
- }
-
- if (*np == '-') {
- np++;
- isneg = 1;
- }
-
- argp->uval = 0;
- do {
- cp = strchr(digits, *np);
- if (cp == NULL) {
- (void) fprintf(stderr,
- "***Illegal integer value %s\n", str);
- return 0;
- }
- argp->uval *= 10;
- argp->uval += (cp - digits);
- } while (*(++np) != '\0');
-
- if (isneg) {
- if ((code & ~OPT) == NTP_UINT) {
- (void) fprintf(stderr,
- "***Value %s should be unsigned\n", str);
- return 0;
- }
- argp->ival = -argp->ival;
- }
- break;
- case IP_VERSION:
- if (!strcmp("-6", str))
- argp->ival = 6 ;
- else if (!strcmp("-4", str))
- argp->ival = 4 ;
- else {
- (void) fprintf(stderr,
- "***Version must be either 4 or 6\n");
- return 0;
- }
- break;
- }
-
- return 1;
-}
-
-
-/*
* getnetnum - given a host name, return its net number
* and (optional) full name
*/
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);
+ INSIST(sizeof(*num) >= ai->ai_addrlen);
+ memcpy(num, ai->ai_addr, ai->ai_addrlen);
+ if (fullhost != NULL) {
+ if (ai->ai_canonname != NULL)
+ strlcpy(fullhost, ai->ai_canonname,
+ LENHOSTNAME);
+ else
+ getnameinfo(&num->sa, SOCKLEN(num),
+ fullhost, LENHOSTNAME, NULL,
+ 0, 0);
+ }
+ freeaddrinfo(ai);
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;
}
+
/*
* nntohost - convert network number to host name. This routine enforces
* the showhostnames setting.
*/
-char *
+const 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.
+ */
+const 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 || SOCK_UNSPEC(addr)) {
+ 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;
}
/*
+ * nntohostp() is the same as nntohost() plus a :port suffix
+ */
+const char *
+nntohostp(
+ sockaddr_u *netnum
+ )
+{
+ const char * hostn;
+ char * buf;
+
+ if (!showhostnames || SOCK_UNSPEC(netnum))
+ return sptoa(netnum);
+ else if (ISREFCLOCKADR(netnum))
+ return refnumtoa(netnum);
+
+ hostn = socktohost(netnum);
+ LIB_GETBUF(buf);
+ snprintf(buf, LIB_BUFLENGTH, "%s:%u", hostn, SRCPORT(netnum));
+
+ return buf;
+}
+
+/*
* rtdatetolfp - decode an RT-11 date into an l_fp
*/
static int
@@ -1790,10 +1929,6 @@ rtdatetolfp(
register int i;
struct calendar cal;
char buf[4];
- static const char *months[12] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
cal.yearday = 0;
@@ -1826,7 +1961,7 @@ rtdatetolfp(
if (*cp++ != '-')
return 0;
-
+
for (i = 0; i < 3; i++)
buf[i] = *cp++;
buf[3] = '\0';
@@ -1840,7 +1975,7 @@ rtdatetolfp(
if (*cp++ != '-')
return 0;
-
+
if (!isdigit((int)*cp))
return 0;
cal.year = (u_short)(*cp++ - '0');
@@ -1913,24 +2048,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 +2076,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 +2113,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 +2189,56 @@ help(
FILE *fp
)
{
- struct xcmd *xcp;
- char *cmd;
+ struct xcmd *xcp = NULL; /* quiet warning */
+ const 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++) {
- if (*(xcp->keyword) != '?')
- list[words++] = xcp->keyword;
+ for (xcp = builtins; xcp->keyword != NULL; xcp++) {
+ if (*(xcp->keyword) != '?' &&
+ words < COUNTOF(list))
+ list[words++] = xcp->keyword;
}
- for (xcp = opcmds; xcp->keyword != 0; xcp++)
- list[words++] = xcp->keyword;
+ for (xcp = opcmds; xcp->keyword != NULL; xcp++)
+ if (words < COUNTOF(list))
+ list[words++] = xcp->keyword;
- qsort(
-#ifdef QSORT_USES_VOID_P
- (void *)
-#else
- (char *)
-#endif
- (list), (size_t)(words), sizeof(char *), helpsort);
+ qsort((void *)list, 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", (int)col,
+ (int)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 +2247,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
@@ -2149,6 +2271,8 @@ printusage(
{
register int i;
+ /* XXX: Do we need to warn about extra args here too? */
+
(void) fprintf(fp, "usage: %s", xcp->keyword);
for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
if (xcp->arg[i] & OPT)
@@ -2172,11 +2296,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 +2353,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;
}
@@ -2242,25 +2367,19 @@ host(
ai_fam_templ = AF_INET;
else if (!strcmp("-6", pcmd->argval[i].string))
ai_fam_templ = AF_INET6;
- else {
- if (havehost)
- (void) fprintf(fp,
- "current host remains %s\n", currenthost);
- else
- (void) fprintf(fp, "still no current host\n");
- return;
- }
+ else
+ goto no_change;
i = 1;
}
- if (openhost(pcmd->argval[i].string)) {
- (void) fprintf(fp, "current host set to %s\n", currenthost);
- numassoc = 0;
+ if (openhost(pcmd->argval[i].string, ai_fam_templ)) {
+ fprintf(fp, "current host set to %s\n", currenthost);
} else {
+ no_change:
if (havehost)
- (void) fprintf(fp,
- "current host remains %s\n", currenthost);
+ fprintf(fp, "current host remains %s\n",
+ currenthost);
else
- (void) fprintf(fp, "still no current host\n");
+ fprintf(fp, "still no current host\n");
}
}
@@ -2310,21 +2429,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 is not valid. "
+#ifdef OPENSSL
+ "Type \"help keytype\" for the available digest types.\n");
+#else
+ "Only \"md5\" is available.\n");
+#endif
+ return;
+ }
+ info_auth_keytype = key_type;
+ info_auth_hashlen = digest_len;
+}
/*
@@ -2337,23 +2469,27 @@ passwd(
FILE *fp
)
{
- char *pass;
+ const char *pass;
if (info_auth_keyid == 0) {
- int u_keyid = getkeyid("Keyid: ");
- if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
- (void)fprintf(fp, "Invalid key identifier\n");
+ info_auth_keyid = getkeyid("Keyid: ");
+ if (info_auth_keyid == 0) {
+ (void)fprintf(fp, "Keyid must be defined\n");
return;
}
- 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,
+ (const u_char *)pass);
+ authtrust(info_auth_keyid, 1);
}
@@ -2523,37 +2659,46 @@ ntpversion(
}
+static void __attribute__((__format__(__printf__, 1, 0)))
+vwarning(const char *fmt, va_list ap)
+{
+ int serrno = errno;
+ (void) fprintf(stderr, "%s: ", progname);
+ vfprintf(stderr, fmt, ap);
+ (void) fprintf(stderr, ": %s", strerror(serrno));
+}
+
/*
* warning - print a warning message
*/
-static void
+static void __attribute__((__format__(__printf__, 1, 2)))
warning(
const char *fmt,
- const char *st1,
- const char *st2
+ ...
)
{
- (void) fprintf(stderr, "%s: ", progname);
- (void) fprintf(stderr, fmt, st1, st2);
- (void) fprintf(stderr, ": ");
- perror("");
+ va_list ap;
+ va_start(ap, fmt);
+ vwarning(fmt, ap);
+ va_end(ap);
}
/*
* error - print a message and exit
*/
-static void
+static void __attribute__((__format__(__printf__, 1, 2)))
error(
const char *fmt,
- const char *st1,
- const char *st2
+ ...
)
{
- warning(fmt, st1, st2);
+ va_list ap;
+ va_start(ap, fmt);
+ vwarning(fmt, ap);
+ va_end(ap);
exit(1);
}
-
/*
* getkeyid - prompt the user for a keyid to use
*/
@@ -2562,29 +2707,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 +2740,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';
+ const u_char * pchIn;
+ const u_char * pchInLimit;
+ u_char * pchOut;
+ 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;
- for (cp = (u_char *)data; cp < (u_char *)data + length; cp++) {
+ data_u_char = (const u_char *)data;
+
+ 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 +2847,62 @@ asciize(
/*
+ * truncate string to fit clipping excess at end.
+ * "too long" -> "too l"
+ * Used for hostnames.
+ */
+const 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.
+ */
+const 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,16 +2917,16 @@ 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 */
- int quoted = 0;
+ const char *cp;
+ const char *np;
+ const char *cpend;
+ size_t srclen;
+ size_t len;
static char name[MAXVARLEN];
static char value[MAXVALLEN];
@@ -2726,40 +2937,34 @@ nextvar(
* Space past commas and white space
*/
while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
- cp++;
- if (cp == cpend)
- return 0;
-
+ cp++;
+ if (cp >= cpend)
+ return 0;
+
/*
* Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
* over any white space and terminate it.
*/
- np = name;
- npend = &name[MAXVARLEN];
- while (cp < cpend && np < npend && *cp != ',' && *cp != '='
- && *cp != '\r' && *cp != '\n')
- *np++ = *cp++;
- /*
- * Check if we ran out of name space, without reaching the end or a
- * terminating character
- */
- if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
- *cp == '\r' || *cp == '\n'))
- return 0;
- while (isspace((int)(*(np-1))))
- np--;
- *np = '\0';
+ srclen = strcspn(cp, ",=\r\n");
+ srclen = min(srclen, (size_t)(cpend - cp));
+ len = srclen;
+ while (len > 0 && isspace((unsigned char)cp[len - 1]))
+ len--;
+ if (len > 0)
+ memcpy(name, cp, len);
+ name[len] = '\0';
*vname = name;
+ cp += srclen;
/*
* Check if we hit the end of the buffer or a ','. If so we are done.
*/
- if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
- if (cp != cpend)
- cp++;
+ if (cp >= cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
+ if (cp < cpend)
+ cp++;
*datap = cp;
*datalen = cpend - cp;
- *vvalue = (char *)0;
+ *vvalue = NULL;
return 1;
}
@@ -2767,68 +2972,54 @@ nextvar(
* So far, so good. Copy out the value
*/
cp++; /* past '=' */
- while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
- cp++;
- np = value;
- npend = &value[MAXVALLEN];
- while (cp < cpend && np < npend && ((*cp != ',') || quoted))
- {
- quoted ^= ((*np++ = *cp++) == '"');
+ while (cp < cpend && (isspace((unsigned char)*cp) && *cp != '\r' && *cp != '\n'))
+ cp++;
+ np = cp;
+ if ('"' == *np) {
+ do {
+ np++;
+ } while (np < cpend && '"' != *np);
+ if (np < cpend && '"' == *np)
+ np++;
+ } else {
+ while (np < cpend && ',' != *np && '\r' != *np)
+ np++;
}
-
- /*
- * Check if we overran the value buffer while still in a quoted string
- * or without finding a comma
- */
- if (np == npend && (quoted || *cp != ','))
- return 0;
+ len = np - cp;
+ if (np > cpend || len >= sizeof(value) ||
+ (np < cpend && ',' != *np && '\r' != *np))
+ return 0;
+ memcpy(value, cp, len);
/*
* Trim off any trailing whitespace
*/
- while (np > value && isspace((int)(*(np-1))))
- np--;
- *np = '\0';
+ while (len > 0 && isspace((unsigned char)value[len - 1]))
+ len--;
+ value[len] = '\0';
/*
* Return this. All done.
*/
- if (cp != cpend)
- cp++;
- *datap = cp;
- *datalen = cpend - cp;
+ if (np < cpend && ',' == *np)
+ np++;
+ *datap = np;
+ *datalen = cpend - np;
*vvalue = value;
return 1;
}
-/*
- * findvar - see if this variable is known to us.
- * If "code" is 1, return ctl_var->code.
- * Otherwise return the ordinal position of the found variable.
- */
-int
-findvar(
- char *varname,
- struct ctl_var *varlist,
- int code
- )
+u_short
+varfmt(const char * varname)
{
- register char *np;
- register struct ctl_var *vl;
+ u_int n;
- vl = varlist;
- np = varname;
- while (vl->fmt != EOV) {
- if (vl->fmt != PADDING && STREQ(np, vl->text))
- return (code)
- ? vl->code
- : (vl - varlist)
- ;
- vl++;
- }
- return 0;
-}
+ for (n = 0; n < COUNTOF(cookedvars); n++)
+ if (!strcmp(varname, cookedvars[n].varname))
+ return cookedvars[n].fmt;
+ return PADDING;
+}
/*
@@ -2837,16 +3028,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 +3049,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 +3064,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 +3074,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((unsigned char)*cp) || isprint((unsigned char)*cp))
putc(*cp, fp);
- } else {
+ else
makeascii(1, cp, fp);
- }
cp++;
}
}
@@ -2916,36 +3109,31 @@ startoutput(void)
static void
output(
FILE *fp,
- char *name,
- char *value
+ const char *name,
+ const 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 +3146,7 @@ endoutput(
)
{
if (out_chars != 0)
- putc('\n', fp);
+ putc('\n', fp);
}
@@ -2985,7 +3173,7 @@ outputarr(
*/
for (i = (int)strlen(name); i < 11; i++)
*bp++ = ' ';
-
+
for (i = narr; i > 0; i--) {
if (i != narr)
*bp++ = ' ';
@@ -3012,33 +3200,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);
+ strlcat(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 < (int)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,185 +3248,122 @@ static void
cookedprint(
int datatype,
int length,
- char *data,
+ const char *data,
int status,
+ int quiet,
FILE *fp
)
{
- register int varid;
char *name;
char *value;
char output_raw;
int fmt;
- 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;
+ size_t len;
+ l_fp lfparr[8];
+ char b[12];
+ char bn[2 * MAXVARLEN];
+ char bv[2 * MAXVALLEN];
- switch (datatype) {
- case TYPE_PEER:
- varlist = peer_var;
- break;
- case TYPE_SYS:
- varlist = sys_var;
- break;
- case TYPE_CLOCK:
- varlist = clock_var;
- break;
- default:
- (void) fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n", datatype);
- return;
- }
+ UNUSED_ARG(datatype);
- (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)) {
- varid = findvar(name, varlist, 0);
- if (varid == 0) {
+ fmt = varfmt(name);
+ output_raw = 0;
+ switch (fmt) {
+
+ case PADDING:
output_raw = '*';
- } else {
- output_raw = 0;
- fmt = varlist[varid].fmt;
- switch(fmt) {
- case TS:
- if (!decodets(value, &lfp))
- output_raw = '?';
- else
- output(fp, name, prettydate(&lfp));
- break;
- case FL:
- case FU:
- case FS:
- if (!decodetime(value, &lfp))
- output_raw = '?';
- else {
- switch (fmt) {
- case FL:
- output(fp, name,
- lfptoms(&lfp, 3));
- break;
- case FU:
- output(fp, name,
- ulfptoms(&lfp, 3));
- break;
- case FS:
- output(fp, name,
- lfptoms(&lfp, 3));
- break;
- }
- }
- break;
-
- case UI:
- if (!decodeuint(value, &uval))
- output_raw = '?';
- else
- output(fp, name, uinttoa(uval));
- break;
-
- case SI:
- if (!decodeint(value, &ival))
- output_raw = '?';
- else
- output(fp, name, inttoa(ival));
- break;
-
- case HA:
- case NA:
- if (!decodenetnum(value, &hval))
- output_raw = '?';
- else if (fmt == HA){
- output(fp, name, nntohost(&hval));
- } else {
- output(fp, name, stoa(&hval));
- }
- break;
-
- case ST:
- output_raw = '*';
- break;
-
- case RF:
- if (decodenetnum(value, &hval)) {
- if ((hval.ss_family == AF_INET) &&
- ISREFCLOCKADR(&hval))
- output(fp, name,
- refnumtoa(&hval));
- else
- output(fp, name, stoa(&hval));
- } else if ((int)strlen(value) <= 4)
- output(fp, name, value);
- else
- output_raw = '?';
- break;
-
- case LP:
- if (!decodeuint(value, &uval) || uval > 3)
- output_raw = '?';
- else {
- char b[3];
- b[0] = b[1] = '0';
- if (uval & 0x2)
- b[0] = '1';
- if (uval & 0x1)
- b[1] = '1';
- b[2] = '\0';
- output(fp, name, b);
- }
- break;
+ break;
- case OC:
- if (!decodeuint(value, &uval))
- output_raw = '?';
- else {
- char b[12];
+ case TS:
+ if (!decodets(value, &lfp))
+ output_raw = '?';
+ else
+ output(fp, name, prettydate(&lfp));
+ break;
- (void) snprintf(b, sizeof b, "%03lo", uval);
- output(fp, name, b);
- }
- break;
-
- case MD:
- if (!decodeuint(value, &uval))
- output_raw = '?';
- else
- output(fp, name, uinttoa(uval));
- break;
-
- case AR:
- if (!decodearr(value, &narr, lfparr))
- output_raw = '?';
- else
- outputarr(fp, name, narr, lfparr);
- break;
+ case HA: /* fallthru */
+ case NA:
+ if (!decodenetnum(value, &hval)) {
+ output_raw = '?';
+ } else if (fmt == HA){
+ output(fp, name, nntohost(&hval));
+ } else {
+ output(fp, name, stoa(&hval));
+ }
+ break;
- case FX:
- if (!decodeuint(value, &uval))
- output_raw = '?';
+ case RF:
+ if (decodenetnum(value, &hval)) {
+ if (ISREFCLOCKADR(&hval))
+ output(fp, name,
+ refnumtoa(&hval));
else
- output(fp, name, tstflags(uval));
- break;
-
- default:
- (void) fprintf(stderr,
- "Internal error in cookedprint, %s=%s, fmt %d\n",
- name, value, fmt);
- break;
+ output(fp, name, stoa(&hval));
+ } else if (strlen(value) <= 4) {
+ output(fp, name, value);
+ } else {
+ output_raw = '?';
+ }
+ break;
+
+ case LP:
+ if (!decodeuint(value, &uval) || uval > 3) {
+ output_raw = '?';
+ } else {
+ b[0] = (0x2 & uval)
+ ? '1'
+ : '0';
+ b[1] = (0x1 & uval)
+ ? '1'
+ : '0';
+ b[2] = '\0';
+ output(fp, name, b);
+ }
+ break;
+
+ case OC:
+ if (!decodeuint(value, &uval)) {
+ output_raw = '?';
+ } else {
+ snprintf(b, sizeof(b), "%03lo", uval);
+ output(fp, name, b);
}
+ break;
+
+ case AR:
+ if (!decodearr(value, &narr, lfparr))
+ output_raw = '?';
+ else
+ outputarr(fp, name, narr, lfparr);
+ break;
+ case FX:
+ if (!decodeuint(value, &uval))
+ output_raw = '?';
+ else
+ output(fp, name, tstflags(uval));
+ break;
+
+ default:
+ fprintf(stderr, "Internal error in cookedprint, %s=%s, fmt %d\n",
+ name, value, fmt);
+ output_raw = '?';
+ break;
}
- if (output_raw != 0) {
- char bn[401];
- char bv[401];
- int len;
- atoascii(400, name, bn);
- atoascii(400, value, bv);
+ if (output_raw != 0) {
+ atoascii(name, MAXVARLEN, bn, sizeof(bn));
+ atoascii(value, MAXVALLEN, bv, sizeof(bv));
if (output_raw != '*') {
len = strlen(bv);
bv[len] = output_raw;
@@ -3247,47 +3383,182 @@ 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(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
+
+
+/*
+ * grow_assoc_cache() - enlarge dynamic assoc_cache array
+ *
+ * The strategy is to add an assumed 4k page size at a time, leaving
+ * room for malloc() bookkeeping overhead equivalent to 4 pointers.
+ */
+void
+grow_assoc_cache(void)
+{
+ static size_t prior_sz;
+ size_t new_sz;
+
+ new_sz = prior_sz + 4 * 1024;
+ if (0 == prior_sz) {
+ new_sz -= 4 * sizeof(void *);
+ }
+ assoc_cache = erealloc_zero(assoc_cache, new_sz, prior_sz);
+ prior_sz = new_sz;
+ assoc_cache_slots = new_sz / sizeof(assoc_cache[0]);
+}
+
+
+/*
+ * 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;
+ }
+}
+/*
+ * Obtain list of digest names
+ */
+
+#ifdef OPENSSL
+# ifdef HAVE_EVP_MD_DO_ALL_SORTED
+struct hstate {
+ char *list;
+ const char **seen;
+ int idx;
+};
+#define K_PER_LINE 8
+#define K_NL_PFX_STR "\n "
+#define K_DELIM_STR ", "
+static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg )
+{
+ size_t len, n;
+ const char *name, *cp, **seen;
+ struct hstate *hstate = arg;
+ EVP_MD_CTX ctx;
+ u_int digest_len;
+ u_char digest[EVP_MAX_MD_SIZE];
+
+ if (!m)
+ return; /* Ignore aliases */
+
+ name = EVP_MD_name(m);
+
+ /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
+
+ for( cp = name; *cp; cp++ ) {
+ if( islower(*cp) )
+ return;
+ }
+ len = (cp - name) + 1;
+
+ /* There are duplicates. Discard if name has been seen. */
+
+ for (seen = hstate->seen; *seen; seen++)
+ if (!strcmp(*seen, name))
+ return;
+ n = (seen - hstate->seen) + 2;
+ hstate->seen = realloc(hstate->seen, n * sizeof(*seen));
+ hstate->seen[n-2] = name;
+ hstate->seen[n-1] = NULL;
+
+ /* Discard MACs that NTP won't accept.
+ * Keep this consistent with keytype_from_text() in ssl_init.c.
+ */
+
+ EVP_DigestInit(&ctx, EVP_get_digestbyname(name));
+ EVP_DigestFinal(&ctx, digest, &digest_len);
+ if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t)))
+ return;
+
+ if (hstate->list != NULL)
+ len += strlen(hstate->list);
+ len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR);
+
+ if (hstate->list == NULL) {
+ hstate->list = (char *)malloc(len);
+ hstate->list[0] = '\0';
+ } else
+ hstate->list = (char *)realloc(hstate->list, len);
+
+ sprintf(hstate->list + strlen(hstate->list), "%s%s",
+ ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR),
+ name);
+ if (hstate->idx >= K_PER_LINE)
+ hstate->idx = 1;
+ else
+ hstate->idx++;
+}
+# endif
+#endif
+
+static char *list_digest_names(void)
+{
+ char *list = NULL;
+
+#ifdef OPENSSL
+# ifdef HAVE_EVP_MD_DO_ALL_SORTED
+ struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
+
+ hstate.seen = (const char **)calloc(1, sizeof( const char * ));
+
+ INIT_SSL();
+ EVP_MD_do_all_sorted(list_md_fn, &hstate);
+ list = hstate.list;
+ free(hstate.seen);
+# else
+ list = (char *)malloc(sizeof("md5, others (upgrade to OpenSSL-1.0 for full list)"));
+ strcpy(list, "md5, others (upgrade to OpenSSL-1.0 for full list)");
+# endif
+#else
+ list = (char *)malloc(sizeof("md5"));
+ strcpy(list, "md5");
+#endif
+
+ return list;
}
-#endif /* not QSORT_USES_VOID_P */
OpenPOWER on IntegriCloud