Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_dynamic/eap_dynamic.c, revision 1.1.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>