]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/charon/control/stroke_interface.c
restructured file layout
[people/ms/strongswan.git] / src / charon / control / stroke_interface.c
1 /**
2 * @file stroke_interface.c
3 *
4 * @brief Implementation of stroke_interface_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006-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 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <sys/fcntl.h>
29 #include <unistd.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <pthread.h>
33 #include <signal.h>
34
35 #include "stroke_interface.h"
36
37 #include <library.h>
38 #include <stroke.h>
39 #include <daemon.h>
40 #include <crypto/x509.h>
41 #include <crypto/ca.h>
42 #include <crypto/crl.h>
43 #include <processing/jobs/initiate_job.h>
44 #include <processing/jobs/route_job.h>
45 #include <utils/leak_detective.h>
46
47 #define IKE_PORT 500
48 #define PATH_BUF 256
49 #define STROKE_THREADS 3
50
51 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
52
53
54 typedef struct private_stroke_interface_t private_stroke_interface_t;
55
56 /**
57 * Private data of an stroke_t object.
58 */
59 struct private_stroke_interface_t {
60
61 /**
62 * Public part of stroke_t object.
63 */
64 stroke_t public;
65
66 /**
67 * backend to store configurations
68 */
69 local_backend_t *backend;
70
71 /**
72 * Unix socket to listen for strokes
73 */
74 int socket;
75
76 /**
77 * Thread which reads from the Socket
78 */
79 pthread_t threads[STROKE_THREADS];
80 };
81
82 /**
83 * Helper function which corrects the string pointers
84 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
85 * contains RELATIVE addresses (relative to the beginning of the
86 * stroke_msg). They must be corrected if they reach our address
87 * space...
88 */
89 static void pop_string(stroke_msg_t *msg, char **string)
90 {
91 if (*string == NULL)
92 return;
93
94 /* check for sanity of string pointer and string */
95 if (string < (char**)msg
96 || string > (char**)msg + sizeof(stroke_msg_t)
97 || (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg)
98 || (unsigned long)*string > msg->length)
99 {
100 *string = "(invalid pointer in stroke msg)";
101 }
102 else
103 {
104 *string = (char*)msg + (unsigned long)*string;
105 }
106 }
107
108 /**
109 * Load end entitity certificate
110 */
111 static x509_t* load_end_certificate(const char *filename, identification_t **idp)
112 {
113 char path[PATH_BUF];
114 x509_t *cert;
115
116 if (*filename == '/')
117 {
118 /* absolute path name */
119 snprintf(path, sizeof(path), "%s", filename);
120 }
121 else
122 {
123 /* relative path name */
124 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
125 }
126
127 cert = x509_create_from_file(path, "end entity");
128
129 if (cert)
130 {
131 identification_t *id = *idp;
132 identification_t *subject = cert->get_subject(cert);
133
134 err_t ugh = cert->is_valid(cert, NULL);
135
136 if (ugh != NULL)
137 {
138 DBG1(DBG_CFG, "warning: certificate %s", ugh);
139 }
140 if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
141 {
142 id->destroy(id);
143 id = subject;
144 *idp = id->clone(id);
145 }
146 return charon->credentials->add_end_certificate(charon->credentials, cert);
147 }
148 return NULL;
149 }
150
151 /**
152 * Load ca certificate
153 */
154 static x509_t* load_ca_certificate(const char *filename)
155 {
156 char path[PATH_BUF];
157 x509_t *cert;
158
159 if (*filename == '/')
160 {
161 /* absolute path name */
162 snprintf(path, sizeof(path), "%s", filename);
163 }
164 else
165 {
166 /* relative path name */
167 snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
168 }
169
170 cert = x509_create_from_file(path, "ca");
171
172 if (cert)
173 {
174 if (cert->is_ca(cert))
175 {
176 return charon->credentials->add_auth_certificate(charon->credentials, cert, AUTH_CA);
177 }
178 else
179 {
180 DBG1(DBG_CFG, " CA basic constraints flag not set, cert discarded");
181 cert->destroy(cert);
182 }
183 }
184 return NULL;
185 }
186
187 /**
188 * Add a connection to the configuration list
189 */
190 static void stroke_add_conn(private_stroke_interface_t *this,
191 stroke_msg_t *msg, FILE *out)
192 {
193 ike_cfg_t *ike_cfg;
194 peer_cfg_t *peer_cfg;
195 child_cfg_t *child_cfg;
196 identification_t *my_id, *other_id;
197 identification_t *my_ca = NULL;
198 identification_t *other_ca = NULL;
199 bool my_ca_same = FALSE;
200 bool other_ca_same =FALSE;
201 host_t *my_host, *other_host, *my_subnet, *other_subnet;
202 host_t *my_vip = NULL, *other_vip = NULL;
203 proposal_t *proposal;
204 traffic_selector_t *my_ts, *other_ts;
205 char *interface;
206 bool use_existing = FALSE;
207 iterator_t *iterator;
208
209 pop_string(msg, &msg->add_conn.name);
210 pop_string(msg, &msg->add_conn.me.address);
211 pop_string(msg, &msg->add_conn.other.address);
212 pop_string(msg, &msg->add_conn.me.subnet);
213 pop_string(msg, &msg->add_conn.other.subnet);
214 pop_string(msg, &msg->add_conn.me.sourceip);
215 pop_string(msg, &msg->add_conn.other.sourceip);
216 pop_string(msg, &msg->add_conn.me.id);
217 pop_string(msg, &msg->add_conn.other.id);
218 pop_string(msg, &msg->add_conn.me.cert);
219 pop_string(msg, &msg->add_conn.other.cert);
220 pop_string(msg, &msg->add_conn.me.ca);
221 pop_string(msg, &msg->add_conn.other.ca);
222 pop_string(msg, &msg->add_conn.me.updown);
223 pop_string(msg, &msg->add_conn.other.updown);
224 pop_string(msg, &msg->add_conn.algorithms.ike);
225 pop_string(msg, &msg->add_conn.algorithms.esp);
226
227 DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
228
229 DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
230 DBG2(DBG_CFG, " left=%s", msg->add_conn.me.address);
231 DBG2(DBG_CFG, " right=%s", msg->add_conn.other.address);
232 DBG2(DBG_CFG, " leftsubnet=%s", msg->add_conn.me.subnet);
233 DBG2(DBG_CFG, " rightsubnet=%s", msg->add_conn.other.subnet);
234 DBG2(DBG_CFG, " leftsourceip=%s", msg->add_conn.me.sourceip);
235 DBG2(DBG_CFG, " rightsourceip=%s", msg->add_conn.other.sourceip);
236 DBG2(DBG_CFG, " leftid=%s", msg->add_conn.me.id);
237 DBG2(DBG_CFG, " rightid=%s", msg->add_conn.other.id);
238 DBG2(DBG_CFG, " leftcert=%s", msg->add_conn.me.cert);
239 DBG2(DBG_CFG, " rightcert=%s", msg->add_conn.other.cert);
240 DBG2(DBG_CFG, " leftca=%s", msg->add_conn.me.ca);
241 DBG2(DBG_CFG, " rightca=%s", msg->add_conn.other.ca);
242 DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
243 DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
244
245 my_host = msg->add_conn.me.address?
246 host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
247 if (my_host == NULL)
248 {
249 DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address);
250 return;
251 }
252
253 other_host = msg->add_conn.other.address ?
254 host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
255 if (other_host == NULL)
256 {
257 DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address);
258 my_host->destroy(my_host);
259 return;
260 }
261
262 interface = charon->kernel_interface->get_interface(charon->kernel_interface,
263 other_host);
264 if (interface)
265 {
266 stroke_end_t tmp_end;
267 host_t *tmp_host;
268
269 DBG2(DBG_CFG, "left is other host, swapping ends\n");
270
271 tmp_host = my_host;
272 my_host = other_host;
273 other_host = tmp_host;
274
275 tmp_end = msg->add_conn.me;
276 msg->add_conn.me = msg->add_conn.other;
277 msg->add_conn.other = tmp_end;
278 free(interface);
279 }
280 if (!interface)
281 {
282 interface = charon->kernel_interface->get_interface(
283 charon->kernel_interface, my_host);
284 if (!interface)
285 {
286 DBG1(DBG_CFG, "left nor right host is our side, aborting\n");
287 goto destroy_hosts;
288 }
289 free(interface);
290 }
291
292 my_id = identification_create_from_string(msg->add_conn.me.id ?
293 msg->add_conn.me.id : msg->add_conn.me.address);
294 if (my_id == NULL)
295 {
296 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
297 goto destroy_hosts;
298 }
299
300 other_id = identification_create_from_string(msg->add_conn.other.id ?
301 msg->add_conn.other.id : msg->add_conn.other.address);
302 if (other_id == NULL)
303 {
304 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
305 my_id->destroy(my_id);
306 goto destroy_hosts;
307 }
308
309 my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
310 msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
311 if (my_subnet == NULL)
312 {
313 DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
314 goto destroy_ids;
315 }
316
317 other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
318 msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
319 if (other_subnet == NULL)
320 {
321 DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
322 my_subnet->destroy(my_subnet);
323 goto destroy_ids;
324 }
325
326 if (msg->add_conn.me.virtual_ip)
327 {
328 my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
329 }
330 other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
331
332 if (msg->add_conn.me.tohost)
333 {
334 my_ts = traffic_selector_create_dynamic(msg->add_conn.me.protocol,
335 my_host->get_family(my_host) == AF_INET ?
336 TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
337 msg->add_conn.me.port ? msg->add_conn.me.port : 0,
338 msg->add_conn.me.port ? msg->add_conn.me.port : 65535);
339 }
340 else
341 {
342 my_ts = traffic_selector_create_from_subnet(my_subnet,
343 msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0,
344 msg->add_conn.me.protocol, msg->add_conn.me.port);
345 }
346 my_subnet->destroy(my_subnet);
347
348 if (msg->add_conn.other.tohost)
349 {
350 other_ts = traffic_selector_create_dynamic(msg->add_conn.other.protocol,
351 other_host->get_family(other_host) == AF_INET ?
352 TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE,
353 msg->add_conn.other.port ? msg->add_conn.other.port : 0,
354 msg->add_conn.other.port ? msg->add_conn.other.port : 65535);
355 }
356 else
357 {
358 other_ts = traffic_selector_create_from_subnet(other_subnet,
359 msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0,
360 msg->add_conn.other.protocol, msg->add_conn.other.port);
361 }
362 other_subnet->destroy(other_subnet);
363
364 if (msg->add_conn.me.ca)
365 {
366 if (streq(msg->add_conn.me.ca, "%same"))
367 {
368 my_ca_same = TRUE;
369 }
370 else
371 {
372 my_ca = identification_create_from_string(msg->add_conn.me.ca);
373 }
374 }
375 if (msg->add_conn.other.ca)
376 {
377 if (streq(msg->add_conn.other.ca, "%same"))
378 {
379 other_ca_same = TRUE;
380 }
381 else
382 {
383 other_ca = identification_create_from_string(msg->add_conn.other.ca);
384 }
385 }
386 if (msg->add_conn.me.cert)
387 {
388 x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id);
389
390 if (my_ca == NULL && !my_ca_same && cert)
391 {
392 identification_t *issuer = cert->get_issuer(cert);
393
394 my_ca = issuer->clone(issuer);
395 }
396 }
397 if (msg->add_conn.other.cert)
398 {
399 x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id);
400
401 if (other_ca == NULL && !other_ca_same && cert)
402 {
403 identification_t *issuer = cert->get_issuer(cert);
404
405 other_ca = issuer->clone(issuer);
406 }
407 }
408 if (other_ca_same && my_ca)
409 {
410 other_ca = my_ca->clone(my_ca);
411 }
412 else if (my_ca_same && other_ca)
413 {
414 my_ca = other_ca->clone(other_ca);
415 }
416 if (my_ca == NULL)
417 {
418 my_ca = identification_create_from_string("%any");
419 }
420 if (other_ca == NULL)
421 {
422 other_ca = identification_create_from_string("%any");
423 }
424 DBG2(DBG_CFG, " my ca: '%D'", my_ca);
425 DBG2(DBG_CFG, " other ca:'%D'", other_ca);
426 DBG2(DBG_CFG, " updown: '%s'", msg->add_conn.me.updown);
427
428 /* have a look for an (almost) identical peer config to reuse */
429 iterator = this->backend->create_peer_cfg_iterator(this->backend);
430 while (iterator->iterate(iterator, (void**)&peer_cfg))
431 {
432 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
433 if (my_id->equals(my_id, peer_cfg->get_my_id(peer_cfg)) &&
434 other_id->equals(other_id, peer_cfg->get_other_id(peer_cfg)) &&
435 my_host->equals(my_host, ike_cfg->get_my_host(ike_cfg)) &&
436 other_host->equals(other_host, ike_cfg->get_other_host(ike_cfg)) &&
437 peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) &&
438 peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method &&
439 peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type)
440 {
441 DBG1(DBG_CFG, "reusing existing configuration '%s'",
442 peer_cfg->get_name(peer_cfg));
443 use_existing = TRUE;
444 break;
445 }
446 }
447 iterator->destroy(iterator);
448
449 if (use_existing)
450 {
451 my_host->destroy(my_host);
452 my_id->destroy(my_id);
453 my_ca->destroy(my_ca);
454 other_host->destroy(other_host);
455 other_id->destroy(other_id);
456 other_ca->destroy(other_ca);
457 }
458 else
459 {
460 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
461 my_host, other_host);
462
463 if (msg->add_conn.algorithms.ike)
464 {
465 char *proposal_string;
466 char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
467
468 if (*strict == '!')
469 *strict = '\0';
470 else
471 strict = NULL;
472
473 while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
474 {
475 proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
476 if (proposal == NULL)
477 {
478 DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
479 my_id->destroy(my_id);
480 other_id->destroy(other_id);
481 my_ts->destroy(my_ts);
482 other_ts->destroy(other_ts);
483 my_ca->destroy(my_ca);
484 other_ca->destroy(other_ca);
485 ike_cfg->destroy(ike_cfg);
486 return;
487 }
488 ike_cfg->add_proposal(ike_cfg, proposal);
489 }
490 if (!strict)
491 {
492 proposal = proposal_create_default(PROTO_IKE);
493 ike_cfg->add_proposal(ike_cfg, proposal);
494 }
495 }
496 else
497 {
498 proposal = proposal_create_default(PROTO_IKE);
499 ike_cfg->add_proposal(ike_cfg, proposal);
500 }
501
502
503 peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1,
504 ike_cfg, my_id, other_id, my_ca, other_ca, msg->add_conn.me.sendcert,
505 msg->add_conn.auth_method, msg->add_conn.eap_type,
506 msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime,
507 msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
508 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
509 msg->add_conn.rekey.reauth, msg->add_conn.dpd.delay,
510 msg->add_conn.dpd.action,my_vip, other_vip);
511 }
512
513 child_cfg = child_cfg_create(
514 msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
515 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
516 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
517 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
518 msg->add_conn.mode);
519
520 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
521
522 child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts);
523 child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts);
524
525 if (msg->add_conn.algorithms.esp)
526 {
527 char *proposal_string;
528 char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
529
530 if (*strict == '!')
531 *strict = '\0';
532 else
533 strict = NULL;
534
535 while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
536 {
537 proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
538 if (proposal == NULL)
539 {
540 DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
541 peer_cfg->destroy(peer_cfg);
542 return;
543 }
544 child_cfg->add_proposal(child_cfg, proposal);
545 }
546 if (!strict)
547 {
548 proposal = proposal_create_default(PROTO_ESP);
549 child_cfg->add_proposal(child_cfg, proposal);
550 }
551 }
552 else
553 {
554 proposal = proposal_create_default(PROTO_ESP);
555 child_cfg->add_proposal(child_cfg, proposal);
556 }
557
558 if (!use_existing)
559 {
560 /* add config to backend */
561 this->backend->add_peer_cfg(this->backend, peer_cfg);
562 DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]",
563 msg->add_conn.name, my_host, my_id, other_host, other_id);
564 }
565 return;
566
567 /* mopping up after parsing errors */
568
569 destroy_ids:
570 my_id->destroy(my_id);
571 other_id->destroy(other_id);
572
573 destroy_hosts:
574 my_host->destroy(my_host);
575 other_host->destroy(other_host);
576 }
577
578 /**
579 * Delete a connection from the list
580 */
581 static void stroke_del_conn(private_stroke_interface_t *this,
582 stroke_msg_t *msg, FILE *out)
583 {
584 iterator_t *peer_iter, *child_iter;
585 peer_cfg_t *peer, *child;
586
587 pop_string(msg, &(msg->del_conn.name));
588 DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
589
590 peer_iter = this->backend->create_peer_cfg_iterator(this->backend);
591 while (peer_iter->iterate(peer_iter, (void**)&peer))
592 {
593 /* remove peer config with such a name */
594 if (streq(peer->get_name(peer), msg->del_conn.name))
595 {
596 peer_iter->remove(peer_iter);
597 peer->destroy(peer);
598 continue;
599 }
600 /* remove any child with such a name */
601 child_iter = peer->create_child_cfg_iterator(peer);
602 while (child_iter->iterate(child_iter, (void**)&child))
603 {
604 if (streq(child->get_name(child), msg->del_conn.name))
605 {
606 child_iter->remove(child_iter);
607 child->destroy(child);
608 }
609 }
610 child_iter->destroy(child_iter);
611 }
612 peer_iter->destroy(peer_iter);
613
614 fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
615 }
616
617 /**
618 * get the child_cfg with the same name as the peer cfg
619 */
620 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg)
621 {
622 child_cfg_t *current, *found = NULL;
623 iterator_t *iterator;
624
625 iterator = peer_cfg->create_child_cfg_iterator(peer_cfg);
626 while (iterator->iterate(iterator, (void**)&current))
627 {
628 if (streq(current->get_name(current), peer_cfg->get_name(peer_cfg)))
629 {
630 found = current;
631 found->get_ref(found);
632 break;
633 }
634 }
635 iterator->destroy(iterator);
636 return found;
637 }
638
639 /**
640 * initiate a connection by name
641 */
642 static void stroke_initiate(private_stroke_interface_t *this,
643 stroke_msg_t *msg, FILE *out)
644 {
645 initiate_job_t *job;
646 peer_cfg_t *peer_cfg;
647 child_cfg_t *child_cfg;
648 ike_sa_t *init_ike_sa = NULL;
649 signal_t signal;
650
651 pop_string(msg, &(msg->initiate.name));
652 DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
653
654 peer_cfg = charon->cfg_store->get_peer_cfg_by_name(charon->cfg_store,
655 msg->initiate.name);
656 if (peer_cfg == NULL)
657 {
658 if (msg->output_verbosity >= 0)
659 {
660 fprintf(out, "no config named '%s'\n", msg->initiate.name);
661 }
662 return;
663 }
664 if (peer_cfg->get_ike_version(peer_cfg) != 2)
665 {
666 DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
667 peer_cfg->get_ike_version(peer_cfg));
668 peer_cfg->destroy(peer_cfg);
669 return;
670 }
671
672 child_cfg = get_child_from_peer(peer_cfg);
673 if (child_cfg == NULL)
674 {
675 if (msg->output_verbosity >= 0)
676 {
677 fprintf(out, "no child config named '%s'\n", msg->initiate.name);
678 }
679 peer_cfg->destroy(peer_cfg);
680 return;
681 }
682
683 job = initiate_job_create(peer_cfg, child_cfg);
684 charon->bus->set_listen_state(charon->bus, TRUE);
685 charon->job_queue->add(charon->job_queue, (job_t*)job);
686 while (TRUE)
687 {
688 level_t level;
689 int thread;
690 ike_sa_t *ike_sa;
691 char* format;
692 va_list args;
693
694 signal = charon->bus->listen(charon->bus, &level, &thread, &ike_sa, &format, &args);
695
696 if ((init_ike_sa == NULL || ike_sa == init_ike_sa) &&
697 level <= msg->output_verbosity)
698 {
699 if (vfprintf(out, format, args) < 0 ||
700 fprintf(out, "\n") < 0 ||
701 fflush(out))
702 {
703 charon->bus->set_listen_state(charon->bus, FALSE);
704 break;
705 }
706 }
707
708 switch (signal)
709 {
710 case CHILD_UP_SUCCESS:
711 case CHILD_UP_FAILED:
712 case IKE_UP_FAILED:
713 if (ike_sa == init_ike_sa)
714 {
715 charon->bus->set_listen_state(charon->bus, FALSE);
716 return;
717 }
718 continue;
719 case CHILD_UP_START:
720 case IKE_UP_START:
721 if (init_ike_sa == NULL)
722 {
723 init_ike_sa = ike_sa;
724 }
725 continue;
726 default:
727 continue;
728 }
729 }
730 }
731
732 /**
733 * route/unroute a policy (install SPD entries)
734 */
735 static void stroke_route(private_stroke_interface_t *this,
736 stroke_msg_t *msg, FILE *out, bool route)
737 {
738 route_job_t *job;
739 peer_cfg_t *peer_cfg;
740 child_cfg_t *child_cfg;
741
742 pop_string(msg, &(msg->route.name));
743 DBG1(DBG_CFG, "received stroke: %s '%s'",
744 route ? "route" : "unroute", msg->route.name);
745
746 peer_cfg = charon->cfg_store->get_peer_cfg_by_name(charon->cfg_store,
747 msg->route.name);
748 if (peer_cfg == NULL)
749 {
750 fprintf(out, "no config named '%s'\n", msg->route.name);
751 return;
752 }
753 if (peer_cfg->get_ike_version(peer_cfg) != 2)
754 {
755 peer_cfg->destroy(peer_cfg);
756 return;
757 }
758
759 child_cfg = get_child_from_peer(peer_cfg);
760 if (child_cfg == NULL)
761 {
762 fprintf(out, "no child config named '%s'\n", msg->route.name);
763 peer_cfg->destroy(peer_cfg);
764 return;
765 }
766 fprintf(out, "%s policy '%s'\n",
767 route ? "routing" : "unrouting", msg->route.name);
768 job = route_job_create(peer_cfg, child_cfg, route);
769 charon->job_queue->add(charon->job_queue, (job_t*)job);
770 }
771
772 /**
773 * terminate a connection by name
774 */
775 static void stroke_terminate(private_stroke_interface_t *this,
776 stroke_msg_t *msg, FILE *out)
777 {
778 char *string, *pos = NULL, *name = NULL;
779 u_int32_t id = 0;
780 bool child;
781 int len;
782 status_t status = SUCCESS;;
783 ike_sa_t *ike_sa;
784
785 pop_string(msg, &(msg->terminate.name));
786 string = msg->terminate.name;
787 DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
788
789 len = strlen(string);
790 if (len < 1)
791 {
792 DBG1(DBG_CFG, "error parsing string");
793 return;
794 }
795 switch (string[len-1])
796 {
797 case '}':
798 child = TRUE;
799 pos = strchr(string, '{');
800 break;
801 case ']':
802 child = FALSE;
803 pos = strchr(string, '[');
804 break;
805 default:
806 name = string;
807 child = FALSE;
808 break;
809 }
810
811 if (name)
812 { /* must be a single name */
813 DBG1(DBG_CFG, "check out by single name '%s'", name);
814 ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
815 name, child);
816 }
817 else if (pos == string + len - 2)
818 { /* must be name[] or name{} */
819 string[len-2] = '\0';
820 DBG1(DBG_CFG, "check out by name '%s'", string);
821 ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
822 string, child);
823 }
824 else
825 { /* must be name[123] or name{23} */
826 string[len-1] = '\0';
827 id = atoi(pos + 1);
828 if (id == 0)
829 {
830 DBG1(DBG_CFG, "error parsing string");
831 return;
832 }
833 DBG1(DBG_CFG, "check out by id '%d'", id);
834 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
835 id, child);
836 }
837 if (ike_sa == NULL)
838 {
839 DBG1(DBG_CFG, "no such IKE_SA found");
840 return;
841 }
842
843 if (!child)
844 {
845 status = ike_sa->delete(ike_sa);
846 }
847 else
848 {
849 child_sa_t *child_sa;
850 iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
851 while (iterator->iterate(iterator, (void**)&child_sa))
852 {
853 if ((id && id == child_sa->get_reqid(child_sa)) ||
854 (string && streq(string, child_sa->get_name(child_sa))))
855 {
856 u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
857 protocol_id_t proto = child_sa->get_protocol(child_sa);
858
859 status = ike_sa->delete_child_sa(ike_sa, proto, spi);
860 break;
861 }
862 }
863 iterator->destroy(iterator);
864 }
865 if (status == DESTROY_ME)
866 {
867 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
868 ike_sa);
869 return;
870 }
871 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
872 }
873
874 /**
875 * Add a ca information record to the cainfo list
876 */
877 static void stroke_add_ca(private_stroke_interface_t *this,
878 stroke_msg_t *msg, FILE *out)
879 {
880 x509_t *cacert;
881 ca_info_t *ca_info;
882
883 pop_string(msg, &msg->add_ca.name);
884 pop_string(msg, &msg->add_ca.cacert);
885 pop_string(msg, &msg->add_ca.crluri);
886 pop_string(msg, &msg->add_ca.crluri2);
887 pop_string(msg, &msg->add_ca.ocspuri);
888 pop_string(msg, &msg->add_ca.ocspuri2);
889
890 DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
891
892 DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
893 DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert);
894 DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri);
895 DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2);
896 DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri);
897 DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2);
898
899 if (msg->add_ca.cacert == NULL)
900 {
901 DBG1(DBG_CFG, "missing cacert parameter\n");
902 return;
903 }
904
905 cacert = load_ca_certificate(msg->add_ca.cacert);
906
907 if (cacert == NULL)
908 {
909 return;
910 }
911 ca_info = ca_info_create(msg->add_ca.name, cacert);
912
913 if (msg->add_ca.crluri)
914 {
915 chunk_t uri = { msg->add_ca.crluri, strlen(msg->add_ca.crluri) };
916
917 ca_info->add_crluri(ca_info, uri);
918 }
919 if (msg->add_ca.crluri2)
920 {
921 chunk_t uri = { msg->add_ca.crluri2, strlen(msg->add_ca.crluri2) };
922
923 ca_info->add_crluri(ca_info, uri);
924 }
925 if (msg->add_ca.ocspuri)
926 {
927 chunk_t uri = { msg->add_ca.ocspuri, strlen(msg->add_ca.ocspuri) };
928
929 ca_info->add_ocspuri(ca_info, uri);
930 }
931 if (msg->add_ca.ocspuri2)
932 {
933 chunk_t uri = { msg->add_ca.ocspuri2, strlen(msg->add_ca.ocspuri2) };
934
935 ca_info->add_ocspuri(ca_info, uri);
936 }
937 charon->credentials->add_ca_info(charon->credentials, ca_info);
938 DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
939
940 }
941
942 /**
943 * Delete a ca information record from the cainfo list
944 */
945 static void stroke_del_ca(private_stroke_interface_t *this,
946 stroke_msg_t *msg, FILE *out)
947 {
948 status_t status;
949
950 pop_string(msg, &(msg->del_ca.name));
951 DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
952
953 status = charon->credentials->release_ca_info(charon->credentials,
954 msg->del_ca.name);
955
956 if (status == SUCCESS)
957 {
958 fprintf(out, "deleted ca '%s'\n", msg->del_ca.name);
959 }
960 else
961 {
962 fprintf(out, "no ca named '%s'\n", msg->del_ca.name);
963 }
964 }
965
966 /**
967 * show status of daemon
968 */
969 static void stroke_statusall(private_stroke_interface_t *this,
970 stroke_msg_t *msg, FILE *out)
971 {
972 iterator_t *iterator, *children;
973 linked_list_t *list;
974 host_t *host;
975 peer_cfg_t *peer_cfg;
976 ike_cfg_t *ike_cfg;
977 child_cfg_t *child_cfg;
978 ike_sa_t *ike_sa;
979 char *name = NULL;
980
981 leak_detective_status(out);
982
983 fprintf(out, "Performance:\n");
984 fprintf(out, " worker threads: %d idle of %d,",
985 charon->thread_pool->get_idle_threads(charon->thread_pool),
986 charon->thread_pool->get_pool_size(charon->thread_pool));
987 fprintf(out, " job queue load: %d,",
988 charon->job_queue->get_count(charon->job_queue));
989 fprintf(out, " scheduled events: %d\n",
990 charon->event_queue->get_count(charon->event_queue));
991 list = charon->kernel_interface->create_address_list(charon->kernel_interface);
992
993 fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
994 while (list->remove_first(list, (void**)&host) == SUCCESS)
995 {
996 fprintf(out, " %H\n", host);
997 host->destroy(host);
998 }
999 list->destroy(list);
1000
1001 if (msg->status.name)
1002 {
1003 pop_string(msg, &(msg->status.name));
1004 name = msg->status.name;
1005 }
1006
1007 fprintf(out, "Connections:\n");
1008 iterator = this->backend->create_peer_cfg_iterator(this->backend);
1009 while (iterator->iterate(iterator, (void**)&peer_cfg))
1010 {
1011 if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
1012 (name && !streq(name, peer_cfg->get_name(peer_cfg))))
1013 {
1014 continue;
1015 }
1016
1017 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
1018 fprintf(out, "%12s: %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg),
1019 ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
1020 ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
1021 children = peer_cfg->create_child_cfg_iterator(peer_cfg);
1022 while (children->iterate(children, (void**)&child_cfg))
1023 {
1024 linked_list_t *my_ts, *other_ts;
1025 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
1026 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
1027 fprintf(out, "%12s: %#R=== %#R\n", child_cfg->get_name(child_cfg),
1028 my_ts, other_ts);
1029 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
1030 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
1031 }
1032 children->destroy(children);
1033 }
1034 iterator->destroy(iterator);
1035
1036
1037 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
1038 if (iterator->get_count(iterator) > 0)
1039 {
1040 fprintf(out, "Security Associations:\n");
1041 }
1042 while (iterator->iterate(iterator, (void**)&ike_sa))
1043 {
1044 bool ike_sa_printed = FALSE;
1045 child_sa_t *child_sa;
1046 iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
1047
1048 /* print IKE_SA */
1049 if (name == NULL || strcmp(name, ike_sa->get_name(ike_sa)) == 0)
1050 {
1051 fprintf(out, "%#K\n", ike_sa);
1052 ike_sa_printed = TRUE;
1053 }
1054
1055 while (children->iterate(children, (void**)&child_sa))
1056 {
1057 bool child_sa_match = name == NULL ||
1058 strcmp(name, child_sa->get_name(child_sa)) == 0;
1059
1060 /* print IKE_SA if its name differs from the CHILD_SA's name */
1061 if (!ike_sa_printed && child_sa_match)
1062 {
1063 fprintf(out, "%#K\n", ike_sa);
1064 ike_sa_printed = TRUE;
1065 }
1066
1067 /* print CHILD_SA */
1068 if (child_sa_match)
1069 {
1070 fprintf(out, "%#P\n", child_sa);
1071 }
1072 }
1073 children->destroy(children);
1074 }
1075 iterator->destroy(iterator);
1076 }
1077
1078 /**
1079 * show status of daemon
1080 */
1081 static void stroke_status(private_stroke_interface_t *this,
1082 stroke_msg_t *msg, FILE *out)
1083 {
1084 iterator_t *iterator;
1085 ike_sa_t *ike_sa;
1086 char *name = NULL;
1087
1088 if (msg->status.name)
1089 {
1090 pop_string(msg, &(msg->status.name));
1091 name = msg->status.name;
1092 }
1093
1094 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
1095 while (iterator->iterate(iterator, (void**)&ike_sa))
1096 {
1097 bool ike_sa_printed = FALSE;
1098 child_sa_t *child_sa;
1099 iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
1100
1101 /* print IKE_SA */
1102 if (name == NULL || strcmp(name, ike_sa->get_name(ike_sa)) == 0)
1103 {
1104 fprintf(out, "%K\n", ike_sa);
1105 ike_sa_printed = TRUE;
1106 }
1107
1108 while (children->iterate(children, (void**)&child_sa))
1109 {
1110 bool child_sa_match = name == NULL ||
1111 strcmp(name, child_sa->get_name(child_sa)) == 0;
1112
1113 /* print IKE_SA if its name differs from the CHILD_SA's name */
1114 if (!ike_sa_printed && child_sa_match)
1115 {
1116 fprintf(out, "%K\n", ike_sa);
1117 ike_sa_printed = TRUE;
1118 }
1119
1120 /* print CHILD_SA */
1121 if (child_sa_match)
1122 {
1123 fprintf(out, "%P\n", child_sa);
1124 }
1125 }
1126 children->destroy(children);
1127 }
1128 iterator->destroy(iterator);
1129 }
1130
1131 /**
1132 * list all authority certificates matching a specified flag
1133 */
1134 static void list_auth_certificates(private_stroke_interface_t *this, u_int flag,
1135 const char *label, bool utc, FILE *out)
1136 {
1137 bool first = TRUE;
1138 x509_t *cert;
1139
1140 iterator_t *iterator = charon->credentials->create_auth_cert_iterator(charon->credentials);
1141
1142 while (iterator->iterate(iterator, (void**)&cert))
1143 {
1144 if (cert->has_authority_flag(cert, flag))
1145 {
1146 if (first)
1147 {
1148 fprintf(out, "\n");
1149 fprintf(out, "List of X.509 %s Certificates:\n", label);
1150 fprintf(out, "\n");
1151 first = FALSE;
1152 }
1153 fprintf(out, "%#Q\n", cert, utc);
1154 }
1155 }
1156 iterator->destroy(iterator);
1157 }
1158
1159 /**
1160 * list various information
1161 */
1162 static void stroke_list(private_stroke_interface_t *this,
1163 stroke_msg_t *msg, FILE *out)
1164 {
1165 iterator_t *iterator;
1166
1167 if (msg->list.flags & LIST_CERTS)
1168 {
1169 x509_t *cert;
1170
1171 iterator = charon->credentials->create_cert_iterator(charon->credentials);
1172 if (iterator->get_count(iterator))
1173 {
1174 fprintf(out, "\n");
1175 fprintf(out, "List of X.509 End Entity Certificates:\n");
1176 fprintf(out, "\n");
1177 }
1178 while (iterator->iterate(iterator, (void**)&cert))
1179 {
1180 fprintf(out, "%#Q", cert, msg->list.utc);
1181 if (charon->credentials->has_rsa_private_key(
1182 charon->credentials, cert->get_public_key(cert)))
1183 {
1184 fprintf(out, ", has private key");
1185 }
1186 fprintf(out, "\n");
1187
1188 }
1189 iterator->destroy(iterator);
1190 }
1191 if (msg->list.flags & LIST_CACERTS)
1192 {
1193 list_auth_certificates(this, AUTH_CA, "CA", msg->list.utc, out);
1194 }
1195 if (msg->list.flags & LIST_CAINFOS)
1196 {
1197 ca_info_t *ca_info;
1198
1199 iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1200 if (iterator->get_count(iterator))
1201 {
1202 fprintf(out, "\n");
1203 fprintf(out, "List of X.509 CA Information Records:\n");
1204 fprintf(out, "\n");
1205 }
1206 while (iterator->iterate(iterator, (void**)&ca_info))
1207 {
1208 fprintf(out, "%#W", ca_info, msg->list.utc);
1209 }
1210 iterator->destroy(iterator);
1211 }
1212 if (msg->list.flags & LIST_CRLS)
1213 {
1214 ca_info_t *ca_info;
1215 bool first = TRUE;
1216
1217 iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1218 while (iterator->iterate(iterator, (void **)&ca_info))
1219 {
1220 if (ca_info->has_crl(ca_info))
1221 {
1222 if (first)
1223 {
1224 fprintf(out, "\n");
1225 fprintf(out, "List of X.509 CRLs:\n");
1226 fprintf(out, "\n");
1227 first = FALSE;
1228 }
1229 ca_info->list_crl(ca_info, out, msg->list.utc);
1230 }
1231 }
1232 iterator->destroy(iterator);
1233 }
1234 if (msg->list.flags & LIST_OCSPCERTS)
1235 {
1236 list_auth_certificates(this, AUTH_OCSP, "OCSP", msg->list.utc, out);
1237 }
1238 if (msg->list.flags & LIST_OCSP)
1239 {
1240 ca_info_t *ca_info;
1241 bool first = TRUE;
1242
1243 iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1244 while (iterator->iterate(iterator, (void **)&ca_info))
1245 {
1246 if (ca_info->has_certinfos(ca_info))
1247 {
1248 if (first)
1249 {
1250 fprintf(out, "\n");
1251 fprintf(out, "List of OCSP responses:\n");
1252 first = FALSE;
1253 }
1254 fprintf(out, "\n");
1255 ca_info->list_certinfos(ca_info, out, msg->list.utc);
1256 }
1257 }
1258 iterator->destroy(iterator);
1259 }
1260 }
1261
1262 /**
1263 * reread various information
1264 */
1265 static void stroke_reread(private_stroke_interface_t *this,
1266 stroke_msg_t *msg, FILE *out)
1267 {
1268 if (msg->reread.flags & REREAD_CACERTS)
1269 {
1270 charon->credentials->load_ca_certificates(charon->credentials);
1271 }
1272 if (msg->reread.flags & REREAD_OCSPCERTS)
1273 {
1274 charon->credentials->load_ocsp_certificates(charon->credentials);
1275 }
1276 if (msg->reread.flags & REREAD_CRLS)
1277 {
1278 charon->credentials->load_crls(charon->credentials);
1279 }
1280 }
1281
1282 /**
1283 * purge various information
1284 */
1285 static void stroke_purge(private_stroke_interface_t *this,
1286 stroke_msg_t *msg, FILE *out)
1287 {
1288 if (msg->purge.flags & PURGE_OCSP)
1289 {
1290 iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1291 ca_info_t *ca_info;
1292
1293 while (iterator->iterate(iterator, (void**)&ca_info))
1294 {
1295 ca_info->purge_ocsp(ca_info);
1296 }
1297 iterator->destroy(iterator);
1298 }
1299 }
1300
1301 signal_t get_signal_from_logtype(char *type)
1302 {
1303 if (strcasecmp(type, "any") == 0) return SIG_ANY;
1304 else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
1305 else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
1306 else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
1307 else if (strcasecmp(type, "job") == 0) return DBG_JOB;
1308 else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
1309 else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
1310 else if (strcasecmp(type, "net") == 0) return DBG_NET;
1311 else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
1312 else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
1313 else return -1;
1314 }
1315
1316 /**
1317 * set the verbosity debug output
1318 */
1319 static void stroke_loglevel(private_stroke_interface_t *this,
1320 stroke_msg_t *msg, FILE *out)
1321 {
1322 signal_t signal;
1323
1324 pop_string(msg, &(msg->loglevel.type));
1325 DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
1326 msg->loglevel.level, msg->loglevel.type);
1327
1328 signal = get_signal_from_logtype(msg->loglevel.type);
1329 if (signal < 0)
1330 {
1331 fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
1332 return;
1333 }
1334
1335 charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
1336 charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
1337 }
1338
1339 /**
1340 * process a stroke request from the socket pointed by "fd"
1341 */
1342 static void stroke_process(private_stroke_interface_t *this, int strokefd)
1343 {
1344 stroke_msg_t *msg;
1345 u_int16_t msg_length;
1346 ssize_t bytes_read;
1347 FILE *out;
1348
1349 /* peek the length */
1350 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
1351 if (bytes_read != sizeof(msg_length))
1352 {
1353 DBG1(DBG_CFG, "reading length of stroke message failed");
1354 close(strokefd);
1355 return;
1356 }
1357
1358 /* read message */
1359 msg = malloc(msg_length);
1360 bytes_read = recv(strokefd, msg, msg_length, 0);
1361 if (bytes_read != msg_length)
1362 {
1363 DBG1(DBG_CFG, "reading stroke message failed: %m");
1364 close(strokefd);
1365 return;
1366 }
1367
1368 out = fdopen(dup(strokefd), "w");
1369 if (out == NULL)
1370 {
1371 DBG1(DBG_CFG, "opening stroke output channel failed: %m");
1372 close(strokefd);
1373 free(msg);
1374 return;
1375 }
1376
1377 DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
1378
1379 switch (msg->type)
1380 {
1381 case STR_INITIATE:
1382 stroke_initiate(this, msg, out);
1383 break;
1384 case STR_ROUTE:
1385 stroke_route(this, msg, out, TRUE);
1386 break;
1387 case STR_UNROUTE:
1388 stroke_route(this, msg, out, FALSE);
1389 break;
1390 case STR_TERMINATE:
1391 stroke_terminate(this, msg, out);
1392 break;
1393 case STR_STATUS:
1394 stroke_status(this, msg, out);
1395 break;
1396 case STR_STATUS_ALL:
1397 stroke_statusall(this, msg, out);
1398 break;
1399 case STR_ADD_CONN:
1400 stroke_add_conn(this, msg, out);
1401 break;
1402 case STR_DEL_CONN:
1403 stroke_del_conn(this, msg, out);
1404 break;
1405 case STR_ADD_CA:
1406 stroke_add_ca(this, msg, out);
1407 break;
1408 case STR_DEL_CA:
1409 stroke_del_ca(this, msg, out);
1410 break;
1411 case STR_LOGLEVEL:
1412 stroke_loglevel(this, msg, out);
1413 break;
1414 case STR_LIST:
1415 stroke_list(this, msg, out);
1416 break;
1417 case STR_REREAD:
1418 stroke_reread(this, msg, out);
1419 break;
1420 case STR_PURGE:
1421 stroke_purge(this, msg, out);
1422 break;
1423 default:
1424 DBG1(DBG_CFG, "received unknown stroke");
1425 }
1426 fclose(out);
1427 close(strokefd);
1428 free(msg);
1429 }
1430
1431 /**
1432 * Implementation of private_stroke_interface_t.stroke_receive.
1433 */
1434 static void stroke_receive(private_stroke_interface_t *this)
1435 {
1436 struct sockaddr_un strokeaddr;
1437 int strokeaddrlen = sizeof(strokeaddr);
1438 int oldstate;
1439 int strokefd;
1440
1441 /* ignore sigpipe. writing over the pipe back to the console
1442 * only fails if SIGPIPE is ignored. */
1443 signal(SIGPIPE, SIG_IGN);
1444
1445 /* disable cancellation by default */
1446 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1447
1448 while (TRUE)
1449 {
1450 /* wait for connections, but allow thread to terminate */
1451 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
1452 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
1453 pthread_setcancelstate(oldstate, NULL);
1454
1455 if (strokefd < 0)
1456 {
1457 DBG1(DBG_CFG, "accepting stroke connection failed: %m");
1458 continue;
1459 }
1460 stroke_process(this, strokefd);
1461 }
1462 }
1463
1464 /**
1465 * Implementation of stroke_t.destroy.
1466 */
1467 static void destroy(private_stroke_interface_t *this)
1468 {
1469 int i;
1470
1471 for (i = 0; i < STROKE_THREADS; i++)
1472 {
1473 pthread_cancel(this->threads[i]);
1474 pthread_join(this->threads[i], NULL);
1475 }
1476
1477 close(this->socket);
1478 unlink(socket_addr.sun_path);
1479 free(this);
1480 }
1481
1482 /*
1483 * Described in header-file
1484 */
1485 stroke_t *stroke_create(local_backend_t *backend)
1486 {
1487 private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t);
1488 mode_t old;
1489 int i;
1490
1491 /* public functions */
1492 this->public.destroy = (void (*)(stroke_t*))destroy;
1493
1494 this->backend = backend;
1495
1496 /* set up unix socket */
1497 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
1498 if (this->socket == -1)
1499 {
1500 DBG1(DBG_CFG, "could not create whack socket");
1501 free(this);
1502 return NULL;
1503 }
1504
1505 old = umask(~S_IRWXU);
1506 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
1507 {
1508 DBG1(DBG_CFG, "could not bind stroke socket: %m");
1509 close(this->socket);
1510 free(this);
1511 return NULL;
1512 }
1513 umask(old);
1514
1515 if (listen(this->socket, 0) < 0)
1516 {
1517 DBG1(DBG_CFG, "could not listen on stroke socket: %m");
1518 close(this->socket);
1519 unlink(socket_addr.sun_path);
1520 free(this);
1521 return NULL;
1522 }
1523
1524 /* start threads reading from the socket */
1525 for (i = 0; i < STROKE_THREADS; i++)
1526 {
1527 if (pthread_create(&this->threads[i], NULL, (void*(*)(void*))stroke_receive, this) != 0)
1528 {
1529 charon->kill(charon, "unable to create stroke thread");
1530 }
1531 }
1532
1533 return (&this->public);
1534 }