diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libcharon/sa/tasks/xauth.c | 168 |
1 files changed, 167 insertions, 1 deletions
diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c index 4d12e16e6..4fcb569a1 100644 --- a/src/libcharon/sa/tasks/xauth.c +++ b/src/libcharon/sa/tasks/xauth.c @@ -22,6 +22,14 @@ typedef struct private_xauth_t private_xauth_t; /** + * Status types exchanged + */ +typedef enum { + XAUTH_FAILED = 0, + XAUTH_OK = 1, +} xauth_status_t; + +/** * Private members of a xauth_t task. */ struct private_xauth_t { @@ -40,11 +48,116 @@ struct private_xauth_t { * Are we the XAUTH initiator? */ bool initiator; + + /** + * XAuth backend to use + */ + xauth_method_t *xauth; + + /** + * Generated configuration payload + */ + cp_payload_t *cp; + + /** + * status of Xauth exchange + */ + xauth_status_t status; }; +/** + * Load XAuth backend + */ +static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) +{ + identification_t *server, *peer; + enumerator_t *enumerator; + xauth_method_t *xauth; + xauth_role_t role; + peer_cfg_t *peer_cfg; + auth_cfg_t *auth; + char *name; + + if (initiator) + { + server = ike_sa->get_my_id(ike_sa); + peer = ike_sa->get_other_id(ike_sa); + role = XAUTH_SERVER; + } + else + { + peer = ike_sa->get_my_id(ike_sa); + server = ike_sa->get_other_id(ike_sa); + role = XAUTH_PEER; + } + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !initiator); + if (!enumerator->enumerate(enumerator, &auth) || + !enumerator->enumerate(enumerator, &auth)) + { + DBG1(DBG_CFG, "no second authentication round found for XAuth"); + enumerator->destroy(enumerator); + return NULL; + } + name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND); + enumerator->destroy(enumerator); + + xauth = charon->xauth->create_instance(charon->xauth, name, role, + server, peer); + if (!xauth) + { + if (name) + { + DBG1(DBG_CFG, "no XAuth method found named '%s'"); + } + else + { + DBG1(DBG_CFG, "no XAuth method found"); + } + } + return xauth; +} + +METHOD(task_t, build_i_status, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET); + cp->add_attribute(cp, + configuration_attribute_create_value(XAUTH_STATUS, this->status)); + + message->add_payload(message, (payload_t *)cp); + + return NEED_MORE; +} + METHOD(task_t, build_i, status_t, private_xauth_t *this, message_t *message) { + if (!this->xauth) + { + cp_payload_t *cp; + + this->xauth = load_method(this->ike_sa, this->initiator); + if (!this->xauth) + { + return FAILED; + } + if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE) + { + return FAILED; + } + message->add_payload(message, (payload_t *)cp); + return NEED_MORE; + } + + if (this->cp) + { /* send previously generated payload */ + message->add_payload(message, (payload_t *)this->cp); + this->cp = NULL; + return NEED_MORE; + } return FAILED; } @@ -60,10 +173,60 @@ METHOD(task_t, build_r, status_t, return FAILED; } +METHOD(task_t, process_i_status, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp || cp->get_type(cp) != CFG_ACK) + { + DBG1(DBG_IKE, "received invalid XAUTH status response"); + return 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; +} + METHOD(task_t, process_i, status_t, private_xauth_t *this, message_t *message) { - return FAILED; + cp_payload_t *cp; + + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp) + { + DBG1(DBG_IKE, "configuration payload missing in XAuth response"); + return FAILED; + } + switch (this->xauth->process(this->xauth, cp, &this->cp)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + DBG1(DBG_IKE, "XAuth authentication successful"); + this->status = XAUTH_OK; + break; + case FAILED: + DBG1(DBG_IKE, "XAuth authentication failed"); + break; + default: + return FAILED; + } + this->public.task.build = _build_i_status; + this->public.task.process = _process_i_status; + return NEED_MORE; } METHOD(task_t, get_type, task_type_t, @@ -81,6 +244,8 @@ METHOD(task_t, migrate, void, METHOD(task_t, destroy, void, private_xauth_t *this) { + DESTROY_IF(this->xauth); + DESTROY_IF(this->cp); free(this); } @@ -101,6 +266,7 @@ xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator) }, .initiator = initiator, .ike_sa = ike_sa, + .status = XAUTH_FAILED, ); if (initiator) |