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, ®_type, ®_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>