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

1.1       misho       1: /*
                      2:  * Copyright (C) 2012 Martin Willi
                      3:  * Copyright (C) 2012 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_forward.h"
                     17: 
                     18: #include <daemon.h>
                     19: #include <collections/linked_list.h>
                     20: #include <collections/hashtable.h>
                     21: #include <threading/mutex.h>
                     22: 
                     23: typedef struct private_eap_radius_forward_t private_eap_radius_forward_t;
                     24: 
                     25: /**
                     26:  * Private data of an eap_radius_forward_t object.
                     27:  */
                     28: struct private_eap_radius_forward_t {
                     29: 
                     30:        /**
                     31:         * Public eap_radius_forward_t interface.
                     32:         */
                     33:        eap_radius_forward_t public;
                     34: 
                     35:        /**
                     36:         * List of attribute types to copy from IKE, as attr_t
                     37:         */
                     38:        linked_list_t *from_attr;
                     39: 
                     40:        /**
                     41:         * List of attribute types to copy to IKE, as attr_t
                     42:         */
                     43:        linked_list_t *to_attr;
                     44: 
                     45:        /**
                     46:         * Queued to forward from IKE, unique_id => linked_list_t of chunk_t
                     47:         */
                     48:        hashtable_t *from;
                     49: 
                     50:        /**
                     51:         * Queued to forward to IKE, unique_id => linked_list_t of chunk_t
                     52:         */
                     53:        hashtable_t *to;
                     54: 
                     55:        /**
                     56:         * Mutex to lock concurrent access to hashtables
                     57:         */
                     58:        mutex_t *mutex;
                     59: };
                     60: 
                     61: /**
                     62:  * RADIUS attribute selector
                     63:  */
                     64: typedef struct {
                     65:        /** vendor ID, 0 for standard attributes */
                     66:        uint32_t vendor;
                     67:        /** attribute type */
                     68:        uint8_t type;
                     69: } attr_t;
                     70: 
                     71: /**
                     72:  * Single instance of this
                     73:  */
                     74: static private_eap_radius_forward_t *singleton = NULL;
                     75: 
                     76: /**
                     77:  * Free a queue entry
                     78:  */
                     79: static void free_attribute(chunk_t *chunk)
                     80: {
                     81:        free(chunk->ptr);
                     82:        free(chunk);
                     83: }
                     84: 
                     85: /**
                     86:  * Lookup/create an attribute queue from a table
                     87:  */
                     88: static linked_list_t *lookup_queue(private_eap_radius_forward_t *this,
                     89:                                                                   hashtable_t *table)
                     90: {
                     91:        linked_list_t *queue = NULL;
                     92:        ike_sa_t *ike_sa;
                     93:        uintptr_t id;
                     94: 
                     95:        ike_sa = charon->bus->get_sa(charon->bus);
                     96:        if (ike_sa && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN))
                     97:        {
                     98:                id = ike_sa->get_unique_id(ike_sa);
                     99:                this->mutex->lock(this->mutex);
                    100:                queue = table->get(table, (void*)id);
                    101:                if (!queue)
                    102:                {
                    103:                        queue = linked_list_create();
                    104:                        table->put(table, (void*)id, queue);
                    105:                }
                    106:                this->mutex->unlock(this->mutex);
                    107:        }
                    108:        return queue;
                    109: }
                    110: 
                    111: /**
                    112:  * Remove attribute queue from table
                    113:  */
                    114: static void remove_queue(private_eap_radius_forward_t *this,
                    115:                                                 hashtable_t *table, ike_sa_t *ike_sa)
                    116: {
                    117:        linked_list_t *queue;
                    118: 
                    119:        this->mutex->lock(this->mutex);
                    120:        queue = table->remove(table, (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
                    121:        this->mutex->unlock(this->mutex);
                    122:        if (queue)
                    123:        {
                    124:                queue->destroy_function(queue, (void*)free_attribute);
                    125:        }
                    126: }
                    127: 
                    128: /**
                    129:  * Check if RADIUS attribute is contained in selector
                    130:  */
                    131: static bool is_attribute_selected(linked_list_t *selector,
                    132:                                                                  radius_attribute_type_t type, chunk_t data)
                    133: {
                    134:        enumerator_t *enumerator;
                    135:        uint32_t vendor = 0;
                    136:        attr_t *sel;
                    137:        bool found = FALSE;
                    138: 
                    139:        if (type == RAT_VENDOR_SPECIFIC)
                    140:        {
                    141:                if (data.len < 4)
                    142:                {
                    143:                        return FALSE;
                    144:                }
                    145:                vendor = untoh32(data.ptr);
                    146:        }
                    147:        enumerator = selector->create_enumerator(selector);
                    148:        while (!found && enumerator->enumerate(enumerator, &sel))
                    149:        {
                    150:                if (sel->vendor == vendor)
                    151:                {
                    152:                        if (vendor)
                    153:                        {
                    154:                                if (sel->type == 0)
                    155:                                {       /* any of that vendor is fine */
                    156:                                        found = TRUE;
                    157:                                }
                    158:                                else if (data.len > 4 && data.ptr[4] == sel->type)
                    159:                                {       /* vendor specific type field, as defined in RFC 2865 */
                    160:                                        found = TRUE;
                    161:                                }
                    162:                        }
                    163:                        else
                    164:                        {
                    165:                                if (sel->type == type)
                    166:                                {
                    167:                                        found = TRUE;
                    168:                                }
                    169:                        }
                    170:                }
                    171:        }
                    172:        enumerator->destroy(enumerator);
                    173: 
                    174:        return found;
                    175: }
                    176: 
                    177: /**
                    178:  * Copy RADIUS attributes from queue to a RADIUS message
                    179:  */
                    180: static void queue2radius(linked_list_t *queue, radius_message_t *message)
                    181: {
                    182:        chunk_t *data;
                    183: 
                    184:        while (queue->remove_last(queue, (void**)&data) == SUCCESS)
                    185:        {
                    186:                if (data->len >= 2)
                    187:                {
                    188:                        message->add(message, data->ptr[0], chunk_skip(*data, 2));
                    189:                }
                    190:                free_attribute(data);
                    191:        }
                    192: }
                    193: 
                    194: /**
                    195:  * Copy RADIUS attributes from a RADIUS message to the queue
                    196:  */
                    197: static void radius2queue(radius_message_t *message, linked_list_t *queue,
                    198:                                                 linked_list_t *selector)
                    199: {
                    200:        enumerator_t *enumerator;
                    201:        int type;
                    202:        chunk_t data, hdr, *ptr;
                    203: 
                    204:        enumerator = message->create_enumerator(message);
                    205:        while (enumerator->enumerate(enumerator, &type, &data))
                    206:        {
                    207:                if (is_attribute_selected(selector, type, data))
                    208:                {
                    209:                        hdr = chunk_alloc(2);
                    210:                        hdr.ptr[0] = type;
                    211:                        hdr.ptr[1] = data.len + 2;
                    212: 
                    213:                        INIT(ptr);
                    214:                        *ptr = chunk_cat("mc", hdr, data);
                    215:                        queue->insert_last(queue, ptr);
                    216:                }
                    217:        }
                    218:        enumerator->destroy(enumerator);
                    219: }
                    220: 
                    221: /**
                    222:  * Copy RADIUS attribute nofifies from IKE message to queue
                    223:  */
                    224: static void ike2queue(message_t *message, linked_list_t *queue,
                    225:                                          linked_list_t *selector)
                    226: {
                    227:        enumerator_t *enumerator;
                    228:        payload_t *payload;
                    229:        notify_payload_t *notify;
                    230:        chunk_t data, *ptr;
                    231: 
                    232:        enumerator = message->create_payload_enumerator(message);
                    233:        while (enumerator->enumerate(enumerator, &payload))
                    234:        {
                    235:                if (payload->get_type(payload) == PLV2_NOTIFY ||
                    236:                        payload->get_type(payload) == PLV1_NOTIFY)
                    237:                {
                    238:                        notify = (notify_payload_t*)payload;
                    239:                        if (notify->get_notify_type(notify) == RADIUS_ATTRIBUTE)
                    240:                        {
                    241:                                data = notify->get_notification_data(notify);
                    242:                                if (data.len >= 2 && is_attribute_selected(selector,
                    243:                                                                                data.ptr[0], chunk_skip(data, 2)))
                    244:                                {
                    245:                                        INIT(ptr);
                    246:                                        *ptr = chunk_clone(data);
                    247:                                        queue->insert_last(queue, ptr);
                    248:                                }
                    249:                        }
                    250:                }
                    251:        }
                    252:        enumerator->destroy(enumerator);
                    253: }
                    254: 
                    255: /**
                    256:  * Copy RADUIS attributes from queue to IKE message notifies
                    257:  */
                    258: static void queue2ike(linked_list_t *queue, message_t *message)
                    259: {
                    260:        chunk_t *data;
                    261: 
                    262:        while (queue->remove_last(queue, (void**)&data) == SUCCESS)
                    263:        {
                    264:                message->add_notify(message, FALSE, RADIUS_ATTRIBUTE, *data);
                    265:                free_attribute(data);
                    266:        }
                    267: }
                    268: 
                    269: /**
                    270:  * See header.
                    271:  */
                    272: void eap_radius_forward_from_ike(radius_message_t *request)
                    273: {
                    274:        private_eap_radius_forward_t *this = singleton;
                    275:        linked_list_t *queue;
                    276: 
                    277:        if (this)
                    278:        {
                    279:                queue = lookup_queue(this, this->from);
                    280:                if (queue)
                    281:                {
                    282:                        queue2radius(queue, request);
                    283:                }
                    284:        }
                    285: }
                    286: 
                    287: /**
                    288:  * See header.
                    289:  */
                    290: void eap_radius_forward_to_ike(radius_message_t *response)
                    291: {
                    292:        private_eap_radius_forward_t *this = singleton;
                    293:        linked_list_t *queue;
                    294: 
                    295:        if (this)
                    296:        {
                    297:                queue = lookup_queue(this, this->to);
                    298:                if (queue)
                    299:                {
                    300:                        radius2queue(response, queue, this->to_attr);
                    301:                }
                    302:        }
                    303: }
                    304: 
                    305: METHOD(listener_t, message, bool,
                    306:        private_eap_radius_forward_t *this,
                    307:        ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain)
                    308: {
                    309:        linked_list_t *queue;
                    310: 
                    311:        if (plain && message->get_exchange_type(message) == IKE_AUTH)
                    312:        {
                    313:                if (incoming)
                    314:                {
                    315:                        queue = lookup_queue(this, this->from);
                    316:                        if (queue)
                    317:                        {
                    318:                                ike2queue(message, queue, this->from_attr);
                    319:                        }
                    320:                }
                    321:                else
                    322:                {
                    323:                        queue = lookup_queue(this, this->to);
                    324:                        if (queue)
                    325:                        {
                    326:                                queue2ike(queue, message);
                    327:                        }
                    328:                }
                    329:        }
                    330:        return TRUE;
                    331: }
                    332: 
                    333: METHOD(listener_t, ike_updown, bool,
                    334:        private_eap_radius_forward_t *this, ike_sa_t *ike_sa, bool up)
                    335: {
                    336:        /* up or down, we don't need the state anymore */
                    337:        remove_queue(this, this->from, ike_sa);
                    338:        remove_queue(this, this->to, ike_sa);
                    339:        return TRUE;
                    340: }
                    341: 
                    342: /**
                    343:  * Parse a selector string to a list of attr_t selectors
                    344:  */
                    345: static linked_list_t* parse_selector(char *selector)
                    346: {
                    347:        enumerator_t *enumerator;
                    348:        linked_list_t *list;
                    349:        char *token, *pos;
                    350: 
                    351:        list = linked_list_create();
                    352:        enumerator = enumerator_create_token(selector, ",", " ");
                    353:        while (enumerator->enumerate(enumerator, &token))
                    354:        {
                    355:                int type, vendor = 0;
                    356:                attr_t *attr;
                    357: 
                    358:                pos = strchr(token, ':');
                    359:                if (pos)
                    360:                {
                    361:                        *(pos++) = 0;
                    362:                        vendor = atoi(token);
                    363:                        token = pos;
                    364:                }
                    365:                if (!enum_from_name(radius_attribute_type_names, token, &type))
                    366:                {
                    367:                        type = atoi(token);
                    368:                }
                    369:                if (vendor == 0 && type == 0)
                    370:                {
                    371:                        DBG1(DBG_CFG, "ignoring unknown RADIUS attribute type '%s'", token);
                    372:                }
                    373:                else
                    374:                {
                    375:                        INIT(attr,
                    376:                                .type = type,
                    377:                                .vendor = vendor,
                    378:                        );
                    379:                        list->insert_last(list, attr);
                    380:                        if (!vendor)
                    381:                        {
                    382:                                DBG1(DBG_IKE, "forwarding RADIUS attribute %N",
                    383:                                         radius_attribute_type_names, type);
                    384:                        }
                    385:                        else
                    386:                        {
                    387:                                DBG1(DBG_IKE, "forwarding RADIUS VSA %d-%d", vendor, type);
                    388:                        }
                    389:                }
                    390:        }
                    391:        enumerator->destroy(enumerator);
                    392:        return list;
                    393: }
                    394: 
                    395: METHOD(eap_radius_forward_t, destroy, void,
                    396:        private_eap_radius_forward_t *this)
                    397: {
                    398:        this->from_attr->destroy_function(this->from_attr, free);
                    399:        this->to_attr->destroy_function(this->to_attr, free);
                    400:        this->from->destroy(this->from);
                    401:        this->to->destroy(this->to);
                    402:        this->mutex->destroy(this->mutex);
                    403:        free(this);
                    404:        singleton = NULL;
                    405: }
                    406: 
                    407: /**
                    408:  * See header
                    409:  */
                    410: eap_radius_forward_t *eap_radius_forward_create()
                    411: {
                    412:        private_eap_radius_forward_t *this;
                    413: 
                    414:        INIT(this,
                    415:                .public = {
                    416:                        .listener = {
                    417:                                .message = _message,
                    418:                                .ike_updown = _ike_updown,
                    419:                        },
                    420:                        .destroy = _destroy,
                    421:                },
                    422:                .from_attr = parse_selector(lib->settings->get_str(lib->settings,
                    423:                                                        "%s.plugins.eap-radius.forward.ike_to_radius", "",
                    424:                                                        lib->ns)),
                    425:                .to_attr = parse_selector(lib->settings->get_str(lib->settings,
                    426:                                                        "%s.plugins.eap-radius.forward.radius_to_ike", "",
                    427:                                                        lib->ns)),
                    428:                .from = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8),
                    429:                .to = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8),
                    430:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    431:        );
                    432: 
                    433:        if (this->from_attr->get_count(this->from_attr) == 0 &&
                    434:                this->to_attr->get_count(this->to_attr) == 0)
                    435:        {
                    436:                destroy(this);
                    437:                return NULL;
                    438:        }
                    439: 
                    440:        singleton = this;
                    441:        return &this->public;
                    442: }

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