diff options
Diffstat (limited to 'src/libcharon/sa/ikev2/tasks/ike_auth.c')
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_auth.c | 144 |
1 files changed, 95 insertions, 49 deletions
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c index 2554496c1..79a436fbf 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_auth.c +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2015 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -25,6 +25,7 @@ #include <encoding/payloads/eap_payload.h> #include <encoding/payloads/nonce_payload.h> #include <sa/ikev2/authenticators/eap_authenticator.h> +#include <processing/jobs/delete_ike_sa_job.h> typedef struct private_ike_auth_t private_ike_auth_t; @@ -117,6 +118,11 @@ struct private_ike_auth_t { * Is EAP acceptable, did we strictly authenticate peer? */ bool eap_acceptable; + + /** + * Gateway ID if redirected + */ + identification_t *redirect_to; }; /** @@ -685,6 +691,7 @@ METHOD(task_t, process_r, status_t, METHOD(task_t, build_r, status_t, private_ike_auth_t *this, message_t *message) { + identification_t *gateway; auth_cfg_t *cfg; if (message->get_exchange_type(message) == IKE_SA_INIT) @@ -817,34 +824,56 @@ METHOD(task_t, build_r, status_t, { this->do_another_auth = FALSE; } - if (!this->do_another_auth && !this->expect_another_auth) + if (this->do_another_auth || this->expect_another_auth) { - if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa, FALSE)) - { - DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy"); - charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; - } - if (!charon->bus->authorize(charon->bus, TRUE)) - { - DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); - goto peer_auth_failed; - } - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - return SUCCESS; + return NEED_MORE; } - return NEED_MORE; + + if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy"); + charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + goto peer_auth_failed; + } + if (this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_REDIRECTION) && + charon->redirect->redirect_on_auth(charon->redirect, this->ike_sa, + &gateway)) + { + delete_ike_sa_job_t *job; + chunk_t data; + + DBG1(DBG_IKE, "redirecting peer to %Y", gateway); + data = redirect_data_create(gateway, chunk_empty); + message->add_notify(message, FALSE, REDIRECT, data); + gateway->destroy(gateway); + chunk_free(&data); + /* we use this condition to prevent the CHILD_SA from getting created */ + this->ike_sa->set_condition(this->ike_sa, COND_REDIRECTED, TRUE); + /* if the peer does not delete the SA we do so after a while */ + job = delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, + lib->settings->get_int(lib->settings, + "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT, + lib->ns)); + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + return SUCCESS; peer_auth_failed: message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); @@ -964,6 +993,15 @@ METHOD(task_t, process_i, status_t, case ME_ENDPOINT: /* handled in ike_me task */ break; + case REDIRECT: + DESTROY_IF(this->redirect_to); + this->redirect_to = redirect_data_parse( + notify->get_notification_data(notify), NULL); + if (!this->redirect_to) + { + DBG1(DBG_IKE, "received invalid REDIRECT notify"); + } + break; default: { if (type <= 16383) @@ -1094,30 +1132,35 @@ METHOD(task_t, process_i, status_t, { this->expect_another_auth = FALSE; } - if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth) + if (this->expect_another_auth || this->do_another_auth || this->my_auth) { - if (!update_cfg_candidates(this, TRUE)) - { - goto peer_auth_failed; - } - if (!charon->bus->authorize(charon->bus, TRUE)) - { - DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, " - "cancelling"); - goto peer_auth_failed; - } - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - return SUCCESS; + return NEED_MORE; } - return NEED_MORE; + if (!update_cfg_candidates(this, TRUE)) + { + goto peer_auth_failed; + } + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, " + "cancelling"); + goto peer_auth_failed; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + if (this->redirect_to) + { + this->ike_sa->handle_redirect(this->ike_sa, this->redirect_to); + } + return SUCCESS; peer_auth_failed: charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); @@ -1141,6 +1184,7 @@ METHOD(task_t, migrate, void, DESTROY_IF(this->peer_cfg); DESTROY_IF(this->my_auth); DESTROY_IF(this->other_auth); + DESTROY_IF(this->redirect_to); this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); this->my_packet = NULL; @@ -1149,6 +1193,7 @@ METHOD(task_t, migrate, void, this->peer_cfg = NULL; this->my_auth = NULL; this->other_auth = NULL; + this->redirect_to = NULL; this->do_another_auth = TRUE; this->expect_another_auth = TRUE; this->authentication_failed = FALSE; @@ -1165,6 +1210,7 @@ METHOD(task_t, destroy, void, DESTROY_IF(this->my_auth); DESTROY_IF(this->other_auth); DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->redirect_to); this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); free(this); } |