reduced debbugging level
[strongswan.git] / src / charon / control / interfaces / xml_interface.c
1 /**
2 * @file xml_interface.c
3 *
4 * @brief Implementation of xml_interface_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <stdlib.h>
24
25 #include "xml_interface.h"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <pthread.h>
34 #include <signal.h>
35 #include <libxml/xmlreader.h>
36 #include <libxml/xmlwriter.h>
37
38 #include <library.h>
39 #include <daemon.h>
40 #include <processing/jobs/callback_job.h>
41
42
43 typedef struct private_xml_interface_t private_xml_interface_t;
44
45 /**
46 * Private data of an xml_interface_t object.
47 */
48 struct private_xml_interface_t {
49
50 /**
51 * Public part of xml_t object.
52 */
53 xml_interface_t public;
54
55 /**
56 * XML unix socket fd
57 */
58 int socket;
59
60 /**
61 * job accepting stroke messages
62 */
63 callback_job_t *job;
64 };
65
66 ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING,
67 "created",
68 "connecting",
69 "established",
70 "rekeying",
71 "deleting",
72 );
73
74 /**
75 * write a bool into element
76 */
77 static void write_bool(xmlTextWriterPtr writer, char *element, bool val)
78 {
79 xmlTextWriterWriteElement(writer, element, val ? "true" : "false");
80 }
81
82 /**
83 * write a identification_t into element
84 */
85 static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id)
86 {
87 xmlTextWriterStartElement(writer, element);
88 switch (id->get_type(id))
89 {
90 {
91 char *type = "";
92 while (TRUE)
93 {
94 case ID_IPV4_ADDR:
95 type = "ipv4";
96 break;
97 case ID_IPV6_ADDR:
98 type = "ipv6";
99 break;
100 case ID_FQDN:
101 type = "fqdn";
102 break;
103 case ID_RFC822_ADDR:
104 type = "email";
105 break;
106 case ID_DER_ASN1_DN:
107 type = "asn1dn";
108 break;
109 case ID_DER_ASN1_GN:
110 type = "asn1gn";
111 break;
112 }
113 xmlTextWriterWriteAttribute(writer, "type", type);
114 xmlTextWriterWriteFormatString(writer, "%D", id);
115 break;
116 }
117 case ID_ANY:
118 xmlTextWriterWriteAttribute(writer, "type", "any");
119 break;
120 default:
121 /* TODO: base64 keyid */
122 xmlTextWriterWriteAttribute(writer, "type", "keyid");
123 break;
124 }
125 xmlTextWriterEndElement(writer);
126 }
127
128 /**
129 * write a host_t address into an element
130 */
131 static void write_address(xmlTextWriterPtr writer, char *element, host_t *host)
132 {
133 xmlTextWriterStartElement(writer, element);
134 xmlTextWriterWriteAttribute(writer, "type",
135 host->get_family(host) == AF_INET ? "ipv4" : "ipv6");
136 if (host->is_anyaddr(host))
137 { /* do not use %any for XML */
138 xmlTextWriterWriteFormatString(writer, "%s",
139 host->get_family(host) == AF_INET ? "0.0.0.0" : "::");
140 }
141 else
142 {
143 xmlTextWriterWriteFormatString(writer, "%H", host);
144 }
145 xmlTextWriterEndElement(writer);
146 }
147
148 /**
149 * write a childEnd
150 */
151 static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local)
152 {
153 iterator_t *iterator;
154 linked_list_t *list;
155 traffic_selector_t *ts;
156 xmlTextWriterWriteFormatElement(writer, "spi", "%lx",
157 child->get_spi(child, local));
158 xmlTextWriterStartElement(writer, "networks");
159 list = child->get_traffic_selectors(child, local);
160 iterator = list->create_iterator(list, TRUE);
161 while (iterator->iterate(iterator, (void**)&ts))
162 {
163 xmlTextWriterStartElement(writer, "network");
164 xmlTextWriterWriteAttribute(writer, "type",
165 ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? "ipv4" : "ipv6");
166 xmlTextWriterWriteFormatString(writer, "%R", ts);
167 xmlTextWriterEndElement(writer);
168 }
169 iterator->destroy(iterator);
170 xmlTextWriterEndElement(writer);
171 }
172
173 /**
174 * write a child_sa_t
175 */
176 static void write_child(xmlTextWriterPtr writer, child_sa_t *child)
177 {
178 mode_t mode;
179 encryption_algorithm_t encr;
180 integrity_algorithm_t int_algo;
181 size_t encr_len, int_len;
182 u_int32_t rekey, use_in, use_out, use_fwd;
183 child_cfg_t *config;
184
185 config = child->get_config(child);
186 child->get_stats(child, &mode, &encr, &encr_len, &int_algo, &int_len,
187 &rekey, &use_in, &use_out, &use_fwd);
188
189 xmlTextWriterStartElement(writer, "childsa");
190 xmlTextWriterWriteFormatElement(writer, "reqid", "%d", child->get_reqid(child));
191 xmlTextWriterWriteFormatElement(writer, "childconfig", "%s",
192 config->get_name(config));
193 xmlTextWriterStartElement(writer, "local");
194 write_childend(writer, child, TRUE);
195 xmlTextWriterEndElement(writer);
196 xmlTextWriterStartElement(writer, "remote");
197 write_childend(writer, child, FALSE);
198 xmlTextWriterEndElement(writer);
199 xmlTextWriterEndElement(writer);
200 }
201
202 /**
203 * process a ikesalist query request message
204 */
205 static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
206 {
207 iterator_t *iterator;
208 ike_sa_t *ike_sa;
209
210 /* <ikesalist> */
211 xmlTextWriterStartElement(writer, "ikesalist");
212
213 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
214 while (iterator->iterate(iterator, (void**)&ike_sa))
215 {
216 ike_sa_id_t *id;
217 host_t *local, *remote;
218 iterator_t *children;
219 child_sa_t *child_sa;
220
221 id = ike_sa->get_id(ike_sa);
222
223 xmlTextWriterStartElement(writer, "ikesa");
224 xmlTextWriterWriteFormatElement(writer, "id", "%d",
225 ike_sa->get_unique_id(ike_sa));
226 xmlTextWriterWriteFormatElement(writer, "status", "%N",
227 ike_sa_state_lower_names, ike_sa->get_state(ike_sa));
228 xmlTextWriterWriteElement(writer, "role",
229 id->is_initiator(id) ? "initiator" : "responder");
230 xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa));
231
232 /* <local> */
233 local = ike_sa->get_my_host(ike_sa);
234 xmlTextWriterStartElement(writer, "local");
235 xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
236 id->is_initiator(id) ? id->get_initiator_spi(id)
237 : id->get_responder_spi(id));
238 write_id(writer, "identification", ike_sa->get_my_id(ike_sa));
239 write_address(writer, "address", local);
240 xmlTextWriterWriteFormatElement(writer, "port", "%d",
241 local->get_port(local));
242 if (ike_sa->supports_extension(ike_sa, EXT_NATT))
243 {
244 write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE));
245 }
246 xmlTextWriterEndElement(writer);
247 /* </local> */
248
249 /* <remote> */
250 remote = ike_sa->get_other_host(ike_sa);
251 xmlTextWriterStartElement(writer, "remote");
252 xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
253 id->is_initiator(id) ? id->get_responder_spi(id)
254 : id->get_initiator_spi(id));
255 write_id(writer, "identification", ike_sa->get_other_id(ike_sa));
256 write_address(writer, "address", remote);
257 xmlTextWriterWriteFormatElement(writer, "port", "%d",
258 remote->get_port(remote));
259 if (ike_sa->supports_extension(ike_sa, EXT_NATT))
260 {
261 write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE));
262 }
263 xmlTextWriterEndElement(writer);
264 /* </remote> */
265
266 /* <childsalist> */
267 xmlTextWriterStartElement(writer, "childsalist");
268 children = ike_sa->create_child_sa_iterator(ike_sa);
269 while (children->iterate(children, (void**)&child_sa))
270 {
271 write_child(writer, child_sa);
272 }
273 children->destroy(children);
274 /* </childsalist> */
275 xmlTextWriterEndElement(writer);
276
277 /* </ikesa> */
278 xmlTextWriterEndElement(writer);
279 }
280 iterator->destroy(iterator);
281
282 /* </ikesalist> */
283 xmlTextWriterEndElement(writer);
284 }
285
286 /**
287 * process a query request
288 */
289 static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
290 {
291 /* <query> */
292 xmlTextWriterStartElement(writer, "query");
293 while (xmlTextReaderRead(reader))
294 {
295 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
296 {
297 if (streq(xmlTextReaderConstName(reader), "ikesalist"))
298 {
299 request_query_ikesa(reader, writer);
300 break;
301 }
302 }
303 }
304 /* </query> */
305 xmlTextWriterEndElement(writer);
306 }
307
308 /**
309 * process a request message
310 */
311 static void request(xmlTextReaderPtr reader, char *id, int fd)
312 {
313 xmlTextWriterPtr writer;
314
315 writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
316 if (writer == NULL)
317 {
318 DBG1(DBG_CFG, "opening SMP XML writer failed");
319 return;
320 }
321
322 xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
323 /* <message xmlns="http://www.strongswan.org/smp/1.0"
324 id="id" type="response"> */
325 xmlTextWriterStartElement(writer, "message");
326 xmlTextWriterWriteAttribute(writer, "xmlns",
327 "http://www.strongswan.org/smp/1.0");
328 xmlTextWriterWriteAttribute(writer, "id", id);
329 xmlTextWriterWriteAttribute(writer, "type", "response");
330
331 while (xmlTextReaderRead(reader))
332 {
333 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
334 {
335 if (streq(xmlTextReaderConstName(reader), "query"))
336 {
337 request_query(reader, writer);
338 break;
339 }
340 }
341 }
342 /* </message> and close document */
343 xmlTextWriterEndDocument(writer);
344 xmlFreeTextWriter(writer);
345 }
346
347 /**
348 * cleanup helper function for open file descriptors
349 */
350 static void closefdp(int *fd)
351 {
352 close(*fd);
353 }
354
355 /**
356 * read from a opened connection and process it
357 */
358 static job_requeue_t process(int *fdp)
359 {
360 int oldstate, fd = *fdp;
361 char buffer[4096];
362 size_t len;
363 xmlTextReaderPtr reader;
364 char *id = NULL, *type = NULL;
365
366 pthread_cleanup_push((void*)closefdp, (void*)&fd);
367 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
368 len = read(fd, buffer, sizeof(buffer));
369 pthread_setcancelstate(oldstate, NULL);
370 pthread_cleanup_pop(0);
371 if (len <= 0)
372 {
373 close(fd);
374 DBG2(DBG_CFG, "SMP XML connection closed");
375 return JOB_REQUEUE_NONE;
376 }
377 DBG3(DBG_CFG, "got XML request: %b", buffer, len);
378
379 reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0);
380 if (reader == NULL)
381 {
382 DBG1(DBG_CFG, "opening SMP XML reader failed");
383 return JOB_REQUEUE_FAIR;;
384 }
385
386 /* read message type and id */
387 while (xmlTextReaderRead(reader))
388 {
389 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT &&
390 streq(xmlTextReaderConstName(reader), "message"))
391 {
392 id = xmlTextReaderGetAttribute(reader, "id");
393 type = xmlTextReaderGetAttribute(reader, "type");
394 break;
395 }
396 }
397
398 /* process message */
399 if (id && type)
400 {
401 if (streq(type, "request"))
402 {
403 request(reader, id, fd);
404 }
405 else
406 {
407 /* response(reader, id) */
408 }
409 }
410 xmlFreeTextReader(reader);
411 return JOB_REQUEUE_FAIR;;
412 }
413
414 /**
415 * accept from XML socket and create jobs to process connections
416 */
417 static job_requeue_t dispatch(private_xml_interface_t *this)
418 {
419 struct sockaddr_un strokeaddr;
420 int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr);
421 callback_job_t *job;
422
423 /* wait for connections, but allow thread to terminate */
424 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
425 fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
426 pthread_setcancelstate(oldstate, NULL);
427
428 if (fd < 0)
429 {
430 DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno));
431 sleep(1);
432 return JOB_REQUEUE_FAIR;;
433 }
434
435 fdp = malloc_thing(int);
436 *fdp = fd;
437 job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job);
438 charon->processor->queue_job(charon->processor, (job_t*)job);
439
440 return JOB_REQUEUE_DIRECT;
441 }
442
443 /** XML unix socket */
444 struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"};
445
446 /**
447 * Implementation of itnerface_t.destroy.
448 */
449 static void destroy(private_xml_interface_t *this)
450 {
451 this->job->cancel(this->job);
452 close(this->socket);
453 unlink(unix_addr.sun_path);
454 free(this);
455 }
456
457 /*
458 * Described in header file
459 */
460 interface_t *interface_create()
461 {
462 private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
463 mode_t old;
464
465 this->public.interface.destroy = (void (*)(interface_t*))destroy;
466
467 /* set up unix socket */
468 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
469 if (this->socket == -1)
470 {
471 DBG1(DBG_CFG, "could not create XML socket");
472 free(this);
473 return NULL;
474 }
475
476 old = umask(~(S_IRWXU | S_IRWXG));
477 if (bind(this->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0)
478 {
479 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
480 close(this->socket);
481 free(this);
482 return NULL;
483 }
484 umask(old);
485 if (chown(unix_addr.sun_path, IPSEC_UID, IPSEC_GID) != 0)
486 {
487 DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno));
488 }
489
490 if (listen(this->socket, 5) < 0)
491 {
492 DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
493 close(this->socket);
494 free(this);
495 return NULL;
496 }
497
498 this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL);
499 charon->processor->queue_job(charon->processor, (job_t*)this->job);
500
501 return &this->public.interface;
502 }
503