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