[strongSwan-dev] [PATCH] xauth_identity config option

Heiko Hund hhund at astaro.com
Thu May 6 14:19:38 CEST 2010


Hi list.

This introduces the new configuration option "xauth_identity" which
is used similar to the "eap_identity" option. It was needed to allow
strongSwan to have more than one XAUTH credential. It comes with a
change of the format for XAUTH ipsec.secrets(5). The new form is:

    <xauth_id> [remote_id] : XAUTH <password>

Note that the username moved to the beginning of the line. The
"xauth_identity" value of a connection is matched against <xauth_id>
when a XAUTH client is looking for a secret. On the XAUTH server
it is matched against the incoming user name. The <xauth_id> is 
optionally followed by a remote ID. It's only needed on the client
side if a client has the same username but different passwords with
two or more XAUTH servers. The <remote_id> will be matched against
the <rightid> from the client connection.

If the "xauth_identity" is set to "%any" on the server side. Lookup
for virtual IP addresses is performed with the XAUTH user name as
identity instead of the client's ID from phase 1. This is especially
nice in case of PSK authentication where the client ID is the - most
of the times dynamic - client IP address.

Applies to strongSwan 4.4.0

Please test and comment.

Heiko

Signed-off-by: Heiko Hund <hhund at astaro.com>

---
 src/pluto/connections.c    |   20 ++++++-
 src/pluto/connections.h    |    2 +
 src/pluto/keys.c           |  131 ++++++++++++++++++++++++++++++--------------
 src/pluto/modecfg.c        |   21 ++++++-
 src/pluto/rcv_whack.c      |    1 +
 src/pluto/xauth.c          |    3 +-
 src/pluto/xauth.h          |    5 +-
 src/starter/args.c         |    1 +
 src/starter/confread.h     |    1 +
 src/starter/keywords.h     |    1 +
 src/starter/keywords.txt   |    1 +
 src/starter/starterwhack.c |    2 +
 src/whack/whack.c          |    1 +
 src/whack/whack.h          |    5 +-
 14 files changed, 143 insertions(+), 52 deletions(-)

diff --git a/src/pluto/connections.c b/src/pluto/connections.c
index b83c3b3..84075c1 100644
--- a/src/pluto/connections.c
+++ b/src/pluto/connections.c
@@ -418,6 +418,8 @@ void delete_connection(connection_t *c, bool relations)
 	cur_debugging = old_cur_debugging;
 #endif
 	free(c->name);
+	DESTROY_IF(c->xauth_identity);
+	DESTROY_IF(c->xauth_username);
 	DESTROY_IF(c->spd.this.id);
 	DESTROY_IF(c->spd.this.ca);
 	DESTROY_IF(c->spd.this.groups);
@@ -781,6 +783,14 @@ static size_t format_connection(char *buf, size_t buf_len,
 static void unshare_connection_strings(connection_t *c)
 {
 	c->name = clone_str(c->name);
+	if (c->xauth_identity)
+	{
+		c->xauth_identity = c->xauth_identity->clone(c->xauth_identity);
+	}
+	if (c->xauth_username)
+	{
+		c->xauth_username = c->xauth_username->clone(c->xauth_username);
+	}
 	c->spd.this.id = c->spd.this.id->clone(c->spd.this.id);
 	c->spd.this.pool = clone_str(c->spd.this.pool);
 	c->spd.this.updown = clone_str(c->spd.this.updown);
@@ -1083,10 +1093,16 @@ void add_connection(const whack_message_t *wm)
 		connection_t *c = malloc_thing(connection_t);
 
 		zero(c);
-		c->name   = clone_str(wm->name);
-		c->ikev1  = wm->ikev1;
+		c->name = clone_str(wm->name);
+		c->ikev1 = wm->ikev1;
 		c->policy = wm->policy;
 
+		if (wm->xauth_identity)
+		{
+			c->xauth_identity
+				= identification_create_from_string(wm->xauth_identity);
+		}
+
 		if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp)
 		{
 			loglog(RC_COMMENT
diff --git a/src/pluto/connections.h b/src/pluto/connections.h
index 477012a..ba13ecf 100644
--- a/src/pluto/connections.h
+++ b/src/pluto/connections.h
@@ -185,6 +185,8 @@ struct connection {
 	time_t sa_rekey_margin;
 	unsigned long sa_rekey_fuzz;
 	unsigned long sa_keying_tries;
+	identification_t *xauth_identity;     /* xauth_identity value from config */
+	identification_t *xauth_username;     /* client username sent to server */
 
 	/* RFC 3706 DPD */
 	time_t dpd_delay;
diff --git a/src/pluto/keys.c b/src/pluto/keys.c
index 747df4c..ed1c620 100644
--- a/src/pluto/keys.c
+++ b/src/pluto/keys.c
@@ -70,7 +70,7 @@ struct secret {
 	enum PrivateKeyKind kind;
 	union {
 		chunk_t        preshared_secret;
-		xauth_t        xauth_secret;
+		chunk_t        xauth_secret;
 		private_key_t *private_key;
 		smartcard_t   *smartcard;
 	} u;
@@ -639,86 +639,134 @@ static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd)
  */
 static err_t process_xauth(secret_t *s)
 {
-	chunk_t user_name;
+	if (s->ids == NULL)
+	{
+		return "missing XAUTH username";
+	}
+	if (!shift())
+	{
+		return "missing XAUTH password";
+	}
 
 	s->kind = PPK_XAUTH;
-
-	if (!shift())
-		return "missing xauth user name";
-	if (*tok == '"' || *tok == '\'')  /* quoted user name */
+	if (s->ids->next)
 	{
-		user_name.ptr = tok + 1;
-		user_name.len = flp->cur - tok - 2;
+		plog("  loaded XAUTH key for %Y %Y", s->ids->id, s->ids->next->id);
 	}
 	else
 	{
-		user_name.ptr = tok;
-		user_name.len = flp->cur - tok;
+		plog("  loaded XAUTH key for %Y", s->ids->id);
 	}
-	plog("  loaded xauth credentials of user '%.*s'"
-				, user_name.len
-				, user_name.ptr);
-	s->u.xauth_secret.user_name = chunk_clone(user_name);
-
-	if (!shift())
-		return "missing xauth user password";
-	return process_psk_secret(&s->u.xauth_secret.user_password);
+	return process_psk_secret(&s->u.xauth_secret);
 }
 
 /**
  * Get XAUTH secret from chained secrets lists
- * only one entry is currently supported
  */
-static bool xauth_get_secret(xauth_t *xauth_secret)
+static bool xauth_get_secret(const connection_t *c, xauth_t *credentials)
 {
+	typedef enum {
+		match_none,
+		match_user,
+		match_both
+	} match_t;
+
+	identification_t *xauth_id = c->xauth_identity;
+	identification_t *remote_id = c->spd.that.id;
+	match_t best_match = match_none;
+	secret_t *best_secret = NULL;
 	secret_t *s;
-	bool found = FALSE;
 
 	for (s = secrets; s != NULL; s = s->next)
 	{
-		if (s->kind == PPK_XAUTH)
+		match_t match = match_none;
+
+		if (s->kind != PPK_XAUTH)
 		{
-			if (found)
+			continue;
+		}
+
+		if (xauth_id)
+		{
+			if (s->ids->next)
 			{
-				plog("found multiple xauth secrets - first selected");
+				if (!xauth_id->equals(xauth_id, s->ids->id)
+				||  !remote_id->equals(remote_id, s->ids->next->id))
+				{
+					continue;
+				}
+				match = match_both;
 			}
 			else
 			{
-				found = TRUE;
-				*xauth_secret = s->u.xauth_secret;
+				if (!xauth_id->equals(xauth_id, s->ids->id))
+				{
+					continue;
+				}
+				match = match_user;
 			}
 		}
+
+		if (match > best_match || !best_secret)
+		{
+			best_match = match;
+			best_secret = s;
+		}
+		else if (match == best_match
+		&& chunk_equals(best_secret->u.xauth_secret, s->u.xauth_secret))
+		{
+			best_secret = s;  /* list is backwards: take latest in list */
+			plog("found matching XAUTH entries that conflict: using first one");
+		}
+	}
+
+	if (best_secret)
+	{
+		identification_t *xauth_id = best_secret->ids->id;
+		credentials->user_name = xauth_id->get_encoding(xauth_id);
+		credentials->user_password = best_secret->u.xauth_secret;
 	}
-	return found;
+
+	return (best_secret ? TRUE : FALSE);
 }
 
 /**
  * find a matching secret
  */
 static bool xauth_verify_secret(const xauth_peer_t *peer,
-								const xauth_t *xauth_secret)
+								const xauth_t *credentials)
 {
+	identification_t *xauth_id;
 	bool found = FALSE;
 	secret_t *s;
 
+	xauth_id = identification_create_from_data(credentials->user_name);
+
 	for (s = secrets; s != NULL; s = s->next)
 	{
 		if (s->kind == PPK_XAUTH)
 		{
-			if (!chunk_equals(xauth_secret->user_name, s->u.xauth_secret.user_name))
-			{
-				continue;
-			}
-			found = TRUE;
-			if (chunk_equals(xauth_secret->user_password, s->u.xauth_secret.user_password))
-			{
-				return TRUE;
-			}
+			continue;
+		}
+
+		if (!xauth_id->equals(xauth_id, s->ids->id))
+		{
+			continue;
+		}
+
+		found = TRUE;
+		if (chunk_equals(credentials->user_password, s->u.xauth_secret))
+		{
+			xauth_id->destroy(xauth_id);
+			return TRUE;
 		}
 	}
-	plog("xauth user '%.*s' %s"
-	   , xauth_secret->user_name.len, xauth_secret->user_name.ptr
-	   , found? "sent wrong password":"not found");
+
+	plog("XAUTH user '%.*s' %s"
+		, credentials->user_name.len, credentials->user_name.ptr
+		, (found ? "sent wrong password" : "not found"));
+
+	xauth_id->destroy(xauth_id);
 	return FALSE;
 }
 
@@ -1133,8 +1181,7 @@ void free_preshared_secrets(void)
 				DESTROY_IF(s->u.private_key);
 				break;
 			case PPK_XAUTH:
-				free(s->u.xauth_secret.user_name.ptr);
-				free(s->u.xauth_secret.user_password.ptr);
+				free(s->u.xauth_secret.ptr);
 				break;
 			case PPK_PIN:
 				scx_release(s->u.smartcard);
diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c
index 050d62d..0e49aba 100644
--- a/src/pluto/modecfg.c
+++ b/src/pluto/modecfg.c
@@ -130,16 +130,19 @@ static void get_internal_addr(connection_t *c, host_t *requested_vip,
 	{
 		if (c->spd.that.pool)
 		{
+			identification_t *peer_id = (c->xauth_username && c->xauth_identity
+				&& c->xauth_identity->get_type(c->xauth_identity) == ID_ANY
+				 ? c->xauth_username : c->spd.that.id);
+
 			vip = hydra->attributes->acquire_address(hydra->attributes,
-										c->spd.that.pool, c->spd.that.id,
-										requested_vip);
+													 c->spd.that.pool, peer_id,
+													 requested_vip);
 			if (vip)
 			{
 				chunk_t addr = vip->get_address(vip);
 
 				plog("assigning virtual IP %H to peer", vip);
 				initaddr(addr.ptr, addr.len, vip->get_family(vip), &ia->ipaddr);
-
 			}
 		}
 		else
@@ -1088,7 +1091,7 @@ stf_status xauth_inI0(struct msg_digest *md)
 	if (stat == STF_OK)
 	{
 		/* get user credentials using a plugin function */
-		if (!xauth_module.get_secret(&ia.xauth_secret))
+		if (!xauth_module.get_secret(st->st_connection, &ia.xauth_secret))
 		{
 			plog("xauth user credentials not found");
 			stat = STF_FAIL;
@@ -1212,6 +1215,16 @@ stf_status xauth_inR1(struct msg_digest *md)
 		st->st_xauth.status = xauth_module.verify_secret(&peer, &ia.xauth_secret);
 		plog("extended authentication %s", st->st_xauth.status? "was successful":"failed");
 
+		if (st->st_connection->xauth_username)
+		{
+			st->st_connection->xauth_username->destroy(st->st_connection->xauth_username);
+			st->st_connection->xauth_username = NULL;
+		}
+		if (st->st_xauth.status)
+		{
+			st->st_connection->xauth_username
+				= identification_create_from_data(ia.xauth_secret.user_name);
+		}
 		if (st->st_connection->spd.that.xauth_user)
 		{
 			free(st->st_connection->spd.that.xauth_user);
diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c
index edb96c3..53ed50f 100644
--- a/src/pluto/rcv_whack.c
+++ b/src/pluto/rcv_whack.c
@@ -331,6 +331,7 @@ void whack_handle(int whackctlfd)
 		|| !unpack_str(&msg.sc_data)            /* string 26 */
 		|| !unpack_str(&msg.whack_lease_ip)     /* string 27 */
 		|| !unpack_str(&msg.whack_lease_id)     /* string 28 */
+		|| !unpack_str(&msg.xauth_identity)     /* string 29 */
 		|| str_roof - next_str != (ptrdiff_t)msg.keyval.len)    /* check chunk */
 		{
 			ugh = "message from whack contains bad string";
diff --git a/src/pluto/xauth.c b/src/pluto/xauth.c
index 2086a92..9e388ea 100644
--- a/src/pluto/xauth.c
+++ b/src/pluto/xauth.c
@@ -17,6 +17,7 @@
 
 #include <freeswan.h>
 
+#include "connections.h"
 #include "constants.h"
 #include "defs.h"
 #include "xauth.h"
@@ -34,7 +35,7 @@ xauth_init(void)
 		DBG(DBG_CONTROL,
 			DBG_log("xauth module '%s' loading'", XAUTH_DEFAULT_LIB)
 		)
-		xauth_module.get_secret = (bool (*) (const xauth_t*))
+		xauth_module.get_secret = (bool (*) (const connection_t *, const xauth_t*))
 						dlsym(xauth_module.handle, "get_secret");
 		DBG(DBG_CONTROL,
 			if (xauth_module.get_secret != NULL)
diff --git a/src/pluto/xauth.h b/src/pluto/xauth.h
index 23cae3e..80d74ce 100644
--- a/src/pluto/xauth.h
+++ b/src/pluto/xauth.h
@@ -17,6 +17,7 @@
 #define _XAUTH_H
 
 #include <freeswan.h>
+#include "connections.h"
 #include "defs.h"
 
 /* XAUTH credentials */
@@ -36,8 +37,8 @@ typedef struct {
 
 typedef struct {
 	void *handle;
-	bool (*get_secret) (xauth_t *xauth_secret);
-	bool (*verify_secret) (const xauth_peer_t *peer, const xauth_t *xauth_secret);
+	bool (*get_secret) (const connection_t *c, xauth_t *credentials);
+	bool (*verify_secret) (const xauth_peer_t *peer, const xauth_t *credentials);
 } xauth_module_t;
 
 extern xauth_module_t xauth_module;
diff --git a/src/starter/args.c b/src/starter/args.c
index 792c778..d266393 100644
--- a/src/starter/args.c
+++ b/src/starter/args.c
@@ -237,6 +237,7 @@ static const token_info_t token_info[] =
 	{ ARG_TIME, offsetof(starter_conn_t, inactivity), NULL                         },
 	{ ARG_MISC, 0, NULL  /* KW_MODECONFIG */                                       },
 	{ ARG_MISC, 0, NULL  /* KW_XAUTH */                                            },
+	{ ARG_STR,  offsetof(starter_conn_t, xauth_identity), NULL                     },
 	{ ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool                   },
 	{ ARG_STR,  offsetof(starter_conn_t, me_mediated_by), NULL                     },
 	{ ARG_STR,  offsetof(starter_conn_t, me_peerid), NULL                          },
diff --git a/src/starter/confread.h b/src/starter/confread.h
index 6bee92e..c6e431e 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -110,6 +110,7 @@ struct starter_conn {
 		u_int32_t       eap_type;
 		u_int32_t       eap_vendor;
 		char            *eap_identity;
+		char            *xauth_identity;
 		lset_t          policy;
 		time_t          sa_ike_life_seconds;
 		time_t          sa_ipsec_life_seconds;
diff --git a/src/starter/keywords.h b/src/starter/keywords.h
index 0ada5a9..b104dbd 100644
--- a/src/starter/keywords.h
+++ b/src/starter/keywords.h
@@ -99,6 +99,7 @@ typedef enum {
 	KW_INACTIVITY,
 	KW_MODECONFIG,
 	KW_XAUTH,
+	KW_XAUTH_IDENTITY,
 	KW_MEDIATION,
 	KW_MEDIATED_BY,
 	KW_ME_PEERID,
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
index a054536..568aa66 100644
--- a/src/starter/keywords.txt
+++ b/src/starter/keywords.txt
@@ -90,6 +90,7 @@ dpdaction,         KW_DPDACTION
 inactivity,        KW_INACTIVITY
 modeconfig,        KW_MODECONFIG
 xauth,             KW_XAUTH
+xauth_identity,    KW_XAUTH_IDENTITY
 mediation,         KW_MEDIATION
 mediated_by,       KW_MEDIATED_BY
 me_peerid,         KW_ME_PEERID
diff --git a/src/starter/starterwhack.c b/src/starter/starterwhack.c
index 6014805..cb75b38 100644
--- a/src/starter/starterwhack.c
+++ b/src/starter/starterwhack.c
@@ -93,6 +93,7 @@ static int send_whack_msg (whack_message_t *msg)
 	||  !pack_str(&msg->sc_data,        &str_next, &str_roof)
 	||  !pack_str(&msg->whack_lease_ip, &str_next, &str_roof)
 	||  !pack_str(&msg->whack_lease_id, &str_next, &str_roof)
+	||  !pack_str(&msg->xauth_identity, &str_next, &str_roof)
 	||  (str_roof - str_next < msg->keyval.len))
 	{
 		plog("send_wack_msg(): can't pack strings");
@@ -285,6 +286,7 @@ int starter_whack_add_conn(starter_conn_t *conn)
 	msg.sa_rekey_fuzz         = conn->sa_rekey_fuzz;
 	msg.sa_keying_tries       = conn->sa_keying_tries;
 	msg.policy                = conn->policy;
+	msg.xauth_identity        = conn->xauth_identity;
 
 	/*
 	 * Make sure the IKEv2-only policy bits are unset for IKEv1 connections
diff --git a/src/whack/whack.c b/src/whack/whack.c
index d42c1c4..ca365b3 100644
--- a/src/whack/whack.c
+++ b/src/whack/whack.c
@@ -1838,6 +1838,7 @@ int main(int argc, char **argv)
 	||  !pack_str(&msg.sc_data)          /* string 26 */
 	||  !pack_str(&msg.whack_lease_ip)   /* string 27 */
 	||  !pack_str(&msg.whack_lease_id)   /* string 28 */
+	||  !pack_str(&msg.xauth_identity)   /* string 29 */
 	||  str_roof - next_str < (ptrdiff_t)msg.keyval.len)
 		diag("too many bytes of strings to fit in message to pluto");
 
diff --git a/src/whack/whack.h b/src/whack/whack.h
index 7b95b2d..603bce9 100644
--- a/src/whack/whack.h
+++ b/src/whack/whack.h
@@ -48,7 +48,7 @@ typedef enum {
  */
 
 #define WHACK_BASIC_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 24)
-#define WHACK_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 26)
+#define WHACK_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 29)
 
 typedef struct whack_end whack_end_t;
 
@@ -217,6 +217,9 @@ struct whack_message {
 	int inbase, outbase;
 	char *sc_data;
 
+	/* XAUTH user identity */
+	char *xauth_identity;
+
 	/* space for strings (hope there is enough room):
 	 * Note that pointers don't travel on wire.
 	 *  1 connection name [name_len]
-- 
tg: (1a8157d..) t/xauth_identity_config_option (depends on: t/inbound_sa_install_after_outbound)

-- 
Heiko Hund | Software Engineer | Phone +49-721-25516-237 | Fax -200
Astaro GmbH & Co. KG | An der RaumFabrik 33a | 76227 Karlsruhe | Germany

Astaro GmbH & Co. KG
Commercial Register: Mannheim HRA 702710
Headquarter Location: Karlsruhe
 
Represented by the General Partner Astaro Verwaltungs GmbH
An der RaumFabrik 33a | 76227 Karlsruhe | Germany 
Commercial Register: Mannheim HRB 708248
Executive Board: Gert Hansen, Markus Hennig, Jan Hichert, Günter Junk, Dr. Frank Nellissen





More information about the Dev mailing list