b295ec201644475745f3a27827b2c3c594723842
[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 * process a ikesalist query request message
150 */
151 static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
152 {
153 iterator_t *iterator;
154 ike_sa_t *ike_sa;
155
156 /* <ikesalist> */
157 xmlTextWriterStartElement(writer, "ikesalist");
158
159 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
160 while (iterator->iterate(iterator, (void**)&ike_sa))
161 {
162 ike_sa_id_t *id;
163 host_t *local, *remote;
164 iterator_t *children;
165 child_sa_t *child_sa;
166
167 id = ike_sa->get_id(ike_sa);
168
169 xmlTextWriterStartElement(writer, "ikesa");
170 xmlTextWriterWriteFormatElement(writer, "id", "%d",
171 ike_sa->get_unique_id(ike_sa));
172 xmlTextWriterWriteFormatElement(writer, "status", "%N",
173 ike_sa_state_lower_names, ike_sa->get_state(ike_sa));
174 xmlTextWriterWriteElement(writer, "role",
175 id->is_initiator(id) ? "initiator" : "responder");
176 xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa));
177
178 /* <local> */
179 local = ike_sa->get_my_host(ike_sa);
180 xmlTextWriterStartElement(writer, "local");
181 xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
182 id->is_initiator(id) ? id->get_initiator_spi(id)
183 : id->get_responder_spi(id));
184 write_id(writer, "identification", ike_sa->get_my_id(ike_sa));
185 write_address(writer, "address", local);
186 xmlTextWriterWriteFormatElement(writer, "port", "%d",
187 local->get_port(local));
188 if (ike_sa->supports_extension(ike_sa, EXT_NATT))
189 {
190 write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE));
191 }
192 xmlTextWriterEndElement(writer);
193 /* </local> */
194
195 /* <remote> */
196 remote = ike_sa->get_other_host(ike_sa);
197 xmlTextWriterStartElement(writer, "remote");
198 xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
199 id->is_initiator(id) ? id->get_responder_spi(id)
200 : id->get_initiator_spi(id));
201 write_id(writer, "identification", ike_sa->get_other_id(ike_sa));
202 write_address(writer, "address", remote);
203 xmlTextWriterWriteFormatElement(writer, "port", "%d",
204 remote->get_port(remote));
205 if (ike_sa->supports_extension(ike_sa, EXT_NATT))
206 {
207 write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE));
208 }
209 xmlTextWriterEndElement(writer);
210 /* </remote> */
211
212 /* <childsalist> */
213 xmlTextWriterStartElement(writer, "childsalist");
214 children = ike_sa->create_child_sa_iterator(ike_sa);
215 while (children->iterate(children, (void**)&child_sa))
216 {
217 /* TODO: Children */
218 }
219 children->destroy(children);
220 /* </childsalist> */
221 xmlTextWriterEndElement(writer);
222
223 /* </ikesa> */
224 xmlTextWriterEndElement(writer);
225 }
226 iterator->destroy(iterator);
227
228 /* </ikesalist> */
229 xmlTextWriterEndElement(writer);
230 }
231
232 /**
233 * process a query request
234 */
235 static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
236 {
237 /* <query> */
238 xmlTextWriterStartElement(writer, "query");
239 while (xmlTextReaderRead(reader))
240 {
241 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
242 {
243 if (streq(xmlTextReaderConstName(reader), "ikesalist"))
244 {
245 request_query_ikesa(reader, writer);
246 break;
247 }
248 }
249 }
250 /* </query> */
251 xmlTextWriterEndElement(writer);
252 }
253
254 /**
255 * process a request message
256 */
257 static void request(xmlTextReaderPtr reader, char *id, int fd)
258 {
259 xmlTextWriterPtr writer;
260
261 writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
262 if (writer == NULL)
263 {
264 DBG1(DBG_CFG, "opening SMP XML writer failed");
265 return;
266 }
267
268 xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
269 /* <message xmlns="http://www.strongswan.org/smp/1.0"
270 id="id" type="response"> */
271 xmlTextWriterStartElement(writer, "message");
272 xmlTextWriterWriteAttribute(writer, "xmlns",
273 "http://www.strongswan.org/smp/1.0");
274 xmlTextWriterWriteAttribute(writer, "id", id);
275 xmlTextWriterWriteAttribute(writer, "type", "response");
276
277 while (xmlTextReaderRead(reader))
278 {
279 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
280 {
281 if (streq(xmlTextReaderConstName(reader), "query"))
282 {
283 request_query(reader, writer);
284 break;
285 }
286 }
287 }
288 /* </message> and close document */
289 xmlTextWriterEndDocument(writer);
290 xmlFreeTextWriter(writer);
291 }
292
293 /**
294 * read from a opened connection and process it
295 */
296 static job_requeue_t process(int *fdp)
297 {
298 int oldstate, fd = *fdp;
299 char buffer[4096];
300 size_t len;
301 xmlTextReaderPtr reader;
302 char *id = NULL, *type = NULL;
303
304 pthread_cleanup_push((void*)close, (void*)fd);
305 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
306 len = read(fd, buffer, sizeof(buffer));
307 pthread_setcancelstate(oldstate, NULL);
308 pthread_cleanup_pop(0);
309 if (len <= 0)
310 {
311 close(fd);
312 DBG2(DBG_CFG, "SMP XML connection closed");
313 return JOB_REQUEUE_NONE;
314 }
315 DBG1(DBG_CFG, "got XML request: %b", buffer, len);
316
317 reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0);
318 if (reader == NULL)
319 {
320 DBG1(DBG_CFG, "opening SMP XML reader failed");
321 return JOB_REQUEUE_FAIR;;
322 }
323
324 /* read message type and id */
325 while (xmlTextReaderRead(reader))
326 {
327 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT &&
328 streq(xmlTextReaderConstName(reader), "message"))
329 {
330 id = xmlTextReaderGetAttribute(reader, "id");
331 type = xmlTextReaderGetAttribute(reader, "type");
332 break;
333 }
334 }
335
336 /* process message */
337 if (id && type)
338 {
339 if (streq(type, "request"))
340 {
341 request(reader, id, fd);
342 }
343 else
344 {
345 /* response(reader, id) */
346 }
347 }
348 xmlFreeTextReader(reader);
349 return JOB_REQUEUE_FAIR;;
350 }
351
352 /**
353 * accept from XML socket and create jobs to process connections
354 */
355 static job_requeue_t dispatch(private_xml_interface_t *this)
356 {
357 struct sockaddr_un strokeaddr;
358 int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr);
359 callback_job_t *job;
360
361 /* wait for connections, but allow thread to terminate */
362 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
363 fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
364 pthread_setcancelstate(oldstate, NULL);
365
366 if (fd < 0)
367 {
368 DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno));
369 sleep(1);
370 return JOB_REQUEUE_FAIR;;
371 }
372
373 fdp = malloc_thing(int);
374 *fdp = fd;
375 job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job);
376 charon->processor->queue_job(charon->processor, (job_t*)job);
377
378 return JOB_REQUEUE_DIRECT;
379 }
380
381 struct sockaddr_un unix_addr = { AF_UNIX, "/var/run/charon.xml"};
382
383 /**
384 * Implementation of itnerface_t.destroy.
385 */
386 static void destroy(private_xml_interface_t *this)
387 {
388 this->job->cancel(this->job);
389 close(this->socket);
390 //unlink(unix_addr.sun_path);
391 free(this);
392 }
393
394 /*
395 * Described in header file
396 */
397 interface_t *interface_create()
398 {
399 private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
400 //mode_t old;
401 struct sockaddr_in tcp_addr;
402
403 this->public.interface.destroy = (void (*)(interface_t*))destroy;
404
405 /* set up unix socket */
406 this->socket = socket(AF_INET, SOCK_STREAM, 0);//socket(AF_UNIX, SOCK_STREAM, 0);
407 if (this->socket == -1)
408 {
409 DBG1(DBG_CFG, "could not create XML socket");
410 free(this);
411 return NULL;
412 }
413
414 memset(&tcp_addr, 0, sizeof(tcp_addr));
415 tcp_addr.sin_family = AF_INET;
416 tcp_addr.sin_addr.s_addr = INADDR_ANY;
417 tcp_addr.sin_port = htons(4502);
418 if (bind(this->socket, (struct sockaddr*)&tcp_addr, sizeof(tcp_addr)) < 0)
419 {
420 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
421 close(this->socket);
422 free(this);
423 return NULL;
424 }
425
426 /*
427 old = umask(~S_IRWXU);
428 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
429 {
430 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
431 close(this->socket);
432 free(this);
433 return NULL;
434 }
435 umask(old);*/
436
437 if (listen(this->socket, 5) < 0)
438 {
439 DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
440 close(this->socket);
441 free(this);
442 return NULL;
443 }
444
445 this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL);
446 charon->processor->queue_job(charon->processor, (job_t*)this->job);
447
448 return &this->public.interface;
449 }
450