Annotation of embedaddon/strongswan/src/libcharon/encoding/payloads/eap_payload.c, revision 1.1.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>