| /* |
| * Copyright (C) 2011-2013 Andreas Steffen |
| * HSR Hochschule fuer Technik Rapperswil |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * for more details. |
| */ |
| |
| #include "tnc_ifmap_soap.h" |
| #include "tnc_ifmap_soap_msg.h" |
| |
| #include <utils/debug.h> |
| #include <credentials/sets/mem_cred.h> |
| #include <daemon.h> |
| |
| #include <tls_socket.h> |
| |
| #include <errno.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2" |
| #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2" |
| #define IFMAP_URI "https://localhost:8444/imap" |
| #define IFMAP_NO_FD -1 |
| |
| typedef struct private_tnc_ifmap_soap_t private_tnc_ifmap_soap_t; |
| |
| /** |
| * Private data of an tnc_ifmap_soap_t object. |
| */ |
| struct private_tnc_ifmap_soap_t { |
| |
| /** |
| * Public tnc_ifmap_soap_t interface. |
| */ |
| tnc_ifmap_soap_t public; |
| |
| /** |
| * SOAP Session ID |
| */ |
| xmlChar *session_id; |
| |
| /** |
| * IF-MAP Publisher ID |
| */ |
| xmlChar *ifmap_publisher_id; |
| |
| /** |
| * IF-MAP namespace |
| */ |
| xmlNsPtr ns; |
| |
| /** |
| * IF-MAP metadata namespace |
| */ |
| xmlNsPtr ns_meta; |
| |
| /** |
| * PEP and PDP device name |
| */ |
| char *device_name; |
| |
| /** |
| * HTTPS Server URI with https:// prefix removed |
| */ |
| char *uri; |
| |
| /** |
| * Optional base64-encoded username:password for HTTP Basic Authentication |
| */ |
| chunk_t user_pass; |
| |
| /** |
| * IF-MAP Server (IP address and port) |
| */ |
| host_t *host; |
| |
| /** |
| * TLS socket |
| */ |
| tls_socket_t *tls; |
| |
| /** |
| * File descriptor for secure TCP socket |
| */ |
| int fd; |
| |
| /** |
| * In memory credential set |
| */ |
| mem_cred_t *creds; |
| |
| /** |
| * reference count |
| */ |
| refcount_t ref; |
| |
| }; |
| |
| METHOD(tnc_ifmap_soap_t, newSession, bool, |
| private_tnc_ifmap_soap_t *this) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request, result; |
| |
| /*build newSession request */ |
| request = xmlNewNode(NULL, "newSession"); |
| this->ns = xmlNewNs(request, IFMAP_NS, "ifmap"); |
| xmlSetNs(request, this->ns); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| if (!soap_msg->post(soap_msg, request, "newSessionResult", &result)) |
| { |
| soap_msg->destroy(soap_msg); |
| return FALSE; |
| } |
| |
| /* get session-id and ifmap-publisher-id properties */ |
| this->session_id = xmlGetProp(result, "session-id"); |
| this->ifmap_publisher_id = xmlGetProp(result, "ifmap-publisher-id"); |
| soap_msg->destroy(soap_msg); |
| |
| DBG1(DBG_TNC, "created ifmap session '%s' as publisher '%s'", |
| this->session_id, this->ifmap_publisher_id); |
| |
| /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */ |
| this->device_name = lib->settings->get_str(lib->settings, |
| "%s.plugins.tnc-ifmap.device_name", |
| this->ifmap_publisher_id, lib->ns); |
| this->device_name = strdup(this->device_name); |
| |
| return this->session_id && this->ifmap_publisher_id; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, renewSession, bool, |
| private_tnc_ifmap_soap_t *this) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request; |
| bool success; |
| |
| /* build renewSession request */ |
| request = xmlNewNode(NULL, "renewSession"); |
| this->ns = xmlNewNs(request, IFMAP_NS, "ifmap"); |
| xmlSetNs(request, this->ns); |
| xmlNewProp(request, "session-id", this->session_id); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "renewSessionResult", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| return success; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, purgePublisher, bool, |
| private_tnc_ifmap_soap_t *this) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request; |
| bool success; |
| |
| /* build purgePublisher request */ |
| request = xmlNewNode(NULL, "purgePublisher"); |
| this->ns = xmlNewNs(request, IFMAP_NS, "ifmap"); |
| xmlSetNs(request, this->ns); |
| xmlNewProp(request, "session-id", this->session_id); |
| xmlNewProp(request, "ifmap-publisher-id", this->ifmap_publisher_id); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "purgePublisherReceived", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| return success; |
| } |
| |
| /** |
| * Create an access-request based on device_name and ike_sa_id |
| */ |
| static xmlNodePtr create_access_request(private_tnc_ifmap_soap_t *this, |
| uint32_t id) |
| { |
| xmlNodePtr node; |
| char buf[BUF_LEN]; |
| |
| node = xmlNewNode(NULL, "access-request"); |
| |
| snprintf(buf, BUF_LEN, "%s:%d", this->device_name, id); |
| xmlNewProp(node, "name", buf); |
| |
| return node; |
| } |
| |
| /** |
| * Create an identity |
| */ |
| static xmlNodePtr create_identity(private_tnc_ifmap_soap_t *this, |
| identification_t *id, bool is_user) |
| { |
| xmlNodePtr node; |
| char buf[BUF_LEN], *id_type; |
| |
| node = xmlNewNode(NULL, "identity"); |
| |
| snprintf(buf, BUF_LEN, "%Y", id); |
| xmlNewProp(node, "name", buf); |
| |
| switch (id->get_type(id)) |
| { |
| case ID_IPV4_ADDR: |
| id_type = "other"; |
| xmlNewProp(node, "other-type-definition", "36906:ipv4-address"); |
| break; |
| case ID_FQDN: |
| id_type = is_user ? "username" : "dns-name"; |
| break; |
| case ID_RFC822_ADDR: |
| id_type = "email-address"; |
| break; |
| case ID_IPV6_ADDR: |
| id_type = "other"; |
| xmlNewProp(node, "other-type-definition", "36906:ipv6-address"); |
| break; |
| case ID_DER_ASN1_DN: |
| id_type = "distinguished-name"; |
| break; |
| case ID_KEY_ID: |
| id_type = "other"; |
| xmlNewProp(node, "other-type-definition", "36906:key-id"); |
| break; |
| default: |
| id_type = "other"; |
| xmlNewProp(node, "other-type-definition", "36906:other"); |
| } |
| xmlNewProp(node, "type", id_type); |
| |
| return node; |
| } |
| |
| /** |
| * Create enforcement-report metadata |
| */ |
| static xmlNodePtr create_enforcement_report(private_tnc_ifmap_soap_t *this, |
| xmlChar *action, xmlChar *reason) |
| { |
| xmlNodePtr node, node2, node3; |
| |
| node = xmlNewNode(NULL, "metadata"); |
| node2 = xmlNewNode(this->ns_meta, "enforcement-report"); |
| xmlAddChild(node, node2); |
| xmlNewProp(node2, "ifmap-cardinality", "multiValue"); |
| |
| node3 = xmlNewNode(NULL, "enforcement-action"); |
| xmlAddChild(node2, node3); |
| xmlNodeAddContent(node3, action); |
| |
| node3 = xmlNewNode(NULL, "enforcement-reason"); |
| xmlAddChild(node2, node3); |
| xmlNodeAddContent(node3, reason); |
| |
| return node; |
| } |
| |
| /** |
| * Create delete filter |
| */ |
| static xmlNodePtr create_delete_filter(private_tnc_ifmap_soap_t *this, |
| char *metadata) |
| { |
| xmlNodePtr node; |
| char buf[BUF_LEN]; |
| |
| node = xmlNewNode(NULL, "delete"); |
| |
| snprintf(buf, BUF_LEN, "meta:%s[@ifmap-publisher-id='%s']", |
| metadata, this->ifmap_publisher_id); |
| xmlNewProp(node, "filter", buf); |
| |
| return node; |
| } |
| |
| /** |
| * Create a publish request |
| */ |
| static xmlNodePtr create_publish_request(private_tnc_ifmap_soap_t *this) |
| { |
| xmlNodePtr request; |
| |
| request = xmlNewNode(NULL, "publish"); |
| this->ns = xmlNewNs(request, IFMAP_NS, "ifmap"); |
| xmlSetNs(request, this->ns); |
| this->ns_meta = xmlNewNs(request, IFMAP_META_NS, "meta"); |
| xmlNewProp(request, "session-id", this->session_id); |
| |
| return request; |
| } |
| |
| /** |
| * Create a device |
| */ |
| static xmlNodePtr create_device(private_tnc_ifmap_soap_t *this) |
| { |
| xmlNodePtr node, node2; |
| |
| node = xmlNewNode(NULL, "device"); |
| node2 = xmlNewNode(NULL, "name"); |
| xmlAddChild(node, node2); |
| xmlNodeAddContent(node2, this->device_name); |
| |
| return node; |
| } |
| |
| /** |
| * Create an ip-address |
| */ |
| static xmlNodePtr create_ip_address(private_tnc_ifmap_soap_t *this, |
| host_t *host) |
| { |
| xmlNodePtr node; |
| char buf[BUF_LEN]; |
| |
| node = xmlNewNode(NULL, "ip-address"); |
| |
| if (host->get_family(host) == AF_INET6) |
| { |
| chunk_t address; |
| int len, written, i; |
| char *pos; |
| bool first = TRUE; |
| |
| /* output IPv6 address in canonical IF-MAP 2.0 format */ |
| address = host->get_address(host); |
| pos = buf; |
| len = sizeof(buf); |
| |
| for (i = 0; i < address.len; i = i + 2) |
| { |
| written = snprintf(pos, len, "%s%x", first ? "" : ":", |
| 256*address.ptr[i] + address.ptr[i+1]); |
| if (written < 0 || written >= len) |
| { |
| break; |
| } |
| pos += written; |
| len -= written; |
| first = FALSE; |
| } |
| } |
| else |
| { |
| snprintf(buf, BUF_LEN, "%H", host); |
| } |
| |
| xmlNewProp(node, "value", buf); |
| xmlNewProp(node, "type", host->get_family(host) == AF_INET ? "IPv4" : "IPv6"); |
| |
| return node; |
| } |
| |
| /** |
| * Create metadata |
| */ |
| static xmlNodePtr create_metadata(private_tnc_ifmap_soap_t *this, |
| xmlChar *metadata) |
| { |
| xmlNodePtr node, node2; |
| |
| node = xmlNewNode(NULL, "metadata"); |
| node2 = xmlNewNode(this->ns_meta, metadata); |
| xmlAddChild(node, node2); |
| xmlNewProp(node2, "ifmap-cardinality", "singleValue"); |
| |
| return node; |
| } |
| |
| /** |
| * Create capability metadata |
| */ |
| static xmlNodePtr create_capability(private_tnc_ifmap_soap_t *this, |
| identification_t *name) |
| { |
| xmlNodePtr node, node2; |
| char buf[BUF_LEN]; |
| |
| node = xmlNewNode(this->ns_meta, "capability"); |
| xmlNewProp(node, "ifmap-cardinality", "multiValue"); |
| |
| node2 = xmlNewNode(NULL, "name"); |
| xmlAddChild(node, node2); |
| snprintf(buf, BUF_LEN, "%Y", name); |
| xmlNodeAddContent(node2, buf); |
| |
| node2 = xmlNewNode(NULL, "administrative-domain"); |
| xmlAddChild(node, node2); |
| xmlNodeAddContent(node2, "strongswan"); |
| |
| return node; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, publish_ike_sa, bool, |
| private_tnc_ifmap_soap_t *this, ike_sa_t *ike_sa, bool up) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request, node, node2 = NULL; |
| enumerator_t *e1, *e2; |
| auth_rule_t type; |
| identification_t *id, *eap_id, *group; |
| host_t *host; |
| auth_cfg_t *auth; |
| uint32_t ike_sa_id; |
| bool is_user = FALSE, first = TRUE, success; |
| |
| /* extract relevant data from IKE_SA*/ |
| ike_sa_id = ike_sa->get_unique_id(ike_sa); |
| host = ike_sa->get_other_host(ike_sa); |
| id = ike_sa->get_other_id(ike_sa); |
| eap_id = ike_sa->get_other_eap_id(ike_sa); |
| |
| /* in the presence of an EAP Identity, treat it as a username */ |
| if (!id->equals(id, eap_id)) |
| { |
| is_user = TRUE; |
| id = eap_id; |
| } |
| |
| /* build publish request */ |
| request = create_publish_request(this); |
| |
| /* delete any existing enforcement reports */ |
| if (up) |
| { |
| node = create_delete_filter(this, "enforcement-report"); |
| xmlAddChild(request, node); |
| xmlAddChild(node, create_ip_address(this, host)); |
| xmlAddChild(node, create_device(this)); |
| } |
| |
| /** |
| * update or delete authenticated-as metadata |
| */ |
| if (up) |
| { |
| node = xmlNewNode(NULL, "update"); |
| } |
| else |
| { |
| node = create_delete_filter(this, "authenticated-as"); |
| } |
| xmlAddChild(request, node); |
| |
| /* add access-request, identity and [if up] metadata */ |
| xmlAddChild(node, create_access_request(this, ike_sa_id)); |
| xmlAddChild(node, create_identity(this, id, is_user)); |
| if (up) |
| { |
| xmlAddChild(node, create_metadata(this, "authenticated-as")); |
| } |
| |
| /** |
| * update or delete access-request-ip metadata for physical IP address |
| */ |
| if (up) |
| { |
| node = xmlNewNode(NULL, "update"); |
| } |
| else |
| { |
| node = create_delete_filter(this, "access-request-ip"); |
| } |
| xmlAddChild(request, node); |
| |
| /* add access-request, ip-address and [if up] metadata */ |
| xmlAddChild(node, create_access_request(this, ike_sa_id)); |
| xmlAddChild(node, create_ip_address(this, host)); |
| if (up) |
| { |
| xmlAddChild(node, create_metadata(this, "access-request-ip")); |
| } |
| |
| /** |
| * update or delete authenticated-by metadata |
| */ |
| if (up) |
| { |
| node = xmlNewNode(NULL, "update"); |
| } |
| else |
| { |
| node = create_delete_filter(this, "authenticated-by"); |
| } |
| xmlAddChild(request, node); |
| |
| /* add access-request, device and [if up] metadata */ |
| xmlAddChild(node, create_access_request(this, ike_sa_id)); |
| xmlAddChild(node, create_device(this)); |
| if (up) |
| { |
| xmlAddChild(node, create_metadata(this, "authenticated-by")); |
| } |
| |
| /** |
| * update or delete capability metadata |
| */ |
| e1 = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE); |
| while (e1->enumerate(e1, &auth) && (first || up)) |
| { |
| e2 = auth->create_enumerator(auth); |
| while (e2->enumerate(e2, &type, &group)) |
| { |
| /* look for group memberships */ |
| if (type == AUTH_RULE_GROUP) |
| { |
| if (first) |
| { |
| first = FALSE; |
| |
| if (up) |
| { |
| node = xmlNewNode(NULL, "update"); |
| } |
| else |
| { |
| node = create_delete_filter(this, "capability"); |
| } |
| xmlAddChild(request, node); |
| |
| /* add access-request */ |
| xmlAddChild(node, create_access_request(this, ike_sa_id)); |
| if (!up) |
| { |
| break; |
| } |
| node2 = xmlNewNode(NULL, "metadata"); |
| xmlAddChild(node, node2); |
| } |
| xmlAddChild(node2, create_capability(this, group)); |
| } |
| } |
| e2->destroy(e2); |
| } |
| e1->destroy(e1); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "publishReceived", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| return success; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, publish_device_ip, bool, |
| private_tnc_ifmap_soap_t *this, host_t *host) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request, update; |
| bool success; |
| |
| /* build publish update request */ |
| request = create_publish_request(this); |
| update = xmlNewNode(NULL, "update"); |
| xmlAddChild(request, update); |
| |
| /* add device, ip-address and metadata */ |
| xmlAddChild(update, create_device(this)); |
| xmlAddChild(update, create_ip_address(this, host)); |
| xmlAddChild(update, create_metadata(this, "device-ip")); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "publishReceived", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| return success; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, publish_virtual_ips, bool, |
| private_tnc_ifmap_soap_t *this, ike_sa_t *ike_sa, bool assign) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request, node; |
| uint32_t ike_sa_id; |
| enumerator_t *enumerator; |
| host_t *vip; |
| bool success; |
| |
| /* extract relevant data from IKE_SA*/ |
| ike_sa_id = ike_sa->get_unique_id(ike_sa); |
| |
| /* build publish request */ |
| request = create_publish_request(this); |
| |
| enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); |
| while (enumerator->enumerate(enumerator, &vip)) |
| { |
| /** |
| * update or delete access-request-ip metadata for a virtual IP address |
| */ |
| if (assign) |
| { |
| node = xmlNewNode(NULL, "update"); |
| } |
| else |
| { |
| node = create_delete_filter(this, "access-request-ip"); |
| } |
| xmlAddChild(request, node); |
| |
| /* add access-request, virtual ip-address and [if assign] metadata */ |
| xmlAddChild(node, create_access_request(this, ike_sa_id)); |
| xmlAddChild(node, create_ip_address(this, vip)); |
| if (assign) |
| { |
| xmlAddChild(node, create_metadata(this, "access-request-ip")); |
| } |
| } |
| enumerator->destroy(enumerator); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "publishReceived", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| return success; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, publish_enforcement_report, bool, |
| private_tnc_ifmap_soap_t *this, host_t *host, char *action, char *reason) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request, update; |
| bool success; |
| |
| /* build publish update request */ |
| request = create_publish_request(this); |
| update = xmlNewNode(NULL, "update"); |
| xmlAddChild(request, update); |
| |
| /* add ip-address and metadata */ |
| xmlAddChild(update, create_ip_address(this, host)); |
| xmlAddChild(update, create_device(this)); |
| xmlAddChild(update, create_enforcement_report(this, action, reason)); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "publishReceived", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| return success; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, endSession, bool, |
| private_tnc_ifmap_soap_t *this) |
| { |
| tnc_ifmap_soap_msg_t *soap_msg; |
| xmlNodePtr request; |
| bool success; |
| |
| /* build endSession request */ |
| request = xmlNewNode(NULL, "endSession"); |
| this->ns = xmlNewNs(request, IFMAP_NS, "ifmap"); |
| xmlSetNs(request, this->ns); |
| xmlNewProp(request, "session-id", this->session_id); |
| |
| soap_msg = tnc_ifmap_soap_msg_create(this->uri, this->user_pass, this->tls); |
| success = soap_msg->post(soap_msg, request, "endSessionResult", NULL); |
| soap_msg->destroy(soap_msg); |
| |
| DBG1(DBG_TNC, "ended ifmap session '%s' as publisher '%s'", |
| this->session_id, this->ifmap_publisher_id); |
| |
| return success; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, get_session_id, char*, |
| private_tnc_ifmap_soap_t *this) |
| { |
| return this->session_id; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, orphaned, bool, |
| private_tnc_ifmap_soap_t *this) |
| { |
| return this->ref == 1; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, get_ref, tnc_ifmap_soap_t*, |
| private_tnc_ifmap_soap_t *this) |
| { |
| ref_get(&this->ref); |
| return &this->public; |
| } |
| |
| METHOD(tnc_ifmap_soap_t, destroy, void, |
| private_tnc_ifmap_soap_t *this) |
| { |
| if (ref_put(&this->ref)) |
| { |
| if (this->session_id) |
| { |
| xmlFree(this->session_id); |
| xmlFree(this->ifmap_publisher_id); |
| free(this->device_name); |
| } |
| DESTROY_IF(this->tls); |
| DESTROY_IF(this->host); |
| |
| if (this->fd != IFMAP_NO_FD) |
| { |
| close(this->fd); |
| } |
| lib->credmgr->remove_set(lib->credmgr, &this->creds->set); |
| this->creds->destroy(this->creds); |
| free(this->user_pass.ptr); |
| free(this); |
| } |
| } |
| |
| static bool soap_init(private_tnc_ifmap_soap_t *this) |
| { |
| char *server_uri, *server_str, *port_str, *uri_str; |
| char *server_cert, *client_cert, *client_key, *user_pass; |
| int port; |
| auth_cfg_t *auth; |
| certificate_t *cert; |
| private_key_t *key; |
| identification_t *server_id, *client_id = NULL; |
| |
| /* getting configuration parameters from strongswan.conf */ |
| server_uri = lib->settings->get_str(lib->settings, |
| "%s.plugins.tnc-ifmap.server_uri", IFMAP_URI, lib->ns); |
| server_cert = lib->settings->get_str(lib->settings, |
| "%s.plugins.tnc-ifmap.server_cert", NULL, lib->ns); |
| client_cert = lib->settings->get_str(lib->settings, |
| "%s.plugins.tnc-ifmap.client_cert", NULL, lib->ns); |
| client_key = lib->settings->get_str(lib->settings, |
| "%s.plugins.tnc-ifmap.client_key", NULL, lib->ns); |
| user_pass = lib->settings->get_str(lib->settings, |
| "%s.plugins.tnc-ifmap.username_password", NULL, lib->ns); |
| |
| /* load [self-signed] MAP server certificate */ |
| if (!server_cert) |
| { |
| DBG1(DBG_TNC, "MAP server certificate not defined"); |
| return FALSE; |
| } |
| cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, |
| BUILD_FROM_FILE, server_cert, BUILD_END); |
| if (!cert) |
| { |
| DBG1(DBG_TNC, "loading MAP server certificate from '%s' failed", |
| server_cert); |
| return FALSE; |
| } |
| DBG1(DBG_TNC, "loaded MAP server certificate from '%s'", server_cert); |
| server_id = cert->get_subject(cert); |
| this->creds->add_cert(this->creds, TRUE, cert); |
| |
| /* check availability of client credentials */ |
| if (!client_cert && !user_pass) |
| { |
| DBG1(DBG_TNC, "neither MAP client certificate " |
| "nor username:password defined"); |
| return FALSE; |
| } |
| |
| if (client_cert) |
| { |
| /* load MAP client certificate */ |
| cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, |
| BUILD_FROM_FILE, client_cert, BUILD_END); |
| if (!cert) |
| { |
| DBG1(DBG_TNC, "loading MAP client certificate from '%s' failed", |
| client_cert); |
| return FALSE; |
| } |
| DBG1(DBG_TNC, "loaded MAP client certificate from '%s'", client_cert); |
| cert = this->creds->add_cert_ref(this->creds, TRUE, cert); |
| |
| /* load MAP client private key */ |
| if (client_key) |
| { |
| key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, |
| BUILD_FROM_FILE, client_key, BUILD_END); |
| if (!key) |
| { |
| DBG1(DBG_TNC, "loading MAP client private key from '%s' failed", |
| client_key); |
| return FALSE; |
| } |
| DBG1(DBG_TNC, "loaded MAP client RSA private key from '%s'", |
| client_key); |
| this->creds->add_key(this->creds, key); |
| } |
| |
| /* set client ID to certificate distinguished name */ |
| client_id = cert->get_subject(cert); |
| |
| /* check if we have a private key matching the certificate */ |
| auth = auth_cfg_create(); |
| auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert); |
| key = lib->credmgr->get_private(lib->credmgr, KEY_RSA, client_id, auth); |
| auth->destroy(auth); |
| if (!key) |
| { |
| DBG1(DBG_TNC, "no RSA private key matching MAP client certificate"); |
| return FALSE; |
| } |
| } |
| else |
| { |
| /* set base64-encoded username:password for HTTP Basic Authentication */ |
| this->user_pass = chunk_to_base64(chunk_from_str(user_pass), NULL); |
| } |
| |
| /* remove HTTPS prefix if any */ |
| if (strlen(server_uri) >= 8 && strncaseeq(server_uri, "https://", 8)) |
| { |
| server_uri += 8; |
| } |
| this->uri = server_uri; |
| |
| /* duplicate server string since we are going to manipulate it */ |
| server_str = strdup(server_uri); |
| |
| /* extract server name and port from server URI */ |
| port_str = strchr(server_str, ':'); |
| if (port_str) |
| { |
| *port_str++ = '\0'; |
| if (sscanf(port_str, "%d", &port) != 1) |
| { |
| DBG1(DBG_TNC, "parsing server port %s failed", port_str); |
| free(server_str); |
| return FALSE; |
| } |
| } |
| else |
| { |
| /* use default https port */ |
| port = 443; |
| uri_str = strchr(server_str, '/'); |
| if (uri_str) |
| { |
| *uri_str = '\0'; |
| } |
| } |
| |
| /* open TCP socket and connect to MAP server */ |
| this->host = host_create_from_dns(server_str, 0, port); |
| if (!this->host) |
| { |
| DBG1(DBG_TNC, "resolving hostname %s failed", server_str); |
| free(server_str); |
| return FALSE; |
| } |
| free(server_str); |
| |
| this->fd = socket(this->host->get_family(this->host), SOCK_STREAM, 0); |
| if (this->fd == IFMAP_NO_FD) |
| { |
| DBG1(DBG_TNC, "opening socket failed: %s", strerror(errno)); |
| return FALSE; |
| } |
| |
| if (connect(this->fd, this->host->get_sockaddr(this->host), |
| *this->host->get_sockaddr_len(this->host)) == -1) |
| { |
| DBG1(DBG_TNC, "connecting to %#H failed: %s", |
| this->host, strerror(errno)); |
| return FALSE; |
| } |
| |
| /* open TLS socket */ |
| this->tls = tls_socket_create(FALSE, server_id, client_id, this->fd, |
| NULL, TLS_UNSPEC, TLS_UNSPEC, 0); |
| if (!this->tls) |
| { |
| DBG1(DBG_TNC, "creating TLS socket failed"); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * See header |
| */ |
| tnc_ifmap_soap_t *tnc_ifmap_soap_create() |
| { |
| private_tnc_ifmap_soap_t *this; |
| |
| INIT(this, |
| .public = { |
| .newSession = _newSession, |
| .renewSession = _renewSession, |
| .purgePublisher = _purgePublisher, |
| .publish_ike_sa = _publish_ike_sa, |
| .publish_device_ip = _publish_device_ip, |
| .publish_virtual_ips = _publish_virtual_ips, |
| .publish_enforcement_report = _publish_enforcement_report, |
| .endSession = _endSession, |
| .get_session_id = _get_session_id, |
| .orphaned = _orphaned, |
| .get_ref = _get_ref, |
| .destroy = _destroy, |
| }, |
| .fd = IFMAP_NO_FD, |
| .creds = mem_cred_create(), |
| .ref = 1, |
| ); |
| |
| lib->credmgr->add_set(lib->credmgr, &this->creds->set); |
| |
| if (!soap_init(this)) |
| { |
| destroy(this); |
| return NULL; |
| } |
| |
| return &this->public; |
| } |