moved tnc_imv plugin to libtnccs thanks to recommendation callback function
[strongswan.git] / src / libcharon / plugins / tnc_pdp / tnc_pdp.c
1 /*
2 * Copyright (C) 2012-2013 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tnc_pdp.h"
17 #include "tnc_pdp_connections.h"
18
19 #include <errno.h>
20 #include <unistd.h>
21
22 #include <radius_message.h>
23 #include <radius_mppe.h>
24
25 #include <pt_tls_server.h>
26
27 #include <tnc/tnc.h>
28
29 #include <tncifimv.h>
30 #include <tncif_names.h>
31
32 #include <daemon.h>
33 #include <utils/debug.h>
34 #include <pen/pen.h>
35 #include <threading/thread.h>
36 #include <processing/jobs/callback_job.h>
37 #include <sa/eap/eap_method.h>
38
39 typedef struct private_tnc_pdp_t private_tnc_pdp_t;
40
41 /**
42 * Default RADIUS port, when not configured
43 */
44 #define RADIUS_PORT 1812
45
46 /**
47 * Maximum size of a RADIUS IP packet
48 */
49 #define MAX_PACKET 4096
50
51 /**
52 * private data of tnc_pdp_t
53 */
54 struct private_tnc_pdp_t {
55
56 /**
57 * implements tnc_pdp_t interface
58 */
59 tnc_pdp_t public;
60
61 /**
62 * ID of the server
63 */
64 identification_t *server;
65
66 /**
67 * EAP method type to be used
68 */
69 eap_type_t type;
70
71 /**
72 * PT-TLS IPv4 socket
73 */
74 int pt_tls_ipv4;
75
76 /**
77 * PT-TLS IPv6 socket
78 */
79 int pt_tls_ipv6;
80
81 /**
82 * RADIUS IPv4 socket
83 */
84 int radius_ipv4;
85
86 /**
87 * RADIUS IPv6 socket
88 */
89 int radius_ipv6;
90
91 /**
92 * RADIUS shared secret
93 */
94 chunk_t secret;
95
96 /**
97 * MD5 hasher
98 */
99 hasher_t *hasher;
100
101 /**
102 * HMAC MD5 signer, with secret set
103 */
104 signer_t *signer;
105
106 /**
107 * Nonce generator for MS-MPPE salt values
108 */
109 nonce_gen_t *ng;
110
111 /**
112 * List of registered TNC-PDP connections
113 */
114 tnc_pdp_connections_t *connections;
115
116 };
117
118 /**
119 * Open IPv4 or IPv6 UDP socket
120 */
121 static int open_udp_socket(int family, u_int16_t port)
122 {
123 int on = TRUE;
124 struct sockaddr_storage addr;
125 socklen_t addrlen;
126 int skt;
127
128 memset(&addr, 0, sizeof(addr));
129 addr.ss_family = family;
130
131 /* precalculate constants depending on address family */
132 switch (family)
133 {
134 case AF_INET:
135 {
136 struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
137
138 htoun32(&sin->sin_addr.s_addr, INADDR_ANY);
139 htoun16(&sin->sin_port, port);
140 addrlen = sizeof(struct sockaddr_in);
141 break;
142 }
143 case AF_INET6:
144 {
145 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
146
147 memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
148 htoun16(&sin6->sin6_port, port);
149 addrlen = sizeof(struct sockaddr_in6);
150 break;
151 }
152 default:
153 return 0;
154 }
155
156 /* open the socket */
157 skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
158 if (skt < 0)
159 {
160 DBG1(DBG_CFG, "opening UDP socket failed: %s", strerror(errno));
161 return 0;
162 }
163 if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
164 {
165 DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s",
166 strerror(errno));
167 close(skt);
168 return 0;
169 }
170 if (family == AF_INET6)
171 {
172 if (setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY,
173 (void *)&on, sizeof(on)) < 0)
174 {
175 DBG1(DBG_CFG, "unable to set IPV6_V6ONLY on socket: %s",
176 strerror(errno));
177 close(skt);
178 return 0;
179 }
180 }
181
182 /* bind the socket */
183 if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0)
184 {
185 DBG1(DBG_CFG, "unable to bind UDP socket: %s", strerror(errno));
186 close(skt);
187 return 0;
188 }
189
190 return skt;
191 }
192
193 /**
194 * Open IPv4 or IPv6 TCP socket
195 */
196 static int open_tcp_socket(int family, u_int16_t port)
197 {
198 int on = TRUE;
199 struct sockaddr_storage addr;
200 socklen_t addrlen;
201 int skt;
202
203 memset(&addr, 0, sizeof(addr));
204 addr.ss_family = family;
205
206 /* precalculate constants depending on address family */
207 switch (family)
208 {
209 case AF_INET:
210 {
211 struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
212
213 htoun32(&sin->sin_addr.s_addr, INADDR_ANY);
214 htoun16(&sin->sin_port, port);
215 addrlen = sizeof(struct sockaddr_in);
216 break;
217 }
218 case AF_INET6:
219 {
220 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
221
222 memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
223 htoun16(&sin6->sin6_port, port);
224 addrlen = sizeof(struct sockaddr_in6);
225 break;
226 }
227 default:
228 return 0;
229 }
230
231 /* open the socket */
232 skt = socket(family, SOCK_STREAM, IPPROTO_TCP);
233 if (skt < 0)
234 {
235 DBG1(DBG_CFG, "opening TCP socket failed: %s", strerror(errno));
236 return 0;
237 }
238 if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
239 {
240 DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s",
241 strerror(errno));
242 close(skt);
243 return 0;
244 }
245 if (family == AF_INET6)
246 {
247 if (setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY,
248 (void *)&on, sizeof(on)) < 0)
249 {
250 DBG1(DBG_CFG, "unable to set IPV6_V6ONLY on socket: %s",
251 strerror(errno));
252 close(skt);
253 return 0;
254 }
255 }
256
257 /* bind the socket */
258 if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0)
259 {
260 DBG1(DBG_CFG, "unable to bind TCP socket: %s", strerror(errno));
261 close(skt);
262 return 0;
263 }
264
265 /* start listening on socket */
266 if (listen(skt, 5) == -1)
267 {
268 DBG1(DBG_TNC, "listen on TCP socket failed: %s", strerror(errno));
269 close(skt);
270 return 0;
271 }
272
273 return skt;
274 }
275
276 /**
277 * Send a RADIUS message to client
278 */
279 static void send_message(private_tnc_pdp_t *this, radius_message_t *message,
280 host_t *client)
281 {
282 int fd;
283 chunk_t data;
284
285 fd = (client->get_family(client) == AF_INET) ?
286 this->radius_ipv4 : this->radius_ipv6;
287 data = message->get_encoding(message);
288
289 DBG2(DBG_CFG, "sending RADIUS packet to %#H", client);
290 DBG3(DBG_CFG, "%B", &data);
291
292 if (sendto(fd, data.ptr, data.len, 0, client->get_sockaddr(client),
293 *client->get_sockaddr_len(client)) != data.len)
294 {
295 DBG1(DBG_CFG, "sending RADIUS message failed: %s", strerror(errno));
296 }
297 }
298
299 /**
300 * Encrypt a MS-MPPE-Send/Recv-Key
301 */
302 static chunk_t encrypt_mppe_key(private_tnc_pdp_t *this, u_int8_t type,
303 chunk_t key, u_int16_t *salt,
304 radius_message_t *request)
305 {
306 chunk_t a, r, seed, data;
307 u_char b[HASH_SIZE_MD5], *c;
308 mppe_key_t *mppe_key;
309
310 /**
311 * From RFC2548 (encryption):
312 * b(1) = MD5(S + R + A) c(1) = p(1) xor b(1) C = c(1)
313 * b(2) = MD5(S + c(1)) c(2) = p(2) xor b(2) C = C + c(2)
314 * . . .
315 * b(i) = MD5(S + c(i-1)) c(i) = p(i) xor b(i) C = C + c(i)
316 */
317
318 data = chunk_alloc(sizeof(mppe_key_t) +
319 HASH_SIZE_MD5 * (1 + key.len / HASH_SIZE_MD5));
320 memset(data.ptr, 0x00, data.len);
321
322 mppe_key = (mppe_key_t*)data.ptr;
323 mppe_key->id = htonl(PEN_MICROSOFT);
324 mppe_key->type = type;
325 mppe_key->length = data.len - sizeof(mppe_key->id);
326 mppe_key->key[0] = key.len;
327
328 memcpy(&mppe_key->key[1], key.ptr, key.len);
329
330 /**
331 * generate a 16 bit unique random salt value for the MPPE stream cipher
332 * the MSB of the salt MUST be set to 1
333 */
334 a = chunk_create((u_char*)&(mppe_key->salt), sizeof(mppe_key->salt));
335 do
336 {
337 if (!this->ng->get_nonce(this->ng, a.len, a.ptr))
338 {
339 free(data.ptr);
340 return chunk_empty;
341 }
342 *a.ptr |= 0x80;
343 }
344 while (mppe_key->salt == *salt);
345
346 /* update the salt value */
347 *salt = mppe_key->salt;
348
349 r = chunk_create(request->get_authenticator(request), HASH_SIZE_MD5);
350 seed = chunk_cata("cc", r, a);
351
352 c = mppe_key->key;
353 while (c < data.ptr + data.len)
354 {
355 /* b(i) = MD5(S + c(i-1)) */
356 if (!this->hasher->get_hash(this->hasher, this->secret, NULL) ||
357 !this->hasher->get_hash(this->hasher, seed, b))
358 {
359 free(data.ptr);
360 return chunk_empty;
361 }
362
363 /* c(i) = b(i) xor p(1) */
364 memxor(c, b, HASH_SIZE_MD5);
365
366 /* prepare next round */
367 seed = chunk_create(c, HASH_SIZE_MD5);
368 c += HASH_SIZE_MD5;
369 }
370
371 return data;
372 }
373
374 /**
375 * Send a RADIUS response for a request
376 */
377 static void send_response(private_tnc_pdp_t *this, radius_message_t *request,
378 radius_message_code_t code, eap_payload_t *eap,
379 identification_t *group, chunk_t msk, host_t *client)
380 {
381 radius_message_t *response;
382 chunk_t data, recv, send;
383 u_int32_t tunnel_type;
384 u_int16_t salt = 0;
385
386 response = radius_message_create(code);
387 data = eap->get_data(eap);
388 DBG3(DBG_CFG, "%N payload %B", eap_type_names, this->type, &data);
389
390 /* fragment data suitable for RADIUS */
391 while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
392 {
393 response->add(response, RAT_EAP_MESSAGE,
394 chunk_create(data.ptr, MAX_RADIUS_ATTRIBUTE_SIZE));
395 data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
396 }
397 response->add(response, RAT_EAP_MESSAGE, data);
398
399 if (group)
400 {
401 tunnel_type = RADIUS_TUNNEL_TYPE_ESP;
402 htoun32(data.ptr, tunnel_type);
403 data.len = sizeof(tunnel_type);
404 response->add(response, RAT_TUNNEL_TYPE, data);
405 response->add(response, RAT_FILTER_ID, group->get_encoding(group));
406 }
407 if (msk.len)
408 {
409 recv = chunk_create(msk.ptr, msk.len / 2);
410 data = encrypt_mppe_key(this, MS_MPPE_RECV_KEY, recv, &salt, request);
411 response->add(response, RAT_VENDOR_SPECIFIC, data);
412 chunk_free(&data);
413
414 send = chunk_create(msk.ptr + recv.len, msk.len - recv.len);
415 data = encrypt_mppe_key(this, MS_MPPE_SEND_KEY, send, &salt, request);
416 response->add(response, RAT_VENDOR_SPECIFIC, data);
417 chunk_free(&data);
418 }
419 response->set_identifier(response, request->get_identifier(request));
420 if (response->sign(response, request->get_authenticator(request),
421 this->secret, this->hasher, this->signer, NULL, TRUE))
422 {
423 DBG1(DBG_CFG, "sending RADIUS %N to client '%H'",
424 radius_message_code_names, code, client);
425 send_message(this, response, client);
426 }
427 response->destroy(response);
428 }
429
430 /**
431 * Process EAP message
432 */
433 static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
434 host_t *source)
435 {
436 enumerator_t *enumerator;
437 eap_payload_t *in, *out = NULL;
438 eap_method_t *method;
439 eap_type_t eap_type;
440 u_int32_t eap_vendor;
441 chunk_t data, message = chunk_empty, msk = chunk_empty;
442 chunk_t user_name = chunk_empty, nas_id = chunk_empty;
443 identification_t *group = NULL;
444 radius_message_code_t code = RMC_ACCESS_CHALLENGE;
445 int type;
446
447 enumerator = request->create_enumerator(request);
448 while (enumerator->enumerate(enumerator, &type, &data))
449 {
450 switch (type)
451 {
452 case RAT_USER_NAME:
453 user_name = data;
454 break;
455 case RAT_NAS_IDENTIFIER:
456 nas_id = data;
457 break;
458 case RAT_EAP_MESSAGE:
459 if (data.len)
460 {
461 message = chunk_cat("mc", message, data);
462 }
463 break;
464 default:
465 break;
466 }
467 }
468 enumerator->destroy(enumerator);
469
470 if (message.len)
471 {
472 in = eap_payload_create_data(message);
473
474 /* apply EAP method selected by RADIUS server */
475 eap_type = in->get_type(in, &eap_vendor);
476
477 DBG3(DBG_CFG, "%N payload %B", eap_type_names, eap_type, &message);
478
479 if (eap_type == EAP_IDENTITY)
480 {
481 identification_t *peer;
482 chunk_t eap_identity;
483
484 if (message.len < 5)
485 {
486 goto end;
487 }
488 eap_identity = chunk_create(message.ptr + 5, message.len - 5);
489 peer = identification_create_from_data(eap_identity);
490 method = charon->eap->create_instance(charon->eap, this->type,
491 0, EAP_SERVER, this->server, peer);
492 if (!method)
493 {
494 peer->destroy(peer);
495 goto end;
496 }
497 this->connections->add(this->connections, nas_id, user_name, peer,
498 method);
499 if (method->initiate(method, &out) == NEED_MORE)
500 {
501 send_response(this, request, code, out, group, msk, source);
502 }
503 }
504 else
505 {
506 ike_sa_t *ike_sa;
507 auth_cfg_t *auth;
508 auth_rule_t type;
509 identification_t *data;
510 enumerator_t *e;
511
512 method = this->connections->get_state(this->connections, nas_id,
513 user_name, &ike_sa);
514 if (!method)
515 {
516 goto end;
517 }
518 charon->bus->set_sa(charon->bus, ike_sa);
519
520 switch (method->process(method, in, &out))
521 {
522 case NEED_MORE:
523 code = RMC_ACCESS_CHALLENGE;
524 break;
525 case SUCCESS:
526 code = RMC_ACCESS_ACCEPT;
527 method->get_msk(method, &msk);
528 auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
529 e = auth->create_enumerator(auth);
530 while (e->enumerate(e, &type, &data))
531 {
532 /* look for group memberships */
533 if (type == AUTH_RULE_GROUP)
534 {
535 group = data;
536 }
537 }
538 e->destroy(e);
539
540 DESTROY_IF(out);
541 out = eap_payload_create_code(EAP_SUCCESS,
542 in->get_identifier(in));
543 break;
544 case FAILED:
545 default:
546 code = RMC_ACCESS_REJECT;
547 DESTROY_IF(out);
548 out = eap_payload_create_code(EAP_FAILURE,
549 in->get_identifier(in));
550 }
551 charon->bus->set_sa(charon->bus, NULL);
552 send_response(this, request, code, out, group, msk, source);
553 this->connections->unlock(this->connections);
554 }
555
556 if (code == RMC_ACCESS_ACCEPT || code == RMC_ACCESS_REJECT)
557 {
558 this->connections->remove(this->connections, nas_id, user_name);
559 }
560
561 out->destroy(out);
562 end:
563 free(message.ptr);
564 in->destroy(in);
565 }
566 }
567
568 /**
569 * Callback function to get recommendation from TNCCS connection
570 */
571 static bool get_recommendation(TNC_IMV_Action_Recommendation rec,
572 TNC_IMV_Evaluation_Result eval)
573 {
574 DBG1(DBG_TNC, "final recommendation is '%N' and evaluation is '%N'",
575 TNC_IMV_Action_Recommendation_names, rec,
576 TNC_IMV_Evaluation_Result_names, eval);
577
578 return TRUE;
579 }
580
581 /**
582 * Get more data on a PT-TLS connection
583 */
584 static bool pt_tls_receive_more(pt_tls_server_t *this, int fd,
585 watcher_event_t event)
586 {
587 switch (this->handle(this))
588 {
589 case NEED_MORE:
590 DBG1(DBG_TNC, "PT-TLS connection needs more");
591 break;
592 case FAILED:
593 case SUCCESS:
594 default:
595 DBG1(DBG_TNC, "PT-TLS connection terminates");
596 lib->watcher->remove(lib->watcher, fd);
597 close(fd);
598 this->destroy(this);
599 break;
600 }
601
602 return TRUE;
603 }
604
605 /**
606 * Accept TCP connection received on the PT-TLS listening socket
607 */
608 static bool pt_tls_receive(private_tnc_pdp_t *this, int fd, watcher_event_t event)
609 {
610 int pt_tls_fd;
611 identification_t *peer;
612 pt_tls_server_t *pt_tls;
613 tnccs_t *tnccs;
614
615 pt_tls_fd = accept(fd, NULL, NULL);
616 if (pt_tls_fd == -1)
617 {
618 DBG1(DBG_TNC, "accepting PT-TLS stream failed: %s", strerror(errno));
619 return FALSE;
620 }
621
622 /* At this moment the peer identity is not known yet */
623 peer = identification_create_from_encoding(ID_ANY, chunk_empty),
624
625 tnccs = tnc->tnccs->create_instance(tnc->tnccs, TNCCS_2_0, TRUE,
626 this->server, peer, TNC_IFT_TLS_2_0,
627 (tnccs_cb_t)get_recommendation);
628 peer->destroy(peer);
629
630 if (!tnccs)
631 {
632 DBG1(DBG_TNC, "could not create TNCCS 2.0 connection instance");
633 close(pt_tls_fd);
634 return FALSE;
635 }
636
637 pt_tls = pt_tls_server_create(this->server, pt_tls_fd, PT_TLS_AUTH_NONE,
638 tnccs);
639 if (!pt_tls)
640 {
641 DBG1(DBG_TNC, "could not create PT-TLS connection instance");
642 close(pt_tls_fd);
643 return FALSE;
644 }
645
646 lib->watcher->add(lib->watcher, pt_tls_fd, WATCHER_READ,
647 (watcher_cb_t)pt_tls_receive_more, pt_tls);
648
649 return TRUE;
650 }
651
652 /**
653 * Process packets received on the RADIUS socket
654 */
655 static bool radius_receive(private_tnc_pdp_t *this, int fd, watcher_event_t event)
656 {
657 radius_message_t *request;
658 char buffer[MAX_PACKET];
659 int bytes_read = 0;
660 host_t *source;
661 union {
662 struct sockaddr_in in4;
663 struct sockaddr_in6 in6;
664 } src;
665 struct iovec iov = {
666 .iov_base = buffer,
667 .iov_len = MAX_PACKET,
668 };
669 struct msghdr msg = {
670 .msg_name = &src,
671 .msg_namelen = sizeof(src),
672 .msg_iov = &iov,
673 .msg_iovlen = 1,
674 };
675
676 /* read received packet */
677 bytes_read = recvmsg(fd, &msg, 0);
678 if (bytes_read < 0)
679 {
680 DBG1(DBG_CFG, "error reading RADIUS socket: %s", strerror(errno));
681 return FALSE;
682 }
683 if (msg.msg_flags & MSG_TRUNC)
684 {
685 DBG1(DBG_CFG, "receive buffer too small, RADIUS packet discarded");
686 return FALSE;
687 }
688 source = host_create_from_sockaddr((sockaddr_t*)&src);
689 DBG2(DBG_CFG, "received RADIUS packet from %#H", source);
690 DBG3(DBG_CFG, "%b", buffer, bytes_read);
691 request = radius_message_parse(chunk_create(buffer, bytes_read));
692 if (request)
693 {
694 DBG1(DBG_CFG, "received RADIUS %N from client '%H'",
695 radius_message_code_names, request->get_code(request), source);
696
697 if (request->verify(request, NULL, this->secret, this->hasher,
698 this->signer))
699 {
700 process_eap(this, request, source);
701 }
702 request->destroy(request);
703 }
704 else
705 {
706 DBG1(DBG_CFG, "received invalid RADIUS message, ignored");
707 }
708 source->destroy(source);
709 return TRUE;
710 }
711
712 METHOD(tnc_pdp_t, destroy, void,
713 private_tnc_pdp_t *this)
714 {
715 if (this->pt_tls_ipv4)
716 {
717 lib->watcher->remove(lib->watcher, this->pt_tls_ipv4);
718 close(this->pt_tls_ipv4);
719 }
720 if (this->pt_tls_ipv6)
721 {
722 lib->watcher->remove(lib->watcher, this->pt_tls_ipv6);
723 close(this->pt_tls_ipv6);
724 }
725 if (this->radius_ipv4)
726 {
727 lib->watcher->remove(lib->watcher, this->radius_ipv4);
728 close(this->radius_ipv4);
729 }
730 if (this->radius_ipv6)
731 {
732 lib->watcher->remove(lib->watcher, this->radius_ipv6);
733 close(this->radius_ipv6);
734 }
735 DESTROY_IF(this->server);
736 DESTROY_IF(this->signer);
737 DESTROY_IF(this->hasher);
738 DESTROY_IF(this->ng);
739 DESTROY_IF(this->connections);
740 free(this);
741 }
742
743 /*
744 * see header file
745 */
746 tnc_pdp_t *tnc_pdp_create(void)
747 {
748 private_tnc_pdp_t *this;
749 char *secret, *server, *eap_type_str;
750 int radius_port, pt_tls_port;
751
752 server = lib->settings->get_str(lib->settings,
753 "%s.plugins.tnc-pdp.server", NULL, charon->name);
754 pt_tls_port = lib->settings->get_int(lib->settings,
755 "%s.plugins.tnc-pdp.pt_tls.port", PT_TLS_PORT, charon->name);
756 radius_port = lib->settings->get_int(lib->settings,
757 "%s.plugins.tnc-pdp.radius.port", RADIUS_PORT, charon->name);
758 secret = lib->settings->get_str(lib->settings,
759 "%s.plugins.tnc-pdp.radius.secret", NULL, charon->name);
760 eap_type_str = lib->settings->get_str(lib->settings,
761 "%s.plugins.tnc-pdp.radius.method", "ttls", charon->name);
762
763 if (!server)
764 {
765 DBG1(DBG_CFG, "missing PDP server name, PDP disabled");
766 return NULL;
767 }
768 if (!secret)
769 {
770 DBG1(DBG_CFG, "missing RADIUS secret, PDP disabled");
771 return NULL;
772 }
773
774 INIT(this,
775 .public = {
776 .destroy = _destroy,
777 },
778 .server = identification_create_from_string(server),
779 .pt_tls_ipv4 = open_tcp_socket(AF_INET, pt_tls_port),
780 .pt_tls_ipv6 = open_tcp_socket(AF_INET6, pt_tls_port),
781 .radius_ipv4 = open_udp_socket(AF_INET, radius_port),
782 .radius_ipv6 = open_udp_socket(AF_INET6, radius_port),
783 .secret = chunk_from_str(secret),
784 .type = eap_type_from_string(eap_type_str),
785 .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
786 .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128),
787 .ng = lib->crypto->create_nonce_gen(lib->crypto),
788 .connections = tnc_pdp_connections_create(),
789 );
790
791 if (!this->pt_tls_ipv4 && !this->pt_tls_ipv6)
792 {
793 DBG1(DBG_NET, "could not create any PT-TLS sockets");
794 destroy(this);
795 return NULL;
796 }
797 if (this->pt_tls_ipv4)
798 {
799 lib->watcher->add(lib->watcher, this->pt_tls_ipv4, WATCHER_READ,
800 (watcher_cb_t)pt_tls_receive, this);
801 }
802 else
803 {
804 DBG1(DBG_NET, "could not open IPv4 PT-TLS socket, IPv4 disabled");
805 }
806 if (this->pt_tls_ipv6)
807 {
808 lib->watcher->add(lib->watcher, this->pt_tls_ipv6, WATCHER_READ,
809 (watcher_cb_t)pt_tls_receive, this);
810 }
811 else
812 {
813 DBG1(DBG_NET, "could not open IPv6 PT-TLS socket, IPv6 disabled");
814 }
815
816 if (!this->hasher || !this->signer || !this->ng)
817 {
818 DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/NG required");
819 destroy(this);
820 return NULL;
821 }
822
823 if (!this->radius_ipv4 && !this->radius_ipv6)
824 {
825 DBG1(DBG_NET, "could not create any RADIUS sockets");
826 destroy(this);
827 return NULL;
828 }
829 if (this->radius_ipv4)
830 {
831 lib->watcher->add(lib->watcher, this->radius_ipv4, WATCHER_READ,
832 (watcher_cb_t)radius_receive, this);
833 }
834 else
835 {
836 DBG1(DBG_NET, "could not open IPv4 RADIUS socket, IPv4 disabled");
837 }
838 if (this->radius_ipv6)
839
840 {
841 lib->watcher->add(lib->watcher, this->radius_ipv6, WATCHER_READ,
842 (watcher_cb_t)radius_receive, this);
843 }
844 else
845 {
846 DBG1(DBG_NET, "could not open IPv6 RADIUS socket, IPv6 disabled");
847 }
848
849 if (!this->signer->set_key(this->signer, this->secret))
850 {
851 DBG1(DBG_CFG, "could not set signer key");
852 destroy(this);
853 return NULL;
854 }
855
856 if (this->type == 0)
857 {
858 DBG1(DBG_CFG, "unrecognized eap method \"%s\"", eap_type_str);
859 destroy(this);
860 return NULL;
861 }
862 DBG1(DBG_IKE, "eap method %N selected", eap_type_names, this->type);
863
864 return &this->public;
865 }