Return to eap_payload.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / encoding / payloads |
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: }