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