Annotation of embedaddon/strongswan/src/libimcv/seg/seg_contract.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2014-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 "seg_contract.h"
                     17: #include "seg_env.h"
                     18: #include "ietf/ietf_attr_pa_tnc_error.h"
                     19: #include "tcg/seg/tcg_seg_attr_seg_env.h"
                     20: 
                     21: #include <utils/debug.h>
                     22: #include <bio/bio_writer.h>
                     23: 
                     24: #include <tncif_pa_subtypes.h>
                     25: 
                     26: typedef struct private_seg_contract_t private_seg_contract_t;
                     27: 
                     28: /**
                     29:  * Private data of a seg_contract_t object.
                     30:  */
                     31: struct private_seg_contract_t {
                     32: 
                     33:        /**
                     34:         * Public seg_contract_t interface.
                     35:         */
                     36:        seg_contract_t public;
                     37: 
                     38:        /**
                     39:         * PA-TNC message type
                     40:         */
                     41:        pen_type_t msg_type;
                     42: 
                     43:        /**
                     44:         * Maximum PA-TNC attribute size
                     45:         */
                     46:        uint32_t max_attr_size;
                     47: 
                     48:        /**
                     49:         * Maximum PA-TNC attribute segment size
                     50:         */
                     51:        uint32_t max_seg_size;
                     52: 
                     53:        /**
                     54:         * Maximum PA-TNC attribute segment size
                     55:         */
                     56:        uint32_t last_base_attr_id;
                     57: 
                     58:        /**
                     59:         * List of attribute segment envelopes
                     60:         */
                     61: 
                     62:        linked_list_t *seg_envs;
                     63: 
                     64:        /**
                     65:         * Is this a null contract?
                     66:         */
                     67:        bool is_null;
                     68: 
                     69:        /**
                     70:         * Contract role
                     71:         */
                     72:        bool is_issuer;
                     73: 
                     74:        /**
                     75:         * Issuer ID (either IMV or IMC ID)
                     76:         */
                     77:        TNC_UInt32 issuer_id;
                     78: 
                     79:        /**
                     80:         * Responder ID (either IMC or IMV ID)
                     81:         */
                     82:        TNC_UInt32 responder_id;
                     83: 
                     84:        /**
                     85:         * IMC/IMV role
                     86:         */
                     87:        bool is_imc;
                     88: 
                     89: };
                     90: 
                     91: METHOD(seg_contract_t, get_msg_type, pen_type_t,
                     92:        private_seg_contract_t *this)
                     93: {
                     94:        return this->msg_type;
                     95: }
                     96: 
                     97: METHOD(seg_contract_t, set_max_size, void,
                     98:        private_seg_contract_t *this, uint32_t max_attr_size, uint32_t max_seg_size)
                     99: {
                    100:        this->max_attr_size = max_attr_size;
                    101:        this->max_seg_size = max_seg_size;
                    102:        this->is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
                    103:                                        max_seg_size  == SEG_CONTRACT_MAX_SIZE_VALUE;
                    104: }
                    105: 
                    106: METHOD(seg_contract_t, get_max_size, void,
                    107:        private_seg_contract_t *this, uint32_t *max_attr_size, uint32_t *max_seg_size)
                    108: {
                    109:        if (max_attr_size)
                    110:        {
                    111:                *max_attr_size = this->max_attr_size;
                    112:        }
                    113:        if (max_seg_size)
                    114:        {
                    115:                *max_seg_size = this->max_seg_size;
                    116:        }
                    117: }
                    118: 
                    119: METHOD(seg_contract_t, check_size, bool,
                    120:        private_seg_contract_t *this, pa_tnc_attr_t *attr, bool *oversize)
                    121: {
                    122:        chunk_t attr_value;
                    123:        size_t attr_len;
                    124: 
                    125:        *oversize = FALSE;
                    126: 
                    127:        if (this->is_null)
                    128:        {
                    129:                /* null segmentation contract */
                    130:                return FALSE;
                    131:        }
                    132:        attr->build(attr);
                    133:        attr_value = attr->get_value(attr);
                    134:        attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
                    135: 
                    136:        if (attr_len > this->max_attr_size)
                    137:        {
                    138:                /* oversize attribute */
                    139:                *oversize = TRUE;
                    140:                return FALSE;
                    141:        }
                    142:        if (this->max_seg_size == SEG_CONTRACT_NO_FRAGMENTATION)
                    143:        {
                    144:                /* no fragmentation wanted */
                    145:                return FALSE;
                    146:        }
                    147:        return attr_value.len > this->max_seg_size + TCG_SEG_ATTR_SEG_ENV_HEADER;
                    148: }
                    149: 
                    150: METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
                    151:        private_seg_contract_t *this, pa_tnc_attr_t *attr, size_t max_attr_len)
                    152: {
                    153:        seg_env_t *seg_env;
                    154: 
                    155:        seg_env = seg_env_create(++this->last_base_attr_id, attr,
                    156:                                                         this->max_seg_size);
                    157:        if (!seg_env)
                    158:        {
                    159:                return NULL;
                    160:        }
                    161:        this->seg_envs->insert_last(this->seg_envs, seg_env);
                    162: 
                    163:        return seg_env->first_segment(seg_env, max_attr_len);
                    164: }
                    165: 
                    166: METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*,
                    167:        private_seg_contract_t *this, uint32_t base_attr_id)
                    168: {
                    169:        pa_tnc_attr_t *seg_env_attr = NULL;
                    170:        seg_env_t *seg_env;
                    171:        bool last_segment = FALSE;
                    172:        enumerator_t *enumerator;
                    173: 
                    174:        enumerator = this->seg_envs->create_enumerator(this->seg_envs);
                    175:        while (enumerator->enumerate(enumerator, &seg_env))
                    176:        {
                    177:                if (seg_env->get_base_attr_id(seg_env) == base_attr_id)
                    178:                {
                    179:                        seg_env_attr = seg_env->next_segment(seg_env, &last_segment);
                    180:                        if (!seg_env_attr)
                    181:                        {
                    182:                                break;
                    183:                        }
                    184:                        if (last_segment)
                    185:                        {
                    186:                                this->seg_envs->remove_at(this->seg_envs, enumerator);
                    187:                                seg_env->destroy(seg_env);
                    188:                        }
                    189:                        break;
                    190:                }
                    191:        }
                    192:        enumerator->destroy(enumerator);
                    193: 
                    194:        return seg_env_attr;
                    195: }
                    196: 
                    197: METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
                    198:        private_seg_contract_t *this, pa_tnc_attr_t *attr, pa_tnc_attr_t **error,
                    199:        bool *more)
                    200: {
                    201:        tcg_seg_attr_seg_env_t *seg_env_attr;
                    202:        seg_env_t *current, *seg_env = NULL;
                    203:        pa_tnc_attr_t *base_attr;
                    204:        pen_type_t error_code;
                    205:        uint32_t base_attr_id;
                    206:        uint8_t flags;
                    207:        chunk_t segment_data, msg_info;
                    208:        enumerator_t *enumerator;
                    209: 
                    210:        seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
                    211:        base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr);
                    212:        segment_data = seg_env_attr->get_segment(seg_env_attr, &flags);
                    213:        *more = flags & SEG_ENV_FLAG_MORE;
                    214:        *error = NULL;
                    215: 
                    216:        enumerator = this->seg_envs->create_enumerator(this->seg_envs);
                    217:        while (enumerator->enumerate(enumerator, &current))
                    218:        {
                    219:                if (current->get_base_attr_id(current) == base_attr_id)
                    220:                {
                    221:                        seg_env = current;
                    222:                        this->seg_envs->remove_at(this->seg_envs, enumerator);
                    223:                        break;
                    224:                }
                    225:        }
                    226:        enumerator->destroy(enumerator);
                    227: 
                    228:        if (flags & SEG_ENV_FLAG_START)
                    229:        {
                    230:                if (seg_env)
                    231:                {
                    232:                        DBG1(DBG_TNC, "base attribute ID %d is already in use",
                    233:                                                   base_attr_id);
                    234:                        this->seg_envs->insert_last(this->seg_envs, seg_env);
                    235:                        return NULL;
                    236:                }
                    237:                DBG2(DBG_TNC, "received first segment for base attribute ID %d "
                    238:                                          "(%d bytes)", base_attr_id, segment_data.len);
                    239:                seg_env = seg_env_create_from_data(base_attr_id, segment_data,
                    240:                                                                                   this->max_seg_size, error);
                    241:                if (!seg_env)
                    242:                {
                    243:                        return NULL;
                    244:                }
                    245:        }
                    246:        else
                    247:        {
                    248:                if (!seg_env)
                    249:                {
                    250:                        DBG1(DBG_TNC, "base attribute ID %d not found", base_attr_id);
                    251:                        return NULL;
                    252:                }
                    253:                DBG2(DBG_TNC, "received %s segment for base attribute ID %d "
                    254:                                          "(%d bytes)", (*more) ? "next" : "last", base_attr_id,
                    255:                                           segment_data.len);
                    256:                if (!seg_env->add_segment(seg_env, segment_data, error))
                    257:                {
                    258:                        seg_env->destroy(seg_env);
                    259:                        return NULL;
                    260:                }
                    261:        }
                    262:        base_attr = seg_env->get_base_attr(seg_env);
                    263: 
                    264:        if (*more)
                    265:        {
                    266:                /* reinsert into list since more segments are to come */
                    267:                this->seg_envs->insert_last(this->seg_envs, seg_env);
                    268:        }
                    269:        else
                    270:        {
                    271:                /* added the last segment */
                    272:                if (!base_attr)
                    273:                {
                    274:                        /* base attribute waits for more data */
                    275:                        DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value");
                    276:                        msg_info = seg_env->get_base_attr_info(seg_env);
                    277:                        error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
                    278:                        *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
                    279:                                                                                msg_info, PA_TNC_ATTR_INFO_SIZE);
                    280:                }
                    281:                seg_env->destroy(seg_env);
                    282:        }
                    283:        return base_attr;
                    284: }
                    285: 
                    286: METHOD(seg_contract_t, is_issuer, bool,
                    287:        private_seg_contract_t *this)
                    288: {
                    289:        return this->is_issuer;
                    290: }
                    291: 
                    292: METHOD(seg_contract_t, is_null, bool,
                    293:        private_seg_contract_t *this)
                    294: {
                    295:        return this->is_null;
                    296: }
                    297: 
                    298: METHOD(seg_contract_t, set_responder, void,
                    299:        private_seg_contract_t *this, TNC_UInt32 responder_id)
                    300: {
                    301:        this->responder_id = responder_id;
                    302: }
                    303: 
                    304: METHOD(seg_contract_t, get_responder, TNC_UInt32,
                    305:        private_seg_contract_t *this)
                    306: {
                    307:        return this->responder_id;
                    308: }
                    309: 
                    310: METHOD(seg_contract_t, get_issuer, TNC_UInt32,
                    311:        private_seg_contract_t *this)
                    312: {
                    313:        return this->issuer_id;
                    314: }
                    315: 
                    316: METHOD(seg_contract_t, clone_, seg_contract_t*,
                    317:        private_seg_contract_t *this)
                    318: {
                    319:        private_seg_contract_t *clone;
                    320: 
                    321:        clone = malloc_thing(private_seg_contract_t);
                    322:        memcpy(clone, this, sizeof(private_seg_contract_t));
                    323:        clone->seg_envs = linked_list_create();
                    324: 
                    325:        return &clone->public;
                    326: }
                    327: 
                    328: METHOD(seg_contract_t, get_info_string, void,
                    329:        private_seg_contract_t *this, char *buf, size_t len, bool request)
                    330: {
                    331:        enum_name_t *pa_subtype_names;
                    332:        uint32_t msg_vid, msg_subtype;
                    333:        char *pos = buf;
                    334:        int written;
                    335: 
                    336:        /* nul-terminate the string buffer */
                    337:        buf[--len] = '\0';
                    338: 
                    339:        if (this->is_issuer && request)
                    340:        {
                    341:                written = snprintf(pos, len, "%s %lu requests",
                    342:                                                  this->is_imc ? "IMC" : "IMV", this->issuer_id);
                    343:        }
                    344:        else
                    345:        {
                    346:                written = snprintf(pos, len, "%s %lu received",
                    347:                                                   this->is_imc ? "IMC" : "IMV",
                    348:                                                   this->is_issuer ? this->issuer_id :
                    349:                                                                                         this->responder_id);
                    350:        }
                    351:        if (written < 0 || written > len)
                    352:        {
                    353:                return;
                    354:        }
                    355:        pos += written;
                    356:        len -= written;
                    357: 
                    358:        written = snprintf(pos, len, " a %ssegmentation contract%s ",
                    359:                                           this->is_null ? "null" : "", request ?
                    360:                                          (this->is_issuer ? "" : " request") : " response");
                    361:        if (written < 0 || written > len)
                    362:        {
                    363:                return;
                    364:        }
                    365:        pos += written;
                    366:        len -= written;
                    367: 
                    368:        if ((!this->is_issuer && this->issuer_id != TNC_IMVID_ANY) ||
                    369:                ( this->is_issuer && this->responder_id != TNC_IMVID_ANY))
                    370:        {
                    371:                written = snprintf(pos, len, "from %s %lu ",
                    372:                                                   this->is_imc ? "IMV" : "IMC",
                    373:                                                   this->is_issuer ? this->responder_id :
                    374:                                                                                         this->issuer_id);
                    375:                if (written < 0 || written > len)
                    376:                {
                    377:                        return;
                    378:                }
                    379:                pos += written;
                    380:                len -= written;
                    381:        }
                    382: 
                    383:        msg_vid     = this->msg_type.vendor_id;
                    384:        msg_subtype = this->msg_type.type;
                    385:        pa_subtype_names = get_pa_subtype_names(msg_vid);
                    386:        if (pa_subtype_names)
                    387:        {
                    388:                written = snprintf(pos, len, "for PA message type '%N/%N' "
                    389:                                                   "0x%06x/0x%08x", pen_names, msg_vid,
                    390:                                                   pa_subtype_names, msg_subtype, msg_vid,
                    391:                                                   msg_subtype);
                    392:        }
                    393:        else
                    394:        {
                    395:                written = snprintf(pos, len, "for PA message type '%N' "
                    396:                                                   "0x%06x/0x%08x", pen_names, msg_vid,
                    397:                                                   msg_vid, msg_subtype);
                    398:        }
                    399:        if (written < 0 || written > len)
                    400:        {
                    401:                return;
                    402:        }
                    403:        pos += written;
                    404:        len -= written;
                    405: 
                    406:        if (!this->is_null)
                    407:        {
                    408:                written = snprintf(pos, len, "\n  maximum attribute size of %u bytes "
                    409:                                                   "with ", this->max_attr_size);
                    410:                if (written < 0 || written > len)
                    411:                {
                    412:                        return;
                    413:                }
                    414:                pos += written;
                    415:                len -= written;
                    416: 
                    417:                if (this->max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE)
                    418:                {
                    419:                        written = snprintf(pos, len, "no segmentation");
                    420:                }
                    421:                else
                    422:                {
                    423:                        written = snprintf(pos, len, "maximum segment size of %u bytes",
                    424:                                                           this->max_seg_size);
                    425:                }
                    426:        }
                    427: }
                    428: 
                    429: METHOD(seg_contract_t, destroy, void,
                    430:        private_seg_contract_t *this)
                    431: {
                    432:        this->seg_envs->destroy_offset(this->seg_envs, offsetof(seg_env_t, destroy));
                    433:        free(this);
                    434: }
                    435: 
                    436: /**
                    437:  * See header
                    438:  */
                    439: seg_contract_t *seg_contract_create(pen_type_t msg_type,
                    440:                                                                    uint32_t max_attr_size,
                    441:                                                                        uint32_t max_seg_size,
                    442:                                                                        bool is_issuer, TNC_UInt32 issuer_id,
                    443:                                                                        bool is_imc)
                    444: {
                    445:        private_seg_contract_t *this;
                    446: 
                    447:        INIT(this,
                    448:                .public = {
                    449:                        .get_msg_type = _get_msg_type,
                    450:                        .set_max_size = _set_max_size,
                    451:                        .get_max_size = _get_max_size,
                    452:                        .check_size = _check_size,
                    453:                        .first_segment = _first_segment,
                    454:                        .next_segment = _next_segment,
                    455:                        .add_segment = _add_segment,
                    456:                        .is_issuer = _is_issuer,
                    457:                        .is_null = _is_null,
                    458:                        .set_responder = _set_responder,
                    459:                        .get_responder = _get_responder,
                    460:                        .get_issuer = _get_issuer,
                    461:                        .clone = _clone_,
                    462:                        .get_info_string = _get_info_string,
                    463:                        .destroy = _destroy,
                    464:                },
                    465:                .msg_type = msg_type,
                    466:                .max_attr_size = max_attr_size,
                    467:                .max_seg_size = max_seg_size,
                    468:                .seg_envs = linked_list_create(),
                    469:                .is_issuer = is_issuer,
                    470:                .issuer_id = issuer_id,
                    471:                .responder_id = is_imc ? TNC_IMVID_ANY : TNC_IMCID_ANY,
                    472:                .is_imc = is_imc,
                    473:                .is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
                    474:                                   max_seg_size  == SEG_CONTRACT_MAX_SIZE_VALUE,
                    475:        );
                    476: 
                    477:        return &this->public;
                    478: }
                    479: 

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