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

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Martin Willi
                      3:  * Copyright (C) 2013 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "eap_radius_xauth.h"
                     17: #include "eap_radius_plugin.h"
                     18: #include "eap_radius.h"
                     19: #include "eap_radius_forward.h"
                     20: 
                     21: #include <daemon.h>
                     22: #include <radius_client.h>
                     23: #include <collections/array.h>
                     24: 
                     25: 
                     26: typedef struct private_eap_radius_xauth_t private_eap_radius_xauth_t;
                     27: typedef struct xauth_round_t xauth_round_t;
                     28: 
                     29: /**
                     30:  * Configuration for an XAuth authentication exchange
                     31:  */
                     32: struct xauth_round_t {
                     33:        /** XAuth message type to send */
                     34:        configuration_attribute_type_t type;
                     35:        /** Message to present to user */
                     36:        char *message;
                     37: };
                     38: 
                     39: /**
                     40:  * Private data of an eap_radius_xauth_t object.
                     41:  */
                     42: struct private_eap_radius_xauth_t {
                     43: 
                     44:        /**
                     45:         * Public interface.
                     46:         */
                     47:        eap_radius_xauth_t public;
                     48: 
                     49:        /**
                     50:         * ID of the server
                     51:         */
                     52:        identification_t *server;
                     53: 
                     54:        /**
                     55:         * ID of the peer
                     56:         */
                     57:        identification_t *peer;
                     58: 
                     59:        /**
                     60:         * RADIUS connection
                     61:         */
                     62:        radius_client_t *client;
                     63: 
                     64:        /**
                     65:         * XAuth authentication rounds, as xauth_round_t
                     66:         */
                     67:        array_t *rounds;
                     68: 
                     69:        /**
                     70:         * XAuth round currently in progress
                     71:         */
                     72:        xauth_round_t round;
                     73: 
                     74:        /**
                     75:         * Concatenated password of all rounds
                     76:         */
                     77:        chunk_t pass;
                     78: };
                     79: 
                     80: /**
                     81:  * Fetch next XAuth round, add attributes to CP payload
                     82:  */
                     83: static bool build_round(private_eap_radius_xauth_t *this, cp_payload_t *cp)
                     84: {
                     85:        if (!array_remove(this->rounds, ARRAY_HEAD, &this->round))
                     86:        {
                     87:                return FALSE;
                     88:        }
                     89:        cp->add_attribute(cp, configuration_attribute_create_chunk(
                     90:                                        PLV1_CONFIGURATION_ATTRIBUTE, this->round.type, chunk_empty));
                     91: 
                     92:        if (this->round.message && strlen(this->round.message))
                     93:        {
                     94:                cp->add_attribute(cp, configuration_attribute_create_chunk(
                     95:                                        PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_MESSAGE,
                     96:                                        chunk_from_str(this->round.message)));
                     97:        }
                     98:        return TRUE;
                     99: }
                    100: 
                    101: METHOD(xauth_method_t, initiate, status_t,
                    102:        private_eap_radius_xauth_t *this, cp_payload_t **out)
                    103: {
                    104:        cp_payload_t *cp;
                    105: 
                    106:        cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST);
                    107:        /* first message always comes with username */
                    108:        cp->add_attribute(cp, configuration_attribute_create_chunk(
                    109:                                PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty));
                    110: 
                    111:        if (build_round(this, cp))
                    112:        {
                    113:                *out = cp;
                    114:                return NEED_MORE;
                    115:        }
                    116:        cp->destroy(cp);
                    117:        return FAILED;
                    118: }
                    119: 
                    120: /**
                    121:  * Verify a password using RADIUS User-Name/User-Password attributes
                    122:  */
                    123: static status_t verify_radius(private_eap_radius_xauth_t *this)
                    124: {
                    125:        radius_message_t *request, *response;
                    126:        status_t status = FAILED;
                    127: 
                    128:        request = radius_message_create(RMC_ACCESS_REQUEST);
                    129:        request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer));
                    130:        request->add(request, RAT_USER_PASSWORD, this->pass);
                    131: 
                    132:        eap_radius_build_attributes(request);
                    133:        eap_radius_forward_from_ike(request);
                    134: 
                    135:        response = this->client->request(this->client, request);
                    136:        if (response)
                    137:        {
                    138:                eap_radius_forward_to_ike(response);
                    139:                switch (response->get_code(response))
                    140:                {
                    141:                        case RMC_ACCESS_ACCEPT:
                    142:                                eap_radius_process_attributes(response);
                    143:                                status = SUCCESS;
                    144:                                break;
                    145:                        case RMC_ACCESS_CHALLENGE:
                    146:                                DBG1(DBG_IKE, "RADIUS Access-Challenge not supported");
                    147:                                /* FALL */
                    148:                        case RMC_ACCESS_REJECT:
                    149:                        default:
                    150:                                DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
                    151:                                         this->peer);
                    152:                                break;
                    153:                }
                    154:                response->destroy(response);
                    155:        }
                    156:        else
                    157:        {
                    158:                eap_radius_handle_timeout(NULL);
                    159:        }
                    160:        request->destroy(request);
                    161:        return status;
                    162: }
                    163: 
                    164: METHOD(xauth_method_t, process, status_t,
                    165:        private_eap_radius_xauth_t *this, cp_payload_t *in, cp_payload_t **out)
                    166: {
                    167:        configuration_attribute_t *attr;
                    168:        enumerator_t *enumerator;
                    169:        identification_t *id;
                    170:        cp_payload_t *cp;
                    171:        chunk_t user = chunk_empty, pass = chunk_empty;
                    172: 
                    173:        enumerator = in->create_attribute_enumerator(in);
                    174:        while (enumerator->enumerate(enumerator, &attr))
                    175:        {
                    176:                if (attr->get_type(attr) == XAUTH_USER_NAME)
                    177:                {
                    178:                        user = attr->get_chunk(attr);
                    179:                }
                    180:                else if (attr->get_type(attr) == this->round.type)
                    181:                {
                    182:                        pass = attr->get_chunk(attr);
                    183:                        /* trim password to any null termination. As User-Password
                    184:                         * uses null padding, we can't have any null in it, and some
                    185:                         * clients actually send null terminated strings (Android). */
                    186:                        pass.len = strnlen(pass.ptr, pass.len);
                    187:                }
                    188:        }
                    189:        enumerator->destroy(enumerator);
                    190: 
                    191:        if (!pass.ptr)
                    192:        {
                    193:                DBG1(DBG_IKE, "peer did not respond to our XAuth %N request",
                    194:                         configuration_attribute_type_names, this->round.type);
                    195:                return FAILED;
                    196:        }
                    197:        this->pass = chunk_cat("mc", this->pass, pass);
                    198:        if (user.len)
                    199:        {
                    200:                id = identification_create_from_data(user);
                    201:                if (!id)
                    202:                {
                    203:                        DBG1(DBG_IKE, "failed to parse provided XAuth username");
                    204:                        return FAILED;
                    205:                }
                    206:                this->peer->destroy(this->peer);
                    207:                this->peer = id;
                    208:        }
                    209: 
                    210:        if (array_count(this->rounds) == 0)
                    211:        {
                    212:                return verify_radius(this);
                    213:        }
                    214:        cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST);
                    215:        if (build_round(this, cp))
                    216:        {
                    217:                *out = cp;
                    218:                return NEED_MORE;
                    219:        }
                    220:        cp->destroy(cp);
                    221:        return FAILED;
                    222: }
                    223: 
                    224: METHOD(xauth_method_t, get_identity, identification_t*,
                    225:        private_eap_radius_xauth_t *this)
                    226: {
                    227:        return this->peer;
                    228: }
                    229: 
                    230: /**
                    231:  * Parse XAuth round configuration
                    232:  */
                    233: static bool parse_rounds(private_eap_radius_xauth_t *this, char *profile)
                    234: {
                    235:        struct {
                    236:                char *str;
                    237:                configuration_attribute_type_t type;
                    238:        } map[] = {
                    239:                { "password",           XAUTH_USER_PASSWORD,    },
                    240:                { "passcode",           XAUTH_PASSCODE,                 },
                    241:                { "nextpin",            XAUTH_NEXT_PIN,                 },
                    242:                { "answer",                     XAUTH_ANSWER,                   },
                    243:        };
                    244:        enumerator_t *enumerator;
                    245:        char *type, *message;
                    246:        xauth_round_t round;
                    247:        int i;
                    248: 
                    249:        if (!profile || strlen(profile) == 0)
                    250:        {
                    251:                /* no config, fallback to password */
                    252:                round.type = XAUTH_USER_PASSWORD;
                    253:                round.message = NULL;
                    254:                array_insert(this->rounds, ARRAY_TAIL, &round);
                    255:                return TRUE;
                    256:        }
                    257: 
                    258:        enumerator = lib->settings->create_key_value_enumerator(lib->settings,
                    259:                                                        "%s.plugins.eap-radius.xauth.%s", lib->ns, profile);
                    260:        while (enumerator->enumerate(enumerator, &type, &message))
                    261:        {
                    262:                bool invalid = TRUE;
                    263: 
                    264:                for (i = 0; i < countof(map); i++)
                    265:                {
                    266:                        if (strcaseeq(map[i].str, type))
                    267:                        {
                    268:                                round.type = map[i].type;
                    269:                                round.message = message;
                    270:                                array_insert(this->rounds, ARRAY_TAIL, &round);
                    271:                                invalid = FALSE;
                    272:                                break;
                    273:                        }
                    274:                }
                    275:                if (invalid)
                    276:                {
                    277:                        DBG1(DBG_CFG, "invalid XAuth round type: '%s'", type);
                    278:                        enumerator->destroy(enumerator);
                    279:                        return FALSE;
                    280:                }
                    281:        }
                    282:        enumerator->destroy(enumerator);
                    283: 
                    284:        if (array_count(this->rounds) == 0)
                    285:        {
                    286:                DBG1(DBG_CFG, "XAuth configuration profile '%s' invalid", profile);
                    287:                return FALSE;
                    288:        }
                    289:        return TRUE;
                    290: }
                    291: 
                    292: METHOD(xauth_method_t, destroy, void,
                    293:        private_eap_radius_xauth_t *this)
                    294: {
                    295:        DESTROY_IF(this->client);
                    296:        chunk_clear(&this->pass);
                    297:        array_destroy(this->rounds);
                    298:        this->server->destroy(this->server);
                    299:        this->peer->destroy(this->peer);
                    300:        free(this);
                    301: }
                    302: 
                    303: /*
                    304:  * Described in header.
                    305:  */
                    306: eap_radius_xauth_t *eap_radius_xauth_create_server(identification_t *server,
                    307:                                                                                                   identification_t *peer,
                    308:                                                                                                   char *profile)
                    309: {
                    310:        private_eap_radius_xauth_t *this;
                    311: 
                    312:        INIT(this,
                    313:                .public = {
                    314:                        .xauth_method = {
                    315:                                .initiate = _initiate,
                    316:                                .process = _process,
                    317:                                .get_identity = _get_identity,
                    318:                                .destroy = _destroy,
                    319:                        },
                    320:                },
                    321:                .server = server->clone(server),
                    322:                .peer = peer->clone(peer),
                    323:                .client = eap_radius_create_client(),
                    324:                .rounds = array_create(sizeof(xauth_round_t), 0),
                    325:        );
                    326: 
                    327:        if (!parse_rounds(this, profile))
                    328:        {
                    329:                destroy(this);
                    330:                return NULL;
                    331:        }
                    332:        if (!this->client)
                    333:        {
                    334:                destroy(this);
                    335:                return NULL;
                    336:        }
                    337:        return &this->public;
                    338: }

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