diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2001-07-01 07:32:38 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2001-07-01 07:32:38 +0000 |
commit | b376fd7294172111549e664862aacf700d135815 (patch) | |
tree | 1f4dda6884c0a73f6c78bc18273ee2a2ea4b4d3d /sys/net/pfkeyv2_parsemessage.c | |
parent | 4800ac637f4bf58587b6ed063e8e0df0f51d3949 (diff) |
KNF, and add DPRINTFs all over the place.
Diffstat (limited to 'sys/net/pfkeyv2_parsemessage.c')
-rw-r--r-- | sys/net/pfkeyv2_parsemessage.c | 991 |
1 files changed, 641 insertions, 350 deletions
diff --git a/sys/net/pfkeyv2_parsemessage.c b/sys/net/pfkeyv2_parsemessage.c index aace2894136..a3a95f0a82d 100644 --- a/sys/net/pfkeyv2_parsemessage.c +++ b/sys/net/pfkeyv2_parsemessage.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkeyv2_parsemessage.c,v 1.26 2001/06/08 03:58:48 angelos Exp $ */ +/* $OpenBSD: pfkeyv2_parsemessage.c,v 1.27 2001/07/01 07:32:37 angelos Exp $ */ /* * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 @@ -76,6 +76,14 @@ #include <netinet/ip_ipsp.h> #include <net/pfkeyv2.h> +extern int encdebug; + +#ifdef ENCDEBUG +#define DPRINTF(x) if (encdebug) printf x +#else +#define DPRINTF(x) +#endif + #define BITMAP_SA (1 << SADB_EXT_SA) #define BITMAP_LIFETIME_CURRENT (1 << SADB_EXT_LIFETIME_CURRENT) #define BITMAP_LIFETIME_HARD (1 << SADB_EXT_LIFETIME_HARD) @@ -264,389 +272,672 @@ int pfkeyv2_parsemessage(void *, int, void **); int pfkeyv2_parsemessage(void *p, int len, void **headers) { - struct sadb_ext *sadb_ext; - int i, left = len; - uint32_t allow, seen = 1; - struct sadb_msg *sadb_msg = (struct sadb_msg *) p; - - bzero(headers, (SADB_EXT_MAX + 1) * sizeof(void *)); - - if (left < sizeof(struct sadb_msg)) - return EINVAL; - - headers[0] = p; - - if (sadb_msg->sadb_msg_len * sizeof(uint64_t) != left) - return EINVAL; - - p += sizeof(struct sadb_msg); - left -= sizeof(struct sadb_msg); - - if (sadb_msg->sadb_msg_reserved) - return EINVAL; - - if (sadb_msg->sadb_msg_type > SADB_MAX) - return EINVAL; - - if (!sadb_msg->sadb_msg_type) - return EINVAL; - - if (sadb_msg->sadb_msg_pid != curproc->p_pid) - return EINVAL; - - if (sadb_msg->sadb_msg_errno) { - if (left) - return EINVAL; - - return 0; - } - - if (sadb_msg->sadb_msg_type == SADB_X_PROMISC) - return 0; - - allow = sadb_exts_allowed_in[sadb_msg->sadb_msg_type]; - - while (left > 0) { - sadb_ext = (struct sadb_ext *)p; - if (left < sizeof(struct sadb_ext)) - return EINVAL; - - i = sadb_ext->sadb_ext_len * sizeof(uint64_t); - if (left < i) - return EINVAL; - - if (sadb_ext->sadb_ext_type > SADB_EXT_MAX) - return EINVAL; - - if (!sadb_ext->sadb_ext_type) - return EINVAL; - - if (!(allow & (1 << sadb_ext->sadb_ext_type))) - return EINVAL; - - if (headers[sadb_ext->sadb_ext_type]) - return EINVAL; - - seen |= (1 << sadb_ext->sadb_ext_type); - - switch (sadb_ext->sadb_ext_type) { - case SADB_EXT_SA: - case SADB_X_EXT_SA2: - { - struct sadb_sa *sadb_sa = (struct sadb_sa *)p; + struct sadb_ext *sadb_ext; + int i, left = len; + uint32_t allow, seen = 1; + struct sadb_msg *sadb_msg = (struct sadb_msg *) p; - if (i != sizeof(struct sadb_sa)) - return EINVAL; + bzero(headers, (SADB_EXT_MAX + 1) * sizeof(void *)); - if (sadb_sa->sadb_sa_state > SADB_SASTATE_MAX) - return EINVAL; - - if (sadb_sa->sadb_sa_state == SADB_SASTATE_DEAD) - return EINVAL; - - if (sadb_sa->sadb_sa_encrypt > SADB_EALG_MAX) - return EINVAL; - - if (sadb_sa->sadb_sa_auth > SADB_AALG_MAX) - return EINVAL; - - if (sadb_sa->sadb_sa_replay > 32) - return EINVAL; - } - break; - case SADB_X_EXT_PROTOCOL: - case SADB_X_EXT_FLOW_TYPE: - if (i != sizeof(struct sadb_protocol)) - return EINVAL; - break; - case SADB_X_EXT_POLICY: - if (i != sizeof(struct sadb_x_policy)) - return EINVAL; - break; - case SADB_EXT_LIFETIME_CURRENT: - case SADB_EXT_LIFETIME_HARD: - case SADB_EXT_LIFETIME_SOFT: - { - if (i != sizeof(struct sadb_lifetime)) - return EINVAL; + if (left < sizeof(struct sadb_msg)) { + DPRINTF(("pfkeyv2_parsemessage: message too short\n")); + return EINVAL; } - break; - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_X_EXT_SRC_MASK: - case SADB_X_EXT_DST_MASK: - case SADB_X_EXT_SRC_FLOW: - case SADB_X_EXT_DST_FLOW: - case SADB_X_EXT_DST2: - case SADB_EXT_ADDRESS_PROXY: - { - struct sadb_address *sadb_address = (struct sadb_address *)p; - struct sockaddr *sa = (struct sockaddr *)(p + sizeof(struct sadb_address)); - if (i < sizeof(struct sadb_address) + sizeof(struct sockaddr)) - return EINVAL; + headers[0] = p; - if (sadb_address->sadb_address_reserved) - return EINVAL; + if (sadb_msg->sadb_msg_len * sizeof(uint64_t) != left) { + DPRINTF(("pfkeyv2_parsemessage: length not a multiple of 64\n")); + return EINVAL; + } -#if SALEN - if (sa->sa_len && (i != sizeof(struct sadb_address) + sa->sa_len)) - return EINVAL; -#endif /* SALEN */ + p += sizeof(struct sadb_msg); + left -= sizeof(struct sadb_msg); - switch(sa->sa_family) { - case AF_INET: - if (sizeof(struct sadb_address) + sizeof(struct sockaddr_in) - != i) - return EINVAL; -#if SALEN - if (sa->sa_len != sizeof(struct sockaddr_in)) - return EINVAL; -#endif /* SALEN */ - - /* Only check the right pieces */ - switch (sadb_ext->sadb_ext_type) - { - case SADB_X_EXT_SRC_MASK: - case SADB_X_EXT_DST_MASK: - case SADB_X_EXT_SRC_FLOW: - case SADB_X_EXT_DST_FLOW: - break; - - default: - if (((struct sockaddr_in *)sa)->sin_port) - return EINVAL; - break; - } - - { - char zero[sizeof(((struct sockaddr_in *)sa)->sin_zero)]; - bzero(zero, sizeof(zero)); - - if (bcmp(&((struct sockaddr_in *)sa)->sin_zero, zero, - sizeof(zero))) - return EINVAL; - } - break; -#if INET6 - case AF_INET6: - if (i != sizeof(struct sadb_address) + - sizeof(struct sockaddr_in6) + 4) + if (sadb_msg->sadb_msg_reserved) { + DPRINTF(("pfkeyv2_parsemessage: message header reserved " + "field set\n")); return EINVAL; + } - if (sa->sa_len != sizeof(struct sockaddr_in6)) + if (sadb_msg->sadb_msg_type > SADB_MAX) { + DPRINTF(("pfkeyv2_parsemessage: message type > %d\n", + SADB_MAX)); return EINVAL; + } - if (((struct sockaddr_in6 *)sa)->sin6_flowinfo) + if (!sadb_msg->sadb_msg_type) { + DPRINTF(("pfkeyv2_parsemessage: message type unset\n")); return EINVAL; - - break; -#endif /* INET6 */ - default: - return EINVAL; - } } - break; - case SADB_EXT_KEY_AUTH: - case SADB_EXT_KEY_ENCRYPT: - { - struct sadb_key *sadb_key = (struct sadb_key *)p; - - if (i < sizeof(struct sadb_key)) - return EINVAL; - if (!sadb_key->sadb_key_bits) - return EINVAL; - - if (((sadb_key->sadb_key_bits + 63) / 64) * sizeof(uint64_t) != - i - sizeof(struct sadb_key)) - return EINVAL; - - if (sadb_key->sadb_key_reserved) - return EINVAL; + if (sadb_msg->sadb_msg_pid != curproc->p_pid) { + DPRINTF(("pfkeyv2_parsemessage: bad PID value\n")); + return EINVAL; } - break; - case SADB_X_EXT_LOCAL_AUTH: - case SADB_X_EXT_REMOTE_AUTH: - { - struct sadb_x_cred *sadb_cred = (struct sadb_x_cred *)p; - if (i < sizeof(struct sadb_x_cred)) - return EINVAL; - - if (sadb_cred->sadb_x_cred_type > SADB_X_AUTHTYPE_MAX) - return EINVAL; - - if (sadb_cred->sadb_x_cred_reserved) - return EINVAL; + if (sadb_msg->sadb_msg_errno) { + if (left) { + DPRINTF(("pfkeyv2_parsemessage: too-large error message\n")); + return EINVAL; + } + return 0; } - break; - case SADB_X_EXT_LOCAL_CREDENTIALS: - case SADB_X_EXT_REMOTE_CREDENTIALS: - { - struct sadb_x_cred *sadb_cred = (struct sadb_x_cred *)p; - - if (i < sizeof(struct sadb_x_cred)) - return EINVAL; - - if (sadb_cred->sadb_x_cred_type > SADB_X_CREDTYPE_MAX) - return EINVAL; - if (sadb_cred->sadb_x_cred_reserved) - return EINVAL; + if (sadb_msg->sadb_msg_type == SADB_X_PROMISC) { + DPRINTF(("pfkeyv2_parsemessage: message type promiscuous\n")); + return 0; } - break; - case SADB_EXT_IDENTITY_SRC: - case SADB_EXT_IDENTITY_DST: - { - struct sadb_ident *sadb_ident = (struct sadb_ident *)p; - - if (i < sizeof(struct sadb_ident)) - return EINVAL; - - if (sadb_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) - return EINVAL; - if (sadb_ident->sadb_ident_reserved) - return EINVAL; + allow = sadb_exts_allowed_in[sadb_msg->sadb_msg_type]; - if (i > sizeof(struct sadb_ident)) { - char *c = (char *)(p + sizeof(struct sadb_ident)); - int j; + while (left > 0) { + sadb_ext = (struct sadb_ext *)p; + if (left < sizeof(struct sadb_ext)) { + DPRINTF(("pfkeyv2_parsemessage: extension header too " + "short\n")); + return EINVAL; + } - if (*(char *)(p + i - 1)) - return EINVAL; + i = sadb_ext->sadb_ext_len * sizeof(uint64_t); + if (left < i) { + DPRINTF(("pfkeyv2_parsemessage: extension header " + "exceeds message length\n")); + return EINVAL; + } - j = ((strlen(c) + sizeof(uint64_t)) & ~(sizeof(uint64_t)-1)) + - sizeof(struct sadb_ident); + if (sadb_ext->sadb_ext_type > SADB_EXT_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown extension " + "header %d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } - if (i != j) - return EINVAL; - } - } - break; - case SADB_EXT_SENSITIVITY: - { - struct sadb_sens *sadb_sens = (struct sadb_sens *)p; + if (!sadb_ext->sadb_ext_type) { + DPRINTF(("pfkeyv2_parsemessage: unset extension " + "header\n")); + return EINVAL; + } - if (i < sizeof(struct sadb_sens)) - return EINVAL; + if (!(allow & (1 << sadb_ext->sadb_ext_type))) { + DPRINTF(("pfkeyv2_parsemessage: extension header %d " + "not permitted on message type %d\n", + sadb_ext->sadb_ext_type, sadb_msg->sadb_msg_type)); + return EINVAL; + } - if (i != (sadb_sens->sadb_sens_sens_len + - sadb_sens->sadb_sens_integ_len) * sizeof(uint64_t) + - sizeof(struct sadb_sens)) - return EINVAL; + if (headers[sadb_ext->sadb_ext_type]) { + DPRINTF(("pfkeyv2_parsemessage: duplicate extension " + "header %d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + + seen |= (1 << sadb_ext->sadb_ext_type); + + switch (sadb_ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_X_EXT_SA2: + { + struct sadb_sa *sadb_sa = (struct sadb_sa *)p; + + if (i != sizeof(struct sadb_sa)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length for SA extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_sa->sadb_sa_state > SADB_SASTATE_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown SA " + "state %d in SA extension header %d\n", + sadb_sa->sadb_sa_state, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_sa->sadb_sa_state == SADB_SASTATE_DEAD) { + DPRINTF(("pfkeyv2_parsemessage: cannot set SA " + "state to dead, SA extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_sa->sadb_sa_encrypt > SADB_EALG_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown " + "encryption algorithm %d in SA extension " + "header %d\n", sadb_sa->sadb_sa_encrypt, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_sa->sadb_sa_auth > SADB_AALG_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown " + "authentication algorithm %d in SA " + "extension header %d\n", + sadb_sa->sadb_sa_auth, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_sa->sadb_sa_replay > 32) { + DPRINTF(("pfkeyv2_parsemessage: unsupported " + "replay window size %d in SA extension " + "header %d\n", sadb_sa->sadb_sa_replay, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + break; + case SADB_X_EXT_PROTOCOL: + case SADB_X_EXT_FLOW_TYPE: + if (i != sizeof(struct sadb_protocol)) { + DPRINTF(("pfkeyv2_parsemessage: bad " + "PROTOCOL/FLOW header length in extension " + "header %d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + break; + case SADB_X_EXT_POLICY: + if (i != sizeof(struct sadb_x_policy)) { + DPRINTF(("pfkeyv2_parsemessage: bad POLICY " + "header length\n")); + return EINVAL; + } + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + if (i != sizeof(struct sadb_lifetime)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length for LIFETIME extension header " + "%d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_X_EXT_SRC_MASK: + case SADB_X_EXT_DST_MASK: + case SADB_X_EXT_SRC_FLOW: + case SADB_X_EXT_DST_FLOW: + case SADB_X_EXT_DST2: + case SADB_EXT_ADDRESS_PROXY: + { + struct sadb_address *sadb_address = + (struct sadb_address *)p; + struct sockaddr *sa = (struct sockaddr *)(p + + sizeof(struct sadb_address)); + + if (i < sizeof(struct sadb_address) + + sizeof(struct sockaddr)) { + DPRINTF(("pfkeyv2_parsemessage: bad ADDRESS " + "extension header %d length\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_address->sadb_address_reserved) { + DPRINTF(("pfkeyv2_parsemessage: ADDRESS " + "extension header %d reserved field set\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + if (sa->sa_len && + (i != sizeof(struct sadb_address) + sa->sa_len)) { + DPRINTF(("pfkeyv2_parsemessage: bad sockaddr " + "length field in ADDRESS extension " + "header %d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + + switch(sa->sa_family) { + case AF_INET: + if (sizeof(struct sadb_address) + + sizeof(struct sockaddr_in) != i) { + DPRINTF(("pfkeyv2_parsemessage: " + "invalid ADDRESS extension header " + "%d length\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sa->sa_len != sizeof(struct sockaddr_in)) { + DPRINTF(("pfkeyv2_parsemessage: bad " + "sockaddr_in length in ADDRESS " + "extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + /* Only check the right pieces */ + switch (sadb_ext->sadb_ext_type) + { + case SADB_X_EXT_SRC_MASK: + case SADB_X_EXT_DST_MASK: + case SADB_X_EXT_SRC_FLOW: + case SADB_X_EXT_DST_FLOW: + break; + + default: + if (((struct sockaddr_in *)sa)->sin_port) { + DPRINTF(("pfkeyv2_parsemessage" + ": port field set in " + "sockaddr_in of ADDRESS " + "extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + break; + } + + { + char zero[sizeof(((struct sockaddr_in *)sa)->sin_zero)]; + bzero(zero, sizeof(zero)); + + if (bcmp(&((struct sockaddr_in *)sa)->sin_zero, zero, sizeof(zero))) { + DPRINTF(("pfkeyv2_parsemessage" + ": reserved sockaddr_in " + "field non-zero'ed in " + "ADDRESS extension header " + "%d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + break; +#if INET6 + case AF_INET6: + if (i != sizeof(struct sadb_address) + + sizeof(struct sockaddr_in6) + 4) { + DPRINTF(("pfkeyv2_parsemessage: " + "invalid sockaddr_in6 length in " + "ADDRESS extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sa->sa_len != + sizeof(struct sockaddr_in6)) { + DPRINTF(("pfkeyv2_parsemessage: bad " + "sockaddr_in6 length in ADDRESS " + "extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (((struct sockaddr_in6 *)sa)->sin6_flowinfo) { + DPRINTF(("pfkeyv2_parsemessage: " + "flowinfo field set in " + "sockaddr_in6 of ADDRESS " + "extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + break; +#endif /* INET6 */ + default: + DPRINTF(("pfkeyv2_parsemessage: unknown " + "address family %d in ADDRESS extension " + "header %d\n", + sa->sa_family, sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + { + struct sadb_key *sadb_key = (struct sadb_key *)p; + + if (i < sizeof(struct sadb_key)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length in KEY extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (!sadb_key->sadb_key_bits) { + DPRINTF(("pfkeyv2_parsemessage: key length " + "unset in KEY extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (((sadb_key->sadb_key_bits + 63) / 64) * sizeof(uint64_t) != i - sizeof(struct sadb_key)) { + DPRINTF(("pfkeyv2_parsemessage: invalid key " + "length in KEY extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_key->sadb_key_reserved) { + DPRINTF(("pfkeyv2_parsemessage: reserved field" + " set in KEY extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + break; + case SADB_X_EXT_LOCAL_AUTH: + case SADB_X_EXT_REMOTE_AUTH: + { + struct sadb_x_cred *sadb_cred = + (struct sadb_x_cred *)p; + + if (i < sizeof(struct sadb_x_cred)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length for AUTH extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_cred->sadb_x_cred_type > SADB_X_AUTHTYPE_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown auth " + "type %d in AUTH extension header %d\n", + sadb_cred->sadb_x_cred_type, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_cred->sadb_x_cred_reserved) { + DPRINTF(("pfkeyv2_parsemessage: reserved field" + " set in AUTH extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + break; + case SADB_X_EXT_LOCAL_CREDENTIALS: + case SADB_X_EXT_REMOTE_CREDENTIALS: + { + struct sadb_x_cred *sadb_cred = + (struct sadb_x_cred *)p; + + if (i < sizeof(struct sadb_x_cred)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length of CREDENTIALS extension header " + "%d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_cred->sadb_x_cred_type > SADB_X_CREDTYPE_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown " + "credential type %d in CREDENTIALS " + "extension header %d\n", + sadb_cred->sadb_x_cred_type, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_cred->sadb_x_cred_reserved) { + DPRINTF(("pfkeyv2_parsemessage: reserved " + "field set in CREDENTIALS extension " + "header %d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + { + struct sadb_ident *sadb_ident = (struct sadb_ident *)p; + + if (i < sizeof(struct sadb_ident)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length of IDENTITY extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) { + DPRINTF(("pfkeyv2_parsemessage: unknown " + "identity type %d in IDENTITY extension " + "header %d\n", + sadb_ident->sadb_ident_type, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_ident->sadb_ident_reserved) { + DPRINTF(("pfkeyv2_parsemessage: reserved " + "field set in IDENTITY extension header " + "%d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (i > sizeof(struct sadb_ident)) { + char *c = + (char *)(p + sizeof(struct sadb_ident)); + int j; + + if (*(char *)(p + i - 1)) { + DPRINTF(("pfkeyv2_parsemessage: non " + "NUL-terminated identity in " + "IDENTITY extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + j = ((strlen(c) + sizeof(uint64_t)) & + ~(sizeof(uint64_t)-1)) + + sizeof(struct sadb_ident); + + if (i != j) { + DPRINTF(("pfkeyv2_parsemessage: actual" + "identity length does not match " + "expected length in identity " + "extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + } + } + break; + case SADB_EXT_SENSITIVITY: + { + struct sadb_sens *sadb_sens = (struct sadb_sens *)p; + + if (i < sizeof(struct sadb_sens)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length for SENSITIVITY extension " + "header\n")); + return EINVAL; + } + + if (i != (sadb_sens->sadb_sens_sens_len + + sadb_sens->sadb_sens_integ_len) * + sizeof(uint64_t) + + sizeof(struct sadb_sens)) { + DPRINTF(("pfkeyv2_parsemessage: bad payload " + "length for SENSITIVITY extension " + "header\n")); + return EINVAL; + } + } + break; + case SADB_EXT_PROPOSAL: + { + struct sadb_prop *sadb_prop = (struct sadb_prop *)p; + + if (i < sizeof(struct sadb_prop)) { + DPRINTF(("pfkeyv2_parsemessage: bad PROPOSAL " + "header length\n")); + return EINVAL; + } + + if (sadb_prop->sadb_prop_reserved) { + DPRINTF(("pfkeyv2_parsemessage: reserved field" + "set in PROPOSAL extension header\n")); + return EINVAL; + } + + if ((i - sizeof(struct sadb_prop)) % + sizeof(struct sadb_comb)) { + DPRINTF(("pfkeyv2_parsemessage: bad proposal " + "length\n")); + return EINVAL; + } + + { + struct sadb_comb *sadb_comb = + (struct sadb_comb *)(p + + sizeof(struct sadb_prop)); + int j; + + for (j = 0; + j < (i - sizeof(struct sadb_prop))/sizeof(struct sadb_comb); + j++) { + if (sadb_comb->sadb_comb_auth > + SADB_AALG_MAX) { + DPRINTF(("pfkeyv2_parsemessage" + ": unknown authentication " + "algorithm %d in " + "PROPOSAL\n", + sadb_comb->sadb_comb_auth)); + return EINVAL; + } + + if (sadb_comb->sadb_comb_encrypt > + SADB_EALG_MAX) { + DPRINTF(("pfkeyv2_parsemessage" + ": unknown encryption " + "algorithm %d in " + "PROPOSAL\n", + sadb_comb->sadb_comb_encrypt)); + return EINVAL; + } + + if (sadb_comb->sadb_comb_reserved) { + DPRINTF(("pfkeyv2_parsemessage" + ": reserved field set in " + "COMB header\n")); + return EINVAL; + } + } + } + } + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + { + struct sadb_supported *sadb_supported = + (struct sadb_supported *)p; + int j; + + if (i < sizeof(struct sadb_supported)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length for SUPPORTED extension header " + "%d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_supported->sadb_supported_reserved) { + DPRINTF(("pfkeyv2_parsemessage: reserved " + "field set in SUPPORTED extension " + "header %d\n", sadb_ext->sadb_ext_type)); + return EINVAL; + } + + { + struct sadb_alg *sadb_alg = + (struct sadb_alg *)(p + + sizeof(struct sadb_supported)); + int max_alg; + + max_alg = sadb_ext->sadb_ext_type == SADB_EXT_SUPPORTED_AUTH ? + SADB_AALG_MAX : SADB_EALG_MAX; + + for (j = 0; j < sadb_supported->sadb_supported_len - 1; j++) { + if (sadb_alg->sadb_alg_id > max_alg) { + DPRINTF(("pfkeyv2_parsemessage" + ": unknown algorithm %d " + "in SUPPORTED extension " + "header %d\n", + sadb_alg->sadb_alg_id, + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + if (sadb_alg->sadb_alg_reserved) { + DPRINTF(("pfkeyv2_parsemessage" + ": reserved field set in " + "supported algorithms " + "header inside SUPPORTED " + "extension header %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + sadb_alg++; + } + } + } + break; + case SADB_EXT_SPIRANGE: + { + struct sadb_spirange *sadb_spirange = + (struct sadb_spirange *)p; + + if (i != sizeof(struct sadb_spirange)) { + DPRINTF(("pfkeyv2_parsemessage: bad header " + "length of SPIRANGE extension header\n")); + return EINVAL; + } + + if (sadb_spirange->sadb_spirange_min > + sadb_spirange->sadb_spirange_max) { + DPRINTF(("pfkeyv2_parsemessage: bad SPI " + "range\n")); + return EINVAL; + } + } + break; + default: + DPRINTF(("pfkeyv2_parsemessage: unknown extension " + "header type %d\n", + sadb_ext->sadb_ext_type)); + return EINVAL; + } + + headers[sadb_ext->sadb_ext_type] = p; + p += i; + left -= i; } - break; - case SADB_EXT_PROPOSAL: - { - struct sadb_prop *sadb_prop = (struct sadb_prop *)p; - - if (i < sizeof(struct sadb_prop)) - return EINVAL; - if (sadb_prop->sadb_prop_reserved) - return EINVAL; - - if ((i - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb)) - return EINVAL; - - { - struct sadb_comb *sadb_comb = (struct sadb_comb *)(p + sizeof(struct sadb_prop)); - int j; - - for (j = 0; - j < (i - sizeof(struct sadb_prop))/sizeof(struct sadb_comb); - j++) { - if (sadb_comb->sadb_comb_auth > SADB_AALG_MAX) - return EINVAL; - - if (sadb_comb->sadb_comb_encrypt > SADB_EALG_MAX) - return EINVAL; - - if (sadb_comb->sadb_comb_reserved) + if (left) { + DPRINTF(("pfkeyv2_parsemessage: message too long\n")); return EINVAL; - - } - } } - break; - case SADB_EXT_SUPPORTED_AUTH: - case SADB_EXT_SUPPORTED_ENCRYPT: - { - struct sadb_supported *sadb_supported = (struct sadb_supported *)p; - int j; - - if (i < sizeof(struct sadb_supported)) - return EINVAL; - - if (sadb_supported->sadb_supported_reserved) - return EINVAL; - - { - struct sadb_alg *sadb_alg = (struct sadb_alg *)(p + sizeof(struct sadb_supported)); - int max_alg; - max_alg = sadb_ext->sadb_ext_type == SADB_EXT_SUPPORTED_AUTH ? - SADB_AALG_MAX : SADB_EALG_MAX; - - for (j = 0; j < sadb_supported->sadb_supported_len - 1; j++) { - if (sadb_alg->sadb_alg_id > max_alg) - return EINVAL; + { + uint32_t required; - if (sadb_alg->sadb_alg_reserved) - return EINVAL; + required = sadb_exts_required_in[sadb_msg->sadb_msg_type]; - sadb_alg++; - } - } + if ((seen & required) != required) { + DPRINTF(("pfkeyv2_parsemessage: required fields " + "missing\n")); + return EINVAL; + } } - break; - case SADB_EXT_SPIRANGE: - { - struct sadb_spirange *sadb_spirange = (struct sadb_spirange *)p; - if (i != sizeof(struct sadb_spirange)) - return EINVAL; - - if (sadb_spirange->sadb_spirange_min > - sadb_spirange->sadb_spirange_max) - return EINVAL; + switch(((struct sadb_msg *)headers[0])->sadb_msg_type) { + case SADB_UPDATE: + if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != + SADB_SASTATE_MATURE) { + DPRINTF(("pfkeyv2_parsemessage: updating non-mature " + "SA prohibited\n")); + return EINVAL; + } + break; + case SADB_ADD: + if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != + SADB_SASTATE_MATURE) { + DPRINTF(("pfkeyv2_parsemessage: adding non-mature " + "SA prohibited\n")); + return EINVAL; + } + break; } - break; - default: - return EINVAL; - } - - headers[sadb_ext->sadb_ext_type] = p; - p += i; - left -= i; - } - - if (left) - return EINVAL; - - { - uint32_t required; - - required = sadb_exts_required_in[sadb_msg->sadb_msg_type]; - - if ((seen & required) != required) - return EINVAL; - } - - switch(((struct sadb_msg *)headers[0])->sadb_msg_type) { - case SADB_UPDATE: - if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != - SADB_SASTATE_MATURE) - return EINVAL; - break; - case SADB_ADD: - if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != - SADB_SASTATE_MATURE) - return EINVAL; - break; - } - - return 0; + + return 0; } |