+* [Bug 1003] ntpdc unconfig command doesn't prompt for keyid.
+* [Bug 1376] Enable authenticated ntpq and ntpdc using newly-available
+ digest types.
+* ntp-keygen, Autokey OpenSSL build vs. run version mismatch is now a
+ non-fatal warning.
(4.2.5p242-RC) 2009/11/10 Released by Harlan Stenn <stenn@ntp.org>
* [Bug 1363] CID 92 clarify fallthrough case in clk_trimtsip.c
* [Bug 1366] ioctl(TIOCSCTTY, 0) fails on NetBSD *[0-2].* > 3.99.7.
#ifndef NTP_REQUEST_H
#define NTP_REQUEST_H
+#include "stddef.h"
#include "ntp_types.h"
#include "recvbuff.h"
/* struct conf_peer must fit */
l_fp tstamp; /* time stamp, for authentication */
keyid_t keyid; /* (optional) encryption key */
- char mac[MAX_MD5_LEN-sizeof(u_int32)]; /* (optional) auth code */
+ char mac[MAX_MD5_LEN-sizeof(keyid_t)]; /* (optional) auth code */
};
/*
struct req_pkt_tail {
l_fp tstamp; /* time stamp, for authentication */
keyid_t keyid; /* (optional) encryption key */
- char mac[MAX_MD5_LEN-sizeof(u_int32)]; /* (optional) auth code */
+ char mac[MAX_MD5_LEN-sizeof(keyid_t)]; /* (optional) auth code */
};
-/*
- * Input packet lengths. One with the mac, one without.
- */
-#define REQ_LEN_HDR 8 /* 4 * u_char + 2 * u_short */
-#define REQ_LEN_MAC (sizeof(struct req_pkt))
-#define REQ_LEN_NOMAC (sizeof(struct req_pkt) - MAX_MD5_LEN)
+/* MODE_PRIVATE request packet header length before optional items. */
+#define REQ_LEN_HDR (offsetof(struct req_pkt, data))
+/* MODE_PRIVATE request packet fixed length without MAC. */
+#define REQ_LEN_NOMAC (offsetof(struct req_pkt, keyid))
/*
- * A response packet. The length here is variable, this is a
- * maximally sized one. Note that this implementation doesn't
+ * A MODE_PRIVATE response packet. The length here is variable, this
+ * is a maximally sized one. Note that this implementation doesn't
* authenticate responses.
*/
-#define RESP_HEADER_SIZE (8)
+#define RESP_HEADER_SIZE (offsetof(struct resp_pkt, data))
#define RESP_DATA_SIZE (500)
struct resp_pkt {
__attribute__((__format__(__printf__, 2, 3)));
/*
- * When building without OpenSSL, use one constant #define, NID_md5,
- * for the keytype. MD5 is the only digest supported without OpenSSL.
+ * When building without OpenSSL, use a few macros of theirs to
+ * minimize source differences in NTP.
*/
#ifndef OPENSSL
#define NID_md5 4 /* from openssl/objects.h */
+/* from openssl/evp.h */
+#define EVP_MAX_MD_SIZE 64 /* longest known is SHA512 */
#endif
extern void auth_delkeys (void);
#else /* !OPENSSL follows */
#define INIT_SSL() do {} while (0)
#endif
+extern int keytype_from_text (const char *, size_t *);
+extern const char *keytype_name (int);
+
/* lib/isc/win32/strerror.c
*
int length /* packet length */
)
{
- u_char digest[32];
+ u_char digest[EVP_MAX_MD_SIZE];
u_int len;
#ifdef OPENSSL
EVP_MD_CTX ctx;
int size /* MAC size */
)
{
- u_char digest[32];
+ u_char digest[EVP_MAX_MD_SIZE];
u_int len;
#ifdef OPENSSL
EVP_MD_CTX ctx;
continue;
}
#ifdef OPENSSL
-
/*
- * If the key type is 'M' or 'm', it is replaced by 'MD5".
- * In any case, it must be one of the algorithms supported
- * by OpenSSL. The key type is the NID used by the message
- * digest algorithm. Ther are a number of inconsistencies in
- * the OpenSSL database. We attempt to discover them here
- * and prevent use of inconsistent data.
+ * The key type is the NID used by the message digest
+ * algorithm. There are a number of inconsistencies in
+ * the OpenSSL database. We attempt to discover them
+ * here and prevent use of inconsistent data.
*/
- if (strcmp(token, "M") == 0 || strcmp(token, "m") == 0)
- token = "MD5";
- keytype = OBJ_sn2nid(token);
+ keytype = keytype_from_text(token, NULL);
if (keytype == 0 || keytype > 255) {
msyslog(LOG_ERR,
"authreadkeys: invalid type for key %d", keyno);
#endif
#include <ntp.h>
#include <ntp_debug.h>
+#include <lib_strbuf.h>
-#ifndef OPENSSL
-int ssl_init__non_empty_compliation_unit;
-#else /* OPENSSL follows */
+#ifdef OPENSSL
#include "openssl/err.h"
#include "openssl/rand.h"
ssl_check_version(void)
{
if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
- msyslog(LOG_ERR,
+ msyslog(LOG_WARNING,
"OpenSSL version mismatch. Built against %lx, you have %lx",
OPENSSL_VERSION_NUMBER, SSLeay());
fprintf(stderr,
"OpenSSL version mismatch. Built against %lx, you have %lx\n",
OPENSSL_VERSION_NUMBER, SSLeay());
- exit (-1);
}
INIT_SSL();
}
#endif /* OPENSSL */
+
+
+/*
+ * keytype_from_text returns OpenSSL NID for digest by name, and
+ * optionally the associated digest length.
+ *
+ * Used by ntpd authreadkeys(), ntpq and ntpdc keytype()
+ */
+int
+keytype_from_text(
+ const char *keytype_name,
+ size_t *pdigest_len
+ )
+{
+ int key_type;
+ u_int digest_len;
+#ifdef OPENSSL
+ char digest[EVP_MAX_MD_SIZE];
+ char * upcased;
+ char * pch;
+ EVP_MD_CTX ctx;
+
+ /*
+ * OpenSSL digest short names are capitalized, so uppercase the
+ * digest name before passing to OBJ_sn2nid(). If it is not
+ * recognized but begins with 'M' use NID_md5 to be consistent
+ * with past behavior.
+ */
+ INIT_SSL();
+ LIB_GETBUF(upcased);
+ strncpy(upcased, keytype_name, LIB_BUFLENGTH);
+ for (pch = upcased; '\0' != *pch; pch++)
+ *pch = (char)toupper(*pch);
+ key_type = OBJ_sn2nid(upcased);
+#else
+ key_type = 0;
+#endif
+
+ if (!key_type && 'm' == tolower(keytype_name[0]))
+ key_type = NID_md5;
+
+ if (!key_type)
+ return 0;
+
+ if (NULL != pdigest_len) {
+#ifdef OPENSSL
+ EVP_DigestInit(&ctx, EVP_get_digestbynid(key_type));
+ EVP_DigestFinal(&ctx, digest, &digest_len);
+#else
+ digest_len = 16;
+#endif
+ *pdigest_len = digest_len;
+ }
+
+ return key_type;
+}
+
+
+/*
+ * keytype_name returns OpenSSL short name for digest by NID.
+ *
+ * Used by ntpq and ntpdc keytype()
+ */
+const char *
+keytype_name(
+ int nid
+ )
+{
+ static const char unknown_type[] = "(unknown key type)";
+ const char *name;
+
+#ifdef OPENSSL
+ INIT_SSL();
+ name = OBJ_nid2sn(nid);
+ if (NULL == name)
+ name = unknown_type;
+#else /* !OPENSSL follows */
+ if (nid_MD5 == nid)
+ name = "MD5";
+ else
+ name = unknown_type;
+#endif
+ return name;
+}
+
exit(2);
}
} else {
- my_state = sst_highwater++;
- while (my_state < COUNTOF(sst)
- && sst[my_state].finishes_token)
+ do
my_state = sst_highwater++;
+ while (my_state < COUNTOF(sst)
+ && sst[my_state].finishes_token);
if (my_state >= COUNTOF(sst)) {
fprintf(stderr,
"fatal, keyword scanner state array "
sst[token] = sst[my_state];
memset(&sst[my_state], 0,
sizeof(sst[my_state]));
- sst_highwater--;
- while (sst[sst_highwater].finishes_token)
+ do
sst_highwater--;
+ while (sst[sst_highwater].finishes_token);
my_state = token;
if (prev_char_s)
sst[prev_char_s].other_next_s = my_state;
FD_SET(sockfd, &fdset);
while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
0) {
- recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
+ recv(sockfd, (char *)&reqpkt, sizeof(reqpkt), 0);
FD_ZERO(&fdset);
FD_SET(sockfd, &fdset);
}
};
static void req_ack (sockaddr_u *, struct interface *, struct req_pkt *, int);
-static char * prepare_pkt (sockaddr_u *, struct interface *, struct req_pkt *, u_int);
+static char * prepare_pkt (sockaddr_u *, struct interface *,
+ struct req_pkt *, size_t);
static char * more_pkt (void);
static void flush_pkt (void);
static void peer_list (sockaddr_u *, struct interface *, struct req_pkt *);
sockaddr_u *srcadr,
struct interface *inter,
struct req_pkt *pkt,
- u_int structsize
+ size_t structsize
)
{
-#ifdef DEBUG
- if (debug > 3)
- printf("request: preparing pkt\n");
-#endif
+ DPRINTF(4, ("request: preparing pkt\n"));
/*
* Fill in the implementation, request and itemsize fields
* If we were using the extra buffer, send the packet.
*/
if (usingexbuf) {
-#ifdef DEBUG
- if (debug > 2)
- printf("request: sending pkt\n");
-#endif
+ DPRINTF(3, ("request: sending pkt\n"));
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
rpkt.err_nitems = htons((u_short)nitems);
sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
- RESP_HEADER_SIZE+databytes);
+ RESP_HEADER_SIZE + databytes);
numresppkts++;
/*
* Copy data out of exbuf into the packet.
*/
- memmove(&rpkt.data[0], exbuf, (unsigned)itemsize);
+ memcpy(&rpkt.data[0], exbuf, (unsigned)itemsize);
seqno++;
databytes = 0;
nitems = 0;
databytes += itemsize;
nitems++;
if (databytes + itemsize <= RESP_DATA_SIZE) {
-#ifdef DEBUG
- if (debug > 3)
- printf("request: giving him more data\n");
-#endif
+ DPRINTF(4, ("request: giving him more data\n"));
/*
* More room in packet. Give him the
* next address.
* No room in packet. Give him the extra
* buffer unless this was the last in the sequence.
*/
-#ifdef DEBUG
- if (debug > 3)
- printf("request: into extra buffer\n");
-#endif
+ DPRINTF(4, ("request: into extra buffer\n"));
if (seqno == MAXSEQ)
- return (char *)0;
+ return NULL;
else {
usingexbuf = 1;
return exbuf;
static void
flush_pkt(void)
{
-#ifdef DEBUG
- if (debug > 2)
- printf("request: flushing packet, %d items\n", nitems);
-#endif
+ DPRINTF(3, ("request: flushing packet, %d items\n", nitems));
/*
* Must send the last packet. If nothing in here and nothing
* has been sent, send an error saying no data to be found.
*/
if (seqno == 0 && nitems == 0)
- req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
- INFO_ERR_NODATA);
+ req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
+ INFO_ERR_NODATA);
else {
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt;
return (INFO_MODE(inpkt->rm_vn_mode));
}
+
+
/*
* process_private - process private mode (7) packets
*/
struct req_proc *proc;
int ec;
short temp_size;
+ l_fp ftmp;
+ double dtemp;
+ size_t recv_len;
+ size_t noslop_len;
+ size_t mac_len;
/*
* Initialize pointers, for convenience
*/
+ recv_len = rbufp->recv_length;
inpkt = (struct req_pkt *)&rbufp->recv_pkt;
srcadr = &rbufp->recv_srcadr;
inter = rbufp->dstadr;
-#ifdef DEBUG
- if (debug > 2)
- printf("process_private: impl %d req %d\n",
- inpkt->implementation, inpkt->request);
-#endif
+ DPRINTF(3, ("process_private: impl %d req %d\n",
+ inpkt->implementation, inpkt->request));
/*
* Do some sanity checks on the packet. Return a format
* Get the appropriate procedure list to search.
*/
if (inpkt->implementation == IMPL_UNIV)
- proc = univ_codes;
+ proc = univ_codes;
else if ((inpkt->implementation == IMPL_XNTPD) ||
(inpkt->implementation == IMPL_XNTPD_OLD))
- proc = ntp_codes;
+ proc = ntp_codes;
else {
req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
return;
*/
while (proc->request_code != NO_REQUEST) {
if (proc->request_code == (short) inpkt->request)
- break;
+ break;
proc++;
}
if (proc->request_code == NO_REQUEST) {
return;
}
-#ifdef DEBUG
- if (debug > 3)
- printf("found request in tables\n");
-#endif
+ DPRINTF(4, ("found request in tables\n"));
/*
* If we need data, check to see if we have some. If we
!(inpkt->implementation == IMPL_XNTPD &&
inpkt->request == REQ_CONFIG &&
temp_size == sizeof(struct old_conf_peer))) {
-#ifdef DEBUG
- if (debug > 2)
- printf("process_private: wrong item size, received %d, should be %d or %d\n",
- temp_size, proc->sizeofitem, proc->v6_sizeofitem);
-#endif
+ DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n",
+ temp_size, proc->sizeofitem, proc->v6_sizeofitem));
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if ((proc->sizeofitem != 0) &&
- ((temp_size * INFO_NITEMS(inpkt->err_nitems)) >
- (rbufp->recv_length - REQ_LEN_HDR))) {
-#ifdef DEBUG
- if (debug > 2)
- printf("process_private: not enough data\n");
-#endif
+ ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) >
+ (recv_len - REQ_LEN_HDR))) {
+ DPRINTF(3, ("process_private: not enough data\n"));
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
* time stamp.
*/
if (proc->needs_auth && sys_authenticate) {
- l_fp ftmp;
- double dtemp;
- if (rbufp->recv_length < (REQ_LEN_HDR +
+ if (recv_len < (REQ_LEN_HDR +
(INFO_ITEMSIZE(inpkt->mbz_itemsize) *
INFO_NITEMS(inpkt->err_nitems)) +
sizeof(*tailinpkt))) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
- }
- tailinpkt = (void *)((char *)&rbufp->recv_pkt +
- rbufp->recv_length - sizeof(*tailinpkt));
+ }
+
+ /*
+ * For 16-octet digests, regardless of itemsize and
+ * nitems, authenticated requests are a fixed size
+ * with the timestamp, key ID, and digest located
+ * at the end of the packet. Because the key ID
+ * determining the digest size precedes the digest,
+ * for larger digests the fixed size request scheme
+ * is abandoned and the timestamp, key ID, and digest
+ * are located relative to the start of the packet,
+ * with the digest size determined by the packet size.
+ */
+ noslop_len = REQ_LEN_HDR
+ + INFO_ITEMSIZE(inpkt->mbz_itemsize) *
+ INFO_NITEMS(inpkt->err_nitems)
+ + sizeof(inpkt->tstamp);
+ /* 32-bit alignment */
+ noslop_len = (noslop_len + 3) & ~3;
+ if (recv_len > (noslop_len + MAX_MAC_LEN))
+ mac_len = 20;
+ else
+ mac_len = recv_len - noslop_len;
+
+ tailinpkt = (void *)((char *)inpkt + recv_len -
+ (mac_len + sizeof(inpkt->tstamp)));
/*
- * If this guy is restricted from doing this, don't let him
- * If wrong key was used, or packet doesn't have mac, return.
+ * If this guy is restricted from doing this, don't let
+ * him. If the wrong key was used, or packet doesn't
+ * have mac, return.
*/
- if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0
+ if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid
|| ntohl(tailinpkt->keyid) != info_auth_keyid) {
+ DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %lu maclen %u\n",
+ INFO_IS_AUTH(inpkt->auth_seq),
+ info_auth_keyid,
+ ntohl(tailinpkt->keyid), mac_len));
#ifdef DEBUG
- if (debug > 4)
- printf("failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
- INFO_IS_AUTH(inpkt->auth_seq),
- (u_long)info_auth_keyid,
- (u_long)ntohl(tailinpkt->keyid));
msyslog(LOG_DEBUG,
- "process_private: failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
+ "process_private: failed auth %d info_auth_keyid %u pkt keyid %lu maclen %u\n",
INFO_IS_AUTH(inpkt->auth_seq),
- (u_long)info_auth_keyid,
- (u_long)ntohl(tailinpkt->keyid));
+ info_auth_keyid,
+ ntohl(tailinpkt->keyid), mac_len);
#endif
req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
return;
}
- if (rbufp->recv_length > REQ_LEN_MAC) {
-#ifdef DEBUG
- if (debug > 4)
- printf("bad pkt length %d\n",
- rbufp->recv_length);
-#endif
- msyslog(LOG_ERR, "process_private: bad pkt length %d",
- rbufp->recv_length);
+ if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) {
+ DPRINTF(5, ("bad pkt length %d\n", recv_len));
+ msyslog(LOG_ERR,
+ "process_private: bad pkt length %d",
+ recv_len);
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if (!mod_okay || !authhavekey(info_auth_keyid)) {
+ DPRINTF(5, ("failed auth mod_okay %d\n",
+ mod_okay));
#ifdef DEBUG
- if (debug > 4)
- printf("failed auth mod_okay %d\n", mod_okay);
msyslog(LOG_DEBUG,
"process_private: failed auth mod_okay %d\n",
mod_okay);
* So far so good. See if decryption works out okay.
*/
if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
- rbufp->recv_length - sizeof(struct req_pkt_tail) +
- REQ_LEN_HDR, sizeof(struct req_pkt_tail) - REQ_LEN_HDR)) {
-#ifdef DEBUG
- if (debug > 4)
- printf("authdecrypt failed\n");
-#endif
+ recv_len - mac_len, mac_len)) {
+ DPRINTF(5, ("authdecrypt failed\n"));
req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
return;
}
}
-#ifdef DEBUG
- if (debug > 3)
- printf("process_private: all okay, into handler\n");
-#endif
-
+ DPRINTF(3, ("process_private: all okay, into handler\n"));
/*
* Packet is okay. Call the handler to send him data.
*/
*/
#include <stdio.h>
-
+#include <stddef.h>
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
static u_long info_auth_keyid;
static int keyid_entered = 0;
-static int info_auth_keytype = NID_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 */
/*
* Built in command handler declarations
*/
static int openhost (const char *);
-static int sendpkt (char *, int);
+static int sendpkt (void *, size_t);
static void growpktdata (void);
static int getresponse (int, int, int *, int *, char **, int);
-static int sendrequest (int, int, int, int, int, char *);
+static int sendrequest (int, int, int, u_int, size_t, char *);
static void getcmds (void);
static RETSIGTYPE abortcmd (int);
static void docmd (const char *);
*/
static int
sendpkt(
- char *xdata,
- int xdatalen
+ void * xdata,
+ size_t xdatalen
)
{
- if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
+ if (send(sockfd, xdata, xdatalen, 0) == -1) {
warning("write to %s failed", currenthost, "");
return -1;
}
growpktdata(void)
{
pktdatasize += INCDATASIZE;
- pktdata = (char *)realloc(pktdata, (unsigned)pktdatasize);
- if (pktdata == 0) {
- (void) fprintf(stderr, "%s: realloc() failed!\n", progname);
- exit(1);
- }
+ pktdata = erealloc(pktdata, (size_t)pktdatasize);
}
again:
if (firstpkt)
- tvo = tvout;
+ tvo = tvout;
else
- tvo = tvsout;
+ tvo = tvsout;
FD_SET(sockfd, &fds);
n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
pad = esize - size;
else
pad = 0;
- if ((datasize = items*size) > (n-RESP_HEADER_SIZE)) {
+ datasize = items * size;
+ if ((size_t)datasize > (n-RESP_HEADER_SIZE)) {
if (debug)
printf(
"Received items %d, size %d (total %d), data in packet is %d\n",
if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
int offset = datap - pktdata;
growpktdata();
- *rdata = pktdata; /* might have been realloced ! */
+ *rdata = pktdata; /* might have been realloced ! */
datap = pktdata + offset;
}
/*
* items. This is so we can play nice with older implementations
*/
- tmp_data = (char *)rpkt.data;
- for(i = 0; i <items; i++){
- memmove(datap, tmp_data, (unsigned)size);
+ tmp_data = rpkt.data;
+ for (i = 0; i < items; i++) {
+ memcpy(datap, tmp_data, (unsigned)size);
tmp_data += size;
memset(datap + size, 0, pad);
datap += size + pad;
*/
++numrecv;
if (numrecv <= lastseq)
- goto again;
+ goto again;
return INFO_OKAY;
}
/*
* sendrequest - format and send a request packet
+ *
+ * Historically, ntpdc has used a fixed-size request packet regardless
+ * of the actual payload size. When authenticating, the timestamp, key
+ * ID, and digest have been placed just before the end of the packet.
+ * With the introduction in late 2009 of support for authenticated
+ * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
+ * come up four bytes short.
+ *
+ * To maintain interop while allowing for larger digests, the behavior
+ * is unchanged when using 16-octet digests. For larger digests, the
+ * timestamp, key ID, and digest are placed immediately following the
+ * request payload, with the overall packet size variable. ntpd can
+ * distinguish 16-octet digests by the overall request size being
+ * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled. When using a
+ * longer digest, that request size should be avoided.
+ *
+ * With the form used with 20-octet and larger digests, the timestamp,
+ * key ID, and digest are located by ntpd relative to the start of the
+ * packet, and the size of the digest is then implied by the packet
+ * size.
*/
static int
sendrequest(
int implcode,
int reqcode,
int auth,
- int qitems,
- int qsize,
+ u_int qitems,
+ size_t qsize,
char *qdata
)
{
struct req_pkt qpkt;
- int datasize;
+ size_t datasize;
+ size_t reqsize;
+ u_long key_id;
+ l_fp ts;
+ l_fp * ptstamp;
+ int maclen;
+ char pass_prompt[32];
+ char * pass;
- memset((char *)&qpkt, 0, sizeof qpkt);
+ memset(&qpkt, 0, sizeof(qpkt));
qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
qpkt.implementation = (u_char)implcode;
qpkt.request = (u_char)reqcode;
datasize = qitems * qsize;
- if (datasize != 0 && qdata != NULL) {
- memmove((char *)qpkt.data, qdata, (unsigned)datasize);
+ if (datasize && qdata != NULL) {
+ memcpy(qpkt.data, qdata, datasize);
qpkt.err_nitems = ERR_NITEMS(0, qitems);
qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
} else {
if (!auth || (keyid_entered && info_auth_keyid == 0)) {
qpkt.auth_seq = AUTH_SEQ(0, 0);
- return sendpkt((char *)&qpkt, req_pkt_size);
- } else {
- u_long key_id;
- l_fp ts;
- l_fp * ptstamp;
- int maclen;
- char * pass;
+ return sendpkt(&qpkt, req_pkt_size);
+ }
- if (info_auth_keyid == 0) {
- if (((struct conf_peer *)qpkt.data)->keyid > 0)
- info_auth_keyid = ((struct conf_peer *)qpkt.data)->keyid;
- else {
- key_id = getkeyid("Keyid: ");
- if (key_id == 0) {
- (void) fprintf(stderr,
- "Invalid key identifier\n");
- return 1;
- }
- info_auth_keyid = key_id;
- }
- }
- if (!authistrusted(info_auth_keyid)) {
- pass = getpass("MD5 Password: ");
- if (*pass == '\0') {
- (void) fprintf(stderr,
- "Invalid password\n");
- return (1);
- }
- authusekey(info_auth_keyid, info_auth_keytype,
- (u_char *)pass);
- authtrust(info_auth_keyid, 1);
+ if (info_auth_keyid == 0) {
+ key_id = getkeyid("Keyid: ");
+ if (!key_id) {
+ fprintf(stderr, "Invalid key identifier\n");
+ return 1;
}
- qpkt.auth_seq = AUTH_SEQ(1, 0);
- get_systime(&ts);
- L_ADD(&ts, &delay_time);
- ptstamp = (void *)((char *)&qpkt + req_pkt_size
- - sizeof(qpkt.tstamp));
- HTONL_FP(&ts, ptstamp);
- maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
- req_pkt_size);
- if (maclen == 0) {
- (void) fprintf(stderr, "Key not found\n");
- return (1);
+ info_auth_keyid = key_id;
+ }
+ if (!authistrusted(info_auth_keyid)) {
+ snprintf(pass_prompt, sizeof(pass_prompt),
+ "%s Password: ",
+ keytype_name(info_auth_keytype));
+ pass = getpass(pass_prompt);
+ if ('\0' == pass[0]) {
+ fprintf(stderr, "Invalid password\n");
+ return 1;
}
- return sendpkt((char *)&qpkt, (int)(req_pkt_size + maclen));
+ authusekey(info_auth_keyid, info_auth_keytype,
+ (u_char *)pass);
+ authtrust(info_auth_keyid, 1);
}
- /*NOTREACHED*/
+ qpkt.auth_seq = AUTH_SEQ(1, 0);
+ if (info_auth_hashlen > 16) {
+ /*
+ * Only ntpd which expects REQ_LEN_NOMAC plus maclen
+ * octets in an authenticated request using a 16 octet
+ * digest (that is, a newer ntpd) will handle digests
+ * larger than 16 octets, so for longer digests, do
+ * not attempt to shorten the requests for downlevel
+ * ntpd compatibility.
+ */
+ if (REQ_LEN_NOMAC != req_pkt_size)
+ return 1;
+ reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp);
+ /* align to 32 bits */
+ reqsize = (reqsize + 3) & ~3;
+ } else
+ reqsize = req_pkt_size;
+ ptstamp = (void *)((char *)&qpkt + reqsize);
+ ptstamp--;
+ get_systime(&ts);
+ L_ADD(&ts, &delay_time);
+ HTONL_FP(&ts, ptstamp);
+ maclen = authencrypt(info_auth_keyid, (void *)&qpkt, reqsize);
+ if (!maclen) {
+ fprintf(stderr, "Key not found\n");
+ return 1;
+ } else if (maclen != (info_auth_hashlen + sizeof(keyid_t))) {
+ fprintf(stderr,
+ "%d octet MAC, %u expected with %u octet digest\n",
+ maclen, (info_auth_hashlen + sizeof(keyid_t)),
+ info_auth_hashlen);
+ return 1;
+ }
+ return sendpkt(&qpkt, reqsize + maclen);
}
*/
res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
if (res != 0)
- return res;
+ return res;
/*
* Get the response. If we got a standard error, print a message
/* log error message if not told to be quiet */
if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
switch(res) {
- case INFO_ERR_IMPL:
+ case INFO_ERR_IMPL:
/* Give us a chance to try the older implementation. */
if (implcode == IMPL_XNTPD)
break;
(void) fprintf(stderr,
"***Server implementation incompatable with our own\n");
break;
- case INFO_ERR_REQ:
+ case INFO_ERR_REQ:
(void) fprintf(stderr,
"***Server doesn't implement this request\n");
break;
- case INFO_ERR_FMT:
+ case INFO_ERR_FMT:
(void) fprintf(stderr,
"***Server reports a format error in the received packet (shouldn't happen)\n");
break;
- case INFO_ERR_NODATA:
+ case INFO_ERR_NODATA:
(void) fprintf(stderr,
"***Server reports data not found\n");
break;
- case INFO_ERR_AUTH:
+ case INFO_ERR_AUTH:
(void) fprintf(stderr, "***Permission denied\n");
break;
- case ERR_TIMEOUT:
+ case ERR_TIMEOUT:
(void) fprintf(stderr, "***Request timed out\n");
break;
- case ERR_INCOMPLETE:
+ case ERR_INCOMPLETE:
(void) fprintf(stderr,
"***Response from server was incomplete\n");
break;
- default:
+ default:
(void) fprintf(stderr,
"***Server returns unknown error code %d\n", res);
break;
FILE *fp
)
{
- if (pcmd->nargs == 0)
- fprintf(fp, "keytype is %s\n",
- (info_auth_keytype == NID_md5) ? "MD5" : "???");
- else
- switch (*(pcmd->argval[0].string)) {
- case 'm':
- case 'M':
- info_auth_keytype = NID_md5;
- break;
+ const char * digest_name;
+ size_t digest_len;
+ int keytype;
+
+ if (!pcmd->nargs) {
+ fprintf(fp, "keytype is %s with %u octet digests\n",
+ keytype_name(info_auth_keytype),
+ info_auth_hashlen);
+ return;
+ }
- default:
- fprintf(fp, "keytype must be 'md5'\n");
- }
-}
+ digest_name = pcmd->argval[0].string;
+ digest_len = 0;
+ keytype = keytype_from_text(digest_name, &digest_len);
+
+ if (!keytype) {
+ fprintf(fp, "keytype must be 'md5'%s\n",
+#ifdef OPENSSL
+ " or a digest type provided by OpenSSL");
+#else
+ "");
+#endif
+ return;
+ }
+ info_auth_keytype = keytype;
+ info_auth_hashlen = digest_len;
+}
/*
struct parse *pcmd,
FILE *fp,
int mode,
- int refc
+ int refc
)
{
struct conf_peer cpeer;
maxpoll = NTP_MAXDPOLL;
numtyp = 1;
if (refc)
- numtyp = 5;
+ numtyp = 5;
if (impl_ver == IMPL_XNTPD)
sendsize = sizeof(struct conf_peer);
break;
case PEVNT_RATE:
- last_event = "raate_exceeded";
+ last_event = "rate_exceeded";
break;
case PEVNT_DENY:
#include "ntp_stdlib.h"
#include "ntp_assert.h"
#include "ntp_lineedit.h"
+#include "ntp_debug.h"
#include "isc/net.h"
#include "isc/result.h"
#include <ssl_applink.c>
*/
u_long info_auth_keyid = 0;
-static int info_auth_keytype = NID_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 */
/*
*/
static int openhost (const char *);
-static int sendpkt (char *, int);
+static int sendpkt (void *, size_t);
static int getresponse (int, int, u_short *, int *, char **, int);
static int sendrequest (int, int, int, int, char *);
static char * tstflags (u_long);
*/
static int
sendpkt(
- char *xdata,
- int xdatalen
+ void * xdata,
+ size_t xdatalen
)
{
- if (debug >= 3)
- printf("Sending %d octets\n", xdatalen);
-
+ DPRINTF(3, ("Sending %u octets\n", xdatalen));
if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
warning("write to %s failed", currenthost, "");
if (debug >= 4) {
int first = 8;
+ char *cdata = xdata;
+
printf("Packet data:\n");
while (xdatalen-- > 0) {
if (first-- == 0) {
printf("\n");
first = 7;
}
- printf(" %02x", *xdata++ & 0xff);
+ printf(" %02x", *cdata++ & 0xff);
}
printf("\n");
}
)
{
struct ntp_control qpkt;
- int pktsize;
+ int pktsize;
+ u_long key_id;
+ char pass_prompt[32];
+ 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;
}
* If we have data, copy and pad it out to a 32-bit boundary.
*/
if (qsize > 0) {
- memcpy(qpkt.data, qdata, (unsigned)qsize);
+ memcpy(qpkt.data, qdata, (size_t)qsize);
pktsize += qsize;
while (pktsize & (sizeof(u_int32) - 1)) {
qpkt.data[qsize++] = 0;
* we're going to have to think about it a little.
*/
if (!auth && !always_auth) {
- return sendpkt((char *)&qpkt, pktsize);
- } else {
- char * pass = "\0";
- int maclen = 0;
+ return sendpkt(&qpkt, pktsize);
+ }
- /*
- * Pad out packet to a multiple of 8 octets to be sure
- * receiver can handle it.
- */
- while (pktsize & 7) {
- qpkt.data[qsize++] = 0;
- pktsize++;
- }
+ /*
+ * Pad out packet to a multiple of 8 octets to be sure
+ * receiver can handle it.
+ */
+ while (pktsize & 7) {
+ qpkt.data[qsize++] = 0;
+ pktsize++;
+ }
- /*
- * Get the keyid and the password if we don't have one.
- */
- if (info_auth_keyid == 0) {
- int u_keyid = getkeyid("Keyid: ");
- if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
- (void) fprintf(stderr,
- "Invalid key identifier\n");
- return 1;
- }
- info_auth_keyid = u_keyid;
+ /*
+ * Get the keyid and the password if we don't have one.
+ */
+ if (info_auth_keyid == 0) {
+ key_id = getkeyid("Keyid: ");
+ if (key_id == 0 || key_id > NTP_MAXKEY) {
+ fprintf(stderr,
+ "Invalid key identifier\n");
+ return 1;
}
- if (!authistrusted(info_auth_keyid)) {
- pass = getpass("MD5 Password: ");
- if (*pass == '\0') {
- (void) fprintf(stderr,
- "Invalid password\n");
- return (1);
- }
- authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
- authtrust(info_auth_keyid, 1);
+ info_auth_keyid = key_id;
+ }
+ if (!authistrusted(info_auth_keyid)) {
+ snprintf(pass_prompt, sizeof(pass_prompt),
+ "%s Password: ",
+ keytype_name(info_auth_keytype));
+ pass = getpass(pass_prompt);
+ if ('\0' == pass[0]) {
+ fprintf(stderr, "Invalid password\n");
+ return 1;
}
+ authusekey(info_auth_keyid, info_auth_keytype,
+ (u_char *)pass);
+ authtrust(info_auth_keyid, 1);
+ }
- /*
- * Do the encryption.
- */
- 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, %u expected with %u octet digest\n",
+ maclen, (info_auth_hashlen + sizeof(keyid_t)),
+ info_auth_hashlen);
+ return 1;
}
- /*NOTREACHED*/
+
+ return sendpkt((char *)&qpkt, pktsize + maclen);
}
FILE *fp
)
{
- if (pcmd->nargs == 0)
- fprintf(fp, "keytype is %s\n",
- (info_auth_keytype == NID_md5) ? "MD5" : "???");
- else
- switch (*(pcmd->argval[0].string)) {
- case 'm':
- case 'M':
- info_auth_keytype = NID_md5;
- break;
+ const char * digest_name;
+ size_t digest_len;
+ int key_type;
+
+ if (!pcmd->nargs) {
+ fprintf(fp, "keytype is %s with %u octet digests\n",
+ keytype_name(info_auth_keytype),
+ info_auth_hashlen);
+ return;
+ }
- default:
- fprintf(fp, "keytype must be 'md5'\n");
- }
-}
+ digest_name = pcmd->argval[0].string;
+ digest_len = 0;
+ key_type = keytype_from_text(digest_name, &digest_len);
+ if (!key_type) {
+ fprintf(fp, "keytype must be 'md5'%s\n",
+#ifdef OPENSSL
+ " or a digest type provided by OpenSSL");
+#else
+ "");
+#endif
+ return;
+ }
+
+ info_auth_keytype = key_type;
+ info_auth_hashlen = digest_len;
+}
/*