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