eap-radius: Add RADIUS Accounting session ID to Access-Request messages
[strongswan.git] / src / libcharon / plugins / eap_radius / eap_radius.c
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 attribte 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 pdding */
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 }