prepared support of ca information records and ocsp functionality
[strongswan.git] / src / charon / threads / stroke_interface.c
1 /**
2 * @file stroke.c
3 *
4 * @brief Implementation of stroke_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 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/crl.h>
42 #include <queues/jobs/initiate_job.h>
43 #include <queues/jobs/route_job.h>
44 #include <utils/leak_detective.h>
45
46 #define IKE_PORT 500
47 #define PATH_BUF 256
48
49
50 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
51
52
53 typedef struct private_stroke_t private_stroke_t;
54
55 /**
56 * Private data of an stroke_t object.
57 */
58 struct private_stroke_t {
59
60 /**
61 * Public part of stroke_t object.
62 */
63 stroke_t public;
64
65 /**
66 * Output stream (stroke console)
67 */
68 FILE *out;
69
70 /**
71 * Unix socket to listen for strokes
72 */
73 int socket;
74
75 /**
76 * Thread which reads from the Socket
77 */
78 pthread_t assigned_thread;
79 };
80
81 /**
82 * Helper function which corrects the string pointers
83 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
84 * contains RELATIVE addresses (relative to the beginning of the
85 * stroke_msg). They must be corrected if they reach our address
86 * space...
87 */
88 static void pop_string(stroke_msg_t *msg, char **string)
89 {
90 if (*string == NULL)
91 return;
92
93 /* check for sanity of string pointer and string */
94 if (string < (char**)msg
95 || string > (char**)msg + sizeof(stroke_msg_t)
96 || (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg)
97 || (unsigned long)*string > msg->length)
98 {
99 *string = "(invalid pointer in stroke msg)";
100 }
101 else
102 {
103 *string = (char*)msg + (unsigned long)*string;
104 }
105 }
106
107 /**
108 * Load end entitity certificate
109 */
110 static x509_t* load_end_certificate(const char *filename, identification_t **idp)
111 {
112 char path[PATH_BUF];
113 x509_t *cert;
114
115 if (*filename == '/')
116 {
117 /* absolute path name */
118 snprintf(path, sizeof(path), "%s", filename);
119 }
120 else
121 {
122 /* relative path name */
123 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
124 }
125
126 cert = x509_create_from_file(path, "end entity certificate");
127
128 if (cert)
129 {
130 identification_t *id = *idp;
131 identification_t *subject = cert->get_subject(cert);
132
133 err_t ugh = cert->is_valid(cert, NULL);
134
135 if (ugh != NULL)
136 {
137 DBG1(DBG_CFG, "warning: certificate %s", ugh);
138 }
139 if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
140 {
141 id->destroy(id);
142 id = subject;
143 *idp = id->clone(id);
144 }
145 return charon->credentials->add_end_certificate(charon->credentials, cert);
146 }
147 return NULL;
148 }
149
150 /**
151 * Add a connection to the configuration list
152 */
153 static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
154 {
155 connection_t *connection;
156 policy_t *policy;
157 identification_t *my_id, *other_id;
158 identification_t *my_ca = NULL;
159 identification_t *other_ca = NULL;
160 bool my_ca_same = FALSE;
161 bool other_ca_same =FALSE;
162 host_t *my_host, *other_host, *my_subnet, *other_subnet;
163 proposal_t *proposal;
164 traffic_selector_t *my_ts, *other_ts;
165
166 pop_string(msg, &msg->add_conn.name);
167 pop_string(msg, &msg->add_conn.me.address);
168 pop_string(msg, &msg->add_conn.other.address);
169 pop_string(msg, &msg->add_conn.me.subnet);
170 pop_string(msg, &msg->add_conn.other.subnet);
171 pop_string(msg, &msg->add_conn.me.id);
172 pop_string(msg, &msg->add_conn.other.id);
173 pop_string(msg, &msg->add_conn.me.cert);
174 pop_string(msg, &msg->add_conn.other.cert);
175 pop_string(msg, &msg->add_conn.me.ca);
176 pop_string(msg, &msg->add_conn.other.ca);
177 pop_string(msg, &msg->add_conn.me.updown);
178 pop_string(msg, &msg->add_conn.other.updown);
179 pop_string(msg, &msg->add_conn.algorithms.ike);
180 pop_string(msg, &msg->add_conn.algorithms.esp);
181
182 DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
183
184 DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
185 DBG2(DBG_CFG, " right=%s", msg->add_conn.me.address);
186 DBG2(DBG_CFG, " left=%s", msg->add_conn.other.address);
187 DBG2(DBG_CFG, " rightsubnet=%s", msg->add_conn.me.subnet);
188 DBG2(DBG_CFG, " leftsubnet=%s", msg->add_conn.other.subnet);
189 DBG2(DBG_CFG, " rightid=%s", msg->add_conn.me.id);
190 DBG2(DBG_CFG, " leftid=%s", msg->add_conn.other.id);
191 DBG2(DBG_CFG, " rightcert=%s", msg->add_conn.me.cert);
192 DBG2(DBG_CFG, " leftcert=%s", msg->add_conn.other.cert);
193 DBG2(DBG_CFG, " rightca=%s", msg->add_conn.me.ca);
194 DBG2(DBG_CFG, " leftca=%s", msg->add_conn.other.ca);
195 DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
196 DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
197
198 my_host = msg->add_conn.me.address?
199 host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
200 if (my_host == NULL)
201 {
202 DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.me.address);
203 return;
204 }
205
206 other_host = msg->add_conn.other.address ?
207 host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
208 if (other_host == NULL)
209 {
210 DBG1(DBG_CFG, "invalid host: %s\n", msg->add_conn.other.address);
211 my_host->destroy(my_host);
212 return;
213 }
214
215 if (charon->socket->is_local_address(charon->socket, other_host, NULL))
216 {
217 stroke_end_t tmp_end;
218 host_t *tmp_host;
219
220 DBG2(DBG_CFG, "left is other host, swapping ends\n");
221
222 tmp_host = my_host;
223 my_host = other_host;
224 other_host = tmp_host;
225
226 tmp_end = msg->add_conn.me;
227 msg->add_conn.me = msg->add_conn.other;
228 msg->add_conn.other = tmp_end;
229 }
230 else if (!charon->socket->is_local_address(charon->socket, my_host, NULL))
231 {
232 DBG1(DBG_CFG, "left nor right host is our side, aborting\n");
233 goto destroy_hosts;
234 }
235
236 my_id = identification_create_from_string(msg->add_conn.me.id ?
237 msg->add_conn.me.id : msg->add_conn.me.address);
238 if (my_id == NULL)
239 {
240 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.me.id);
241 goto destroy_hosts;
242 }
243
244 other_id = identification_create_from_string(msg->add_conn.other.id ?
245 msg->add_conn.other.id : msg->add_conn.other.address);
246 if (other_id == NULL)
247 {
248 DBG1(DBG_CFG, "invalid ID: %s\n", msg->add_conn.other.id);
249 my_id->destroy(my_id);
250 goto destroy_hosts;
251 }
252
253 my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
254 msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
255 if (my_subnet == NULL)
256 {
257 DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
258 goto destroy_ids;
259 }
260
261 other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
262 msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
263 if (other_subnet == NULL)
264 {
265 DBG1(DBG_CFG, "invalid subnet: %s\n", msg->add_conn.me.subnet);
266 my_subnet->destroy(my_subnet);
267 goto destroy_ids;
268 }
269
270 my_ts = traffic_selector_create_from_subnet(my_subnet,
271 msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0,
272 msg->add_conn.me.protocol, msg->add_conn.me.port);
273 my_subnet->destroy(my_subnet);
274
275 other_ts = traffic_selector_create_from_subnet(other_subnet,
276 msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0,
277 msg->add_conn.other.protocol, msg->add_conn.other.port);
278 other_subnet->destroy(other_subnet);
279
280 if (msg->add_conn.me.ca)
281 {
282 if (streq(msg->add_conn.me.ca, "%same"))
283 {
284 my_ca_same = TRUE;
285 }
286 else
287 {
288 my_ca = identification_create_from_string(msg->add_conn.me.ca);
289 }
290 }
291 if (msg->add_conn.other.ca)
292 {
293 if (streq(msg->add_conn.other.ca, "%same"))
294 {
295 other_ca_same = TRUE;
296 }
297 else
298 {
299 other_ca = identification_create_from_string(msg->add_conn.other.ca);
300 }
301 }
302 if (msg->add_conn.me.cert)
303 {
304 x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id);
305
306 if (my_ca == NULL && !my_ca_same && cert)
307 {
308 identification_t *issuer = cert->get_issuer(cert);
309
310 my_ca = issuer->clone(issuer);
311 }
312 }
313 if (msg->add_conn.other.cert)
314 {
315 x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id);
316
317 if (other_ca == NULL && !other_ca_same && cert)
318 {
319 identification_t *issuer = cert->get_issuer(cert);
320
321 other_ca = issuer->clone(issuer);
322 }
323 }
324 if (other_ca_same && my_ca)
325 {
326 other_ca = my_ca->clone(my_ca);
327 }
328 else if (my_ca_same && other_ca)
329 {
330 my_ca = other_ca->clone(other_ca);
331 }
332 if (my_ca == NULL)
333 {
334 my_ca = identification_create_from_string("%any");
335 }
336 if (other_ca == NULL)
337 {
338 other_ca = identification_create_from_string("%any");
339 }
340 DBG2(DBG_CFG, " my ca: '%D'", my_ca);
341 DBG2(DBG_CFG, " other ca:'%D'", other_ca);
342 DBG2(DBG_CFG, " updown: '%s'", msg->add_conn.me.updown);
343
344 connection = connection_create(msg->add_conn.name,
345 msg->add_conn.ikev2,
346 msg->add_conn.me.sendcert,
347 msg->add_conn.other.sendcert,
348 my_host, other_host,
349 msg->add_conn.dpd.delay,
350 msg->add_conn.rekey.reauth,
351 msg->add_conn.rekey.tries,
352 msg->add_conn.rekey.ike_lifetime,
353 msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
354 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100);
355
356 if (msg->add_conn.algorithms.ike)
357 {
358 char *proposal_string;
359 char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
360
361 if (*strict == '!')
362 *strict = '\0';
363 else
364 strict = NULL;
365
366 while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
367 {
368 proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
369 if (proposal == NULL)
370 {
371 DBG1(DBG_CFG, "invalid IKE proposal string: %s", proposal_string);
372 my_id->destroy(my_id);
373 other_id->destroy(other_id);
374 my_ts->destroy(my_ts);
375 other_ts->destroy(other_ts);
376 my_ca->destroy(my_ca);
377 other_ca->destroy(other_ca);
378 connection->destroy(connection);
379 return;
380 }
381 connection->add_proposal(connection, proposal);
382 }
383 if (!strict)
384 {
385 proposal = proposal_create_default(PROTO_IKE);
386 connection->add_proposal(connection, proposal);
387 }
388 }
389 else
390 {
391 proposal = proposal_create_default(PROTO_IKE);
392 connection->add_proposal(connection, proposal);
393 }
394
395 policy = policy_create(msg->add_conn.name, my_id, other_id,
396 msg->add_conn.auth_method, msg->add_conn.eap_type,
397 msg->add_conn.rekey.ipsec_lifetime,
398 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
399 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
400 msg->add_conn.me.updown, msg->add_conn.me.hostaccess,
401 msg->add_conn.mode, msg->add_conn.dpd.action);
402 policy->add_my_traffic_selector(policy, my_ts);
403 policy->add_other_traffic_selector(policy, other_ts);
404 policy->add_authorities(policy, my_ca, other_ca);
405
406 if (msg->add_conn.algorithms.esp)
407 {
408 char *proposal_string;
409 char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
410
411 if (*strict == '!')
412 *strict = '\0';
413 else
414 strict = NULL;
415
416 while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
417 {
418 proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
419 if (proposal == NULL)
420 {
421 DBG1(DBG_CFG, "invalid ESP proposal string: %s", proposal_string);
422 policy->destroy(policy);
423 connection->destroy(connection);
424 return;
425 }
426 policy->add_proposal(policy, proposal);
427 }
428 if (!strict)
429 {
430 proposal = proposal_create_default(PROTO_ESP);
431 policy->add_proposal(policy, proposal);
432 }
433 }
434 else
435 {
436 proposal = proposal_create_default(PROTO_ESP);
437 policy->add_proposal(policy, proposal);
438 }
439
440 /* add to global connection list */
441 charon->connections->add_connection(charon->connections, connection);
442 DBG1(DBG_CFG, "added connection '%s': %H[%D]...%H[%D]",
443 msg->add_conn.name, my_host, my_id, other_host, other_id);
444 /* add to global policy list */
445 charon->policies->add_policy(charon->policies, policy);
446
447 return;
448
449 /* mopping up after parsing errors */
450
451 destroy_ids:
452 my_id->destroy(my_id);
453 other_id->destroy(other_id);
454
455 destroy_hosts:
456 my_host->destroy(my_host);
457 other_host->destroy(other_host);
458 }
459
460 /**
461 * Delete a connection from the list
462 */
463 static void stroke_del_conn(stroke_msg_t *msg, FILE *out)
464 {
465 status_t status;
466
467 pop_string(msg, &(msg->del_conn.name));
468 DBG1(DBG_CFG, "received stroke: delete '%s'", msg->del_conn.name);
469
470 status = charon->connections->delete_connection(charon->connections,
471 msg->del_conn.name);
472 charon->policies->delete_policy(charon->policies, msg->del_conn.name);
473 if (status == SUCCESS)
474 {
475 fprintf(out, "deleted connection '%s'\n", msg->del_conn.name);
476 }
477 else
478 {
479 fprintf(out, "no connection named '%s'\n", msg->del_conn.name);
480 }
481 }
482
483 /**
484 * initiate a connection by name
485 */
486 static void stroke_initiate(stroke_msg_t *msg, FILE *out)
487 {
488 initiate_job_t *job;
489 connection_t *connection;
490 policy_t *policy;
491 ike_sa_t *init_ike_sa = NULL;
492 signal_t signal;
493
494 pop_string(msg, &(msg->initiate.name));
495 DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
496
497 connection = charon->connections->get_connection_by_name(charon->connections,
498 msg->initiate.name);
499 if (connection == NULL)
500 {
501 if (msg->output_verbosity >= 0)
502 {
503 fprintf(out, "no connection named '%s'\n", msg->initiate.name);
504 }
505 return;
506 }
507 if (!connection->is_ikev2(connection))
508 {
509 connection->destroy(connection);
510 return;
511 }
512
513 policy = charon->policies->get_policy_by_name(charon->policies,
514 msg->initiate.name);
515 if (policy == NULL)
516 {
517 if (msg->output_verbosity >= 0)
518 {
519 fprintf(out, "no policy named '%s'\n", msg->initiate.name);
520 }
521 connection->destroy(connection);
522 return;
523 }
524
525 job = initiate_job_create(connection, NULL, policy);
526 /*
527 if (msg->output_verbosity < 0)
528 {
529 TODO: detach immediately if verbosity is SILENT. Local credential store
530 is not threadsave yet, so this would cause crashes!!
531 charon->job_queue->add(charon->job_queue, (job_t*)job);
532 return;
533 }*/
534
535 charon->bus->set_listen_state(charon->bus, TRUE);
536 charon->job_queue->add(charon->job_queue, (job_t*)job);
537 while (TRUE)
538 {
539 level_t level;
540 int thread;
541 ike_sa_t *ike_sa;
542 char* format;
543 va_list args;
544
545 signal = charon->bus->listen(charon->bus, &level, &thread, &ike_sa, &format, &args);
546
547 if ((init_ike_sa == NULL || ike_sa == init_ike_sa) &&
548 level <= msg->output_verbosity)
549 {
550 if (vfprintf(out, format, args) < 0 ||
551 fprintf(out, "\n") < 0 ||
552 fflush(out))
553 {
554 charon->bus->set_listen_state(charon->bus, FALSE);
555 break;
556 }
557 }
558
559 switch (signal)
560 {
561 case CHILD_UP_SUCCESS:
562 case CHILD_UP_FAILED:
563 case IKE_UP_FAILED:
564 if (ike_sa == init_ike_sa)
565 {
566 charon->bus->set_listen_state(charon->bus, FALSE);
567 return;
568 }
569 continue;
570 case CHILD_UP_START:
571 case IKE_UP_START:
572 if (init_ike_sa == NULL)
573 {
574 init_ike_sa = ike_sa;
575 }
576 continue;
577 default:
578 continue;
579 }
580 }
581 }
582
583 /**
584 * route/unroute a policy (install SPD entries)
585 */
586 static void stroke_route(stroke_msg_t *msg, FILE *out, bool route)
587 {
588 route_job_t *job;
589 connection_t *connection;
590 policy_t *policy;
591
592 pop_string(msg, &(msg->route.name));
593 DBG1(DBG_CFG, "received stroke: %s '%s'",
594 route ? "route" : "unroute", msg->route.name);
595
596 /* we wouldn't need a connection, but we only want to route policies
597 * whose connections are keyexchange=ikev2. */
598 connection = charon->connections->get_connection_by_name(charon->connections,
599 msg->route.name);
600 if (connection == NULL)
601 {
602 fprintf(out, "no connection named '%s'\n", msg->route.name);
603 return;
604 }
605 if (!connection->is_ikev2(connection))
606 {
607 connection->destroy(connection);
608 return;
609 }
610
611 policy = charon->policies->get_policy_by_name(charon->policies,
612 msg->route.name);
613 if (policy == NULL)
614 {
615 fprintf(out, "no policy named '%s'\n", msg->route.name);
616 connection->destroy(connection);
617 return;
618 }
619 fprintf(out, "%s policy '%s'\n",
620 route ? "routing" : "unrouting", msg->route.name);
621 job = route_job_create(connection, policy, route);
622 charon->job_queue->add(charon->job_queue, (job_t*)job);
623 }
624
625 /**
626 * terminate a connection by name
627 */
628 static void stroke_terminate(stroke_msg_t *msg, FILE *out)
629 {
630 pop_string(msg, &(msg->terminate.name));
631 DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
632
633 charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name);
634 }
635
636 /**
637 * Add a ca information record to the cainfo list
638 */
639 static void stroke_add_ca(stroke_msg_t *msg, FILE *out)
640 {
641 /* TODO add code */
642 }
643
644 /**
645 * Delete a ca information record from the cainfo list
646 */
647 static void stroke_del_ca(stroke_msg_t *msg, FILE *out)
648 {
649 /* TODO add code */
650 }
651
652 /**
653 * show status of daemon
654 */
655 static void stroke_statusall(stroke_msg_t *msg, FILE *out)
656 {
657 iterator_t *iterator;
658 linked_list_t *list;
659 host_t *host;
660 connection_t *connection;
661 policy_t *policy;
662 ike_sa_t *ike_sa;
663 char *name = NULL;
664
665 leak_detective_status(out);
666
667 fprintf(out, "Performance:\n");
668 fprintf(out, " worker threads: %d idle of %d,",
669 charon->thread_pool->get_idle_threads(charon->thread_pool),
670 charon->thread_pool->get_pool_size(charon->thread_pool));
671 fprintf(out, " job queue load: %d,",
672 charon->job_queue->get_count(charon->job_queue));
673 fprintf(out, " scheduled events: %d\n",
674 charon->event_queue->get_count(charon->event_queue));
675 list = charon->socket->create_local_address_list(charon->socket);
676
677 fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
678 while (list->remove_first(list, (void**)&host) == SUCCESS)
679 {
680 fprintf(out, " %H\n", host);
681 host->destroy(host);
682 }
683 list->destroy(list);
684
685 if (msg->status.name)
686 {
687 pop_string(msg, &(msg->status.name));
688 name = msg->status.name;
689 }
690
691 iterator = charon->connections->create_iterator(charon->connections);
692 if (iterator->get_count(iterator) > 0)
693 {
694 fprintf(out, "Connections:\n");
695 }
696 while (iterator->iterate(iterator, (void**)&connection))
697 {
698 if (connection->is_ikev2(connection)
699 && (name == NULL || streq(name, connection->get_name(connection))))
700 {
701 fprintf(out, "%12s: %H...%H\n",
702 connection->get_name(connection),
703 connection->get_my_host(connection),
704 connection->get_other_host(connection));
705 }
706 }
707 iterator->destroy(iterator);
708
709 iterator = charon->policies->create_iterator(charon->policies);
710 if (iterator->get_count(iterator) > 0)
711 {
712 fprintf(out, "Policies:\n");
713 }
714 while (iterator->iterate(iterator, (void**)&policy))
715 {
716 if (name == NULL || streq(name, policy->get_name(policy)))
717 {
718 fprintf(out, "%12s: '%D'...'%D'\n",
719 policy->get_name(policy),
720 policy->get_my_id(policy),
721 policy->get_other_id(policy));
722 }
723 }
724 iterator->destroy(iterator);
725
726 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
727 if (iterator->get_count(iterator) > 0)
728 {
729 fprintf(out, "Security Associations:\n");
730 }
731 while (iterator->iterate(iterator, (void**)&ike_sa))
732 {
733 bool ike_sa_printed = FALSE;
734 child_sa_t *child_sa;
735 iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
736
737 /* print IKE_SA */
738 if (name == NULL || strncmp(name, ike_sa->get_name(ike_sa), strlen(name)) == 0)
739 {
740 fprintf(out, "%#K\n", ike_sa);
741 ike_sa_printed = TRUE;
742 }
743
744 while (children->iterate(children, (void**)&child_sa))
745 {
746 bool child_sa_match = name == NULL ||
747 strncmp(name, child_sa->get_name(child_sa), strlen(name)) == 0;
748
749 /* print IKE_SA if its name differs from the CHILD_SA's name */
750 if (!ike_sa_printed && child_sa_match)
751 {
752 fprintf(out, "%#K\n", ike_sa);
753 ike_sa_printed = TRUE;
754 }
755
756 /* print CHILD_SA */
757 if (child_sa_match)
758 {
759 fprintf(out, "%#P\n", child_sa);
760 }
761 }
762 children->destroy(children);
763 }
764 iterator->destroy(iterator);
765 }
766
767 /**
768 * show status of daemon
769 */
770 static void stroke_status(stroke_msg_t *msg, FILE *out)
771 {
772 iterator_t *iterator;
773 ike_sa_t *ike_sa;
774 char *name = NULL;
775
776 if (msg->status.name)
777 {
778 pop_string(msg, &(msg->status.name));
779 name = msg->status.name;
780 }
781
782 iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
783 while (iterator->iterate(iterator, (void**)&ike_sa))
784 {
785 bool ike_sa_printed = FALSE;
786 child_sa_t *child_sa;
787 iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
788
789 /* print IKE_SA */
790 if (name == NULL || strncmp(name, ike_sa->get_name(ike_sa), strlen(name)) == 0)
791 {
792 fprintf(out, "%K\n", ike_sa);
793 ike_sa_printed = TRUE;
794 }
795
796 while (children->iterate(children, (void**)&child_sa))
797 {
798 bool child_sa_match = name == NULL ||
799 strncmp(name, child_sa->get_name(child_sa), strlen(name)) == 0;
800
801 /* print IKE_SA if its name differs from the CHILD_SA's name */
802 if (!ike_sa_printed && child_sa_match)
803 {
804 fprintf(out, "%K\n", ike_sa);
805 ike_sa_printed = TRUE;
806 }
807
808 /* print CHILD_SA */
809 if (child_sa_match)
810 {
811 fprintf(out, "%P\n", child_sa);
812 }
813 }
814 children->destroy(children);
815 }
816 iterator->destroy(iterator);
817 }
818
819 /**
820 * list various information
821 */
822 static void stroke_list(stroke_msg_t *msg, FILE *out)
823 {
824 iterator_t *iterator;
825
826 if (msg->list.flags & LIST_CERTS)
827 {
828 x509_t *cert;
829
830 iterator = charon->credentials->create_cert_iterator(charon->credentials);
831 if (iterator->get_count(iterator))
832 {
833 fprintf(out, "\n");
834 fprintf(out, "List of X.509 End Entity Certificates:\n");
835 fprintf(out, "\n");
836 }
837 while (iterator->iterate(iterator, (void**)&cert))
838 {
839 fprintf(out, "%#Q", cert, msg->list.utc);
840 if (charon->credentials->has_rsa_private_key(
841 charon->credentials, cert->get_public_key(cert)))
842 {
843 fprintf(out, ", has private key");
844 }
845 fprintf(out, "\n");
846
847 }
848 iterator->destroy(iterator);
849 }
850 if (msg->list.flags & LIST_CACERTS)
851 {
852 x509_t *cert;
853
854 iterator = charon->credentials->create_cacert_iterator(charon->credentials);
855 if (iterator->get_count(iterator))
856 {
857 fprintf(out, "\n");
858 fprintf(out, "List of X.509 CA Certificates:\n");
859 fprintf(out, "\n");
860 }
861 while (iterator->iterate(iterator, (void**)&cert))
862 {
863 fprintf(out, "%#Q\n", cert, msg->list.utc);
864 }
865 iterator->destroy(iterator);
866 }
867 if (msg->list.flags & LIST_CRLS)
868 {
869 crl_t *crl;
870
871 iterator = charon->credentials->create_crl_iterator(charon->credentials);
872 if (iterator->get_count(iterator))
873 {
874 fprintf(out, "\n");
875 fprintf(out, "List of X.509 CRLs:\n");
876 fprintf(out, "\n");
877 }
878 while (iterator->iterate(iterator, (void**)&crl))
879 {
880 fprintf(out, "%#U\n", crl, msg->list.utc);
881 }
882 iterator->destroy(iterator);
883 }
884 }
885
886 /**
887 * reread various information
888 */
889 static void stroke_reread(stroke_msg_t *msg, FILE *out)
890 {
891 if (msg->reread.flags & REREAD_CACERTS)
892 {
893 charon->credentials->load_ca_certificates(charon->credentials);
894 }
895 if (msg->reread.flags & REREAD_CRLS)
896 {
897 charon->credentials->load_crls(charon->credentials);
898 }
899 }
900
901 /**
902 * purge various information
903 */
904 static void stroke_purge(stroke_msg_t *msg, FILE *out)
905 {
906 if (msg->purge.flags & PURGE_OCSP)
907 {
908 /* TODO charon->credentials->purge_ocsp(charon->credentials); */
909 }
910 }
911
912 signal_t get_signal_from_logtype(char *type)
913 {
914 if (strcasecmp(type, "any") == 0) return SIG_ANY;
915 else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
916 else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
917 else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
918 else if (strcasecmp(type, "job") == 0) return DBG_JOB;
919 else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
920 else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
921 else if (strcasecmp(type, "net") == 0) return DBG_NET;
922 else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
923 else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
924 else return -1;
925 }
926
927 /**
928 * set the verbosity debug output
929 */
930 static void stroke_loglevel(stroke_msg_t *msg, FILE *out)
931 {
932 signal_t signal;
933
934 pop_string(msg, &(msg->loglevel.type));
935 DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
936 msg->loglevel.level, msg->loglevel.type);
937
938 signal = get_signal_from_logtype(msg->loglevel.type);
939 if (signal < 0)
940 {
941 fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
942 return;
943 }
944
945 charon->outlog->set_level(charon->outlog, signal, msg->loglevel.level);
946 charon->syslog->set_level(charon->syslog, signal, msg->loglevel.level);
947 }
948
949 /**
950 * process a stroke request from the socket pointed by "fd"
951 */
952 static void stroke_process(int *fd)
953 {
954 stroke_msg_t *msg;
955 u_int16_t msg_length;
956 ssize_t bytes_read;
957 FILE *out;
958 int strokefd = *fd;
959
960 /* peek the length */
961 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
962 if (bytes_read != sizeof(msg_length))
963 {
964 DBG1(DBG_CFG, "reading length of stroke message failed");
965 close(strokefd);
966 return;
967 }
968
969 /* read message */
970 msg = malloc(msg_length);
971 bytes_read = recv(strokefd, msg, msg_length, 0);
972 if (bytes_read != msg_length)
973 {
974 DBG1(DBG_CFG, "reading stroke message failed: %m");
975 close(strokefd);
976 return;
977 }
978
979 out = fdopen(dup(strokefd), "w");
980 if (out == NULL)
981 {
982 DBG1(DBG_CFG, "opening stroke output channel failed: %m");
983 close(strokefd);
984 free(msg);
985 return;
986 }
987
988 DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
989
990 switch (msg->type)
991 {
992 case STR_INITIATE:
993 stroke_initiate(msg, out);
994 break;
995 case STR_ROUTE:
996 stroke_route(msg, out, TRUE);
997 break;
998 case STR_UNROUTE:
999 stroke_route(msg, out, FALSE);
1000 break;
1001 case STR_TERMINATE:
1002 stroke_terminate(msg, out);
1003 break;
1004 case STR_STATUS:
1005 stroke_status(msg, out);
1006 break;
1007 case STR_STATUS_ALL:
1008 stroke_statusall(msg, out);
1009 break;
1010 case STR_ADD_CONN:
1011 stroke_add_conn(msg, out);
1012 break;
1013 case STR_DEL_CONN:
1014 stroke_del_conn(msg, out);
1015 break;
1016 case STR_ADD_CA:
1017 stroke_add_ca(msg, out);
1018 break;
1019 case STR_DEL_CA:
1020 stroke_del_ca(msg, out);
1021 break;
1022 case STR_LOGLEVEL:
1023 stroke_loglevel(msg, out);
1024 break;
1025 case STR_LIST:
1026 stroke_list(msg, out);
1027 break;
1028 case STR_REREAD:
1029 stroke_reread(msg, out);
1030 break;
1031 case STR_PURGE:
1032 stroke_purge(msg, out);
1033 break;
1034 default:
1035 DBG1(DBG_CFG, "received unknown stroke");
1036 }
1037 fclose(out);
1038 close(strokefd);
1039 free(msg);
1040 }
1041
1042 /**
1043 * Implementation of private_stroke_t.stroke_receive.
1044 */
1045 static void stroke_receive(private_stroke_t *this)
1046 {
1047 struct sockaddr_un strokeaddr;
1048 int strokeaddrlen = sizeof(strokeaddr);
1049 int strokefd;
1050 int oldstate;
1051 pthread_t thread;
1052
1053 /* ignore sigpipe. writing over the pipe back to the console
1054 * only fails if SIGPIPE is ignored. */
1055 signal(SIGPIPE, SIG_IGN);
1056
1057 /* disable cancellation by default */
1058 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1059
1060 while (TRUE)
1061 {
1062 /* wait for connections, but allow thread to terminate */
1063 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
1064 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
1065 pthread_setcancelstate(oldstate, NULL);
1066
1067 if (strokefd < 0)
1068 {
1069 DBG1(DBG_CFG, "accepting stroke connection failed: %m");
1070 continue;
1071 }
1072
1073 /* handle request asynchronously */
1074 if (pthread_create(&thread, NULL, (void*(*)(void*))stroke_process, (void*)&strokefd) != 0)
1075 {
1076 DBG1(DBG_CFG, "failed to spawn stroke thread: %m");
1077 }
1078 /* detach so the thread terminates cleanly */
1079 pthread_detach(thread);
1080 }
1081 }
1082
1083 /**
1084 * Implementation of stroke_t.destroy.
1085 */
1086 static void destroy(private_stroke_t *this)
1087 {
1088 pthread_cancel(this->assigned_thread);
1089 pthread_join(this->assigned_thread, NULL);
1090
1091 close(this->socket);
1092 unlink(socket_addr.sun_path);
1093 free(this);
1094 }
1095
1096 /*
1097 * Described in header-file
1098 */
1099 stroke_t *stroke_create()
1100 {
1101 private_stroke_t *this = malloc_thing(private_stroke_t);
1102 mode_t old;
1103
1104 /* public functions */
1105 this->public.destroy = (void (*)(stroke_t*))destroy;
1106
1107 /* set up unix socket */
1108 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
1109 if (this->socket == -1)
1110 {
1111 DBG1(DBG_CFG, "could not create whack socket");
1112 free(this);
1113 return NULL;
1114 }
1115
1116 old = umask(~S_IRWXU);
1117 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
1118 {
1119 DBG1(DBG_CFG, "could not bind stroke socket: %m");
1120 close(this->socket);
1121 free(this);
1122 return NULL;
1123 }
1124 umask(old);
1125
1126 if (listen(this->socket, 0) < 0)
1127 {
1128 DBG1(DBG_CFG, "could not listen on stroke socket: %m");
1129 close(this->socket);
1130 unlink(socket_addr.sun_path);
1131 free(this);
1132 return NULL;
1133 }
1134
1135 /* start a thread reading from the socket */
1136 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))stroke_receive, this) != 0)
1137 {
1138 DBG1(DBG_CFG, "could not spawn stroke thread");
1139 close(this->socket);
1140 unlink(socket_addr.sun_path);
1141 free(this);
1142 return NULL;
1143 }
1144
1145 return (&this->public);
1146 }