getting rid of axis2.html configuration
[strongswan.git] / src / libcharon / plugins / tnc_ifmap / tnc_ifmap_soap.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_soap.h"
17
18 #include <debug.h>
19
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>
25
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/"
30
31 typedef struct private_tnc_ifmap_soap_t private_tnc_ifmap_soap_t;
32
33 /**
34 * Private data of an tnc_ifmap_soap_t object.
35 */
36 struct private_tnc_ifmap_soap_t {
37
38 /**
39 * Public tnc_ifmap_soap_t interface.
40 */
41 tnc_ifmap_soap_t public;
42
43 /**
44 * Axis2/C environment
45 */
46 axutil_env_t *env;
47
48 /**
49 * Axis2 service client
50 */
51 axis2_svc_client_t* svc_client;
52
53 /**
54 * SOAP Session ID
55 */
56 char *session_id;
57
58 /**
59 * IF-MAP Publisher ID
60 */
61 char *ifmap_publisher_id;
62
63 /**
64 * PEP and PDP device name
65 */
66 char *device_name;
67
68 };
69
70 /**
71 * Send request and receive result via SOAP
72 */
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)
76
77 {
78 axiom_node_t *parent, *node;
79 axiom_element_t *el;
80 axutil_qname_t *qname;
81 bool success = FALSE;
82
83 /* send request and receive result */
84 DBG2(DBG_TNC, "sending ifmap %s", request_qname);
85
86 parent = axis2_svc_client_send_receive(this->svc_client, this->env, request);
87 if (!parent)
88 {
89 DBG1(DBG_TNC, "no ifmap %s received from MAP server", receipt_qname);
90 return FALSE;
91 }
92
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)
96 {
97 el = (axiom_element_t *)axiom_node_get_data_element(node, this->env);
98
99 qname = axiom_element_get_qname(el, this->env, node);
100 success = streq(receipt_qname, axutil_qname_to_string(qname, this->env));
101 if (success)
102 {
103 DBG2(DBG_TNC, "received ifmap %s", receipt_qname);
104 if (result)
105 {
106 *result = parent;
107 }
108 else
109 {
110 /* no further processing requested */
111 axiom_node_free_tree(parent, this->env);
112 }
113 return TRUE;
114 }
115 /* TODO proper error handling */
116 DBG1(DBG_TNC, "%s", axiom_element_to_string(el, this->env, node));
117 }
118
119 /* free parent in the error case */
120 axiom_node_free_tree(parent, this->env);
121
122 return FALSE;
123 }
124
125 METHOD(tnc_ifmap_soap_t, newSession, bool,
126 private_tnc_ifmap_soap_t *this)
127 {
128 axiom_node_t *request, *result, *node;
129 axiom_element_t *el;
130 axiom_namespace_t *ns;
131 axis2_char_t *value;
132
133
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);
137
138 /* send newSession request and receive newSessionResult */
139 if (!send_receive(this, "newSession", request, "newSessionResult", &result))
140 {
141 return FALSE;
142 }
143
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);
147
148 /* get session-id */
149 value = axiom_element_get_attribute_value_by_name(el, this->env,
150 "session-id");
151 this->session_id = strdup(value);
152
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);
157
158 DBG1(DBG_TNC, "session-id: %s, ifmap-publisher-id: %s",
159 this->session_id, this->ifmap_publisher_id);
160
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);
166
167 /* free result */
168 axiom_node_free_tree(result, this->env);
169
170 return this->session_id && this->ifmap_publisher_id;
171 }
172
173 METHOD(tnc_ifmap_soap_t, purgePublisher, bool,
174 private_tnc_ifmap_soap_t *this)
175 {
176 axiom_node_t *request;
177 axiom_element_t *el;
178 axiom_namespace_t *ns;
179 axiom_attribute_t *attr;
180
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);
190
191 /* send purgePublisher request and receive purgePublisherReceived */
192 return send_receive(this, "purgePublisher", request,
193 "purgePublisherReceived", NULL);
194 }
195
196 /**
197 * Create an access-request based on device_name and ike_sa_id
198 */
199 static axiom_node_t* create_access_request(private_tnc_ifmap_soap_t *this,
200 u_int32_t id)
201 {
202 axiom_element_t *el;
203 axiom_node_t *node;
204 axiom_attribute_t *attr;
205 char buf[BUF_LEN];
206
207 el = axiom_element_create(this->env, NULL, "access-request", NULL, &node);
208
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);
212
213 return node;
214 }
215
216 /**
217 * Create an identity
218 */
219 static axiom_node_t* create_identity(private_tnc_ifmap_soap_t *this,
220 identification_t *id, bool is_user)
221 {
222 axiom_element_t *el;
223 axiom_node_t *node;
224 axiom_attribute_t *attr;
225 char buf[BUF_LEN], *id_type;
226
227 el = axiom_element_create(this->env, NULL, "identity", NULL, &node);
228
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);
232
233 switch (id->get_type(id))
234 {
235 case ID_FQDN:
236 id_type = is_user ? "username" : "dns-name";
237 break;
238 case ID_RFC822_ADDR:
239 id_type = "email-address";
240 break;
241 case ID_DER_ASN1_DN:
242 id_type = "distinguished-name";
243 break;
244 default:
245 id_type = "other";
246 }
247 attr = axiom_attribute_create(this->env, "type", id_type, NULL);
248 axiom_element_add_attribute(el, this->env, attr, node);
249
250 return node;
251 }
252
253 /**
254 * Create an ip-address
255 */
256 static axiom_node_t* create_ip_address(private_tnc_ifmap_soap_t *this,
257 host_t *host)
258 {
259 axiom_element_t *el;
260 axiom_node_t *node;
261 axiom_attribute_t *attr;
262 char buf[BUF_LEN];
263
264 el = axiom_element_create(this->env, NULL, "ip-address", NULL, &node);
265
266 if (host->get_family(host) == AF_INET6)
267 {
268 chunk_t address;
269 int len, written, i;
270 char *pos;
271 bool first = TRUE;
272
273 /* output IPv6 address in canonical IF-MAP 2.0 format */
274 address = host->get_address(host);
275 pos = buf;
276 len = sizeof(buf);
277
278 for (i = 0; i < address.len; i = i + 2)
279 {
280 written = snprintf(pos, len, "%s%x", first ? "" : ":",
281 256*address.ptr[i] + address.ptr[i+1]);
282 if (written < 0 || written > len)
283 {
284 break;
285 }
286 pos += written;
287 len -= written;
288 first = FALSE;
289 }
290 }
291 else
292 {
293 snprintf(buf, BUF_LEN, "%H", host);
294 }
295 attr = axiom_attribute_create(this->env, "value", buf, NULL);
296 axiom_element_add_attribute(el, this->env, attr, node);
297
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);
301
302 return node;
303 }
304
305 /**
306 * Create a device
307 */
308 static axiom_node_t* create_device(private_tnc_ifmap_soap_t *this)
309 {
310 axiom_element_t *el;
311 axiom_node_t *node, *node2, *node3;
312 axiom_text_t *text;
313
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);
318
319 return node;
320 }
321
322 /**
323 * Create metadata
324 */
325 static axiom_node_t* create_metadata(private_tnc_ifmap_soap_t *this,
326 char *metadata)
327 {
328 axiom_element_t *el;
329 axiom_node_t *node, *node2;
330 axiom_attribute_t *attr;
331 axiom_namespace_t *ns_meta;
332
333 el = axiom_element_create(this->env, NULL, "metadata", NULL, &node);
334 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
335
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",
339 NULL);
340 axiom_element_add_attribute(el, this->env, attr, node2);
341
342 return node;
343 }
344
345 /**
346 * Create delete filter
347 */
348 static axiom_node_t* create_delete_filter(private_tnc_ifmap_soap_t *this,
349 char *metadata)
350 {
351 axiom_element_t *el;
352 axiom_node_t *node;
353 axiom_attribute_t *attr;
354 char buf[BUF_LEN];
355
356 el = axiom_element_create(this->env, NULL, "delete", NULL, &node);
357
358 snprintf(buf, BUF_LEN, "meta:%s[@ifmap-publisher-id='%s']",
359 metadata, this->ifmap_publisher_id);
360 attr = axiom_attribute_create(this->env, "filter", buf, NULL);
361 axiom_element_add_attribute(el, this->env, attr, node);
362
363 return node;
364 }
365
366 METHOD(tnc_ifmap_soap_t, publish_ike_sa, bool,
367 private_tnc_ifmap_soap_t *this, u_int32_t ike_sa_id, identification_t *id,
368 bool is_user, host_t *host, bool up)
369 {
370 axiom_node_t *request, *node;
371 axiom_element_t *el;
372 axiom_namespace_t *ns, *ns_meta;
373 axiom_attribute_t *attr;
374
375 /* build publish request */
376 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
377 el = axiom_element_create(this->env, NULL, "publish", ns, &request);
378 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
379 axiom_element_declare_namespace(el, this->env, request, ns_meta);
380 attr = axiom_attribute_create(this->env, "session-id", this->session_id,
381 NULL);
382 axiom_element_add_attribute(el, this->env, attr, request);
383
384 /**
385 * update or delete authenticated-as metadata
386 */
387 if (up)
388 {
389 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
390 }
391 else
392 {
393 node = create_delete_filter(this, "authenticated-as");
394 }
395 axiom_node_add_child(request, this->env, node);
396
397 /* add access-request, identity and [if up] metadata */
398 axiom_node_add_child(node, this->env,
399 create_access_request(this, ike_sa_id));
400 axiom_node_add_child(node, this->env,
401 create_identity(this, id, is_user));
402 if (up)
403 {
404 axiom_node_add_child(node, this->env,
405 create_metadata(this, "authenticated-as"));
406 }
407
408 /**
409 * update or delete access-request-ip metadata
410 */
411 if (up)
412 {
413 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
414 }
415 else
416 {
417 node = create_delete_filter(this, "access-request-ip");
418 }
419 axiom_node_add_child(request, this->env, node);
420
421 /* add access-request, ip-address and [if up] metadata */
422 axiom_node_add_child(node, this->env,
423 create_access_request(this, ike_sa_id));
424 axiom_node_add_child(node, this->env,
425 create_ip_address(this, host));
426 if (up)
427 {
428 axiom_node_add_child(node, this->env,
429 create_metadata(this, "access-request-ip"));
430 }
431
432 /**
433 * update or delete authenticated-by metadata
434 */
435 if (up)
436 {
437 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
438 }
439 else
440 {
441 node = create_delete_filter(this, "authenticated-by");
442 }
443 axiom_node_add_child(request, this->env, node);
444
445 /* add access-request, device and [if up] metadata */
446 axiom_node_add_child(node, this->env,
447 create_access_request(this, ike_sa_id));
448 axiom_node_add_child(node, this->env,
449 create_device(this));
450 if (up)
451 {
452 axiom_node_add_child(node, this->env,
453 create_metadata(this, "authenticated-by"));
454 }
455
456 /* send publish request and receive publishReceived */
457 return send_receive(this, "publish", request, "publishReceived", NULL);
458 }
459
460 METHOD(tnc_ifmap_soap_t, publish_device_ip, bool,
461 private_tnc_ifmap_soap_t *this, host_t *host)
462 {
463 axiom_node_t *request, *node;
464 axiom_element_t *el;
465 axiom_namespace_t *ns, *ns_meta;
466 axiom_attribute_t *attr;
467
468 /* build publish request */
469 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
470 el = axiom_element_create(this->env, NULL, "publish", ns, &request);
471 ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta");
472 axiom_element_declare_namespace(el, this->env, request, ns_meta);
473 attr = axiom_attribute_create(this->env, "session-id", this->session_id,
474 NULL);
475 axiom_element_add_attribute(el, this->env, attr, request);
476 el = axiom_element_create(this->env, NULL, "update", NULL, &node);
477 axiom_node_add_child(request, this->env, node);
478
479 /* add device, ip-address and metadata */
480 axiom_node_add_child(node, this->env,
481 create_device(this));
482 axiom_node_add_child(node, this->env,
483 create_ip_address(this, host));
484 axiom_node_add_child(node, this->env,
485 create_metadata(this, "device-ip"));
486
487 /* send publish request and receive publishReceived */
488 return send_receive(this, "publish", request, "publishReceived", NULL);
489 }
490
491 METHOD(tnc_ifmap_soap_t, endSession, bool,
492 private_tnc_ifmap_soap_t *this)
493 {
494 axiom_node_t *request;
495 axiom_element_t *el;
496 axiom_namespace_t *ns;
497 axiom_attribute_t *attr;
498
499 /* build endSession request */
500 ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap");
501 el = axiom_element_create(this->env, NULL, "endSession", ns, &request);
502 attr = axiom_attribute_create(this->env, "session-id", this->session_id, NULL);
503 axiom_element_add_attribute(el, this->env, attr, request);
504
505 /* send endSession request and receive end SessionResult */
506 return send_receive(this, "endSession", request, "endSessionResult", NULL);
507 }
508
509 METHOD(tnc_ifmap_soap_t, destroy, void,
510 private_tnc_ifmap_soap_t *this)
511 {
512 if (this->session_id)
513 {
514 endSession(this);
515 free(this->session_id);
516 free(this->ifmap_publisher_id);
517 free(this->device_name);
518 }
519 if (this->svc_client)
520 {
521 axis2_svc_client_free(this->svc_client, this->env);
522 }
523 if (this->env)
524 {
525 axutil_env_free(this->env);
526 }
527 free(this);
528 }
529
530 static bool axis2c_init(private_tnc_ifmap_soap_t *this)
531 {
532 axis2_char_t *server, *client_home, *username, *password, *auth_type;
533 axis2_endpoint_ref_t* endpoint_ref = NULL;
534 axis2_options_t *options = NULL;
535 axis2_transport_in_desc_t *transport_in;
536 axis2_transport_out_desc_t *transport_out;
537 axis2_transport_sender_t *transport_sender;
538 axutil_property_t* property;
539
540 client_home = lib->settings->get_str(lib->settings,
541 "charon.plugins.tnc-ifmap.client_home",
542 AXIS2_GETENV("AXIS2C_HOME"));
543 server = lib->settings->get_str(lib->settings,
544 "charon.plugins.tnc-ifmap.server", IFMAP_SERVER);
545 auth_type = lib->settings->get_str(lib->settings,
546 "charon.plugins.tnc-ifmap.auth_type", "Basic");
547 username = lib->settings->get_str(lib->settings,
548 "charon.plugins.tnc-ifmap.username", NULL);
549 password = lib->settings->get_str(lib->settings,
550 "charon.plugins.tnc-ifmap.password", NULL);
551
552 if (!username || !password)
553 {
554 DBG1(DBG_TNC, "MAP client %s%s%s not defined",
555 (!username) ? "username" : "",
556 (!username && ! password) ? " and " : "",
557 (!password) ? "password" : "");
558 return FALSE;
559 }
560
561 /* Create Axis2/C environment and options */
562 this->env = axutil_env_create_all(IFMAP_LOGFILE, AXIS2_LOG_LEVEL_TRACE);
563 options = axis2_options_create(this->env);
564
565 /* Path to the MAP server certificate */
566 property =axutil_property_create_with_args(this->env,
567 0, 0, 0, "/home/andi/axis2c/irond.pem");
568
569 /* Define the MAP server as the to endpoint reference */
570 endpoint_ref = axis2_endpoint_ref_create(this->env, server);
571
572 /* Set up https transport */
573 axis2_options_set_http_auth_info(options, this->env, username, password,
574 auth_type);
575 transport_in = axis2_transport_in_desc_create(this->env,
576 AXIS2_TRANSPORT_ENUM_HTTPS);
577 transport_out = axis2_transport_out_desc_create(this->env,
578 AXIS2_TRANSPORT_ENUM_HTTPS);
579 transport_sender = axis2_http_transport_sender_create(this->env);
580 axis2_transport_out_desc_set_sender(transport_out, this->env,
581 transport_sender);
582 axis2_options_set_transport_in(options, this->env, transport_in);
583 axis2_options_set_transport_out(options, this->env, transport_out);
584 axis2_options_set_to(options, this->env, endpoint_ref);
585 axis2_options_set_property(options, this->env, AXIS2_SSL_SERVER_CERT, property);
586
587 /* Create the axis2 service client */
588 this->svc_client = axis2_svc_client_create(this->env, client_home);
589 if (!this->svc_client)
590 {
591 DBG1(DBG_TNC, "could not create axis2 service client");
592 AXIS2_LOG_ERROR(this->env->log, AXIS2_LOG_SI,
593 "Stub invoke FAILED: Error code: %d :: %s",
594 this->env->error->error_number,
595 AXIS2_ERROR_GET_MESSAGE(this->env->error));
596 destroy(this);
597 return FALSE;
598 }
599
600 axis2_svc_client_set_options(this->svc_client, this->env, options);
601 DBG1(DBG_TNC, "connecting as MAP client '%s' to MAP server at '%s'",
602 username, server);
603
604 return TRUE;
605 }
606
607 /**
608 * See header
609 */
610 tnc_ifmap_soap_t *tnc_ifmap_soap_create()
611 {
612 private_tnc_ifmap_soap_t *this;
613
614 INIT(this,
615 .public = {
616 .newSession = _newSession,
617 .purgePublisher = _purgePublisher,
618 .publish_ike_sa = _publish_ike_sa,
619 .publish_device_ip = _publish_device_ip,
620 .endSession = _endSession,
621 .destroy = _destroy,
622 },
623 );
624
625 if (!axis2c_init(this))
626 {
627 destroy(this);
628 return NULL;
629 }
630
631 return &this->public;
632 }
633