X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..bb59bff194111743b33cc36712410b5656329d3c:/bsd/netinet6/ah_output.c diff --git a/bsd/netinet6/ah_output.c b/bsd/netinet6/ah_output.c index e8c81b01f..18391b187 100644 --- a/bsd/netinet6/ah_output.c +++ b/bsd/netinet6/ah_output.c @@ -1,4 +1,33 @@ -/* $KAME: ah_output.c,v 1.17 2000/03/09 08:54:48 itojun Exp $ */ +/* + * Copyright (c) 2008-2011 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* $FreeBSD: src/sys/netinet6/ah_output.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $ */ +/* $KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -34,9 +63,6 @@ */ #define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include @@ -67,14 +93,23 @@ #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include -static struct in_addr *ah4_finaldst __P((struct mbuf *)); +#if INET +static struct in_addr *ah4_finaldst(struct mbuf *); +#endif + +extern lck_mtx_t *sadb_mutex; /* * compute AH header size. @@ -85,8 +120,6 @@ size_t ah_hdrsiz(isr) struct ipsecrequest *isr; { - struct ah_algorithm *algo; - size_t hdrsiz; /* sanity check */ if (isr == NULL) @@ -95,33 +128,46 @@ ah_hdrsiz(isr) if (isr->saidx.proto != IPPROTO_AH) panic("unsupported mode passed to ah_hdrsiz"); - if (isr->sav == NULL) - goto estimate; - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) - goto estimate; +#if 0 + { - /* we need transport mode AH. */ - algo = &ah_algorithms[isr->sav->alg_auth]; - if (!algo) - goto estimate; + lck_mtx_lock(sadb_mutex); + const struct ah_algorithm *algo; + size_t hdrsiz; - /* - * XXX - * right now we don't calcurate the padding size. simply - * treat the padding size as constant, for simplicity. - * - * XXX variable size padding support - */ - hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1)); - if (isr->sav->flags & SADB_X_EXT_OLD) - hdrsiz += sizeof(struct ah); - else - hdrsiz += sizeof(struct newah); + /*%%%%% this needs to change - no sav in ipsecrequest any more */ + if (isr->sav == NULL) + goto estimate; + if (isr->sav->state != SADB_SASTATE_MATURE + && isr->sav->state != SADB_SASTATE_DYING) + goto estimate; + + /* we need transport mode AH. */ + algo = ah_algorithm_lookup(isr->sav->alg_auth); + if (!algo) + goto estimate; + + /* + * XXX + * right now we don't calcurate the padding size. simply + * treat the padding size as constant, for simplicity. + * + * XXX variable size padding support + */ + hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1)); + if (isr->sav->flags & SADB_X_EXT_OLD) + hdrsiz += sizeof(struct ah); + else + hdrsiz += sizeof(struct newah); + + lck_mtx_unlock(sadb_mutex); + return hdrsiz; + } - return hdrsiz; +estimate: +#endif - estimate: + //lck_mtx_unlock(sadb_mutex); /* ASSUMING: * sizeof(struct newah) > sizeof(struct ah). * 16 = (16 + 3) & ~(4 - 1). @@ -129,6 +175,7 @@ ah_hdrsiz(isr) return sizeof(struct newah) + 16; } +#if INET /* * Modify the packet so that it includes the authentication data. * The mbuf passed must start with IPv4 header. @@ -137,12 +184,11 @@ ah_hdrsiz(isr) * the function does not modify m. */ int -ah4_output(m, isr) +ah4_output(m, sav) struct mbuf *m; - struct ipsecrequest *isr; + struct secasvar *sav; { - struct secasvar *sav = isr->sav; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; u_int32_t spi; u_char *ahdrpos; u_char *ahsumpos = NULL; @@ -150,26 +196,31 @@ ah4_output(m, isr) size_t plen = 0; /*AH payload size in bytes*/ size_t ahlen = 0; /*plen + sizeof(ah)*/ struct ip *ip; - struct in_addr dst; + struct in_addr dst = { 0 }; struct in_addr *finaldst; int error; /* sanity checks */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { - struct ip *ip; - ip = mtod(m, struct ip *); ipseclog((LOG_DEBUG, "ah4_output: internal error: " "sav->replay is null: %x->%x, SPI=%u\n", (u_int32_t)ntohl(ip->ip_src.s_addr), (u_int32_t)ntohl(ip->ip_dst.s_addr), (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); m_freem(m); return EINVAL; } - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); + m_freem(m); + return EINVAL; + } spi = sav->spi; /* @@ -226,7 +277,7 @@ ah4_output(m, isr) if (sav->flags & SADB_X_EXT_OLD) { struct ah *ahdr; - ahdr = (struct ah *)ahdrpos; + ahdr = (struct ah *)(void *)ahdrpos; ahsumpos = (u_char *)(ahdr + 1); ahdr->ah_len = plen >> 2; ahdr->ah_nxt = ip->ip_p; @@ -236,7 +287,7 @@ ah4_output(m, isr) } else { struct newah *ahdr; - ahdr = (struct newah *)ahdrpos; + ahdr = (struct newah *)(void *)ahdrpos; ahsumpos = (u_char *)(ahdr + 1); ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */ ahdr->ah_nxt = ip->ip_p; @@ -248,12 +299,14 @@ ah4_output(m, isr) ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); m_freem(m); return EINVAL; } } + lck_mtx_lock(sadb_mutex); sav->replay->count++; + lck_mtx_unlock(sadb_mutex); /* * XXX sequence number must not be cycled, if the SA is * installed by IKE daemon. @@ -270,7 +323,7 @@ ah4_output(m, isr) ip->ip_len = htons(ntohs(ip->ip_len) + ahlen); else { ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n")); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); m_freem(m); return EMSGSIZE; } @@ -292,12 +345,13 @@ ah4_output(m, isr) * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah4_calccksum(m, (caddr_t)ahsumpos, algo, sav); + error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav); if (error) { ipseclog((LOG_ERR, "error after ah4_calccksum, called from ah4_output")); + m_freem(m); m = NULL; - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.out_inval); return error; } @@ -305,22 +359,27 @@ ah4_output(m, isr) ip = mtod(m, struct ip *); /*just to make sure*/ ip->ip_dst.s_addr = dst.s_addr; } + lck_mtx_lock(sadb_stat_mutex); ipsecstat.out_success++; ipsecstat.out_ahhist[sav->alg_auth]++; + lck_mtx_unlock(sadb_stat_mutex); key_sa_recordxfer(sav, m); return 0; } +#endif /* Calculate AH length */ int ah_hdrlen(sav) struct secasvar *sav; { - struct ah_algorithm *algo; + const struct ah_algorithm *algo; int plen, ahlen; - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) + return 0; if (sav->flags & SADB_X_EXT_OLD) { /* RFC 1826 */ plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/ @@ -339,16 +398,15 @@ ah_hdrlen(sav) * Fill in the Authentication Header and calculate checksum. */ int -ah6_output(m, nexthdrp, md, isr) +ah6_output(m, nexthdrp, md, sav) struct mbuf *m; u_char *nexthdrp; struct mbuf *md; - struct ipsecrequest *isr; + struct secasvar *sav; { struct mbuf *mprev; struct mbuf *mah; - struct secasvar *sav = isr->sav; - struct ah_algorithm *algo; + const struct ah_algorithm *algo; u_int32_t spi; u_char *ahsumpos = NULL; size_t plen; /*AH payload size in bytes*/ @@ -404,14 +462,21 @@ ah6_output(m, nexthdrp, md, isr) if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { ipseclog((LOG_DEBUG, "ah6_output: internal error: " - "sav->replay is null: SPI=%u\n", - (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; + "sav->replay is null: SPI=%u\n", + (u_int32_t)ntohl(sav->spi))); + IPSEC_STAT_INCREMENT(ipsec6stat.out_inval); m_freem(m); return EINVAL; } - algo = &ah_algorithms[sav->alg_auth]; + algo = ah_algorithm_lookup(sav->alg_auth); + if (!algo) { + ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: " + "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); + IPSEC_STAT_INCREMENT(ipsec6stat.out_inval); + m_freem(m); + return EINVAL; + } spi = sav->spi; /* @@ -442,14 +507,16 @@ ah6_output(m, nexthdrp, md, isr) if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { /* XXX Is it noisy ? */ ipseclog((LOG_WARNING, - "replay counter overflowed. %s\n", + "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + IPSEC_STAT_INCREMENT(ipsec6stat.out_inval); m_freem(m); return EINVAL; } } + lck_mtx_lock(sadb_mutex); sav->replay->count++; + lck_mtx_unlock(sadb_mutex); /* * XXX sequence number must not be cycled, if the SA is * installed by IKE daemon. @@ -462,20 +529,21 @@ ah6_output(m, nexthdrp, md, isr) * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah6_calccksum(m, (caddr_t)ahsumpos, algo, sav); + error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav); if (error) { - ipsec6stat.out_inval++; + IPSEC_STAT_INCREMENT(ipsec6stat.out_inval); m_freem(m); } else { - ipsec6stat.out_success++; + IPSEC_STAT_INCREMENT(ipsec6stat.out_success); key_sa_recordxfer(sav, m); } - ipsec6stat.out_ahhist[sav->alg_auth]++; + IPSEC_STAT_INCREMENT(ipsec6stat.out_ahhist[sav->alg_auth]); return(error); } #endif +#if INET /* * Find the final destination if there is loose/strict source routing option. * Returns NULL if there's no source routing options. @@ -522,6 +590,15 @@ ah4_finaldst(m) q = (u_char *)(ip + 1); i = 0; while (i < optlen) { + if (i + IPOPT_OPTVAL >= optlen) + return NULL; + if (q[i + IPOPT_OPTVAL] == IPOPT_EOL || + q[i + IPOPT_OPTVAL] == IPOPT_NOP || + i + IPOPT_OLEN < optlen) + ; + else + return NULL; + switch (q[i + IPOPT_OPTVAL]) { case IPOPT_EOL: i = optlen; /* bye */ @@ -531,8 +608,8 @@ ah4_finaldst(m) break; case IPOPT_LSRR: case IPOPT_SSRR: - if (q[i + IPOPT_OLEN] <= 0 - || optlen - i < q[i + IPOPT_OLEN]) { + if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) || + optlen - i < q[i + IPOPT_OLEN]) { ipseclog((LOG_ERR, "ip_finaldst: invalid IP option " "(code=%02x len=%02x)\n", @@ -540,10 +617,10 @@ ah4_finaldst(m) return NULL; } i += q[i + IPOPT_OLEN] - sizeof(struct in_addr); - return (struct in_addr *)(q + i); + return (struct in_addr *)(void *)(q + i); default: - if (q[i + IPOPT_OLEN] <= 0 - || optlen - i < q[i + IPOPT_OLEN]) { + if (q[i + IPOPT_OLEN] < 2 || + optlen - i < q[i + IPOPT_OLEN]) { ipseclog((LOG_ERR, "ip_finaldst: invalid IP option " "(code=%02x len=%02x)\n", @@ -556,3 +633,4 @@ ah4_finaldst(m) } return NULL; } +#endif