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 <axiom_soap.h>
24 #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2"
25 #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2"
26 #define IFMAP_LOGFILE "strongswan_ifmap.log"
27 #define IFMAP_SERVER "https://localhost:8443/"
29 typedef struct private_tnc_ifmap_soap_t private_tnc_ifmap_soap_t
;
32 * Private data of an tnc_ifmap_soap_t object.
34 struct private_tnc_ifmap_soap_t
{
37 * Public tnc_ifmap_soap_t interface.
39 tnc_ifmap_soap_t
public;
47 * Axis2 service client
49 axis2_svc_client_t
* svc_client
;
59 char *ifmap_publisher_id
;
62 * PEP and PDP device name
69 * Send request and receive result via SOAP
71 static bool send_receive(private_tnc_ifmap_soap_t
*this,
72 char *request_qname
, axiom_node_t
*request
,
73 char *receipt_qname
, axiom_node_t
**result
)
76 axiom_node_t
*parent
, *node
;
78 axutil_qname_t
*qname
;
81 /* send request and receive result */
82 DBG2(DBG_TNC
, "sending ifmap %s", request_qname
);
84 parent
= axis2_svc_client_send_receive(this->svc_client
, this->env
, request
);
87 DBG1(DBG_TNC
, "no ifmap %s received from MAP server", receipt_qname
);
91 /* pre-process result */
92 node
= axiom_node_get_first_child(parent
, this->env
);
93 if (node
&& axiom_node_get_node_type(node
, this->env
) == AXIOM_ELEMENT
)
95 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
97 qname
= axiom_element_get_qname(el
, this->env
, node
);
98 success
= streq(receipt_qname
, axutil_qname_to_string(qname
, this->env
));
101 DBG2(DBG_TNC
, "received ifmap %s", receipt_qname
);
108 /* no further processing requested */
109 axiom_node_free_tree(parent
, this->env
);
113 /* TODO proper error handling */
114 DBG1(DBG_TNC
, "%s", axiom_element_to_string(el
, this->env
, node
));
117 /* free parent in the error case */
118 axiom_node_free_tree(parent
, this->env
);
123 METHOD(tnc_ifmap_soap_t
, newSession
, bool,
124 private_tnc_ifmap_soap_t
*this)
126 axiom_node_t
*request
, *result
, *node
;
128 axiom_namespace_t
*ns
;
132 /* build newSession request */
133 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
134 el
= axiom_element_create(this->env
, NULL
, "newSession", ns
, &request
);
136 /* send newSession request and receive newSessionResult */
137 if (!send_receive(this, "newSession", request
, "newSessionResult", &result
))
142 /* process newSessionResult */
143 node
= axiom_node_get_first_child(result
, this->env
);
144 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
147 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
149 this->session_id
= strdup(value
);
151 /* get ifmap-publisher-id */
152 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
153 "ifmap-publisher-id");
154 this->ifmap_publisher_id
= strdup(value
);
156 DBG1(DBG_TNC
, "session-id: %s, ifmap-publisher-id: %s",
157 this->session_id
, this->ifmap_publisher_id
);
159 /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */
160 this->device_name
= lib
->settings
->get_str(lib
->settings
,
161 "charon.plugins.tnc-ifmap.device_name",
162 this->ifmap_publisher_id
);
163 this->device_name
= strdup(this->device_name
);
166 axiom_node_free_tree(result
, this->env
);
168 return this->session_id
&& this->ifmap_publisher_id
;
171 METHOD(tnc_ifmap_soap_t
, purgePublisher
, bool,
172 private_tnc_ifmap_soap_t
*this)
174 axiom_node_t
*request
;
176 axiom_namespace_t
*ns
;
177 axiom_attribute_t
*attr
;
179 /* build purgePublisher request */
180 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
181 el
= axiom_element_create(this->env
, NULL
, "purgePublisher", ns
, &request
);
182 attr
= axiom_attribute_create(this->env
, "session-id",
183 this->session_id
, NULL
);
184 axiom_element_add_attribute(el
, this->env
, attr
, request
);
185 attr
= axiom_attribute_create(this->env
, "ifmap-publisher-id",
186 this->ifmap_publisher_id
, NULL
);
187 axiom_element_add_attribute(el
, this->env
, attr
, request
);
189 /* send purgePublisher request and receive purgePublisherReceived */
190 return send_receive(this, "purgePublisher", request
,
191 "purgePublisherReceived", NULL
);
195 * Create an access-request based on device_name and ike_sa_id
197 static axiom_node_t
* create_access_request(private_tnc_ifmap_soap_t
*this,
202 axiom_attribute_t
*attr
;
205 el
= axiom_element_create(this->env
, NULL
, "access-request", NULL
, &node
);
207 snprintf(buf
, BUF_LEN
, "%s:%d", this->device_name
, id
);
208 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
209 axiom_element_add_attribute(el
, this->env
, attr
, node
);
217 static axiom_node_t
* create_identity(private_tnc_ifmap_soap_t
*this,
218 identification_t
*id
)
222 axiom_attribute_t
*attr
;
223 char buf
[BUF_LEN
], *id_type
;
225 el
= axiom_element_create(this->env
, NULL
, "identity", NULL
, &node
);
227 snprintf(buf
, BUF_LEN
, "%Y", id
);
228 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
229 axiom_element_add_attribute(el
, this->env
, attr
, node
);
231 switch (id
->get_type(id
))
234 id_type
= "dns-name";
237 id_type
= "email-address";
240 id_type
= "distinguished-name";
245 attr
= axiom_attribute_create(this->env
, "type", id_type
, NULL
);
246 axiom_element_add_attribute(el
, this->env
, attr
, node
);
252 * Create an ip-address
254 static axiom_node_t
* create_ip_address(private_tnc_ifmap_soap_t
*this,
259 axiom_attribute_t
*attr
;
262 el
= axiom_element_create(this->env
, NULL
, "ip-address", NULL
, &node
);
264 snprintf(buf
, BUF_LEN
, "%H", host
);
265 attr
= axiom_attribute_create(this->env
, "value", buf
, NULL
);
266 axiom_element_add_attribute(el
, this->env
, attr
, node
);
268 attr
= axiom_attribute_create(this->env
, "type",
269 host
->get_family(host
) == AF_INET ?
"IPv4" : "IPv6", NULL
);
270 axiom_element_add_attribute(el
, this->env
, attr
, node
);
278 static axiom_node_t
* create_device(private_tnc_ifmap_soap_t
*this)
281 axiom_node_t
*node
, *node2
, *node3
;
284 el
= axiom_element_create(this->env
, NULL
, "device", NULL
, &node
);
285 el
= axiom_element_create(this->env
, NULL
, "name", NULL
, &node2
);
286 axiom_node_add_child(node
, this->env
, node2
);
287 text
= axiom_text_create(this->env
, node2
, this->device_name
, &node3
);
295 static axiom_node_t
* create_metadata(private_tnc_ifmap_soap_t
*this,
299 axiom_node_t
*node
, *node2
;
300 axiom_attribute_t
*attr
;
301 axiom_namespace_t
*ns_meta
;
303 el
= axiom_element_create(this->env
, NULL
, "metadata", NULL
, &node
);
304 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
306 el
= axiom_element_create(this->env
, NULL
, metadata
, ns_meta
, &node2
);
307 axiom_node_add_child(node
, this->env
, node2
);
308 attr
= axiom_attribute_create(this->env
, "ifmap-cardinality", "singleValue",
310 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
316 * Create delete filter
318 static axiom_node_t
* create_delete_filter(private_tnc_ifmap_soap_t
*this,
323 axiom_attribute_t
*attr
;
326 el
= axiom_element_create(this->env
, NULL
, "delete", NULL
, &node
);
328 snprintf(buf
, BUF_LEN
, "meta:%s[@ifmap-publisher-id='%s']",
329 metadata
, this->ifmap_publisher_id
);
330 attr
= axiom_attribute_create(this->env
, "filter", buf
, NULL
);
331 axiom_element_add_attribute(el
, this->env
, attr
, node
);
336 METHOD(tnc_ifmap_soap_t
, publish
, bool,
337 private_tnc_ifmap_soap_t
*this, u_int32_t ike_sa_id
, identification_t
*id
,
338 host_t
*host
, bool up
)
340 axiom_node_t
*request
, *node
;
342 axiom_namespace_t
*ns
, *ns_meta
;
343 axiom_attribute_t
*attr
;
345 /* build publish request */
346 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
347 el
= axiom_element_create(this->env
, NULL
, "publish", ns
, &request
);
348 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
349 axiom_element_declare_namespace(el
, this->env
, request
, ns_meta
);
350 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
,
352 axiom_element_add_attribute(el
, this->env
, attr
, request
);
355 * update or delete authenticated-as metadata
359 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
363 node
= create_delete_filter(this, "authenticated-as");
365 axiom_node_add_child(request
, this->env
, node
);
367 /* add access-request, identity and [if up] metadata */
368 axiom_node_add_child(node
, this->env
,
369 create_access_request(this, ike_sa_id
));
370 axiom_node_add_child(node
, this->env
,
371 create_identity(this, id
));
374 axiom_node_add_child(node
, this->env
,
375 create_metadata(this, "authenticated-as"));
379 * update or delete access-request-ip metadata
383 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
387 node
= create_delete_filter(this, "access-request-ip");
389 axiom_node_add_child(request
, this->env
, node
);
391 /* add access-request, ip-address and [if up] metadata */
392 axiom_node_add_child(node
, this->env
,
393 create_access_request(this, ike_sa_id
));
394 axiom_node_add_child(node
, this->env
,
395 create_ip_address(this, host
));
398 axiom_node_add_child(node
, this->env
,
399 create_metadata(this, "access-request-ip"));
403 * update or delete authenticated-by metadata
407 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
411 node
= create_delete_filter(this, "authenticated-by");
413 axiom_node_add_child(request
, this->env
, node
);
415 /* add access-request, device and [if up] metadata */
416 axiom_node_add_child(node
, this->env
,
417 create_access_request(this, ike_sa_id
));
418 axiom_node_add_child(node
, this->env
,
419 create_device(this));
422 axiom_node_add_child(node
, this->env
,
423 create_metadata(this, "authenticated-by"));
426 /* send publish request and receive publishReceived */
427 return send_receive(this, "publish", request
, "publishReceived", NULL
);
430 METHOD(tnc_ifmap_soap_t
, endSession
, bool,
431 private_tnc_ifmap_soap_t
*this)
433 axiom_node_t
*request
;
435 axiom_namespace_t
*ns
;
436 axiom_attribute_t
*attr
;
438 /* build endSession request */
439 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
440 el
= axiom_element_create(this->env
, NULL
, "endSession", ns
, &request
);
441 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
, NULL
);
442 axiom_element_add_attribute(el
, this->env
, attr
, request
);
444 /* send endSession request and receive end SessionResult */
445 return send_receive(this, "endSession", request
, "endSessionResult", NULL
);
448 METHOD(tnc_ifmap_soap_t
, destroy
, void,
449 private_tnc_ifmap_soap_t
*this)
451 if (this->session_id
)
454 free(this->session_id
);
455 free(this->ifmap_publisher_id
);
456 free(this->device_name
);
458 if (this->svc_client
)
460 axis2_svc_client_free(this->svc_client
, this->env
);
464 axutil_env_free(this->env
);
472 tnc_ifmap_soap_t
*tnc_ifmap_soap_create()
474 private_tnc_ifmap_soap_t
*this;
475 axis2_char_t
*server
, *client_home
, *username
, *password
, *auth_type
;
476 axis2_endpoint_ref_t
* endpoint_ref
= NULL
;
477 axis2_options_t
*options
= NULL
;
479 client_home
= lib
->settings
->get_str(lib
->settings
,
480 "charon.plugins.tnc-ifmap.client_home",
481 AXIS2_GETENV("AXIS2C_HOME"));
482 server
= lib
->settings
->get_str(lib
->settings
,
483 "charon.plugins.tnc-ifmap.server", IFMAP_SERVER
);
484 auth_type
= lib
->settings
->get_str(lib
->settings
,
485 "charon.plugins.tnc-ifmap.auth_type", "Basic");
486 username
= lib
->settings
->get_str(lib
->settings
,
487 "charon.plugins.tnc-ifmap.username", NULL
);
488 password
= lib
->settings
->get_str(lib
->settings
,
489 "charon.plugins.tnc-ifmap.password", NULL
);
491 if (!username
|| !password
)
493 DBG1(DBG_TNC
, "MAP client %s%s%s not defined",
494 (!username
) ?
"username" : "",
495 (!username
&& ! password
) ?
" and " : "",
496 (!password
) ?
"password" : "");
502 .newSession
= _newSession
,
503 .purgePublisher
= _purgePublisher
,
505 .endSession
= _endSession
,
510 /* Create Axis2/C environment and options */
511 this->env
= axutil_env_create_all(IFMAP_LOGFILE
, AXIS2_LOG_LEVEL_TRACE
);
512 options
= axis2_options_create(this->env
);
514 /* Define the IF-MAP server as the to endpoint reference */
515 endpoint_ref
= axis2_endpoint_ref_create(this->env
, server
);
516 axis2_options_set_to(options
, this->env
, endpoint_ref
);
518 /* Create the axis2 service client */
519 this->svc_client
= axis2_svc_client_create(this->env
, client_home
);
520 if (!this->svc_client
)
522 DBG1(DBG_TNC
, "could not create axis2 service client");
523 AXIS2_LOG_ERROR(this->env
->log
, AXIS2_LOG_SI
,
524 "Stub invoke FAILED: Error code: %d :: %s",
525 this->env
->error
->error_number
,
526 AXIS2_ERROR_GET_MESSAGE(this->env
->error
));
531 axis2_svc_client_set_options(this->svc_client
, this->env
, options
);
532 axis2_options_set_http_auth_info(options
, this->env
, username
, password
,
534 DBG1(DBG_TNC
, "connecting as MAP client '%s' to MAP server at '%s'",
537 return &this->public;