diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2010-05-14 17:07:03 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2010-05-14 17:07:03 +0200 |
commit | 03b5e4d8d79bceb12cdc4b227d10c46bb6721b98 (patch) | |
tree | 9146df2accfbc063e418a2752b90a19e24462c99 /src | |
parent | a27354685451ac84a7decc411f17cfbbbb15d59f (diff) | |
download | strongswan-03b5e4d8d79bceb12cdc4b227d10c46bb6721b98.tar.bz2 strongswan-03b5e4d8d79bceb12cdc4b227d10c46bb6721b98.tar.xz |
refactoring of Mode Config functionality allows transport and handling of any attribute
Diffstat (limited to 'src')
-rw-r--r-- | src/libhydra/attributes/attributes.c | 27 | ||||
-rw-r--r-- | src/libhydra/attributes/attributes.h | 61 | ||||
-rw-r--r-- | src/pluto/connections.c | 37 | ||||
-rw-r--r-- | src/pluto/connections.h | 9 | ||||
-rw-r--r-- | src/pluto/constants.h | 35 | ||||
-rw-r--r-- | src/pluto/ipsec_doi.c | 27 | ||||
-rw-r--r-- | src/pluto/kernel.c | 8 | ||||
-rw-r--r-- | src/pluto/modecfg.c | 1245 | ||||
-rw-r--r-- | src/pluto/modecfg.h | 5 |
9 files changed, 722 insertions, 732 deletions
diff --git a/src/libhydra/attributes/attributes.c b/src/libhydra/attributes/attributes.c index 83feed17e..164fb1690 100644 --- a/src/libhydra/attributes/attributes.c +++ b/src/libhydra/attributes/attributes.c @@ -36,8 +36,31 @@ ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP "MIP6_HOME_PREFIX", "INTERNAL_IP6_LINK", "INTERNAL_IP6_PREFIX"); -ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER, INTERNAL_IP6_PREFIX, +ENUM_NEXT(configuration_attribute_type_names, XAUTH_TYPE, XAUTH_ANSWER, INTERNAL_IP6_PREFIX, + "XAUTH_TYPE", + "XAUTH_USER_NAME", + "XAUTH_USER_PASSWORD", + "XAUTH_PASSCODE", + "XAUTH_MESSAGE", + "XAUTH_CHALLENGE", + "XAUTH_DOMAIN", + "XAUTH_STATUS", + "XAUTH_NEXT_PIN", + "XAUTH_ANSWER"); +ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER, XAUTH_ANSWER, "INTERNAL_IP4_SERVER", "INTERNAL_IP6_SERVER"); -ENUM_END(configuration_attribute_type_names, INTERNAL_IP6_SERVER); +ENUM_NEXT(configuration_attribute_type_names, UNITY_BANNER, UNITY_DDNS_HOSTNAME, INTERNAL_IP6_SERVER, + "UNITY_BANNER", + "UNITY_SAVE_PASSWD", + "UNITY_DEF_DOMAIN", + "UNITY_SPLITDNS_NAME", + "UNITY_SPLIT_INCLUDE", + "UNITY_NATT_PORT", + "UNITY_LOCAL_LAN", + "UNITY_PFS", + "UNITY_FW_TYPE", + "UNITY_BACKUP_SERVERS", + "UNITY_DDNS_HOSTNAME"); +ENUM_END(configuration_attribute_type_names, UNITY_DDNS_HOSTNAME); diff --git a/src/libhydra/attributes/attributes.h b/src/libhydra/attributes/attributes.h index f4a396f21..b4693702a 100644 --- a/src/libhydra/attributes/attributes.h +++ b/src/libhydra/attributes/attributes.h @@ -30,27 +30,50 @@ typedef enum configuration_attribute_type_t configuration_attribute_type_t; * Type of the attribute, as in IKEv2 RFC 3.15.1 or IKEv1 ModeConfig. */ enum configuration_attribute_type_t { - INTERNAL_IP4_ADDRESS = 1, - INTERNAL_IP4_NETMASK = 2, - INTERNAL_IP4_DNS = 3, - INTERNAL_IP4_NBNS = 4, + INTERNAL_IP4_ADDRESS = 1, + INTERNAL_IP4_NETMASK = 2, + INTERNAL_IP4_DNS = 3, + INTERNAL_IP4_NBNS = 4, INTERNAL_ADDRESS_EXPIRY = 5, - INTERNAL_IP4_DHCP = 6, - APPLICATION_VERSION = 7, - INTERNAL_IP6_ADDRESS = 8, - INTERNAL_IP6_NETMASK = 9, - INTERNAL_IP6_DNS = 10, - INTERNAL_IP6_NBNS = 11, - INTERNAL_IP6_DHCP = 12, - INTERNAL_IP4_SUBNET = 13, - SUPPORTED_ATTRIBUTES = 14, - INTERNAL_IP6_SUBNET = 15, - MIP6_HOME_PREFIX = 16, - INTERNAL_IP6_LINK = 17, - INTERNAL_IP6_PREFIX = 18, + INTERNAL_IP4_DHCP = 6, + APPLICATION_VERSION = 7, + INTERNAL_IP6_ADDRESS = 8, + INTERNAL_IP6_NETMASK = 9, + INTERNAL_IP6_DNS = 10, + INTERNAL_IP6_NBNS = 11, + INTERNAL_IP6_DHCP = 12, + INTERNAL_IP4_SUBNET = 13, + SUPPORTED_ATTRIBUTES = 14, + INTERNAL_IP6_SUBNET = 15, + MIP6_HOME_PREFIX = 16, + INTERNAL_IP6_LINK = 17, + INTERNAL_IP6_PREFIX = 18, + /* XAUTH attributes */ + XAUTH_TYPE = 16520, + XAUTH_USER_NAME = 16521, + XAUTH_USER_PASSWORD = 16522, + XAUTH_PASSCODE = 16523, + XAUTH_MESSAGE = 16524, + XAUTH_CHALLENGE = 16525, + XAUTH_DOMAIN = 16526, + XAUTH_STATUS = 16527, + XAUTH_NEXT_PIN = 16528, + XAUTH_ANSWER = 16529, /* proprietary Microsoft attributes */ - INTERNAL_IP4_SERVER = 23456, - INTERNAL_IP6_SERVER = 23457 + INTERNAL_IP4_SERVER = 23456, + INTERNAL_IP6_SERVER = 23457, + /* proprietary Cisco Unity attributes */ + UNITY_BANNER = 28672, + UNITY_SAVE_PASSWD = 28673, + UNITY_DEF_DOMAIN = 28674, + UNITY_SPLITDNS_NAME = 28675, + UNITY_SPLIT_INCLUDE = 28676, + UNITY_NATT_PORT = 28677, + UNITY_LOCAL_LAN = 28678, + UNITY_PFS = 28679, + UNITY_FW_TYPE = 28680, + UNITY_BACKUP_SERVERS = 28681, + UNITY_DDNS_HOSTNAME = 28682 }; /** diff --git a/src/pluto/connections.c b/src/pluto/connections.c index d6c38514d..a8d297ebf 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -369,14 +369,10 @@ void delete_connection(connection_t *c, bool relations) /* release virtual IP address lease if any */ if (c->spd.that.modecfg && c->spd.that.pool && - !isanyaddr(&c->spd.that.host_srcip)) + !c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) { - host_t *vip; - - vip = host_create_from_sockaddr((sockaddr_t*)&c->spd.that.host_srcip); hydra->attributes->release_address(hydra->attributes, c->spd.that.pool, - vip, c->spd.that.id); - vip->destroy(vip); + c->spd.that.host_srcip, c->spd.that.id); } /* release requested attributes if any */ @@ -411,11 +407,14 @@ void delete_connection(connection_t *c, bool relations) DESTROY_IF(c->spd.this.id); DESTROY_IF(c->spd.this.ca); DESTROY_IF(c->spd.this.groups); + DESTROY_IF(c->spd.this.host_srcip); + free(c->spd.this.updown); free(c->spd.this.pool); DESTROY_IF(c->spd.that.id); DESTROY_IF(c->spd.that.ca); DESTROY_IF(c->spd.that.groups); + DESTROY_IF(c->spd.that.host_srcip); free(c->spd.that.updown); free(c->spd.that.pool); if (c->requested_ca) @@ -678,7 +677,7 @@ size_t format_end(char *buf, size_t buf_len, const struct end *this, subnettot(&this->client, 0, client, sizeof(client)); } } - else if (this->modecfg && isanyaddr(&this->host_srcip)) + else if (this->modecfg && this->host_srcip->is_anyaddr(this->host_srcip)) { /* we are mode config client, or a server with a pool */ client_sep = "==="; @@ -763,6 +762,7 @@ static void unshare_connection_strings(connection_t *c) 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); + c->spd.this.host_srcip = c->spd.this.host_srcip->clone(c->spd.this.host_srcip); scx_share(c->spd.this.sc); cert_share(c->spd.this.cert); if (c->spd.this.ca) @@ -776,6 +776,7 @@ static void unshare_connection_strings(connection_t *c) c->spd.that.id = c->spd.that.id->clone(c->spd.that.id); c->spd.that.pool = clone_str(c->spd.that.pool); c->spd.that.updown = clone_str(c->spd.that.updown); + c->spd.that.host_srcip = c->spd.that.host_srcip->clone(c->spd.that.host_srcip); scx_share(c->spd.that.sc); cert_share(c->spd.that.cert); if (c->spd.that.ca) @@ -924,7 +925,7 @@ static bool extract_end(struct end *dst, const whack_end_t *src, /* the rest is simple copying of corresponding fields */ dst->host_addr = src->host_addr; dst->host_nexthop = src->host_nexthop; - dst->host_srcip = src->host_srcip; + dst->host_srcip = host_create_from_sockaddr((sockaddr_t*)&src->host_srcip); dst->has_natip = src->has_natip; dst->client = src->client; dst->protocol = src->protocol; @@ -949,10 +950,14 @@ static bool extract_end(struct end *dst, const whack_end_t *src, /* if host sourceip is defined but no client is present * behind the host then set client to sourceip/32 */ - if (addrbytesptr(&dst->host_srcip, NULL) && - !isanyaddr(&dst->host_srcip) && !dst->has_natip && !dst->has_client) + if (!dst->host_srcip->is_anyaddr(dst->host_srcip) && + !dst->has_natip && !dst->has_client) { - err_t ugh = addrtosubnet(&dst->host_srcip, &dst->client); + ip_address addr; + err_t ugh; + + addr = *(ip_address*)dst->host_srcip->get_sockaddr(dst->host_srcip); + ugh = addrtosubnet(&addr, &dst->client); if (ugh) { @@ -1233,7 +1238,8 @@ void add_connection(const whack_message_t *wm) c->spd.that.modecfg = TRUE; c->spd.that.has_client = FALSE; /* reset the host_srcip so that it gets assigned in modecfg */ - anyaddr(AF_INET, &c->spd.that.host_srcip); + DESTROY_IF(c->spd.that.host_srcip); + c->spd.that.host_srcip = host_create_any(AF_INET); } if (c->ikev1) @@ -3068,7 +3074,8 @@ void ISAKMP_SA_established(connection_t *c, so_serial_t serial) /* the connection is now oriented so that we are able to determine * whether we are a mode config server with a virtual IP to send. */ - if (!isanyaddr(&c->spd.that.host_srcip) && !c->spd.that.has_natip) + if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip) && + !c->spd.that.has_natip) { c->spd.that.modecfg = TRUE; } @@ -3715,8 +3722,10 @@ static connection_t *fc_try(const connection_t *c, struct host_pair *hp, } else { + host_t *vip = c->spd.that.host_srcip; + if (!peer_net_is_host && !(sr->that.modecfg && c->spd.that.modecfg && - subnetisaddr(peer_net, &c->spd.that.host_srcip))) + subnetisaddr(peer_net, (ip_address*)vip->get_sockaddr(vip)))) { continue; } diff --git a/src/pluto/connections.h b/src/pluto/connections.h index ae6356db1..1aa3b5757 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -1,6 +1,6 @@ /* information about connections between hosts and clients * Copyright (C) 1998-2001 D. Hugh Redelmeier - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil + * Copyright (C) 2009-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil * * 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 @@ -18,6 +18,7 @@ #include <sys/queue.h> +#include <utils/host.h> #include <utils/linked_list.h> #include <utils/identification.h> #include <credentials/ietf_attributes/ietf_attributes.h> @@ -131,10 +132,8 @@ struct virtual_t; struct end { identification_t *id; - ip_address - host_addr, - host_nexthop, - host_srcip; + ip_address host_addr, host_nexthop; + host_t *host_srcip; ip_subnet client; bool is_left; diff --git a/src/pluto/constants.h b/src/pluto/constants.h index 9c87926d0..790bbefa6 100644 --- a/src/pluto/constants.h +++ b/src/pluto/constants.h @@ -543,41 +543,6 @@ extern enum_names attr_msg_type_names; extern enum_names modecfg_attr_names; -/* XAUTH attribute values */ -#define XAUTH_TYPE 16520 -#define XAUTH_USER_NAME 16521 -#define XAUTH_USER_PASSWORD 16522 -#define XAUTH_PASSCODE 16523 -#define XAUTH_MESSAGE 16524 -#define XAUTH_CHALLENGE 16525 -#define XAUTH_DOMAIN 16526 -#define XAUTH_STATUS 16527 -#define XAUTH_NEXT_PIN 16528 -#define XAUTH_ANSWER 16529 - -#define XAUTH_BASE XAUTH_TYPE - -extern enum_names xauth_attr_names; - -extern enum_names microsoft_attr_names; - -/* ISAKMP mode config attributes specific to the Unity vendor ID */ -#define UNITY_BANNER 28672 -#define UNITY_SAVE_PASSWD 28673 -#define UNITY_DEF_DOMAIN 28674 -#define UNITY_SPLITDNS_NAME 28675 -#define UNITY_SPLIT_INCLUDE 28676 -#define UNITY_NATT_PORT 28677 -#define UNITY_LOCAL_LAN 28678 -#define UNITY_PFS 28679 -#define UNITY_FW_TYPE 28680 -#define UNITY_BACKUP_SERVERS 28681 -#define UNITY_DDNS_HOSTNAME 28682 - -#define UNITY_BASE UNITY_BANNER - -extern enum_names unity_attr_names; - /* XAUTH authentication types */ #define XAUTH_TYPE_GENERIC 0 #define XAUTH_TYPE_CHAP 1 diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index 34c42e294..e506d71bc 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -702,7 +702,7 @@ void accept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p) { struct isakmp_delete *d = &(p->payload.delete); - identification_t *this_id, *that_id; + identification_t *this_id = NULL, *that_id = NULL; ip_address peer_addr; size_t sizespi; int i; @@ -1949,19 +1949,18 @@ stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, u_int8_t np = ISAKMP_NEXT_NONE; if (c->spd.this.modecfg && !c->spd.this.has_client && - isanyaddr(&c->spd.this.host_srcip)) + c->spd.this.host_srcip->is_anyaddr(c->spd.this.host_srcip)) { connection_t *ph1_c = isakmp_sa->st_connection; + host_t * ph1_srcip = ph1_c->spd.this.host_srcip; - if (ph1_c->spd.this.modecfg && !isanyaddr(&ph1_c->spd.this.host_srcip)) + if (ph1_c->spd.this.modecfg && !ph1_srcip->is_anyaddr(ph1_srcip)) { - char srcip[ADDRTOT_BUF]; - - c->spd.this.host_srcip = ph1_c->spd.this.host_srcip; + c->spd.this.host_srcip->destroy(c->spd.this.host_srcip); + c->spd.this.host_srcip = ph1_srcip->clone(ph1_srcip); c->spd.this.client = ph1_c->spd.this.client; c->spd.this.has_client = TRUE; - addrtot(&c->spd.this.host_srcip, 0, srcip, sizeof(srcip)); - plog("inheriting virtual IP source address %s from ModeCfg", srcip); + plog("inheriting virtual IP source address %H from ModeCfg", ph1_srcip); } } @@ -4888,20 +4887,20 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, /* Plain Road Warrior: * instantiate, carrying over authenticated peer ID */ + host_t *vip = c->spd.that.host_srcip; + p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port , his_net, c->spd.that.id); /* inherit any virtual IP assigned by a Mode Config exchange */ if (p->spd.that.modecfg && c->spd.that.modecfg && - subnetisaddr(his_net, &c->spd.that.host_srcip)) + subnetisaddr(his_net, (ip_address*)vip->get_sockaddr(vip))) { - char srcip[ADDRTOT_BUF]; - DBG(DBG_CONTROL, - addrtot(&c->spd.that.host_srcip, 0, srcip, sizeof(srcip)); - DBG_log("inheriting virtual IP source address %s from ModeCfg", srcip) + DBG_log("inheriting virtual IP source address %H from ModeCfg", vip) ) - p->spd.that.host_srcip = c->spd.that.host_srcip; + p->spd.that.host_srcip->destroy(p->spd.that.host_srcip); + p->spd.that.host_srcip = vip->clone(vip); p->spd.that.client = c->spd.that.client; p->spd.that.has_client = TRUE; } diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c index ee22fb55e..79ba3aa57 100644 --- a/src/pluto/kernel.c +++ b/src/pluto/kernel.c @@ -483,16 +483,14 @@ static bool do_command(connection_t *c, struct spd_route *sr, strncat(nexthop_str, "' ", sizeof(nexthop_str)); } - if (addrbytesptr(&sr->this.host_srcip, NULL) - && !isanyaddr(&sr->this.host_srcip)) + if (!sr->this.host_srcip->is_anyaddr(sr->this.host_srcip)) { char *n; strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); n = srcip_str + strlen(srcip_str); - - addrtot(&sr->this.host_srcip, 0 - ,n , sizeof(srcip_str)-strlen(srcip_str)); + snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", + sr->this.host_srcip); strncat(srcip_str, "' ", sizeof(srcip_str)); } diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c index 1f2711f33..2ca771d17 100644 --- a/src/pluto/modecfg.c +++ b/src/pluto/modecfg.c @@ -2,7 +2,7 @@ * Copyright (C) 2001-2002 Colubris Networks * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc. * Copyright (C) 2003-2004 Xelerance Corporation - * Copyright (C) 2006-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil + * Copyright (C) 2006-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil * * 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 @@ -44,19 +44,7 @@ #define MAX_XAUTH_TRIES 3 -#define SUPPORTED_ATTR_SET ( LELEM(INTERNAL_IP4_ADDRESS) \ - | LELEM(INTERNAL_IP4_NETMASK) \ - | LELEM(INTERNAL_IP4_DNS) \ - | LELEM(INTERNAL_IP4_NBNS) \ - | LELEM(APPLICATION_VERSION) \ - | LELEM(INTERNAL_IP6_DNS) \ - | LELEM(INTERNAL_IP6_NBNS) \ - ) - -#define SUPPORTED_UNITY_ATTR_SET ( LELEM(UNITY_BANNER - UNITY_BASE) ) - -#define UNITY_BANNER_STR "Welcome to strongSwan - the Linux VPN Solution!\n" - +#define DEFAULT_UNITY_BANNER "Welcome to strongSwan - the Linux VPN Solution!\n" /** * Creates a modecfg_attribute_t object @@ -68,6 +56,7 @@ static modecfg_attribute_t *modecfg_attribute_create(configuration_attribute_typ this = malloc_thing(modecfg_attribute_t); this->type = ((u_int16_t)type) & 0x7FFF; + this->is_tv = FALSE; this->value = chunk_clone(value); this->handler = NULL; @@ -75,66 +64,85 @@ static modecfg_attribute_t *modecfg_attribute_create(configuration_attribute_typ } /** - * Destroys a modecfg_attribute_t object + * Creates a modecfg_attribute_t object coded in TV format */ -void modecfg_attribute_destroy(modecfg_attribute_t *this) +static modecfg_attribute_t *modecfg_attribute_create_tv(configuration_attribute_type_t type, + size_t value) { - free(this->value.ptr); - free(this); -} - -/* - * Addresses assigned (usually via ModeCfg) to the Initiator - */ -typedef struct internal_addr internal_addr_t; - -struct internal_addr -{ - lset_t attr_set; - lset_t xauth_attr_set; - lset_t unity_attr_set; - - /* ModeCfg variables */ - ip_address ipaddr; + modecfg_attribute_t *this; - char *unity_banner; + this = modecfg_attribute_create(type, chunk_empty); + this->value.len = value; + this->is_tv = TRUE; - /* XAUTH variables */ - u_int16_t xauth_type; - xauth_t xauth_secret; - bool xauth_status; -}; + return this; +} /** - * Initialize an internal_addr struct + * Destroys a modecfg_attribute_t object */ -static void init_internal_addr(internal_addr_t *ia) +void modecfg_attribute_destroy(modecfg_attribute_t *this) { - ia->attr_set = LEMPTY; - ia->xauth_attr_set = LEMPTY; - ia->xauth_secret.user_name = chunk_empty; - ia->xauth_secret.user_password = chunk_empty; - ia->xauth_type = XAUTH_TYPE_GENERIC; - ia->xauth_status = XAUTH_STATUS_FAIL; - ia->unity_attr_set = LEMPTY; - ia->unity_banner = NULL; - - anyaddr(AF_INET, &ia->ipaddr); + free(this->value.ptr); + free(this); } /** - * Get internal IP address for a connection + * Get attributes to be sent to client */ -static void get_internal_addr(connection_t *c, host_t *requested_vip, - internal_addr_t *ia, linked_list_t *ca_list) +static void get_attributes(connection_t *c, linked_list_t *ca_list) { - enumerator_t *enumerator; configuration_attribute_type_t type; - chunk_t value; modecfg_attribute_t *ca; - host_t *vip = NULL; + enumerator_t *enumerator; + chunk_t value; + host_t *vip = NULL, *requested_vip = NULL; + bool want_unity_banner = FALSE; + int family; + +#ifdef CISCO_QUIRKS + /* always send banner in ModeCfg push mode */ + if (ca_list->get_count(ca_list) == 0) + { + want_unity_banner = TRUE; + } +#endif + + /* scan list of requested attributes in ModeCfg pull mode */ + while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) + { + switch (ca->type) + { + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP6_ADDRESS: + { + int family; + + family = (ca->type == INTERNAL_IP4_ADDRESS) ? AF_INET : AF_INET6; + requested_vip = (ca->value.len) ? + host_create_from_chunk(family, ca->value, 0) : + host_create_any(family); + plog("peer requested virtual IP %H", requested_vip); + break; + } +#ifdef CISCO_QUIRKS + case UNITY_BANNER: + want_unity_banner = TRUE; + break; +#endif + default: + break; + } + modecfg_attribute_destroy(ca); + } - if (isanyaddr(&c->spd.that.host_srcip)) + if (requested_vip == NULL) + { + requested_vip = host_create_any(AF_INET); + } + + /* if no virtual IP has been assigned yet - acquire one */ + if (c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) { if (c->spd.that.pool) { @@ -143,11 +151,8 @@ static void get_internal_addr(connection_t *c, host_t *requested_vip, 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); - + c->spd.that.host_srcip->destroy(c->spd.that.host_srcip); + c->spd.that.host_srcip = vip; } } else @@ -155,22 +160,25 @@ static void get_internal_addr(connection_t *c, host_t *requested_vip, plog("no virtual IP found"); } } - else + + requested_vip->destroy(requested_vip); + + /* if we have a virtual IP address - send it */ + if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) { - ia->ipaddr = c->spd.that.host_srcip; - vip = host_create_from_sockaddr((sockaddr_t*)&ia->ipaddr); + vip = c->spd.that.host_srcip; plog("assigning virtual IP %H to peer", vip); - } + family = vip->get_family(vip); + ca = modecfg_attribute_create((family == AF_INET) ? + INTERNAL_IP4_ADDRESS : + INTERNAL_IP6_ADDRESS, + vip->get_address(vip)); + ca_list->insert_last(ca_list, ca); - if (!isanyaddr(&ia->ipaddr)) /* We got an IP address, send it */ - { - c->spd.that.host_srcip = ia->ipaddr; - c->spd.that.client.addr = ia->ipaddr; - c->spd.that.client.maskbits = 32; + /* set the remote client subnet to virtual IP */ + c->spd.that.client.addr = *(ip_address*)vip->get_sockaddr(vip); + c->spd.that.client.maskbits = (family == AF_INET) ? 32 : 128; c->spd.that.has_client = TRUE; - - ia->attr_set = LELEM(INTERNAL_IP4_ADDRESS) - | LELEM(INTERNAL_IP4_NETMASK); } /* assign attributes from registered providers */ @@ -178,103 +186,158 @@ static void get_internal_addr(connection_t *c, host_t *requested_vip, c->spd.that.id, vip); while (enumerator->enumerate(enumerator, &type, &value)) { - DBG(DBG_CONTROLMORE, - DBG_log("building %N attribute", - configuration_attribute_type_names, type) - ) ca = modecfg_attribute_create(type, value); ca_list->insert_last(ca_list, ca); + if (type == UNITY_BANNER) + { + want_unity_banner = FALSE; + } } enumerator->destroy(enumerator); - DESTROY_IF(vip); -} + if (want_unity_banner) + { + ca = modecfg_attribute_create(UNITY_BANNER, + chunk_create(DEFAULT_UNITY_BANNER, + strlen(DEFAULT_UNITY_BANNER))); + ca_list->insert_last(ca_list, ca); + } +} /** * Set srcip and client subnet to internal IP address */ -static bool set_internal_addr(connection_t *c, internal_addr_t *ia, - linked_list_t *ca_list) +static bool set_attributes(connection_t *c, linked_list_t *ca_list) { - if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS) - && !isanyaddr(&ia->ipaddr)) + host_t *vip, *srcip; + modecfg_attribute_t *ca, *ca_handler; + enumerator_t *enumerator; + bool vip_set = FALSE; + + enumerator = ca_list->create_enumerator(ca_list); + while (enumerator->enumerate(enumerator, &ca)) { - host_t *vip; - modecfg_attribute_t *ca; - enumerator_t *enumerator; + int family = AF_INET6; + attribute_handler_t *handler = NULL; + enumerator_t *e; - if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0 - || isanyaddr(&c->spd.this.host_srcip) - || sameaddr(&c->spd.this.host_srcip, &ia->ipaddr)) + switch (ca->type) { - char srcip[ADDRTOT_BUF]; + case INTERNAL_IP4_ADDRESS: + family = AF_INET; + /* fall */ + case INTERNAL_IP6_ADDRESS: + if (ca->value.len == 0) + { + vip = host_create_any(family); + } + else + { + /* skip prefix byte in IPv6 payload*/ + if (family == AF_INET6) + { + ca->value.len = 16; + } + vip = host_create_from_chunk(family, ca->value, 0); + } + if (vip) + { + srcip = c->spd.this.host_srcip; - addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip)); - plog("setting virtual IP source address to %s", srcip); + if (srcip->is_anyaddr(srcip) || srcip->equals(srcip, vip)) + { + plog("setting virtual IP source address to %H", vip); + } + else + { + plog("replacing virtual IP source address %H by %H", + srcip, vip); + } + srcip->destroy(srcip); + c->spd.this.host_srcip = vip; + + /* setting client subnet to vip/32 */ + addrtosubnet((ip_address*)vip->get_sockaddr(vip), + &c->spd.this.client); + setportof(0, &c->spd.this.client.addr); + c->spd.this.has_client = TRUE; + + vip_set = TRUE; + } + continue; + case APPLICATION_VERSION: +#ifdef CISCO_QUIRKS + case UNITY_BANNER: +#endif + if (ca->value.len > 0) + { + DBG(DBG_PARSING | DBG_CONTROLMORE, + DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) + ) + } + break; + default: + break; } - else - { - char old_srcip[ADDRTOT_BUF]; - char new_srcip[ADDRTOT_BUF]; - addrtot(&c->spd.this.host_srcip, 0, old_srcip, sizeof(old_srcip)); - addrtot(&ia->ipaddr, 0, new_srcip, sizeof(new_srcip)); - plog("replacing virtual IP source address %s by %s" - , old_srcip, new_srcip); + /* find the first handler which requested this attribute */ + e = c->requested->create_enumerator(c->requested); + while (e->enumerate(e, &ca_handler)) + { + if (ca_handler->type == ca->type) + { + handler = ca_handler->handler; + break; + } } + e->destroy(e); - /* setting srcip */ - c->spd.this.host_srcip = ia->ipaddr; - vip = host_create_from_sockaddr((sockaddr_t*)&ia->ipaddr); - - /* setting client subnet to srcip/32 */ - addrtosubnet(&ia->ipaddr, &c->spd.this.client); - setportof(0, &c->spd.this.client.addr); - c->spd.this.has_client = TRUE; - - /* setting other attributes (e.g. DNS and NBNS servers) */ - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) + /* and pass it to the handle function */ + handler = hydra->attributes->handle(hydra->attributes, + c->spd.that.id, handler, ca->type, ca->value); + if (handler) { - modecfg_attribute_t *ca_handler; - attribute_handler_t *handler = NULL; - enumerator_t *e; + ca_handler = modecfg_attribute_create(ca->type, ca->value); + ca_handler->handler = handler; - /* find the first handler which requested this attribute */ - e = c->requested->create_enumerator(c->requested); - while (e->enumerate(e, &ca_handler)) + if (c->attributes == NULL) { - if (ca_handler->type == ca->type) - { - handler = ca_handler->handler; - break; - } + c->attributes = linked_list_create(); } - e->destroy(e); + c->attributes->insert_last(c->attributes, ca_handler); + } + } + enumerator->destroy(enumerator); + c->requested->destroy_function(c->requested, (void*)modecfg_attribute_destroy); + c->requested = NULL; + return vip_set; +} - /* and pass it to the handle function */ - handler = hydra->attributes->handle(hydra->attributes, - c->spd.that.id, handler, ca->type, ca->value); - if (handler) - { - ca_handler = modecfg_attribute_create(ca->type, ca->value); - ca_handler->handler = handler; +/** + * Register configuration attribute handlers + */ +static void register_attribute_handlers(connection_t *c) +{ + configuration_attribute_type_t type; + modecfg_attribute_t *ca; + chunk_t value; + attribute_handler_t *handler; + enumerator_t *enumerator; - if (c->attributes == NULL) - { - c->attributes = linked_list_create(); - } - c->attributes->insert_last(c->attributes, ca_handler); - } - } - enumerator->destroy(enumerator); - vip->destroy(vip); - c->requested->destroy_function(c->requested, - (void*)modecfg_attribute_destroy); - c->requested = NULL; - return TRUE; + /* add configuration attributes requested by handlers */ + if (c->requested == NULL) + { + c->requested = linked_list_create(); + } + enumerator = hydra->attributes->create_initiator_enumerator( + hydra->attributes,c->spd.that.id, c->spd.this.host_srcip); + while (enumerator->enumerate(enumerator, &handler, &type, &value)) + { + ca = modecfg_attribute_create(type, value); + ca->handler = handler; + c->requested->insert_last(c->requested, ca); } - return FALSE; + enumerator->destroy(enumerator); } /** @@ -309,188 +372,53 @@ static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS) */ static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody, - u_int16_t msg_type, - internal_addr_t *ia, - linked_list_t *ca_list, + u_int16_t msg_type, linked_list_t *ca_list, u_int16_t ap_id) { u_char *r_hash_start, *r_hashval; + struct isakmp_mode_attr attrh; + struct isakmp_attribute attr; + pb_stream strattr,attrval; + enumerator_t *enumerator; + modecfg_attribute_t *ca; START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR); - /* ATTR out */ + attrh.isama_np = ISAKMP_NEXT_NONE; + attrh.isama_type = msg_type; + attrh.isama_identifier = ap_id; + + if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr)) { - struct isakmp_mode_attr attrh; - struct isakmp_attribute attr; - pb_stream strattr,attrval; - int attr_type; - bool is_xauth_attr_set = ia->xauth_attr_set != LEMPTY; - bool is_unity_attr_set = ia->unity_attr_set != LEMPTY; - lset_t attr_set = ia->attr_set; - enumerator_t *enumerator; - modecfg_attribute_t *ca; - - attrh.isama_np = ISAKMP_NEXT_NONE; - attrh.isama_type = msg_type; - attrh.isama_identifier = ap_id; - - if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr)) - { - return STF_INTERNAL_ERROR; - } - attr_type = 0; + return STF_INTERNAL_ERROR; + } - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) + enumerator = ca_list->create_enumerator(ca_list); + while (enumerator->enumerate(enumerator, &ca)) + { + DBG(DBG_CONTROLMORE, + DBG_log("building %N attribute", configuration_attribute_type_names, ca->type) + ) + if (ca->is_tv) { - char ca_type_name[BUF_LEN]; - - snprintf(ca_type_name, BUF_LEN, "%N", - configuration_attribute_type_names, ca->type); - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TLV; + attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TV; + attr.isaat_lv = ca->value.len; out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - out_raw(ca->value.ptr, ca->value.len, &attrval, ca_type_name); - close_output_pbs(&attrval); } - enumerator->destroy(enumerator); - - while (attr_set != LEMPTY || is_xauth_attr_set || is_unity_attr_set) + else { - if (attr_set == LEMPTY) - { - if (is_xauth_attr_set) - { - attr_set = ia->xauth_attr_set; - attr_type = XAUTH_BASE; - is_xauth_attr_set = FALSE; - } - else - { - attr_set = ia->unity_attr_set; - attr_type = UNITY_BASE; - is_unity_attr_set = FALSE; - } - } - - if (attr_set & 1) - { - const u_char *byte_ptr; - u_int len; - - /* ISAKMP attr out */ - if (attr_type == XAUTH_TYPE) - { - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ia->xauth_type; - } - else if (attr_type == XAUTH_STATUS) - { - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ia->xauth_status; - } - else - { - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV; - } - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); + char buf[BUF_LEN]; - switch (attr_type) - { - case INTERNAL_IP4_ADDRESS: - if (!isanyaddr(&ia->ipaddr)) - { - len = addrbytesptr(&ia->ipaddr, &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_addr"); - } - break; - case INTERNAL_IP4_NETMASK: - { - u_int mask; -#if 0 - char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; - int t,m=st->st_connection->that.host_addr.maskbit; - for (t=0; t<4; t++) - { - if (m < 8) - mask[t] = bits[m]; - else - mask[t] = 0xff; - m -= 8; - } -#endif - if (st->st_connection->spd.this.client.maskbits == 0) - { - mask = 0; - } - else - { - mask = 0xffffffff * 1; - out_raw(&mask, 4, &attrval, "IP4_mask"); - } - } - break; - case INTERNAL_IP4_SUBNET: - { - char mask[4]; - char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; - int t; - int m = st->st_connection->spd.this.client.maskbits; - - for (t = 0; t < 4; t++) - { - mask[t] = (m < 8) ? bits[m] : 0xff; - m -= 8; - if (m < 0) - { - m = 0; - } - } - len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_subnet"); - out_raw(mask, sizeof(mask), &attrval, "IP4_submsk"); - } - break; - case XAUTH_TYPE: - break; - case XAUTH_USER_NAME: - if (ia->xauth_secret.user_name.ptr != NULL) - { - out_raw(ia->xauth_secret.user_name.ptr - , ia->xauth_secret.user_name.len - , &attrval, "xauth_user_name"); - } - break; - case XAUTH_USER_PASSWORD: - if (ia->xauth_secret.user_password.ptr != NULL) - { - out_raw(ia->xauth_secret.user_password.ptr - , ia->xauth_secret.user_password.len - , &attrval, "xauth_user_password"); - } - break; - case XAUTH_STATUS: - break; - case UNITY_BANNER: - if (ia->unity_banner != NULL) - { - out_raw(ia->unity_banner - , strlen(ia->unity_banner) - , &attrval, "UNITY_BANNER"); - } - break; - default: - plog("attempt to send unsupported mode cfg attribute %s." - , enum_show(&modecfg_attr_names, attr_type)); - break; - } - close_output_pbs(&attrval); - } - attr_type++; - attr_set >>= 1; + attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TLV; + out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); + snprintf(buf, BUF_LEN, "%N", configuration_attribute_type_names, ca->type); + out_raw(ca->value.ptr, ca->value.len, &attrval, buf); } - close_message(&strattr); + close_output_pbs(&attrval); } - + enumerator->destroy(enumerator); + close_message(&strattr); + modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); close_message(rbody); encrypt_message(rbody, st); @@ -501,7 +429,7 @@ static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody, * Send ModeCfg message */ static stf_status modecfg_send_msg(struct state *st, int isama_type, - internal_addr_t *ia, linked_list_t *ca_list) + linked_list_t *ca_list) { pb_stream msg; pb_stream rbody; @@ -534,7 +462,7 @@ static stf_status modecfg_send_msg(struct state *st, int isama_type, } /* ATTR out with isama_id of 0 */ - modecfg_build_msg(st, &rbody, isama_type, ia, ca_list, 0); + modecfg_build_msg(st, &rbody, isama_type, ca_list, 0); free(st->st_tpacket.ptr); st->st_tpacket = chunk_create(msg.start, pbs_offset(&msg)); @@ -554,20 +482,17 @@ static stf_status modecfg_send_msg(struct state *st, int isama_type, /** * Parse a ModeCfg attribute payload */ -static stf_status modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia, - linked_list_t *ca_list) +static stf_status modecfg_parse_attributes(pb_stream *attrs, linked_list_t *ca_list) { struct isakmp_attribute attr; pb_stream strattr; - err_t ugh; + u_int16_t attr_type; + u_int16_t attr_len; + chunk_t attr_chunk; + modecfg_attribute_t *ca; while (pbs_left(attrs) >= sizeof(struct isakmp_attribute)) { - u_int16_t attr_type; - u_int16_t attr_len; - chunk_t attr_chunk; - modecfg_attribute_t *ca; - if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr)) { return STF_FAIL; @@ -581,149 +506,139 @@ static stf_status modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia switch (attr_type) { - case INTERNAL_IP4_ADDRESS: - if (attr_len == 4) - { - ugh = initaddr((char *)(strattr.cur), 4, AF_INET, &ia->ipaddr); - if (ugh != NULL) + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case INTERNAL_ADDRESS_EXPIRY: + case INTERNAL_IP4_DHCP: + if (attr_len != 4 && attr_len != 0) { - plog("received invalid virtual IPv4 address: %s", ugh); + goto error; } - } - ia->attr_set |= LELEM(attr_type); - break; - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - if (attr_len == 4) - { - attr_chunk = chunk_create(strattr.cur, attr_len); - ca = modecfg_attribute_create(attr_type, attr_chunk); - ca_list->insert_last(ca_list, ca); - } - break; - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - if (attr_len == 16) - { - attr_chunk = chunk_create(strattr.cur, attr_len); - ca = modecfg_attribute_create(attr_type, attr_chunk); - ca_list->insert_last(ca_list, ca); - } - break; - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_SUBNET: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_NETMASK: - case INTERNAL_IP6_DHCP: - case SUPPORTED_ATTRIBUTES: - case INTERNAL_IP6_SUBNET: - ia->attr_set |= LELEM(attr_type); - break; - case APPLICATION_VERSION: - if (attr_len > 0) - { - DBG(DBG_PARSING, - DBG_log(" '%.*s'", attr_len, strattr.cur) - ) - } - ia->attr_set |= LELEM(attr_type); - break; - case XAUTH_TYPE: - ia->xauth_type = attr.isaat_lv; - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_USER_NAME: - ia->xauth_secret.user_name = chunk_create(strattr.cur, attr_len); - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_USER_PASSWORD: - ia->xauth_secret.user_password = chunk_create(strattr.cur, attr_len); - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_STATUS: - ia->xauth_status = attr.isaat_lv; - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_MESSAGE: - if (attr_len > 0) - { - DBG(DBG_PARSING, - DBG_log(" '%.*s'", attr_len, strattr.cur) - ) - } - /* fall through to set attribute flag */ - case XAUTH_PASSCODE: - case XAUTH_CHALLENGE: - case XAUTH_DOMAIN: - case XAUTH_NEXT_PIN: - case XAUTH_ANSWER: - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case UNITY_DDNS_HOSTNAME: - if (attr_len > 0) - { - DBG(DBG_PARSING, - DBG_log(" '%.*s'", attr_len, strattr.cur) - ) - } - /* fall through to set attribute flag */ - case UNITY_BANNER: - case UNITY_SAVE_PASSWD: - case UNITY_DEF_DOMAIN: - case UNITY_SPLITDNS_NAME: - case UNITY_SPLIT_INCLUDE: - case UNITY_NATT_PORT: - case UNITY_LOCAL_LAN: - case UNITY_PFS: - case UNITY_FW_TYPE: - case UNITY_BACKUP_SERVERS: - ia->unity_attr_set |= LELEM(attr_type - UNITY_BASE); - break; - default: - plog("unsupported ModeCfg attribute %s received." - , enum_show(&modecfg_attr_names, attr_type)); - break; + break; + case INTERNAL_IP4_SUBNET: + if (attr_len != 8 && attr_len != 0) + { + goto error; + } + break; + case INTERNAL_IP6_NETMASK: + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: + case INTERNAL_IP6_DHCP: + if (attr_len != 16 && attr_len != 0) + { + goto error; + } + break; + case INTERNAL_IP6_ADDRESS: + if (attr_len != 17 && attr_len != 16 && attr_len != 0) + { + goto error; + } + break; + case INTERNAL_IP6_SUBNET: + if (attr_len != 17 && attr_len != 0) + { + goto error; + } + break; + case SUPPORTED_ATTRIBUTES: + if (attr_len % 2) + { + goto error; + } + break; + case APPLICATION_VERSION: + break; + /* XAUTH attributes */ + case XAUTH_TYPE: + case XAUTH_STATUS: + if (!(attr.isaat_af_type & ISAKMP_ATTR_AF_TV)) + { + plog("%N attribute is not TV encoded", + configuration_attribute_type_names, attr_type); + return STF_FAIL; + } + case XAUTH_USER_NAME: + case XAUTH_USER_PASSWORD: + case XAUTH_PASSCODE: + case XAUTH_MESSAGE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + break; + /* Microsoft attributes */ + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + break; + /* Cisco Unity attributes */ + case UNITY_BANNER: + case UNITY_SAVE_PASSWD: + case UNITY_DEF_DOMAIN: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_LOCAL_LAN: + case UNITY_PFS: + case UNITY_FW_TYPE: + case UNITY_BACKUP_SERVERS: + case UNITY_DDNS_HOSTNAME: + break; + default: + plog("unknown attribute type (%u)", attr_type); + continue; + } + + /* add attribute */ + if (attr.isaat_af_type & ISAKMP_ATTR_AF_TV) + { + ca = modecfg_attribute_create_tv(attr_type, attr_len); + } + else + { + attr_chunk = chunk_create(strattr.cur, attr_len); + ca = modecfg_attribute_create(attr_type, attr_chunk); } + ca_list->insert_last(ca_list, ca); } return STF_OK; + +error: + plog("%N attribute has invalid size of %u octets", + configuration_attribute_type_names, attr_type, attr_len); + return STF_FAIL; } /** * Parse a ModeCfg message */ static stf_status modecfg_parse_msg(struct msg_digest *md, int isama_type, - u_int16_t *isama_id, internal_addr_t *ia, - linked_list_t *ca_list) + u_int16_t *isama_id, linked_list_t *ca_list) { + modecfg_attribute_t *ca; struct state *const st = md->st; struct payload_digest *p; stf_status stat; st->st_msgid = md->hdr.isa_msgid; - CHECK_QUICK_HASH(md, modecfg_hash(hash_val - , hash_pbs->roof - , md->message_pbs.roof, st) - , "MODECFG-HASH", "ISAKMP_CFG_MSG"); + CHECK_QUICK_HASH(md, modecfg_hash(hash_val, hash_pbs->roof, + md->message_pbs.roof, st), "MODECFG-HASH", "ISAKMP_CFG_MSG"); /* process the ModeCfg payloads received */ for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next) { - internal_addr_t ia_candidate; - - init_internal_addr(&ia_candidate); - if (p->payload.attribute.isama_type == isama_type) { *isama_id = p->payload.attribute.isama_identifier; - stat = modecfg_parse_attributes(&p->pbs, &ia_candidate, ca_list); + stat = modecfg_parse_attributes(&p->pbs, ca_list); if (stat == STF_OK) { /* return with a valid set of attributes */ - *ia = ia_candidate; return STF_OK; } } @@ -733,63 +648,61 @@ static stf_status modecfg_parse_msg(struct msg_digest *md, int isama_type, , enum_name(&attr_msg_type_names, isama_type) , enum_name(&attr_msg_type_names, p->payload.attribute.isama_type)); - stat = modecfg_parse_attributes(&p->pbs, &ia_candidate, ca_list); + stat = modecfg_parse_attributes(&p->pbs, ca_list); } + + /* abort if a parsing error occurred */ if (stat != STF_OK) { + ca_list->destroy_function(ca_list, (void*)modecfg_attribute_destroy); return stat; } + + /* discard the parsed attributes and look for another payload */ + while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) {} } return STF_IGNORE; } /** - * Send ModeCfg request message from client to server in pull mode + * Used in ModeCfg pull mode on the client (initiator) + * called in demux.c + * client -> CFG_REQUEST + * STF_OK transitions to STATE_MODE_CFG_I1 */ stf_status modecfg_send_request(struct state *st) { connection_t *c = st->st_connection; stf_status stat; - internal_addr_t ia; - attribute_handler_t *handler; - configuration_attribute_type_t type; - chunk_t data; - host_t *vip; + modecfg_attribute_t *ca; enumerator_t *enumerator; + int family; + chunk_t value; + host_t *vip; + linked_list_t *ca_list = linked_list_create(); - init_internal_addr(&ia); - - ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS) - | LELEM(INTERNAL_IP4_NETMASK); - ia.ipaddr = c->spd.this.host_srcip; - vip = host_create_from_sockaddr((sockaddr_t*)&ia.ipaddr); - - /* add configuration attributes requested by handlers */ - enumerator = hydra->attributes->create_initiator_enumerator( - hydra->attributes,c->spd.that.id, vip); - while (enumerator->enumerate(enumerator, &handler, &type, &data)) + vip = c->spd.this.host_srcip; + value = vip->is_anyaddr(vip) ? chunk_empty : vip->get_address(vip); + family = vip->get_family(vip); + ca = modecfg_attribute_create((family == AF_INET) ? + INTERNAL_IP4_ADDRESS : INTERNAL_IP6_ADDRESS, + value); + ca_list->insert_last(ca_list, ca); + + register_attribute_handlers(c); + enumerator = c->requested->create_enumerator(c->requested); + while (enumerator->enumerate(enumerator, &ca)) { - modecfg_attribute_t *ca; - - /* create configuration attribute request and link to handler */ - DBG(DBG_CONTROLMORE, - DBG_log("building %N attribute", configuration_attribute_type_names, type) - ) - ca = modecfg_attribute_create(type, data); - ca->handler = handler; - - if (c->requested == NULL) - { - c->requested = linked_list_create(); - } - c->requested->insert_last(c->requested, ca); + ca = modecfg_attribute_create(ca->type, chunk_empty); + ca_list->insert_last(ca_list, ca); } enumerator->destroy(enumerator); - vip->destroy(vip); plog("sending ModeCfg request"); + st->st_state = STATE_MODE_CFG_I1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia, c->requested); + stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); + ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat == STF_OK) { st->st_modecfg.started = TRUE; @@ -797,56 +710,35 @@ stf_status modecfg_send_request(struct state *st) return stat; } -/* STATE_MODE_CFG_R0: - * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP) - * - * used in ModeCfg pull mode, on the server (responder) +/** + * Used in ModeCfg pull mode on the server (responder) + * called in demux.c from STATE_MODE_CFG_R0 + * server <- CFG_REQUEST + * server -> CFG_REPLY + * STF_OK transitions to STATE_MODE_CFG_R0 */ stf_status modecfg_inR0(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; - bool want_unity_banner; stf_status stat, stat_build; - host_t *requested_vip; linked_list_t *ca_list = linked_list_create(); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia, ca_list); + plog("parsing ModeCfg request"); + + stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); if (stat != STF_OK) { return stat; } - if (ia.attr_set & LELEM(INTERNAL_IP4_ADDRESS)) - { - requested_vip = host_create_from_sockaddr((sockaddr_t*)&ia.ipaddr); - } - else - { - requested_vip = host_create_any(AF_INET); - } - plog("peer requested virtual IP %H", requested_vip); - - want_unity_banner = (ia.unity_attr_set & LELEM(UNITY_BANNER - UNITY_BASE)) != LEMPTY; - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - /* build the CFG_REPLY */ - ca_list = linked_list_create(); - init_internal_addr(&ia); - get_internal_addr(st->st_connection, requested_vip, &ia, ca_list); - requested_vip->destroy(requested_vip); - - if (want_unity_banner) - { - ia.unity_banner = UNITY_BANNER_STR; - ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE); - } + get_attributes(st->st_connection, ca_list); plog("sending ModeCfg reply"); stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - &ia, ca_list, isama_id); + ca_list, isama_id); ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat_build != STF_OK) @@ -857,56 +749,49 @@ stf_status modecfg_inR0(struct msg_digest *md) return STF_OK; } -/* STATE_MODE_CFG_I1: - * HDR*, HASH, ATTR(REPLY=IP) - * - * used in ModeCfg pull mode, on the client (initiator) +/** + * Used in ModeCfg pull mode on the client (initiator) + * called in demux.c from STATE_MODE_CFG_I1 + * client <- CFG_REPLY + * STF_OK transitions to STATE_MODE_CFG_I2 */ stf_status modecfg_inI1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; stf_status stat; linked_list_t *ca_list = linked_list_create(); plog("parsing ModeCfg reply"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia, ca_list); + stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); if (stat != STF_OK) { return stat; } - st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia, ca_list); + st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); st->st_msgid = 0; ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); return STF_OK; } - /** - * Send ModeCfg set message from server to client in push mode + * Used in ModeCfg push mode on the server (responder) + * called in demux.c + * server -> CFG_SET + * STF_OK transitions to STATE_MODE_CFG_R3 */ stf_status modecfg_send_set(struct state *st) { stf_status stat; - internal_addr_t ia; - host_t *vip; linked_list_t *ca_list = linked_list_create(); - init_internal_addr(&ia); - vip = host_create_any(AF_INET); - get_internal_addr(st->st_connection, vip, &ia, ca_list); - vip->destroy(vip); -#ifdef CISCO_QUIRKS - ia.unity_banner = UNITY_BANNER_STR; - ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE); -#endif + plog("sending ModeCfg set"); - plog("sending ModeCfg set"); + get_attributes(st->st_connection, ca_list); st->st_state = STATE_MODE_CFG_R3; - stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia, ca_list); + stat = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat == STF_OK) { @@ -915,43 +800,64 @@ stf_status modecfg_send_set(struct state *st) return stat; } -/* STATE_MODE_CFG_I0: - * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK) - * - * used in ModeCfg push mode, on the client (initiator). +/** + * Used in ModeCfg push mode on the client (initiator) + * called in demux.c from STATE_MODE_CFG_I0 + * client <- CFG_SET + * client -> CFG_ACK + * STF_OK transitions to STATE_MODE_CFG_I3 */ stf_status modecfg_inI0(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; - lset_t attr_set, unity_attr_set; stf_status stat, stat_build; - linked_list_t *ca_list = linked_list_create(); + modecfg_attribute_t *ca; + linked_list_t *ca_list, *ca_ack_list; plog("parsing ModeCfg set"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - + ca_list = linked_list_create(); + stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); if (stat != STF_OK) { return stat; } - st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia, ca_list); + register_attribute_handlers(st->st_connection); + st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); /* prepare ModeCfg ack which sends zero length attributes */ - attr_set = ia.attr_set; - unity_attr_set = ia.unity_attr_set; - init_internal_addr(&ia); - ia.attr_set = attr_set & SUPPORTED_ATTR_SET; - ia.unity_attr_set = unity_attr_set & SUPPORTED_UNITY_ATTR_SET; + ca_ack_list = linked_list_create(); + while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) + { + switch (ca->type) + { + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case APPLICATION_VERSION: + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: +#ifdef CISCO_QUIRKS + case UNITY_BANNER: +#endif + /* supported attributes */ + ca->value.len = 0; + ca_ack_list->insert_last(ca_ack_list, ca); + break; + default: + /* unsupportd attributes */ + modecfg_attribute_destroy(ca); + } + } + ca_list->destroy(ca_list); plog("sending ModeCfg ack"); stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, - &ia, ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); + ca_ack_list, isama_id); + ca_ack_list->destroy_function(ca_ack_list, (void *)modecfg_attribute_destroy); if (stat_build != STF_OK) { return stat_build; @@ -960,22 +866,22 @@ stf_status modecfg_inI0(struct msg_digest *md) return STF_OK; } -/* STATE_MODE_CFG_R3: - * HDR*, HASH, ATTR(ACK,OK) - * - * used in ModeCfg push mode, on the server (responder) +/** + * Used in ModeCfg push mode on the server (responder) + * called in demux.c from STATE_MODE_CFG_R3 + * server <- CFG_ACK + * STF_OK transitions to STATE_MODE_CFG_R4 */ stf_status modecfg_inR3(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; stf_status stat; linked_list_t *ca_list = linked_list_create(); plog("parsing ModeCfg ack"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia, ca_list); + stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat != STF_OK) { @@ -986,21 +892,25 @@ stf_status modecfg_inR3(struct msg_digest *md) } /** - * Send XAUTH credentials request (username + password) + * Used on the XAUTH server (responder) + * called in demux.c + * server -> CFG_REQUEST + * STF_OK transitions to STATE_XAUTH_R1 */ stf_status xauth_send_request(struct state *st) { stf_status stat; - internal_addr_t ia; + modecfg_attribute_t *ca; linked_list_t *ca_list = linked_list_create(); - init_internal_addr(&ia); - ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE) - | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE); + ca = modecfg_attribute_create(XAUTH_USER_NAME, chunk_empty); + ca_list->insert_last(ca_list, ca); + ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, chunk_empty); + ca_list->insert_last(ca_list, ca); plog("sending XAUTH request"); st->st_state = STATE_XAUTH_R1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia, ca_list); + stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat == STF_OK) { @@ -1009,55 +919,85 @@ stf_status xauth_send_request(struct state *st) return stat; } -/* STATE_XAUTH_I0: - * HDR*, HASH, ATTR(REQ) --> HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) - * - * used on the XAUTH client (initiator) +/** + * Used on the XAUTH client (initiator) + * called in demux.c from STATE_XAUTH_I0 + * client <- CFG_REQUEST + * client -> CFG_REPLY + * STF_OK transitions to STATE_XAUTH_I1 */ stf_status xauth_inI0(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; stf_status stat, stat_build; - bool xauth_type_present; + modecfg_attribute_t *ca; + bool xauth_user_name = FALSE; + bool xauth_user_password = FALSE; + bool xauth_type_present = FALSE; + xauth_t xauth_secret; linked_list_t *ca_list = linked_list_create(); plog("parsing XAUTH request"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); + stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); if (stat != STF_OK) { return stat; } - /* check XAUTH attributes */ - xauth_type_present = (ia.xauth_attr_set & LELEM(XAUTH_TYPE - XAUTH_BASE)) != LEMPTY; - - if (xauth_type_present && ia.xauth_type != XAUTH_TYPE_GENERIC) + while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) { - plog("xauth type %s is not supported", enum_name(&xauth_type_names, ia.xauth_type)); - stat = STF_FAIL; + switch (ca->type) + { + case XAUTH_TYPE: + if (ca->value.len != XAUTH_TYPE_GENERIC) + { + plog("xauth type %s is not supported", + enum_name(&xauth_type_names, ca->value.len)); + stat = STF_FAIL; + } + else + { + xauth_type_present = TRUE; + } + break; + case XAUTH_USER_NAME: + xauth_user_name = TRUE; + break; + case XAUTH_USER_PASSWORD: + xauth_user_password = TRUE; + break; + case XAUTH_MESSAGE: + if (ca->value.len) + { + DBG(DBG_PARSING | DBG_CONTROLMORE, + DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) + ) + } + break; + default: + break; + } + modecfg_attribute_destroy(ca); } - else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY) + + if (!xauth_user_name) { plog("user name attribute is missing in XAUTH request"); stat = STF_FAIL; } - else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY) + if (!xauth_user_password) { plog("user password attribute is missing in XAUTH request"); stat = STF_FAIL; } /* prepare XAUTH reply */ - init_internal_addr(&ia); - if (stat == STF_OK) { /* get user credentials using a plugin function */ - if (!xauth_module.get_secret(&ia.xauth_secret)) + if (!xauth_module.get_secret(&xauth_secret)) { plog("xauth user credentials not found"); stat = STF_FAIL; @@ -1065,33 +1005,33 @@ stf_status xauth_inI0(struct msg_digest *md) } if (stat == STF_OK) { + if (xauth_type_present) + { + ca = modecfg_attribute_create_tv(XAUTH_TYPE, XAUTH_TYPE_GENERIC); + ca_list->insert_last(ca_list, ca); + } DBG(DBG_CONTROL, - DBG_log("my xauth user name is '%.*s'" - , ia.xauth_secret.user_name.len - , ia.xauth_secret.user_name.ptr) + DBG_log("my xauth user name is '%.*s'", xauth_secret.user_name.len, + xauth_secret.user_name.ptr) ) + ca = modecfg_attribute_create(XAUTH_USER_NAME, xauth_secret.user_name); + ca_list->insert_last(ca_list, ca); DBG(DBG_PRIVATE, - DBG_log("my xauth user password is '%.*s'" - , ia.xauth_secret.user_password.len - , ia.xauth_secret.user_password.ptr) + DBG_log("my xauth user password is '%.*s'", xauth_secret.user_password.len, + xauth_secret.user_password.ptr) ) - ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE) - | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE); - if (xauth_type_present) - { - ia.xauth_attr_set |= LELEM(XAUTH_TYPE - XAUTH_BASE); - } + ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, xauth_secret.user_password); + ca_list->insert_last(ca_list, ca); } else { - ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE); - ia.xauth_status = XAUTH_STATUS_FAIL; + ca = modecfg_attribute_create_tv(XAUTH_STATUS, XAUTH_STATUS_FAIL); + ca_list->insert_last(ca_list, ca); } plog("sending XAUTH reply"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - &ia, ca_list, isama_id); + ca_list, isama_id); ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat_build != STF_OK) { @@ -1115,45 +1055,71 @@ stf_status xauth_inI0(struct msg_digest *md) } } -/* STATE_XAUTH_R1: - * HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) --> HDR*, HASH, ATTR(STATUS) - * - * used on the XAUTH server (responder) +/** + * Used on the XAUTH server (responder) + * called in demux.c from STATE_XAUTH_R1 + server <- CFG_REPLY + server -> CFG_SET + STF_OK transitions to STATE_XAUTH_R2 */ stf_status xauth_inR1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; stf_status stat, stat_build; + xauth_t xauth_secret; + int xauth_status = XAUTH_STATUS_OK; + modecfg_attribute_t *ca; linked_list_t *ca_list = linked_list_create(); plog("parsing XAUTH reply"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); + stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); if (stat != STF_OK) { return stat; } + /* initialize xauth_secret */ + xauth_secret.user_name = chunk_empty; + xauth_secret.user_password = chunk_empty; + + while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) + { + switch (ca->type) + { + case XAUTH_STATUS: + xauth_status = ca->value.len; + break; + case XAUTH_USER_NAME: + xauth_secret.user_name = chunk_clone(ca->value); + break; + case XAUTH_USER_PASSWORD: + xauth_secret.user_password = chunk_clone(ca->value); + break; + default: + break; + } + modecfg_attribute_destroy(ca); + } /* did the client return an XAUTH FAIL status? */ - if ((ia.xauth_attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE)) != LEMPTY) + if (xauth_status == XAUTH_STATUS_FAIL) { plog("received FAIL status in XAUTH reply"); /* client is not able to do XAUTH, delete ISAKMP SA */ delete_state(st); + ca_list->destroy(ca_list); return STF_IGNORE; } /* check XAUTH reply */ - if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY) + if (xauth_secret.user_name.ptr == NULL) { plog("user name attribute is missing in XAUTH reply"); st->st_xauth.status = FALSE; } - else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY) + else if (xauth_secret.user_password.ptr == NULL) { plog("user password attribute is missing in XAUTH reply"); st->st_xauth.status = FALSE; @@ -1164,33 +1130,28 @@ stf_status xauth_inR1(struct msg_digest *md) peer.conn_name = st->st_connection->name; addrtot(&md->sender, 0, peer.ip_address, sizeof(peer.ip_address)); - snprintf(peer.id, sizeof(peer.id), "%Y", - md->st->st_connection->spd.that.id); + snprintf(peer.id, sizeof(peer.id), "%Y", md->st->st_connection->spd.that.id); DBG(DBG_CONTROL, - DBG_log("peer xauth user name is '%.*s'" - , ia.xauth_secret.user_name.len - , ia.xauth_secret.user_name.ptr) + DBG_log("peer xauth user name is '%.*s'", xauth_secret.user_name.len, + xauth_secret.user_name.ptr) ) DBG(DBG_PRIVATE, - DBG_log("peer xauth user password is '%.*s'" - , ia.xauth_secret.user_password.len - , ia.xauth_secret.user_password.ptr) + DBG_log("peer xauth user password is '%.*s'", xauth_secret.user_password.len, + xauth_secret.user_password.ptr) ) /* verify the user credentials using a plugin function */ - st->st_xauth.status = xauth_module.verify_secret(&peer, &ia.xauth_secret); + st->st_xauth.status = xauth_module.verify_secret(&peer, &xauth_secret); plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); } - - /* prepare XAUTH set which sends the authentication status */ - init_internal_addr(&ia); - ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE); - ia.xauth_status = (st->st_xauth.status)? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; - ca_list = linked_list_create(); - - plog("sending XAUTH status:"); - - stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia, ca_list); + chunk_clear(&xauth_secret.user_name); + chunk_clear(&xauth_secret.user_password); + + plog("sending XAUTH status"); + xauth_status = (st->st_xauth.status) ? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; + ca = modecfg_attribute_create_tv(XAUTH_STATUS, xauth_status); + ca_list->insert_last(ca_list, ca); + stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); if (stat_build != STF_OK) { @@ -1199,22 +1160,23 @@ stf_status xauth_inR1(struct msg_digest *md) return STF_OK; } -/* STATE_XAUTH_I1: - * HDR*, HASH, ATTR(STATUS) --> HDR*, HASH, ATTR(ACK) - * - * used on the XAUTH client (initiator) +/** + * Used on the XAUTH client (initiator) + * called in demux.c from STATE_XAUTH_I1 + * client <- CFG_SET + * client -> CFG_ACK + * STF_OK transitions to STATE_XAUTH_I2 */ stf_status xauth_inI1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; stf_status stat, stat_build; + modecfg_attribute_t *ca; linked_list_t *ca_list = linked_list_create(); plog("parsing XAUTH status"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); + stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); if (stat != STF_OK) { /* notification payload - not exactly the right choice, but okay */ @@ -1222,14 +1184,21 @@ stf_status xauth_inI1(struct msg_digest *md) return stat; } - st->st_xauth.status = ia.xauth_status; + st->st_xauth.status = FALSE; + while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) + { + if (ca->type == XAUTH_STATUS) + { + st->st_xauth.status = (ca->value.len == XAUTH_STATUS_OK); + } + modecfg_attribute_destroy(ca); + } plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); plog("sending XAUTH ack"); - init_internal_addr(&ia); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, - &ia, ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); + stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, ca_list, isama_id); + ca_list->destroy(ca_list); + if (stat_build != STF_OK) { return stat_build; @@ -1251,27 +1220,27 @@ stf_status xauth_inI1(struct msg_digest *md) } } -/* STATE_XAUTH_R2: - * HDR*, ATTR(STATUS), HASH --> Done - * - * used on the XAUTH server (responder) +/** + * Used on the XAUTH server (responder) + * called in demux.c from STATE_XAUTH_R2 + * server <- CFG_ACK + * STF_OK transitions to STATE_XAUTH_R3 */ stf_status xauth_inR2(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; - internal_addr_t ia; stf_status stat; linked_list_t *ca_list = linked_list_create(); plog("parsing XAUTH ack"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); + stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); if (stat != STF_OK) { return stat; } + ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); st->st_msgid = 0; if (st->st_xauth.status) { diff --git a/src/pluto/modecfg.h b/src/pluto/modecfg.h index 8ed5de9a5..7adf18682 100644 --- a/src/pluto/modecfg.h +++ b/src/pluto/modecfg.h @@ -34,6 +34,11 @@ struct modecfg_attribute_t { u_int16_t type; /** + * Attribute is coded as TV + */ + bool is_tv; + + /** * Attribute value as chunk. */ chunk_t value; |