Annotation of embedaddon/strongswan/src/libimcv/imv/imv_agent.c, revision 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>