using %V time delta for rekeying times
[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 DESTROY_IF(my_vip);
452 DESTROY_IF(other_vip);
453 my_host->destroy(my_host);
454 my_id->destroy(my_id);
455 my_ca->destroy(my_ca);
456 other_host->destroy(other_host);
457 other_id->destroy(other_id);
458 other_ca->destroy(other_ca);
459 }
460 else
461 {
462 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
463 my_host, other_host);
464
465 if (msg->add_conn.algorithms.ike)
466 {
467 char *proposal_string;
468 char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
469
470 if (*strict == '!')
471 *strict = '\0';
472 else
473 strict = NULL;
474
475 while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
476 {
477 proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
478 if (proposal == NULL)
479 {
480 DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
481 my_id->destroy(my_id);
482 other_id->destroy(other_id);
483 my_ts->destroy(my_ts);
484 other_ts->destroy(other_ts);
485 my_ca->destroy(my_ca);
486 other_ca->destroy(other_ca);
487 ike_cfg->destroy(ike_cfg);
488 return;
489 }
490 ike_cfg->add_proposal(ike_cfg, proposal);
491 }
492 if (!strict)
493 {
494 proposal = proposal_create_default(PROTO_IKE);
495 ike_cfg->add_proposal(ike_cfg, proposal);
496 }
497 }
498 else
499 {
500 proposal = proposal_create_default(PROTO_IKE);
501 ike_cfg->add_proposal(ike_cfg, proposal);
502 }
503
504
505 peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1,
506 ike_cfg, my_id, other_id, my_ca, other_ca, msg->add_conn.me.sendcert,
507 msg->add_conn.auth_method, msg->add_conn.eap_type,
508 msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime,
509 msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
510 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
511 msg->add_conn.rekey.reauth, msg->add_conn.dpd.delay,
512 msg->add_conn.dpd.action,my_vip, other_vip);
513 }
514
515 child_cfg = child_cfg_create(
516 msg->add_conn.name, msg->add_conn.rekey.ipsec_lifetime,
517 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
518 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
519 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
520 msg->add_conn.mode);
521
522 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
523
524 child_cfg->add_traffic_selector(child_cfg, TRUE, my_ts);
525 child_cfg->add_traffic_selector(child_cfg, FALSE, other_ts);
526
527 if (msg->add_conn.algorithms.esp)
528 {
529 char *proposal_string;
530 char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
531
532 if (*strict == '!')
533 *strict = '\0';
534 else
535 strict = NULL;
536
537 while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
538 {
539 proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
540 if (proposal == NULL)
541 {
542 DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
543 peer_cfg->destroy(peer_cfg);
544 return;
545 }
546 child_cfg->add_proposal(child_cfg, proposal);
547 }
548 if (!strict)
549 {
550 proposal = proposal_create_default(PROTO_ESP);
551 child_cfg->add_proposal(child_cfg, proposal);
552 }
553 }
554 else
555 {
556 proposal = proposal_create_default(PROTO_ESP);
557 child_cfg->add_proposal(child_cfg, proposal);
558 }
559
560 if (!use_existing)
561 {
562 /* add config to backend */
563 this->backend->add_peer_cfg(this->backend, peer_cfg);
564 DBG1(DBG_CFG, "added configuration '%s': %H[%D]...%H[%D]",
565 msg->add_conn.name, my_host, my_id, other_host, other_id);
566 }
567 return;
568
569 /* mopping up after parsing errors */
570
571 destroy_ids:
572 my_id->destroy(my_id);
573 other_id->destroy(other_id);
574
575 destroy_hosts:
576 my_host->destroy(my_host);
577 other_host->destroy(other_host);
578 }
579
580 /**
581 * Delete a connection from the list
582 */
583 static void stroke_del_conn(private_stroke_interface_t *this,
584 stroke_msg_t *msg, FILE *out)
585 {
586 iterator_t *peer_iter, *child_iter;
587 peer_cfg_t *peer, *child;
588
589 pop_string(msg, &(msg->del_conn.name));
590 DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
591
592 peer_iter = this->backend->create_peer_cfg_iterator(this->backend);
593 while (peer_iter->iterate(peer_iter, (void**)&peer))
594 {
595 /* remove peer config with such a name */
596 if (streq(peer->get_name(peer), msg->del_conn.name))
597 {
598 peer_iter->remove(peer_iter);
599 peer->destroy(peer);
600 continue;
601 }
602 /* remove any child with such a name */
603 child_iter = peer->create_child_cfg_iterator(peer);
604 while (child_iter->iterate(child_iter, (void**)&child))
605 {
606 if (streq(child->get_name(child), msg->del_conn.name))
607 {
608 child_iter->remove(child_iter);
609 child->destroy(child);
610 }
611 }
612 child_iter->destroy(child_iter);
613 }
614 peer_iter->destroy(peer_iter);
615
616 fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
617 }
618
619 /**
620 * get the child_cfg with the same name as the peer cfg
621 */
622 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
623 {
624 child_cfg_t *current, *found = NULL;
625 iterator_t *iterator;
626
627 iterator = peer_cfg->create_child_cfg_iterator(peer_cfg);
628 while (iterator->iterate(iterator, (void**)&current))
629 {
630 if (streq(current->get_name(current), name))
631 {
632 found = current;
633 found->get_ref(found);
634 break;
635 }
636 }
637 iterator->destroy(iterator);
638 return found;
639 }
640
641 /**
642 * initiate a connection by name
643 */
644 static void stroke_initiate(private_stroke_interface_t *this,
645 stroke_msg_t *msg, FILE *out)
646 {
647 initiate_job_t *job;
648 peer_cfg_t *peer_cfg;
649 child_cfg_t *child_cfg;
650 ike_sa_t *init_ike_sa = NULL;
651 signal_t signal;
652
653 pop_string(msg, &(msg->initiate.name));
654 DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
655
656 peer_cfg = this->backend->get_peer_cfg_by_name(this->backend,
657 msg->initiate.name);
658 if (peer_cfg == NULL)
659 {
660 if (msg->output_verbosity >= 0)
661 {
662 fprintf(out, "no config named '%s'\n", msg->initiate.name);
663 }
664 return;
665 }
666 if (peer_cfg->get_ike_version(peer_cfg) != 2)
667 {
668 DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
669 peer_cfg->get_ike_version(peer_cfg));
670 peer_cfg->destroy(peer_cfg);
671 return;
672 }
673
674 child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
675 if (child_cfg == NULL)
676 {
677 if (msg->output_verbosity >= 0)
678 {
679 fprintf(out, "no child config named '%s'\n", msg->initiate.name);
680 }
681 peer_cfg->destroy(peer_cfg);
682 return;
683 }
684
685 job = initiate_job_create(peer_cfg, child_cfg);
686 charon->bus->set_listen_state(charon->bus, TRUE);
687 charon->job_queue->add(charon->job_queue, (job_t*)job);
688 while (TRUE)
689 {
690 level_t level;
691 int thread;
692 ike_sa_t *ike_sa;
693 char* format;
694 va_list args;
695
696 signal = charon->bus->listen(charon->bus, &level, &thread, &ike_sa, &format, &args);
697
698 if ((init_ike_sa == NULL || ike_sa == init_ike_sa) &&
699 level <= msg->output_verbosity)
700 {
701 if (vfprintf(out, format, args) < 0 ||
702 fprintf(out, "\n") < 0 ||
703 fflush(out))
704 {
705 charon->bus->set_listen_state(charon->bus, FALSE);
706 break;
707 }
708 }
709
710 switch (signal)
711 {
712 case CHILD_UP_SUCCESS:
713 case CHILD_UP_FAILED:
714 case IKE_UP_FAILED:
715 if (ike_sa == init_ike_sa)
716 {
717 charon->bus->set_listen_state(charon->bus, FALSE);
718 return;
719 }
720 continue;
721 case CHILD_UP_START:
722 case IKE_UP_START:
723 if (init_ike_sa == NULL)
724 {
725 init_ike_sa = ike_sa;
726 }
727 continue;
728 default:
729 continue;
730 }
731 }
732 }
733
734 /**
735 * route/unroute a policy (install SPD entries)
736 */
737 static void stroke_route(private_stroke_interface_t *this,
738 stroke_msg_t *msg, FILE *out, bool route)
739 {
740 route_job_t *job;
741 peer_cfg_t *peer_cfg;
742 child_cfg_t *child_cfg;
743
744 pop_string(msg, &(msg->route.name));
745 DBG1(DBG_CFG, "received stroke: %s '%s'",
746 route ? "route" : "unroute", msg->route.name);
747
748 peer_cfg = this->backend->get_peer_cfg_by_name(this->backend, msg->route.name);
749 if (peer_cfg == NULL)
750 {
751 fprintf(out, "no config named '%s'\n", msg->route.name);
752 return;
753 }
754 if (peer_cfg->get_ike_version(peer_cfg) != 2)
755 {
756 peer_cfg->destroy(peer_cfg);
757 return;
758 }
759
760 child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
761 if (child_cfg == NULL)
762 {
763 fprintf(out, "no child config named '%s'\n", msg->route.name);
764 peer_cfg->destroy(peer_cfg);
765 return;
766 }
767 fprintf(out, "%s policy '%s'\n",
768 route ? "routing" : "unrouting", msg->route.name);
769 job = route_job_create(peer_cfg, child_cfg, route);
770 charon->job_queue->add(charon->job_queue, (job_t*)job);
771 }
772
773 /**
774 * terminate a connection by name
775 */
776 static void stroke_terminate(private_stroke_interface_t *this,
777 stroke_msg_t *msg, FILE *out)
778 {
779 char *string, *pos = NULL, *name = NULL;
780 u_int32_t id = 0;
781 bool child;
782 int len;
783 status_t status = SUCCESS;;
784 ike_sa_t *ike_sa;
785
786 pop_string(msg, &(msg->terminate.name));
787 string = msg->terminate.name;
788 DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
789
790 len = strlen(string);
791 if (len < 1)
792 {
793 DBG1(DBG_CFG, "error parsing string");
794 return;
795 }
796 switch (string[len-1])
797 {
798 case '}':
799 child = TRUE;
800 pos = strchr(string, '{');
801 break;
802 case ']':
803 child = FALSE;
804 pos = strchr(string, '[');
805 break;
806 default:
807 name = string;
808 child = FALSE;
809 break;
810 }
811
812 if (name)
813 { /* must be a single name */
814 DBG1(DBG_CFG, "check out by single name '%s'", name);
815 ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
816 name, child);
817 }
818 else if (pos == string + len - 2)
819 { /* must be name[] or name{} */
820 string[len-2] = '\0';
821 DBG1(DBG_CFG, "check out by name '%s'", string);
822 ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
823 string, child);
824 }
825 else
826 { /* must be name[123] or name{23} */
827 string[len-1] = '\0';
828 id = atoi(pos + 1);
829 if (id == 0)
830 {
831 DBG1(DBG_CFG, "error parsing string");
832 return;
833 }
834 DBG1(DBG_CFG, "check out by id '%d'", id);
835 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
836 id, child);
837 }
838 if (ike_sa == NULL)
839 {
840 DBG1(DBG_CFG, "no such IKE_SA found");
841 return;
842 }
843
844 if (!child)
845 {
846 status = ike_sa->delete(ike_sa);
847 }
848 else
849 {
850 child_sa_t *child_sa;
851 iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
852 while (iterator->iterate(iterator, (void**)&child_sa))
853 {
854 if ((id && id == child_sa->get_reqid(child_sa)) ||
855 (string && streq(string, child_sa->get_name(child_sa))))
856 {
857 u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
858 protocol_id_t proto = child_sa->get_protocol(child_sa);
859
860 status = ike_sa->delete_child_sa(ike_sa, proto, spi);
861 break;
862 }
863 }
864 iterator->destroy(iterator);
865 }
866 if (status == DESTROY_ME)
867 {
868 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
869 ike_sa);
870 return;
871 }
872 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
873 }
874
875 /**
876 * Add a ca information record to the cainfo list
877 */
878 static void stroke_add_ca(private_stroke_interface_t *this,
879 stroke_msg_t *msg, FILE *out)
880 {
881 x509_t *cacert;
882 ca_info_t *ca_info;
883
884 pop_string(msg, &msg->add_ca.name);
885 pop_string(msg, &msg->add_ca.cacert);
886 pop_string(msg, &msg->add_ca.crluri);
887 pop_string(msg, &msg->add_ca.crluri2);
888 pop_string(msg, &msg->add_ca.ocspuri);
889 pop_string(msg, &msg->add_ca.ocspuri2);
890
891 DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
892
893 DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
894 DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert);
895 DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri);
896 DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2);
897 DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri);
898 DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2);
899
900 if (msg->add_ca.cacert == NULL)
901 {
902 DBG1(DBG_CFG, "missing cacert parameter\n");
903 return;
904 }
905
906 cacert = load_ca_certificate(msg->add_ca.cacert);
907
908 if (cacert == NULL)
909 {
910 return;
911 }
912 ca_info = ca_info_create(msg->add_ca.name, cacert);
913
914 if (msg->add_ca.crluri)
915 {
916 chunk_t uri = { msg->add_ca.crluri, strlen(msg->add_ca.crluri) };
917
918 ca_info->add_crluri(ca_info, uri);
919 }
920 if (msg->add_ca.crluri2)
921 {
922 chunk_t uri = { msg->add_ca.crluri2, strlen(msg->add_ca.crluri2) };
923
924 ca_info->add_crluri(ca_info, uri);
925 }
926 if (msg->add_ca.ocspuri)
927 {
928 chunk_t uri = { msg->add_ca.ocspuri, strlen(msg->add_ca.ocspuri) };
929
930 ca_info->add_ocspuri(ca_info, uri);
931 }
932 if (msg->add_ca.ocspuri2)
933 {
934 chunk_t uri = { msg->add_ca.ocspuri2, strlen(msg->add_ca.ocspuri2) };
935
936 ca_info->add_ocspuri(ca_info, uri);
937 }
938 charon->credentials->add_ca_info(charon->credentials, ca_info);
939 DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name);
940
941 }
942
943 /**
944 * Delete a ca information record from the cainfo list
945 */
946 static void stroke_del_ca(private_stroke_interface_t *this,
947 stroke_msg_t *msg, FILE *out)
948 {
949 status_t status;
950
951 pop_string(msg, &(msg->del_ca.name));
952 DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
953
954 status = charon->credentials->release_ca_info(charon->credentials,
955 msg->del_ca.name);
956
957 if (status == SUCCESS)
958 {
959 fprintf(out, "deleted ca '%s'\n", msg->del_ca.name);
960 }
961 else
962 {
963 fprintf(out, "no ca named '%s'\n", msg->del_ca.name);
964 }
965 }
966
967 /**
968 * show status of daemon
969 */
970 static void stroke_status(private_stroke_interface_t *this,
971 stroke_msg_t *msg, FILE *out, bool all)
972 {
973 iterator_t *iterator, *children;
974 linked_list_t *list;
975 host_t *host;
976 peer_cfg_t *peer_cfg;
977 ike_cfg_t *ike_cfg;
978 child_cfg_t *child_cfg;
979 ike_sa_t *ike_sa;
980 char *name = NULL;
981 u_int32_t now = time(NULL);
982
983 if (msg->status.name)
984 {
985 pop_string(msg, &(msg->status.name));
986 name = msg->status.name;
987 }
988
989 if (all)
990 {
991 leak_detective_status(out);
992
993 fprintf(out, "Performance:\n");
994 fprintf(out, " worker threads: %d idle of %d,",
995 charon->thread_pool->get_idle_threads(charon->thread_pool),
996 charon->thread_pool->get_pool_size(charon->thread_pool));
997 fprintf(out, " job queue load: %d,",
998 charon->job_queue->get_count(charon->job_queue));
999 fprintf(out, " scheduled events: %d\n",
1000 charon->event_queue->get_count(charon->event_queue));
1001 list = charon->kernel_interface->create_address_list(charon->kernel_interface);
1002
1003 fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
1004 while (list->remove_first(list, (void**)&host) == SUCCESS)
1005 {
1006 fprintf(out, " %H\n", host);
1007 host->destroy(host);
1008 }
1009 list->destroy(list);
1010
1011 fprintf(out, "Connections:\n");
1012 iterator = this->backend->create_peer_cfg_iterator(this->backend);
1013 while (iterator->iterate(iterator, (void**)&peer_cfg))
1014 {
1015 if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
1016 (name && !streq(name, peer_cfg->get_name(peer_cfg))))
1017 {
1018 continue;
1019 }
1020
1021 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
1022 fprintf(out, "%12s: %H[%D]...%H[%D]\n", peer_cfg->get_name(peer_cfg),
1023 ike_cfg->get_my_host(ike_cfg), peer_cfg->get_my_id(peer_cfg),
1024 ike_cfg->get_other_host(ike_cfg), peer_cfg->get_other_id(peer_cfg));
1025 children = peer_cfg->create_child_cfg_iterator(peer_cfg);
1026 while (children->iterate(children, (void**)&child_cfg))
1027 {
1028 linked_list_t *my_ts, *other_ts;
1029 my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
1030 other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
1031 fprintf(out, "%12s: %#R=== %#R\n", child_cfg->get_name(child_cfg),
1032 my_ts, other_ts);
1033 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
1034 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
1035 }
1036 children->destroy(children);
1037 }
1038 iterator->destroy(iterator);
1039 }
1040
1041 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
1042 if (all && iterator->get_count(iterator) > 0)
1043 {
1044 fprintf(out, "Security Associations:\n");
1045 }
1046 while (iterator->iterate(iterator, (void**)&ike_sa))
1047 {
1048 bool ike_match = FALSE, ike_printed = FALSE;
1049 child_sa_t *child_sa;
1050 iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
1051
1052 if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
1053 {
1054 ike_match = TRUE;
1055 }
1056
1057 while (children->iterate(children, (void**)&child_sa))
1058 {
1059 bool child_match = FALSE;
1060
1061 if (name == NULL || streq(name, child_sa->get_name(child_sa)))
1062 {
1063 child_match = TRUE;
1064 }
1065
1066 if ((child_match || ike_match) && !ike_printed)
1067 {
1068 peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa);
1069 u_int32_t next;
1070
1071 fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
1072 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
1073 ike_sa_state_names, ike_sa->get_state(ike_sa),
1074 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
1075 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
1076
1077 if (all)
1078 {
1079 fprintf(out, "%12s[%d]: IKE SPIs: %J, ",
1080 ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
1081 ike_sa->get_id(ike_sa));
1082
1083 ike_sa->get_stats(ike_sa, &next);
1084 if (next)
1085 {
1086 fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ?
1087 "reauthentication" : "rekeying", &now, &next);
1088 }
1089 else
1090 {
1091 fprintf(out, "rekeying disabled\n");
1092 }
1093 }
1094
1095
1096 ike_printed = TRUE;
1097 }
1098
1099 if (child_match)
1100 {
1101 u_int32_t rekey;
1102 u_int32_t use_in, use_out, use_fwd;
1103 encryption_algorithm_t encr_alg;
1104 integrity_algorithm_t int_alg;
1105 size_t encr_len, int_len;
1106 mode_t mode;
1107
1108 child_sa->get_stats(child_sa, &mode, &encr_alg, &encr_len,
1109 &int_alg, &int_len, &rekey, &use_in, &use_out,
1110 &use_fwd);
1111
1112 fprintf(out, "%12s{%d}: %N, %N",
1113 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
1114 child_sa_state_names, child_sa->get_state(child_sa),
1115 mode_names, mode);
1116
1117 if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
1118 {
1119 fprintf(out, ", %N SPIs: 0x%0x_i 0x%0x_o",
1120 protocol_id_names, child_sa->get_protocol(child_sa),
1121 htonl(child_sa->get_spi(child_sa, TRUE)),
1122 htonl(child_sa->get_spi(child_sa, FALSE)));
1123
1124 if (all)
1125 {
1126 fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa),
1127 child_sa->get_reqid(child_sa));
1128
1129
1130 if (child_sa->get_protocol(child_sa) == PROTO_ESP)
1131 {
1132 fprintf(out, "%N", encryption_algorithm_names, encr_alg);
1133
1134 if (encr_len)
1135 {
1136 fprintf(out, "-%d", encr_len);
1137 }
1138 fprintf(out, "/");
1139 }
1140
1141 fprintf(out, "%N", integrity_algorithm_names, int_alg);
1142 if (int_len)
1143 {
1144 fprintf(out, "-%d", int_len);
1145 }
1146 fprintf(out, ", rekeying ");
1147
1148 if (rekey)
1149 {
1150 fprintf(out, "in %V", &now, &rekey);
1151 }
1152 else
1153 {
1154 fprintf(out, "disabled");
1155 }
1156
1157 fprintf(out, ", last use: ");
1158 use_in = max(use_in, use_fwd);
1159 if (use_in)
1160 {
1161 fprintf(out, "%ds_i ", now - use_in);
1162 }
1163 else
1164 {
1165 fprintf(out, "no_i ");
1166 }
1167 if (use_out)
1168 {
1169 fprintf(out, "%ds_o ", now - use_out);
1170 }
1171 else
1172 {
1173 fprintf(out, "no_o ");
1174 }
1175 }
1176 }
1177
1178 fprintf(out, "\n%12s{%d}: %#R=== %#R\n",
1179 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
1180 child_sa->get_traffic_selectors(child_sa, TRUE),
1181 child_sa->get_traffic_selectors(child_sa, FALSE));
1182 }
1183 }
1184 children->destroy(children);
1185 }
1186 iterator->destroy(iterator);
1187 }
1188
1189 /**
1190 * list all authority certificates matching a specified flag
1191 */
1192 static void list_auth_certificates(private_stroke_interface_t *this, u_int flag,
1193 const char *label, bool utc, FILE *out)
1194 {
1195 bool first = TRUE;
1196 x509_t *cert;
1197
1198 iterator_t *iterator = charon->credentials->create_auth_cert_iterator(charon->credentials);
1199
1200 while (iterator->iterate(iterator, (void**)&cert))
1201 {
1202 if (cert->has_authority_flag(cert, flag))
1203 {
1204 if (first)
1205 {
1206 fprintf(out, "\n");
1207 fprintf(out, "List of X.509 %s Certificates:\n", label);
1208 fprintf(out, "\n");
1209 first = FALSE;
1210 }
1211 fprintf(out, "%#Q\n", cert, utc);
1212 }
1213 }
1214 iterator->destroy(iterator);
1215 }
1216
1217 /**
1218 * list various information
1219 */
1220 static void stroke_list(private_stroke_interface_t *this,
1221 stroke_msg_t *msg, FILE *out)
1222 {
1223 iterator_t *iterator;
1224
1225 if (msg->list.flags & LIST_CERTS)
1226 {
1227 x509_t *cert;
1228
1229 iterator = charon->credentials->create_cert_iterator(charon->credentials);
1230 if (iterator->get_count(iterator))
1231 {
1232 fprintf(out, "\n");
1233 fprintf(out, "List of X.509 End Entity Certificates:\n");
1234 fprintf(out, "\n");
1235 }
1236 while (iterator->iterate(iterator, (void**)&cert))
1237 {
1238 fprintf(out, "%#Q", cert, msg->list.utc);
1239 if (charon->credentials->has_rsa_private_key(
1240 charon->credentials, cert->get_public_key(cert)))
1241 {
1242 fprintf(out, ", has private key");
1243 }
1244 fprintf(out, "\n");
1245
1246 }
1247 iterator->destroy(iterator);
1248 }
1249 if (msg->list.flags & LIST_CACERTS)
1250 {
1251 list_auth_certificates(this, AUTH_CA, "CA", msg->list.utc, out);
1252 }
1253 if (msg->list.flags & LIST_CAINFOS)
1254 {
1255 ca_info_t *ca_info;
1256
1257 iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1258 if (iterator->get_count(iterator))
1259 {
1260 fprintf(out, "\n");
1261 fprintf(out, "List of X.509 CA Information Records:\n");
1262 fprintf(out, "\n");
1263 }
1264 while (iterator->iterate(iterator, (void**)&ca_info))
1265 {
1266 fprintf(out, "%#W", ca_info, msg->list.utc);
1267 }
1268 iterator->destroy(iterator);
1269 }
1270 if (msg->list.flags & LIST_CRLS)
1271 {
1272 ca_info_t *ca_info;
1273 bool first = TRUE;
1274
1275 iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1276 while (iterator->iterate(iterator, (void **)&ca_info))
1277 {
1278 if (ca_info->has_crl(ca_info))
1279 {
1280 if (first)
1281 {
1282 fprintf(out, "\n");
1283 fprintf(out, "List of X.509 CRLs:\n");
1284 fprintf(out, "\n");
1285 first = FALSE;
1286 }
1287 ca_info->list_crl(ca_info, out, msg->list.utc);
1288 }
1289 }
1290 iterator->destroy(iterator);
1291 }
1292 if (msg->list.flags & LIST_OCSPCERTS)
1293 {
1294 list_auth_certificates(this, AUTH_OCSP, "OCSP", msg->list.utc, out);
1295 }
1296 if (msg->list.flags & LIST_OCSP)
1297 {
1298 ca_info_t *ca_info;
1299 bool first = TRUE;
1300
1301 iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1302 while (iterator->iterate(iterator, (void **)&ca_info))
1303 {
1304 if (ca_info->has_certinfos(ca_info))
1305 {
1306 if (first)
1307 {
1308 fprintf(out, "\n");
1309 fprintf(out, "List of OCSP responses:\n");
1310 first = FALSE;
1311 }
1312 fprintf(out, "\n");
1313 ca_info->list_certinfos(ca_info, out, msg->list.utc);
1314 }
1315 }
1316 iterator->destroy(iterator);
1317 }
1318 }
1319
1320 /**
1321 * reread various information
1322 */
1323 static void stroke_reread(private_stroke_interface_t *this,
1324 stroke_msg_t *msg, FILE *out)
1325 {
1326 if (msg->reread.flags & REREAD_CACERTS)
1327 {
1328 charon->credentials->load_ca_certificates(charon->credentials);
1329 }
1330 if (msg->reread.flags & REREAD_OCSPCERTS)
1331 {
1332 charon->credentials->load_ocsp_certificates(charon->credentials);
1333 }
1334 if (msg->reread.flags & REREAD_CRLS)
1335 {
1336 charon->credentials->load_crls(charon->credentials);
1337 }
1338 }
1339
1340 /**
1341 * purge various information
1342 */
1343 static void stroke_purge(private_stroke_interface_t *this,
1344 stroke_msg_t *msg, FILE *out)
1345 {
1346 if (msg->purge.flags & PURGE_OCSP)
1347 {
1348 iterator_t *iterator = charon->credentials->create_cainfo_iterator(charon->credentials);
1349 ca_info_t *ca_info;
1350
1351 while (iterator->iterate(iterator, (void**)&ca_info))
1352 {
1353 ca_info->purge_ocsp(ca_info);
1354 }
1355 iterator->destroy(iterator);
1356 }
1357 }
1358
1359 signal_t get_signal_from_logtype(char *type)
1360 {
1361 if (strcasecmp(type, "any") == 0) return SIG_ANY;
1362 else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
1363 else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
1364 else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
1365 else if (strcasecmp(type, "job") == 0) return DBG_JOB;
1366 else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
1367 else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
1368 else if (strcasecmp(type, "net") == 0) return DBG_NET;
1369 else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
1370 else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
1371 else return -1;
1372 }
1373
1374 /**
1375 * set the verbosity debug output
1376 */
1377 static void stroke_loglevel(private_stroke_interface_t *this,
1378 stroke_msg_t *msg, FILE *out)
1379 {
1380 signal_t signal;
1381
1382 pop_string(msg, &(msg->loglevel.type));
1383 DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
1384 msg->loglevel.level, msg->loglevel.type);
1385
1386 signal = get_signal_from_logtype(msg->loglevel.type);
1387 if (signal < 0)
1388 {
1389 fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
1390 return;
1391 }
1392
1393 charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
1394 charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
1395 }
1396
1397 /**
1398 * process a stroke request from the socket pointed by "fd"
1399 */
1400 static void stroke_process(private_stroke_interface_t *this, int strokefd)
1401 {
1402 stroke_msg_t *msg;
1403 u_int16_t msg_length;
1404 ssize_t bytes_read;
1405 FILE *out;
1406
1407 /* peek the length */
1408 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
1409 if (bytes_read != sizeof(msg_length))
1410 {
1411 DBG1(DBG_CFG, "reading length of stroke message failed");
1412 close(strokefd);
1413 return;
1414 }
1415
1416 /* read message */
1417 msg = malloc(msg_length);
1418 bytes_read = recv(strokefd, msg, msg_length, 0);
1419 if (bytes_read != msg_length)
1420 {
1421 DBG1(DBG_CFG, "reading stroke message failed: %m");
1422 close(strokefd);
1423 return;
1424 }
1425
1426 out = fdopen(dup(strokefd), "w");
1427 if (out == NULL)
1428 {
1429 DBG1(DBG_CFG, "opening stroke output channel failed: %m");
1430 close(strokefd);
1431 free(msg);
1432 return;
1433 }
1434
1435 DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
1436
1437 switch (msg->type)
1438 {
1439 case STR_INITIATE:
1440 stroke_initiate(this, msg, out);
1441 break;
1442 case STR_ROUTE:
1443 stroke_route(this, msg, out, TRUE);
1444 break;
1445 case STR_UNROUTE:
1446 stroke_route(this, msg, out, FALSE);
1447 break;
1448 case STR_TERMINATE:
1449 stroke_terminate(this, msg, out);
1450 break;
1451 case STR_STATUS:
1452 stroke_status(this, msg, out, FALSE);
1453 break;
1454 case STR_STATUS_ALL:
1455 stroke_status(this, msg, out, TRUE);
1456 break;
1457 case STR_ADD_CONN:
1458 stroke_add_conn(this, msg, out);
1459 break;
1460 case STR_DEL_CONN:
1461 stroke_del_conn(this, msg, out);
1462 break;
1463 case STR_ADD_CA:
1464 stroke_add_ca(this, msg, out);
1465 break;
1466 case STR_DEL_CA:
1467 stroke_del_ca(this, msg, out);
1468 break;
1469 case STR_LOGLEVEL:
1470 stroke_loglevel(this, msg, out);
1471 break;
1472 case STR_LIST:
1473 stroke_list(this, msg, out);
1474 break;
1475 case STR_REREAD:
1476 stroke_reread(this, msg, out);
1477 break;
1478 case STR_PURGE:
1479 stroke_purge(this, msg, out);
1480 break;
1481 default:
1482 DBG1(DBG_CFG, "received unknown stroke");
1483 }
1484 fclose(out);
1485 close(strokefd);
1486 free(msg);
1487 }
1488
1489 /**
1490 * Implementation of private_stroke_interface_t.stroke_receive.
1491 */
1492 static void stroke_receive(private_stroke_interface_t *this)
1493 {
1494 struct sockaddr_un strokeaddr;
1495 int strokeaddrlen = sizeof(strokeaddr);
1496 int oldstate;
1497 int strokefd;
1498
1499 /* ignore sigpipe. writing over the pipe back to the console
1500 * only fails if SIGPIPE is ignored. */
1501 signal(SIGPIPE, SIG_IGN);
1502
1503 /* disable cancellation by default */
1504 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1505
1506 while (TRUE)
1507 {
1508 /* wait for connections, but allow thread to terminate */
1509 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
1510 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
1511 pthread_setcancelstate(oldstate, NULL);
1512
1513 if (strokefd < 0)
1514 {
1515 DBG1(DBG_CFG, "accepting stroke connection failed: %m");
1516 continue;
1517 }
1518 stroke_process(this, strokefd);
1519 }
1520 }
1521
1522 /**
1523 * Implementation of stroke_t.destroy.
1524 */
1525 static void destroy(private_stroke_interface_t *this)
1526 {
1527 int i;
1528
1529 for (i = 0; i < STROKE_THREADS; i++)
1530 {
1531 pthread_cancel(this->threads[i]);
1532 pthread_join(this->threads[i], NULL);
1533 }
1534
1535 close(this->socket);
1536 unlink(socket_addr.sun_path);
1537 free(this);
1538 }
1539
1540 /*
1541 * Described in header-file
1542 */
1543 stroke_t *stroke_create(local_backend_t *backend)
1544 {
1545 private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t);
1546 mode_t old;
1547 int i;
1548
1549 /* public functions */
1550 this->public.destroy = (void (*)(stroke_t*))destroy;
1551
1552 this->backend = backend;
1553
1554 /* set up unix socket */
1555 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
1556 if (this->socket == -1)
1557 {
1558 DBG1(DBG_CFG, "could not create whack socket");
1559 free(this);
1560 return NULL;
1561 }
1562
1563 old = umask(~S_IRWXU);
1564 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
1565 {
1566 DBG1(DBG_CFG, "could not bind stroke socket: %m");
1567 close(this->socket);
1568 free(this);
1569 return NULL;
1570 }
1571 umask(old);
1572
1573 if (listen(this->socket, 0) < 0)
1574 {
1575 DBG1(DBG_CFG, "could not listen on stroke socket: %m");
1576 close(this->socket);
1577 unlink(socket_addr.sun_path);
1578 free(this);
1579 return NULL;
1580 }
1581
1582 /* start threads reading from the socket */
1583 for (i = 0; i < STROKE_THREADS; i++)
1584 {
1585 if (pthread_create(&this->threads[i], NULL, (void*(*)(void*))stroke_receive, this) != 0)
1586 {
1587 charon->kill(charon, "unable to create stroke thread");
1588 }
1589 }
1590
1591 return (&this->public);
1592 }