Annotation of embedaddon/strongswan/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2012 Andreas Steffen
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "tnc_pdp_connections.h"
                     17: 
                     18: #include <collections/linked_list.h>
                     19: #include <utils/debug.h>
                     20: #include <threading/rwlock.h>
                     21: #include <processing/jobs/callback_job.h>
                     22: 
                     23: #include <daemon.h>
                     24: 
                     25: /**
                     26:  * Default PDP connection timeout, in s
                     27:  */
                     28: #define DEFAULT_TIMEOUT 30
                     29: 
                     30: typedef struct private_tnc_pdp_connections_t private_tnc_pdp_connections_t;
                     31: typedef struct entry_t entry_t;
                     32: 
                     33: /**
                     34:  * Private data of tnc_pdp_connections_t
                     35:  */
                     36: struct private_tnc_pdp_connections_t {
                     37: 
                     38:        /**
                     39:         * Implements tnc_pdp_connections_t interface
                     40:         */
                     41:        tnc_pdp_connections_t public;
                     42: 
                     43:        /**
                     44:         * TNC PEP RADIUS Connections
                     45:         */
                     46:        linked_list_t *list;
                     47: 
                     48:        /**
                     49:         * Lock to access PEP connection list
                     50:         */
                     51:        rwlock_t *lock;
                     52: 
                     53:        /**
                     54:         * Connection timeout before we kill non-completed connections, in s
                     55:         */
                     56:        int timeout;
                     57: };
                     58: 
                     59: /**
                     60:  * Data entry for a TNC PEP RADIUS connection
                     61:  */
                     62: struct entry_t {
                     63: 
                     64:        /**
                     65:         * NAS identifier of PEP
                     66:         */
                     67:        chunk_t nas_id;
                     68: 
                     69:        /**
                     70:         * User name of TNC Client
                     71:         */
                     72:        chunk_t user_name;
                     73: 
                     74:        /**
                     75:         * EAP method state
                     76:         */
                     77:        eap_method_t *method;
                     78: 
                     79:        /**
                     80:         * IKE SA used for bus communication
                     81:         */
                     82:        ike_sa_t *ike_sa;
                     83: 
                     84:        /**
                     85:         * Timestamp this entry has been created
                     86:         */
                     87:        time_t created;
                     88: };
                     89: 
                     90: /**
                     91:  * Free the memory allocated to a data entry
                     92:  */
                     93: static void free_entry(entry_t *this)
                     94: {
                     95:        this->method->destroy(this->method);
                     96:        this->ike_sa->destroy(this->ike_sa);
                     97:        free(this->nas_id.ptr);
                     98:        free(this->user_name.ptr);
                     99:        free(this);
                    100: }
                    101: 
                    102: /**
                    103:  * Find a matching data entry
                    104:  */
                    105: static bool equals_entry( entry_t *this, chunk_t nas_id, chunk_t user_name)
                    106: {
                    107:        bool no_nas_id = !this->nas_id.ptr && !nas_id.ptr;
                    108: 
                    109:        return (chunk_equals(this->nas_id, nas_id) || no_nas_id) &&
                    110:                        chunk_equals(this->user_name, user_name);
                    111: }
                    112: 
                    113: /**
                    114:  * Find a matching data entry
                    115:  */
                    116: static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op)
                    117: {
                    118:        if (nas_id.len)
                    119:        {
                    120:                DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s' NAS '%.*s'",
                    121:                                           not ? "could not find" : op, (int)user_name.len,
                    122:                                           user_name.ptr, (int)nas_id.len, nas_id.ptr);
                    123:        }
                    124:        else
                    125:        {
                    126:                DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'",
                    127:                                           not ? "could not find" : op, (int)user_name.len,
                    128:                                           user_name.ptr);
                    129:        }
                    130: }
                    131: 
                    132: /**
                    133:  * Check if any connection has timed out
                    134:  */
                    135: static job_requeue_t check_timeouts(private_tnc_pdp_connections_t *this)
                    136: {
                    137:        enumerator_t *enumerator;
                    138:        entry_t *entry;
                    139:        time_t now;
                    140: 
                    141:        now = time_monotonic(NULL);
                    142: 
                    143:        this->lock->write_lock(this->lock);
                    144:        enumerator = this->list->create_enumerator(this->list);
                    145:        while (enumerator->enumerate(enumerator, &entry))
                    146:        {
                    147:                if (entry->created + this->timeout <= now)
                    148:                {
                    149:                        DBG1(DBG_CFG, "RADIUS connection timed out after %d seconds",
                    150:                                 this->timeout);
                    151:                        this->list->remove_at(this->list, enumerator);
                    152:                        free_entry(entry);
                    153:                }
                    154:        }
                    155:        enumerator->destroy(enumerator);
                    156:        this->lock->unlock(this->lock);
                    157: 
                    158:        return JOB_REQUEUE_NONE;
                    159: }
                    160: 
                    161: METHOD(tnc_pdp_connections_t, add, void,
                    162:        private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
                    163:        identification_t *peer, eap_method_t *method)
                    164: {
                    165:        enumerator_t *enumerator;
                    166:        entry_t *entry;
                    167:        ike_sa_id_t *ike_sa_id;
                    168:        ike_sa_t *ike_sa;
                    169:        bool found = FALSE;
                    170: 
                    171:        ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, 0, 0, FALSE);
                    172:        ike_sa = ike_sa_create(ike_sa_id, FALSE, IKEV2);
                    173:        ike_sa_id->destroy(ike_sa_id);
                    174:        ike_sa->set_other_id(ike_sa, peer);
                    175: 
                    176:        this->lock->read_lock(this->lock);
                    177:        enumerator = this->list->create_enumerator(this->list);
                    178:        while (enumerator->enumerate(enumerator, &entry))
                    179:        {
                    180:                if (equals_entry(entry, nas_id, user_name))
                    181:                {
                    182:                        found = TRUE;
                    183:                        entry->method->destroy(entry->method);
                    184:                        entry->ike_sa->destroy(entry->ike_sa);
                    185:                        DBG1(DBG_CFG, "removed stale RADIUS connection");
                    186:                        entry->method = method;
                    187:                        entry->ike_sa = ike_sa;
                    188:                        entry->created = time_monotonic(NULL);
                    189:                        break;
                    190:                }
                    191:        }
                    192:        enumerator->destroy(enumerator);
                    193:        this->lock->unlock(this->lock);
                    194: 
                    195:        if (!found)
                    196:        {
                    197:                INIT(entry,
                    198:                        .nas_id = chunk_clone(nas_id),
                    199:                        .user_name = chunk_clone(user_name),
                    200:                        .method = method,
                    201:                        .ike_sa = ike_sa,
                    202:                        .created = time_monotonic(NULL),
                    203:                );
                    204:                this->lock->write_lock(this->lock);
                    205:                this->list->insert_last(this->list, entry);
                    206:                this->lock->unlock(this->lock);
                    207:        }
                    208: 
                    209:        /* schedule timeout checking */
                    210:        lib->scheduler->schedule_job_ms(lib->scheduler,
                    211:                                (job_t*)callback_job_create((callback_job_cb_t)check_timeouts,
                    212:                                        this, NULL, (callback_job_cancel_t)return_false),
                    213:                                this->timeout * 1000);
                    214: 
                    215:        dbg_nas_user(nas_id, user_name, FALSE, "created");
                    216: }
                    217: 
                    218: METHOD(tnc_pdp_connections_t, remove_, void,
                    219:        private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name)
                    220: {
                    221:        enumerator_t *enumerator;
                    222:        entry_t *entry;
                    223: 
                    224:        this->lock->write_lock(this->lock);
                    225:        enumerator = this->list->create_enumerator(this->list);
                    226:        while (enumerator->enumerate(enumerator, &entry))
                    227:        {
                    228:                if (equals_entry(entry, nas_id, user_name))
                    229:                {
                    230:                        free_entry(entry);
                    231:                        this->list->remove_at(this->list, enumerator);
                    232:                        dbg_nas_user(nas_id, user_name, FALSE, "removed");
                    233:                        break;
                    234:                }
                    235:        }
                    236:        enumerator->destroy(enumerator);
                    237:        this->lock->unlock(this->lock);
                    238: }
                    239: 
                    240: METHOD(tnc_pdp_connections_t, get_state, eap_method_t*,
                    241:        private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
                    242:        ike_sa_t **ike_sa)
                    243: {
                    244:        enumerator_t *enumerator;
                    245:        entry_t *entry;
                    246:        eap_method_t *found = NULL;
                    247: 
                    248:        this->lock->read_lock(this->lock);
                    249:        enumerator = this->list->create_enumerator(this->list);
                    250:        while (enumerator->enumerate(enumerator, &entry))
                    251:        {
                    252:                if (equals_entry(entry, nas_id, user_name))
                    253:                {
                    254:                        found = entry->method;
                    255:                        *ike_sa = entry->ike_sa;
                    256:                        break;
                    257:                }
                    258:        }
                    259:        enumerator->destroy(enumerator);
                    260:        if (!found)
                    261:        {
                    262:                this->lock->unlock(this->lock);
                    263:        }
                    264: 
                    265:        dbg_nas_user(nas_id, user_name, !found, "found");
                    266:        return found;
                    267: }
                    268: 
                    269: METHOD(tnc_pdp_connections_t, unlock, void,
                    270:        private_tnc_pdp_connections_t *this)
                    271: {
                    272:        this->lock->unlock(this->lock);
                    273: }
                    274: 
                    275: METHOD(tnc_pdp_connections_t, destroy, void,
                    276:        private_tnc_pdp_connections_t *this)
                    277: {
                    278:        this->lock->destroy(this->lock);
                    279:        this->list->destroy_function(this->list, (void*)free_entry);
                    280:        free(this);
                    281: }
                    282: 
                    283: /*
                    284:  * see header file
                    285:  */
                    286: tnc_pdp_connections_t *tnc_pdp_connections_create(void)
                    287: {
                    288:        private_tnc_pdp_connections_t *this;
                    289: 
                    290:        INIT(this,
                    291:                .public = {
                    292:                        .add = _add,
                    293:                        .remove = _remove_,
                    294:                        .get_state = _get_state,
                    295:                        .unlock = _unlock,
                    296:                        .destroy = _destroy,
                    297:                },
                    298:                .list = linked_list_create(),
                    299:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    300:                .timeout = lib->settings->get_int(lib->settings,
                    301:                                                "%s.plugins.tnc-pdp.timeout", DEFAULT_TIMEOUT, lib->ns),
                    302:        );
                    303: 
                    304:        return &this->public;
                    305: }

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