Annotation of embedaddon/strongswan/src/libcharon/encoding/payloads/eap_payload.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012 Tobias Brunner
        !             3:  * Copyright (C) 2005-2010 Martin Willi
        !             4:  * Copyright (C) 2005 Jan Hutter
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: #include <stddef.h>
        !            19: 
        !            20: #include "eap_payload.h"
        !            21: 
        !            22: #include <daemon.h>
        !            23: #include <eap/eap.h>
        !            24: #include <bio/bio_writer.h>
        !            25: 
        !            26: typedef struct private_eap_payload_t private_eap_payload_t;
        !            27: 
        !            28: /**
        !            29:  * Private data of an eap_payload_t object.
        !            30:  *
        !            31:  */
        !            32: struct private_eap_payload_t {
        !            33:        /**
        !            34:         * Public eap_payload_t interface.
        !            35:         */
        !            36:        eap_payload_t public;
        !            37: 
        !            38:        /**
        !            39:         * Next payload type.
        !            40:         */
        !            41:        uint8_t  next_payload;
        !            42: 
        !            43:        /**
        !            44:         * Critical flag.
        !            45:         */
        !            46:        bool critical;
        !            47: 
        !            48:        /**
        !            49:         * Reserved bits
        !            50:         */
        !            51:        bool reserved[7];
        !            52: 
        !            53:        /**
        !            54:         * Length of this payload.
        !            55:         */
        !            56:        uint16_t payload_length;
        !            57: 
        !            58:        /**
        !            59:         * EAP message data, if available
        !            60:         */
        !            61:        chunk_t data;
        !            62: };
        !            63: 
        !            64: /**
        !            65:  * Encoding rules to parse or generate a EAP payload.
        !            66:  *
        !            67:  * The defined offsets are the positions in a object of type
        !            68:  * private_eap_payload_t.
        !            69:  *
        !            70:  */
        !            71: static encoding_rule_t encodings[] = {
        !            72:        /* 1 Byte next payload type, stored in the field next_payload */
        !            73:        { U_INT_8,                      offsetof(private_eap_payload_t, next_payload)   },
        !            74:        /* the critical bit */
        !            75:        { FLAG,                         offsetof(private_eap_payload_t, critical)               },
        !            76:        /* 7 Bit reserved bits, nowhere stored */
        !            77:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[0])    },
        !            78:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[1])    },
        !            79:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[2])    },
        !            80:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[3])    },
        !            81:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[4])    },
        !            82:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[5])    },
        !            83:        { RESERVED_BIT,         offsetof(private_eap_payload_t, reserved[6])    },
        !            84:        /* Length of the whole payload*/
        !            85:        { PAYLOAD_LENGTH,       offsetof(private_eap_payload_t, payload_length) },
        !            86:        /* chunk to data, starting at "code" */
        !            87:        { CHUNK_DATA,           offsetof(private_eap_payload_t, data)                   },
        !            88: };
        !            89: 
        !            90: /*
        !            91:                             1                   2                   3
        !            92:         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        !            93:        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            94:        ! Next Payload  !C!  RESERVED   !         Payload Length        !
        !            95:        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            96:        !     Code      ! Identifier    !           Length              !
        !            97:        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            98:        !     Type      ! Type_Data...
        !            99:        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
        !           100: */
        !           101: 
        !           102: METHOD(payload_t, verify, status_t,
        !           103:        private_eap_payload_t *this)
        !           104: {
        !           105:        uint16_t length;
        !           106:        uint8_t code;
        !           107: 
        !           108:        if (this->data.len < 4)
        !           109:        {
        !           110:                DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len);
        !           111:                return FAILED;
        !           112:        }
        !           113:        length = untoh16(this->data.ptr + 2);
        !           114:        if (this->data.len != length)
        !           115:        {
        !           116:                DBG1(DBG_ENC, "EAP payload length (%d) does not match contained "
        !           117:                         "message length (%d)", this->data.len, length);
        !           118:                return FAILED;
        !           119:        }
        !           120:        code = this->data.ptr[0];
        !           121:        switch (code)
        !           122:        {
        !           123:                case EAP_REQUEST:
        !           124:                case EAP_RESPONSE:
        !           125:                {
        !           126:                        if (this->data.len < 4)
        !           127:                        {
        !           128:                                DBG1(DBG_ENC, "EAP Request/Response does not have any data");
        !           129:                                return FAILED;
        !           130:                        }
        !           131:                        break;
        !           132:                }
        !           133:                case EAP_SUCCESS:
        !           134:                case EAP_FAILURE:
        !           135:                {
        !           136:                        if (this->data.len != 4)
        !           137:                        {
        !           138:                                DBG1(DBG_ENC, "EAP Success/Failure has data");
        !           139:                                return FAILED;
        !           140:                        }
        !           141:                        break;
        !           142:                }
        !           143:                default:
        !           144:                        return FAILED;
        !           145:        }
        !           146:        return SUCCESS;
        !           147: }
        !           148: 
        !           149: METHOD(payload_t, get_encoding_rules, int,
        !           150:        private_eap_payload_t *this, encoding_rule_t **rules)
        !           151: {
        !           152:        *rules = encodings;
        !           153:        return countof(encodings);
        !           154: }
        !           155: 
        !           156: METHOD(payload_t, get_header_length, int,
        !           157:        private_eap_payload_t *this)
        !           158: {
        !           159:        return 4;
        !           160: }
        !           161: 
        !           162: METHOD(payload_t, get_payload_type, payload_type_t,
        !           163:        private_eap_payload_t *this)
        !           164: {
        !           165:        return PLV2_EAP;
        !           166: }
        !           167: 
        !           168: METHOD(payload_t, get_next_type, payload_type_t,
        !           169:        private_eap_payload_t *this)
        !           170: {
        !           171:        return (this->next_payload);
        !           172: }
        !           173: 
        !           174: METHOD(payload_t, set_next_type, void,
        !           175:        private_eap_payload_t *this, payload_type_t type)
        !           176: {
        !           177:        this->next_payload = type;
        !           178: }
        !           179: 
        !           180: METHOD(payload_t, get_length, size_t,
        !           181:        private_eap_payload_t *this)
        !           182: {
        !           183:        return this->payload_length;
        !           184: }
        !           185: 
        !           186: METHOD(eap_payload_t, get_data, chunk_t,
        !           187:        private_eap_payload_t *this)
        !           188: {
        !           189:        return this->data;
        !           190: }
        !           191: 
        !           192: METHOD(eap_payload_t, set_data, void,
        !           193:        private_eap_payload_t *this, chunk_t data)
        !           194: {
        !           195:        free(this->data.ptr);
        !           196:        this->data = chunk_clone(data);
        !           197:        this->payload_length = this->data.len + 4;
        !           198: }
        !           199: 
        !           200: METHOD(eap_payload_t, get_code, eap_code_t,
        !           201:        private_eap_payload_t *this)
        !           202: {
        !           203:        if (this->data.len > 0)
        !           204:        {
        !           205:                return this->data.ptr[0];
        !           206:        }
        !           207:        /* should not happen, as it is verified */
        !           208:        return 0;
        !           209: }
        !           210: 
        !           211: METHOD(eap_payload_t, get_identifier, uint8_t,
        !           212:        private_eap_payload_t *this)
        !           213: {
        !           214:        if (this->data.len > 1)
        !           215:        {
        !           216:                return this->data.ptr[1];
        !           217:        }
        !           218:        /* should not happen, as it is verified */
        !           219:        return 0;
        !           220: }
        !           221: 
        !           222: /**
        !           223:  * Get the current type at the given offset into this->data.
        !           224:  * @return     the new offset or 0 if failed
        !           225:  */
        !           226: static size_t extract_type(private_eap_payload_t *this, size_t offset,
        !           227:                                               eap_type_t *type, uint32_t *vendor)
        !           228: {
        !           229:        if (this->data.len > offset)
        !           230:        {
        !           231:                *vendor = 0;
        !           232:                *type = this->data.ptr[offset];
        !           233:                if (*type != EAP_EXPANDED)
        !           234:                {
        !           235:                        return offset + 1;
        !           236:                }
        !           237:                if (this->data.len >= offset + 8)
        !           238:                {
        !           239:                        *vendor = untoh32(this->data.ptr + offset) & 0x00FFFFFF;
        !           240:                        *type = untoh32(this->data.ptr + offset + 4);
        !           241:                        return offset + 8;
        !           242:                }
        !           243:        }
        !           244:        return 0;
        !           245: }
        !           246: 
        !           247: METHOD(eap_payload_t, get_type, eap_type_t,
        !           248:        private_eap_payload_t *this, uint32_t *vendor)
        !           249: {
        !           250:        eap_type_t type;
        !           251: 
        !           252:        *vendor = 0;
        !           253:        if (extract_type(this, 4, &type, vendor))
        !           254:        {
        !           255:                return type;
        !           256:        }
        !           257:        return 0;
        !           258: }
        !           259: 
        !           260: /**
        !           261:  * Type enumerator
        !           262:  */
        !           263: typedef struct {
        !           264:        /** public interface */
        !           265:        enumerator_t public;
        !           266:        /** payload */
        !           267:        private_eap_payload_t *payload;
        !           268:        /** current offset in the data */
        !           269:        size_t offset;
        !           270: } type_enumerator_t;
        !           271: 
        !           272: METHOD(enumerator_t, enumerate_types, bool,
        !           273:        type_enumerator_t *this, va_list args)
        !           274: {
        !           275:        eap_type_t *type;
        !           276:        uint32_t *vendor;
        !           277: 
        !           278:        VA_ARGS_VGET(args, type, vendor);
        !           279:        this->offset = extract_type(this->payload, this->offset, type, vendor);
        !           280:        return this->offset;
        !           281: }
        !           282: 
        !           283: METHOD(eap_payload_t, get_types, enumerator_t*,
        !           284:        private_eap_payload_t *this)
        !           285: {
        !           286:        type_enumerator_t *enumerator;
        !           287:        eap_type_t type;
        !           288:        uint32_t vendor;
        !           289:        size_t offset;
        !           290: 
        !           291:        offset = extract_type(this, 4, &type, &vendor);
        !           292:        if (offset && type == EAP_NAK)
        !           293:        {
        !           294:                INIT(enumerator,
        !           295:                        .public = {
        !           296:                                .enumerate = enumerator_enumerate_default,
        !           297:                                .venumerate = _enumerate_types,
        !           298:                                .destroy = (void*)free,
        !           299:                        },
        !           300:                        .payload = this,
        !           301:                        .offset = offset,
        !           302:                );
        !           303:                return &enumerator->public;
        !           304:        }
        !           305:        return enumerator_create_empty();
        !           306: }
        !           307: 
        !           308: METHOD(eap_payload_t, is_expanded, bool,
        !           309:        private_eap_payload_t *this)
        !           310: {
        !           311:        return this->data.len > 4 ? this->data.ptr[4] == EAP_EXPANDED : FALSE;
        !           312: }
        !           313: 
        !           314: METHOD2(payload_t, eap_payload_t, destroy, void,
        !           315:        private_eap_payload_t *this)
        !           316: {
        !           317:        chunk_free(&this->data);
        !           318:        free(this);
        !           319: }
        !           320: 
        !           321: /*
        !           322:  * Described in header
        !           323:  */
        !           324: eap_payload_t *eap_payload_create()
        !           325: {
        !           326:        private_eap_payload_t *this;
        !           327: 
        !           328:        INIT(this,
        !           329:                .public = {
        !           330:                        .payload_interface = {
        !           331:                                .verify = _verify,
        !           332:                                .get_encoding_rules = _get_encoding_rules,
        !           333:                                .get_header_length = _get_header_length,
        !           334:                                .get_length = _get_length,
        !           335:                                .get_next_type = _get_next_type,
        !           336:                                .set_next_type = _set_next_type,
        !           337:                                .get_type = _get_payload_type,
        !           338:                                .destroy = _destroy,
        !           339:                        },
        !           340:                        .get_data = _get_data,
        !           341:                        .set_data = _set_data,
        !           342:                        .get_code = _get_code,
        !           343:                        .get_identifier = _get_identifier,
        !           344:                        .get_type = _get_type,
        !           345:                        .get_types = _get_types,
        !           346:                        .is_expanded = _is_expanded,
        !           347:                        .destroy = _destroy,
        !           348:                },
        !           349:                .next_payload = PL_NONE,
        !           350:                .payload_length = get_header_length(this),
        !           351:        );
        !           352:        return &this->public;
        !           353: }
        !           354: 
        !           355: /*
        !           356:  * Described in header
        !           357:  */
        !           358: eap_payload_t *eap_payload_create_data(chunk_t data)
        !           359: {
        !           360:        eap_payload_t *this = eap_payload_create();
        !           361: 
        !           362:        this->set_data(this, data);
        !           363:        return this;
        !           364: }
        !           365: 
        !           366: /*
        !           367:  * Described in header
        !           368:  */
        !           369: eap_payload_t *eap_payload_create_data_own(chunk_t data)
        !           370: {
        !           371:        eap_payload_t *this = eap_payload_create();
        !           372: 
        !           373:        this->set_data(this, data);
        !           374:        free(data.ptr);
        !           375:        return this;
        !           376: }
        !           377: 
        !           378: /*
        !           379:  * Described in header
        !           380:  */
        !           381: eap_payload_t *eap_payload_create_code(eap_code_t code, uint8_t identifier)
        !           382: {
        !           383:        chunk_t data;
        !           384: 
        !           385:        data = chunk_from_chars(code, identifier, 0, 0);
        !           386:        htoun16(data.ptr + 2, data.len);
        !           387:        return eap_payload_create_data(data);
        !           388: }
        !           389: 
        !           390: /**
        !           391:  * Write the given type either expanded or not
        !           392:  */
        !           393: static void write_type(bio_writer_t *writer, eap_type_t type, uint32_t vendor,
        !           394:                                           bool expanded)
        !           395: {
        !           396:        if (expanded)
        !           397:        {
        !           398:                writer->write_uint8(writer, EAP_EXPANDED);
        !           399:                writer->write_uint24(writer, vendor);
        !           400:                writer->write_uint32(writer, type);
        !           401:        }
        !           402:        else
        !           403:        {
        !           404:                writer->write_uint8(writer, type);
        !           405:        }
        !           406: }
        !           407: 
        !           408: /*
        !           409:  * Described in header
        !           410:  */
        !           411: eap_payload_t *eap_payload_create_nak(uint8_t identifier, eap_type_t type,
        !           412:                                                                          uint32_t vendor, bool expanded)
        !           413: {
        !           414:        enumerator_t *enumerator;
        !           415:        eap_type_t reg_type;
        !           416:        uint32_t reg_vendor;
        !           417:        bio_writer_t *writer;
        !           418:        chunk_t data;
        !           419:        bool added_any = FALSE, found_vendor = FALSE;
        !           420:        eap_payload_t *payload;
        !           421: 
        !           422:        writer = bio_writer_create(12);
        !           423:        writer->write_uint8(writer, EAP_RESPONSE);
        !           424:        writer->write_uint8(writer, identifier);
        !           425:        /* write zero length, we update it once we know the length */
        !           426:        writer->write_uint16(writer, 0);
        !           427: 
        !           428:        write_type(writer, EAP_NAK, 0, expanded);
        !           429: 
        !           430:        enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER);
        !           431:        while (enumerator->enumerate(enumerator, &reg_type, &reg_vendor))
        !           432:        {
        !           433:                if ((type && type != reg_type) ||
        !           434:                        (type && vendor && vendor != reg_vendor))
        !           435:                {       /* the preferred type is only sent if we actually find it */
        !           436:                        continue;
        !           437:                }
        !           438:                if (!reg_vendor || expanded)
        !           439:                {
        !           440:                        write_type(writer, reg_type, reg_vendor, expanded);
        !           441:                        added_any = TRUE;
        !           442:                }
        !           443:                else if (reg_vendor)
        !           444:                {       /* found vendor specific method, but this is not an expanded Nak */
        !           445:                        found_vendor = TRUE;
        !           446:                }
        !           447:        }
        !           448:        enumerator->destroy(enumerator);
        !           449: 
        !           450:        if (found_vendor)
        !           451:        {       /* request an expanded authentication type */
        !           452:                write_type(writer, EAP_EXPANDED, 0, expanded);
        !           453:                added_any = TRUE;
        !           454:        }
        !           455:        if (!added_any)
        !           456:        {       /* no methods added */
        !           457:                write_type(writer, 0, 0, expanded);
        !           458:        }
        !           459: 
        !           460:        /* set length */
        !           461:        data = writer->get_buf(writer);
        !           462:        htoun16(data.ptr + offsetof(eap_packet_t, length), data.len);
        !           463: 
        !           464:        payload = eap_payload_create_data(data);
        !           465:        writer->destroy(writer);
        !           466:        return payload;
        !           467: }

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