--- openswan-2.1.6/programs/pluto/id.h.original	2005-04-15 11:45:05.424962712 +1000
+++ openswan-2.1.6/programs/pluto/id.h	2005-04-15 11:45:05.468956024 +1000
@@ -54,6 +54,7 @@
 extern bool match_id(const struct id *a, const struct id *b, int *wildcards);
 extern int id_count_wildcards(const struct id *id);
 #define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR)
+#define id_is_any(id) (id_is_ipaddr(id) ? isanyaddr(&(id)->ip_addr) : FALSE)
 
 struct isakmp_ipsec_id;	/* forward declaration of tag (defined in packet.h) */
 extern void
--- openswan-2.1.6/programs/pluto/keys.c.original	2005-04-15 13:58:07.278536528 +1000
+++ openswan-2.1.6/programs/pluto/keys.c	2005-04-15 13:58:16.446142840 +1000
@@ -308,9 +308,11 @@
 get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym)
 {
     enum {	/* bits */
-	match_default = 01,
-	match_him = 02,
-	match_me = 04
+	match_him = 1,
+	match_me = 2,
+	match_him_exact = 4,
+	match_me_exact = 8
+
     };
     unsigned char idstr1[IDTOA_BUF], idme[IDTOA_BUF], idhim[IDTOA_BUF];
     unsigned int best_match = 0;
@@ -318,156 +320,107 @@
     struct secret *s;
     const struct id *my_id = &c->spd.this.id
 	, *his_id = &c->spd.that.id;
-    struct id rw_id;
-
-    idtoa(my_id,  idme,  IDTOA_BUF);
-    idtoa(his_id, idhim, IDTOA_BUF);
-
-    DBG(DBG_CONTROL,
-	DBG_log("looking for secret for %s->%s of kind %s",
-		idme, idhim, enum_name(&ppk_names, kind)));
-
-    /* is there a certificate assigned to this connection? */
-    if (kind == PPK_RSA && c->spd.this.cert.type != CERT_NONE)
-    {
-	struct pubkey *my_public_key = allocate_RSA_public_key(c->spd.this.cert);
-
-	for (s = secrets; s != NULL; s = s->next)
-	{
-	  DBG(DBG_CONTROL,
-	      DBG_log("searching for certificate %s:%s vs %s:%s",
-		      enum_name(&ppk_names, s->kind),
-		      s->u.RSA_private_key.pub.keyid,
-		      enum_name(&ppk_names, kind),
-		      my_public_key->u.rsa.keyid)
-	      );
-	    if (s->kind == kind &&
-		same_RSA_public_key(&s->u.RSA_private_key.pub, &my_public_key->u.rsa))
-	    {
-		best = s;
-		break; /* we have found the private key - no sense in searching further */
-	    }
-	}
-	free_public_key(my_public_key);
-	return best;
-    }
+    // struct id rw_id;
 
-    if (his_id_was_instantiated(c))
-    {
-	/* roadwarrior: replace him with 0.0.0.0 */
-	rw_id.kind = addrtypeof(&c->spd.that.host_addr) == AF_INET ?
-	    ID_IPV4_ADDR : ID_IPV6_ADDR;
-	happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
-	his_id = &rw_id;
-    }
-#ifdef NAT_TRAVERSAL
-    else if ((nat_traversal_enabled) && (c->policy & POLICY_PSK) &&
-       (kind == PPK_PSK) && (
-	((c->kind == CK_TEMPLATE) && (c->spd.that.id.kind == ID_NONE)) ||
-	((c->kind == CK_INSTANCE) && (id_is_ipaddr(&c->spd.that.id)))))
-    {
-	    /* roadwarrior: replace him with 0.0.0.0 */
-	    rw_id.kind = ID_IPV4_ADDR;
-	    happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
-	    his_id = &rw_id;
-    }
-#endif
 
     for (s = secrets; s != NULL; s = s->next)
     {
+	unsigned int match = 0;
+	int anycnt = 0, idcnt = 0;
+	struct id_list *i;
 
-	if (s->kind == kind)
+	for (i = s->ids; i != NULL; i = i->next)
 	{
-	    unsigned int match = 0;
+	    idcnt++;
 
-	    if (s->ids == NULL)
-	    {
-		/* a default (signified by lack of ids):
-		 * accept if no more specific match found
-		 */
-		match = match_default;
-	    }
+	    if ( id_is_any(&i->id) )
+		anycnt++;
 	    else
 	    {
-		/* check if both ends match ids */
-		struct id_list *i;
+		if (same_id(my_id, &i->id))
+		    match |= match_me | match_me_exact;
 
-		for (i = s->ids; i != NULL; i = i->next)
-		{
-		    idtoa(&i->id, idstr1, IDTOA_BUF);
+		if (same_id(his_id, &i->id))
+		    match |= match_him | match_him_exact;
 
-		    DBG(DBG_PRIVATE,
-			DBG_log("comparing PSK %s to %s / %s",
-				idstr1, idme, idhim));
+	    }
+	}
 
-		    if (same_id(my_id, &i->id))
-			match |= match_me;
+	/* If only one ID, add a %any. If none, add 2. */
+	if ( idcnt <= 1 )
+	{
+	   anycnt++;
+	   if ( idcnt == 0 )
+	      anycnt++;
+	}
 
-		    if (same_id(his_id, &i->id))
-			match |= match_him;
-		}
+	/* Distribute any to him and me if we don't have a match. */
+	if ( anycnt > 0 && !(match & match_him_exact) )
+	{
+	   match |= match_him;
+	   anycnt--;
+	}
 
-		/* If our end matched the only id in the list,
-		 * default to matching any peer.
-		 * A more specific match will trump this.
-		 */
-		if (match == match_me
-		&& s->ids->next == NULL)
-		    match |= match_default;
-	    }
+	if ( anycnt > 0 && !(match & match_me_exact) )
+	{
+	   match |= match_me;
+	   anycnt--;
+	}
 
-	    switch (match)
-	    {
-	    case match_me:
-		/* if this is an asymmetric (eg. public key) system,
-		 * allow this-side-only match to count, even if
-		 * there are other ids in the list.
+	/* COMPATABILITY:  if this is an asymmetric (eg. public key)
+	 * system, allow this-side-only match to count, even if
+	 * there are other ids in the list.
+	 *
+	 * Is this really a good idea?
+	 *
+	 * Treat as a match for him against %any.
+	 */
+	if ( (match & match_me) && !(match & match_him) && asym )
+	   match |= match_him;
+
+	/* If we got a match in him and me, this is a successful match.
+	 * See if it supercedes the current best match.
+	 */
+	if ( (match & match_me) && (match & match_him) )
+	{
+	   if (match == best_match)
+	   {
+		/* two good matches are equally good:
+		 * do they agree?
 		 */
-		if (!asym)
-		    break;
-		/* FALLTHROUGH */
-	    case match_default:	/* default all */
-	    case match_me | match_default:	/* default peer */
-	    case match_me | match_him:	/* explicit */
-		if (match == best_match)
-		{
-		    /* two good matches are equally good:
-		     * do they agree?
-		     */
-		    bool same;
+		bool same;
 
-		    switch (kind)
-		    {
-		    case PPK_PSK:
+		switch (kind)
+		{
+		case PPK_PSK:
 			same = s->u.preshared_secret.len == best->u.preshared_secret.len
-			    && memcmp(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len) == 0;
-			break;
-		    case PPK_RSA:
+			&& memcmp(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len) == 0;
+		   break;
+		case PPK_RSA:
 			/* Dirty trick: since we have code to compare
 			 * RSA public keys, but not private keys, we
 			 * make the assumption that equal public keys
 			 * mean equal private keys.  This ought to work.
 			 */
 			same = same_RSA_public_key(&s->u.RSA_private_key.pub
-			    , &best->u.RSA_private_key.pub);
+				, &best->u.RSA_private_key.pub);
 			break;
-		    default:
+		default:
 			bad_case(kind);
-		    }
-		    if (!same)
-		    {
-			loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with distinct secrets match endpoints:"
-			    " first secret used");
-			best = s;	/* list is backwards: take latest in list */
-		    }
 		}
-		else if (match > best_match)
+		if (!same)
 		{
-		    /* this is the best match so far */
-		    best_match = match;
-		    best = s;
+			loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with distinct secrets match endpoints:"
+				" first secret used");
+			best = s;   /* list is backwards: take latest in list */
 		}
-	    }
+	   }
+	   else if (match > best_match)
+	   {
+		/* this is the best match so far */
+		best_match = match;
+		best = s;
+	   }
 	}
     }
     return best;
