Annotation of embedaddon/strongswan/src/libimcv/imv/imv_agent.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2011-2015 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 "imcv.h"
                     17: #include "imv_agent.h"
                     18: #include "imv_session.h"
                     19: 
                     20: #include "ietf/ietf_attr_assess_result.h"
                     21: 
                     22: #include <tncif_names.h>
                     23: #include <tncif_identity.h>
                     24: 
                     25: #include <utils/debug.h>
                     26: #include <collections/linked_list.h>
                     27: #include <bio/bio_reader.h>
                     28: #include <threading/rwlock.h>
                     29: 
                     30: typedef struct private_imv_agent_t private_imv_agent_t;
                     31: 
                     32: /**
                     33:  * Private data of an imv_agent_t object.
                     34:  */
                     35: struct private_imv_agent_t {
                     36: 
                     37:        /**
                     38:         * Public members of imv_agent_t
                     39:         */
                     40:        imv_agent_t public;
                     41: 
                     42:        /**
                     43:         * name of IMV
                     44:         */
                     45:        const char *name;
                     46: 
                     47:        /**
                     48:         * message types registered by IMV
                     49:         */
                     50:        pen_type_t *supported_types;
                     51: 
                     52:        /**
                     53:         * number of message types registered by IMV
                     54:         */
                     55:        uint32_t type_count;
                     56: 
                     57:        /**
                     58:         * ID of IMV as assigned by TNCS
                     59:         */
                     60:        TNC_IMVID id;
                     61: 
                     62:        /**
                     63:         * List of additional IMV IDs assigned by TNCS
                     64:         */
                     65:        linked_list_t *additional_ids;
                     66: 
                     67:        /**
                     68:         * list of non-fatal unsupported PA-TNC attribute types
                     69:         */
                     70:        linked_list_t *non_fatal_attr_types;
                     71: 
                     72:        /**
                     73:         * list of TNCS connection entries
                     74:         */
                     75:        linked_list_t *connections;
                     76: 
                     77:        /**
                     78:         * rwlock to lock TNCS connection entries
                     79:         */
                     80:        rwlock_t *connection_lock;
                     81: 
                     82:        /**
                     83:         * Inform a TNCS about the set of message types the IMV is able to receive
                     84:         *
                     85:         * @param imv_id                        IMV ID assigned by TNCS
                     86:         * @param supported_types       list of supported message types
                     87:         * @param type_count            number of list elements
                     88:         * @return                                      TNC result code
                     89:         */
                     90:        TNC_Result (*report_message_types)(TNC_IMVID imv_id,
                     91:                                                                           TNC_MessageTypeList supported_types,
                     92:                                                                           TNC_UInt32 type_count);
                     93: 
                     94:        /**
                     95:         * Inform a TNCS about the set of message types the IMV is able to receive
                     96:         *
                     97:         * @param imv_id                                IMV ID assigned by TNCS
                     98:         * @param supported_vids                list of supported message vendor IDs
                     99:         * @param supported_subtypes    list of supported message subtypes
                    100:         * @param type_count                    number of list elements
                    101:         * @return                                              TNC result code
                    102:         */
                    103:        TNC_Result (*report_message_types_long)(TNC_IMVID imv_id,
                    104:                                                                        TNC_VendorIDList supported_vids,
                    105:                                                                        TNC_MessageSubtypeList supported_subtypes,
                    106:                                                                        TNC_UInt32 type_count);
                    107: 
                    108:        /**
                    109:         * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS
                    110:         *
                    111:         * @param imv_id                        IMV ID assigned by TNCS
                    112:         # @param connection_id         network connection ID assigned by TNCS
                    113:         * @param rec                           IMV action recommendation
                    114:         * @param eval                          IMV evaluation result
                    115:         * @return                                      TNC result code
                    116:         */
                    117:        TNC_Result (*provide_recommendation)(TNC_IMVID imv_id,
                    118:                                                                                 TNC_ConnectionID connection_id,
                    119:                                                                                 TNC_IMV_Action_Recommendation rec,
                    120:                                                                                 TNC_IMV_Evaluation_Result eval);
                    121: 
                    122:        /**
                    123:         * Get the value of an attribute associated with a connection
                    124:         * or with the TNCS as a whole.
                    125:         *
                    126:         * @param imv_id                        IMV ID assigned by TNCS
                    127:         * @param connection_id         network connection ID assigned by TNCS
                    128:         * @param attribute_id          attribute ID
                    129:         * @param buffer_len            length of buffer in bytes
                    130:         * @param buffer                        buffer
                    131:         * @param out_value_len         size in bytes of attribute stored in buffer
                    132:         * @return                                      TNC result code
                    133:         */
                    134:        TNC_Result (*get_attribute)(TNC_IMVID imv_id,
                    135:                                                                TNC_ConnectionID connection_id,
                    136:                                                                TNC_AttributeID attribute_id,
                    137:                                                                TNC_UInt32 buffer_len,
                    138:                                                                TNC_BufferReference buffer,
                    139:                                                                TNC_UInt32 *out_value_len);
                    140: 
                    141:        /**
                    142:         * Set the value of an attribute associated with a connection
                    143:         * or with the TNCS as a whole.
                    144:         *
                    145:         * @param imv_id                        IMV ID assigned by TNCS
                    146:         * @param connection_id         network connection ID assigned by TNCS
                    147:         * @param attribute_id          attribute ID
                    148:         * @param buffer_len            length of buffer in bytes
                    149:         * @param buffer                        buffer
                    150:         * @return                                      TNC result code
                    151:         */
                    152:        TNC_Result (*set_attribute)(TNC_IMVID imv_id,
                    153:                                                                TNC_ConnectionID connection_id,
                    154:                                                                TNC_AttributeID attribute_id,
                    155:                                                                TNC_UInt32 buffer_len,
                    156:                                                                TNC_BufferReference buffer);
                    157: 
                    158:        /**
                    159:         * Reserve an additional IMV ID
                    160:         *
                    161:         * @param imv_id                        primary IMV ID assigned by TNCS
                    162:         * @param out_imv_id            additional IMV ID assigned by TNCS
                    163:         * @return                                      TNC result code
                    164:         */
                    165:        TNC_Result (*reserve_additional_id)(TNC_IMVID imv_id,
                    166:                                                                                TNC_UInt32 *out_imv_id);
                    167: 
                    168: };
                    169: 
                    170: METHOD(imv_agent_t, bind_functions, TNC_Result,
                    171:        private_imv_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
                    172: {
                    173:        if (!bind_function)
                    174:        {
                    175:                DBG1(DBG_IMV, "TNC server failed to provide bind function");
                    176:                return TNC_RESULT_INVALID_PARAMETER;
                    177:        }
                    178:        if (bind_function(this->id, "TNC_TNCS_ReportMessageTypes",
                    179:                        (void**)&this->report_message_types) != TNC_RESULT_SUCCESS)
                    180:        {
                    181:                this->report_message_types = NULL;
                    182:        }
                    183:        if (bind_function(this->id, "TNC_TNCS_ReportMessageTypesLong",
                    184:                        (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
                    185:        {
                    186:                this->report_message_types_long = NULL;
                    187:        }
                    188:        if (bind_function(this->id, "TNC_TNCS_RequestHandshakeRetry",
                    189:                        (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
                    190:        {
                    191:                this->public.request_handshake_retry = NULL;
                    192:        }
                    193:        if (bind_function(this->id, "TNC_TNCS_SendMessage",
                    194:                        (void**)&this->public.send_message) != TNC_RESULT_SUCCESS)
                    195:        {
                    196:                this->public.send_message = NULL;
                    197:        }
                    198:        if (bind_function(this->id, "TNC_TNCS_SendMessageLong",
                    199:                        (void**)&this->public.send_message_long) != TNC_RESULT_SUCCESS)
                    200:        {
                    201:                this->public.send_message_long = NULL;
                    202:        }
                    203:        if (bind_function(this->id, "TNC_TNCS_ProvideRecommendation",
                    204:                        (void**)&this->provide_recommendation) != TNC_RESULT_SUCCESS)
                    205:        {
                    206:                this->provide_recommendation = NULL;
                    207:        }
                    208:        if (bind_function(this->id, "TNC_TNCS_GetAttribute",
                    209:                        (void**)&this->get_attribute) != TNC_RESULT_SUCCESS)
                    210:        {
                    211:                this->get_attribute = NULL;
                    212:        }
                    213:        if (bind_function(this->id, "TNC_TNCS_SetAttribute",
                    214:                        (void**)&this->set_attribute) != TNC_RESULT_SUCCESS)
                    215:        {
                    216:                this->set_attribute = NULL;
                    217:        }
                    218:        if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMVID",
                    219:                        (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS)
                    220:        {
                    221:                this->reserve_additional_id = NULL;
                    222:        }
                    223: 
                    224:        if (this->report_message_types_long)
                    225:        {
                    226:                TNC_VendorIDList vendor_id_list;
                    227:                TNC_MessageSubtypeList subtype_list;
                    228:                int i;
                    229: 
                    230:                vendor_id_list = malloc(this->type_count * sizeof(TNC_UInt32));
                    231:                subtype_list   = malloc(this->type_count * sizeof(TNC_UInt32));
                    232: 
                    233:                for (i = 0; i < this->type_count; i++)
                    234:                {
                    235:                        vendor_id_list[i] = this->supported_types[i].vendor_id;
                    236:                        subtype_list[i]   = this->supported_types[i].type;
                    237:                }
                    238:                this->report_message_types_long(this->id, vendor_id_list, subtype_list,
                    239:                                                                                this->type_count);
                    240:                free(vendor_id_list);
                    241:                free(subtype_list);
                    242:        }
                    243:        else if (this->report_message_types)
                    244:        {
                    245:                TNC_MessageTypeList type_list;
                    246:                int i;
                    247: 
                    248:                type_list = malloc(this->type_count * sizeof(TNC_UInt32));
                    249: 
                    250:                for (i = 0; i < this->type_count; i++)
                    251:                {
                    252:                        type_list[i] = (this->supported_types[i].vendor_id << 8) |
                    253:                                                   (this->supported_types[i].type & 0xff);
                    254:                }
                    255:                this->report_message_types(this->id, type_list, this->type_count);
                    256:                free(type_list);
                    257:        }
                    258:        return TNC_RESULT_SUCCESS;
                    259: }
                    260: 
                    261: /**
                    262:  * finds a connection state based on its Connection ID
                    263:  */
                    264: static imv_state_t* find_connection(private_imv_agent_t *this,
                    265:                                                                         TNC_ConnectionID id)
                    266: {
                    267:        enumerator_t *enumerator;
                    268:        imv_state_t *state, *found = NULL;
                    269: 
                    270:        this->connection_lock->read_lock(this->connection_lock);
                    271:        enumerator = this->connections->create_enumerator(this->connections);
                    272:        while (enumerator->enumerate(enumerator, &state))
                    273:        {
                    274:                if (id == state->get_connection_id(state))
                    275:                {
                    276:                        found = state;
                    277:                        break;
                    278:                }
                    279:        }
                    280:        enumerator->destroy(enumerator);
                    281:        this->connection_lock->unlock(this->connection_lock);
                    282: 
                    283:        return found;
                    284: }
                    285: 
                    286: /**
                    287:  * delete a connection state with a given Connection ID
                    288:  */
                    289: static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id)
                    290: {
                    291:        enumerator_t *enumerator;
                    292:        imv_state_t *state;
                    293:        imv_session_t *session;
                    294:        bool found = FALSE;
                    295: 
                    296:        this->connection_lock->write_lock(this->connection_lock);
                    297:        enumerator = this->connections->create_enumerator(this->connections);
                    298:        while (enumerator->enumerate(enumerator, &state))
                    299:        {
                    300:                if (id == state->get_connection_id(state))
                    301:                {
                    302:                        found = TRUE;
                    303:                        session = state->get_session(state);
                    304:                        imcv_sessions->remove_session(imcv_sessions, session);
                    305:                        state->destroy(state);
                    306:                        this->connections->remove_at(this->connections, enumerator);
                    307:                        break;
                    308:                }
                    309:        }
                    310:        enumerator->destroy(enumerator);
                    311:        this->connection_lock->unlock(this->connection_lock);
                    312: 
                    313:        return found;
                    314: }
                    315: 
                    316: /**
                    317:  * Read a boolean attribute
                    318:  */
                    319: static bool get_bool_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
                    320:                                                           TNC_AttributeID attribute_id)
                    321: {
                    322:        TNC_UInt32 len;
                    323:        char buf[4];
                    324: 
                    325:        return this->get_attribute  &&
                    326:                   this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
                    327:                                                           TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01;
                    328:  }
                    329: 
                    330: /**
                    331:  * Read a string attribute
                    332:  */
                    333: static char* get_str_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
                    334:                                                                TNC_AttributeID attribute_id)
                    335: {
                    336:        TNC_UInt32 len;
                    337:        char buf[BUF_LEN];
                    338: 
                    339:        if (this->get_attribute  &&
                    340:                this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) ==
                    341:                                                        TNC_RESULT_SUCCESS && len <= BUF_LEN)
                    342:        {
                    343:                return strdup(buf);
                    344:        }
                    345:        return NULL;
                    346:  }
                    347: 
                    348: /**
                    349:  * Read an UInt32 attribute
                    350:  */
                    351: static uint32_t get_uint_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
                    352:                                                                        TNC_AttributeID attribute_id)
                    353: {
                    354:        TNC_UInt32 len;
                    355:        char buf[4];
                    356: 
                    357:        if (this->get_attribute  &&
                    358:                this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
                    359:                                                        TNC_RESULT_SUCCESS && len == 4)
                    360:        {
                    361:                return untoh32(buf);
                    362:        }
                    363:        return 0;
                    364:  }
                    365: 
                    366: /**
                    367:  * Read a TNC identity attribute
                    368:  */
                    369: static linked_list_t* get_identity_attribute(private_imv_agent_t *this,
                    370:                                                                                         TNC_ConnectionID id,
                    371:                                                                                         TNC_AttributeID attribute_id)
                    372: {
                    373:        TNC_UInt32 len;
                    374:        char buf[2048];
                    375:        uint32_t count;
                    376:        tncif_identity_t *tnc_id;
                    377:        bio_reader_t *reader;
                    378:        linked_list_t *list;
                    379: 
                    380:        list = linked_list_create();
                    381: 
                    382:        if (!this->get_attribute ||
                    383:                 this->get_attribute(this->id, id, attribute_id, sizeof(buf), buf, &len)
                    384:                                != TNC_RESULT_SUCCESS || len > sizeof(buf))
                    385:        {
                    386:                return list;
                    387:        }
                    388: 
                    389:        reader = bio_reader_create(chunk_create(buf, len));
                    390:        if (!reader->read_uint32(reader, &count))
                    391:        {
                    392:                        goto end;
                    393:        }
                    394:        while (count--)
                    395:        {
                    396:                tnc_id = tncif_identity_create_empty();
                    397:                if (!tnc_id->process(tnc_id, reader))
                    398:                {
                    399:                        tnc_id->destroy(tnc_id);
                    400:                        goto end;
                    401:                }
                    402:                list->insert_last(list, tnc_id);
                    403:        }
                    404: 
                    405: end:
                    406:        reader->destroy(reader);
                    407:        return list;
                    408:  }
                    409: 
                    410: METHOD(imv_agent_t, create_state, TNC_Result,
                    411:        private_imv_agent_t *this, imv_state_t *state)
                    412: {
                    413:        TNC_ConnectionID conn_id;
                    414:        char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL;
                    415:        bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE;
                    416:        linked_list_t *ar_identities;
                    417:        imv_session_t *session;
                    418:        uint32_t max_msg_len;
                    419: 
                    420:        conn_id = state->get_connection_id(state);
                    421:        if (find_connection(this, conn_id))
                    422:        {
                    423:                DBG1(DBG_IMV, "IMV %u \"%s\" already created a state for Connection ID %u",
                    424:                                           this->id, this->name, conn_id);
                    425:                state->destroy(state);
                    426:                return TNC_RESULT_OTHER;
                    427:        }
                    428: 
                    429:        /* Get and display attributes from TNCS via IF-IMV */
                    430:        has_long = get_bool_attribute(this, conn_id,
                    431:                                                                        TNC_ATTRIBUTEID_HAS_LONG_TYPES);
                    432:        has_excl = get_bool_attribute(this, conn_id,
                    433:                                                                        TNC_ATTRIBUTEID_HAS_EXCLUSIVE);
                    434:        has_soh  = get_bool_attribute(this, conn_id,
                    435:                                                                        TNC_ATTRIBUTEID_HAS_SOH);
                    436:        tnccs_p = get_str_attribute(this, conn_id,
                    437:                                                                        TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL);
                    438:        tnccs_v = get_str_attribute(this, conn_id,
                    439:                                                                        TNC_ATTRIBUTEID_IFTNCCS_VERSION);
                    440:        t_p = get_str_attribute(this, conn_id,
                    441:                                                                        TNC_ATTRIBUTEID_IFT_PROTOCOL);
                    442:        t_v = get_str_attribute(this, conn_id,
                    443:                                                                        TNC_ATTRIBUTEID_IFT_VERSION);
                    444:        max_msg_len = get_uint_attribute(this, conn_id,
                    445:                                                                        TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE);
                    446:        ar_identities = get_identity_attribute(this, conn_id,
                    447:                                                                        TNC_ATTRIBUTEID_AR_IDENTITIES);
                    448: 
                    449:        state->set_flags(state, has_long, has_excl);
                    450:        state->set_max_msg_len(state, max_msg_len);
                    451: 
                    452:        DBG2(DBG_IMV, "IMV %u \"%s\" created a state for %s %s Connection ID %u: "
                    453:                                  "%slong %sexcl %ssoh", this->id, this->name,
                    454:                                  tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id,
                    455:                              has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-");
                    456:        DBG2(DBG_IMV, "  over %s %s with maximum PA-TNC message size of %u bytes",
                    457:                                  t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len);
                    458: 
                    459:        session = imcv_sessions->add_session(imcv_sessions, conn_id, ar_identities);
                    460:        state->set_session(state, session);
                    461: 
                    462:        free(tnccs_p);
                    463:        free(tnccs_v);
                    464:        free(t_p);
                    465:        free(t_v);
                    466: 
                    467:        /* insert state in connection list */
                    468:        this->connection_lock->write_lock(this->connection_lock);
                    469:        this->connections->insert_last(this->connections, state);
                    470:        this->connection_lock->unlock(this->connection_lock);
                    471: 
                    472:        return TNC_RESULT_SUCCESS;
                    473: }
                    474: 
                    475: METHOD(imv_agent_t, delete_state, TNC_Result,
                    476:        private_imv_agent_t *this, TNC_ConnectionID connection_id)
                    477: {
                    478:        if (!delete_connection(this, connection_id))
                    479:        {
                    480:                DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
                    481:                                          this->id, this->name, connection_id);
                    482:                return TNC_RESULT_FATAL;
                    483:        }
                    484:        DBG2(DBG_IMV, "IMV %u \"%s\" deleted the state of Connection ID %u",
                    485:                                  this->id, this->name, connection_id);
                    486:        return TNC_RESULT_SUCCESS;
                    487: }
                    488: 
                    489: METHOD(imv_agent_t, change_state, TNC_Result,
                    490:        private_imv_agent_t *this, TNC_ConnectionID connection_id,
                    491:                                                           TNC_ConnectionState new_state,
                    492:                                                           imv_state_t **state_p)
                    493: {
                    494:        imv_state_t *state;
                    495:        TNC_ConnectionState old_state;
                    496: 
                    497:        switch (new_state)
                    498:        {
                    499:                case TNC_CONNECTION_STATE_HANDSHAKE:
                    500:                case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
                    501:                case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
                    502:                case TNC_CONNECTION_STATE_ACCESS_NONE:
                    503:                        state = find_connection(this, connection_id);
                    504:                        if (!state)
                    505:                        {
                    506:                                DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
                    507:                                                          this->id, this->name, connection_id);
                    508:                                return TNC_RESULT_FATAL;
                    509:                        }
                    510:                        old_state = state->change_state(state, new_state);
                    511:                        DBG2(DBG_IMV, "IMV %u \"%s\" changed state of Connection ID %u to '%N'",
                    512:                                                  this->id, this->name, connection_id,
                    513:                                                  TNC_Connection_State_names, new_state);
                    514:                        if (state_p)
                    515:                        {
                    516:                                *state_p = state;
                    517:                        }
                    518:                        if (new_state == TNC_CONNECTION_STATE_HANDSHAKE &&
                    519:                                old_state != TNC_CONNECTION_STATE_CREATE)
                    520:                        {
                    521:                                state->reset(state);
                    522:                                DBG2(DBG_IMV, "IMV %u \"%s\" reset state of Connection ID %u",
                    523:                                                           this->id, this->name, connection_id);
                    524:                        }
                    525:                        break;
                    526:                case TNC_CONNECTION_STATE_CREATE:
                    527:                        DBG1(DBG_IMV, "state '%N' should be handled by create_state()",
                    528:                                                  TNC_Connection_State_names, new_state);
                    529:                                return TNC_RESULT_FATAL;
                    530:                case TNC_CONNECTION_STATE_DELETE:
                    531:                        DBG1(DBG_IMV, "state '%N' should be handled by delete_state()",
                    532:                                                  TNC_Connection_State_names, new_state);
                    533:                                return TNC_RESULT_FATAL;
                    534:                default:
                    535:                        DBG1(DBG_IMV, "IMV %u \"%s\" was notified of unknown state %u "
                    536:                                                  "for Connection ID %u",
                    537:                                                  this->id, this->name, new_state, connection_id);
                    538:                        return TNC_RESULT_INVALID_PARAMETER;
                    539:        }
                    540:        return TNC_RESULT_SUCCESS;
                    541: }
                    542: 
                    543: METHOD(imv_agent_t, get_state, bool,
                    544:        private_imv_agent_t *this, TNC_ConnectionID connection_id,
                    545:                                                           imv_state_t **state)
                    546: {
                    547:        *state = find_connection(this, connection_id);
                    548:        if (!*state)
                    549:        {
                    550:                DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
                    551:                                          this->id, this->name, connection_id);
                    552:                return FALSE;
                    553:        }
                    554:        return TRUE;
                    555: }
                    556: 
                    557: METHOD(imv_agent_t, get_name, const char*,
                    558:        private_imv_agent_t *this)
                    559: {
                    560:        return  this->name;
                    561: }
                    562: 
                    563: METHOD(imv_agent_t, get_id, TNC_IMVID,
                    564:        private_imv_agent_t *this)
                    565: {
                    566:        return  this->id;
                    567: }
                    568: 
                    569: METHOD(imv_agent_t, reserve_additional_ids, TNC_Result,
                    570:        private_imv_agent_t *this, int count)
                    571: {
                    572:        TNC_Result result;
                    573:        TNC_UInt32 id;
                    574:        void *pointer;
                    575: 
                    576:        if (!this->reserve_additional_id)
                    577:        {
                    578:                DBG1(DBG_IMV, "IMV %u \"%s\" did not detect the capability to reserve "
                    579:                                          "additional IMV IDs from the TNCS", this->id, this->name);
                    580:                return TNC_RESULT_ILLEGAL_OPERATION;
                    581:        }
                    582:        while (count > 0)
                    583:        {
                    584:                result = this->reserve_additional_id(this->id, &id);
                    585:                if (result != TNC_RESULT_SUCCESS)
                    586:                {
                    587:                        DBG1(DBG_IMV, "IMV %u \"%s\" failed to reserve %d additional IMV IDs",
                    588:                                                  this->id, this->name, count);
                    589:                        return result;
                    590:                }
                    591:                count--;
                    592: 
                    593:                /* store the scalar value in the pointer */
                    594:                pointer = (void*)(uintptr_t)id;
                    595:                this->additional_ids->insert_last(this->additional_ids, pointer);
                    596:                DBG2(DBG_IMV, "IMV %u \"%s\" reserved additional ID %u",
                    597:                                          this->id, this->name, id);
                    598:        }
                    599:        return TNC_RESULT_SUCCESS;
                    600: }
                    601: 
                    602: METHOD(imv_agent_t, count_additional_ids, int,
                    603:        private_imv_agent_t *this)
                    604: {
                    605:        return  this->additional_ids->get_count(this->additional_ids);
                    606: }
                    607: 
                    608: METHOD(imv_agent_t, create_id_enumerator, enumerator_t*,
                    609:        private_imv_agent_t *this)
                    610: {
                    611:        return this->additional_ids->create_enumerator(this->additional_ids);
                    612: }
                    613: 
                    614: typedef struct {
                    615:        /**
                    616:         * implements enumerator_t
                    617:         */
                    618:        enumerator_t public;
                    619: 
                    620:        /**
                    621:         * language length
                    622:         */
                    623:        TNC_UInt32 lang_len;
                    624: 
                    625:        /**
                    626:         * language buffer
                    627:         */
                    628:        char lang_buf[BUF_LEN];
                    629: 
                    630:        /**
                    631:         * position pointer into language buffer
                    632:         */
                    633:        char *lang_pos;
                    634: 
                    635: } language_enumerator_t;
                    636: 
                    637: METHOD(enumerator_t, language_enumerator_enumerate, bool,
                    638:        language_enumerator_t *this, va_list args)
                    639: {
                    640:        char *pos, *cur_lang, **lang;
                    641:        TNC_UInt32 len;
                    642: 
                    643:        VA_ARGS_VGET(args, lang);
                    644: 
                    645:        if (!this->lang_len)
                    646:        {
                    647:                return FALSE;
                    648:        }
                    649:        cur_lang = this->lang_pos;
                    650:        pos = strchr(this->lang_pos, ',');
                    651:        if (pos)
                    652:        {
                    653:                len = pos - this->lang_pos;
                    654:                this->lang_pos += len + 1;
                    655:                this->lang_len -= len + 1;
                    656:        }
                    657:        else
                    658:        {
                    659:                len = this->lang_len;
                    660:                pos = this->lang_pos + len;
                    661:                this->lang_pos = NULL;
                    662:                this->lang_len = 0;
                    663:        }
                    664: 
                    665:        /* remove preceding whitespace */
                    666:        while (*cur_lang == ' ' && len--)
                    667:        {
                    668:                cur_lang++;
                    669:        }
                    670: 
                    671:        /* remove trailing whitespace */
                    672:        while (len && *(--pos) == ' ')
                    673:        {
                    674:                len--;
                    675:        }
                    676:        cur_lang[len] = '\0';
                    677: 
                    678:        *lang = cur_lang;
                    679:        return TRUE;
                    680: }
                    681: 
                    682: METHOD(imv_agent_t, create_language_enumerator, enumerator_t*,
                    683:        private_imv_agent_t *this, imv_state_t *state)
                    684: {
                    685:        language_enumerator_t *e;
                    686: 
                    687:        INIT(e,
                    688:                .public = {
                    689:                        .enumerate = enumerator_enumerate_default,
                    690:                        .venumerate = _language_enumerator_enumerate,
                    691:                        .destroy = (void*)free,
                    692:                },
                    693:        );
                    694: 
                    695:        if (!this->get_attribute ||
                    696:                 this->get_attribute(this->id, state->get_connection_id(state),
                    697:                                                TNC_ATTRIBUTEID_PREFERRED_LANGUAGE, BUF_LEN,
                    698:                                                e->lang_buf, &e->lang_len) != TNC_RESULT_SUCCESS ||
                    699:                e->lang_len >= BUF_LEN)
                    700:        {
                    701:                e->lang_len = 0;
                    702:        }
                    703:        e->lang_buf[e->lang_len] = '\0';
                    704:        e->lang_pos = e->lang_buf;
                    705: 
                    706:        return (enumerator_t*)e;
                    707: }
                    708: 
                    709: METHOD(imv_agent_t, provide_recommendation, TNC_Result,
                    710:        private_imv_agent_t *this, imv_state_t *state)
                    711: {
                    712:        TNC_IMV_Action_Recommendation rec;
                    713:        TNC_IMV_Evaluation_Result eval;
                    714:        TNC_ConnectionID connection_id;
                    715:        chunk_t reason_string;
                    716:        char *reason_lang;
                    717:        enumerator_t *e;
                    718: 
                    719:        state->get_recommendation(state, &rec, &eval);
                    720:        connection_id = state->get_connection_id(state);
                    721: 
                    722:        /* send a reason string if action recommendation is not allow */
                    723:        if (rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
                    724:        {
                    725:                /* find a reason string for the preferred language and set it */
                    726:                if (this->set_attribute)
                    727:                {
                    728:                        e = create_language_enumerator(this, state);
                    729:                        if (state->get_reason_string(state, e, &reason_string, &reason_lang))
                    730:                        {
                    731:                                this->set_attribute(this->id, connection_id,
                    732:                                                                        TNC_ATTRIBUTEID_REASON_STRING,
                    733:                                                                        reason_string.len, reason_string.ptr);
                    734:                                this->set_attribute(this->id, connection_id,
                    735:                                                                        TNC_ATTRIBUTEID_REASON_LANGUAGE,
                    736:                                                                        strlen(reason_lang), reason_lang);
                    737:                        }
                    738:                        e->destroy(e);
                    739:                }
                    740:        }
                    741:        return this->provide_recommendation(this->id, connection_id, rec, eval);
                    742: }
                    743: 
                    744: METHOD(imv_agent_t, add_non_fatal_attr_type, void,
                    745:        private_imv_agent_t *this, pen_type_t type)
                    746: {
                    747:        pen_type_t *type_p;
                    748: 
                    749:        type_p = malloc_thing(pen_type_t);
                    750:        *type_p = type;
                    751:        this->non_fatal_attr_types->insert_last(this->non_fatal_attr_types, type_p);
                    752: }
                    753: 
                    754: METHOD(imv_agent_t, get_non_fatal_attr_types, linked_list_t*,
                    755:        private_imv_agent_t *this)
                    756: {
                    757:        return this->non_fatal_attr_types;
                    758: }
                    759: 
                    760: METHOD(imv_agent_t, destroy, void,
                    761:        private_imv_agent_t *this)
                    762: {
                    763:        DBG1(DBG_IMV, "IMV %u \"%s\" terminated", this->id, this->name);
                    764:        this->additional_ids->destroy(this->additional_ids);
                    765:        this->non_fatal_attr_types->destroy_function(this->non_fatal_attr_types,
                    766:                                                                                                 free);
                    767:        this->connections->destroy_offset(this->connections,
                    768:                                                                          offsetof(imv_state_t, destroy));
                    769:        this->connection_lock->destroy(this->connection_lock);
                    770:        free(this);
                    771: 
                    772:        /* decrease the reference count or terminate */
                    773:        libimcv_deinit();
                    774: }
                    775: 
                    776: /**
                    777:  * Described in header.
                    778:  */
                    779: imv_agent_t *imv_agent_create(const char *name,
                    780:                                                          pen_type_t *supported_types, uint32_t type_count,
                    781:                                                          TNC_IMVID id, TNC_Version *actual_version)
                    782: {
                    783:        private_imv_agent_t *this;
                    784: 
                    785:        /* initialize  or increase the reference count */
                    786:        if (!libimcv_init(TRUE))
                    787:        {
                    788:                return NULL;
                    789:        }
                    790: 
                    791:        INIT(this,
                    792:                .public = {
                    793:                        .bind_functions = _bind_functions,
                    794:                        .create_state = _create_state,
                    795:                        .delete_state = _delete_state,
                    796:                        .change_state = _change_state,
                    797:                        .get_state = _get_state,
                    798:                        .get_name = _get_name,
                    799:                        .get_id = _get_id,
                    800:                        .reserve_additional_ids = _reserve_additional_ids,
                    801:                        .count_additional_ids = _count_additional_ids,
                    802:                        .create_id_enumerator = _create_id_enumerator,
                    803:                        .create_language_enumerator = _create_language_enumerator,
                    804:                        .provide_recommendation = _provide_recommendation,
                    805:                        .add_non_fatal_attr_type = _add_non_fatal_attr_type,
                    806:                        .get_non_fatal_attr_types = _get_non_fatal_attr_types,
                    807:                        .destroy = _destroy,
                    808:                },
                    809:                .name = name,
                    810:                .supported_types = supported_types,
                    811:                .type_count = type_count,
                    812:                .id = id,
                    813:                .additional_ids = linked_list_create(),
                    814:                .non_fatal_attr_types = linked_list_create(),
                    815:                .connections = linked_list_create(),
                    816:                .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    817:        );
                    818: 
                    819:        *actual_version = TNC_IFIMV_VERSION_1;
                    820:        DBG1(DBG_IMV, "IMV %u \"%s\" initialized", this->id, this->name);
                    821: 
                    822:        return &this->public;
                    823: }

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