ea23dafa01a49c8064c7e2f5da12f8c9384ab0a1
[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
64 static bool newSession(private_tnc_ifmap_listener_t *this)
65 {
66 axiom_node_t *request, *result, *node;
67 axiom_element_t *el;
68 axiom_namespace_t *ns;
69 axiom_attribute_t *attr;
70 axis2_char_t *value;
71 axutil_qname_t *qname;
72
73 bool success = FALSE;
74
75 /* build newSession request */
76 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
77 el = axiom_element_create(this->env, NULL, "newSession", ns, &request);
78 attr = axiom_attribute_create(this->env, "max-poll-result-size", "1000000", NULL);
79 axiom_element_add_attribute(el, this->env, attr, request);
80
81 /* send newSession request */
82 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
83 if (!result)
84 {
85 return FALSE;
86 }
87
88 /* process newSessionResult */
89 node = axiom_node_get_first_child(result, this->env);
90 if (node && axiom_node_get_node_type(node, this->env) == AXIOM_ELEMENT)
91 {
92 el = (axiom_element_t *)axiom_node_get_data_element(node, this->env);
93 qname = axiom_element_get_qname(el, this->env, node);
94 success = streq("newSessionResult",
95 axutil_qname_to_string(qname, this->env));
96
97 /* process the attributes */
98 if (success)
99 {
100 value = axiom_element_get_attribute_value_by_name(el, this->env,
101 "session-id");
102 this->session_id = strdup(value);
103 value = axiom_element_get_attribute_value_by_name(el, this->env,
104 "ifmap-publisher-id");
105 this->ifmap_publisher_id = strdup(value);
106
107 DBG1(DBG_TNC, "session-id: %s, ifmap-publisher-id: %s",
108 this->session_id, this->ifmap_publisher_id);
109 success = this->session_id && this->ifmap_publisher_id;
110
111 value = axiom_element_get_attribute_value_by_name(el, this->env,
112 "max-poll-result-size");
113 if (value)
114 {
115 DBG1(DBG_TNC, "max-poll-result-size: %s", value);
116 }
117 }
118 else
119 {
120 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
121 }
122 }
123 axiom_node_free_tree(result, this->env);
124
125 return success;
126 }
127
128 static bool purgePublisher(private_tnc_ifmap_listener_t *this)
129 {
130 axiom_node_t *request, *result, *node;
131 axiom_element_t *el;
132 axiom_namespace_t *ns;
133 axiom_attribute_t *attr;
134 axutil_qname_t *qname;
135 bool success = FALSE;
136
137 /* build purgePublisher request */
138 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
139 el = axiom_element_create(this->env, NULL, "purgePublisher", ns,
140 &request);
141 attr = axiom_attribute_create(this->env, "session-id",
142 this->session_id, NULL);
143 axiom_element_add_attribute(el, this->env, attr, request);
144 attr = axiom_attribute_create(this->env, "ifmap-publisher-id",
145 this->ifmap_publisher_id, NULL);
146 axiom_element_add_attribute(el, this->env, attr, request);
147
148 /* send purgePublisher request */
149 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
150 if (!result)
151 {
152 return FALSE;
153 }
154
155 /* process purgePublisherReceived */
156 node = axiom_node_get_first_child(result, this->env);
157 if (node && axiom_node_get_node_type(node, this->env) == AXIOM_ELEMENT)
158 {
159 el = (axiom_element_t *)axiom_node_get_data_element(node, this->env);
160 qname = axiom_element_get_qname(el, this->env, node);
161 success = streq("purgePublisherReceived",
162 axutil_qname_to_string(qname, this->env));
163 if (!success)
164 {
165 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
166 }
167 }
168 axiom_node_free_tree(result, this->env);
169
170 return success;
171 }
172
173 static bool publish(private_tnc_ifmap_listener_t *this, u_int32_t ike_sa_id,
174 identification_t *id, host_t *host, bool up)
175 {
176 axiom_node_t *request, *result, *node, *node2, *node3, *node4;
177 axiom_element_t *el;
178 axiom_namespace_t *ns, *ns_meta;
179 axiom_attribute_t *attr;
180 axiom_text_t *text;
181 axutil_qname_t *qname;
182 char buf[BUF_LEN], *id_type;
183 bool success = FALSE;
184
185 /* build publish request */
186 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
187 el = axiom_element_create(this->env, NULL, "publish", ns, &request);
188 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
189 axiom_element_declare_namespace(el, this->env, request, ns_meta);
190 attr = axiom_attribute_create(this->env, "session-id", this->session_id,
191 NULL);
192 axiom_element_add_attribute(el, this->env, attr, request);
193
194 /**
195 * update or delete authenticated-as metadata
196 */
197 if (up)
198 {
199 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
200 axiom_node_add_child(request, this->env, node);
201 }
202 else
203 {
204 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
205 axiom_node_add_child(request, this->env, node);
206
207 /* add filter */
208 snprintf(buf, BUF_LEN, "meta:authenticated-as[@ifmap-publisher-id='%s']",
209 this->ifmap_publisher_id);
210 attr = axiom_attribute_create(this->env, "filter", buf, NULL);
211 axiom_element_add_attribute(el, this->env, attr, node);
212 }
213
214 /* add access-request */
215 el = axiom_element_create(this->env, NULL, "access-request", NULL, &node2);
216 axiom_node_add_child(node, this->env, node2);
217
218 snprintf(buf, BUF_LEN, "%s:%d", this->ifmap_publisher_id, ike_sa_id);
219 attr = axiom_attribute_create(this->env, "name", buf, NULL);
220 axiom_element_add_attribute(el, this->env, attr, node2);
221
222 /* add identity */
223 el = axiom_element_create(this->env, NULL, "identity", NULL, &node2);
224 axiom_node_add_child(node, this->env, node2);
225
226 snprintf(buf, BUF_LEN, "%Y", id);
227 attr = axiom_attribute_create(this->env, "name", buf, NULL);
228 axiom_element_add_attribute(el, this->env, attr, node2);
229
230 switch (id->get_type(id))
231 {
232 case ID_FQDN:
233 id_type = "dns-name";
234 break;
235 case ID_RFC822_ADDR:
236 id_type = "email-address";
237 break;
238 case ID_DER_ASN1_DN:
239 id_type = "distinguished-name";
240 break;
241 default:
242 id_type = "other";
243 }
244 attr = axiom_attribute_create(this->env, "type", id_type, NULL);
245 axiom_element_add_attribute(el, this->env, attr, node2);
246
247 if (up)
248 {
249 /* add metadata */
250 el = axiom_element_create(this->env, NULL, "metadata", NULL, &node2);
251 axiom_node_add_child(node, this->env, node2);
252
253 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
254
255 el = axiom_element_create(this->env, NULL, "authenticated-as", ns_meta,
256 &node3);
257 axiom_node_add_child(node2, this->env, node3);
258 attr = axiom_attribute_create(this->env, "ifmap-cardinality",
259 "singleValue", NULL);
260 axiom_element_add_attribute(el, this->env, attr, node3);
261 }
262
263 /**
264 * update or delete access-request-ip metadata
265 */
266 if (up)
267 {
268 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
269 axiom_node_add_child(request, this->env, node);
270 }
271 else
272 {
273 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
274 axiom_node_add_child(request, this->env, node);
275
276 /* add filter */
277 snprintf(buf, BUF_LEN, "meta:access-request-ip[@ifmap-publisher-id='%s']",
278 this->ifmap_publisher_id);
279 attr = axiom_attribute_create(this->env, "filter", buf, NULL);
280 axiom_element_add_attribute(el, this->env, attr, node);
281 }
282
283 /* add access-request */
284 el = axiom_element_create(this->env, NULL, "access-request", NULL, &node2);
285 axiom_node_add_child(node, this->env, node2);
286
287 snprintf(buf, BUF_LEN, "%s:%d", this->ifmap_publisher_id, ike_sa_id);
288 attr = axiom_attribute_create(this->env, "name", buf, NULL);
289 axiom_element_add_attribute(el, this->env, attr, node2);
290
291 /* add ip-address */
292 el = axiom_element_create(this->env, NULL, "ip-address", NULL, &node2);
293 axiom_node_add_child(node, this->env, node2);
294
295 snprintf(buf, BUF_LEN, "%H", host);
296 attr = axiom_attribute_create(this->env, "value", buf, NULL);
297 axiom_element_add_attribute(el, this->env, attr, node2);
298
299 attr = axiom_attribute_create(this->env, "type",
300 host->get_family(host) == AF_INET ? "IPv4" : "IPv6", NULL);
301 axiom_element_add_attribute(el, this->env, attr, node2);
302
303 if (up)
304 {
305 /* add metadata */
306 el = axiom_element_create(this->env, NULL, "metadata", NULL, &node2);
307 axiom_node_add_child(node, this->env, node2);
308 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
309 el = axiom_element_create(this->env, NULL, "access-request-ip", ns_meta,
310 &node3);
311 axiom_node_add_child(node2, this->env, node3);
312 attr = axiom_attribute_create(this->env, "ifmap-cardinality",
313 "singleValue", NULL);
314 axiom_element_add_attribute(el, this->env, attr, node3);
315 }
316
317 /**
318 * update or delete authenticated-by metadata
319 */
320 if (up)
321 {
322 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
323 axiom_node_add_child(request, this->env, node);
324 }
325 else
326 {
327 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
328 axiom_node_add_child(request, this->env, node);
329
330 /* add filter */
331 snprintf(buf, BUF_LEN, "meta:authenticated-by[@ifmap-publisher-id='%s']",
332 this->ifmap_publisher_id);
333 attr = axiom_attribute_create(this->env, "filter", buf, NULL);
334 axiom_element_add_attribute(el, this->env, attr, node);
335 }
336
337 /* add access-request */
338 el = axiom_element_create(this->env, NULL, "access-request", NULL, &node2);
339 axiom_node_add_child(node, this->env, node2);
340
341 snprintf(buf, BUF_LEN, "%s:%d", this->ifmap_publisher_id, ike_sa_id);
342 attr = axiom_attribute_create(this->env, "name", buf, NULL);
343 axiom_element_add_attribute(el, this->env, attr, node2);
344
345 /* add device */
346 el = axiom_element_create(this->env, NULL, "device", NULL, &node2);
347 axiom_node_add_child(node, this->env, node2);
348 el = axiom_element_create(this->env, NULL, "name", NULL, &node3);
349 axiom_node_add_child(node2, this->env, node3);
350 text = axiom_text_create(this->env, node3, this->ifmap_publisher_id, &node4);
351
352 if (up)
353 {
354 /* add metadata */
355 el = axiom_element_create(this->env, NULL, "metadata", NULL, &node2);
356 axiom_node_add_child(node, this->env, node2);
357 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
358 el = axiom_element_create(this->env, NULL, "authenticated-by", ns_meta,
359 &node3);
360 axiom_node_add_child(node2, this->env, node3);
361 attr = axiom_attribute_create(this->env, "ifmap-cardinality",
362 "singleValue", NULL);
363 axiom_element_add_attribute(el, this->env, attr, node3);
364 }
365
366 /* send publish request */
367 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
368 if (!result)
369 {
370 return FALSE;
371 }
372
373 /* process publishReceived */
374 node = axiom_node_get_first_child(result, this->env);
375 if (node && axiom_node_get_node_type(node, this->env) == AXIOM_ELEMENT)
376 {
377 el = (axiom_element_t *)axiom_node_get_data_element(node, this->env);
378 qname = axiom_element_get_qname(el, this->env, node);
379 success = streq("publishReceived",
380 axutil_qname_to_string(qname, this->env));
381 if (!success)
382 {
383 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
384 }
385 }
386 axiom_node_free_tree(result, this->env);
387
388 return TRUE;
389 }
390
391 static bool endSession(private_tnc_ifmap_listener_t *this)
392 {
393 axiom_node_t *request, *result, *node;
394 axiom_element_t *el;
395 axiom_namespace_t *ns;
396 axiom_attribute_t *attr;
397 axutil_qname_t *qname;
398 bool success = FALSE;
399
400 /* build endSession request */
401 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
402 el = axiom_element_create(this->env, NULL, "endSession", ns, &request);
403 attr = axiom_attribute_create(this->env, "session-id", this->session_id, NULL);
404 axiom_element_add_attribute(el, this->env, attr, request);
405
406 /* send endSession request */
407 result = axis2_svc_client_send_receive(this->svc_client, this->env, request);
408 if (!result)
409 {
410 return FALSE;
411 }
412
413 /* process endSessionResult */
414 node = axiom_node_get_first_child(result, this->env);
415 if (node && axiom_node_get_node_type(node, this->env) == AXIOM_ELEMENT)
416 {
417 el = (axiom_element_t *)axiom_node_get_data_element(node, this->env);
418 qname = axiom_element_get_qname(el, this->env, node);
419 success = streq("endSessionResult",
420 axutil_qname_to_string(qname, this->env));
421 if (!success)
422 {
423 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
424 }
425 }
426 axiom_node_free_tree(result, this->env);
427
428 return success;
429
430 return TRUE;
431 }
432
433 METHOD(listener_t, ike_updown, bool,
434 private_tnc_ifmap_listener_t *this, ike_sa_t *ike_sa, bool up)
435 {
436 u_int32_t ike_sa_id;
437 identification_t *id;
438 host_t *host;
439
440 ike_sa_id = ike_sa->get_unique_id(ike_sa);
441 id = ike_sa->get_other_id(ike_sa);
442 host = ike_sa->get_other_host(ike_sa);
443
444 DBG2(DBG_TNC, "sending publish");
445 if (!publish(this, ike_sa_id, id, host, up))
446 {
447 DBG1(DBG_TNC, "publish with MAP server failed");
448 }
449
450 return TRUE;
451 }
452
453 METHOD(tnc_ifmap_listener_t, destroy, void,
454 private_tnc_ifmap_listener_t *this)
455 {
456 if (this->session_id)
457 {
458 DBG2(DBG_TNC, "sending endSession");
459 if (!endSession(this))
460 {
461 DBG1(DBG_TNC, "endSession with MAP server failed");
462 }
463 free(this->session_id);
464 free(this->ifmap_publisher_id);
465 }
466 if (this->svc_client)
467 {
468 axis2_svc_client_free(this->svc_client, this->env);
469 }
470 if (this->env)
471 {
472 axutil_env_free(this->env);
473 }
474 free(this);
475 }
476
477 /**
478 * See header
479 */
480 tnc_ifmap_listener_t *tnc_ifmap_listener_create()
481 {
482 private_tnc_ifmap_listener_t *this;
483 axis2_char_t *server, *client_home, *username, *password, *auth_type;
484 axis2_endpoint_ref_t* endpoint_ref = NULL;
485 axis2_options_t *options = NULL;
486
487 client_home = lib->settings->get_str(lib->settings,
488 "charon.plugins.tnc-ifmap.client_home",
489 AXIS2_GETENV("AXIS2C_HOME"));
490 server = lib->settings->get_str(lib->settings,
491 "charon.plugins.tnc-ifmap.server", IFMAP_SERVER);
492 auth_type = lib->settings->get_str(lib->settings,
493 "charon.plugins.tnc-ifmap.auth_type", "Basic");
494 username = lib->settings->get_str(lib->settings,
495 "charon.plugins.tnc-ifmap.username", NULL);
496 password = lib->settings->get_str(lib->settings,
497 "charon.plugins.tnc-ifmap.password", NULL);
498
499 if (!username || !password)
500 {
501 DBG1(DBG_TNC, "MAP client %s%s%s not defined",
502 (!username) ? "username" : "",
503 (!username && ! password) ? " and " : "",
504 (!password) ? "password" : "");
505 }
506
507 INIT(this,
508 .public = {
509 .listener = {
510 .ike_updown = _ike_updown,
511 },
512 .destroy = _destroy,
513 },
514 );
515
516 /* Create Axis2/C environment and options */
517 this->env = axutil_env_create_all(IFMAP_LOGFILE, AXIS2_LOG_LEVEL_TRACE);
518 options = axis2_options_create(this->env);
519
520 /* Define the IF-MAP server as the to endpoint reference */
521 endpoint_ref = axis2_endpoint_ref_create(this->env, server);
522 axis2_options_set_to(options, this->env, endpoint_ref);
523
524 /* Create the axis2 service client */
525 this->svc_client = axis2_svc_client_create(this->env, client_home);
526 if (!this->svc_client)
527 {
528 DBG1(DBG_TNC, "Error creating axis2 service client");
529 AXIS2_LOG_ERROR(this->env->log, AXIS2_LOG_SI,
530 "Stub invoke FAILED: Error code: %d :: %s",
531 this->env->error->error_number,
532 AXIS2_ERROR_GET_MESSAGE(this->env->error));
533 destroy(this);
534 return NULL;
535 }
536
537 axis2_svc_client_set_options(this->svc_client, this->env, options);
538 axis2_options_set_http_auth_info(options, this->env, username, password,
539 auth_type);
540 DBG1(DBG_TNC, "connecting as MAP client '%s' to MAP server at '%s'",
541 username, server);
542
543 DBG2(DBG_TNC, "sending newSession");
544 if (!newSession(this))
545 {
546 DBG1(DBG_TNC, "newSession with MAP server failed");
547 destroy(this);
548 return NULL;
549 }
550 DBG2(DBG_TNC, "sending purgePublisher");
551 if (!purgePublisher(this))
552 {
553 DBG1(DBG_TNC, "purgePublisher with MAP server failed");
554 destroy(this);
555 return NULL;
556 }
557
558 return &this->public;
559 }
560