diff options
Diffstat (limited to 'linux/net/ipsec/pfkey_v2_parser.c')
-rw-r--r-- | linux/net/ipsec/pfkey_v2_parser.c | 3420 |
1 files changed, 3420 insertions, 0 deletions
diff --git a/linux/net/ipsec/pfkey_v2_parser.c b/linux/net/ipsec/pfkey_v2_parser.c new file mode 100644 index 000000000..d170ddea5 --- /dev/null +++ b/linux/net/ipsec/pfkey_v2_parser.c @@ -0,0 +1,3420 @@ +/* + * @(#) RFC2367 PF_KEYv2 Key management API message parser + * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: pfkey_v2_parser.c,v 1.4 2004/09/29 22:27:41 as Exp $ + */ + +/* + * Template from klips/net/ipsec/ipsec/ipsec_netlink.c. + */ + +char pfkey_v2_parser_c_version[] = "$Id: pfkey_v2_parser.c,v 1.4 2004/09/29 22:27:41 as Exp $"; + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/kernel.h> /* printk() */ + +#include "freeswan/ipsec_param.h" + +#ifdef MALLOC_SLAB +# include <linux/slab.h> /* kmalloc() */ +#else /* MALLOC_SLAB */ +# include <linux/malloc.h> /* kmalloc() */ +#endif /* MALLOC_SLAB */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> /* size_t */ +#include <linux/interrupt.h> /* mark_bh */ + +#include <linux/netdevice.h> /* struct device, and other headers */ +#include <linux/etherdevice.h> /* eth_type_trans */ +#include <linux/ip.h> /* struct iphdr */ +#include <linux/skbuff.h> + +#include <freeswan.h> + +#include <crypto/des.h> + +#ifdef SPINLOCK +# ifdef SPINLOCK_23 +# include <linux/spinlock.h> /* *lock* */ +# else /* SPINLOCK_23 */ +# include <asm/spinlock.h> /* *lock* */ +# endif /* SPINLOCK_23 */ +#endif /* SPINLOCK */ +#ifdef NET_21 +# include <asm/uaccess.h> +# include <linux/in6.h> +# define ip_chk_addr inet_addr_type +# define IS_MYADDR RTN_LOCAL +#endif +#include <asm/checksum.h> +#include <net/ip.h> +#ifdef NETLINK_SOCK +# include <linux/netlink.h> +#else +# include <net/netlink.h> +#endif + +#include <linux/random.h> /* get_random_bytes() */ + +#include "freeswan/radij.h" +#include "freeswan/ipsec_encap.h" +#include "freeswan/ipsec_sa.h" + +#include "freeswan/ipsec_radij.h" +#include "freeswan/ipsec_xform.h" +#include "freeswan/ipsec_ah.h" +#include "freeswan/ipsec_esp.h" +#include "freeswan/ipsec_tunnel.h" +#include "freeswan/ipsec_rcv.h" +#include "freeswan/ipcomp.h" + +#include <pfkeyv2.h> +#include <pfkey.h> + +#include "freeswan/ipsec_proto.h" +#include "freeswan/ipsec_alg.h" + + +#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) + +struct sklist_t { + struct socket *sk; + struct sklist_t* next; +} pfkey_sklist_head, *pfkey_sklist, *pfkey_sklist_prev; + +__u32 pfkey_msg_seq = 0; + +int +pfkey_alloc_eroute(struct eroute** eroute) +{ + int error = 0; + if(*eroute) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_alloc_eroute: " + "eroute struct already allocated\n"); + SENDERR(EEXIST); + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_alloc_eroute: " + "allocating %lu bytes for an eroute.\n", + (unsigned long) sizeof(**eroute)); + if((*eroute = kmalloc(sizeof(**eroute), GFP_ATOMIC) ) == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_alloc_eroute: " + "memory allocation error\n"); + SENDERR(ENOMEM); + } + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_alloc_eroute: " + "allocated eroute struct=0p%p.\n", eroute); + memset((caddr_t)*eroute, 0, sizeof(**eroute)); + (*eroute)->er_eaddr.sen_len = + (*eroute)->er_emask.sen_len = sizeof(struct sockaddr_encap); + (*eroute)->er_eaddr.sen_family = + (*eroute)->er_emask.sen_family = AF_ENCAP; + (*eroute)->er_eaddr.sen_type = SENT_IP4; + (*eroute)->er_emask.sen_type = 255; + (*eroute)->er_pid = 0; + (*eroute)->er_count = 0; + (*eroute)->er_lasttime = jiffies/HZ; + + errlab: + return(error); +} + +DEBUG_NO_STATIC int +pfkey_x_protocol_process(struct sadb_ext *pfkey_ext, + struct pfkey_extracted_data *extr) +{ + int error = 0; + struct sadb_protocol * p = (struct sadb_protocol *)pfkey_ext; + + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_protocol_process: %p\n", extr); + + if (extr == 0) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_protocol_process:" + "extr is NULL, fatal\n"); + SENDERR(EINVAL); + } + if (extr->eroute == 0) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_protocol_process:" + "extr->eroute is NULL, fatal\n"); + SENDERR(EINVAL); + } + extr->eroute->er_eaddr.sen_proto = p->sadb_protocol_proto; + extr->eroute->er_emask.sen_proto = p->sadb_protocol_proto ? ~0:0; + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_protocol_process: protocol = %d.\n", + p->sadb_protocol_proto); + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_ipsec_sa_init(struct ipsec_sa *ipsp, struct sadb_ext **extensions) +{ + int error = 0; + char sa[SATOA_BUF]; + size_t sa_len; + char ipaddr_txt[ADDRTOA_BUF]; + char ipaddr2_txt[ADDRTOA_BUF]; +#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1) + int i; + unsigned char kb[AHMD596_BLKLEN]; +#endif +#ifdef CONFIG_IPSEC_ALG + struct ipsec_alg_enc *ixt_e = NULL; + struct ipsec_alg_auth *ixt_a = NULL; +#endif /* CONFIG_IPSEC_ALG */ + + if(ipsp == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "ipsp is NULL, fatal\n"); + SENDERR(EINVAL); + } + + sa_len = satoa(ipsp->ips_said, 0, sa, SATOA_BUF); + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "(pfkey defined) called for SA:%s\n", + sa_len ? sa : " (error)"); + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "calling init routine of %s%s%s\n", + IPS_XFORM_NAME(ipsp)); + + switch(ipsp->ips_said.proto) { + +#ifdef CONFIG_IPSEC_IPIP + case IPPROTO_IPIP: { + addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_s))->sin_addr, + 0, + ipaddr_txt, sizeof(ipaddr_txt)); + addrtoa(((struct sockaddr_in*)(ipsp->ips_addr_d))->sin_addr, + 0, + ipaddr2_txt, sizeof(ipaddr_txt)); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "(pfkey defined) IPIP ipsec_sa set for %s->%s.\n", + ipaddr_txt, + ipaddr2_txt); + } + break; +#endif /* !CONFIG_IPSEC_IPIP */ +#ifdef CONFIG_IPSEC_AH + case IPPROTO_AH: + switch(ipsp->ips_authalg) { +# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 + case AH_MD5: { + unsigned char *akp; + unsigned int aks; + MD5_CTX *ictx; + MD5_CTX *octx; + + if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/, + ipsp->ips_key_bits_a, AHMD596_KLEN * 8); + SENDERR(EINVAL); + } + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "hmac md5-96 key is 0x%08x %08x %08x %08x\n", + ntohl(*(((__u32 *)ipsp->ips_key_a)+0)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+1)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+2)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+3))); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + + ipsp->ips_auth_bits = AHMD596_ALEN * 8; + + /* save the pointer to the key material */ + akp = ipsp->ips_key_a; + aks = ipsp->ips_key_a_size; + + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "allocating %lu bytes for md5_ctx.\n", + (unsigned long) sizeof(struct md5_ctx)); + if((ipsp->ips_key_a = (caddr_t) + kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) { + ipsp->ips_key_a = akp; + SENDERR(ENOMEM); + } + ipsp->ips_key_a_size = sizeof(struct md5_ctx); + + for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) { + kb[i] = akp[i] ^ HMAC_IPAD; + } + for (; i < AHMD596_BLKLEN; i++) { + kb[i] = HMAC_IPAD; + } + + ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx); + MD5Init(ictx); + MD5Update(ictx, kb, AHMD596_BLKLEN); + + for (i = 0; i < AHMD596_BLKLEN; i++) { + kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD); + } + + octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx); + MD5Init(octx); + MD5Update(octx, kb, AHMD596_BLKLEN); + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n", + ((__u32*)ictx)[0], + ((__u32*)ictx)[1], + ((__u32*)ictx)[2], + ((__u32*)ictx)[3], + ((__u32*)octx)[0], + ((__u32*)octx)[1], + ((__u32*)octx)[2], + ((__u32*)octx)[3] ); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + + /* zero key buffer -- paranoid */ + memset(akp, 0, aks); + kfree(akp); + } + break; +# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */ +# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 + case AH_SHA: { + unsigned char *akp; + unsigned int aks; + SHA1_CTX *ictx; + SHA1_CTX *octx; + + if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "incorrect key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/, + ipsp->ips_key_bits_a, AHSHA196_KLEN * 8); + SENDERR(EINVAL); + } + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "hmac sha1-96 key is 0x%08x %08x %08x %08x\n", + ntohl(*(((__u32 *)ipsp->ips_key_a)+0)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+1)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+2)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+3))); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + + ipsp->ips_auth_bits = AHSHA196_ALEN * 8; + + /* save the pointer to the key material */ + akp = ipsp->ips_key_a; + aks = ipsp->ips_key_a_size; + + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "allocating %lu bytes for sha1_ctx.\n", + (unsigned long) sizeof(struct sha1_ctx)); + if((ipsp->ips_key_a = (caddr_t) + kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) { + ipsp->ips_key_a = akp; + SENDERR(ENOMEM); + } + ipsp->ips_key_a_size = sizeof(struct sha1_ctx); + + for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) { + kb[i] = akp[i] ^ HMAC_IPAD; + } + for (; i < AHMD596_BLKLEN; i++) { + kb[i] = HMAC_IPAD; + } + + ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx); + SHA1Init(ictx); + SHA1Update(ictx, kb, AHSHA196_BLKLEN); + + for (i = 0; i < AHSHA196_BLKLEN; i++) { + kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD); + } + + octx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->octx); + SHA1Init(octx); + SHA1Update(octx, kb, AHSHA196_BLKLEN); + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n", + ((__u32*)ictx)[0], + ((__u32*)ictx)[1], + ((__u32*)ictx)[2], + ((__u32*)ictx)[3], + ((__u32*)octx)[0], + ((__u32*)octx)[1], + ((__u32*)octx)[2], + ((__u32*)octx)[3] ); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + /* zero key buffer -- paranoid */ + memset(akp, 0, aks); + kfree(akp); + } + break; +# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */ + default: + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "authalg=%d support not available in the kernel", + ipsp->ips_authalg); + SENDERR(EINVAL); + } + break; +#endif /* CONFIG_IPSEC_AH */ +#ifdef CONFIG_IPSEC_ESP + case IPPROTO_ESP: { +#if defined (CONFIG_IPSEC_AUTH_HMAC_MD5) || defined (CONFIG_IPSEC_AUTH_HMAC_SHA1) + unsigned char *akp; + unsigned int aks; +#endif +#if defined (CONFIG_IPSEC_ENC_3DES) + unsigned char *ekp; + unsigned int eks; +#endif + + ipsp->ips_iv_size = 0; +#ifdef CONFIG_IPSEC_ALG + if ((ixt_e=ipsp->ips_alg_enc)) { + ipsp->ips_iv_size = ixt_e->ixt_ivlen/8; + } else +#endif /* CONFIG_IPSEC_ALG */ + switch(ipsp->ips_encalg) { +# ifdef CONFIG_IPSEC_ENC_3DES + case ESP_3DES: +# endif /* CONFIG_IPSEC_ENC_3DES */ +# if defined(CONFIG_IPSEC_ENC_3DES) + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "allocating %u bytes for iv.\n", + EMT_ESPDES_IV_SZ); + if((ipsp->ips_iv = (caddr_t) + kmalloc((ipsp->ips_iv_size = EMT_ESPDES_IV_SZ), GFP_ATOMIC)) == NULL) { + SENDERR(ENOMEM); + } + prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, EMT_ESPDES_IV_SZ); + ipsp->ips_iv_bits = ipsp->ips_iv_size * 8; + ipsp->ips_iv_size = EMT_ESPDES_IV_SZ; + break; +# endif /* defined(CONFIG_IPSEC_ENC_3DES) */ + case ESP_NONE: + break; + default: + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "encalg=%d support not available in the kernel", + ipsp->ips_encalg); + SENDERR(EINVAL); + } + + /* Create IV */ + if (ipsp->ips_iv_size) { + if((ipsp->ips_iv = (caddr_t) + kmalloc(ipsp->ips_iv_size, GFP_ATOMIC)) == NULL) { + SENDERR(ENOMEM); + } + prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, ipsp->ips_iv_size); + ipsp->ips_iv_bits = ipsp->ips_iv_size * 8; + } + +#ifdef CONFIG_IPSEC_ALG + if (ixt_e) { + if ((error=ipsec_alg_enc_key_create(ipsp)) < 0) + SENDERR(-error); + } else +#endif /* CONFIG_IPSEC_ALG */ + switch(ipsp->ips_encalg) { +# ifdef CONFIG_IPSEC_ENC_3DES + case ESP_3DES: + if(ipsp->ips_key_bits_e != (EMT_ESP3DES_KEY_SZ * 8)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "incorrect encryption key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/, + ipsp->ips_key_bits_e, EMT_ESP3DES_KEY_SZ * 8); + SENDERR(EINVAL); + } + + /* save encryption key pointer */ + ekp = ipsp->ips_key_e; + eks = ipsp->ips_key_e_size; + + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "allocating %lu bytes for 3des.\n", + (unsigned long) (3 * sizeof(struct des_eks))); + if((ipsp->ips_key_e = (caddr_t) + kmalloc(3 * sizeof(struct des_eks), GFP_ATOMIC)) == NULL) { + ipsp->ips_key_e = ekp; + SENDERR(ENOMEM); + } + ipsp->ips_key_e_size = 3 * sizeof(struct des_eks); + + for(i = 0; i < 3; i++) { +#if KLIPS_DIVULGE_CYPHER_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "3des key %d/3 is 0x%08x%08x\n", + i + 1, + ntohl(*((__u32 *)ekp + i * 2)), + ntohl(*((__u32 *)ekp + i * 2 + 1))); +# endif +#if KLIPS_FIXES_DES_PARITY + /* force parity */ + des_set_odd_parity((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i)); +#endif + error = des_set_key((des_cblock *)(ekp + EMT_ESPDES_KEY_SZ * i), + ((struct des_eks *)(ipsp->ips_key_e))[i].ks); + if (error == -1) + printk("klips_debug:pfkey_ipsec_sa_init: " + "parity error in des key %d/3\n", + i + 1); + else if (error == -2) + printk("klips_debug:pfkey_ipsec_sa_init: " + "illegal weak des key %d/3\n", i + 1); + if (error) { + memset(ekp, 0, eks); + kfree(ekp); + SENDERR(EINVAL); + } + } + + /* paranoid */ + memset(ekp, 0, eks); + kfree(ekp); + break; +# endif /* CONFIG_IPSEC_ENC_3DES */ + case ESP_NONE: + break; + default: + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "encalg=%d support not available in the kernel", + ipsp->ips_encalg); + SENDERR(EINVAL); + } + +#ifdef CONFIG_IPSEC_ALG + if ((ixt_a=ipsp->ips_alg_auth)) { + if ((error=ipsec_alg_auth_key_create(ipsp)) < 0) + SENDERR(-error); + } else +#endif /* CONFIG_IPSEC_ALG */ + + switch(ipsp->ips_authalg) { +# ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 + case AH_MD5: { + MD5_CTX *ictx; + MD5_CTX *octx; + + if(ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/, + ipsp->ips_key_bits_a, + AHMD596_KLEN * 8); + SENDERR(EINVAL); + } + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "hmac md5-96 key is 0x%08x %08x %08x %08x\n", + ntohl(*(((__u32 *)(ipsp->ips_key_a))+0)), + ntohl(*(((__u32 *)(ipsp->ips_key_a))+1)), + ntohl(*(((__u32 *)(ipsp->ips_key_a))+2)), + ntohl(*(((__u32 *)(ipsp->ips_key_a))+3))); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + ipsp->ips_auth_bits = AHMD596_ALEN * 8; + + /* save the pointer to the key material */ + akp = ipsp->ips_key_a; + aks = ipsp->ips_key_a_size; + + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "allocating %lu bytes for md5_ctx.\n", + (unsigned long) sizeof(struct md5_ctx)); + if((ipsp->ips_key_a = (caddr_t) + kmalloc(sizeof(struct md5_ctx), GFP_ATOMIC)) == NULL) { + ipsp->ips_key_a = akp; + SENDERR(ENOMEM); + } + ipsp->ips_key_a_size = sizeof(struct md5_ctx); + + for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) { + kb[i] = akp[i] ^ HMAC_IPAD; + } + for (; i < AHMD596_BLKLEN; i++) { + kb[i] = HMAC_IPAD; + } + + ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx); + MD5Init(ictx); + MD5Update(ictx, kb, AHMD596_BLKLEN); + + for (i = 0; i < AHMD596_BLKLEN; i++) { + kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD); + } + + octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx); + MD5Init(octx); + MD5Update(octx, kb, AHMD596_BLKLEN); + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n", + ((__u32*)ictx)[0], + ((__u32*)ictx)[1], + ((__u32*)ictx)[2], + ((__u32*)ictx)[3], + ((__u32*)octx)[0], + ((__u32*)octx)[1], + ((__u32*)octx)[2], + ((__u32*)octx)[3] ); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + /* paranoid */ + memset(akp, 0, aks); + kfree(akp); + break; + } +# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */ +# ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 + case AH_SHA: { + SHA1_CTX *ictx; + SHA1_CTX *octx; + + if(ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "incorrect authorisation key size: %d bits -- must be %d bits\n"/*octets (bytes)\n"*/, + ipsp->ips_key_bits_a, + AHSHA196_KLEN * 8); + SENDERR(EINVAL); + } + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "hmac sha1-96 key is 0x%08x %08x %08x %08x\n", + ntohl(*(((__u32 *)ipsp->ips_key_a)+0)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+1)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+2)), + ntohl(*(((__u32 *)ipsp->ips_key_a)+3))); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + ipsp->ips_auth_bits = AHSHA196_ALEN * 8; + + /* save the pointer to the key material */ + akp = ipsp->ips_key_a; + aks = ipsp->ips_key_a_size; + + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "allocating %lu bytes for sha1_ctx.\n", + (unsigned long) sizeof(struct sha1_ctx)); + if((ipsp->ips_key_a = (caddr_t) + kmalloc(sizeof(struct sha1_ctx), GFP_ATOMIC)) == NULL) { + ipsp->ips_key_a = akp; + SENDERR(ENOMEM); + } + ipsp->ips_key_a_size = sizeof(struct sha1_ctx); + + for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++) { + kb[i] = akp[i] ^ HMAC_IPAD; + } + for (; i < AHMD596_BLKLEN; i++) { + kb[i] = HMAC_IPAD; + } + + ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx); + SHA1Init(ictx); + SHA1Update(ictx, kb, AHSHA196_BLKLEN); + + for (i = 0; i < AHSHA196_BLKLEN; i++) { + kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD); + } + + octx = &((struct sha1_ctx*)(ipsp->ips_key_a))->octx; + SHA1Init(octx); + SHA1Update(octx, kb, AHSHA196_BLKLEN); + +# if KLIPS_DIVULGE_HMAC_KEY + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_ipsec_sa_init: " + "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n", + ((__u32*)ictx)[0], + ((__u32*)ictx)[1], + ((__u32*)ictx)[2], + ((__u32*)ictx)[3], + ((__u32*)octx)[0], + ((__u32*)octx)[1], + ((__u32*)octx)[2], + ((__u32*)octx)[3] ); +# endif /* KLIPS_DIVULGE_HMAC_KEY */ + memset(akp, 0, aks); + kfree(akp); + break; + } +# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */ + case AH_NONE: + break; + default: + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "authalg=%d support not available in the kernel.\n", + ipsp->ips_authalg); + SENDERR(EINVAL); + } + } + break; +#endif /* !CONFIG_IPSEC_ESP */ +#ifdef CONFIG_IPSEC_IPCOMP + case IPPROTO_COMP: + ipsp->ips_comp_adapt_tries = 0; + ipsp->ips_comp_adapt_skip = 0; + ipsp->ips_comp_ratio_cbytes = 0; + ipsp->ips_comp_ratio_dbytes = 0; + break; +#endif /* CONFIG_IPSEC_IPCOMP */ + default: + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_ipsec_sa_init: " + "proto=%d unknown.\n", + ipsp->ips_said.proto); + SENDERR(EINVAL); + } + + errlab: + return(error); +} + + +int +pfkey_safe_build(int error, struct sadb_ext *extensions[SADB_MAX+1]) +{ + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build: " + "error=%d\n", + error); + if (!error) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:" + "success.\n"); + return 1; + } else { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_safe_build:" + "caught error %d\n", + error); + pfkey_extensions_free(extensions); + return 0; + } +} + + +DEBUG_NO_STATIC int +pfkey_getspi_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + ipsec_spi_t minspi = htonl(256), maxspi = htonl(-1L); + int found_avail = 0; + struct ipsec_sa *ipsq; + char sa[SATOA_BUF]; + size_t sa_len; + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_getspi_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + if(extr == NULL || extr->ips == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_getspi_parse: " + "error, extr or extr->ipsec_sa pointer NULL\n"); + SENDERR(EINVAL); + } + + if(extensions[SADB_EXT_SPIRANGE]) { + minspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_min; + maxspi = ((struct sadb_spirange *)extensions[SADB_EXT_SPIRANGE])->sadb_spirange_max; + } + + if(maxspi == minspi) { + extr->ips->ips_said.spi = maxspi; + ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if(ipsq != NULL) { + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + ipsec_sa_put(ipsq); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_getspi_parse: " + "EMT_GETSPI found an old ipsec_sa for SA: %s, delete it first.\n", + sa_len ? sa : " (error)"); + SENDERR(EEXIST); + } else { + found_avail = 1; + } + } else { + int i = 0; + __u32 rand_val; + __u32 spi_diff; + while( ( i < (spi_diff = (ntohl(maxspi) - ntohl(minspi)))) && !found_avail ) { + prng_bytes(&ipsec_prng, (char *) &(rand_val), + ( (spi_diff < (2^8)) ? 1 : + ( (spi_diff < (2^16)) ? 2 : + ( (spi_diff < (2^24)) ? 3 : + 4 ) ) ) ); + extr->ips->ips_said.spi = htonl(ntohl(minspi) + + (rand_val % + (spi_diff + 1))); + i++; + ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if(ipsq == NULL) { + found_avail = 1; + } else { + ipsec_sa_put(ipsq); + } + } + } + + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + + if (!found_avail) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_getspi_parse: " + "found an old ipsec_sa for SA: %s, delete it first.\n", + sa_len ? sa : " (error)"); + SENDERR(EEXIST); + } + + if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) { + extr->ips->ips_flags |= EMT_INBOUND; + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_getspi_parse: " + "existing ipsec_sa not found (this is good) for SA: %s, %s-bound, allocating.\n", + sa_len ? sa : " (error)", + extr->ips->ips_flags & EMT_INBOUND ? "in" : "out"); + + /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/ + extr->ips->ips_rcvif = NULL; + extr->ips->ips_life.ipl_addtime.ipl_count = jiffies/HZ; + + extr->ips->ips_state = SADB_SASTATE_LARVAL; + + if(!extr->ips->ips_life.ipl_allocations.ipl_count) { + extr->ips->ips_life.ipl_allocations.ipl_count += 1; + } + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_GETSPI, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + 0, + SADB_SASTATE_LARVAL, + 0, + 0, + 0, + extr->ips->ips_ref), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_s), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: " + "failed to build the getspi reply message extensions\n"); + goto errlab; + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: " + "failed to build the getspi reply message\n"); + SENDERR(-error); + } + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: " + "sending up getspi reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: " + "sending up getspi reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + if((error = ipsec_sa_add(extr->ips))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getspi_parse: " + "failed to add the larval SA=%s with error=%d.\n", + sa_len ? sa : " (error)", + error); + SENDERR(-error); + } + extr->ips = NULL; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_getspi_parse: " + "successful for SA: %s\n", + sa_len ? sa : " (error)"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_update_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + struct ipsec_sa* ipsq; + char sa[SATOA_BUF]; + size_t sa_len; + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + struct ipsec_sa *nat_t_ips_saved = NULL; +#endif + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "error, sa_state=%d must be MATURE=%d\n", + ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state, + SADB_SASTATE_MATURE); + SENDERR(EINVAL); + } + + if(extr == NULL || extr->ips == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "error, extr or extr->ips pointer NULL\n"); + SENDERR(EINVAL); + } + + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + + spin_lock_bh(&tdb_lock); + + ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if (ipsq == NULL) { + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "reserved ipsec_sa for SA: %s not found. Call SADB_GETSPI first or call SADB_ADD instead.\n", + sa_len ? sa : " (error)"); + SENDERR(ENOENT); + } + + if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) { + extr->ips->ips_flags |= EMT_INBOUND; + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "existing ipsec_sa found (this is good) for SA: %s, %s-bound, updating.\n", + sa_len ? sa : " (error)", + extr->ips->ips_flags & EMT_INBOUND ? "in" : "out"); + +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + if (extr->ips->ips_natt_sport || extr->ips->ips_natt_dport) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: only updating NAT-T ports " + "(%u:%u -> %u:%u)\n", + ipsq->ips_natt_sport, ipsq->ips_natt_dport, + extr->ips->ips_natt_sport, extr->ips->ips_natt_dport); + + if (extr->ips->ips_natt_sport) { + ipsq->ips_natt_sport = extr->ips->ips_natt_sport; + if (ipsq->ips_addr_s->sa_family == AF_INET) { + ((struct sockaddr_in *)(ipsq->ips_addr_s))->sin_port = htons(extr->ips->ips_natt_sport); + } + } + + if (extr->ips->ips_natt_dport) { + ipsq->ips_natt_dport = extr->ips->ips_natt_dport; + if (ipsq->ips_addr_d->sa_family == AF_INET) { + ((struct sockaddr_in *)(ipsq->ips_addr_d))->sin_port = htons(extr->ips->ips_natt_dport); + } + } + + nat_t_ips_saved = extr->ips; + extr->ips = ipsq; + } + else { +#endif + + /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/ + extr->ips->ips_rcvif = NULL; + if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) { + ipsec_sa_put(ipsq); + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "not successful for SA: %s, deleting.\n", + sa_len ? sa : " (error)"); + SENDERR(-error); + } + + extr->ips->ips_life.ipl_addtime.ipl_count = ipsq->ips_life.ipl_addtime.ipl_count; + ipsec_sa_put(ipsq); + if((error = ipsec_sa_delchain(ipsq))) { + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "error=%d, trouble deleting intermediate ipsec_sa for SA=%s.\n", + error, + sa_len ? sa : " (error)"); + SENDERR(-error); + } +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + } +#endif + + spin_unlock_bh(&tdb_lock); + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_UPDATE, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions_reply) + /* The 3 lifetime extentions should only be sent if non-zero. */ + && (extensions[SADB_EXT_LIFETIME_HARD] + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD], + SADB_EXT_LIFETIME_HARD, + extr->ips->ips_life.ipl_allocations.ipl_hard, + extr->ips->ips_life.ipl_bytes.ipl_hard, + extr->ips->ips_life.ipl_addtime.ipl_hard, + extr->ips->ips_life.ipl_usetime.ipl_hard, + extr->ips->ips_life.ipl_packets.ipl_hard), + extensions_reply) : 1) + && (extensions[SADB_EXT_LIFETIME_SOFT] + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT], + SADB_EXT_LIFETIME_SOFT, + extr->ips->ips_life.ipl_allocations.ipl_count, + extr->ips->ips_life.ipl_bytes.ipl_count, + extr->ips->ips_life.ipl_addtime.ipl_count, + extr->ips->ips_life.ipl_usetime.ipl_count, + extr->ips->ips_life.ipl_packets.ipl_count), + extensions_reply) : 1) + && (extr->ips->ips_life.ipl_allocations.ipl_count + || extr->ips->ips_life.ipl_bytes.ipl_count + || extr->ips->ips_life.ipl_addtime.ipl_count + || extr->ips->ips_life.ipl_usetime.ipl_count + || extr->ips->ips_life.ipl_packets.ipl_count + + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT], + SADB_EXT_LIFETIME_CURRENT, + extr->ips->ips_life.ipl_allocations.ipl_count, + extr->ips->ips_life.ipl_bytes.ipl_count, + extr->ips->ips_life.ipl_addtime.ipl_count, + extr->ips->ips_life.ipl_usetime.ipl_count, + extr->ips->ips_life.ipl_packets.ipl_count), + extensions_reply) : 1) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_s), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) + && (extr->ips->ips_ident_s.data + ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC], + SADB_EXT_IDENTITY_SRC, + extr->ips->ips_ident_s.type, + extr->ips->ips_ident_s.id, + extr->ips->ips_ident_s.len, + extr->ips->ips_ident_s.data), + extensions_reply) : 1) + && (extr->ips->ips_ident_d.data + ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST], + SADB_EXT_IDENTITY_DST, + extr->ips->ips_ident_d.type, + extr->ips->ips_ident_d.id, + extr->ips->ips_ident_d.len, + extr->ips->ips_ident_d.data), + extensions_reply) : 1) +#if 0 + /* FIXME: This won't work yet because I have not finished + it. */ + && (extr->ips->ips_sens_ + ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY], + extr->ips->ips_sens_dpd, + extr->ips->ips_sens_sens_level, + extr->ips->ips_sens_sens_len, + extr->ips->ips_sens_sens_bitmap, + extr->ips->ips_sens_integ_level, + extr->ips->ips_sens_integ_len, + extr->ips->ips_sens_integ_bitmap), + extensions_reply) : 1) +#endif + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: " + "failed to build the update reply message extensions\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: " + "failed to build the update reply message\n"); + SENDERR(-error); + } + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: " + "sending up update reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: " + "sending up update reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + if (nat_t_ips_saved) { + /** + * As we _really_ update existing SA, we keep tdbq and need to delete + * parsed ips (nat_t_ips_saved, was extr->ips). + * + * goto errlab with extr->ips = nat_t_ips_saved will free it. + */ + + extr->ips = nat_t_ips_saved; + + error = 0; + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse (NAT-T ports): " + "successful for SA: %s\n", + sa_len ? sa : " (error)"); + + goto errlab; + } +#endif + + if((error = ipsec_sa_add(extr->ips))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: " + "failed to update the mature SA=%s with error=%d.\n", + sa_len ? sa : " (error)", + error); + SENDERR(-error); + } + extr->ips = NULL; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_update_parse: " + "successful for SA: %s\n", + sa_len ? sa : " (error)"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_add_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + struct ipsec_sa* ipsq; + char sa[SATOA_BUF]; + size_t sa_len; + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: " + "error, sa_state=%d must be MATURE=%d\n", + ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state, + SADB_SASTATE_MATURE); + SENDERR(EINVAL); + } + + if(!extr || !extr->ips) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: " + "extr or extr->ips pointer NULL\n"); + SENDERR(EINVAL); + } + + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + + ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if(ipsq != NULL) { + ipsec_sa_put(ipsq); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: " + "found an old ipsec_sa for SA%s, delete it first.\n", + sa_len ? sa : " (error)"); + SENDERR(EEXIST); + } + + if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) { + extr->ips->ips_flags |= EMT_INBOUND; + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: " + "existing ipsec_sa not found (this is good) for SA%s, %s-bound, allocating.\n", + sa_len ? sa : " (error)", + extr->ips->ips_flags & EMT_INBOUND ? "in" : "out"); + + /* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/ + extr->ips->ips_rcvif = NULL; + + if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: " + "not successful for SA: %s, deleting.\n", + sa_len ? sa : " (error)"); + SENDERR(-error); + } + + extr->ips->ips_life.ipl_addtime.ipl_count = jiffies / HZ; + if(!extr->ips->ips_life.ipl_allocations.ipl_count) { + extr->ips->ips_life.ipl_allocations.ipl_count += 1; + } + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_ADD, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions_reply) + /* The 3 lifetime extentions should only be sent if non-zero. */ + && (extensions[SADB_EXT_LIFETIME_HARD] + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD], + SADB_EXT_LIFETIME_HARD, + extr->ips->ips_life.ipl_allocations.ipl_hard, + extr->ips->ips_life.ipl_bytes.ipl_hard, + extr->ips->ips_life.ipl_addtime.ipl_hard, + extr->ips->ips_life.ipl_usetime.ipl_hard, + extr->ips->ips_life.ipl_packets.ipl_hard), + extensions_reply) : 1) + && (extensions[SADB_EXT_LIFETIME_SOFT] + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT], + SADB_EXT_LIFETIME_SOFT, + extr->ips->ips_life.ipl_allocations.ipl_soft, + extr->ips->ips_life.ipl_bytes.ipl_soft, + extr->ips->ips_life.ipl_addtime.ipl_soft, + extr->ips->ips_life.ipl_usetime.ipl_soft, + extr->ips->ips_life.ipl_packets.ipl_soft), + extensions_reply) : 1) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_s), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) + && (extr->ips->ips_ident_s.data + ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC], + SADB_EXT_IDENTITY_SRC, + extr->ips->ips_ident_s.type, + extr->ips->ips_ident_s.id, + extr->ips->ips_ident_s.len, + extr->ips->ips_ident_s.data), + extensions_reply) : 1) + && (extr->ips->ips_ident_d.data + ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST], + SADB_EXT_IDENTITY_DST, + extr->ips->ips_ident_d.type, + extr->ips->ips_ident_d.id, + extr->ips->ips_ident_d.len, + extr->ips->ips_ident_d.data), + extensions_reply) : 1) +#if 0 + /* FIXME: This won't work yet because I have not finished + it. */ + && (extr->ips->ips_sens_ + ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY], + extr->ips->ips_sens_dpd, + extr->ips->ips_sens_sens_level, + extr->ips->ips_sens_sens_len, + extr->ips->ips_sens_sens_bitmap, + extr->ips->ips_sens_integ_level, + extr->ips->ips_sens_integ_len, + extr->ips->ips_sens_integ_bitmap), + extensions_reply) : 1) +#endif + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: " + "failed to build the add reply message extensions\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: " + "failed to build the add reply message\n"); + SENDERR(-error); + } + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: " + "sending up add reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: " + "sending up add reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + if((error = ipsec_sa_add(extr->ips))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_add_parse: " + "failed to add the mature SA=%s with error=%d.\n", + sa_len ? sa : " (error)", + error); + SENDERR(-error); + } + extr->ips = NULL; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_add_parse: " + "successful for SA: %s\n", + sa_len ? sa : " (error)"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_delete_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + struct ipsec_sa *ipsp; + char sa[SATOA_BUF]; + size_t sa_len; + int error = 0; + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_delete_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + if(!extr || !extr->ips) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_delete_parse: " + "extr or extr->ips pointer NULL, fatal\n"); + SENDERR(EINVAL); + } + + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + + spin_lock_bh(&tdb_lock); + + ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if (ipsp == NULL) { + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_delete_parse: " + "ipsec_sa not found for SA:%s, could not delete.\n", + sa_len ? sa : " (error)"); + SENDERR(ESRCH); + } + + ipsec_sa_put(ipsp); + if((error = ipsec_sa_delchain(ipsp))) { + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_delete_parse: " + "error=%d returned trying to delete ipsec_sa for SA:%s.\n", + error, + sa_len ? sa : " (error)"); + SENDERR(-error); + } + spin_unlock_bh(&tdb_lock); + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_DELETE, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + 0, + 0, + 0, + 0, + 0, + extr->ips->ips_ref), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_s), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: " + "failed to build the delete reply message extensions\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: " + "failed to build the delete reply message\n"); + SENDERR(-error); + } + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: " + "sending up delete reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_delete_parse: " + "sending up delete reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_get_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + struct ipsec_sa *ipsp; + char sa[SATOA_BUF]; + size_t sa_len; + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_get_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + if(!extr || !extr->ips) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_get_parse: " + "extr or extr->ips pointer NULL, fatal\n"); + SENDERR(EINVAL); + } + + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + + spin_lock_bh(&tdb_lock); + + ipsp = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if (ipsp == NULL) { + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: " + "ipsec_sa not found for SA=%s, could not get.\n", + sa_len ? sa : " (error)"); + SENDERR(ESRCH); + } + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_GET, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions_reply) + /* The 3 lifetime extentions should only be sent if non-zero. */ + && (ipsp->ips_life.ipl_allocations.ipl_count + || ipsp->ips_life.ipl_bytes.ipl_count + || ipsp->ips_life.ipl_addtime.ipl_count + || ipsp->ips_life.ipl_usetime.ipl_count + || ipsp->ips_life.ipl_packets.ipl_count + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_CURRENT], + SADB_EXT_LIFETIME_CURRENT, + ipsp->ips_life.ipl_allocations.ipl_count, + ipsp->ips_life.ipl_bytes.ipl_count, + ipsp->ips_life.ipl_addtime.ipl_count, + ipsp->ips_life.ipl_usetime.ipl_count, + ipsp->ips_life.ipl_packets.ipl_count), + extensions_reply) : 1) + && (ipsp->ips_life.ipl_allocations.ipl_hard + || ipsp->ips_life.ipl_bytes.ipl_hard + || ipsp->ips_life.ipl_addtime.ipl_hard + || ipsp->ips_life.ipl_usetime.ipl_hard + || ipsp->ips_life.ipl_packets.ipl_hard + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_HARD], + SADB_EXT_LIFETIME_HARD, + ipsp->ips_life.ipl_allocations.ipl_hard, + ipsp->ips_life.ipl_bytes.ipl_hard, + ipsp->ips_life.ipl_addtime.ipl_hard, + ipsp->ips_life.ipl_usetime.ipl_hard, + ipsp->ips_life.ipl_packets.ipl_hard), + extensions_reply) : 1) + && (ipsp->ips_life.ipl_allocations.ipl_soft + || ipsp->ips_life.ipl_bytes.ipl_soft + || ipsp->ips_life.ipl_addtime.ipl_soft + || ipsp->ips_life.ipl_usetime.ipl_soft + || ipsp->ips_life.ipl_packets.ipl_soft + ? pfkey_safe_build(error = pfkey_lifetime_build(&extensions_reply[SADB_EXT_LIFETIME_SOFT], + SADB_EXT_LIFETIME_SOFT, + ipsp->ips_life.ipl_allocations.ipl_soft, + ipsp->ips_life.ipl_bytes.ipl_soft, + ipsp->ips_life.ipl_addtime.ipl_soft, + ipsp->ips_life.ipl_usetime.ipl_soft, + ipsp->ips_life.ipl_packets.ipl_soft), + extensions_reply) : 1) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_s), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) + && (extr->ips->ips_addr_p + ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_PROXY], + SADB_EXT_ADDRESS_PROXY, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_p), + extensions_reply) : 1) +#if 0 + /* FIXME: This won't work yet because the keys are not + stored directly in the ipsec_sa. They are stored as + contexts. */ + && (extr->ips->ips_key_a_size + ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_AUTH], + SADB_EXT_KEY_AUTH, + extr->ips->ips_key_a_size * 8, + extr->ips->ips_key_a), + extensions_reply) : 1) + /* FIXME: This won't work yet because the keys are not + stored directly in the ipsec_sa. They are stored as + key schedules. */ + && (extr->ips->ips_key_e_size + ? pfkey_safe_build(error = pfkey_key_build(&extensions_reply[SADB_EXT_KEY_ENCRYPT], + SADB_EXT_KEY_ENCRYPT, + extr->ips->ips_key_e_size * 8, + extr->ips->ips_key_e), + extensions_reply) : 1) +#endif + && (extr->ips->ips_ident_s.data + ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_SRC], + SADB_EXT_IDENTITY_SRC, + extr->ips->ips_ident_s.type, + extr->ips->ips_ident_s.id, + extr->ips->ips_ident_s.len, + extr->ips->ips_ident_s.data), + extensions_reply) : 1) + && (extr->ips->ips_ident_d.data + ? pfkey_safe_build(error = pfkey_ident_build(&extensions_reply[SADB_EXT_IDENTITY_DST], + SADB_EXT_IDENTITY_DST, + extr->ips->ips_ident_d.type, + extr->ips->ips_ident_d.id, + extr->ips->ips_ident_d.len, + extr->ips->ips_ident_d.data), + extensions_reply) : 1) +#if 0 + /* FIXME: This won't work yet because I have not finished + it. */ + && (extr->ips->ips_sens_ + ? pfkey_safe_build(error = pfkey_sens_build(&extensions_reply[SADB_EXT_SENSITIVITY], + extr->ips->ips_sens_dpd, + extr->ips->ips_sens_sens_level, + extr->ips->ips_sens_sens_len, + extr->ips->ips_sens_sens_bitmap, + extr->ips->ips_sens_integ_level, + extr->ips->ips_sens_integ_len, + extr->ips->ips_sens_integ_bitmap), + extensions_reply) : 1) +#endif + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: " + "failed to build the get reply message extensions\n"); + ipsec_sa_put(ipsp); + spin_unlock_bh(&tdb_lock); + SENDERR(-error); + } + + ipsec_sa_put(ipsp); + spin_unlock_bh(&tdb_lock); + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: " + "failed to build the get reply message\n"); + SENDERR(-error); + } + + if((error = pfkey_upmsg(sk->socket, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: " + "failed to send the get reply message\n"); + SENDERR(-error); + } + + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_get_parse: " + "succeeded in sending get reply message.\n"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_acquire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_acquire_parse: .\n"); + + /* XXX I don't know if we want an upper bound, since userspace may + want to register itself for an satype > SADB_SATYPE_MAX. */ + if((satype == 0) || (satype > SADB_SATYPE_MAX)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_acquire_parse: " + "SATYPE=%d invalid.\n", + satype); + SENDERR(EINVAL); + } + + if(!(pfkey_registered_sockets[satype])) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: " + "no sockets registered for SAtype=%d(%s).\n", + satype, + satype2name(satype)); + SENDERR(EPROTONOSUPPORT); + } + + for(pfkey_socketsp = pfkey_registered_sockets[satype]; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: " + "sending up acquire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire_parse: " + "sending up acquire reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_register_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_parse: .\n"); + + /* XXX I don't know if we want an upper bound, since userspace may + want to register itself for an satype > SADB_SATYPE_MAX. */ + if((satype == 0) || (satype > SADB_SATYPE_MAX)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_parse: " + "SATYPE=%d invalid.\n", + satype); + SENDERR(EINVAL); + } + + if(!pfkey_list_insert_socket(sk->socket, + &(pfkey_registered_sockets[satype]))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_parse: " + "SATYPE=%02d(%s) successfully registered by KMd (pid=%d).\n", + satype, + satype2name(satype), + key_pid(sk)); + }; + + /* send up register msg with supported SATYPE algos */ + + error=pfkey_register_reply(satype, (struct sadb_msg*)extensions[SADB_EXT_RESERVED]); + errlab: + return error; +} +int +pfkey_register_reply(int satype, struct sadb_msg *sadb_msg) +{ + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + struct supported_list *pfkey_supported_listp; + unsigned int alg_num_a = 0, alg_num_e = 0; + struct sadb_alg *alg_a = NULL, *alg_e = NULL, *alg_ap = NULL, *alg_ep = NULL; + int error = 0; + + pfkey_extensions_init(extensions_reply); + + if((satype == 0) || (satype > SADB_SATYPE_MAX)) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: " + "SAtype=%d unspecified or unknown.\n", + satype); + SENDERR(EINVAL); + } + if(!(pfkey_registered_sockets[satype])) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: " + "no sockets registered for SAtype=%d(%s).\n", + satype, + satype2name(satype)); + SENDERR(EPROTONOSUPPORT); + } + /* send up register msg with supported SATYPE algos */ + pfkey_supported_listp = pfkey_supported_list[satype]; + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "pfkey_supported_list[%d]=0p%p\n", + satype, + pfkey_supported_list[satype]); + while(pfkey_supported_listp) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "checking supported=0p%p\n", + pfkey_supported_listp); + if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "adding auth alg.\n"); + alg_num_a++; + } + if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "adding encrypt alg.\n"); + alg_num_e++; + } + pfkey_supported_listp = pfkey_supported_listp->next; + } + + if(alg_num_a) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "allocating %lu bytes for auth algs.\n", + (unsigned long) (alg_num_a * sizeof(struct sadb_alg))); + if((alg_a = kmalloc(alg_num_a * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "auth alg memory allocation error\n"); + SENDERR(ENOMEM); + } + alg_ap = alg_a; + } + + if(alg_num_e) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "allocating %lu bytes for enc algs.\n", + (unsigned long) (alg_num_e * sizeof(struct sadb_alg))); + if((alg_e = kmalloc(alg_num_e * sizeof(struct sadb_alg), GFP_ATOMIC) ) == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "enc alg memory allocation error\n"); + SENDERR(ENOMEM); + } + alg_ep = alg_e; + } + + pfkey_supported_listp = pfkey_supported_list[satype]; + while(pfkey_supported_listp) { + if(alg_num_a) { + if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_AUTH) { + alg_ap->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id; + alg_ap->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen; + alg_ap->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits; + alg_ap->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits; + alg_ap->sadb_alg_reserved = 0; + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_register_reply: " + "adding auth=0p%p\n", + alg_ap); + alg_ap++; + } + } + if(alg_num_e) { + if(pfkey_supported_listp->supportedp->supported_alg_exttype == SADB_EXT_SUPPORTED_ENCRYPT) { + alg_ep->sadb_alg_id = pfkey_supported_listp->supportedp->supported_alg_id; + alg_ep->sadb_alg_ivlen = pfkey_supported_listp->supportedp->supported_alg_ivlen; + alg_ep->sadb_alg_minbits = pfkey_supported_listp->supportedp->supported_alg_minbits; + alg_ep->sadb_alg_maxbits = pfkey_supported_listp->supportedp->supported_alg_maxbits; + alg_ep->sadb_alg_reserved = 0; + KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, + "klips_debug:pfkey_register_reply: " + "adding encrypt=0p%p\n", + alg_ep); + alg_ep++; + } + } + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_register_reply: " + "found satype=%d(%s) exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n", + satype, + satype2name(satype), + pfkey_supported_listp->supportedp->supported_alg_exttype, + pfkey_supported_listp->supportedp->supported_alg_id, + pfkey_supported_listp->supportedp->supported_alg_ivlen, + pfkey_supported_listp->supportedp->supported_alg_minbits, + pfkey_supported_listp->supportedp->supported_alg_maxbits); + pfkey_supported_listp = pfkey_supported_listp->next; + } + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_REGISTER, + satype, + 0, + sadb_msg? sadb_msg->sadb_msg_seq : ++pfkey_msg_seq, + sadb_msg? sadb_msg->sadb_msg_pid: current->pid), + extensions_reply) && + (alg_num_a ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_AUTH], + SADB_EXT_SUPPORTED_AUTH, + alg_num_a, + alg_a), + extensions_reply) : 1) && + (alg_num_e ? pfkey_safe_build(error = pfkey_supported_build(&extensions_reply[SADB_EXT_SUPPORTED_ENCRYPT], + SADB_EXT_SUPPORTED_ENCRYPT, + alg_num_e, + alg_e), + extensions_reply) : 1))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: " + "failed to build the register message extensions_reply\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: " + "failed to build the register message\n"); + SENDERR(-error); + } + /* this should go to all registered sockets for that satype only */ + for(pfkey_socketsp = pfkey_registered_sockets[satype]; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: " + "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_register_reply: " + "sending up register message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + errlab: + if(alg_a) { + kfree(alg_a); + } + if(alg_e) { + kfree(alg_e); + } + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_expire_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + struct socket_list *pfkey_socketsp; +#ifdef CONFIG_IPSEC_DEBUG + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; +#endif /* CONFIG_IPSEC_DEBUG */ + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_expire_parse: .\n"); + + if(pfkey_open_sockets) { + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: " + "sending up expire reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire_parse: " + "sending up expire reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + } + + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_flush_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + uint8_t proto = 0; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_flush_parse: " + "flushing type %d SAs\n", + satype); + + if(satype && !(proto = satype2proto(satype))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_flush_parse: " + "satype %d lookup failed.\n", + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); + SENDERR(EINVAL); + } + + if ((error = ipsec_sadb_cleanup(proto))) { + SENDERR(-error); + } + + if(pfkey_open_sockets) { + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: " + "sending up flush reply message for satype=%d(%s) (proto=%d) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + proto, + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_flush_parse: " + "sending up flush reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + } + + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_dump_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_dump_parse: .\n"); + + SENDERR(ENOSYS); + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_promisc_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_promisc_parse: .\n"); + + SENDERR(ENOSYS); + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_pchange_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_pchange_parse: .\n"); + + SENDERR(ENOSYS); + errlab: + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_grpsa_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + struct ipsec_sa *ips1p, *ips2p, *ipsp; + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + char sa1[SATOA_BUF], sa2[SATOA_BUF]; + size_t sa_len1, sa_len2 = 0; + int error = 0; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + if(extr == NULL || extr->ips == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "extr or extr->ips is NULL, fatal.\n"); + SENDERR(EINVAL); + } + + sa_len1 = satoa(extr->ips->ips_said, 0, sa1, SATOA_BUF); + if(extr->ips2 != NULL) { + sa_len2 = satoa(extr->ips2->ips_said, 0, sa2, SATOA_BUF); + } + + spin_lock_bh(&tdb_lock); + + ips1p = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if(ips1p == NULL) { + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "reserved ipsec_sa for SA1: %s not found. Call SADB_ADD/UPDATE first.\n", + sa_len1 ? sa1 : " (error)"); + SENDERR(ENOENT); + } + if(extr->ips2) { /* GRPSA */ + ips2p = ipsec_sa_getbyid(&(extr->ips2->ips_said)); + if(ips2p == NULL) { + ipsec_sa_put(ips1p); + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "reserved ipsec_sa for SA2: %s not found. Call SADB_ADD/UPDATE first.\n", + sa_len2 ? sa2 : " (error)"); + SENDERR(ENOENT); + } + + /* Is either one already linked? */ + if(ips1p->ips_onext) { + ipsec_sa_put(ips1p); + ipsec_sa_put(ips2p); + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "ipsec_sa for SA: %s is already linked.\n", + sa_len1 ? sa1 : " (error)"); + SENDERR(EEXIST); + } + if(ips2p->ips_inext) { + ipsec_sa_put(ips1p); + ipsec_sa_put(ips2p); + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "ipsec_sa for SA: %s is already linked.\n", + sa_len2 ? sa2 : " (error)"); + SENDERR(EEXIST); + } + + /* Is extr->ips already linked to extr->ips2? */ + ipsp = ips2p; + while(ipsp) { + if(ipsp == ips1p) { + ipsec_sa_put(ips1p); + ipsec_sa_put(ips2p); + spin_unlock_bh(&tdb_lock); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "ipsec_sa for SA: %s is already linked to %s.\n", + sa_len1 ? sa1 : " (error)", + sa_len2 ? sa2 : " (error)"); + SENDERR(EEXIST); + } + ipsp = ipsp->ips_onext; + } + + /* link 'em */ + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "linking ipsec_sa SA: %s with %s.\n", + sa_len1 ? sa1 : " (error)", + sa_len2 ? sa2 : " (error)"); + ips1p->ips_onext = ips2p; + ips2p->ips_inext = ips1p; + } else { /* UNGRPSA */ + ipsec_sa_put(ips1p); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_grpsa_parse: " + "unlinking ipsec_sa SA: %s.\n", + sa_len1 ? sa1 : " (error)"); + while(ips1p->ips_onext) { + ips1p = ips1p->ips_onext; + } + while(ips1p->ips_inext) { + ipsp = ips1p; + ips1p = ips1p->ips_inext; + ipsec_sa_put(ips1p); + ipsp->ips_inext = NULL; + ipsec_sa_put(ipsp); + ips1p->ips_onext = NULL; + } + } + + spin_unlock_bh(&tdb_lock); + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_X_GRPSA, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) + && (extr->ips2 + ? (pfkey_safe_build(error = pfkey_x_satype_build(&extensions_reply[SADB_X_EXT_SATYPE2], + ((struct sadb_x_satype*)extensions[SADB_X_EXT_SATYPE2])->sadb_x_satype_satype + /* proto2satype(extr->ips2->ips_said.proto) */), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_X_EXT_SA2], + SADB_X_EXT_SA2, + extr->ips2->ips_said.spi, + extr->ips2->ips_replaywin, + extr->ips2->ips_state, + extr->ips2->ips_authalg, + extr->ips2->ips_encalg, + extr->ips2->ips_flags, + extr->ips2->ips_ref), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST2], + SADB_X_EXT_ADDRESS_DST2, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips2->ips_addr_d), + extensions_reply) ) : 1 ) + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: " + "failed to build the x_grpsa reply message extensions\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: " + "failed to build the x_grpsa reply message\n"); + SENDERR(-error); + } + + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: " + "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: " + "sending up x_grpsa reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_grpsa_parse: " + "succeeded in sending x_grpsa reply message.\n"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_addflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; +#ifdef CONFIG_IPSEC_DEBUG + char buf1[64], buf2[64]; +#endif /* CONFIG_IPSEC_DEBUG */ + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + ip_address srcflow, dstflow, srcmask, dstmask; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + memset((caddr_t)&srcflow, 0, sizeof(srcflow)); + memset((caddr_t)&dstflow, 0, sizeof(dstflow)); + memset((caddr_t)&srcmask, 0, sizeof(srcmask)); + memset((caddr_t)&dstmask, 0, sizeof(dstmask)); + + if(!extr || !(extr->ips) || !(extr->eroute)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "missing extr, ipsec_sa or eroute data.\n"); + SENDERR(EINVAL); + } + + srcflow.u.v4.sin_family = AF_INET; + dstflow.u.v4.sin_family = AF_INET; + srcmask.u.v4.sin_family = AF_INET; + dstmask.u.v4.sin_family = AF_INET; + srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src; + dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst; + srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src; + dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst; + +#ifdef CONFIG_IPSEC_DEBUG + if (debug_pfkey) { + subnettoa(extr->eroute->er_eaddr.sen_ip_src, + extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1)); + subnettoa(extr->eroute->er_eaddr.sen_ip_dst, + extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2)); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "calling breakeroute and/or makeroute for %s->%s\n", + buf1, buf2); + } +#endif /* CONFIG_IPSEC_DEBUG */ + if(extr->ips->ips_flags & SADB_X_SAFLAGS_INFLOW) { +/* if(ip_chk_addr((unsigned long)extr->ips->ips_said.dst.s_addr) == IS_MYADDR) */ + struct ipsec_sa *ipsp, *ipsq; + char sa[SATOA_BUF]; + size_t sa_len; + + ipsq = ipsec_sa_getbyid(&(extr->ips->ips_said)); + if(ipsq == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "ipsec_sa not found, cannot set incoming policy.\n"); + SENDERR(ENOENT); + } + + ipsp = ipsq; + while(ipsp && ipsp->ips_said.proto != IPPROTO_IPIP) { + ipsp = ipsp->ips_inext; + } + + if(ipsp == NULL) { + ipsec_sa_put(ipsq); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "SA chain does not have an IPIP SA, cannot set incoming policy.\n"); + SENDERR(ENOENT); + } + + sa_len = satoa(extr->ips->ips_said, 0, sa, SATOA_BUF); + + ipsp->ips_flags |= SADB_X_SAFLAGS_INFLOW; + ipsp->ips_flow_s = srcflow; + ipsp->ips_flow_d = dstflow; + ipsp->ips_mask_s = srcmask; + ipsp->ips_mask_d = dstmask; + + ipsec_sa_put(ipsq); + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "inbound eroute, setting incoming policy information in IPIP ipsec_sa for SA: %s.\n", + sa_len ? sa : " (error)"); + } else { + struct sk_buff *first = NULL, *last = NULL; + + if(extr->ips->ips_flags & SADB_X_SAFLAGS_REPLACEFLOW) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "REPLACEFLOW flag set, calling breakeroute.\n"); + if ((error = ipsec_breakroute(&(extr->eroute->er_eaddr), + &(extr->eroute->er_emask), + &first, &last))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "breakeroute returned %d. first=0p%p, last=0p%p\n", + error, + first, + last); + if(first != NULL) { + ipsec_kfree_skb(first); + } + if(last != NULL) { + ipsec_kfree_skb(last); + } + SENDERR(-error); + } + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "calling makeroute.\n"); + + if ((error = ipsec_makeroute(&(extr->eroute->er_eaddr), + &(extr->eroute->er_emask), + extr->ips->ips_said, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid, + NULL, + &(extr->ips->ips_ident_s), + &(extr->ips->ips_ident_d)))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "makeroute returned %d.\n", error); + SENDERR(-error); + } + if(first != NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "first=0p%p HOLD packet re-injected.\n", + first); + DEV_QUEUE_XMIT(first, first->dev, SOPRI_NORMAL); + } + if(last != NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "last=0p%p HOLD packet re-injected.\n", + last); + DEV_QUEUE_XMIT(last, last->dev, SOPRI_NORMAL); + } + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "makeroute call successful.\n"); + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_X_ADDFLOW, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions_reply) + && (extensions[SADB_EXT_ADDRESS_SRC] + ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_s), + extensions_reply) : 1) + && (extensions[SADB_EXT_ADDRESS_DST] + ? pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /*extr->ips->ips_said.proto,*/ + 0, + extr->ips->ips_addr_d), + extensions_reply) : 1) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW], + SADB_X_EXT_ADDRESS_SRC_FLOW, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&srcflow), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW], + SADB_X_EXT_ADDRESS_DST_FLOW, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&dstflow), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK], + SADB_X_EXT_ADDRESS_SRC_MASK, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&srcmask), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK], + SADB_X_EXT_ADDRESS_DST_MASK, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&dstmask), + extensions_reply) + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: " + "failed to build the x_addflow reply message extensions\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: " + "failed to build the x_addflow reply message\n"); + SENDERR(-error); + } + + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: " + "sending up x_addflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_addflow_parse: " + "sending up x_addflow reply message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + extr->ips->ips_said.proto, + pfkey_socketsp->socketp); + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_addflow_parse: " + "extr->ips cleaned up and freed.\n"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_delflow_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; +#ifdef CONFIG_IPSEC_DEBUG + char buf1[64], buf2[64]; +#endif /* CONFIG_IPSEC_DEBUG */ + struct sadb_ext *extensions_reply[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_reply = NULL; + struct socket_list *pfkey_socketsp; + uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype; + ip_address srcflow, dstflow, srcmask, dstmask; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: .\n"); + + pfkey_extensions_init(extensions_reply); + + memset((caddr_t)&srcflow, 0, sizeof(srcflow)); + memset((caddr_t)&dstflow, 0, sizeof(dstflow)); + memset((caddr_t)&srcmask, 0, sizeof(srcmask)); + memset((caddr_t)&dstmask, 0, sizeof(dstmask)); + + if(!extr || !(extr->ips)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "extr, or extr->ips is NULL, fatal\n"); + SENDERR(EINVAL); + } + + if(extr->ips->ips_flags & SADB_X_SAFLAGS_CLEARFLOW) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "CLEARFLOW flag set, calling cleareroutes.\n"); + if ((error = ipsec_cleareroutes())) + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "cleareroutes returned %d.\n", error); + SENDERR(-error); + } else { + struct sk_buff *first = NULL, *last = NULL; + + if(!(extr->eroute)) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "extr->eroute is NULL, fatal.\n"); + SENDERR(EINVAL); + } + + srcflow.u.v4.sin_family = AF_INET; + dstflow.u.v4.sin_family = AF_INET; + srcmask.u.v4.sin_family = AF_INET; + dstmask.u.v4.sin_family = AF_INET; + srcflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_src; + dstflow.u.v4.sin_addr = extr->eroute->er_eaddr.sen_ip_dst; + srcmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_src; + dstmask.u.v4.sin_addr = extr->eroute->er_emask.sen_ip_dst; + +#ifdef CONFIG_IPSEC_DEBUG + if (debug_pfkey) { + subnettoa(extr->eroute->er_eaddr.sen_ip_src, + extr->eroute->er_emask.sen_ip_src, 0, buf1, sizeof(buf1)); + subnettoa(extr->eroute->er_eaddr.sen_ip_dst, + extr->eroute->er_emask.sen_ip_dst, 0, buf2, sizeof(buf2)); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "calling breakeroute for %s->%s\n", + buf1, buf2); + } +#endif /* CONFIG_IPSEC_DEBUG */ + error = ipsec_breakroute(&(extr->eroute->er_eaddr), + &(extr->eroute->er_emask), + &first, &last); + if(error) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "breakeroute returned %d. first=0p%p, last=0p%p\n", + error, + first, + last); + } + if(first != NULL) { + ipsec_kfree_skb(first); + } + if(last != NULL) { + ipsec_kfree_skb(last); + } + if(error) { + SENDERR(-error); + } + } + + if(!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions_reply[0], + SADB_X_DELFLOW, + satype, + 0, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_seq, + ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_pid), + extensions_reply) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions_reply[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_FLOW], + SADB_X_EXT_ADDRESS_SRC_FLOW, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&srcflow), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_FLOW], + SADB_X_EXT_ADDRESS_DST_FLOW, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&dstflow), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_SRC_MASK], + SADB_X_EXT_ADDRESS_SRC_MASK, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&srcmask), + extensions_reply) + && pfkey_safe_build(error = pfkey_address_build(&extensions_reply[SADB_X_EXT_ADDRESS_DST_MASK], + SADB_X_EXT_ADDRESS_DST_MASK, + 0, /*extr->ips->ips_said.proto,*/ + 0, + (struct sockaddr*)&dstmask), + extensions_reply) + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: " + "failed to build the x_delflow reply message extensions\n"); + SENDERR(-error); + } + + if((error = pfkey_msg_build(&pfkey_reply, extensions_reply, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: " + "failed to build the x_delflow reply message\n"); + SENDERR(-error); + } + + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: " + "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_delflow_parse: " + "sending up x_delflow reply message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_delflow_parse: " + "extr->ips cleaned up and freed.\n"); + + errlab: + if (pfkey_reply) { + pfkey_msg_free(&pfkey_reply); + } + pfkey_extensions_free(extensions_reply); + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_msg_debug_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + int error = 0; + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_x_msg_debug_parse: .\n"); + +/* errlab:*/ + return error; +} + +/* pfkey_expire expects the ipsec_sa table to be locked before being called. */ +int +pfkey_expire(struct ipsec_sa *ipsp, int hard) +{ + struct sadb_ext *extensions[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_msg = NULL; + struct socket_list *pfkey_socketsp; + int error = 0; + uint8_t satype; + + pfkey_extensions_init(extensions); + + if(!(satype = proto2satype(ipsp->ips_said.proto))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_expire: " + "satype lookup for protocol %d lookup failed.\n", + ipsp->ips_said.proto); + SENDERR(EINVAL); + } + + if(!pfkey_open_sockets) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: " + "no sockets listening.\n"); + SENDERR(EPROTONOSUPPORT); + } + + if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0], + SADB_EXPIRE, + satype, + 0, + ++pfkey_msg_seq, + 0), + extensions) + && pfkey_safe_build(error = pfkey_sa_ref_build(&extensions[SADB_EXT_SA], + SADB_EXT_SA, + ipsp->ips_said.spi, + ipsp->ips_replaywin, + ipsp->ips_state, + ipsp->ips_authalg, + ipsp->ips_encalg, + ipsp->ips_flags, + ipsp->ips_ref), + extensions) + && pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_CURRENT], + SADB_EXT_LIFETIME_CURRENT, + ipsp->ips_life.ipl_allocations.ipl_count, + ipsp->ips_life.ipl_bytes.ipl_count, + ipsp->ips_life.ipl_addtime.ipl_count, + ipsp->ips_life.ipl_usetime.ipl_count, + ipsp->ips_life.ipl_packets.ipl_count), + extensions) + && (hard ? + pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_HARD], + SADB_EXT_LIFETIME_HARD, + ipsp->ips_life.ipl_allocations.ipl_hard, + ipsp->ips_life.ipl_bytes.ipl_hard, + ipsp->ips_life.ipl_addtime.ipl_hard, + ipsp->ips_life.ipl_usetime.ipl_hard, + ipsp->ips_life.ipl_packets.ipl_hard), + extensions) + : pfkey_safe_build(error = pfkey_lifetime_build(&extensions[SADB_EXT_LIFETIME_SOFT], + SADB_EXT_LIFETIME_SOFT, + ipsp->ips_life.ipl_allocations.ipl_soft, + ipsp->ips_life.ipl_bytes.ipl_soft, + ipsp->ips_life.ipl_addtime.ipl_soft, + ipsp->ips_life.ipl_usetime.ipl_soft, + ipsp->ips_life.ipl_packets.ipl_soft), + extensions)) + && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + 0, /* ipsp->ips_said.proto, */ + 0, + ipsp->ips_addr_s), + extensions) + && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + 0, /* ipsp->ips_said.proto, */ + 0, + ipsp->ips_addr_d), + extensions))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: " + "failed to build the expire message extensions\n"); + spin_unlock(&tdb_lock); + goto errlab; + } + + if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: " + "failed to build the expire message\n"); + SENDERR(-error); + } + + for(pfkey_socketsp = pfkey_open_sockets; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: " + "sending up expire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_expire: " + "sending up expire message for satype=%d(%s) (proto=%d) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + ipsp->ips_said.proto, + pfkey_socketsp->socketp); + } + + errlab: + if (pfkey_msg) { + pfkey_msg_free(&pfkey_msg); + } + pfkey_extensions_free(extensions); + return error; +} + +int +pfkey_acquire(struct ipsec_sa *ipsp) +{ + struct sadb_ext *extensions[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_msg = NULL; + struct socket_list *pfkey_socketsp; + int error = 0; + struct sadb_comb comb[] = { + /* auth; encrypt; flags; */ + /* auth_minbits; auth_maxbits; encrypt_minbits; encrypt_maxbits; */ + /* reserved; soft_allocations; hard_allocations; soft_bytes; hard_bytes; */ + /* soft_addtime; hard_addtime; soft_usetime; hard_usetime; */ + /* soft_packets; hard_packets; */ + { SADB_AALG_MD5_HMAC, SADB_EALG_3DES_CBC, SADB_SAFLAGS_PFS, + 128, 128, 168, 168, + 0, 0, 0, 0, 0, + 57600, 86400, 57600, 86400, + 0, 0 }, + { SADB_AALG_SHA1_HMAC, SADB_EALG_3DES_CBC, SADB_SAFLAGS_PFS, + 160, 160, 168, 168, + 0, 0, 0, 0, 0, + 57600, 86400, 57600, 86400, + 0, 0 } + }; + + /* XXX This should not be hard-coded. It should be taken from the spdb */ + uint8_t satype = SADB_SATYPE_ESP; + + pfkey_extensions_init(extensions); + + if((satype == 0) || (satype > SADB_SATYPE_MAX)) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: " + "SAtype=%d unspecified or unknown.\n", + satype); + SENDERR(EINVAL); + } + + if(!(pfkey_registered_sockets[satype])) { + KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: " + "no sockets registered for SAtype=%d(%s).\n", + satype, + satype2name(satype)); + SENDERR(EPROTONOSUPPORT); + } + + if (!(pfkey_safe_build(error = pfkey_msg_hdr_build(&extensions[0], + SADB_ACQUIRE, + satype, + 0, + ++pfkey_msg_seq, + 0), + extensions) + && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + ipsp->ips_said.proto, + 0, + ipsp->ips_addr_s), + extensions) + && pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + ipsp->ips_said.proto, + 0, + ipsp->ips_addr_d), + extensions) +#if 0 + && (ipsp->ips_addr_p + ? pfkey_safe_build(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_PROXY], + SADB_EXT_ADDRESS_PROXY, + ipsp->ips_said.proto, + 0, + ipsp->ips_addr_p), + extensions) : 1) +#endif + && (ipsp->ips_ident_s.type != SADB_IDENTTYPE_RESERVED + ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_SRC], + SADB_EXT_IDENTITY_SRC, + ipsp->ips_ident_s.type, + ipsp->ips_ident_s.id, + ipsp->ips_ident_s.len, + ipsp->ips_ident_s.data), + extensions) : 1) + + && (ipsp->ips_ident_d.type != SADB_IDENTTYPE_RESERVED + ? pfkey_safe_build(error = pfkey_ident_build(&extensions[SADB_EXT_IDENTITY_DST], + SADB_EXT_IDENTITY_DST, + ipsp->ips_ident_d.type, + ipsp->ips_ident_d.id, + ipsp->ips_ident_d.len, + ipsp->ips_ident_d.data), + extensions) : 1) +#if 0 + /* FIXME: This won't work yet because I have not finished + it. */ + && (ipsp->ips_sens_ + ? pfkey_safe_build(error = pfkey_sens_build(&extensions[SADB_EXT_SENSITIVITY], + ipsp->ips_sens_dpd, + ipsp->ips_sens_sens_level, + ipsp->ips_sens_sens_len, + ipsp->ips_sens_sens_bitmap, + ipsp->ips_sens_integ_level, + ipsp->ips_sens_integ_len, + ipsp->ips_sens_integ_bitmap), + extensions) : 1) +#endif + && pfkey_safe_build(error = pfkey_prop_build(&extensions[SADB_EXT_PROPOSAL], + 64, /* replay */ + sizeof(comb)/sizeof(struct sadb_comb), + &(comb[0])), + extensions) + )) { + KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: " + "failed to build the acquire message extensions\n"); + SENDERR(-error); + } + + if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) { + KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: " + "failed to build the acquire message\n"); + SENDERR(-error); + } + +#if KLIPS_PFKEY_ACQUIRE_LOSSAGE > 0 + if(sysctl_ipsec_regress_pfkey_lossage) { + return(0); + } +#endif + + /* this should go to all registered sockets for that satype only */ + for(pfkey_socketsp = pfkey_registered_sockets[satype]; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) { + KLIPS_PRINT(1|debug_pfkey, "klips_debug:pfkey_acquire: " + "sending up acquire message for satype=%d(%s) to socket=0p%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_acquire: " + "sending up acquire message for satype=%d(%s) to socket=0p%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + errlab: + if (pfkey_msg) { + pfkey_msg_free(&pfkey_msg); + } + pfkey_extensions_free(extensions); + return error; +} + +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL +int +pfkey_nat_t_new_mapping(struct ipsec_sa *ipsp, struct sockaddr *ipaddr, + __u16 sport) +{ + struct sadb_ext *extensions[SADB_EXT_MAX+1]; + struct sadb_msg *pfkey_msg = NULL; + struct socket_list *pfkey_socketsp; + int error = 0; + uint8_t satype = (ipsp->ips_said.proto==IPPROTO_ESP) ? SADB_SATYPE_ESP : 0; + + /* Construct SADB_X_NAT_T_NEW_MAPPING message */ + + pfkey_extensions_init(extensions); + + if((satype == 0) || (satype > SADB_SATYPE_MAX)) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: " + "SAtype=%d unspecified or unknown.\n", + satype); + SENDERR(EINVAL); + } + + if(!(pfkey_registered_sockets[satype])) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: " + "no sockets registered for SAtype=%d(%s).\n", + satype, + satype2name(satype)); + SENDERR(EPROTONOSUPPORT); + } + + if (!(pfkey_safe_build + (error = pfkey_msg_hdr_build(&extensions[0], SADB_X_NAT_T_NEW_MAPPING, + satype, 0, ++pfkey_msg_seq, 0), extensions) + /* SA */ + && pfkey_safe_build + (error = pfkey_sa_build(&extensions[SADB_EXT_SA], + SADB_EXT_SA, ipsp->ips_said.spi, 0, 0, 0, 0, 0), extensions) + /* ADDRESS_SRC = old addr */ + && pfkey_safe_build + (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, ipsp->ips_said.proto, 0, ipsp->ips_addr_s), + extensions) + /* NAT_T_SPORT = old port */ + && pfkey_safe_build + (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_SPORT], + SADB_X_EXT_NAT_T_SPORT, ipsp->ips_natt_sport), extensions) + /* ADDRESS_DST = new addr */ + && pfkey_safe_build + (error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, ipsp->ips_said.proto, 0, ipaddr), extensions) + /* NAT_T_DPORT = new port */ + && pfkey_safe_build + (error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_DPORT], + SADB_X_EXT_NAT_T_DPORT, sport), extensions) + )) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: " + "failed to build the nat_t_new_mapping message extensions\n"); + SENDERR(-error); + } + + if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: " + "failed to build the nat_t_new_mapping message\n"); + SENDERR(-error); + } + + /* this should go to all registered sockets for that satype only */ + for(pfkey_socketsp = pfkey_registered_sockets[satype]; + pfkey_socketsp; + pfkey_socketsp = pfkey_socketsp->next) { + if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: " + "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p failed with error=%d.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp, + error); + SENDERR(-error); + } + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: " + "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p succeeded.\n", + satype, + satype2name(satype), + pfkey_socketsp->socketp); + } + + errlab: + if (pfkey_msg) { + pfkey_msg_free(&pfkey_msg); + } + pfkey_extensions_free(extensions); + return error; +} + +DEBUG_NO_STATIC int +pfkey_x_nat_t_new_mapping_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr) +{ + /* SADB_X_NAT_T_NEW_MAPPING not used in kernel */ + return -EINVAL; +} +#endif + +DEBUG_NO_STATIC int (*ext_processors[SADB_EXT_MAX+1])(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) = +{ + NULL, /* pfkey_msg_process, */ + pfkey_sa_process, + pfkey_lifetime_process, + pfkey_lifetime_process, + pfkey_lifetime_process, + pfkey_address_process, + pfkey_address_process, + pfkey_address_process, + pfkey_key_process, + pfkey_key_process, + pfkey_ident_process, + pfkey_ident_process, + pfkey_sens_process, + pfkey_prop_process, + pfkey_supported_process, + pfkey_supported_process, + pfkey_spirange_process, + pfkey_x_kmprivate_process, + pfkey_x_satype_process, + pfkey_sa_process, + pfkey_address_process, + pfkey_address_process, + pfkey_address_process, + pfkey_address_process, + pfkey_address_process, + pfkey_x_debug_process, + pfkey_x_protocol_process +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + , + pfkey_x_nat_t_type_process, + pfkey_x_nat_t_port_process, + pfkey_x_nat_t_port_process, + pfkey_address_process +#endif +}; + + +DEBUG_NO_STATIC int (*msg_parsers[SADB_MAX +1])(struct sock *sk, struct sadb_ext *extensions[], struct pfkey_extracted_data* extr) + = +{ + NULL, /* RESERVED */ + pfkey_getspi_parse, + pfkey_update_parse, + pfkey_add_parse, + pfkey_delete_parse, + pfkey_get_parse, + pfkey_acquire_parse, + pfkey_register_parse, + pfkey_expire_parse, + pfkey_flush_parse, + pfkey_dump_parse, + pfkey_x_promisc_parse, + pfkey_x_pchange_parse, + pfkey_x_grpsa_parse, + pfkey_x_addflow_parse, + pfkey_x_delflow_parse, + pfkey_x_msg_debug_parse +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + , pfkey_x_nat_t_new_mapping_parse +#endif +}; + +int +pfkey_build_reply(struct sadb_msg *pfkey_msg, struct pfkey_extracted_data *extr, + struct sadb_msg **pfkey_reply) +{ + struct sadb_ext *extensions[SADB_EXT_MAX+1]; + int error = 0; + int msg_type = pfkey_msg->sadb_msg_type; + int seq = pfkey_msg->sadb_msg_seq; + + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: " + "building reply with type: %d\n", + msg_type); + pfkey_extensions_init(extensions); + if (!extr || !extr->ips) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: " + "bad ipsec_sa passed\n"); + return EINVAL; + } + error = pfkey_safe_build(pfkey_msg_hdr_build(&extensions[0], + msg_type, + proto2satype(extr->ips->ips_said.proto), + 0, + seq, + pfkey_msg->sadb_msg_pid), + extensions) && + (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] & + 1 << SADB_EXT_SA) + || pfkey_safe_build(pfkey_sa_ref_build(&extensions[SADB_EXT_SA], + SADB_EXT_SA, + extr->ips->ips_said.spi, + extr->ips->ips_replaywin, + extr->ips->ips_state, + extr->ips->ips_authalg, + extr->ips->ips_encalg, + extr->ips->ips_flags, + extr->ips->ips_ref), + extensions)) && + (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] & + 1 << SADB_EXT_LIFETIME_CURRENT) + || pfkey_safe_build(pfkey_lifetime_build(&extensions + [SADB_EXT_LIFETIME_CURRENT], + SADB_EXT_LIFETIME_CURRENT, + extr->ips->ips_life.ipl_allocations.ipl_count, + extr->ips->ips_life.ipl_bytes.ipl_count, + extr->ips->ips_life.ipl_addtime.ipl_count, + extr->ips->ips_life.ipl_usetime.ipl_count, + extr->ips->ips_life.ipl_packets.ipl_count), + extensions)) && + (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] & + 1 << SADB_EXT_ADDRESS_SRC) + || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC], + SADB_EXT_ADDRESS_SRC, + extr->ips->ips_said.proto, + 0, + extr->ips->ips_addr_s), + extensions)) && + (!(extensions_bitmaps[EXT_BITS_OUT][EXT_BITS_REQ][msg_type] & + 1 << SADB_EXT_ADDRESS_DST) + || pfkey_safe_build(pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST], + SADB_EXT_ADDRESS_DST, + extr->ips->ips_said.proto, + 0, + extr->ips->ips_addr_d), + extensions)); + + if (error == 0) { + KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_build_reply: " + "building extensions failed\n"); + return EINVAL; + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_build_reply: " + "built extensions, proceed to build the message\n"); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_build_reply: " + "extensions[1]=0p%p\n", + extensions[1]); + error = pfkey_msg_build(pfkey_reply, extensions, EXT_BITS_OUT); + pfkey_extensions_free(extensions); + + return error; +} + +int +pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg, + struct sadb_msg **pfkey_reply) +{ + int error = 0; + int i; + struct sadb_ext *extensions[SADB_EXT_MAX+1]; + struct pfkey_extracted_data extr = {NULL, NULL, NULL}; + + pfkey_extensions_init(extensions); + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "parsing message ver=%d, type=%d, errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", + pfkey_msg->sadb_msg_version, + pfkey_msg->sadb_msg_type, + pfkey_msg->sadb_msg_errno, + pfkey_msg->sadb_msg_satype, + satype2name(pfkey_msg->sadb_msg_satype), + pfkey_msg->sadb_msg_len, + pfkey_msg->sadb_msg_reserved, + pfkey_msg->sadb_msg_seq, + pfkey_msg->sadb_msg_pid); + + extr.ips = ipsec_sa_alloc(&error); /* pass in error var by pointer */ + if(extr.ips == NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "memory allocation error.\n"); + SENDERR(-error); + } + + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "allocated extr->ips=0p%p.\n", + extr.ips); + + if(pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "satype %d > max %d\n", + pfkey_msg->sadb_msg_satype, + SADB_SATYPE_MAX); + SENDERR(EINVAL); + } + + switch(pfkey_msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_X_GRPSA: + case SADB_X_ADDFLOW: + if(!(extr.ips->ips_said.proto = satype2proto(pfkey_msg->sadb_msg_satype))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "satype %d lookup failed.\n", + pfkey_msg->sadb_msg_satype); + SENDERR(EINVAL); + } else { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "satype %d lookups to proto=%d.\n", + pfkey_msg->sadb_msg_satype, + extr.ips->ips_said.proto); + } + break; + default: + break; + } + + /* The NULL below causes the default extension parsers to be used */ + /* Parse the extensions */ + if((error = pfkey_msg_parse(pfkey_msg, NULL, extensions, EXT_BITS_IN))) + { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "message parsing failed with error %d.\n", + error); + SENDERR(-error); + } + + /* Process the extensions */ + for(i=1; i <= SADB_EXT_MAX;i++) { + if(extensions[i] != NULL) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "processing ext %d 0p%p with processor 0p%p.\n", + i, extensions[i], ext_processors[i]); + if((error = ext_processors[i](extensions[i], &extr))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "extension processing for type %d failed with error %d.\n", + i, + error); + SENDERR(-error); + } + + } + + } + + /* Parse the message types */ + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "parsing message type %d(%s) with msg_parser 0p%p.\n", + pfkey_msg->sadb_msg_type, + pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type), + msg_parsers[pfkey_msg->sadb_msg_type]); + if((error = msg_parsers[pfkey_msg->sadb_msg_type](sk, extensions, &extr))) { + KLIPS_PRINT(debug_pfkey, + "klips_debug:pfkey_msg_interp: " + "message parsing failed with error %d.\n", + error); + SENDERR(-error); + } + +#if 0 + error = pfkey_build_reply(pfkey_msg, &extr, pfkey_reply); + if (error) { + *pfkey_reply = NULL; + } +#endif + errlab: + if(extr.ips != NULL) { + ipsec_sa_wipe(extr.ips); + } + if(extr.ips2 != NULL) { + ipsec_sa_wipe(extr.ips2); + } + if (extr.eroute != NULL) { + kfree(extr.eroute); + } + return(error); +} + |