summaryrefslogtreecommitdiffstats
path: root/lib/libipsec/pfkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libipsec/pfkey.c')
-rw-r--r--lib/libipsec/pfkey.c767
1 files changed, 640 insertions, 127 deletions
diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c
index 11b6722..6cdea34 100644
--- a/lib/libipsec/pfkey.c
+++ b/lib/libipsec/pfkey.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: pfkey.c,v 1.31 2000/06/10 14:17:43 sakane Exp $ */
+/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
@@ -42,12 +42,16 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <stdio.h>
#include "ipsec_strerror.h"
#include "libpfkey.h"
#define CALLOC(size, cast) (cast)calloc(1, (size))
+static int findsupportedmap __P((int));
+static int setsupportedmap __P((struct sadb_supported *));
+static struct sadb_alg *findsupportedalg __P((u_int, u_int));
static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
@@ -56,94 +60,215 @@ static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
struct sockaddr *, struct sockaddr *, u_int32_t));
static int pfkey_send_x3 __P((int, u_int, u_int));
static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, char *, int, u_int32_t));
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ char *, int, u_int32_t));
static int pfkey_send_x5 __P((int, u_int, u_int32_t));
-static caddr_t pfkey_setsadbmsg __P((caddr_t, u_int, u_int,
+static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
u_int, u_int32_t, pid_t));
-static caddr_t pfkey_setsadbsa __P((caddr_t, u_int32_t, u_int,
+static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
u_int, u_int, u_int32_t));
-static caddr_t pfkey_setsadbaddr __P((caddr_t, u_int,
+static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
struct sockaddr *, u_int, u_int));
-static caddr_t pfkey_setsadbkey __P((caddr_t, u_int, caddr_t, u_int));
-static caddr_t pfkey_setsadblifetime __P((caddr_t, u_int, u_int32_t, u_int32_t,
- u_int32_t, u_int32_t));
-static caddr_t pfkey_setsadbxsa2 __P((caddr_t, u_int32_t, u_int32_t));
+static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
+static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t));
+static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
+
+/*
+ * make and search supported algorithm structure.
+ */
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };
+
+static int supported_map[] = {
+ SADB_SATYPE_AH,
+ SADB_SATYPE_ESP,
+ SADB_X_SATYPE_IPCOMP,
+};
+
+static int
+findsupportedmap(satype)
+ int satype;
+{
+ int i;
+
+ for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
+ if (supported_map[i] == satype)
+ return i;
+ return -1;
+}
+
+static struct sadb_alg *
+findsupportedalg(satype, alg_id)
+ u_int satype, alg_id;
+{
+ int algno;
+ int tlen;
+ caddr_t p;
+
+ /* validity check */
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return NULL;
+ }
+ if (ipsec_supported[algno] == NULL) {
+ __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+ return NULL;
+ }
+
+ tlen = ipsec_supported[algno]->sadb_supported_len
+ - sizeof(struct sadb_supported);
+ p = (caddr_t)(ipsec_supported[algno] + 1);
+ while (tlen > 0) {
+ if (tlen < sizeof(struct sadb_alg)) {
+ /* invalid format */
+ break;
+ }
+ if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)
+ return (struct sadb_alg *)p;
+
+ tlen -= sizeof(struct sadb_alg);
+ p += sizeof(struct sadb_alg);
+ }
+
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return NULL;
+}
+
+static int
+setsupportedmap(sup)
+ struct sadb_supported *sup;
+{
+ struct sadb_supported **ipsup;
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ if (*ipsup)
+ free(*ipsup);
+
+ *ipsup = malloc(sup->sadb_supported_len);
+ if (!*ipsup) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ memcpy(*ipsup, sup, sup->sadb_supported_len);
+
+ return 0;
+}
/*
* check key length against algorithm specified.
- * supported is either SADB_EXT_SUPPORTED_ENCRYPT or SADB_EXT_SUPPORTED_AUTH.
- * Refer to keyv2.h to get more info.
+ * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
+ * augument, and only calls to ipsec_check_keylen2();
* keylen is the unit of bit.
* OUT:
* -1: invalid.
* 0: valid.
*/
-struct sadb_msg *ipsec_supported = NULL;
-
int
ipsec_check_keylen(supported, alg_id, keylen)
u_int supported;
u_int alg_id;
u_int keylen;
{
- u_int tlen;
- caddr_t p;
- struct sadb_supported *sup;
- struct sadb_alg *alg;
+ int satype;
/* validity check */
- if (ipsec_supported == NULL) {
- __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
- return -1;
- }
switch (supported) {
case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
break;
default:
__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
return -1;
}
- tlen = ipsec_supported->sadb_msg_len - sizeof(struct sadb_msg);
- p = (caddr_t)ipsec_supported + sizeof(struct sadb_msg);
+ return ipsec_check_keylen2(satype, alg_id, keylen);
+}
- for (;
- tlen > 0;
- tlen -= sup->sadb_supported_len, p += sup->sadb_supported_len) {
+/*
+ * check key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen2(satype, alg_id, keylen)
+ u_int satype;
+ u_int alg_id;
+ u_int keylen;
+{
+ struct sadb_alg *alg;
- sup = (struct sadb_supported *)p;
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
- if (sup->sadb_supported_exttype != supported)
- continue;
+ if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
+ __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+ return -1;
+ }
- {
- u_int ttlen = sup->sadb_supported_len;
- caddr_t pp = p + sizeof(*sup);
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
- for (;
- ttlen > 0;
- ttlen -= sizeof(*alg), pp += sizeof(*alg)) {
- alg = (struct sadb_alg *)pp;
+/*
+ * get max/min key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_get_keylen(supported, alg_id, alg0)
+ u_int supported, alg_id;
+ struct sadb_alg *alg0;
+{
+ struct sadb_alg *alg;
+ u_int satype;
- if (alg->sadb_alg_id == alg_id)
- goto found;
- }
- }
+ /* validity check */
+ if (!alg0) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
}
- __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
- return -1;
- /* NOTREACHED */
-
- found:
- if (keylen < alg->sadb_alg_minbits
- || keylen > alg->sadb_alg_maxbits) {
- __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
return -1;
}
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ memcpy(alg0, alg, sizeof(*alg0));
+
__ipsec_errcode = EIPSEC_NO_ERROR;
return 0;
}
@@ -221,6 +346,7 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
u_int32_t min, max, reqid, seq;
{
struct sadb_msg *newmsg;
+ caddr_t ep;
int len;
int need_spirange = 0;
caddr_t p;
@@ -268,31 +394,59 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
__ipsec_set_strerror(strerror(errno));
return -1;
}
+ ep = ((caddr_t)newmsg) + len;
- p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_GETSPI,
- len, satype, seq, getpid());
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI,
+ len, satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
- p = pfkey_setsadbxsa2(p, mode, reqid);
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
/* set sadb_address for source */
- p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen,
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
/* set sadb_address for destination */
- p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen,
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
/* proccessing spi range */
if (need_spirange) {
- int _len = sizeof(struct sadb_spirange);
+ struct sadb_spirange spirange;
-#define _SADB_SPIRANGE(p) ((struct sadb_spirange *)(p))
- _SADB_SPIRANGE(p)->sadb_spirange_len = PFKEY_UNIT64(_len);
- _SADB_SPIRANGE(p)->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
- _SADB_SPIRANGE(p)->sadb_spirange_min = min;
- _SADB_SPIRANGE(p)->sadb_spirange_max = max;
-#undef _SADB_SPIRANGE(p)
- p += _len;
+ if (p + sizeof(spirange) > ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ memset(&spirange, 0, sizeof(spirange));
+ spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
+ spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ spirange.sadb_spirange_min = min;
+ spirange.sadb_spirange_max = max;
+
+ memcpy(p, &spirange, sizeof(spirange));
+
+ p += sizeof(spirange);
+ }
+ if (p != ep) {
+ free(newmsg);
+ return -1;
}
/* send message */
@@ -389,6 +543,91 @@ pfkey_send_delete(so, satype, mode, src, dst, spi)
}
/*
+ * sending SADB_DELETE without spi to the kernel. This is
+ * the "delete all" request (an extension also present in
+ * Solaris).
+ *
+ * OUT:
+ * positive: success and return length sent
+ * -1 : error occured, and set errno
+ */
+int
+pfkey_send_delete_all(so, satype, mode, src, dst)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
* sending SADB_GET message to the kernel.
* OUT:
* positive: success and return length sent.
@@ -419,7 +658,29 @@ pfkey_send_register(so, satype)
int so;
u_int satype;
{
- int len;
+ int len, algno;
+
+ if (satype == PF_UNSPEC) {
+ for (algno = 0;
+ algno < sizeof(supported_map)/sizeof(supported_map[0]);
+ algno++) {
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+ } else {
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
return -1;
@@ -440,51 +701,92 @@ pfkey_recv_register(so)
{
pid_t pid = getpid();
struct sadb_msg *newmsg;
- struct sadb_supported *sup;
- caddr_t p;
- int tlen;
+ int error = -1;
/* receive message */
do {
if ((newmsg = pfkey_recv(so)) == NULL)
return -1;
-
} while (newmsg->sadb_msg_type != SADB_REGISTER
|| newmsg->sadb_msg_pid != pid);
/* check and fix */
newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
- tlen = newmsg->sadb_msg_len - sizeof(struct sadb_msg);
- p = (caddr_t)newmsg + sizeof(struct sadb_msg);
- while (tlen > 0) {
+ error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
+ free(newmsg);
+
+ if (error == 0)
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return error;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * NOTE: sadb_msg_len must be host order.
+ * IN:
+ * tlen: msg length, it's to makeing sure.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_set_supported(msg, tlen)
+ struct sadb_msg *msg;
+ int tlen;
+{
+ struct sadb_supported *sup;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity */
+ if (msg->sadb_msg_len != tlen) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ p = (caddr_t)msg;
+ ep = p + tlen;
+
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
sup = (struct sadb_supported *)p;
+ if (ep < p + sizeof(*sup) ||
+ PFKEY_EXTLEN(sup) < sizeof(*sup) ||
+ ep < p + sup->sadb_supported_len) {
+ /* invalid format */
+ break;
+ }
+
switch (sup->sadb_supported_exttype) {
case SADB_EXT_SUPPORTED_AUTH:
case SADB_EXT_SUPPORTED_ENCRYPT:
- sup->sadb_supported_len = PFKEY_EXTLEN(sup);
break;
default:
__ipsec_errcode = EIPSEC_INVAL_SATYPE;
- free(newmsg);
return -1;
}
- tlen -= sup->sadb_supported_len;
+ /* fixed length */
+ sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+
+ /* set supported map */
+ if (setsupportedmap(sup) != 0)
+ return -1;
+
p += sup->sadb_supported_len;
}
- if (tlen < 0) {
+ if (p != ep) {
__ipsec_errcode = EIPSEC_INVAL_SATYPE;
return -1;
}
- if (ipsec_supported != NULL)
- free(ipsec_supported);
-
- ipsec_supported = newmsg;
-
__ipsec_errcode = EIPSEC_NO_ERROR;
+
return 0;
}
@@ -570,6 +872,35 @@ pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
policy, policylen, seq)) < 0)
return -1;
@@ -595,6 +926,35 @@ pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
policy, policylen, seq)) < 0)
return -1;
@@ -625,6 +985,7 @@ pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
src, prefs, dst, prefd, proto,
+ 0, 0,
policy, policylen, seq)) < 0)
return -1;
@@ -693,6 +1054,7 @@ pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
src, prefs, dst, prefd, proto,
+ 0, 0,
policy, policylen, seq)) < 0)
return -1;
@@ -753,6 +1115,7 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
int len;
caddr_t p;
int plen;
+ caddr_t ep;
/* validity check */
if (src == NULL || dst == NULL) {
@@ -793,6 +1156,14 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
}
break;
case SADB_X_SATYPE_IPCOMP:
+ if (e_type == SADB_X_CALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type != SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
break;
default:
__ipsec_errcode = EIPSEC_INVAL_SATYPE;
@@ -819,28 +1190,67 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
__ipsec_set_strerror(strerror(errno));
return -1;
}
+ ep = ((caddr_t)newmsg) + len;
- p = pfkey_setsadbmsg((caddr_t)newmsg, type, len,
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
satype, seq, getpid());
- p = pfkey_setsadbsa(p, spi, wsize, a_type, e_type, flags);
- p = pfkey_setsadbxsa2(p, mode, reqid);
- p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen,
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
IPSEC_ULPROTO_ANY);
- p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen,
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
- if (e_type != SADB_EALG_NONE)
- p = pfkey_setsadbkey(p, SADB_EXT_KEY_ENCRYPT,
+ if (e_type != SADB_EALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
keymat, e_keylen);
- if (a_type != SADB_AALG_NONE)
- p = pfkey_setsadbkey(p, SADB_EXT_KEY_AUTH,
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+ if (a_type != SADB_AALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
keymat + e_keylen, a_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
/* set sadb_lifetime for destination */
- p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_HARD,
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
l_alloc, l_bytes, l_addtime, l_usetime);
- p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_SOFT,
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
/* send message */
len = pfkey_send(so, newmsg, len);
@@ -865,6 +1275,7 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi)
int len;
caddr_t p;
int plen;
+ caddr_t ep;
/* validity check */
if (src == NULL || dst == NULL) {
@@ -899,13 +1310,31 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi)
__ipsec_set_strerror(strerror(errno));
return -1;
}
+ ep = ((caddr_t)newmsg) + len;
- p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, getpid());
- p = pfkey_setsadbsa(p, spi, 0, 0, 0, 0);
- p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen,
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
IPSEC_ULPROTO_ANY);
- p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen,
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
/* send message */
len = pfkey_send(so, newmsg, len);
@@ -929,6 +1358,8 @@ pfkey_send_x3(so, type, satype)
{
struct sadb_msg *newmsg;
int len;
+ caddr_t p;
+ caddr_t ep;
/* validity check */
switch (type) {
@@ -958,8 +1389,14 @@ pfkey_send_x3(so, type, satype)
__ipsec_set_strerror(strerror(errno));
return -1;
}
+ ep = ((caddr_t)newmsg) + len;
- (void)pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, getpid());
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
/* send message */
len = pfkey_send(so, newmsg, len);
@@ -974,10 +1411,12 @@ pfkey_send_x3(so, type, satype)
/* sending SADB_X_SPDADD message to the kernel */
static int
-pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq)
+pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
+ ltime, vtime, policy, policylen, seq)
int so;
struct sockaddr *src, *dst;
u_int type, prefs, prefd, proto;
+ u_int64_t ltime, vtime;
char *policy;
int policylen;
u_int32_t seq;
@@ -986,6 +1425,7 @@ pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq)
int len;
caddr_t p;
int plen;
+ caddr_t ep;
/* validity check */
if (src == NULL || dst == NULL) {
@@ -1019,25 +1459,37 @@ pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ PFKEY_ALIGN8(src->sa_len)
+ sizeof(struct sadb_address)
+ PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_lifetime)
+ policylen;
if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
__ipsec_set_strerror(strerror(errno));
return -1;
}
+ ep = ((caddr_t)newmsg) + len;
- p = pfkey_setsadbmsg((caddr_t)newmsg, type, len,
- SADB_SATYPE_UNSPEC, seq, getpid());
- p = pfkey_setsadbaddr(p,
- SADB_EXT_ADDRESS_SRC,
- src,
- prefs,
- proto);
- p = pfkey_setsadbaddr(p,
- SADB_EXT_ADDRESS_DST,
- dst,
- prefd,
- proto);
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ 0, 0, ltime, vtime);
+ if (!p || p + policylen != ep) {
+ free(newmsg);
+ return -1;
+ }
memcpy(p, policy, policylen);
/* send message */
@@ -1062,6 +1514,7 @@ pfkey_send_x5(so, type, spid)
struct sadb_x_policy xpl;
int len;
caddr_t p;
+ caddr_t ep;
/* create new sadb_msg to reply. */
len = sizeof(struct sadb_msg)
@@ -1071,15 +1524,23 @@ pfkey_send_x5(so, type, spid)
__ipsec_set_strerror(strerror(errno));
return -1;
}
+ ep = ((caddr_t)newmsg) + len;
- p = pfkey_setsadbmsg((caddr_t)newmsg, type, len,
- SADB_SATYPE_UNSPEC, 0, getpid());
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, 0, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ if (p + sizeof(xpl) != ep) {
+ free(newmsg);
+ return -1;
+ }
memset(&xpl, 0, sizeof(xpl));
xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl));
xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
xpl.sadb_x_policy_id = spid;
-
memcpy(p, &xpl, sizeof(xpl));
/* send message */
@@ -1143,6 +1604,8 @@ pfkey_close(so)
* OUT:
* NULL : error occured.
* others : a pointer to sadb_msg structure.
+ *
+ * XXX should be rewritten to pass length explicitly
*/
struct sadb_msg *
pfkey_recv(so)
@@ -1152,7 +1615,8 @@ pfkey_recv(so)
int len, reallen;
while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
- if (errno == EINTR) continue;
+ if (errno == EINTR)
+ continue;
__ipsec_set_strerror(strerror(errno));
return NULL;
}
@@ -1171,7 +1635,8 @@ pfkey_recv(so)
}
while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
- if (errno == EINTR) continue;
+ if (errno == EINTR)
+ continue;
__ipsec_set_strerror(strerror(errno));
free(newmsg);
return NULL;
@@ -1183,6 +1648,13 @@ pfkey_recv(so)
return NULL;
}
+ /* don't trust what the kernel says, validate! */
+ if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
__ipsec_errcode = EIPSEC_NO_ERROR;
return newmsg;
}
@@ -1219,6 +1691,8 @@ pfkey_send(so, msg, len)
* caddr_t mhp[SADB_EXT_MAX + 1];
* OUT: -1: invalid.
* 0: valid.
+ *
+ * XXX should be rewritten to obtain length explicitly
*/
int
pfkey_align(msg, mhp)
@@ -1226,8 +1700,9 @@ pfkey_align(msg, mhp)
caddr_t *mhp;
{
struct sadb_ext *ext;
- int tlen, extlen;
int i;
+ caddr_t p;
+ caddr_t ep; /* XXX should be passed from upper layer */
/* validity check */
if (msg == NULL || mhp == NULL) {
@@ -1241,10 +1716,21 @@ pfkey_align(msg, mhp)
mhp[0] = (caddr_t)msg;
- tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg);
- ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg));
+ /* initialize */
+ p = (caddr_t) msg;
+ ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
+
+ /* skip base header */
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ ext = (struct sadb_ext *)p;
+ if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) ||
+ ep < p + PFKEY_EXTLEN(ext)) {
+ /* invalid format */
+ break;
+ }
- while (tlen > 0) {
/* duplicate check */
/* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
if (mhp[ext->sadb_ext_type] != NULL) {
@@ -1281,9 +1767,12 @@ pfkey_align(msg, mhp)
return -1;
}
- extlen = PFKEY_EXTLEN(ext);
- tlen -= extlen;
- ext = (struct sadb_ext *)((caddr_t)ext + extlen);
+ p += PFKEY_EXTLEN(ext);
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+ return -1;
}
__ipsec_errcode = EIPSEC_NO_ERROR;
@@ -1413,8 +1902,9 @@ pfkey_check(mhp)
* `buf' must has been allocated sufficiently.
*/
static caddr_t
-pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid)
+pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
caddr_t buf;
+ caddr_t lim;
u_int type, satype;
u_int tlen;
u_int32_t seq;
@@ -1426,6 +1916,9 @@ pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid)
p = (struct sadb_msg *)buf;
len = sizeof(struct sadb_msg);
+ if (buf + len > lim)
+ return NULL;
+
memset(p, 0, len);
p->sadb_msg_version = PF_KEY_V2;
p->sadb_msg_type = type;
@@ -1444,8 +1937,9 @@ pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid)
* `buf' must has been allocated sufficiently.
*/
static caddr_t
-pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags)
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
caddr_t buf;
+ caddr_t lim;
u_int32_t spi, flags;
u_int wsize, auth, enc;
{
@@ -1455,6 +1949,9 @@ pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags)
p = (struct sadb_sa *)buf;
len = sizeof(struct sadb_sa);
+ if (buf + len > lim)
+ return NULL;
+
memset(p, 0, len);
p->sadb_sa_len = PFKEY_UNIT64(len);
p->sadb_sa_exttype = SADB_EXT_SA;
@@ -1474,8 +1971,9 @@ pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags)
* prefixlen is in bits.
*/
static caddr_t
-pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto)
+pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
caddr_t buf;
+ caddr_t lim;
u_int exttype;
struct sockaddr *saddr;
u_int prefixlen;
@@ -1487,6 +1985,9 @@ pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto)
p = (struct sadb_address *)buf;
len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+ if (buf + len > lim)
+ return NULL;
+
memset(p, 0, len);
p->sadb_address_len = PFKEY_UNIT64(len);
p->sadb_address_exttype = exttype & 0xffff;
@@ -1504,8 +2005,10 @@ pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto)
* OUT: the pointer of buf + len.
*/
static caddr_t
-pfkey_setsadbkey(buf, type, key, keylen)
- caddr_t buf, key;
+pfkey_setsadbkey(buf, lim, type, key, keylen)
+ caddr_t buf;
+ caddr_t lim;
+ caddr_t key;
u_int type, keylen;
{
struct sadb_key *p;
@@ -1514,6 +2017,9 @@ pfkey_setsadbkey(buf, type, key, keylen)
p = (struct sadb_key *)buf;
len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+ if (buf + len > lim)
+ return NULL;
+
memset(p, 0, len);
p->sadb_key_len = PFKEY_UNIT64(len);
p->sadb_key_exttype = type;
@@ -1530,8 +2036,9 @@ pfkey_setsadbkey(buf, type, key, keylen)
* OUT: the pointer of buf + len.
*/
static caddr_t
-pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime)
+pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
caddr_t buf;
+ caddr_t lim;
u_int type;
u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
{
@@ -1541,6 +2048,9 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime)
p = (struct sadb_lifetime *)buf;
len = sizeof(struct sadb_lifetime);
+ if (buf + len > lim)
+ return NULL;
+
memset(p, 0, len);
p->sadb_lifetime_len = PFKEY_UNIT64(len);
p->sadb_lifetime_exttype = type;
@@ -1572,8 +2082,9 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime)
* `buf' must has been allocated sufficiently.
*/
static caddr_t
-pfkey_setsadbxsa2(buf, mode0, reqid)
+pfkey_setsadbxsa2(buf, lim, mode0, reqid)
caddr_t buf;
+ caddr_t lim;
u_int32_t mode0;
u_int32_t reqid;
{
@@ -1584,6 +2095,9 @@ pfkey_setsadbxsa2(buf, mode0, reqid)
p = (struct sadb_x_sa2 *)buf;
len = sizeof(struct sadb_x_sa2);
+ if (buf + len > lim)
+ return NULL;
+
memset(p, 0, len);
p->sadb_x_sa2_len = PFKEY_UNIT64(len);
p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
@@ -1592,4 +2106,3 @@ pfkey_setsadbxsa2(buf, mode0, reqid)
return(buf + len);
}
-
OpenPOWER on IntegriCloud