Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_dynamic/eap_dynamic.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 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 "eap_dynamic.h"
! 17:
! 18: #include <daemon.h>
! 19: #include <library.h>
! 20:
! 21: typedef struct private_eap_dynamic_t private_eap_dynamic_t;
! 22:
! 23: /**
! 24: * Private data of an eap_dynamic_t object.
! 25: */
! 26: struct private_eap_dynamic_t {
! 27:
! 28: /**
! 29: * Public authenticator_t interface.
! 30: */
! 31: eap_dynamic_t public;
! 32:
! 33: /**
! 34: * ID of the server
! 35: */
! 36: identification_t *server;
! 37:
! 38: /**
! 39: * ID of the peer
! 40: */
! 41: identification_t *peer;
! 42:
! 43: /**
! 44: * Our supported EAP types (as eap_vendor_type_t*)
! 45: */
! 46: linked_list_t *types;
! 47:
! 48: /**
! 49: * EAP types supported by peer, if any
! 50: */
! 51: linked_list_t *other_types;
! 52:
! 53: /**
! 54: * Prefer types sent by peer
! 55: */
! 56: bool prefer_peer;
! 57:
! 58: /**
! 59: * The proxied EAP method
! 60: */
! 61: eap_method_t *method;
! 62: };
! 63:
! 64: /**
! 65: * Compare two eap_vendor_type_t objects
! 66: */
! 67: static bool entry_matches(eap_vendor_type_t *item, eap_vendor_type_t *other)
! 68: {
! 69: return item->type == other->type && item->vendor == other->vendor;
! 70: }
! 71:
! 72: CALLBACK(entry_matches_cb, bool,
! 73: eap_vendor_type_t *item, va_list args)
! 74: {
! 75: eap_vendor_type_t *other;
! 76:
! 77: VA_ARGS_VGET(args, other);
! 78: return entry_matches(item, other);
! 79: }
! 80:
! 81: /**
! 82: * Load the given EAP method
! 83: */
! 84: static eap_method_t *load_method(private_eap_dynamic_t *this,
! 85: eap_type_t type, uint32_t vendor)
! 86: {
! 87: eap_method_t *method;
! 88:
! 89: method = charon->eap->create_instance(charon->eap, type, vendor, EAP_SERVER,
! 90: this->server, this->peer);
! 91: if (!method)
! 92: {
! 93: if (vendor)
! 94: {
! 95: DBG1(DBG_IKE, "loading vendor specific EAP method %d-%d failed",
! 96: type, vendor);
! 97: }
! 98: else
! 99: {
! 100: DBG1(DBG_IKE, "loading %N method failed", eap_type_names, type);
! 101: }
! 102: }
! 103: return method;
! 104: }
! 105:
! 106: METHOD(eap_method_t, get_auth, auth_cfg_t*,
! 107: private_eap_dynamic_t *this)
! 108: {
! 109: /* get_auth() is only registered if the EAP method supports it */
! 110: return this->method->get_auth(this->method);
! 111: }
! 112:
! 113: /**
! 114: * Select the first method we can instantiate and is supported by both peers.
! 115: */
! 116: static void select_method(private_eap_dynamic_t *this)
! 117: {
! 118: eap_vendor_type_t *entry;
! 119: linked_list_t *outer = this->types, *inner = this->other_types;
! 120: char *who = "peer";
! 121:
! 122: if (this->other_types && this->prefer_peer)
! 123: {
! 124: outer = this->other_types;
! 125: inner = this->types;
! 126: who = "us";
! 127: }
! 128:
! 129: while (outer->remove_first(outer, (void*)&entry) == SUCCESS)
! 130: {
! 131: if (inner)
! 132: {
! 133: if (!inner->find_first(inner, entry_matches_cb, NULL, entry))
! 134: {
! 135: if (entry->vendor)
! 136: {
! 137: DBG2(DBG_IKE, "proposed vendor specific EAP method %d-%d "
! 138: "not supported by %s, skipped", entry->type,
! 139: entry->vendor, who);
! 140: }
! 141: else
! 142: {
! 143: DBG2(DBG_IKE, "proposed %N method not supported by %s, "
! 144: "skipped", eap_type_names, entry->type, who);
! 145: }
! 146: free(entry);
! 147: continue;
! 148: }
! 149: }
! 150: this->method = load_method(this, entry->type, entry->vendor);
! 151: if (this->method)
! 152: {
! 153: if (this->method->get_auth)
! 154: {
! 155: this->public.interface.get_auth = _get_auth;
! 156: }
! 157: if (entry->vendor)
! 158: {
! 159: DBG1(DBG_IKE, "vendor specific EAP method %d-%d selected",
! 160: entry->type, entry->vendor);
! 161: }
! 162: else
! 163: {
! 164: DBG1(DBG_IKE, "%N method selected", eap_type_names,
! 165: entry->type);
! 166: }
! 167: free(entry);
! 168: break;
! 169: }
! 170: free(entry);
! 171: }
! 172: }
! 173:
! 174: METHOD(eap_method_t, initiate, status_t,
! 175: private_eap_dynamic_t *this, eap_payload_t **out)
! 176: {
! 177: if (!this->method)
! 178: {
! 179: select_method(this);
! 180: if (!this->method)
! 181: {
! 182: DBG1(DBG_IKE, "no supported EAP method found");
! 183: return FAILED;
! 184: }
! 185: }
! 186: return this->method->initiate(this->method, out);
! 187: }
! 188:
! 189: METHOD(eap_method_t, process, status_t,
! 190: private_eap_dynamic_t *this, eap_payload_t *in, eap_payload_t **out)
! 191: {
! 192: eap_type_t received_type, type;
! 193: uint32_t received_vendor, vendor;
! 194:
! 195: received_type = in->get_type(in, &received_vendor);
! 196: if (received_vendor == 0 && received_type == EAP_NAK)
! 197: {
! 198: enumerator_t *enumerator;
! 199:
! 200: DBG1(DBG_IKE, "received %N, selecting a different EAP method",
! 201: eap_type_names, EAP_NAK);
! 202:
! 203: if (this->other_types)
! 204: { /* we already received a Nak or a proper response before */
! 205: DBG1(DBG_IKE, "%N is not supported in this state", eap_type_names,
! 206: EAP_NAK);
! 207: return FAILED;
! 208: }
! 209:
! 210: this->other_types = linked_list_create();
! 211: enumerator = in->get_types(in);
! 212: while (enumerator->enumerate(enumerator, &type, &vendor))
! 213: {
! 214: eap_vendor_type_t *entry;
! 215:
! 216: if (!type)
! 217: {
! 218: DBG1(DBG_IKE, "peer does not support any other EAP methods");
! 219: enumerator->destroy(enumerator);
! 220: return FAILED;
! 221: }
! 222: INIT(entry,
! 223: .type = type,
! 224: .vendor = vendor,
! 225: );
! 226: this->other_types->insert_last(this->other_types, entry);
! 227: }
! 228: enumerator->destroy(enumerator);
! 229:
! 230: /* restart with a different method */
! 231: this->method->destroy(this->method);
! 232: this->method = NULL;
! 233: this->public.interface.get_auth = NULL;
! 234: return initiate(this, out);
! 235: }
! 236: if (!this->other_types)
! 237: { /* so we don't handle EAP-Naks later */
! 238: this->other_types = linked_list_create();
! 239: }
! 240: if (this->method)
! 241: {
! 242: return this->method->process(this->method, in, out);
! 243: }
! 244: return FAILED;
! 245: }
! 246:
! 247: METHOD(eap_method_t, get_type, eap_type_t,
! 248: private_eap_dynamic_t *this, uint32_t *vendor)
! 249: {
! 250: if (this->method)
! 251: {
! 252: return this->method->get_type(this->method, vendor);
! 253: }
! 254: *vendor = 0;
! 255: return EAP_DYNAMIC;
! 256: }
! 257:
! 258: METHOD(eap_method_t, get_msk, status_t,
! 259: private_eap_dynamic_t *this, chunk_t *msk)
! 260: {
! 261: if (this->method)
! 262: {
! 263: return this->method->get_msk(this->method, msk);
! 264: }
! 265: return FAILED;
! 266: }
! 267:
! 268: METHOD(eap_method_t, get_identifier, uint8_t,
! 269: private_eap_dynamic_t *this)
! 270: {
! 271: if (this->method)
! 272: {
! 273: return this->method->get_identifier(this->method);
! 274: }
! 275: return 0;
! 276: }
! 277:
! 278: METHOD(eap_method_t, set_identifier, void,
! 279: private_eap_dynamic_t *this, uint8_t identifier)
! 280: {
! 281: if (this->method)
! 282: {
! 283: this->method->set_identifier(this->method, identifier);
! 284: }
! 285: }
! 286:
! 287: METHOD(eap_method_t, is_mutual, bool,
! 288: private_eap_dynamic_t *this)
! 289: {
! 290: if (this->method)
! 291: {
! 292: return this->method->is_mutual(this->method);
! 293: }
! 294: return FALSE;
! 295: }
! 296:
! 297: METHOD(eap_method_t, destroy, void,
! 298: private_eap_dynamic_t *this)
! 299: {
! 300: DESTROY_IF(this->method);
! 301: this->types->destroy_function(this->types, (void*)free);
! 302: DESTROY_FUNCTION_IF(this->other_types, (void*)free);
! 303: this->server->destroy(this->server);
! 304: this->peer->destroy(this->peer);
! 305: free(this);
! 306: }
! 307:
! 308: /**
! 309: * Parse preferred EAP types
! 310: */
! 311: static void handle_preferred_eap_types(private_eap_dynamic_t *this,
! 312: char *methods)
! 313: {
! 314: enumerator_t *enumerator;
! 315: eap_vendor_type_t *type, *entry;
! 316: linked_list_t *preferred;
! 317: char *method;
! 318:
! 319: /* parse preferred EAP methods, format: type[-vendor], ... */
! 320: preferred = linked_list_create();
! 321: enumerator = enumerator_create_token(methods, ",", " ");
! 322: while (enumerator->enumerate(enumerator, &method))
! 323: {
! 324: type = eap_vendor_type_from_string(method);
! 325: if (type)
! 326: {
! 327: preferred->insert_last(preferred, type);
! 328: }
! 329: }
! 330: enumerator->destroy(enumerator);
! 331:
! 332: enumerator = this->types->create_enumerator(this->types);
! 333: while (preferred->remove_last(preferred, (void**)&type) == SUCCESS)
! 334: { /* move (supported) types to the front, maintain the preferred order */
! 335: this->types->reset_enumerator(this->types, enumerator);
! 336: while (enumerator->enumerate(enumerator, &entry))
! 337: {
! 338: if (entry_matches(entry, type))
! 339: {
! 340: this->types->remove_at(this->types, enumerator);
! 341: this->types->insert_first(this->types, entry);
! 342: break;
! 343: }
! 344: }
! 345: free(type);
! 346: }
! 347: enumerator->destroy(enumerator);
! 348: preferred->destroy(preferred);
! 349: }
! 350:
! 351: /**
! 352: * Get all supported EAP methods
! 353: */
! 354: static void get_supported_eap_types(private_eap_dynamic_t *this)
! 355: {
! 356: enumerator_t *enumerator;
! 357: eap_type_t type;
! 358: uint32_t vendor;
! 359:
! 360: enumerator = charon->eap->create_enumerator(charon->eap, EAP_SERVER);
! 361: while (enumerator->enumerate(enumerator, &type, &vendor))
! 362: {
! 363: eap_vendor_type_t *entry;
! 364:
! 365: INIT(entry,
! 366: .type = type,
! 367: .vendor = vendor,
! 368: );
! 369: this->types->insert_last(this->types, entry);
! 370: }
! 371: enumerator->destroy(enumerator);
! 372: }
! 373:
! 374: /*
! 375: * Defined in header
! 376: */
! 377: eap_dynamic_t *eap_dynamic_create(identification_t *server,
! 378: identification_t *peer)
! 379: {
! 380: private_eap_dynamic_t *this;
! 381: char *preferred;
! 382:
! 383: INIT(this,
! 384: .public = {
! 385: .interface = {
! 386: .initiate = _initiate,
! 387: .process = _process,
! 388: .get_type = _get_type,
! 389: .is_mutual = _is_mutual,
! 390: .get_msk = _get_msk,
! 391: .get_identifier = _get_identifier,
! 392: .set_identifier = _set_identifier,
! 393: .destroy = _destroy,
! 394: },
! 395: },
! 396: .peer = peer->clone(peer),
! 397: .server = server->clone(server),
! 398: .types = linked_list_create(),
! 399: .prefer_peer = lib->settings->get_bool(lib->settings,
! 400: "%s.plugins.eap-dynamic.prefer_peer", FALSE, lib->ns),
! 401: );
! 402:
! 403: /* get all supported EAP methods */
! 404: get_supported_eap_types(this);
! 405: /* move preferred methods to the front */
! 406: preferred = lib->settings->get_str(lib->settings,
! 407: "%s.plugins.eap-dynamic.preferred", NULL, lib->ns);
! 408: if (preferred)
! 409: {
! 410: handle_preferred_eap_types(this, preferred);
! 411: }
! 412: return &this->public;
! 413: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>