Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_radius/eap_radius.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012-2018 Tobias Brunner
        !             3:  * Copyright (C) 2009 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "eap_radius.h"
        !            18: #include "eap_radius_plugin.h"
        !            19: #include "eap_radius_forward.h"
        !            20: #include "eap_radius_provider.h"
        !            21: #include "eap_radius_accounting.h"
        !            22: 
        !            23: #include <radius_message.h>
        !            24: #include <radius_client.h>
        !            25: #include <bio/bio_writer.h>
        !            26: 
        !            27: #include <daemon.h>
        !            28: 
        !            29: typedef struct private_eap_radius_t private_eap_radius_t;
        !            30: 
        !            31: /**
        !            32:  * Private data of an eap_radius_t object.
        !            33:  */
        !            34: struct private_eap_radius_t {
        !            35: 
        !            36:        /**
        !            37:         * Public authenticator_t interface.
        !            38:         */
        !            39:        eap_radius_t public;
        !            40: 
        !            41:        /**
        !            42:         * ID of the server
        !            43:         */
        !            44:        identification_t *server;
        !            45: 
        !            46:        /**
        !            47:         * ID of the peer
        !            48:         */
        !            49:        identification_t *peer;
        !            50: 
        !            51:        /**
        !            52:         * EAP method type we are proxying
        !            53:         */
        !            54:        eap_type_t type;
        !            55: 
        !            56:        /**
        !            57:         * EAP vendor, if any
        !            58:         */
        !            59:        uint32_t vendor;
        !            60: 
        !            61:        /**
        !            62:         * EAP message identifier
        !            63:         */
        !            64:        uint8_t identifier;
        !            65: 
        !            66:        /**
        !            67:         * RADIUS client instance
        !            68:         */
        !            69:        radius_client_t *client;
        !            70: 
        !            71:        /**
        !            72:         * TRUE to use EAP-Start, FALSE to send EAP-Identity Response directly
        !            73:         */
        !            74:        bool eap_start;
        !            75: 
        !            76:        /**
        !            77:         * Prefix to prepend to EAP identity
        !            78:         */
        !            79:        char *id_prefix;
        !            80: };
        !            81: 
        !            82: /**
        !            83:  * Add EAP-Identity to RADIUS message
        !            84:  */
        !            85: static void add_eap_identity(private_eap_radius_t *this,
        !            86:                                                         radius_message_t *request)
        !            87: {
        !            88:        struct {
        !            89:                /** EAP code (REQUEST/RESPONSE) */
        !            90:                uint8_t code;
        !            91:                /** unique message identifier */
        !            92:                uint8_t identifier;
        !            93:                /** length of whole message */
        !            94:                uint16_t length;
        !            95:                /** EAP type */
        !            96:                uint8_t type;
        !            97:                /** identity data */
        !            98:                uint8_t data[];
        !            99:        } __attribute__((__packed__)) *hdr;
        !           100:        chunk_t id, prefix;
        !           101:        size_t len;
        !           102: 
        !           103:        id = this->peer->get_encoding(this->peer);
        !           104:        prefix = chunk_create(this->id_prefix, strlen(this->id_prefix));
        !           105:        len = sizeof(*hdr) + prefix.len + id.len;
        !           106: 
        !           107:        hdr = alloca(len);
        !           108:        hdr->code = EAP_RESPONSE;
        !           109:        hdr->identifier = this->identifier;
        !           110:        hdr->length = htons(len);
        !           111:        hdr->type = EAP_IDENTITY;
        !           112:        memcpy(hdr->data, prefix.ptr, prefix.len);
        !           113:        memcpy(hdr->data + prefix.len, id.ptr, id.len);
        !           114: 
        !           115:        request->add(request, RAT_EAP_MESSAGE, chunk_create((u_char*)hdr, len));
        !           116: }
        !           117: 
        !           118: /**
        !           119:  * Copy EAP-Message attribute from RADIUS message to an new EAP payload
        !           120:  */
        !           121: static bool radius2ike(private_eap_radius_t *this,
        !           122:                                           radius_message_t *msg, eap_payload_t **out)
        !           123: {
        !           124:        enumerator_t *enumerator;
        !           125:        eap_payload_t *payload;
        !           126:        chunk_t data, message = chunk_empty;
        !           127:        int type;
        !           128: 
        !           129:        enumerator = msg->create_enumerator(msg);
        !           130:        while (enumerator->enumerate(enumerator, &type, &data))
        !           131:        {
        !           132:                if (type == RAT_EAP_MESSAGE && data.len)
        !           133:                {
        !           134:                        message = chunk_cat("mc", message, data);
        !           135:                }
        !           136:        }
        !           137:        enumerator->destroy(enumerator);
        !           138:        if (message.len)
        !           139:        {
        !           140:                *out = payload = eap_payload_create_data(message);
        !           141: 
        !           142:                /* apply EAP method selected by RADIUS server */
        !           143:                this->type = payload->get_type(payload, &this->vendor);
        !           144: 
        !           145:                DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &message);
        !           146:                free(message.ptr);
        !           147:                return TRUE;
        !           148:        }
        !           149:        return FALSE;
        !           150: }
        !           151: 
        !           152: /**
        !           153:  * See header.
        !           154:  */
        !           155: void eap_radius_build_attributes(radius_message_t *request)
        !           156: {
        !           157:        ike_sa_t *ike_sa;
        !           158:        host_t *host;
        !           159:        char buf[40], *station_id_fmt, *session_id;
        !           160:        uint32_t value;
        !           161:        chunk_t chunk;
        !           162: 
        !           163:        /* virtual NAS-Port-Type */
        !           164:        value = htonl(5);
        !           165:        request->add(request, RAT_NAS_PORT_TYPE, chunk_from_thing(value));
        !           166:        /* framed ServiceType */
        !           167:        value = htonl(2);
        !           168:        request->add(request, RAT_SERVICE_TYPE, chunk_from_thing(value));
        !           169: 
        !           170:        ike_sa = charon->bus->get_sa(charon->bus);
        !           171:        if (ike_sa)
        !           172:        {
        !           173:                value = htonl(ike_sa->get_unique_id(ike_sa));
        !           174:                request->add(request, RAT_NAS_PORT, chunk_from_thing(value));
        !           175:                request->add(request, RAT_NAS_PORT_ID,
        !           176:                                         chunk_from_str(ike_sa->get_name(ike_sa)));
        !           177: 
        !           178:                host = ike_sa->get_my_host(ike_sa);
        !           179:                chunk = host->get_address(host);
        !           180:                switch (host->get_family(host))
        !           181:                {
        !           182:                        case AF_INET:
        !           183:                                request->add(request, RAT_NAS_IP_ADDRESS, chunk);
        !           184:                                break;
        !           185:                        case AF_INET6:
        !           186:                                request->add(request, RAT_NAS_IPV6_ADDRESS, chunk);
        !           187:                        default:
        !           188:                                break;
        !           189:                }
        !           190:                if (lib->settings->get_bool(lib->settings,
        !           191:                                                                        "%s.plugins.eap-radius.station_id_with_port",
        !           192:                                                                        TRUE, lib->ns))
        !           193:                {
        !           194:                        station_id_fmt = "%#H";
        !           195:                }
        !           196:                else
        !           197:                {
        !           198:                        station_id_fmt = "%H";
        !           199:                }
        !           200:                snprintf(buf, sizeof(buf), station_id_fmt, host);
        !           201:                request->add(request, RAT_CALLED_STATION_ID, chunk_from_str(buf));
        !           202:                host = ike_sa->get_other_host(ike_sa);
        !           203:                snprintf(buf, sizeof(buf), station_id_fmt, host);
        !           204:                request->add(request, RAT_CALLING_STATION_ID, chunk_from_str(buf));
        !           205: 
        !           206:                session_id = eap_radius_accounting_session_id(ike_sa);
        !           207:                if (session_id)
        !           208:                {
        !           209:                        request->add(request, RAT_ACCT_SESSION_ID,
        !           210:                                                 chunk_from_str(session_id));
        !           211:                        free(session_id);
        !           212:                }
        !           213:        }
        !           214: }
        !           215: 
        !           216: /**
        !           217:  * Add a set of RADIUS attributes to a request message
        !           218:  */
        !           219: static void add_radius_request_attrs(private_eap_radius_t *this,
        !           220:                                                                         radius_message_t *request)
        !           221: {
        !           222:        chunk_t chunk;
        !           223: 
        !           224:        chunk = chunk_from_str(this->id_prefix);
        !           225:        chunk = chunk_cata("cc", chunk, this->peer->get_encoding(this->peer));
        !           226:        request->add(request, RAT_USER_NAME, chunk);
        !           227: 
        !           228:        eap_radius_build_attributes(request);
        !           229:        eap_radius_forward_from_ike(request);
        !           230: }
        !           231: 
        !           232: METHOD(eap_method_t, initiate, status_t,
        !           233:        private_eap_radius_t *this, eap_payload_t **out)
        !           234: {
        !           235:        radius_message_t *request, *response;
        !           236:        status_t status = FAILED;
        !           237: 
        !           238:        request = radius_message_create(RMC_ACCESS_REQUEST);
        !           239:        add_radius_request_attrs(this, request);
        !           240: 
        !           241:        if (this->eap_start)
        !           242:        {
        !           243:                request->add(request, RAT_EAP_MESSAGE, chunk_empty);
        !           244:        }
        !           245:        else
        !           246:        {
        !           247:                add_eap_identity(this, request);
        !           248:        }
        !           249: 
        !           250:        response = this->client->request(this->client, request);
        !           251:        if (response)
        !           252:        {
        !           253:                eap_radius_forward_to_ike(response);
        !           254:                switch (response->get_code(response))
        !           255:                {
        !           256:                        case RMC_ACCESS_CHALLENGE:
        !           257:                                if (radius2ike(this, response, out))
        !           258:                                {
        !           259:                                        status = NEED_MORE;
        !           260:                                }
        !           261:                                break;
        !           262:                        case RMC_ACCESS_ACCEPT:
        !           263:                                /* Microsoft RADIUS servers can run in a mode where they respond
        !           264:                                 * like this on the first request (i.e. without authentication),
        !           265:                                 * we treat this as Access-Reject */
        !           266:                        case RMC_ACCESS_REJECT:
        !           267:                        default:
        !           268:                                DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
        !           269:                                         this->peer);
        !           270:                                break;
        !           271:                }
        !           272:                response->destroy(response);
        !           273:        }
        !           274:        else
        !           275:        {
        !           276:                eap_radius_handle_timeout(NULL);
        !           277:        }
        !           278:        request->destroy(request);
        !           279:        return status;
        !           280: }
        !           281: 
        !           282: /**
        !           283:  * Handle the Class attribute
        !           284:  */
        !           285: static void process_class(radius_message_t *msg)
        !           286: {
        !           287:        enumerator_t *enumerator;
        !           288:        ike_sa_t *ike_sa;
        !           289:        identification_t *id;
        !           290:        auth_cfg_t *auth;
        !           291:        chunk_t data;
        !           292:        bool class_group, class_send;
        !           293:        int type;
        !           294: 
        !           295:        class_group = lib->settings->get_bool(lib->settings,
        !           296:                                "%s.plugins.eap-radius.class_group", FALSE, lib->ns);
        !           297:        class_send = lib->settings->get_bool(lib->settings,
        !           298:                                "%s.plugins.eap-radius.accounting_send_class", FALSE, lib->ns);
        !           299:        ike_sa = charon->bus->get_sa(charon->bus);
        !           300: 
        !           301:        if ((!class_group && !class_send) || !ike_sa)
        !           302:        {
        !           303:                return;
        !           304:        }
        !           305: 
        !           306:        enumerator = msg->create_enumerator(msg);
        !           307:        while (enumerator->enumerate(enumerator, &type, &data))
        !           308:        {
        !           309:                if (type == RAT_CLASS)
        !           310:                {
        !           311:                        if (class_group && data.len < 44)
        !           312:                        {       /* quirk: ignore long class attributes, these are used for
        !           313:                                 * other purposes by some RADIUS servers (such as NPS). */
        !           314:                                auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
        !           315:                                id = identification_create_from_data(data);
        !           316:                                DBG1(DBG_CFG, "received group membership '%Y' from RADIUS",
        !           317:                                         id);
        !           318:                                auth->add(auth, AUTH_RULE_GROUP, id);
        !           319:                        }
        !           320:                        if (class_send)
        !           321:                        {
        !           322:                                eap_radius_accounting_add_class(ike_sa, data);
        !           323:                        }
        !           324:                }
        !           325:        }
        !           326:        enumerator->destroy(enumerator);
        !           327: }
        !           328: 
        !           329: /**
        !           330:  * Handle the Filter-Id attribute as IPsec CHILD_SA name
        !           331:  */
        !           332: static void process_filter_id(radius_message_t *msg)
        !           333: {
        !           334:        enumerator_t *enumerator;
        !           335:        int type;
        !           336:        uint8_t tunnel_tag;
        !           337:        uint32_t tunnel_type;
        !           338:        chunk_t filter_id = chunk_empty, data;
        !           339:        bool is_esp_tunnel = FALSE;
        !           340: 
        !           341:        enumerator = msg->create_enumerator(msg);
        !           342:        while (enumerator->enumerate(enumerator, &type, &data))
        !           343:        {
        !           344:                switch (type)
        !           345:                {
        !           346:                        case RAT_TUNNEL_TYPE:
        !           347:                                if (data.len != 4)
        !           348:                                {
        !           349:                                        continue;
        !           350:                                }
        !           351:                                tunnel_tag = *data.ptr;
        !           352:                                *data.ptr = 0x00;
        !           353:                                tunnel_type = untoh32(data.ptr);
        !           354:                                DBG1(DBG_IKE, "received RADIUS attribute Tunnel-Type: "
        !           355:                                                          "tag = %u, value = %u", tunnel_tag, tunnel_type);
        !           356:                                is_esp_tunnel = (tunnel_type == RADIUS_TUNNEL_TYPE_ESP);
        !           357:                                break;
        !           358:                        case RAT_FILTER_ID:
        !           359:                                filter_id = data;
        !           360:                                DBG1(DBG_IKE, "received RADIUS attribute Filter-Id: "
        !           361:                                                          "'%.*s'", (int)filter_id.len, filter_id.ptr);
        !           362:                                break;
        !           363:                        default:
        !           364:                                break;
        !           365:                }
        !           366:        }
        !           367:        enumerator->destroy(enumerator);
        !           368: 
        !           369:        if (is_esp_tunnel && filter_id.len)
        !           370:        {
        !           371:                identification_t *id;
        !           372:                ike_sa_t *ike_sa;
        !           373:                auth_cfg_t *auth;
        !           374: 
        !           375:                ike_sa = charon->bus->get_sa(charon->bus);
        !           376:                if (ike_sa)
        !           377:                {
        !           378:                        auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
        !           379:                        id = identification_create_from_data(filter_id);
        !           380:                        auth->add(auth, AUTH_RULE_GROUP, id);
        !           381:                }
        !           382:        }
        !           383: }
        !           384: 
        !           385: /**
        !           386:  * Handle Session-Timeout attribute and Interim updates
        !           387:  */
        !           388: static void process_timeout(radius_message_t *msg)
        !           389: {
        !           390:        enumerator_t *enumerator;
        !           391:        ike_sa_t *ike_sa;
        !           392:        chunk_t data;
        !           393:        int type;
        !           394: 
        !           395:        ike_sa = charon->bus->get_sa(charon->bus);
        !           396:        if (ike_sa)
        !           397:        {
        !           398:                enumerator = msg->create_enumerator(msg);
        !           399:                while (enumerator->enumerate(enumerator, &type, &data))
        !           400:                {
        !           401:                        if (type == RAT_SESSION_TIMEOUT && data.len == 4)
        !           402:                        {
        !           403:                                ike_sa->set_auth_lifetime(ike_sa, untoh32(data.ptr));
        !           404:                        }
        !           405:                        else if (type == RAT_ACCT_INTERIM_INTERVAL && data.len == 4)
        !           406:                        {
        !           407:                                eap_radius_accounting_start_interim(ike_sa, untoh32(data.ptr));
        !           408:                        }
        !           409:                }
        !           410:                enumerator->destroy(enumerator);
        !           411:        }
        !           412: }
        !           413: 
        !           414: /**
        !           415:  * Add a Cisco Unity configuration attribute
        !           416:  */
        !           417: static void add_unity_attribute(eap_radius_provider_t *provider, uint32_t id,
        !           418:                                                                int type, chunk_t data)
        !           419: {
        !           420:        switch (type)
        !           421:        {
        !           422:                case 15: /* CVPN3000-IPSec-Banner1 */
        !           423:                case 36: /* CVPN3000-IPSec-Banner2 */
        !           424:                        provider->add_attribute(provider, id, UNITY_BANNER, data);
        !           425:                        break;
        !           426:                case 28: /* CVPN3000-IPSec-Default-Domain */
        !           427:                        provider->add_attribute(provider, id, UNITY_DEF_DOMAIN, data);
        !           428:                        break;
        !           429:                case 29: /* CVPN3000-IPSec-Split-DNS-Names */
        !           430:                        provider->add_attribute(provider, id, UNITY_SPLITDNS_NAME, data);
        !           431:                        break;
        !           432:        }
        !           433: }
        !           434: 
        !           435: /**
        !           436:  * Add a DNS/NBNS configuration attribute
        !           437:  */
        !           438: static void add_nameserver_attribute(eap_radius_provider_t *provider,
        !           439:                                                                         uint32_t id, int type, chunk_t data)
        !           440: {
        !           441:        /* these are from different vendors, but there is currently no conflict */
        !           442:        switch (type)
        !           443:        {
        !           444:                case  5: /* CVPN3000-Primary-DNS */
        !           445:                case  6: /* CVPN3000-Secondary-DNS */
        !           446:                case 28: /* MS-Primary-DNS-Server */
        !           447:                case 29: /* MS-Secondary-DNS-Server */
        !           448:                        provider->add_attribute(provider, id, INTERNAL_IP4_DNS, data);
        !           449:                        break;
        !           450:                case  7: /* CVPN3000-Primary-WINS */
        !           451:                case  8: /* CVPN3000-Secondary-WINS */
        !           452:                case 30: /* MS-Primary-NBNS-Server */
        !           453:                case 31: /* MS-Secondary-NBNS-Server */
        !           454:                        provider->add_attribute(provider, id, INTERNAL_IP4_NBNS, data);
        !           455:                        break;
        !           456:                case RAT_FRAMED_IPV6_DNS_SERVER:
        !           457:                        provider->add_attribute(provider, id, INTERNAL_IP6_DNS, data);
        !           458:                        break;
        !           459:        }
        !           460: }
        !           461: 
        !           462: /**
        !           463:  * Add a UNITY_LOCAL_LAN or UNITY_SPLIT_INCLUDE attribute
        !           464:  */
        !           465: static void add_unity_split_attribute(eap_radius_provider_t *provider,
        !           466:                                                        uint32_t id, configuration_attribute_type_t type,
        !           467:                                                        chunk_t data)
        !           468: {
        !           469:        enumerator_t *enumerator;
        !           470:        bio_writer_t *writer;
        !           471:        char buffer[256], *token, *slash;
        !           472: 
        !           473:        if (snprintf(buffer, sizeof(buffer), "%.*s", (int)data.len,
        !           474:                                 data.ptr) >= sizeof(buffer))
        !           475:        {
        !           476:                return;
        !           477:        }
        !           478:        writer = bio_writer_create(16); /* two IPv4 addresses and 6 bytes padding */
        !           479:        enumerator = enumerator_create_token(buffer, ",", " ");
        !           480:        while (enumerator->enumerate(enumerator, &token))
        !           481:        {
        !           482:                host_t *net, *mask = NULL;
        !           483:                chunk_t padding;
        !           484: 
        !           485:                slash = strchr(token, '/');
        !           486:                if (slash)
        !           487:                {
        !           488:                        *slash++ = '\0';
        !           489:                        mask = host_create_from_string(slash, 0);
        !           490:                }
        !           491:                if (!mask)
        !           492:                {       /* default to /32 */
        !           493:                        mask = host_create_from_string("255.255.255.255", 0);
        !           494:                }
        !           495:                net = host_create_from_string(token, 0);
        !           496:                if (!net || net->get_family(net) != AF_INET ||
        !           497:                         mask->get_family(mask) != AF_INET)
        !           498:                {
        !           499:                        mask->destroy(mask);
        !           500:                        DESTROY_IF(net);
        !           501:                        continue;
        !           502:                }
        !           503:                writer->write_data(writer, net->get_address(net));
        !           504:                writer->write_data(writer, mask->get_address(mask));
        !           505:                padding = writer->skip(writer, 6); /* 6 bytes padding */
        !           506:                memset(padding.ptr, 0, padding.len);
        !           507:                mask->destroy(mask);
        !           508:                net->destroy(net);
        !           509:        }
        !           510:        enumerator->destroy(enumerator);
        !           511: 
        !           512:        data = writer->get_buf(writer);
        !           513:        if (data.len)
        !           514:        {
        !           515:                provider->add_attribute(provider, id, type, data);
        !           516:        }
        !           517:        writer->destroy(writer);
        !           518: }
        !           519: 
        !           520: /**
        !           521:  * Handle Framed-IP-Address and other IKE configuration attributes
        !           522:  */
        !           523: static void process_cfg_attributes(radius_message_t *msg)
        !           524: {
        !           525:        eap_radius_provider_t *provider;
        !           526:        enumerator_t *enumerator;
        !           527:        ike_sa_t *ike_sa;
        !           528:        host_t *host;
        !           529:        chunk_t data;
        !           530:        configuration_attribute_type_t split_type = 0;
        !           531:        int type, vendor;
        !           532: 
        !           533:        ike_sa = charon->bus->get_sa(charon->bus);
        !           534:        provider = eap_radius_provider_get();
        !           535:        if (provider && ike_sa)
        !           536:        {
        !           537:                enumerator = msg->create_enumerator(msg);
        !           538:                while (enumerator->enumerate(enumerator, &type, &data))
        !           539:                {
        !           540:                        if ((type == RAT_FRAMED_IP_ADDRESS && data.len == 4) ||
        !           541:                                (type == RAT_FRAMED_IPV6_ADDRESS && data.len == 16))
        !           542:                        {
        !           543:                                host = host_create_from_chunk(AF_UNSPEC, data, 0);
        !           544:                                if (host)
        !           545:                                {
        !           546:                                        provider->add_framed_ip(provider,
        !           547:                                                                        ike_sa->get_unique_id(ike_sa), host);
        !           548:                                }
        !           549:                        }
        !           550:                        else if (type == RAT_FRAMED_IP_NETMASK && data.len == 4)
        !           551:                        {
        !           552:                                provider->add_attribute(provider, ike_sa->get_unique_id(ike_sa),
        !           553:                                                                                INTERNAL_IP4_NETMASK, data);
        !           554:                        }
        !           555:                        else if (type == RAT_FRAMED_IPV6_DNS_SERVER && data.len == 16)
        !           556:                        {
        !           557:                                add_nameserver_attribute(provider,
        !           558:                                                                        ike_sa->get_unique_id(ike_sa), type, data);
        !           559:                        }
        !           560:                }
        !           561:                enumerator->destroy(enumerator);
        !           562: 
        !           563:                enumerator = msg->create_vendor_enumerator(msg);
        !           564:                while (enumerator->enumerate(enumerator, &vendor, &type, &data))
        !           565:                {
        !           566:                        if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */)
        !           567:                        {
        !           568:                                switch (type)
        !           569:                                {
        !           570:                                        case  5: /* CVPN3000-Primary-DNS */
        !           571:                                        case  6: /* CVPN3000-Secondary-DNS */
        !           572:                                        case  7: /* CVPN3000-Primary-WINS */
        !           573:                                        case  8: /* CVPN3000-Secondary-WINS */
        !           574:                                                if (data.len == 4)
        !           575:                                                {
        !           576:                                                        add_nameserver_attribute(provider,
        !           577:                                                                        ike_sa->get_unique_id(ike_sa), type, data);
        !           578:                                                }
        !           579:                                                break;
        !           580:                                        case 15: /* CVPN3000-IPSec-Banner1 */
        !           581:                                        case 28: /* CVPN3000-IPSec-Default-Domain */
        !           582:                                        case 29: /* CVPN3000-IPSec-Split-DNS-Names */
        !           583:                                        case 36: /* CVPN3000-IPSec-Banner2 */
        !           584:                                                if (ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
        !           585:                                                {
        !           586:                                                        add_unity_attribute(provider,
        !           587:                                                                        ike_sa->get_unique_id(ike_sa), type, data);
        !           588:                                                }
        !           589:                                                break;
        !           590:                                        case 55: /* CVPN3000-IPSec-Split-Tunneling-Policy */
        !           591:                                                if (data.len)
        !           592:                                                {
        !           593:                                                        switch (data.ptr[data.len - 1])
        !           594:                                                        {
        !           595:                                                                case 0: /* tunnelall */
        !           596:                                                                default:
        !           597:                                                                        break;
        !           598:                                                                case 1: /* tunnelspecified */
        !           599:                                                                        split_type = UNITY_SPLIT_INCLUDE;
        !           600:                                                                        break;
        !           601:                                                                case 2: /* excludespecified */
        !           602:                                                                        split_type = UNITY_LOCAL_LAN;
        !           603:                                                                        break;
        !           604:                                                        }
        !           605:                                                }
        !           606:                                                break;
        !           607:                                        default:
        !           608:                                                break;
        !           609:                                }
        !           610:                        }
        !           611:                        if (vendor == PEN_MICROSOFT)
        !           612:                        {
        !           613:                                switch (type)
        !           614:                                {
        !           615:                                        case 28: /* MS-Primary-DNS-Server */
        !           616:                                        case 29: /* MS-Secondary-DNS-Server */
        !           617:                                        case 30: /* MS-Primary-NBNS-Server */
        !           618:                                        case 31: /* MS-Secondary-NBNS-Server */
        !           619:                                                if (data.len == 4)
        !           620:                                                {
        !           621:                                                        add_nameserver_attribute(provider,
        !           622:                                                                        ike_sa->get_unique_id(ike_sa), type, data);
        !           623:                                                }
        !           624:                                                break;
        !           625:                                }
        !           626:                        }
        !           627:                }
        !           628:                enumerator->destroy(enumerator);
        !           629: 
        !           630:                if (split_type != 0 &&
        !           631:                        ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
        !           632:                {
        !           633:                        enumerator = msg->create_vendor_enumerator(msg);
        !           634:                        while (enumerator->enumerate(enumerator, &vendor, &type, &data))
        !           635:                        {
        !           636:                                if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */ &&
        !           637:                                        type == 27 /* CVPN3000-IPSec-Split-Tunnel-List */)
        !           638:                                {
        !           639:                                        add_unity_split_attribute(provider,
        !           640:                                                        ike_sa->get_unique_id(ike_sa), split_type, data);
        !           641:                                }
        !           642:                        }
        !           643:                        enumerator->destroy(enumerator);
        !           644:                }
        !           645:        }
        !           646: }
        !           647: 
        !           648: /**
        !           649:  * See header.
        !           650:  */
        !           651: void eap_radius_process_attributes(radius_message_t *message)
        !           652: {
        !           653:        process_class(message);
        !           654:        if (lib->settings->get_bool(lib->settings,
        !           655:                                                "%s.plugins.eap-radius.filter_id", FALSE, lib->ns))
        !           656:        {
        !           657:                process_filter_id(message);
        !           658:        }
        !           659:        process_timeout(message);
        !           660:        process_cfg_attributes(message);
        !           661: }
        !           662: 
        !           663: METHOD(eap_method_t, process, status_t,
        !           664:        private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out)
        !           665: {
        !           666:        radius_message_t *request, *response;
        !           667:        status_t status = FAILED;
        !           668:        chunk_t data;
        !           669: 
        !           670:        request = radius_message_create(RMC_ACCESS_REQUEST);
        !           671:        add_radius_request_attrs(this, request);
        !           672: 
        !           673:        data = in->get_data(in);
        !           674:        DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &data);
        !           675: 
        !           676:        /* fragment data suitable for RADIUS */
        !           677:        while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
        !           678:        {
        !           679:                request->add(request, RAT_EAP_MESSAGE,
        !           680:                                         chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE));
        !           681:                data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
        !           682:        }
        !           683:        request->add(request, RAT_EAP_MESSAGE, data);
        !           684: 
        !           685:        response = this->client->request(this->client, request);
        !           686:        if (response)
        !           687:        {
        !           688:                eap_radius_forward_to_ike(response);
        !           689:                switch (response->get_code(response))
        !           690:                {
        !           691:                        case RMC_ACCESS_CHALLENGE:
        !           692:                                if (radius2ike(this, response, out))
        !           693:                                {
        !           694:                                        status = NEED_MORE;
        !           695:                                        break;
        !           696:                                }
        !           697:                                status = FAILED;
        !           698:                                break;
        !           699:                        case RMC_ACCESS_ACCEPT:
        !           700:                                eap_radius_process_attributes(response);
        !           701:                                DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful",
        !           702:                                         this->peer);
        !           703:                                status = SUCCESS;
        !           704:                                break;
        !           705:                        case RMC_ACCESS_REJECT:
        !           706:                        default:
        !           707:                                DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
        !           708:                                         this->peer);
        !           709:                                status = FAILED;
        !           710:                                break;
        !           711:                }
        !           712:                response->destroy(response);
        !           713:        }
        !           714:        request->destroy(request);
        !           715:        return status;
        !           716: }
        !           717: 
        !           718: METHOD(eap_method_t, get_type, eap_type_t,
        !           719:        private_eap_radius_t *this, uint32_t *vendor)
        !           720: {
        !           721:        *vendor = this->vendor;
        !           722:        return this->type;
        !           723: }
        !           724: 
        !           725: METHOD(eap_method_t, get_msk, status_t,
        !           726:        private_eap_radius_t *this, chunk_t *out)
        !           727: {
        !           728:        chunk_t msk;
        !           729: 
        !           730:        msk = this->client->get_msk(this->client);
        !           731:        if (msk.len)
        !           732:        {
        !           733:                *out = msk;
        !           734:                return SUCCESS;
        !           735:        }
        !           736:        return FAILED;
        !           737: }
        !           738: 
        !           739: METHOD(eap_method_t, get_identifier, uint8_t,
        !           740:        private_eap_radius_t *this)
        !           741: {
        !           742:        return this->identifier;
        !           743: }
        !           744: 
        !           745: METHOD(eap_method_t, set_identifier, void,
        !           746:        private_eap_radius_t *this, uint8_t identifier)
        !           747: {
        !           748:        this->identifier = identifier;
        !           749: }
        !           750: 
        !           751: METHOD(eap_method_t, is_mutual, bool,
        !           752:        private_eap_radius_t *this)
        !           753: {
        !           754:        switch (this->type)
        !           755:        {
        !           756:                case EAP_AKA:
        !           757:                case EAP_SIM:
        !           758:                        return TRUE;
        !           759:                default:
        !           760:                        return FALSE;
        !           761:        }
        !           762: }
        !           763: 
        !           764: METHOD(eap_method_t, destroy, void,
        !           765:        private_eap_radius_t *this)
        !           766: {
        !           767:        this->peer->destroy(this->peer);
        !           768:        this->server->destroy(this->server);
        !           769:        this->client->destroy(this->client);
        !           770:        free(this);
        !           771: }
        !           772: 
        !           773: /**
        !           774:  * Generic constructor
        !           775:  */
        !           776: eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer)
        !           777: {
        !           778:        private_eap_radius_t *this;
        !           779: 
        !           780:        INIT(this,
        !           781:                .public = {
        !           782:                        .eap_method = {
        !           783:                                .initiate = _initiate,
        !           784:                                .process = _process,
        !           785:                                .get_type = _get_type,
        !           786:                                .is_mutual = _is_mutual,
        !           787:                                .get_msk = _get_msk,
        !           788:                                .get_identifier = _get_identifier,
        !           789:                                .set_identifier = _set_identifier,
        !           790:                                .destroy = _destroy,
        !           791:                        },
        !           792:                },
        !           793:                /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
        !           794:                .type = EAP_RADIUS,
        !           795:                .eap_start = lib->settings->get_bool(lib->settings,
        !           796:                                                                        "%s.plugins.eap-radius.eap_start", FALSE,
        !           797:                                                                        lib->ns),
        !           798:                .id_prefix = lib->settings->get_str(lib->settings,
        !           799:                                                                        "%s.plugins.eap-radius.id_prefix", "",
        !           800:                                                                        lib->ns),
        !           801:        );
        !           802:        this->client = eap_radius_create_client();
        !           803:        if (!this->client)
        !           804:        {
        !           805:                free(this);
        !           806:                return NULL;
        !           807:        }
        !           808:        this->peer = peer->clone(peer);
        !           809:        this->server = server->clone(server);
        !           810:        return &this->public;
        !           811: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>