[PFKEY]
Adds support for RFC 2367 Section 3.1.6 option 3 - SA consumer sending of
PFKEY acquire messages.  Previously, the only acquire messages accepted from
user space to the kernel was for the key manager to indicate an error.

Signed-off-by: Thomas M. DuBuisson <[EMAIL PROTECTED]>

----

The Linux kernels implementation of PFKEYv2 is not compliant with the
standard (RFC 2367). As stated in section 3.1.6, option 3, an application
layer consumer of SAs in need of an association may send an acquire message
to the kernel looking like this:
        <base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
And the kernel should respond to registered KMs as such:
        <base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>

The patch makes the kernel respond:
        <base, address(SD), ...as above..., proposal, (policy)>

The message flow looks a bit like:
        App->PFKEY Socket->af_key.c code->PF_KEY registered sockets

Another option would be to force the PF_KEY specification on XFRM in effort
to include netlink / any other key managers, but do we really want PF_KEY
specification dictating XFRM?  This flow would be a little more work to
implement:
        App->PFKEY Scoket->af_key.c code->XFRM->{netlink,
pfkey_send_acquire}->{PFKEY,netlink registered sockets}

Please review the code as I am not familiar with Kernel programming.

Thomas DuBuisson

(1 file, +93, -14)

--- linux-2.6.14.5/net/key/af_key.c.orig        2006-01-04
11:00:34.000000000 -0500
+++ linux-2.6.14.5/net/key/af_key.c     2006-01-04 11:08:30.000000000 -0500
@@ -33,6 +33,7 @@
 #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
 #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
 
+static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp);
 
 /* List of all pfkey sockets. */
 static HLIST_HEAD(pfkey_table);
@@ -1221,25 +1222,103 @@ static int pfkey_getspi(struct sock *sk,
 
 static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct
sadb_msg *hdr, void **ext_hdrs)
 {
-       struct xfrm_state *x;
+       struct sadb_x_policy *pol;
+       struct sk_buff *out_skb;
+       struct sadb_address *sa;
+       struct xfrm_selector sel;
+       struct xfrm_policy *xp;
+       struct sadb_msg *hdr2;
+       int pol_size = sizeof(struct sadb_x_policy);
+       int i, err;
+
+       if (hdr->sadb_msg_len == sizeof(struct sadb_msg)/8) {
+               struct xfrm_state *x;
+               if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0)
+                       return 0;
+
+               x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);
+               if (x == NULL)
+                       return 0;
+
+               spin_lock_bh(&x->lock);
+               if (x->km.state == XFRM_STATE_ACQ) {
+                       x->km.state = XFRM_STATE_ERROR;
+                       wake_up(&km_waitq);
+               }
+               spin_unlock_bh(&x->lock);
+               xfrm_state_put(x);
+               return 0;
+       }
+
+       if(!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+                                       ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
+                                       !ext_hdrs[SADB_EXT_PROPOSAL-1])
+               return -EINVAL;
+
+       for(i=0; i<SADB_EXT_MAX; i++) {
+               switch(i+1) {
+               case SADB_EXT_ADDRESS_SRC:
+               case SADB_EXT_ADDRESS_DST:
+               case SADB_EXT_ADDRESS_PROXY:
+               case SADB_EXT_IDENTITY_SRC:
+               case SADB_EXT_IDENTITY_DST:
+               case SADB_EXT_SENSITIVITY:
+               case SADB_EXT_PROPOSAL:
+                       break;
+               default:
+                       if(ext_hdrs[i] != NULL)
+                               return -EOPNOTSUPP;
+               }
+       }
 
-       if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8)
-               return -EOPNOTSUPP;
+       // Get the XFRM policy (if one exists)
+       memset(&sel, 0, sizeof(sel));
+       sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+       sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
+       sel.prefixlen_s = sa->sadb_address_prefixlen;
+       sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+       sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
+       if(sel.sport)
+               sel.sport_mask = ~0;
 
-       if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0)
-               return 0;
+       sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
+       pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
+       sel.prefixlen_d = sa->sadb_address_prefixlen;
+       sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+       sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
+       if (sel.dport)
+               sel.dport_mask = ~0;
 
-       x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);
-       if (x == NULL)
-               return 0;
+       xp = xfrm_policy_bysel(IPSEC_DIR_OUTBOUND-1, &sel, 0);
 
-       spin_lock_bh(&x->lock);
-       if (x->km.state == XFRM_STATE_ACQ) {
-               x->km.state = XFRM_STATE_ERROR;
-               wake_up(&km_waitq);
+       // Now that we have the policy (or NULL), build and send acquire msg
+       if(xp == NULL) {
+               out_skb = skb_clone(skb, GFP_KERNEL);
+       }
+       else {
+               out_skb = skb_copy_expand(skb, 0, pol_size, GFP_ATOMIC);
+               hdr2 = pfkey_get_base_msg(out_skb, &err);
+               pol = (struct sadb_x_policy *) skb_put(out_skb, pol_size);
+               pol->sadb_x_policy_len = pol_size/8;
+               pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+               pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD;
+               if (xp->action == XFRM_POLICY_ALLOW) {
+                       if (xp->xfrm_nr)
+                               pol->sadb_x_policy_type =
IPSEC_POLICY_IPSEC;
+                       else
+                               pol->sadb_x_policy_type = IPSEC_POLICY_NONE;
+               }
+               pol->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
+               pol->sadb_x_policy_id = xp->index;
+               pol->sadb_x_policy_priority = xp->priority;
+
+               if(err) {
+                       dev_kfree_skb(out_skb);
+                       return err;
+               }
+               hdr2->sadb_msg_len += pol_size/8;
        }
-       spin_unlock_bh(&x->lock);
-       xfrm_state_put(x);
+       pfkey_broadcast(out_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk);
        return 0;
 }
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to