2 * Copyright (C) 2011 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "tnc_ifmap_soap.h"
20 #include <axis2_util.h>
21 #include <axis2_client.h>
22 #include <axis2_http_transport.h>
23 #include <axis2_http_transport_sender.h>
24 #include <axiom_soap.h>
26 #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2"
27 #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2"
28 #define IFMAP_LOGFILE "strongswan_ifmap.log"
29 #define IFMAP_SERVER "https://localhost:8443/"
31 typedef struct private_tnc_ifmap_soap_t private_tnc_ifmap_soap_t
;
34 * Private data of an tnc_ifmap_soap_t object.
36 struct private_tnc_ifmap_soap_t
{
39 * Public tnc_ifmap_soap_t interface.
41 tnc_ifmap_soap_t
public;
49 * Axis2 service client
51 axis2_svc_client_t
* svc_client
;
61 char *ifmap_publisher_id
;
64 * PEP and PDP device name
71 * Send request and receive result via SOAP
73 static bool send_receive(private_tnc_ifmap_soap_t
*this,
74 char *request_qname
, axiom_node_t
*request
,
75 char *receipt_qname
, axiom_node_t
**result
)
78 axiom_node_t
*parent
, *node
;
80 axutil_qname_t
*qname
;
83 /* send request and receive result */
84 DBG2(DBG_TNC
, "sending ifmap %s", request_qname
);
86 parent
= axis2_svc_client_send_receive(this->svc_client
, this->env
, request
);
89 DBG1(DBG_TNC
, "no ifmap %s received from MAP server", receipt_qname
);
93 /* pre-process result */
94 node
= axiom_node_get_first_child(parent
, this->env
);
95 if (node
&& axiom_node_get_node_type(node
, this->env
) == AXIOM_ELEMENT
)
97 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
99 qname
= axiom_element_get_qname(el
, this->env
, node
);
100 success
= streq(receipt_qname
, axutil_qname_to_string(qname
, this->env
));
103 DBG2(DBG_TNC
, "received ifmap %s", receipt_qname
);
110 /* no further processing requested */
111 axiom_node_free_tree(parent
, this->env
);
115 /* TODO proper error handling */
116 DBG1(DBG_TNC
, "%s", axiom_element_to_string(el
, this->env
, node
));
119 /* free parent in the error case */
120 axiom_node_free_tree(parent
, this->env
);
125 METHOD(tnc_ifmap_soap_t
, newSession
, bool,
126 private_tnc_ifmap_soap_t
*this)
128 axiom_node_t
*request
, *result
, *node
;
130 axiom_namespace_t
*ns
;
134 /* build newSession request */
135 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
136 el
= axiom_element_create(this->env
, NULL
, "newSession", ns
, &request
);
138 /* send newSession request and receive newSessionResult */
139 if (!send_receive(this, "newSession", request
, "newSessionResult", &result
))
144 /* process newSessionResult */
145 node
= axiom_node_get_first_child(result
, this->env
);
146 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
149 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
151 this->session_id
= strdup(value
);
153 /* get ifmap-publisher-id */
154 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
155 "ifmap-publisher-id");
156 this->ifmap_publisher_id
= strdup(value
);
158 DBG1(DBG_TNC
, "session-id: %s, ifmap-publisher-id: %s",
159 this->session_id
, this->ifmap_publisher_id
);
161 /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */
162 this->device_name
= lib
->settings
->get_str(lib
->settings
,
163 "charon.plugins.tnc-ifmap.device_name",
164 this->ifmap_publisher_id
);
165 this->device_name
= strdup(this->device_name
);
168 axiom_node_free_tree(result
, this->env
);
170 return this->session_id
&& this->ifmap_publisher_id
;
173 METHOD(tnc_ifmap_soap_t
, purgePublisher
, bool,
174 private_tnc_ifmap_soap_t
*this)
176 axiom_node_t
*request
;
178 axiom_namespace_t
*ns
;
179 axiom_attribute_t
*attr
;
181 /* build purgePublisher request */
182 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
183 el
= axiom_element_create(this->env
, NULL
, "purgePublisher", ns
, &request
);
184 attr
= axiom_attribute_create(this->env
, "session-id",
185 this->session_id
, NULL
);
186 axiom_element_add_attribute(el
, this->env
, attr
, request
);
187 attr
= axiom_attribute_create(this->env
, "ifmap-publisher-id",
188 this->ifmap_publisher_id
, NULL
);
189 axiom_element_add_attribute(el
, this->env
, attr
, request
);
191 /* send purgePublisher request and receive purgePublisherReceived */
192 return send_receive(this, "purgePublisher", request
,
193 "purgePublisherReceived", NULL
);
197 * Create an access-request based on device_name and ike_sa_id
199 static axiom_node_t
* create_access_request(private_tnc_ifmap_soap_t
*this,
204 axiom_attribute_t
*attr
;
207 el
= axiom_element_create(this->env
, NULL
, "access-request", NULL
, &node
);
209 snprintf(buf
, BUF_LEN
, "%s:%d", this->device_name
, id
);
210 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
211 axiom_element_add_attribute(el
, this->env
, attr
, node
);
219 static axiom_node_t
* create_identity(private_tnc_ifmap_soap_t
*this,
220 identification_t
*id
, bool is_user
)
224 axiom_attribute_t
*attr
;
225 char buf
[BUF_LEN
], *id_type
;
227 el
= axiom_element_create(this->env
, NULL
, "identity", NULL
, &node
);
229 snprintf(buf
, BUF_LEN
, "%Y", id
);
230 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
231 axiom_element_add_attribute(el
, this->env
, attr
, node
);
233 switch (id
->get_type(id
))
236 id_type
= is_user ?
"username" : "dns-name";
239 id_type
= "email-address";
242 id_type
= "distinguished-name";
247 attr
= axiom_attribute_create(this->env
, "type", id_type
, NULL
);
248 axiom_element_add_attribute(el
, this->env
, attr
, node
);
254 * Create an ip-address
256 static axiom_node_t
* create_ip_address(private_tnc_ifmap_soap_t
*this,
261 axiom_attribute_t
*attr
;
264 el
= axiom_element_create(this->env
, NULL
, "ip-address", NULL
, &node
);
266 if (host
->get_family(host
) == AF_INET6
)
273 /* output IPv6 address in canonical IF-MAP 2.0 format */
274 address
= host
->get_address(host
);
278 for (i
= 0; i
< address
.len
; i
= i
+ 2)
280 written
= snprintf(pos
, len
, "%s%x", first ?
"" : ":",
281 256*address
.ptr
[i
] + address
.ptr
[i
+1]);
282 if (written
< 0 || written
> len
)
293 snprintf(buf
, BUF_LEN
, "%H", host
);
295 attr
= axiom_attribute_create(this->env
, "value", buf
, NULL
);
296 axiom_element_add_attribute(el
, this->env
, attr
, node
);
298 attr
= axiom_attribute_create(this->env
, "type",
299 host
->get_family(host
) == AF_INET ?
"IPv4" : "IPv6", NULL
);
300 axiom_element_add_attribute(el
, this->env
, attr
, node
);
308 static axiom_node_t
* create_device(private_tnc_ifmap_soap_t
*this)
311 axiom_node_t
*node
, *node2
, *node3
;
314 el
= axiom_element_create(this->env
, NULL
, "device", NULL
, &node
);
315 el
= axiom_element_create(this->env
, NULL
, "name", NULL
, &node2
);
316 axiom_node_add_child(node
, this->env
, node2
);
317 text
= axiom_text_create(this->env
, node2
, this->device_name
, &node3
);
325 static axiom_node_t
* create_metadata(private_tnc_ifmap_soap_t
*this,
329 axiom_node_t
*node
, *node2
;
330 axiom_attribute_t
*attr
;
331 axiom_namespace_t
*ns_meta
;
333 el
= axiom_element_create(this->env
, NULL
, "metadata", NULL
, &node
);
334 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
336 el
= axiom_element_create(this->env
, NULL
, metadata
, ns_meta
, &node2
);
337 axiom_node_add_child(node
, this->env
, node2
);
338 attr
= axiom_attribute_create(this->env
, "ifmap-cardinality", "singleValue",
340 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
346 * Create capability metadata
348 static axiom_node_t
* create_capability(private_tnc_ifmap_soap_t
*this,
349 identification_t
*name
)
352 axiom_node_t
*node
, *node2
, *node3
;
353 axiom_namespace_t
*ns_meta
;
354 axiom_attribute_t
*attr
;
358 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
359 el
= axiom_element_create(this->env
, NULL
, "capability", ns_meta
, &node
);
360 attr
= axiom_attribute_create(this->env
, "ifmap-cardinality", "multiValue",
362 axiom_element_add_attribute(el
, this->env
, attr
, node
);
364 el
= axiom_element_create(this->env
, NULL
, "name", NULL
, &node2
);
365 axiom_node_add_child(node
, this->env
, node2
);
366 snprintf(buf
, BUF_LEN
, "%Y", name
);
367 text
= axiom_text_create(this->env
, node2
, buf
, &node3
);
369 el
= axiom_element_create(this->env
, NULL
, "administrative-domain", NULL
, &node2
);
370 axiom_node_add_child(node
, this->env
, node2
);
371 text
= axiom_text_create(this->env
, node2
, "strongswan", &node3
);
377 * Create delete filter
379 static axiom_node_t
* create_delete_filter(private_tnc_ifmap_soap_t
*this,
384 axiom_attribute_t
*attr
;
387 el
= axiom_element_create(this->env
, NULL
, "delete", NULL
, &node
);
389 snprintf(buf
, BUF_LEN
, "meta:%s[@ifmap-publisher-id='%s']",
390 metadata
, this->ifmap_publisher_id
);
391 attr
= axiom_attribute_create(this->env
, "filter", buf
, NULL
);
392 axiom_element_add_attribute(el
, this->env
, attr
, node
);
397 METHOD(tnc_ifmap_soap_t
, publish_ike_sa
, bool,
398 private_tnc_ifmap_soap_t
*this, ike_sa_t
*ike_sa
, bool up
)
400 axiom_node_t
*request
, *node
, *node2
;
402 axiom_namespace_t
*ns
, *ns_meta
;
403 axiom_attribute_t
*attr
;
405 enumerator_t
*e1
, *e2
;
407 identification_t
*id
, *eap_id
, *group
;
411 bool is_user
, first
= TRUE
;
413 /* extract relevant data from IKE_SA*/
414 ike_sa_id
= ike_sa
->get_unique_id(ike_sa
);
415 id
= ike_sa
->get_other_id(ike_sa
);
416 eap_id
= ike_sa
->get_other_eap_id(ike_sa
);
417 host
= ike_sa
->get_other_host(ike_sa
);
419 /* in the presence of an EAP Identity, treat it as a username */
420 is_user
= !id
->equals(id
, eap_id
);
422 /* build publish request */
423 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
424 el
= axiom_element_create(this->env
, NULL
, "publish", ns
, &request
);
425 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
426 axiom_element_declare_namespace(el
, this->env
, request
, ns_meta
);
427 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
,
429 axiom_element_add_attribute(el
, this->env
, attr
, request
);
432 * update or delete authenticated-as metadata
436 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
440 node
= create_delete_filter(this, "authenticated-as");
442 axiom_node_add_child(request
, this->env
, node
);
444 /* add access-request, identity and [if up] metadata */
445 axiom_node_add_child(node
, this->env
,
446 create_access_request(this, ike_sa_id
));
447 axiom_node_add_child(node
, this->env
,
448 create_identity(this, id
, is_user
));
451 axiom_node_add_child(node
, this->env
,
452 create_metadata(this, "authenticated-as"));
456 * update or delete access-request-ip metadata
460 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
464 node
= create_delete_filter(this, "access-request-ip");
466 axiom_node_add_child(request
, this->env
, node
);
468 /* add access-request, ip-address and [if up] metadata */
469 axiom_node_add_child(node
, this->env
,
470 create_access_request(this, ike_sa_id
));
471 axiom_node_add_child(node
, this->env
,
472 create_ip_address(this, host
));
475 axiom_node_add_child(node
, this->env
,
476 create_metadata(this, "access-request-ip"));
480 * update or delete authenticated-by metadata
484 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
488 node
= create_delete_filter(this, "authenticated-by");
490 axiom_node_add_child(request
, this->env
, node
);
492 /* add access-request, device and [if up] metadata */
493 axiom_node_add_child(node
, this->env
,
494 create_access_request(this, ike_sa_id
));
495 axiom_node_add_child(node
, this->env
,
496 create_device(this));
499 axiom_node_add_child(node
, this->env
,
500 create_metadata(this, "authenticated-by"));
504 * update or delete capability metadata
506 e1
= ike_sa
->create_auth_cfg_enumerator(ike_sa
, FALSE
);
507 while (e1
->enumerate(e1
, &auth
))
509 e2
= auth
->create_enumerator(auth
);
510 while (e2
->enumerate(e2
, &type
, &group
))
512 /* look for group memberships */
513 if (type
== AUTH_RULE_GROUP
)
521 el
= axiom_element_create(this->env
, NULL
, "update",
526 node
= create_delete_filter(this, "capability");
528 axiom_node_add_child(request
, this->env
, node
);
530 /* add access-request */
531 axiom_node_add_child(node
, this->env
,
532 create_access_request(this, ike_sa_id
));
537 el
= axiom_element_create(this->env
, NULL
, "metadata", NULL
,
539 axiom_node_add_child(node
, this->env
, node2
);
541 axiom_node_add_child(node2
, this->env
,
542 create_capability(this, group
));
553 /* send publish request and receive publishReceived */
554 return send_receive(this, "publish", request
, "publishReceived", NULL
);
557 METHOD(tnc_ifmap_soap_t
, publish_device_ip
, bool,
558 private_tnc_ifmap_soap_t
*this, host_t
*host
)
560 axiom_node_t
*request
, *node
;
562 axiom_namespace_t
*ns
, *ns_meta
;
563 axiom_attribute_t
*attr
;
565 /* build publish request */
566 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
567 el
= axiom_element_create(this->env
, NULL
, "publish", ns
, &request
);
568 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
569 axiom_element_declare_namespace(el
, this->env
, request
, ns_meta
);
570 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
,
572 axiom_element_add_attribute(el
, this->env
, attr
, request
);
573 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
574 axiom_node_add_child(request
, this->env
, node
);
576 /* add device, ip-address and metadata */
577 axiom_node_add_child(node
, this->env
,
578 create_device(this));
579 axiom_node_add_child(node
, this->env
,
580 create_ip_address(this, host
));
581 axiom_node_add_child(node
, this->env
,
582 create_metadata(this, "device-ip"));
584 /* send publish request and receive publishReceived */
585 return send_receive(this, "publish", request
, "publishReceived", NULL
);
588 METHOD(tnc_ifmap_soap_t
, endSession
, bool,
589 private_tnc_ifmap_soap_t
*this)
591 axiom_node_t
*request
;
593 axiom_namespace_t
*ns
;
594 axiom_attribute_t
*attr
;
596 /* build endSession request */
597 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
598 el
= axiom_element_create(this->env
, NULL
, "endSession", ns
, &request
);
599 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
, NULL
);
600 axiom_element_add_attribute(el
, this->env
, attr
, request
);
602 /* send endSession request and receive end SessionResult */
603 return send_receive(this, "endSession", request
, "endSessionResult", NULL
);
606 METHOD(tnc_ifmap_soap_t
, destroy
, void,
607 private_tnc_ifmap_soap_t
*this)
609 if (this->session_id
)
612 free(this->session_id
);
613 free(this->ifmap_publisher_id
);
614 free(this->device_name
);
616 if (this->svc_client
)
618 axis2_svc_client_free(this->svc_client
, this->env
);
622 axutil_env_free(this->env
);
627 static bool axis2c_init(private_tnc_ifmap_soap_t
*this)
629 axis2_char_t
*server
, *server_cert
, *client_home
;
630 axis2_char_t
*username
, *password
, *auth_type
;
631 axis2_endpoint_ref_t
* endpoint_ref
= NULL
;
632 axis2_options_t
*options
= NULL
;
633 axis2_transport_in_desc_t
*transport_in
;
634 axis2_transport_out_desc_t
*transport_out
;
635 axis2_transport_sender_t
*transport_sender
;
636 axutil_property_t
* property
;
638 /* Getting configuration parameters from strongswan.conf */
639 client_home
= lib
->settings
->get_str(lib
->settings
,
640 "charon.plugins.tnc-ifmap.client_home",
641 AXIS2_GETENV("AXIS2C_HOME"));
642 server
= lib
->settings
->get_str(lib
->settings
,
643 "charon.plugins.tnc-ifmap.server", IFMAP_SERVER
);
644 server_cert
= lib
->settings
->get_str(lib
->settings
,
645 "charon.plugins.tnc-ifmap.server_cert", NULL
);
646 auth_type
= lib
->settings
->get_str(lib
->settings
,
647 "charon.plugins.tnc-ifmap.auth_type", "Basic");
648 username
= lib
->settings
->get_str(lib
->settings
,
649 "charon.plugins.tnc-ifmap.username", NULL
);
650 password
= lib
->settings
->get_str(lib
->settings
,
651 "charon.plugins.tnc-ifmap.password", NULL
);
655 DBG1(DBG_TNC
, "MAP server certificate not defined");
658 if (!username
|| !password
)
660 DBG1(DBG_TNC
, "MAP client %s%s%s not defined",
661 (!username
) ?
"username" : "",
662 (!username
&& ! password
) ?
" and " : "",
663 (!password
) ?
"password" : "");
667 /* Create Axis2/C environment and options */
668 this->env
= axutil_env_create_all(IFMAP_LOGFILE
, AXIS2_LOG_LEVEL_TRACE
);
669 options
= axis2_options_create(this->env
);
671 /* Path to the MAP server certificate */
672 property
=axutil_property_create_with_args(this->env
, 0, 0, 0, server_cert
);
673 axis2_options_set_property(options
, this->env
, AXIS2_SSL_SERVER_CERT
, property
);
675 /* Define the MAP server as the to endpoint reference */
676 endpoint_ref
= axis2_endpoint_ref_create(this->env
, server
);
677 axis2_options_set_to(options
, this->env
, endpoint_ref
);
679 /* Set up HTTP Basic or Digest MAP client authentication */
680 axis2_options_set_http_auth_info(options
, this->env
, username
, password
,
683 /* Set up https transport */
684 transport_in
= axis2_transport_in_desc_create(this->env
,
685 AXIS2_TRANSPORT_ENUM_HTTPS
);
686 transport_out
= axis2_transport_out_desc_create(this->env
,
687 AXIS2_TRANSPORT_ENUM_HTTPS
);
688 transport_sender
= axis2_http_transport_sender_create(this->env
);
689 axis2_transport_out_desc_set_sender(transport_out
, this->env
,
691 axis2_options_set_transport_in(options
, this->env
, transport_in
);
692 axis2_options_set_transport_out(options
, this->env
, transport_out
);
694 /* Create the axis2 service client */
695 this->svc_client
= axis2_svc_client_create(this->env
, client_home
);
696 if (!this->svc_client
)
698 DBG1(DBG_TNC
, "could not create axis2 service client");
699 AXIS2_LOG_ERROR(this->env
->log
, AXIS2_LOG_SI
,
700 "Stub invoke FAILED: Error code: %d :: %s",
701 this->env
->error
->error_number
,
702 AXIS2_ERROR_GET_MESSAGE(this->env
->error
));
707 axis2_svc_client_set_options(this->svc_client
, this->env
, options
);
708 DBG1(DBG_TNC
, "connecting as MAP client '%s' to MAP server at '%s'",
717 tnc_ifmap_soap_t
*tnc_ifmap_soap_create()
719 private_tnc_ifmap_soap_t
*this;
723 .newSession
= _newSession
,
724 .purgePublisher
= _purgePublisher
,
725 .publish_ike_sa
= _publish_ike_sa
,
726 .publish_device_ip
= _publish_device_ip
,
727 .endSession
= _endSession
,
732 if (!axis2c_init(this))
738 return &this->public;