Return to eap_dynamic.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / eap_dynamic |
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: }