testing: Accept LANG and LC_* env variables via SSH on guests
[strongswan.git] / src / libcharon / plugins / smp / smp.c
1 /*
2 * Copyright (C) 2007 Martin Willi
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 <stdlib.h>
17
18 #include "smp.h"
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <signal.h>
27 #include <inttypes.h>
28 #include <libxml/xmlreader.h>
29 #include <libxml/xmlwriter.h>
30
31 #include <library.h>
32 #include <daemon.h>
33 #include <threading/thread.h>
34 #include <processing/jobs/callback_job.h>
35
36
37 typedef struct private_smp_t private_smp_t;
38
39 /**
40 * Private data of an smp_t object.
41 */
42 struct private_smp_t {
43
44 /**
45 * Public part of smp_t object.
46 */
47 smp_t public;
48
49 /**
50 * XML unix socket fd
51 */
52 int socket;
53 };
54
55 ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING,
56 "created",
57 "connecting",
58 "established",
59 "passive",
60 "rekeying",
61 "rekeyed",
62 "deleting",
63 );
64
65 /**
66 * write a bool into element
67 */
68 static void write_bool(xmlTextWriterPtr writer, char *element, bool val)
69 {
70 xmlTextWriterWriteElement(writer, element, val ? "true" : "false");
71 }
72
73 /**
74 * write a identification_t into element
75 */
76 static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id)
77 {
78 xmlTextWriterStartElement(writer, element);
79 switch (id->get_type(id))
80 {
81 {
82 char *type;
83
84 while (TRUE)
85 {
86 case ID_ANY:
87 type = "any";
88 break;
89 case ID_IPV4_ADDR:
90 type = "ipv4";
91 break;
92 case ID_IPV6_ADDR:
93 type = "ipv6";
94 break;
95 case ID_FQDN:
96 type = "fqdn";
97 break;
98 case ID_RFC822_ADDR:
99 type = "email";
100 break;
101 case ID_DER_ASN1_DN:
102 type = "asn1dn";
103 break;
104 case ID_DER_ASN1_GN:
105 type = "asn1gn";
106 break;
107 }
108 xmlTextWriterWriteAttribute(writer, "type", type);
109 xmlTextWriterWriteFormatString(writer, "%Y", id);
110 break;
111 }
112 default:
113 /* TODO: base64 keyid */
114 xmlTextWriterWriteAttribute(writer, "type", "keyid");
115 break;
116 }
117 xmlTextWriterEndElement(writer);
118 }
119
120 /**
121 * write a host_t address into an element
122 */
123 static void write_address(xmlTextWriterPtr writer, char *element, host_t *host)
124 {
125 xmlTextWriterStartElement(writer, element);
126 xmlTextWriterWriteAttribute(writer, "type",
127 host->get_family(host) == AF_INET ? "ipv4" : "ipv6");
128 if (host->is_anyaddr(host))
129 { /* do not use %any for XML */
130 xmlTextWriterWriteFormatString(writer, "%s",
131 host->get_family(host) == AF_INET ? "0.0.0.0" : "::");
132 }
133 else
134 {
135 xmlTextWriterWriteFormatString(writer, "%H", host);
136 }
137 xmlTextWriterEndElement(writer);
138 }
139
140 /**
141 * write networks element
142 */
143 static void write_networks(xmlTextWriterPtr writer, char *element,
144 linked_list_t *list)
145 {
146 enumerator_t *enumerator;
147 traffic_selector_t *ts;
148
149 xmlTextWriterStartElement(writer, element);
150 enumerator = list->create_enumerator(list);
151 while (enumerator->enumerate(enumerator, (void**)&ts))
152 {
153 xmlTextWriterStartElement(writer, "network");
154 xmlTextWriterWriteAttribute(writer, "type",
155 ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? "ipv4" : "ipv6");
156 xmlTextWriterWriteFormatString(writer, "%R", ts);
157 xmlTextWriterEndElement(writer);
158 }
159 enumerator->destroy(enumerator);
160 xmlTextWriterEndElement(writer);
161 }
162
163 /**
164 * write a childEnd
165 */
166 static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local)
167 {
168 linked_list_t *list;
169
170 xmlTextWriterWriteFormatElement(writer, "spi", "%x",
171 htonl(child->get_spi(child, local)));
172 list = linked_list_create_from_enumerator(
173 child->create_ts_enumerator(child, local));
174 write_networks(writer, "networks", list);
175 list->destroy(list);
176 }
177
178 /**
179 * write a child_sa_t
180 */
181 static void write_child(xmlTextWriterPtr writer, child_sa_t *child)
182 {
183 child_cfg_t *config;
184
185 config = child->get_config(child);
186
187 xmlTextWriterStartElement(writer, "childsa");
188 xmlTextWriterWriteFormatElement(writer, "reqid", "%d",
189 child->get_reqid(child));
190 xmlTextWriterWriteFormatElement(writer, "childconfig", "%s",
191 config->get_name(config));
192 xmlTextWriterStartElement(writer, "local");
193 write_childend(writer, child, TRUE);
194 xmlTextWriterEndElement(writer);
195 xmlTextWriterStartElement(writer, "remote");
196 write_childend(writer, child, FALSE);
197 xmlTextWriterEndElement(writer);
198 xmlTextWriterEndElement(writer);
199 }
200
201 /**
202 * process a ikesalist query request message
203 */
204 static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
205 {
206 enumerator_t *enumerator;
207 ike_sa_t *ike_sa;
208
209 /* <ikesalist> */
210 xmlTextWriterStartElement(writer, "ikesalist");
211
212 enumerator = charon->controller->create_ike_sa_enumerator(
213 charon->controller, TRUE);
214 while (enumerator->enumerate(enumerator, &ike_sa))
215 {
216 ike_sa_id_t *id;
217 host_t *local, *remote;
218 enumerator_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", "%.16"PRIx64,
236 be64toh(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", "%.16"PRIx64,
253 be64toh(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_enumerator(ike_sa);
269 while (children->enumerate(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 enumerator->destroy(enumerator);
281
282 /* </ikesalist> */
283 xmlTextWriterEndElement(writer);
284 }
285
286 /**
287 * process a configlist query request message
288 */
289 static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
290 {
291 enumerator_t *enumerator;
292 peer_cfg_t *peer_cfg;
293
294 /* <configlist> */
295 xmlTextWriterStartElement(writer, "configlist");
296
297 enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends,
298 NULL, NULL, NULL, NULL, IKE_ANY);
299 while (enumerator->enumerate(enumerator, &peer_cfg))
300 {
301 enumerator_t *children;
302 child_cfg_t *child_cfg;
303 ike_cfg_t *ike_cfg;
304 linked_list_t *list;
305
306 /* <peerconfig> */
307 xmlTextWriterStartElement(writer, "peerconfig");
308 xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg));
309
310 /* TODO: write auth_cfgs */
311
312 /* <ikeconfig> */
313 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
314 xmlTextWriterStartElement(writer, "ikeconfig");
315 xmlTextWriterWriteElement(writer, "local",
316 ike_cfg->get_my_addr(ike_cfg));
317 xmlTextWriterWriteElement(writer, "remote",
318 ike_cfg->get_other_addr(ike_cfg));
319 xmlTextWriterEndElement(writer);
320 /* </ikeconfig> */
321
322 /* <childconfiglist> */
323 xmlTextWriterStartElement(writer, "childconfiglist");
324 children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
325 while (children->enumerate(children, &child_cfg))
326 {
327 /* <childconfig> */
328 xmlTextWriterStartElement(writer, "childconfig");
329 xmlTextWriterWriteElement(writer, "name",
330 child_cfg->get_name(child_cfg));
331 list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
332 NULL, FALSE);
333 write_networks(writer, "local", list);
334 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
335 list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
336 NULL, FALSE);
337 write_networks(writer, "remote", list);
338 list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
339 xmlTextWriterEndElement(writer);
340 /* </childconfig> */
341 }
342 children->destroy(children);
343 /* </childconfiglist> */
344 xmlTextWriterEndElement(writer);
345 /* </peerconfig> */
346 xmlTextWriterEndElement(writer);
347 }
348 enumerator->destroy(enumerator);
349 /* </configlist> */
350 xmlTextWriterEndElement(writer);
351 }
352
353 /**
354 * callback which logs to a XML writer
355 */
356 static bool xml_callback(xmlTextWriterPtr writer, debug_t group, level_t level,
357 ike_sa_t* ike_sa, char* message)
358 {
359 if (level <= 1)
360 {
361 /* <item> */
362 xmlTextWriterStartElement(writer, "item");
363 xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level);
364 xmlTextWriterWriteFormatAttribute(writer, "source", "%N", debug_names, group);
365 xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", thread_current_id());
366 xmlTextWriterWriteString(writer, message);
367 xmlTextWriterEndElement(writer);
368 /* </item> */
369 }
370 return TRUE;
371 }
372
373 /**
374 * process a *terminate control request message
375 */
376 static void request_control_terminate(xmlTextReaderPtr reader,
377 xmlTextWriterPtr writer, bool ike)
378 {
379 if (xmlTextReaderRead(reader) &&
380 xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT)
381 {
382 const char *str;
383 uint32_t id;
384 status_t status;
385
386 str = xmlTextReaderConstValue(reader);
387 if (str == NULL)
388 {
389 DBG1(DBG_CFG, "error parsing XML id string");
390 return;
391 }
392 id = atoi(str);
393 if (!id)
394 {
395 enumerator_t *enumerator;
396 ike_sa_t *ike_sa;
397
398 enumerator = charon->controller->create_ike_sa_enumerator(
399 charon->controller, TRUE);
400 while (enumerator->enumerate(enumerator, &ike_sa))
401 {
402 if (streq(str, ike_sa->get_name(ike_sa)))
403 {
404 ike = TRUE;
405 id = ike_sa->get_unique_id(ike_sa);
406 break;
407 }
408 }
409 enumerator->destroy(enumerator);
410 }
411 if (!id)
412 {
413 DBG1(DBG_CFG, "error parsing XML id string");
414 return;
415 }
416
417 DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id);
418
419 /* <log> */
420 xmlTextWriterStartElement(writer, "log");
421 if (ike)
422 {
423 status = charon->controller->terminate_ike(
424 charon->controller, id, FALSE,
425 (controller_cb_t)xml_callback, writer, 0);
426 }
427 else
428 {
429 status = charon->controller->terminate_child(
430 charon->controller, id,
431 (controller_cb_t)xml_callback, writer, 0);
432 }
433 /* </log> */
434 xmlTextWriterEndElement(writer);
435 xmlTextWriterWriteFormatElement(writer, "status", "%d", status);
436 }
437 }
438
439 /**
440 * process a *initiate control request message
441 */
442 static void request_control_initiate(xmlTextReaderPtr reader,
443 xmlTextWriterPtr writer, bool ike)
444 {
445 if (xmlTextReaderRead(reader) &&
446 xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT)
447 {
448 const char *str;
449 status_t status = FAILED;
450 peer_cfg_t *peer;
451 child_cfg_t *child = NULL;
452 enumerator_t *enumerator;
453
454 str = xmlTextReaderConstValue(reader);
455 if (str == NULL)
456 {
457 DBG1(DBG_CFG, "error parsing XML config name string");
458 return;
459 }
460 DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str);
461
462 /* <log> */
463 xmlTextWriterStartElement(writer, "log");
464 peer = charon->backends->get_peer_cfg_by_name(charon->backends,
465 (char*)str);
466 if (peer)
467 {
468 enumerator = peer->create_child_cfg_enumerator(peer);
469 if (ike)
470 {
471 if (enumerator->enumerate(enumerator, &child))
472 {
473 child->get_ref(child);
474 }
475 else
476 {
477 child = NULL;
478 }
479 }
480 else
481 {
482 while (enumerator->enumerate(enumerator, &child))
483 {
484 if (streq(child->get_name(child), str))
485 {
486 child->get_ref(child);
487 break;
488 }
489 child = NULL;
490 }
491 }
492 enumerator->destroy(enumerator);
493 if (child)
494 {
495 status = charon->controller->initiate(charon->controller,
496 peer, child, (controller_cb_t)xml_callback,
497 writer, 0, FALSE);
498 }
499 else
500 {
501 peer->destroy(peer);
502 }
503 }
504 /* </log> */
505 xmlTextWriterEndElement(writer);
506 xmlTextWriterWriteFormatElement(writer, "status", "%d", status);
507 }
508 }
509
510 /**
511 * process a query request
512 */
513 static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
514 {
515 /* <query> */
516 xmlTextWriterStartElement(writer, "query");
517 while (xmlTextReaderRead(reader))
518 {
519 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
520 {
521 if (streq(xmlTextReaderConstName(reader), "ikesalist"))
522 {
523 request_query_ikesa(reader, writer);
524 break;
525 }
526 if (streq(xmlTextReaderConstName(reader), "configlist"))
527 {
528 request_query_config(reader, writer);
529 break;
530 }
531 }
532 }
533 /* </query> */
534 xmlTextWriterEndElement(writer);
535 }
536
537 /**
538 * process a control request
539 */
540 static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
541 {
542 /* <control> */
543 xmlTextWriterStartElement(writer, "control");
544 while (xmlTextReaderRead(reader))
545 {
546 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
547 {
548 if (streq(xmlTextReaderConstName(reader), "ikesaterminate"))
549 {
550 request_control_terminate(reader, writer, TRUE);
551 break;
552 }
553 if (streq(xmlTextReaderConstName(reader), "childsaterminate"))
554 {
555 request_control_terminate(reader, writer, FALSE);
556 break;
557 }
558 if (streq(xmlTextReaderConstName(reader), "ikesainitiate"))
559 {
560 request_control_initiate(reader, writer, TRUE);
561 break;
562 }
563 if (streq(xmlTextReaderConstName(reader), "childsainitiate"))
564 {
565 request_control_initiate(reader, writer, FALSE);
566 break;
567 }
568 }
569 }
570 /* </control> */
571 xmlTextWriterEndElement(writer);
572 }
573
574 /**
575 * process a request message
576 */
577 static void request(xmlTextReaderPtr reader, char *id, int fd)
578 {
579 xmlTextWriterPtr writer;
580
581 writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
582 if (writer == NULL)
583 {
584 DBG1(DBG_CFG, "opening SMP XML writer failed");
585 return;
586 }
587
588 xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
589 /* <message xmlns="http://www.strongswan.org/smp/1.0"
590 id="id" type="response"> */
591 xmlTextWriterStartElement(writer, "message");
592 xmlTextWriterWriteAttribute(writer, "xmlns",
593 "http://www.strongswan.org/smp/1.0");
594 xmlTextWriterWriteAttribute(writer, "id", id);
595 xmlTextWriterWriteAttribute(writer, "type", "response");
596
597 while (xmlTextReaderRead(reader))
598 {
599 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
600 {
601 if (streq(xmlTextReaderConstName(reader), "query"))
602 {
603 request_query(reader, writer);
604 break;
605 }
606 if (streq(xmlTextReaderConstName(reader), "control"))
607 {
608 request_control(reader, writer);
609 break;
610 }
611 }
612 }
613 /* </message> and close document */
614 xmlTextWriterEndDocument(writer);
615 xmlFreeTextWriter(writer);
616 }
617
618 /**
619 * cleanup helper function for open file descriptors
620 */
621 static void closefdp(int *fd)
622 {
623 close(*fd);
624 }
625
626 /**
627 * read from a opened connection and process it
628 */
629 static job_requeue_t process(int *fdp)
630 {
631 int fd = *fdp;
632 bool oldstate;
633 char buffer[4096];
634 ssize_t len;
635 xmlTextReaderPtr reader;
636 char *id = NULL, *type = NULL;
637
638 thread_cleanup_push((thread_cleanup_t)closefdp, (void*)&fd);
639 oldstate = thread_cancelability(TRUE);
640 len = read(fd, buffer, sizeof(buffer));
641 thread_cancelability(oldstate);
642 thread_cleanup_pop(FALSE);
643 if (len <= 0)
644 {
645 close(fd);
646 DBG2(DBG_CFG, "SMP XML connection closed");
647 return JOB_REQUEUE_NONE;
648 }
649 DBG3(DBG_CFG, "got XML request: %b", buffer, (u_int)len);
650
651 reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0);
652 if (reader == NULL)
653 {
654 DBG1(DBG_CFG, "opening SMP XML reader failed");
655 return JOB_REQUEUE_FAIR;;
656 }
657
658 /* read message type and id */
659 while (xmlTextReaderRead(reader))
660 {
661 if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT &&
662 streq(xmlTextReaderConstName(reader), "message"))
663 {
664 id = xmlTextReaderGetAttribute(reader, "id");
665 type = xmlTextReaderGetAttribute(reader, "type");
666 break;
667 }
668 }
669
670 /* process message */
671 if (id && type)
672 {
673 if (streq(type, "request"))
674 {
675 request(reader, id, fd);
676 }
677 else
678 {
679 /* response(reader, id) */
680 }
681 }
682 xmlFreeTextReader(reader);
683 return JOB_REQUEUE_FAIR;;
684 }
685
686 /**
687 * accept from XML socket and create jobs to process connections
688 */
689 static job_requeue_t dispatch(private_smp_t *this)
690 {
691 struct sockaddr_un strokeaddr;
692 int fd, *fdp, strokeaddrlen = sizeof(strokeaddr);
693 callback_job_t *job;
694 bool oldstate;
695
696 /* wait for connections, but allow thread to terminate */
697 oldstate = thread_cancelability(TRUE);
698 fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
699 thread_cancelability(oldstate);
700
701 if (fd < 0)
702 {
703 DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno));
704 sleep(1);
705 return JOB_REQUEUE_FAIR;;
706 }
707
708 fdp = malloc_thing(int);
709 *fdp = fd;
710 job = callback_job_create((callback_job_cb_t)process, fdp, free,
711 (callback_job_cancel_t)return_false);
712 lib->processor->queue_job(lib->processor, (job_t*)job);
713
714 return JOB_REQUEUE_DIRECT;
715 }
716
717 METHOD(plugin_t, get_name, char*,
718 private_smp_t *this)
719 {
720 return "smp";
721 }
722
723 METHOD(plugin_t, get_features, int,
724 private_smp_t *this, plugin_feature_t *features[])
725 {
726 static plugin_feature_t f[] = {
727 PLUGIN_NOOP,
728 PLUGIN_PROVIDE(CUSTOM, "smp"),
729 };
730 *features = f;
731 return countof(f);
732 }
733
734 METHOD(plugin_t, destroy, void,
735 private_smp_t *this)
736 {
737 close(this->socket);
738 free(this);
739 }
740
741 /*
742 * Described in header file
743 */
744 plugin_t *smp_plugin_create()
745 {
746 struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"};
747 private_smp_t *this;
748 mode_t old;
749
750 if (!lib->caps->check(lib->caps, CAP_CHOWN))
751 { /* required to chown(2) control socket */
752 DBG1(DBG_CFG, "smp plugin requires CAP_CHOWN capability");
753 return NULL;
754 }
755
756 INIT(this,
757 .public = {
758 .plugin = {
759 .get_name = _get_name,
760 .get_features = _get_features,
761 .destroy = _destroy,
762 },
763 },
764 );
765
766 /* set up unix socket */
767 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
768 if (this->socket == -1)
769 {
770 DBG1(DBG_CFG, "could not create XML socket");
771 free(this);
772 return NULL;
773 }
774
775 unlink(unix_addr.sun_path);
776 old = umask(S_IRWXO);
777 if (bind(this->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0)
778 {
779 DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
780 close(this->socket);
781 free(this);
782 return NULL;
783 }
784 umask(old);
785 if (chown(unix_addr.sun_path, lib->caps->get_uid(lib->caps),
786 lib->caps->get_gid(lib->caps)) != 0)
787 {
788 DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno));
789 }
790
791 if (listen(this->socket, 5) < 0)
792 {
793 DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
794 close(this->socket);
795 free(this);
796 return NULL;
797 }
798
799 lib->processor->queue_job(lib->processor,
800 (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this,
801 NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
802
803 return &this->public.plugin;
804 }