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_listener.h"
19 #include <config/child_cfg.h>
21 #include <axis2_util.h>
22 #include <axis2_client.h>
23 #include <axiom_soap.h>
25 #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2"
26 #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2"
27 #define IFMAP_LOGFILE "strongswan_ifmap.log"
28 #define IFMAP_SERVER "https://localhost:8443/"
30 typedef struct private_tnc_ifmap_listener_t private_tnc_ifmap_listener_t
;
33 * Private data of an tnc_ifmap_listener_t object.
35 struct private_tnc_ifmap_listener_t
{
38 * Public tnc_ifmap_listener_t interface.
40 tnc_ifmap_listener_t
public;
48 * Axis2 service client
50 axis2_svc_client_t
* svc_client
;
60 char *ifmap_publisher_id
;
63 * PEP and PDP device name
69 static bool newSession(private_tnc_ifmap_listener_t
*this)
71 axiom_node_t
*request
, *result
, *node
;
73 axiom_namespace_t
*ns
;
74 axiom_attribute_t
*attr
;
76 axutil_qname_t
*qname
;
80 /* build newSession request */
81 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
82 el
= axiom_element_create(this->env
, NULL
, "newSession", ns
, &request
);
83 attr
= axiom_attribute_create(this->env
, "max-poll-result-size", "1000000", NULL
);
84 axiom_element_add_attribute(el
, this->env
, attr
, request
);
86 /* send newSession request */
87 result
= axis2_svc_client_send_receive(this->svc_client
, this->env
, request
);
93 /* process newSessionResult */
94 node
= axiom_node_get_first_child(result
, 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
);
98 qname
= axiom_element_get_qname(el
, this->env
, node
);
99 success
= streq("newSessionResult",
100 axutil_qname_to_string(qname
, this->env
));
102 /* process the attributes */
105 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
107 this->session_id
= strdup(value
);
108 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
109 "ifmap-publisher-id");
110 this->ifmap_publisher_id
= strdup(value
);
112 DBG1(DBG_TNC
, "session-id: %s, ifmap-publisher-id: %s",
113 this->session_id
, this->ifmap_publisher_id
);
114 success
= this->session_id
&& this->ifmap_publisher_id
;
116 value
= axiom_element_get_attribute_value_by_name(el
, this->env
,
117 "max-poll-result-size");
120 DBG1(DBG_TNC
, "max-poll-result-size: %s", value
);
125 DBG1(DBG_TNC
, "%s", axiom_element_to_string(el
, this->env
, node
));
128 axiom_node_free_tree(result
, this->env
);
133 static bool purgePublisher(private_tnc_ifmap_listener_t
*this)
135 axiom_node_t
*request
, *result
, *node
;
137 axiom_namespace_t
*ns
;
138 axiom_attribute_t
*attr
;
139 axutil_qname_t
*qname
;
140 bool success
= FALSE
;
142 /* build purgePublisher request */
143 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
144 el
= axiom_element_create(this->env
, NULL
, "purgePublisher", ns
,
146 attr
= axiom_attribute_create(this->env
, "session-id",
147 this->session_id
, NULL
);
148 axiom_element_add_attribute(el
, this->env
, attr
, request
);
149 attr
= axiom_attribute_create(this->env
, "ifmap-publisher-id",
150 this->ifmap_publisher_id
, NULL
);
151 axiom_element_add_attribute(el
, this->env
, attr
, request
);
153 /* send purgePublisher request */
154 result
= axis2_svc_client_send_receive(this->svc_client
, this->env
, request
);
160 /* process purgePublisherReceived */
161 node
= axiom_node_get_first_child(result
, this->env
);
162 if (node
&& axiom_node_get_node_type(node
, this->env
) == AXIOM_ELEMENT
)
164 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
165 qname
= axiom_element_get_qname(el
, this->env
, node
);
166 success
= streq("purgePublisherReceived",
167 axutil_qname_to_string(qname
, this->env
));
170 DBG1(DBG_TNC
, "%s", axiom_element_to_string(el
, this->env
, node
));
173 axiom_node_free_tree(result
, this->env
);
178 static bool publish(private_tnc_ifmap_listener_t
*this, u_int32_t ike_sa_id
,
179 identification_t
*id
, host_t
*host
, bool up
)
181 axiom_node_t
*request
, *result
, *node
, *node2
, *node3
, *node4
;
183 axiom_namespace_t
*ns
, *ns_meta
;
184 axiom_attribute_t
*attr
;
186 axutil_qname_t
*qname
;
187 char buf
[BUF_LEN
], *id_type
;
188 bool success
= FALSE
;
190 /* build publish request */
191 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
192 el
= axiom_element_create(this->env
, NULL
, "publish", ns
, &request
);
193 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
194 axiom_element_declare_namespace(el
, this->env
, request
, ns_meta
);
195 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
,
197 axiom_element_add_attribute(el
, this->env
, attr
, request
);
200 * update or delete authenticated-as metadata
204 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
205 axiom_node_add_child(request
, this->env
, node
);
209 el
= axiom_element_create(this->env
, NULL
, "delete", NULL
, &node
);
210 axiom_node_add_child(request
, this->env
, node
);
213 snprintf(buf
, BUF_LEN
, "meta:authenticated-as[@ifmap-publisher-id='%s']",
214 this->ifmap_publisher_id
);
215 attr
= axiom_attribute_create(this->env
, "filter", buf
, NULL
);
216 axiom_element_add_attribute(el
, this->env
, attr
, node
);
219 /* add access-request */
220 el
= axiom_element_create(this->env
, NULL
, "access-request", NULL
, &node2
);
221 axiom_node_add_child(node
, this->env
, node2
);
223 snprintf(buf
, BUF_LEN
, "%s:%d", this->device_name
, ike_sa_id
);
224 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
225 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
228 el
= axiom_element_create(this->env
, NULL
, "identity", NULL
, &node2
);
229 axiom_node_add_child(node
, this->env
, node2
);
231 snprintf(buf
, BUF_LEN
, "%Y", id
);
232 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
233 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
235 switch (id
->get_type(id
))
238 id_type
= "dns-name";
241 id_type
= "email-address";
244 id_type
= "distinguished-name";
249 attr
= axiom_attribute_create(this->env
, "type", id_type
, NULL
);
250 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
255 el
= axiom_element_create(this->env
, NULL
, "metadata", NULL
, &node2
);
256 axiom_node_add_child(node
, this->env
, node2
);
258 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
260 el
= axiom_element_create(this->env
, NULL
, "authenticated-as", ns_meta
,
262 axiom_node_add_child(node2
, this->env
, node3
);
263 attr
= axiom_attribute_create(this->env
, "ifmap-cardinality",
264 "singleValue", NULL
);
265 axiom_element_add_attribute(el
, this->env
, attr
, node3
);
269 * update or delete access-request-ip metadata
273 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
274 axiom_node_add_child(request
, this->env
, node
);
278 el
= axiom_element_create(this->env
, NULL
, "delete", NULL
, &node
);
279 axiom_node_add_child(request
, this->env
, node
);
282 snprintf(buf
, BUF_LEN
, "meta:access-request-ip[@ifmap-publisher-id='%s']",
283 this->ifmap_publisher_id
);
284 attr
= axiom_attribute_create(this->env
, "filter", buf
, NULL
);
285 axiom_element_add_attribute(el
, this->env
, attr
, node
);
288 /* add access-request */
289 el
= axiom_element_create(this->env
, NULL
, "access-request", NULL
, &node2
);
290 axiom_node_add_child(node
, this->env
, node2
);
292 snprintf(buf
, BUF_LEN
, "%s:%d", this->device_name
, ike_sa_id
);
293 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
294 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
297 el
= axiom_element_create(this->env
, NULL
, "ip-address", NULL
, &node2
);
298 axiom_node_add_child(node
, this->env
, node2
);
300 snprintf(buf
, BUF_LEN
, "%H", host
);
301 attr
= axiom_attribute_create(this->env
, "value", buf
, NULL
);
302 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
304 attr
= axiom_attribute_create(this->env
, "type",
305 host
->get_family(host
) == AF_INET ?
"IPv4" : "IPv6", NULL
);
306 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
311 el
= axiom_element_create(this->env
, NULL
, "metadata", NULL
, &node2
);
312 axiom_node_add_child(node
, this->env
, node2
);
313 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
314 el
= axiom_element_create(this->env
, NULL
, "access-request-ip", ns_meta
,
316 axiom_node_add_child(node2
, this->env
, node3
);
317 attr
= axiom_attribute_create(this->env
, "ifmap-cardinality",
318 "singleValue", NULL
);
319 axiom_element_add_attribute(el
, this->env
, attr
, node3
);
323 * update or delete authenticated-by metadata
327 el
= axiom_element_create(this->env
, NULL
, "update", NULL
, &node
);
328 axiom_node_add_child(request
, this->env
, node
);
332 el
= axiom_element_create(this->env
, NULL
, "delete", NULL
, &node
);
333 axiom_node_add_child(request
, this->env
, node
);
336 snprintf(buf
, BUF_LEN
, "meta:authenticated-by[@ifmap-publisher-id='%s']",
337 this->ifmap_publisher_id
);
338 attr
= axiom_attribute_create(this->env
, "filter", buf
, NULL
);
339 axiom_element_add_attribute(el
, this->env
, attr
, node
);
342 /* add access-request */
343 el
= axiom_element_create(this->env
, NULL
, "access-request", NULL
, &node2
);
344 axiom_node_add_child(node
, this->env
, node2
);
346 snprintf(buf
, BUF_LEN
, "%s:%d", this->device_name
, ike_sa_id
);
347 attr
= axiom_attribute_create(this->env
, "name", buf
, NULL
);
348 axiom_element_add_attribute(el
, this->env
, attr
, node2
);
351 el
= axiom_element_create(this->env
, NULL
, "device", NULL
, &node2
);
352 axiom_node_add_child(node
, this->env
, node2
);
353 el
= axiom_element_create(this->env
, NULL
, "name", NULL
, &node3
);
354 axiom_node_add_child(node2
, this->env
, node3
);
355 text
= axiom_text_create(this->env
, node3
, this->device_name
, &node4
);
360 el
= axiom_element_create(this->env
, NULL
, "metadata", NULL
, &node2
);
361 axiom_node_add_child(node
, this->env
, node2
);
362 ns_meta
= axiom_namespace_create(this->env
, IFMAP_META_NS
, "meta");
363 el
= axiom_element_create(this->env
, NULL
, "authenticated-by", ns_meta
,
365 axiom_node_add_child(node2
, this->env
, node3
);
366 attr
= axiom_attribute_create(this->env
, "ifmap-cardinality",
367 "singleValue", NULL
);
368 axiom_element_add_attribute(el
, this->env
, attr
, node3
);
371 /* send publish request */
372 result
= axis2_svc_client_send_receive(this->svc_client
, this->env
, request
);
378 /* process publishReceived */
379 node
= axiom_node_get_first_child(result
, this->env
);
380 if (node
&& axiom_node_get_node_type(node
, this->env
) == AXIOM_ELEMENT
)
382 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
383 qname
= axiom_element_get_qname(el
, this->env
, node
);
384 success
= streq("publishReceived",
385 axutil_qname_to_string(qname
, this->env
));
388 DBG1(DBG_TNC
, "%s", axiom_element_to_string(el
, this->env
, node
));
391 axiom_node_free_tree(result
, this->env
);
396 static bool endSession(private_tnc_ifmap_listener_t
*this)
398 axiom_node_t
*request
, *result
, *node
;
400 axiom_namespace_t
*ns
;
401 axiom_attribute_t
*attr
;
402 axutil_qname_t
*qname
;
403 bool success
= FALSE
;
405 /* build endSession request */
406 ns
= axiom_namespace_create(this->env
, IFMAP_NS
, "ifmap");
407 el
= axiom_element_create(this->env
, NULL
, "endSession", ns
, &request
);
408 attr
= axiom_attribute_create(this->env
, "session-id", this->session_id
, NULL
);
409 axiom_element_add_attribute(el
, this->env
, attr
, request
);
411 /* send endSession request */
412 result
= axis2_svc_client_send_receive(this->svc_client
, this->env
, request
);
418 /* process endSessionResult */
419 node
= axiom_node_get_first_child(result
, this->env
);
420 if (node
&& axiom_node_get_node_type(node
, this->env
) == AXIOM_ELEMENT
)
422 el
= (axiom_element_t
*)axiom_node_get_data_element(node
, this->env
);
423 qname
= axiom_element_get_qname(el
, this->env
, node
);
424 success
= streq("endSessionResult",
425 axutil_qname_to_string(qname
, this->env
));
428 DBG1(DBG_TNC
, "%s", axiom_element_to_string(el
, this->env
, node
));
431 axiom_node_free_tree(result
, this->env
);
438 METHOD(listener_t
, ike_updown
, bool,
439 private_tnc_ifmap_listener_t
*this, ike_sa_t
*ike_sa
, bool up
)
442 identification_t
*id
;
445 ike_sa_id
= ike_sa
->get_unique_id(ike_sa
);
446 id
= ike_sa
->get_other_id(ike_sa
);
447 host
= ike_sa
->get_other_host(ike_sa
);
449 DBG2(DBG_TNC
, "sending publish");
450 if (!publish(this, ike_sa_id
, id
, host
, up
))
452 DBG1(DBG_TNC
, "publish with MAP server failed");
458 METHOD(tnc_ifmap_listener_t
, destroy
, void,
459 private_tnc_ifmap_listener_t
*this)
461 if (this->session_id
)
463 DBG2(DBG_TNC
, "sending endSession");
464 if (!endSession(this))
466 DBG1(DBG_TNC
, "endSession with MAP server failed");
468 free(this->session_id
);
469 free(this->ifmap_publisher_id
);
471 if (this->svc_client
)
473 axis2_svc_client_free(this->svc_client
, this->env
);
477 axutil_env_free(this->env
);
485 tnc_ifmap_listener_t
*tnc_ifmap_listener_create()
487 private_tnc_ifmap_listener_t
*this;
488 axis2_char_t
*server
, *client_home
, *username
, *password
, *auth_type
;
489 axis2_endpoint_ref_t
* endpoint_ref
= NULL
;
490 axis2_options_t
*options
= NULL
;
492 client_home
= lib
->settings
->get_str(lib
->settings
,
493 "charon.plugins.tnc-ifmap.client_home",
494 AXIS2_GETENV("AXIS2C_HOME"));
495 server
= lib
->settings
->get_str(lib
->settings
,
496 "charon.plugins.tnc-ifmap.server", IFMAP_SERVER
);
497 auth_type
= lib
->settings
->get_str(lib
->settings
,
498 "charon.plugins.tnc-ifmap.auth_type", "Basic");
499 username
= lib
->settings
->get_str(lib
->settings
,
500 "charon.plugins.tnc-ifmap.username", NULL
);
501 password
= lib
->settings
->get_str(lib
->settings
,
502 "charon.plugins.tnc-ifmap.password", NULL
);
504 if (!username
|| !password
)
506 DBG1(DBG_TNC
, "MAP client %s%s%s not defined",
507 (!username
) ?
"username" : "",
508 (!username
&& ! password
) ?
" and " : "",
509 (!password
) ?
"password" : "");
515 .ike_updown
= _ike_updown
,
521 /* Create Axis2/C environment and options */
522 this->env
= axutil_env_create_all(IFMAP_LOGFILE
, AXIS2_LOG_LEVEL_TRACE
);
523 options
= axis2_options_create(this->env
);
525 /* Define the IF-MAP server as the to endpoint reference */
526 endpoint_ref
= axis2_endpoint_ref_create(this->env
, server
);
527 axis2_options_set_to(options
, this->env
, endpoint_ref
);
529 /* Create the axis2 service client */
530 this->svc_client
= axis2_svc_client_create(this->env
, client_home
);
531 if (!this->svc_client
)
533 DBG1(DBG_TNC
, "Error creating axis2 service client");
534 AXIS2_LOG_ERROR(this->env
->log
, AXIS2_LOG_SI
,
535 "Stub invoke FAILED: Error code: %d :: %s",
536 this->env
->error
->error_number
,
537 AXIS2_ERROR_GET_MESSAGE(this->env
->error
));
542 axis2_svc_client_set_options(this->svc_client
, this->env
, options
);
543 axis2_options_set_http_auth_info(options
, this->env
, username
, password
,
545 DBG1(DBG_TNC
, "connecting as MAP client '%s' to MAP server at '%s'",
548 DBG2(DBG_TNC
, "sending newSession");
549 if (!newSession(this))
551 DBG1(DBG_TNC
, "newSession with MAP server failed");
556 /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */
557 this->device_name
= lib
->settings
->get_str(lib
->settings
,
558 "charon.plugins.tnc-ifmap.device_name", this->ifmap_publisher_id
);
559 this->device_name
= strdup(this->device_name
);
561 DBG2(DBG_TNC
, "sending purgePublisher");
562 if (!purgePublisher(this))
564 DBG1(DBG_TNC
, "purgePublisher with MAP server failed");
569 return &this->public;