diff options
Diffstat (limited to 'src/pluto/modecfg.c')
-rw-r--r-- | src/pluto/modecfg.c | 1263 |
1 files changed, 0 insertions, 1263 deletions
diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c deleted file mode 100644 index 8298ea601..000000000 --- a/src/pluto/modecfg.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* Mode config related functions - * 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-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 - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * This code originally written by Colubris Networks, Inc. - * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation - * Porting to 2.x by Sean Mathews - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <freeswan.h> - -#include <library.h> -#include <hydra.h> -#include <utils/linked_list.h> -#include <crypto/prfs/prf.h> - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "demux.h" -#include "timer.h" -#include "ipsec_doi.h" -#include "log.h" -#include "crypto.h" -#include "modecfg.h" -#include "whack.h" -#include "pluto.h" - -#define MAX_XAUTH_TRIES 3 - -#define DEFAULT_UNITY_BANNER "Welcome to strongSwan - the Linux VPN Solution!\n" - -/** - * Creates a modecfg_attribute_t object - */ -static modecfg_attribute_t *modecfg_attribute_create(configuration_attribute_type_t type, - chunk_t value) -{ - modecfg_attribute_t *this; - - 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; - - return this; -} - -/** - * Creates a modecfg_attribute_t object coded in TV format - */ -static modecfg_attribute_t *modecfg_attribute_create_tv(configuration_attribute_type_t type, - size_t value) -{ - modecfg_attribute_t *this; - - this = modecfg_attribute_create(type, chunk_empty); - this->value.len = value; - this->is_tv = TRUE; - - return this; -} - -/** - * Destroys a modecfg_attribute_t object - */ -void modecfg_attribute_destroy(modecfg_attribute_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Get attributes to be sent to client - */ -static void get_attributes(connection_t *c, linked_list_t *ca_list) -{ - configuration_attribute_type_t type; - identification_t *client_id; - modecfg_attribute_t *ca; - 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; - DESTROY_IF(requested_vip); - 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 (requested_vip == NULL) - { - requested_vip = host_create_any(AF_INET); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* 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) - { - vip = hydra->attributes->acquire_address(hydra->attributes, - c->spd.that.pool, client_id, requested_vip); - if (vip) - { - c->spd.that.host_srcip->destroy(c->spd.that.host_srcip); - c->spd.that.host_srcip = vip; - } - } - else - { - plog("no virtual IP found"); - } - } - - 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)) - { - 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); - - /* 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; - } - - /* assign attributes from registered providers */ - enumerator = hydra->attributes->create_responder_enumerator(hydra->attributes, - c->spd.that.pool, client_id, vip); - while (enumerator->enumerate(enumerator, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca_list->insert_last(ca_list, ca); - if (type == UNITY_BANNER) - { - want_unity_banner = FALSE; - } - } - enumerator->destroy(enumerator); - - 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_attributes(connection_t *c, linked_list_t *ca_list) -{ - 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)) - { - int family = AF_INET6; - attribute_handler_t *handler = NULL; - enumerator_t *e; - - switch (ca->type) - { - 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; - - 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; - } - - /* 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); - - /* 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; - - if (c->attributes == NULL) - { - c->attributes = linked_list_create(); - } - 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; -} - -/** - * 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; - - /* 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); - } - enumerator->destroy(enumerator); -} - -/** - * Compute HASH of Mode Config. - */ -static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, - const struct state *st) -{ - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - chunk_t msg_chunk = { start, roof - start }; - size_t prf_block_size; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("ModeCfg HASH computed:"); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - - -/** - * 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, 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); - - 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; - } - - 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) - { - 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); - } - else - { - char buf[BUF_LEN]; - - 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_output_pbs(&attrval); - } - enumerator->destroy(enumerator); - close_output_pbs(&strattr); - - modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); - close_message(rbody); - encrypt_message(rbody, st); - return STF_OK; -} - -/** - * Send ModeCfg message - */ -static stf_status modecfg_send_msg(struct state *st, int isama_type, - linked_list_t *ca_list) -{ - pb_stream msg; - pb_stream rbody; - char buf[BUF_LEN]; - - /* set up attr */ - init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer"); - - /* this is the beginning of a new exchange */ - st->st_msgid = generate_msgid(st); - init_phase2_iv(st, &st->st_msgid); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - hdr.isa_msgid = st->st_msgid; - - if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody)) - { - return STF_INTERNAL_ERROR; - } - } - - /* ATTR out with isama_id of 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)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - send_packet(st, "ModeCfg msg"); - - if (st->st_event->ev_type != EVENT_RETRANSMIT) - { - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - } - return STF_OK; -} - -/** - * Parse a ModeCfg attribute payload - */ -static stf_status modecfg_parse_attributes(pb_stream *attrs, linked_list_t *ca_list) -{ - struct isakmp_attribute attr; - pb_stream strattr; - 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)) - { - if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr)) - { - return STF_FAIL; - } - attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK; - attr_len = attr.isaat_lv; - DBG(DBG_CONTROLMORE, - DBG_log("processing %N attribute", - configuration_attribute_type_names, attr_type) - ) - - switch (attr_type) - { - 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) - { - goto error; - } - 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: - 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, 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"); - - /* process the ModeCfg payloads received */ - for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next) - { - if (p->payload.attribute.isama_type == isama_type) - { - *isama_id = p->payload.attribute.isama_identifier; - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - if (stat == STF_OK) - { - /* return with a valid set of attributes */ - return STF_OK; - } - } - else - { - plog("expected %s, got %s instead (ignored)" - , 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, 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; -} - -/** - * 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; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - int family; - chunk_t value; - host_t *vip; - linked_list_t *ca_list = linked_list_create(); - - 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)) - { - ca = modecfg_attribute_create(ca->type, chunk_empty); - ca_list->insert_last(ca_list, ca); - } - enumerator->destroy(enumerator); - - plog("sending ModeCfg request"); - - st->st_state = STATE_MODE_CFG_I1; - 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; - } - return stat; -} - -/** - * 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; - stf_status stat, stat_build; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* build the CFG_REPLY */ - get_attributes(st->st_connection, ca_list); - - plog("sending ModeCfg reply"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * 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; - 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, ca_list); - if (stat != STF_OK) - { - return stat; - } - 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; -} - -/** - * 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; - linked_list_t *ca_list = linked_list_create(); - - - 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, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * 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; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list, *ca_ack_list; - - plog("parsing ModeCfg set"); - - ca_list = linked_list_create(); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - 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 */ - 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, - 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; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * 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; - 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, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat != STF_OK) - { - return stat; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * 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; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - 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, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - } - return stat; -} - -/** - * 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; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - bool xauth_user_name_present = FALSE; - bool xauth_user_password_present = FALSE; - bool xauth_type_present = FALSE; - chunk_t xauth_user_name, xauth_user_password; - identification_t *user_id; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - 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_present = TRUE; - break; - case XAUTH_USER_PASSWORD: - xauth_user_password_present = 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); - } - - if (!xauth_user_name_present) - { - plog("user name attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - if (!xauth_user_password_present) - { - plog("user password attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - - /* prepare XAUTH reply */ - if (stat == STF_OK) - { - /* get user credentials using a plugin function */ - if (!pluto->xauth->get_secret(pluto->xauth, c, &xauth_user_password)) - { - plog("xauth user credentials not found"); - stat = STF_FAIL; - } - } - if (stat == STF_OK) - { - /* insert xauth type if present */ - if (xauth_type_present) - { - ca = modecfg_attribute_create_tv(XAUTH_TYPE, XAUTH_TYPE_GENERIC); - ca_list->insert_last(ca_list, ca); - } - - /* insert xauth user name */ - user_id = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - xauth_user_name = user_id->get_encoding(user_id); - DBG(DBG_CONTROL, - DBG_log("my xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_NAME, xauth_user_name); - ca_list->insert_last(ca_list, ca); - - /* insert xauth user password */ - DBG(DBG_PRIVATE, - DBG_log("my xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, xauth_user_password); - ca_list->insert_last(ca_list, ca); - chunk_clear(&xauth_user_password); - } - else - { - 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, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH reply msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH reply msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * 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; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - chunk_t xauth_user_name, xauth_user_password; - 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, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* initialize xauth_secret */ - xauth_user_name = chunk_empty; - xauth_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_user_name = chunk_clone(ca->value); - break; - case XAUTH_USER_PASSWORD: - xauth_user_password = chunk_clone(ca->value); - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - /* did the client return an XAUTH FAIL status? */ - if (xauth_status == XAUTH_STATUS_FAIL) - { - plog("received FAIL status in XAUTH reply"); - - /* client is not able to do XAUTH, delete ISAKMP SA */ - free(xauth_user_name.ptr); - free(xauth_user_password.ptr); - delete_state(st); - ca_list->destroy(ca_list); - return STF_IGNORE; - } - - /* check XAUTH reply */ - if (xauth_user_name.ptr == NULL) - { - plog("user name attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else if (xauth_user_password.ptr == NULL) - { - plog("user password attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - DESTROY_IF(c->xauth_identity); - c->xauth_identity = identification_create_from_data(xauth_user_name); - - DBG(DBG_PRIVATE, - DBG_log("peer xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - /* verify the user credentials using a plugin function */ - st->st_xauth.status = pluto->xauth->verify_secret(pluto->xauth, c, - xauth_user_password); - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - } - chunk_clear(&xauth_user_name); - chunk_clear(&xauth_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) - { - return stat_build; - } - return STF_OK; -} - -/** - * 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; - 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, ca_list); - if (stat != STF_OK) - { - /* notification payload - not exactly the right choice, but okay */ - md->note = ISAKMP_ATTRIBUTES_NOT_SUPPORTED; - return stat; - } - - 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"); - 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; - } - if (st->st_xauth.status) - { - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH ack msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH ack msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * 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; - 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, 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) - { - return STF_OK; - } - else - { - delete_state(st); - return STF_IGNORE; - } - -} |