Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_radius/eap_radius.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012-2018 Tobias Brunner
3: * Copyright (C) 2009 Martin Willi
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include "eap_radius.h"
18: #include "eap_radius_plugin.h"
19: #include "eap_radius_forward.h"
20: #include "eap_radius_provider.h"
21: #include "eap_radius_accounting.h"
22:
23: #include <radius_message.h>
24: #include <radius_client.h>
25: #include <bio/bio_writer.h>
26:
27: #include <daemon.h>
28:
29: typedef struct private_eap_radius_t private_eap_radius_t;
30:
31: /**
32: * Private data of an eap_radius_t object.
33: */
34: struct private_eap_radius_t {
35:
36: /**
37: * Public authenticator_t interface.
38: */
39: eap_radius_t public;
40:
41: /**
42: * ID of the server
43: */
44: identification_t *server;
45:
46: /**
47: * ID of the peer
48: */
49: identification_t *peer;
50:
51: /**
52: * EAP method type we are proxying
53: */
54: eap_type_t type;
55:
56: /**
57: * EAP vendor, if any
58: */
59: uint32_t vendor;
60:
61: /**
62: * EAP message identifier
63: */
64: uint8_t identifier;
65:
66: /**
67: * RADIUS client instance
68: */
69: radius_client_t *client;
70:
71: /**
72: * TRUE to use EAP-Start, FALSE to send EAP-Identity Response directly
73: */
74: bool eap_start;
75:
76: /**
77: * Prefix to prepend to EAP identity
78: */
79: char *id_prefix;
80: };
81:
82: /**
83: * Add EAP-Identity to RADIUS message
84: */
85: static void add_eap_identity(private_eap_radius_t *this,
86: radius_message_t *request)
87: {
88: struct {
89: /** EAP code (REQUEST/RESPONSE) */
90: uint8_t code;
91: /** unique message identifier */
92: uint8_t identifier;
93: /** length of whole message */
94: uint16_t length;
95: /** EAP type */
96: uint8_t type;
97: /** identity data */
98: uint8_t data[];
99: } __attribute__((__packed__)) *hdr;
100: chunk_t id, prefix;
101: size_t len;
102:
103: id = this->peer->get_encoding(this->peer);
104: prefix = chunk_create(this->id_prefix, strlen(this->id_prefix));
105: len = sizeof(*hdr) + prefix.len + id.len;
106:
107: hdr = alloca(len);
108: hdr->code = EAP_RESPONSE;
109: hdr->identifier = this->identifier;
110: hdr->length = htons(len);
111: hdr->type = EAP_IDENTITY;
112: memcpy(hdr->data, prefix.ptr, prefix.len);
113: memcpy(hdr->data + prefix.len, id.ptr, id.len);
114:
115: request->add(request, RAT_EAP_MESSAGE, chunk_create((u_char*)hdr, len));
116: }
117:
118: /**
119: * Copy EAP-Message attribute from RADIUS message to an new EAP payload
120: */
121: static bool radius2ike(private_eap_radius_t *this,
122: radius_message_t *msg, eap_payload_t **out)
123: {
124: enumerator_t *enumerator;
125: eap_payload_t *payload;
126: chunk_t data, message = chunk_empty;
127: int type;
128:
129: enumerator = msg->create_enumerator(msg);
130: while (enumerator->enumerate(enumerator, &type, &data))
131: {
132: if (type == RAT_EAP_MESSAGE && data.len)
133: {
134: message = chunk_cat("mc", message, data);
135: }
136: }
137: enumerator->destroy(enumerator);
138: if (message.len)
139: {
140: *out = payload = eap_payload_create_data(message);
141:
142: /* apply EAP method selected by RADIUS server */
143: this->type = payload->get_type(payload, &this->vendor);
144:
145: DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &message);
146: free(message.ptr);
147: return TRUE;
148: }
149: return FALSE;
150: }
151:
152: /**
153: * See header.
154: */
155: void eap_radius_build_attributes(radius_message_t *request)
156: {
157: ike_sa_t *ike_sa;
158: host_t *host;
159: char buf[40], *station_id_fmt, *session_id;
160: uint32_t value;
161: chunk_t chunk;
162:
163: /* virtual NAS-Port-Type */
164: value = htonl(5);
165: request->add(request, RAT_NAS_PORT_TYPE, chunk_from_thing(value));
166: /* framed ServiceType */
167: value = htonl(2);
168: request->add(request, RAT_SERVICE_TYPE, chunk_from_thing(value));
169:
170: ike_sa = charon->bus->get_sa(charon->bus);
171: if (ike_sa)
172: {
173: value = htonl(ike_sa->get_unique_id(ike_sa));
174: request->add(request, RAT_NAS_PORT, chunk_from_thing(value));
175: request->add(request, RAT_NAS_PORT_ID,
176: chunk_from_str(ike_sa->get_name(ike_sa)));
177:
178: host = ike_sa->get_my_host(ike_sa);
179: chunk = host->get_address(host);
180: switch (host->get_family(host))
181: {
182: case AF_INET:
183: request->add(request, RAT_NAS_IP_ADDRESS, chunk);
184: break;
185: case AF_INET6:
186: request->add(request, RAT_NAS_IPV6_ADDRESS, chunk);
187: default:
188: break;
189: }
190: if (lib->settings->get_bool(lib->settings,
191: "%s.plugins.eap-radius.station_id_with_port",
192: TRUE, lib->ns))
193: {
194: station_id_fmt = "%#H";
195: }
196: else
197: {
198: station_id_fmt = "%H";
199: }
200: snprintf(buf, sizeof(buf), station_id_fmt, host);
201: request->add(request, RAT_CALLED_STATION_ID, chunk_from_str(buf));
202: host = ike_sa->get_other_host(ike_sa);
203: snprintf(buf, sizeof(buf), station_id_fmt, host);
204: request->add(request, RAT_CALLING_STATION_ID, chunk_from_str(buf));
205:
206: session_id = eap_radius_accounting_session_id(ike_sa);
207: if (session_id)
208: {
209: request->add(request, RAT_ACCT_SESSION_ID,
210: chunk_from_str(session_id));
211: free(session_id);
212: }
213: }
214: }
215:
216: /**
217: * Add a set of RADIUS attributes to a request message
218: */
219: static void add_radius_request_attrs(private_eap_radius_t *this,
220: radius_message_t *request)
221: {
222: chunk_t chunk;
223:
224: chunk = chunk_from_str(this->id_prefix);
225: chunk = chunk_cata("cc", chunk, this->peer->get_encoding(this->peer));
226: request->add(request, RAT_USER_NAME, chunk);
227:
228: eap_radius_build_attributes(request);
229: eap_radius_forward_from_ike(request);
230: }
231:
232: METHOD(eap_method_t, initiate, status_t,
233: private_eap_radius_t *this, eap_payload_t **out)
234: {
235: radius_message_t *request, *response;
236: status_t status = FAILED;
237:
238: request = radius_message_create(RMC_ACCESS_REQUEST);
239: add_radius_request_attrs(this, request);
240:
241: if (this->eap_start)
242: {
243: request->add(request, RAT_EAP_MESSAGE, chunk_empty);
244: }
245: else
246: {
247: add_eap_identity(this, request);
248: }
249:
250: response = this->client->request(this->client, request);
251: if (response)
252: {
253: eap_radius_forward_to_ike(response);
254: switch (response->get_code(response))
255: {
256: case RMC_ACCESS_CHALLENGE:
257: if (radius2ike(this, response, out))
258: {
259: status = NEED_MORE;
260: }
261: break;
262: case RMC_ACCESS_ACCEPT:
263: /* Microsoft RADIUS servers can run in a mode where they respond
264: * like this on the first request (i.e. without authentication),
265: * we treat this as Access-Reject */
266: case RMC_ACCESS_REJECT:
267: default:
268: DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
269: this->peer);
270: break;
271: }
272: response->destroy(response);
273: }
274: else
275: {
276: eap_radius_handle_timeout(NULL);
277: }
278: request->destroy(request);
279: return status;
280: }
281:
282: /**
283: * Handle the Class attribute
284: */
285: static void process_class(radius_message_t *msg)
286: {
287: enumerator_t *enumerator;
288: ike_sa_t *ike_sa;
289: identification_t *id;
290: auth_cfg_t *auth;
291: chunk_t data;
292: bool class_group, class_send;
293: int type;
294:
295: class_group = lib->settings->get_bool(lib->settings,
296: "%s.plugins.eap-radius.class_group", FALSE, lib->ns);
297: class_send = lib->settings->get_bool(lib->settings,
298: "%s.plugins.eap-radius.accounting_send_class", FALSE, lib->ns);
299: ike_sa = charon->bus->get_sa(charon->bus);
300:
301: if ((!class_group && !class_send) || !ike_sa)
302: {
303: return;
304: }
305:
306: enumerator = msg->create_enumerator(msg);
307: while (enumerator->enumerate(enumerator, &type, &data))
308: {
309: if (type == RAT_CLASS)
310: {
311: if (class_group && data.len < 44)
312: { /* quirk: ignore long class attributes, these are used for
313: * other purposes by some RADIUS servers (such as NPS). */
314: auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
315: id = identification_create_from_data(data);
316: DBG1(DBG_CFG, "received group membership '%Y' from RADIUS",
317: id);
318: auth->add(auth, AUTH_RULE_GROUP, id);
319: }
320: if (class_send)
321: {
322: eap_radius_accounting_add_class(ike_sa, data);
323: }
324: }
325: }
326: enumerator->destroy(enumerator);
327: }
328:
329: /**
330: * Handle the Filter-Id attribute as IPsec CHILD_SA name
331: */
332: static void process_filter_id(radius_message_t *msg)
333: {
334: enumerator_t *enumerator;
335: int type;
336: uint8_t tunnel_tag;
337: uint32_t tunnel_type;
338: chunk_t filter_id = chunk_empty, data;
339: bool is_esp_tunnel = FALSE;
340:
341: enumerator = msg->create_enumerator(msg);
342: while (enumerator->enumerate(enumerator, &type, &data))
343: {
344: switch (type)
345: {
346: case RAT_TUNNEL_TYPE:
347: if (data.len != 4)
348: {
349: continue;
350: }
351: tunnel_tag = *data.ptr;
352: *data.ptr = 0x00;
353: tunnel_type = untoh32(data.ptr);
354: DBG1(DBG_IKE, "received RADIUS attribute Tunnel-Type: "
355: "tag = %u, value = %u", tunnel_tag, tunnel_type);
356: is_esp_tunnel = (tunnel_type == RADIUS_TUNNEL_TYPE_ESP);
357: break;
358: case RAT_FILTER_ID:
359: filter_id = data;
360: DBG1(DBG_IKE, "received RADIUS attribute Filter-Id: "
361: "'%.*s'", (int)filter_id.len, filter_id.ptr);
362: break;
363: default:
364: break;
365: }
366: }
367: enumerator->destroy(enumerator);
368:
369: if (is_esp_tunnel && filter_id.len)
370: {
371: identification_t *id;
372: ike_sa_t *ike_sa;
373: auth_cfg_t *auth;
374:
375: ike_sa = charon->bus->get_sa(charon->bus);
376: if (ike_sa)
377: {
378: auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
379: id = identification_create_from_data(filter_id);
380: auth->add(auth, AUTH_RULE_GROUP, id);
381: }
382: }
383: }
384:
385: /**
386: * Handle Session-Timeout attribute and Interim updates
387: */
388: static void process_timeout(radius_message_t *msg)
389: {
390: enumerator_t *enumerator;
391: ike_sa_t *ike_sa;
392: chunk_t data;
393: int type;
394:
395: ike_sa = charon->bus->get_sa(charon->bus);
396: if (ike_sa)
397: {
398: enumerator = msg->create_enumerator(msg);
399: while (enumerator->enumerate(enumerator, &type, &data))
400: {
401: if (type == RAT_SESSION_TIMEOUT && data.len == 4)
402: {
403: ike_sa->set_auth_lifetime(ike_sa, untoh32(data.ptr));
404: }
405: else if (type == RAT_ACCT_INTERIM_INTERVAL && data.len == 4)
406: {
407: eap_radius_accounting_start_interim(ike_sa, untoh32(data.ptr));
408: }
409: }
410: enumerator->destroy(enumerator);
411: }
412: }
413:
414: /**
415: * Add a Cisco Unity configuration attribute
416: */
417: static void add_unity_attribute(eap_radius_provider_t *provider, uint32_t id,
418: int type, chunk_t data)
419: {
420: switch (type)
421: {
422: case 15: /* CVPN3000-IPSec-Banner1 */
423: case 36: /* CVPN3000-IPSec-Banner2 */
424: provider->add_attribute(provider, id, UNITY_BANNER, data);
425: break;
426: case 28: /* CVPN3000-IPSec-Default-Domain */
427: provider->add_attribute(provider, id, UNITY_DEF_DOMAIN, data);
428: break;
429: case 29: /* CVPN3000-IPSec-Split-DNS-Names */
430: provider->add_attribute(provider, id, UNITY_SPLITDNS_NAME, data);
431: break;
432: }
433: }
434:
435: /**
436: * Add a DNS/NBNS configuration attribute
437: */
438: static void add_nameserver_attribute(eap_radius_provider_t *provider,
439: uint32_t id, int type, chunk_t data)
440: {
441: /* these are from different vendors, but there is currently no conflict */
442: switch (type)
443: {
444: case 5: /* CVPN3000-Primary-DNS */
445: case 6: /* CVPN3000-Secondary-DNS */
446: case 28: /* MS-Primary-DNS-Server */
447: case 29: /* MS-Secondary-DNS-Server */
448: provider->add_attribute(provider, id, INTERNAL_IP4_DNS, data);
449: break;
450: case 7: /* CVPN3000-Primary-WINS */
451: case 8: /* CVPN3000-Secondary-WINS */
452: case 30: /* MS-Primary-NBNS-Server */
453: case 31: /* MS-Secondary-NBNS-Server */
454: provider->add_attribute(provider, id, INTERNAL_IP4_NBNS, data);
455: break;
456: case RAT_FRAMED_IPV6_DNS_SERVER:
457: provider->add_attribute(provider, id, INTERNAL_IP6_DNS, data);
458: break;
459: }
460: }
461:
462: /**
463: * Add a UNITY_LOCAL_LAN or UNITY_SPLIT_INCLUDE attribute
464: */
465: static void add_unity_split_attribute(eap_radius_provider_t *provider,
466: uint32_t id, configuration_attribute_type_t type,
467: chunk_t data)
468: {
469: enumerator_t *enumerator;
470: bio_writer_t *writer;
471: char buffer[256], *token, *slash;
472:
473: if (snprintf(buffer, sizeof(buffer), "%.*s", (int)data.len,
474: data.ptr) >= sizeof(buffer))
475: {
476: return;
477: }
478: writer = bio_writer_create(16); /* two IPv4 addresses and 6 bytes padding */
479: enumerator = enumerator_create_token(buffer, ",", " ");
480: while (enumerator->enumerate(enumerator, &token))
481: {
482: host_t *net, *mask = NULL;
483: chunk_t padding;
484:
485: slash = strchr(token, '/');
486: if (slash)
487: {
488: *slash++ = '\0';
489: mask = host_create_from_string(slash, 0);
490: }
491: if (!mask)
492: { /* default to /32 */
493: mask = host_create_from_string("255.255.255.255", 0);
494: }
495: net = host_create_from_string(token, 0);
496: if (!net || net->get_family(net) != AF_INET ||
497: mask->get_family(mask) != AF_INET)
498: {
499: mask->destroy(mask);
500: DESTROY_IF(net);
501: continue;
502: }
503: writer->write_data(writer, net->get_address(net));
504: writer->write_data(writer, mask->get_address(mask));
505: padding = writer->skip(writer, 6); /* 6 bytes padding */
506: memset(padding.ptr, 0, padding.len);
507: mask->destroy(mask);
508: net->destroy(net);
509: }
510: enumerator->destroy(enumerator);
511:
512: data = writer->get_buf(writer);
513: if (data.len)
514: {
515: provider->add_attribute(provider, id, type, data);
516: }
517: writer->destroy(writer);
518: }
519:
520: /**
521: * Handle Framed-IP-Address and other IKE configuration attributes
522: */
523: static void process_cfg_attributes(radius_message_t *msg)
524: {
525: eap_radius_provider_t *provider;
526: enumerator_t *enumerator;
527: ike_sa_t *ike_sa;
528: host_t *host;
529: chunk_t data;
530: configuration_attribute_type_t split_type = 0;
531: int type, vendor;
532:
533: ike_sa = charon->bus->get_sa(charon->bus);
534: provider = eap_radius_provider_get();
535: if (provider && ike_sa)
536: {
537: enumerator = msg->create_enumerator(msg);
538: while (enumerator->enumerate(enumerator, &type, &data))
539: {
540: if ((type == RAT_FRAMED_IP_ADDRESS && data.len == 4) ||
541: (type == RAT_FRAMED_IPV6_ADDRESS && data.len == 16))
542: {
543: host = host_create_from_chunk(AF_UNSPEC, data, 0);
544: if (host)
545: {
546: provider->add_framed_ip(provider,
547: ike_sa->get_unique_id(ike_sa), host);
548: }
549: }
550: else if (type == RAT_FRAMED_IP_NETMASK && data.len == 4)
551: {
552: provider->add_attribute(provider, ike_sa->get_unique_id(ike_sa),
553: INTERNAL_IP4_NETMASK, data);
554: }
555: else if (type == RAT_FRAMED_IPV6_DNS_SERVER && data.len == 16)
556: {
557: add_nameserver_attribute(provider,
558: ike_sa->get_unique_id(ike_sa), type, data);
559: }
560: }
561: enumerator->destroy(enumerator);
562:
563: enumerator = msg->create_vendor_enumerator(msg);
564: while (enumerator->enumerate(enumerator, &vendor, &type, &data))
565: {
566: if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */)
567: {
568: switch (type)
569: {
570: case 5: /* CVPN3000-Primary-DNS */
571: case 6: /* CVPN3000-Secondary-DNS */
572: case 7: /* CVPN3000-Primary-WINS */
573: case 8: /* CVPN3000-Secondary-WINS */
574: if (data.len == 4)
575: {
576: add_nameserver_attribute(provider,
577: ike_sa->get_unique_id(ike_sa), type, data);
578: }
579: break;
580: case 15: /* CVPN3000-IPSec-Banner1 */
581: case 28: /* CVPN3000-IPSec-Default-Domain */
582: case 29: /* CVPN3000-IPSec-Split-DNS-Names */
583: case 36: /* CVPN3000-IPSec-Banner2 */
584: if (ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
585: {
586: add_unity_attribute(provider,
587: ike_sa->get_unique_id(ike_sa), type, data);
588: }
589: break;
590: case 55: /* CVPN3000-IPSec-Split-Tunneling-Policy */
591: if (data.len)
592: {
593: switch (data.ptr[data.len - 1])
594: {
595: case 0: /* tunnelall */
596: default:
597: break;
598: case 1: /* tunnelspecified */
599: split_type = UNITY_SPLIT_INCLUDE;
600: break;
601: case 2: /* excludespecified */
602: split_type = UNITY_LOCAL_LAN;
603: break;
604: }
605: }
606: break;
607: default:
608: break;
609: }
610: }
611: if (vendor == PEN_MICROSOFT)
612: {
613: switch (type)
614: {
615: case 28: /* MS-Primary-DNS-Server */
616: case 29: /* MS-Secondary-DNS-Server */
617: case 30: /* MS-Primary-NBNS-Server */
618: case 31: /* MS-Secondary-NBNS-Server */
619: if (data.len == 4)
620: {
621: add_nameserver_attribute(provider,
622: ike_sa->get_unique_id(ike_sa), type, data);
623: }
624: break;
625: }
626: }
627: }
628: enumerator->destroy(enumerator);
629:
630: if (split_type != 0 &&
631: ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
632: {
633: enumerator = msg->create_vendor_enumerator(msg);
634: while (enumerator->enumerate(enumerator, &vendor, &type, &data))
635: {
636: if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */ &&
637: type == 27 /* CVPN3000-IPSec-Split-Tunnel-List */)
638: {
639: add_unity_split_attribute(provider,
640: ike_sa->get_unique_id(ike_sa), split_type, data);
641: }
642: }
643: enumerator->destroy(enumerator);
644: }
645: }
646: }
647:
648: /**
649: * See header.
650: */
651: void eap_radius_process_attributes(radius_message_t *message)
652: {
653: process_class(message);
654: if (lib->settings->get_bool(lib->settings,
655: "%s.plugins.eap-radius.filter_id", FALSE, lib->ns))
656: {
657: process_filter_id(message);
658: }
659: process_timeout(message);
660: process_cfg_attributes(message);
661: }
662:
663: METHOD(eap_method_t, process, status_t,
664: private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out)
665: {
666: radius_message_t *request, *response;
667: status_t status = FAILED;
668: chunk_t data;
669:
670: request = radius_message_create(RMC_ACCESS_REQUEST);
671: add_radius_request_attrs(this, request);
672:
673: data = in->get_data(in);
674: DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &data);
675:
676: /* fragment data suitable for RADIUS */
677: while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
678: {
679: request->add(request, RAT_EAP_MESSAGE,
680: chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE));
681: data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
682: }
683: request->add(request, RAT_EAP_MESSAGE, data);
684:
685: response = this->client->request(this->client, request);
686: if (response)
687: {
688: eap_radius_forward_to_ike(response);
689: switch (response->get_code(response))
690: {
691: case RMC_ACCESS_CHALLENGE:
692: if (radius2ike(this, response, out))
693: {
694: status = NEED_MORE;
695: break;
696: }
697: status = FAILED;
698: break;
699: case RMC_ACCESS_ACCEPT:
700: eap_radius_process_attributes(response);
701: DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful",
702: this->peer);
703: status = SUCCESS;
704: break;
705: case RMC_ACCESS_REJECT:
706: default:
707: DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
708: this->peer);
709: status = FAILED;
710: break;
711: }
712: response->destroy(response);
713: }
714: request->destroy(request);
715: return status;
716: }
717:
718: METHOD(eap_method_t, get_type, eap_type_t,
719: private_eap_radius_t *this, uint32_t *vendor)
720: {
721: *vendor = this->vendor;
722: return this->type;
723: }
724:
725: METHOD(eap_method_t, get_msk, status_t,
726: private_eap_radius_t *this, chunk_t *out)
727: {
728: chunk_t msk;
729:
730: msk = this->client->get_msk(this->client);
731: if (msk.len)
732: {
733: *out = msk;
734: return SUCCESS;
735: }
736: return FAILED;
737: }
738:
739: METHOD(eap_method_t, get_identifier, uint8_t,
740: private_eap_radius_t *this)
741: {
742: return this->identifier;
743: }
744:
745: METHOD(eap_method_t, set_identifier, void,
746: private_eap_radius_t *this, uint8_t identifier)
747: {
748: this->identifier = identifier;
749: }
750:
751: METHOD(eap_method_t, is_mutual, bool,
752: private_eap_radius_t *this)
753: {
754: switch (this->type)
755: {
756: case EAP_AKA:
757: case EAP_SIM:
758: return TRUE;
759: default:
760: return FALSE;
761: }
762: }
763:
764: METHOD(eap_method_t, destroy, void,
765: private_eap_radius_t *this)
766: {
767: this->peer->destroy(this->peer);
768: this->server->destroy(this->server);
769: this->client->destroy(this->client);
770: free(this);
771: }
772:
773: /**
774: * Generic constructor
775: */
776: eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer)
777: {
778: private_eap_radius_t *this;
779:
780: INIT(this,
781: .public = {
782: .eap_method = {
783: .initiate = _initiate,
784: .process = _process,
785: .get_type = _get_type,
786: .is_mutual = _is_mutual,
787: .get_msk = _get_msk,
788: .get_identifier = _get_identifier,
789: .set_identifier = _set_identifier,
790: .destroy = _destroy,
791: },
792: },
793: /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
794: .type = EAP_RADIUS,
795: .eap_start = lib->settings->get_bool(lib->settings,
796: "%s.plugins.eap-radius.eap_start", FALSE,
797: lib->ns),
798: .id_prefix = lib->settings->get_str(lib->settings,
799: "%s.plugins.eap-radius.id_prefix", "",
800: lib->ns),
801: );
802: this->client = eap_radius_create_client();
803: if (!this->client)
804: {
805: free(this);
806: return NULL;
807: }
808: this->peer = peer->clone(peer);
809: this->server = server->clone(server);
810: return &this->public;
811: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>