free device_name in destroy()
[strongswan.git] / src / libcharon / plugins / tnc_ifmap / tnc_ifmap_listener.c
1 /*
2 * Copyright (C) 2011 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_ifmap_listener.h"
17
18 #include <daemon.h>
19 #include <config/child_cfg.h>
20
21 #include <axis2_util.h>
22 #include <axis2_client.h>
23 #include <axiom_soap.h>
24
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/"
29
30 typedef struct private_tnc_ifmap_listener_t private_tnc_ifmap_listener_t;
31
32 /**
33 * Private data of an tnc_ifmap_listener_t object.
34 */
35 struct private_tnc_ifmap_listener_t {
36
37 /**
38 * Public tnc_ifmap_listener_t interface.
39 */
40 tnc_ifmap_listener_t public;
41
42 /**
43 * Axis2/C environment
44 */
45 axutil_env_t *env;
46
47 /**
48 * Axis2 service client
49 */
50 axis2_svc_client_t* svc_client;
51
52 /**
53 * SOAP Session ID
54 */
55 char *session_id;
56
57 /**
58 * IF-MAP Publisher ID
59 */
60 char *ifmap_publisher_id;
61
62 /**
63 * PEP and PDP device name
64 */
65 char *device_name;
66
67 };
68
69 static bool newSession(private_tnc_ifmap_listener_t *this)
70 {
71 axiom_node_t *request, *result, *node;
72 axiom_element_t *el;
73 axiom_namespace_t *ns;
74 axiom_attribute_t *attr;
75 axis2_char_t *value;
76 axutil_qname_t *qname;
77
78 bool success = FALSE;
79
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);
85
86 /* send newSession request */
87 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
88 if (!result)
89 {
90 return FALSE;
91 }
92
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)
96 {
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));
101
102 /* process the attributes */
103 if (success)
104 {
105 value = axiom_element_get_attribute_value_by_name(el, this->env,
106 "session-id");
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);
111
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;
115
116 value = axiom_element_get_attribute_value_by_name(el, this->env,
117 "max-poll-result-size");
118 if (value)
119 {
120 DBG1(DBG_TNC, "max-poll-result-size: %s", value);
121 }
122 }
123 else
124 {
125 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
126 }
127 }
128 axiom_node_free_tree(result, this->env);
129
130 return success;
131 }
132
133 static bool purgePublisher(private_tnc_ifmap_listener_t *this)
134 {
135 axiom_node_t *request, *result, *node;
136 axiom_element_t *el;
137 axiom_namespace_t *ns;
138 axiom_attribute_t *attr;
139 axutil_qname_t *qname;
140 bool success = FALSE;
141
142 /* build purgePublisher request */
143 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
144 el = axiom_element_create(this->env, NULL, "purgePublisher", ns,
145 &request);
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);
152
153 /* send purgePublisher request */
154 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
155 if (!result)
156 {
157 return FALSE;
158 }
159
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)
163 {
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));
168 if (!success)
169 {
170 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
171 }
172 }
173 axiom_node_free_tree(result, this->env);
174
175 return success;
176 }
177
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)
180 {
181 axiom_node_t *request, *result, *node, *node2, *node3, *node4;
182 axiom_element_t *el;
183 axiom_namespace_t *ns, *ns_meta;
184 axiom_attribute_t *attr;
185 axiom_text_t *text;
186 axutil_qname_t *qname;
187 char buf[BUF_LEN], *id_type;
188 bool success = FALSE;
189
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,
196 NULL);
197 axiom_element_add_attribute(el, this->env, attr, request);
198
199 /**
200 * update or delete authenticated-as metadata
201 */
202 if (up)
203 {
204 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
205 axiom_node_add_child(request, this->env, node);
206 }
207 else
208 {
209 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
210 axiom_node_add_child(request, this->env, node);
211
212 /* add filter */
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);
217 }
218
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);
222
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);
226
227 /* add identity */
228 el = axiom_element_create(this->env, NULL, "identity", NULL, &node2);
229 axiom_node_add_child(node, this->env, node2);
230
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);
234
235 switch (id->get_type(id))
236 {
237 case ID_FQDN:
238 id_type = "dns-name";
239 break;
240 case ID_RFC822_ADDR:
241 id_type = "email-address";
242 break;
243 case ID_DER_ASN1_DN:
244 id_type = "distinguished-name";
245 break;
246 default:
247 id_type = "other";
248 }
249 attr = axiom_attribute_create(this->env, "type", id_type, NULL);
250 axiom_element_add_attribute(el, this->env, attr, node2);
251
252 if (up)
253 {
254 /* add metadata */
255 el = axiom_element_create(this->env, NULL, "metadata", NULL, &node2);
256 axiom_node_add_child(node, this->env, node2);
257
258 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
259
260 el = axiom_element_create(this->env, NULL, "authenticated-as", ns_meta,
261 &node3);
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);
266 }
267
268 /**
269 * update or delete access-request-ip metadata
270 */
271 if (up)
272 {
273 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
274 axiom_node_add_child(request, this->env, node);
275 }
276 else
277 {
278 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
279 axiom_node_add_child(request, this->env, node);
280
281 /* add filter */
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);
286 }
287
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);
291
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);
295
296 /* add ip-address */
297 el = axiom_element_create(this->env, NULL, "ip-address", NULL, &node2);
298 axiom_node_add_child(node, this->env, node2);
299
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);
303
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);
307
308 if (up)
309 {
310 /* add metadata */
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,
315 &node3);
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);
320 }
321
322 /**
323 * update or delete authenticated-by metadata
324 */
325 if (up)
326 {
327 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
328 axiom_node_add_child(request, this->env, node);
329 }
330 else
331 {
332 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
333 axiom_node_add_child(request, this->env, node);
334
335 /* add filter */
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);
340 }
341
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);
345
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);
349
350 /* add device */
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);
356
357 if (up)
358 {
359 /* add metadata */
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,
364 &node3);
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);
369 }
370
371 /* send publish request */
372 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
373 if (!result)
374 {
375 return FALSE;
376 }
377
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)
381 {
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));
386 if (!success)
387 {
388 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
389 }
390 }
391 axiom_node_free_tree(result, this->env);
392
393 return TRUE;
394 }
395
396 static bool endSession(private_tnc_ifmap_listener_t *this)
397 {
398 axiom_node_t *request, *result, *node;
399 axiom_element_t *el;
400 axiom_namespace_t *ns;
401 axiom_attribute_t *attr;
402 axutil_qname_t *qname;
403 bool success = FALSE;
404
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);
410
411 /* send endSession request */
412 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
413 if (!result)
414 {
415 return FALSE;
416 }
417
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)
421 {
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));
426 if (!success)
427 {
428 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
429 }
430 }
431 axiom_node_free_tree(result, this->env);
432
433 return success;
434
435 return TRUE;
436 }
437
438 METHOD(listener_t, ike_updown, bool,
439 private_tnc_ifmap_listener_t *this, ike_sa_t *ike_sa, bool up)
440 {
441 u_int32_t ike_sa_id;
442 identification_t *id;
443 host_t *host;
444
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);
448
449 DBG2(DBG_TNC, "sending publish");
450 if (!publish(this, ike_sa_id, id, host, up))
451 {
452 DBG1(DBG_TNC, "publish with MAP server failed");
453 }
454
455 return TRUE;
456 }
457
458 METHOD(tnc_ifmap_listener_t, destroy, void,
459 private_tnc_ifmap_listener_t *this)
460 {
461 if (this->session_id)
462 {
463 DBG2(DBG_TNC, "sending endSession");
464 if (!endSession(this))
465 {
466 DBG1(DBG_TNC, "endSession with MAP server failed");
467 }
468 free(this->session_id);
469 free(this->ifmap_publisher_id);
470 free(this->device_name);
471 }
472 if (this->svc_client)
473 {
474 axis2_svc_client_free(this->svc_client, this->env);
475 }
476 if (this->env)
477 {
478 axutil_env_free(this->env);
479 }
480 free(this);
481 }
482
483 /**
484 * See header
485 */
486 tnc_ifmap_listener_t *tnc_ifmap_listener_create()
487 {
488 private_tnc_ifmap_listener_t *this;
489 axis2_char_t *server, *client_home, *username, *password, *auth_type;
490 axis2_endpoint_ref_t* endpoint_ref = NULL;
491 axis2_options_t *options = NULL;
492
493 client_home = lib->settings->get_str(lib->settings,
494 "charon.plugins.tnc-ifmap.client_home",
495 AXIS2_GETENV("AXIS2C_HOME"));
496 server = lib->settings->get_str(lib->settings,
497 "charon.plugins.tnc-ifmap.server", IFMAP_SERVER);
498 auth_type = lib->settings->get_str(lib->settings,
499 "charon.plugins.tnc-ifmap.auth_type", "Basic");
500 username = lib->settings->get_str(lib->settings,
501 "charon.plugins.tnc-ifmap.username", NULL);
502 password = lib->settings->get_str(lib->settings,
503 "charon.plugins.tnc-ifmap.password", NULL);
504
505 if (!username || !password)
506 {
507 DBG1(DBG_TNC, "MAP client %s%s%s not defined",
508 (!username) ? "username" : "",
509 (!username && ! password) ? " and " : "",
510 (!password) ? "password" : "");
511 }
512
513 INIT(this,
514 .public = {
515 .listener = {
516 .ike_updown = _ike_updown,
517 },
518 .destroy = _destroy,
519 },
520 );
521
522 /* Create Axis2/C environment and options */
523 this->env = axutil_env_create_all(IFMAP_LOGFILE, AXIS2_LOG_LEVEL_TRACE);
524 options = axis2_options_create(this->env);
525
526 /* Define the IF-MAP server as the to endpoint reference */
527 endpoint_ref = axis2_endpoint_ref_create(this->env, server);
528 axis2_options_set_to(options, this->env, endpoint_ref);
529
530 /* Create the axis2 service client */
531 this->svc_client = axis2_svc_client_create(this->env, client_home);
532 if (!this->svc_client)
533 {
534 DBG1(DBG_TNC, "Error creating axis2 service client");
535 AXIS2_LOG_ERROR(this->env->log, AXIS2_LOG_SI,
536 "Stub invoke FAILED: Error code: %d :: %s",
537 this->env->error->error_number,
538 AXIS2_ERROR_GET_MESSAGE(this->env->error));
539 destroy(this);
540 return NULL;
541 }
542
543 axis2_svc_client_set_options(this->svc_client, this->env, options);
544 axis2_options_set_http_auth_info(options, this->env, username, password,
545 auth_type);
546 DBG1(DBG_TNC, "connecting as MAP client '%s' to MAP server at '%s'",
547 username, server);
548
549 DBG2(DBG_TNC, "sending newSession");
550 if (!newSession(this))
551 {
552 DBG1(DBG_TNC, "newSession with MAP server failed");
553 destroy(this);
554 return NULL;
555 }
556
557 /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */
558 this->device_name = lib->settings->get_str(lib->settings,
559 "charon.plugins.tnc-ifmap.device_name", this->ifmap_publisher_id);
560 this->device_name = strdup(this->device_name);
561
562 DBG2(DBG_TNC, "sending purgePublisher");
563 if (!purgePublisher(this))
564 {
565 DBG1(DBG_TNC, "purgePublisher with MAP server failed");
566 destroy(this);
567 return NULL;
568 }
569
570 return &this->public;
571 }
572