Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/xauth.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011 Martin Willi
! 3: * Copyright (C) 2011 revosec AG
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "xauth.h"
! 17:
! 18: #include <daemon.h>
! 19: #include <encoding/payloads/cp_payload.h>
! 20: #include <processing/jobs/adopt_children_job.h>
! 21: #include <sa/ikev1/tasks/mode_config.h>
! 22:
! 23: typedef struct private_xauth_t private_xauth_t;
! 24:
! 25: /**
! 26: * Status types exchanged
! 27: */
! 28: typedef enum {
! 29: XAUTH_FAILED = 0,
! 30: XAUTH_OK = 1,
! 31: } xauth_status_t;
! 32:
! 33: /**
! 34: * Private members of a xauth_t task.
! 35: */
! 36: struct private_xauth_t {
! 37:
! 38: /**
! 39: * Public methods and task_t interface.
! 40: */
! 41: xauth_t public;
! 42:
! 43: /**
! 44: * Assigned IKE_SA.
! 45: */
! 46: ike_sa_t *ike_sa;
! 47:
! 48: /**
! 49: * Are we the XAUTH initiator?
! 50: */
! 51: bool initiator;
! 52:
! 53: /**
! 54: * XAuth backend to use
! 55: */
! 56: xauth_method_t *xauth;
! 57:
! 58: /**
! 59: * XAuth username
! 60: */
! 61: identification_t *user;
! 62:
! 63: /**
! 64: * Generated configuration payload
! 65: */
! 66: cp_payload_t *cp;
! 67:
! 68: /**
! 69: * received identifier
! 70: */
! 71: uint16_t identifier;
! 72:
! 73: /**
! 74: * status of Xauth exchange
! 75: */
! 76: xauth_status_t status;
! 77:
! 78: /**
! 79: * Queue a Mode Config Push mode after completing XAuth?
! 80: */
! 81: bool mode_config_push;
! 82: };
! 83:
! 84: /**
! 85: * Load XAuth backend
! 86: */
! 87: static xauth_method_t *load_method(private_xauth_t* this)
! 88: {
! 89: identification_t *server, *peer;
! 90: enumerator_t *enumerator;
! 91: xauth_method_t *xauth;
! 92: xauth_role_t role;
! 93: peer_cfg_t *peer_cfg;
! 94: auth_cfg_t *auth;
! 95: char *name;
! 96:
! 97: if (this->initiator)
! 98: {
! 99: server = this->ike_sa->get_my_id(this->ike_sa);
! 100: peer = this->ike_sa->get_other_id(this->ike_sa);
! 101: role = XAUTH_SERVER;
! 102: }
! 103: else
! 104: {
! 105: peer = this->ike_sa->get_my_id(this->ike_sa);
! 106: server = this->ike_sa->get_other_id(this->ike_sa);
! 107: role = XAUTH_PEER;
! 108: }
! 109: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 110: enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator);
! 111: if (!enumerator->enumerate(enumerator, &auth) ||
! 112: (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
! 113: {
! 114: if (!enumerator->enumerate(enumerator, &auth) ||
! 115: (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
! 116: {
! 117: DBG1(DBG_CFG, "no XAuth authentication round found");
! 118: enumerator->destroy(enumerator);
! 119: return NULL;
! 120: }
! 121: }
! 122: name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
! 123: this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY);
! 124: enumerator->destroy(enumerator);
! 125: if (!this->initiator && this->user)
! 126: { /* use XAUTH username, if configured */
! 127: peer = this->user;
! 128: }
! 129: xauth = charon->xauth->create_instance(charon->xauth, name, role,
! 130: server, peer);
! 131: if (!xauth)
! 132: {
! 133: if (name)
! 134: {
! 135: DBG1(DBG_CFG, "no XAuth method found for '%s'", name);
! 136: }
! 137: else
! 138: {
! 139: DBG1(DBG_CFG, "no XAuth method found");
! 140: }
! 141: }
! 142: return xauth;
! 143: }
! 144:
! 145: /**
! 146: * Check if XAuth connection is allowed to succeed
! 147: */
! 148: static bool allowed(private_xauth_t *this)
! 149: {
! 150: if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
! 151: this->ike_sa, FALSE))
! 152: {
! 153: DBG1(DBG_IKE, "cancelling XAuth due to uniqueness policy");
! 154: return FALSE;
! 155: }
! 156: if (!charon->bus->authorize(charon->bus, FALSE))
! 157: {
! 158: DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling");
! 159: return FALSE;
! 160: }
! 161: if (!charon->bus->authorize(charon->bus, TRUE))
! 162: {
! 163: DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
! 164: return FALSE;
! 165: }
! 166: return TRUE;
! 167: }
! 168:
! 169: /**
! 170: * Set IKE_SA to established state
! 171: */
! 172: static bool establish(private_xauth_t *this)
! 173: {
! 174: DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
! 175: this->ike_sa->get_name(this->ike_sa),
! 176: this->ike_sa->get_unique_id(this->ike_sa),
! 177: this->ike_sa->get_my_host(this->ike_sa),
! 178: this->ike_sa->get_my_id(this->ike_sa),
! 179: this->ike_sa->get_other_host(this->ike_sa),
! 180: this->ike_sa->get_other_id(this->ike_sa));
! 181:
! 182: this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
! 183: charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
! 184:
! 185: return TRUE;
! 186: }
! 187:
! 188: /**
! 189: * Check if we are compliant to a given peer config
! 190: */
! 191: static bool is_compliant(private_xauth_t *this, peer_cfg_t *peer_cfg, bool log)
! 192: {
! 193: bool complies = TRUE;
! 194: enumerator_t *e1, *e2;
! 195: auth_cfg_t *c1, *c2;
! 196:
! 197: e1 = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
! 198: e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE);
! 199: while (e1->enumerate(e1, &c1))
! 200: {
! 201: if (!e2->enumerate(e2, &c2) || !c2->complies(c2, c1, log))
! 202: {
! 203: complies = FALSE;
! 204: break;
! 205: }
! 206: }
! 207: e1->destroy(e1);
! 208: e2->destroy(e2);
! 209:
! 210: return complies;
! 211: }
! 212:
! 213: /**
! 214: * Check if we are compliant to current config, switch to another if not
! 215: */
! 216: static bool select_compliant_config(private_xauth_t *this)
! 217: {
! 218: peer_cfg_t *peer_cfg = NULL, *old, *current;
! 219: identification_t *my_id, *other_id;
! 220: host_t *my_host, *other_host;
! 221: enumerator_t *enumerator;
! 222: bool aggressive;
! 223:
! 224: old = this->ike_sa->get_peer_cfg(this->ike_sa);
! 225: if (is_compliant(this, old, TRUE))
! 226: { /* current config is fine */
! 227: return TRUE;
! 228: }
! 229: DBG1(DBG_CFG, "selected peer config '%s' unacceptable",
! 230: old->get_name(old));
! 231: aggressive = old->use_aggressive(old);
! 232:
! 233: my_host = this->ike_sa->get_my_host(this->ike_sa);
! 234: other_host = this->ike_sa->get_other_host(this->ike_sa);
! 235: my_id = this->ike_sa->get_my_id(this->ike_sa);
! 236: other_id = this->ike_sa->get_other_id(this->ike_sa);
! 237: enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
! 238: my_host, other_host, my_id, other_id, IKEV1);
! 239: while (enumerator->enumerate(enumerator, ¤t))
! 240: {
! 241: if (!current->equals(current, old) &&
! 242: current->use_aggressive(current) == aggressive &&
! 243: is_compliant(this, current, FALSE))
! 244: {
! 245: peer_cfg = current;
! 246: break;
! 247: }
! 248: }
! 249: if (peer_cfg)
! 250: {
! 251: DBG1(DBG_CFG, "switching to peer config '%s'",
! 252: peer_cfg->get_name(peer_cfg));
! 253: this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg);
! 254: }
! 255: else
! 256: {
! 257: DBG1(DBG_CFG, "no alternative config found");
! 258: }
! 259: enumerator->destroy(enumerator);
! 260:
! 261: return peer_cfg != NULL;
! 262: }
! 263:
! 264: /**
! 265: * Create auth config after successful authentication
! 266: */
! 267: static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local)
! 268: {
! 269: auth_cfg_t *auth;
! 270:
! 271: auth = auth_cfg_create();
! 272: auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
! 273: if (id)
! 274: {
! 275: auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id));
! 276: }
! 277: auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), FALSE);
! 278: this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
! 279:
! 280: return select_compliant_config(this);
! 281: }
! 282:
! 283: METHOD(task_t, build_i_status, status_t,
! 284: private_xauth_t *this, message_t *message)
! 285: {
! 286: cp_payload_t *cp;
! 287:
! 288: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_SET);
! 289: cp->add_attribute(cp,
! 290: configuration_attribute_create_value(XAUTH_STATUS, this->status));
! 291:
! 292: message->add_payload(message, (payload_t *)cp);
! 293:
! 294: return NEED_MORE;
! 295: }
! 296:
! 297: METHOD(task_t, process_i_status, status_t,
! 298: private_xauth_t *this, message_t *message)
! 299: {
! 300: cp_payload_t *cp;
! 301: adopt_children_job_t *job;
! 302:
! 303: cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
! 304: if (!cp || cp->get_type(cp) != CFG_ACK)
! 305: {
! 306: DBG1(DBG_IKE, "received invalid XAUTH status response");
! 307: return FAILED;
! 308: }
! 309: if (this->status != XAUTH_OK)
! 310: {
! 311: DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
! 312: return FAILED;
! 313: }
! 314: if (!establish(this))
! 315: {
! 316: return FAILED;
! 317: }
! 318: this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE);
! 319: job = adopt_children_job_create(this->ike_sa->get_id(this->ike_sa));
! 320: if (this->mode_config_push)
! 321: {
! 322: job->queue_task(job,
! 323: (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
! 324: }
! 325: lib->processor->queue_job(lib->processor, (job_t*)job);
! 326: return SUCCESS;
! 327: }
! 328:
! 329: METHOD(task_t, build_i, status_t,
! 330: private_xauth_t *this, message_t *message)
! 331: {
! 332: if (!this->xauth)
! 333: {
! 334: cp_payload_t *cp = NULL;
! 335:
! 336: this->xauth = load_method(this);
! 337: if (!this->xauth)
! 338: {
! 339: return FAILED;
! 340: }
! 341: switch (this->xauth->initiate(this->xauth, &cp))
! 342: {
! 343: case NEED_MORE:
! 344: break;
! 345: case SUCCESS:
! 346: DESTROY_IF(cp);
! 347: if (add_auth_cfg(this, NULL, FALSE) && allowed(this))
! 348: {
! 349: this->status = XAUTH_OK;
! 350: }
! 351: this->public.task.process = _process_i_status;
! 352: return build_i_status(this, message);
! 353: default:
! 354: return FAILED;
! 355: }
! 356: message->add_payload(message, (payload_t *)cp);
! 357: return NEED_MORE;
! 358: }
! 359:
! 360: if (this->cp)
! 361: { /* send previously generated payload */
! 362: message->add_payload(message, (payload_t *)this->cp);
! 363: this->cp = NULL;
! 364: return NEED_MORE;
! 365: }
! 366: return FAILED;
! 367: }
! 368:
! 369: METHOD(task_t, build_r_ack, status_t,
! 370: private_xauth_t *this, message_t *message)
! 371: {
! 372: cp_payload_t *cp;
! 373:
! 374: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_ACK);
! 375: cp->set_identifier(cp, this->identifier);
! 376: cp->add_attribute(cp,
! 377: configuration_attribute_create_chunk(
! 378: PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_STATUS, chunk_empty));
! 379:
! 380: message->add_payload(message, (payload_t *)cp);
! 381:
! 382: if (this->status == XAUTH_OK && allowed(this) && establish(this))
! 383: {
! 384: return SUCCESS;
! 385: }
! 386: return FAILED;
! 387: }
! 388:
! 389: METHOD(task_t, process_r, status_t,
! 390: private_xauth_t *this, message_t *message)
! 391: {
! 392: cp_payload_t *cp;
! 393:
! 394: if (!this->xauth)
! 395: {
! 396: this->xauth = load_method(this);
! 397: if (!this->xauth)
! 398: { /* send empty reply */
! 399: return NEED_MORE;
! 400: }
! 401: }
! 402: cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
! 403: if (!cp)
! 404: {
! 405: DBG1(DBG_IKE, "configuration payload missing in XAuth request");
! 406: return FAILED;
! 407: }
! 408: if (cp->get_type(cp) == CFG_REQUEST)
! 409: {
! 410: switch (this->xauth->process(this->xauth, cp, &this->cp))
! 411: {
! 412: case NEED_MORE:
! 413: return NEED_MORE;
! 414: case SUCCESS:
! 415: case FAILED:
! 416: default:
! 417: break;
! 418: }
! 419: this->cp = NULL;
! 420: return NEED_MORE;
! 421: }
! 422: if (cp->get_type(cp) == CFG_SET)
! 423: {
! 424: configuration_attribute_t *attribute;
! 425: enumerator_t *enumerator;
! 426:
! 427: enumerator = cp->create_attribute_enumerator(cp);
! 428: while (enumerator->enumerate(enumerator, &attribute))
! 429: {
! 430: if (attribute->get_type(attribute) == XAUTH_STATUS)
! 431: {
! 432: this->status = attribute->get_value(attribute);
! 433: }
! 434: }
! 435: enumerator->destroy(enumerator);
! 436: if (this->status == XAUTH_OK &&
! 437: add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE))
! 438: {
! 439: DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful",
! 440: this->xauth->get_identity(this->xauth));
! 441: }
! 442: else
! 443: {
! 444: DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed",
! 445: this->xauth->get_identity(this->xauth));
! 446: }
! 447: }
! 448: this->identifier = cp->get_identifier(cp);
! 449: this->public.task.build = _build_r_ack;
! 450: return NEED_MORE;
! 451: }
! 452:
! 453: METHOD(task_t, build_r, status_t,
! 454: private_xauth_t *this, message_t *message)
! 455: {
! 456: if (!this->cp)
! 457: { /* send empty reply if building data failed */
! 458: this->cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
! 459: }
! 460: message->add_payload(message, (payload_t *)this->cp);
! 461: this->cp = NULL;
! 462: return NEED_MORE;
! 463: }
! 464:
! 465: METHOD(task_t, process_i, status_t,
! 466: private_xauth_t *this, message_t *message)
! 467: {
! 468: identification_t *id;
! 469: cp_payload_t *cp;
! 470:
! 471: cp = (cp_payload_t*)message->get_payload(message, PLV1_CONFIGURATION);
! 472: if (!cp)
! 473: {
! 474: DBG1(DBG_IKE, "configuration payload missing in XAuth response");
! 475: return FAILED;
! 476: }
! 477: switch (this->xauth->process(this->xauth, cp, &this->cp))
! 478: {
! 479: case NEED_MORE:
! 480: return NEED_MORE;
! 481: case SUCCESS:
! 482: id = this->xauth->get_identity(this->xauth);
! 483: DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id);
! 484: if (add_auth_cfg(this, id, FALSE) && allowed(this))
! 485: {
! 486: this->status = XAUTH_OK;
! 487: }
! 488: break;
! 489: case FAILED:
! 490: DBG1(DBG_IKE, "XAuth authentication of '%Y' failed",
! 491: this->xauth->get_identity(this->xauth));
! 492: break;
! 493: default:
! 494: return FAILED;
! 495: }
! 496: this->public.task.build = _build_i_status;
! 497: this->public.task.process = _process_i_status;
! 498: return NEED_MORE;
! 499: }
! 500:
! 501: METHOD(task_t, get_type, task_type_t,
! 502: private_xauth_t *this)
! 503: {
! 504: return TASK_XAUTH;
! 505: }
! 506:
! 507: METHOD(task_t, migrate, void,
! 508: private_xauth_t *this, ike_sa_t *ike_sa)
! 509: {
! 510: DESTROY_IF(this->xauth);
! 511: DESTROY_IF(this->cp);
! 512:
! 513: this->ike_sa = ike_sa;
! 514: this->xauth = NULL;
! 515: this->cp = NULL;
! 516: this->user = NULL;
! 517: this->status = XAUTH_FAILED;
! 518:
! 519: if (this->initiator)
! 520: {
! 521: this->public.task.build = _build_i;
! 522: this->public.task.process = _process_i;
! 523: }
! 524: else
! 525: {
! 526: this->public.task.build = _build_r;
! 527: this->public.task.process = _process_r;
! 528: }
! 529: }
! 530:
! 531: METHOD(xauth_t, queue_mode_config_push, void,
! 532: private_xauth_t *this)
! 533: {
! 534: this->mode_config_push = TRUE;
! 535: }
! 536:
! 537: METHOD(task_t, destroy, void,
! 538: private_xauth_t *this)
! 539: {
! 540: DESTROY_IF(this->xauth);
! 541: DESTROY_IF(this->cp);
! 542: free(this);
! 543: }
! 544:
! 545: /*
! 546: * Described in header.
! 547: */
! 548: xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
! 549: {
! 550: private_xauth_t *this;
! 551:
! 552: INIT(this,
! 553: .public = {
! 554: .task = {
! 555: .get_type = _get_type,
! 556: .migrate = _migrate,
! 557: .destroy = _destroy,
! 558: },
! 559: .queue_mode_config_push = _queue_mode_config_push,
! 560: },
! 561: .initiator = initiator,
! 562: .ike_sa = ike_sa,
! 563: .status = XAUTH_FAILED,
! 564: );
! 565:
! 566: if (initiator)
! 567: {
! 568: this->public.task.build = _build_i;
! 569: this->public.task.process = _process_i;
! 570: }
! 571: else
! 572: {
! 573: this->public.task.build = _build_r;
! 574: this->public.task.process = _process_r;
! 575: }
! 576: return &this->public;
! 577: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>