55a3b79c35740864e9700ff45176c75243973fd6
[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
34 #include "stroke_interface.h"
35
36 #include <stroke.h>
37 #include <types.h>
38 #include <daemon.h>
39 #include <crypto/x509.h>
40 #include <queues/jobs/initiate_job.h>
41 #include <queues/jobs/route_job.h>
42
43 #define IKE_PORT 500
44 #define PATH_BUF 256
45
46
47 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
48
49
50 typedef struct private_stroke_t private_stroke_t;
51
52 /**
53 * Private data of an stroke_t object.
54 */
55 struct private_stroke_t {
56
57 /**
58 * Public part of stroke_t object.
59 */
60 stroke_t public;
61
62 /**
63 * Assigned logger_t object in charon.
64 */
65 logger_t *logger;
66
67 /**
68 * Logger which logs to stroke
69 */
70 logger_t *stroke_logger;
71
72 /**
73 * Unix socket to listen for strokes
74 */
75 int socket;
76
77 /**
78 * Thread which reads from the \ 1ocket
79 */
80 pthread_t assigned_thread;
81
82 /**
83 * Read from the socket and handle stroke messages
84 */
85 void (*stroke_receive) (private_stroke_t *this);
86 };
87
88 /**
89 * Helper function which corrects the string pointers
90 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
91 * contains RELATIVE addresses (relative to the beginning of the
92 * stroke_msg). They must be corrected if they reach our address
93 * space...
94 */
95 static void pop_string(stroke_msg_t *msg, char **string)
96 {
97 if (*string == NULL)
98 return;
99
100 /* check for sanity of string pointer and string */
101 if (string < (char**)msg
102 || string > (char**)msg + sizeof(stroke_msg_t)
103 || (u_int)*string < (u_int)((char*)msg->buffer - (char*)msg)
104 || (u_int)*string > msg->length)
105 {
106 *string = "(invalid pointer in stroke msg)";
107 }
108 else
109 {
110 *string = (char*)msg + (u_int)*string;
111 }
112 }
113
114 /**
115 * Load end entitity certificate
116 */
117 static x509_t* load_end_certificate(const char *filename, identification_t **idp, logger_t *logger)
118 {
119 char path[PATH_BUF];
120 x509_t *cert;
121
122 if (*filename == '/')
123 {
124 /* absolute path name */
125 snprintf(path, sizeof(path), "%s", filename);
126 }
127 else
128 {
129 /* relative path name */
130 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
131 }
132
133 cert = x509_create_from_file(path, "end entity certificate");
134
135 if (cert)
136 {
137 identification_t *id = *idp;
138 identification_t *subject = cert->get_subject(cert);
139
140 err_t ugh = cert->is_valid(cert, NULL);
141
142 if (ugh != NULL)
143 {
144 logger->log(logger, ERROR, "warning: certificate %s", ugh);
145 }
146 if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
147 {
148 id->destroy(id);
149 id = subject;
150 *idp = id->clone(id);
151 }
152 return charon->credentials->add_end_certificate(charon->credentials, cert);
153 }
154 return NULL;
155 }
156
157 /**
158 * Add a connection to the configuration list
159 */
160 static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
161 {
162 connection_t *connection;
163 policy_t *policy;
164 identification_t *my_id, *other_id;
165 identification_t *my_ca = NULL;
166 identification_t *other_ca = NULL;
167 bool my_ca_same = FALSE;
168 bool other_ca_same =FALSE;
169 host_t *my_host, *other_host, *my_subnet, *other_subnet;
170 proposal_t *proposal;
171 traffic_selector_t *my_ts, *other_ts;
172
173 pop_string(msg, &msg->add_conn.name);
174 pop_string(msg, &msg->add_conn.me.address);
175 pop_string(msg, &msg->add_conn.other.address);
176 pop_string(msg, &msg->add_conn.me.subnet);
177 pop_string(msg, &msg->add_conn.other.subnet);
178 pop_string(msg, &msg->add_conn.me.id);
179 pop_string(msg, &msg->add_conn.other.id);
180 pop_string(msg, &msg->add_conn.me.cert);
181 pop_string(msg, &msg->add_conn.other.cert);
182 pop_string(msg, &msg->add_conn.me.ca);
183 pop_string(msg, &msg->add_conn.other.ca);
184 pop_string(msg, &msg->add_conn.me.updown);
185 pop_string(msg, &msg->add_conn.other.updown);
186 pop_string(msg, &msg->add_conn.algorithms.ike);
187 pop_string(msg, &msg->add_conn.algorithms.esp);
188
189 this->logger->log(this->logger, CONTROL,
190 "received stroke: add connection \"%s\"", msg->add_conn.name);
191
192 this->logger->log(this->logger, CONTROL|LEVEL2, "conn %s", msg->add_conn.name);
193 this->logger->log(this->logger, CONTROL|LEVEL2, " right=%s", msg->add_conn.me.address);
194 this->logger->log(this->logger, CONTROL|LEVEL2, " left=%s", msg->add_conn.other.address);
195 this->logger->log(this->logger, CONTROL|LEVEL2, " rightsubnet=%s", msg->add_conn.me.subnet);
196 this->logger->log(this->logger, CONTROL|LEVEL2, " leftsubnet=%s", msg->add_conn.other.subnet);
197 this->logger->log(this->logger, CONTROL|LEVEL2, " rightid=%s", msg->add_conn.me.id);
198 this->logger->log(this->logger, CONTROL|LEVEL2, " leftid=%s", msg->add_conn.other.id);
199 this->logger->log(this->logger, CONTROL|LEVEL2, " rightcert=%s", msg->add_conn.me.cert);
200 this->logger->log(this->logger, CONTROL|LEVEL2, " leftcert=%s", msg->add_conn.other.cert);
201 this->logger->log(this->logger, CONTROL|LEVEL2, " rightca=%s", msg->add_conn.me.ca);
202 this->logger->log(this->logger, CONTROL|LEVEL2, " leftca=%s", msg->add_conn.other.ca);
203 this->logger->log(this->logger, CONTROL|LEVEL2, " ike=%s", msg->add_conn.algorithms.ike);
204 this->logger->log(this->logger, CONTROL|LEVEL2, " esp=%s", msg->add_conn.algorithms.esp);
205
206 my_host = msg->add_conn.me.address?
207 host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
208 if (my_host == NULL)
209 {
210 this->stroke_logger->log(this->stroke_logger, ERROR,
211 "invalid host: %s", msg->add_conn.me.address);
212 return;
213 }
214
215 other_host = msg->add_conn.other.address ?
216 host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
217 if (other_host == NULL)
218 {
219 this->stroke_logger->log(this->stroke_logger, ERROR,
220 "invalid host: %s", msg->add_conn.other.address);
221 my_host->destroy(my_host);
222 return;
223 }
224
225 if (charon->socket->is_local_address(charon->socket, other_host))
226 {
227 stroke_end_t tmp_end;
228 host_t *tmp_host;
229
230 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
231 "left is other host, swapping ends");
232
233 tmp_host = my_host;
234 my_host = other_host;
235 other_host = tmp_host;
236
237 tmp_end = msg->add_conn.me;
238 msg->add_conn.me = msg->add_conn.other;
239 msg->add_conn.other = tmp_end;
240 }
241 else if (!charon->socket->is_local_address(charon->socket, my_host))
242 {
243 this->stroke_logger->log(this->stroke_logger, ERROR,
244 "left nor right host is our side, aborting");
245 goto destroy_hosts;
246 }
247
248 my_id = identification_create_from_string(msg->add_conn.me.id ?
249 msg->add_conn.me.id : msg->add_conn.me.address);
250 if (my_id == NULL)
251 {
252 this->stroke_logger->log(this->stroke_logger, ERROR,
253 "invalid id: %s", msg->add_conn.me.id);
254 goto destroy_hosts;
255 }
256
257 other_id = identification_create_from_string(msg->add_conn.other.id ?
258 msg->add_conn.other.id : msg->add_conn.other.address);
259 if (other_id == NULL)
260 {
261 this->stroke_logger->log(this->stroke_logger, ERROR,
262 "invalid id: %s", msg->add_conn.other.id);
263 my_id->destroy(my_id);
264 goto destroy_hosts;
265 }
266
267 my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
268 msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
269 if (my_subnet == NULL)
270 {
271 this->stroke_logger->log(this->stroke_logger, ERROR,
272 "invalid subnet: %s", msg->add_conn.me.subnet);
273 goto destroy_ids;
274 }
275
276 other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
277 msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
278 if (other_subnet == NULL)
279 {
280 this->stroke_logger->log(this->stroke_logger, ERROR,
281 "invalid subnet: %s", msg->add_conn.me.subnet);
282 my_subnet->destroy(my_subnet);
283 goto destroy_ids;
284 }
285
286 my_ts = traffic_selector_create_from_subnet(my_subnet,
287 msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 0,
288 msg->add_conn.me.protocol, msg->add_conn.me.port);
289 my_subnet->destroy(my_subnet);
290
291 other_ts = traffic_selector_create_from_subnet(other_subnet,
292 msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 0,
293 msg->add_conn.other.protocol, msg->add_conn.other.port);
294 other_subnet->destroy(other_subnet);
295
296 if (msg->add_conn.me.ca)
297 {
298 if (streq(msg->add_conn.me.ca, "%same"))
299 {
300 my_ca_same = TRUE;
301 }
302 else
303 {
304 my_ca = identification_create_from_string(msg->add_conn.me.ca);
305 }
306 }
307 if (msg->add_conn.other.ca)
308 {
309 if (streq(msg->add_conn.other.ca, "%same"))
310 {
311 other_ca_same = TRUE;
312 }
313 else
314 {
315 other_ca = identification_create_from_string(msg->add_conn.other.ca);
316 }
317 }
318 if (msg->add_conn.me.cert)
319 {
320 x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id, this->logger);
321
322 if (my_ca == NULL && !my_ca_same && cert)
323 {
324 identification_t *issuer = cert->get_issuer(cert);
325
326 my_ca = issuer->clone(issuer);
327 }
328 }
329 if (msg->add_conn.other.cert)
330 {
331 x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id, this->logger);
332
333 if (other_ca == NULL && !other_ca_same && cert)
334 {
335 identification_t *issuer = cert->get_issuer(cert);
336
337 other_ca = issuer->clone(issuer);
338 }
339 }
340 if (other_ca_same && my_ca)
341 {
342 other_ca = my_ca->clone(my_ca);
343 }
344 else if (my_ca_same && other_ca)
345 {
346 my_ca = other_ca->clone(other_ca);
347 }
348 if (my_ca == NULL)
349 {
350 my_ca = identification_create_from_string("%any");
351 }
352 if (other_ca == NULL)
353 {
354 other_ca = identification_create_from_string("%any");
355 }
356 this->logger->log(this->logger, CONTROL|LEVEL1, " my ca: '%s'", my_ca->get_string(my_ca));
357 this->logger->log(this->logger, CONTROL|LEVEL1, " other ca:'%s'", other_ca->get_string(other_ca));
358 this->logger->log(this->logger, CONTROL|LEVEL1, " updown:'%s'", msg->add_conn.me.updown);
359
360 connection = connection_create(msg->add_conn.name,
361 msg->add_conn.ikev2,
362 msg->add_conn.me.sendcert,
363 msg->add_conn.other.sendcert,
364 my_host, other_host,
365 RSA_DIGITAL_SIGNATURE,
366 msg->add_conn.dpd.delay,
367 msg->add_conn.rekey.tries,
368 msg->add_conn.rekey.ike_lifetime,
369 msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin,
370 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100);
371
372 if (msg->add_conn.algorithms.ike)
373 {
374 char *proposal_string;
375 char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
376
377 if (*strict == '!')
378 *strict = '\0';
379 else
380 strict = NULL;
381
382 while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
383 {
384 proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
385 if (proposal == NULL)
386 {
387 this->logger->log(this->logger, ERROR, "invalid IKE proposal string: %s", msg->add_conn.algorithms.esp);
388 my_id->destroy(my_id);
389 other_id->destroy(other_id);
390 my_ts->destroy(my_ts);
391 other_ts->destroy(other_ts);
392 my_ca->destroy(my_ca);
393 other_ca->destroy(other_ca);
394 connection->destroy(connection);
395 return;
396 }
397 connection->add_proposal(connection, proposal);
398 }
399 if (!strict)
400 {
401 proposal = proposal_create_default(PROTO_IKE);
402 connection->add_proposal(connection, proposal);
403 }
404 }
405 else
406 {
407 proposal = proposal_create_default(PROTO_IKE);
408 connection->add_proposal(connection, proposal);
409 }
410
411 policy = policy_create(msg->add_conn.name, my_id, other_id,
412 msg->add_conn.rekey.ipsec_lifetime,
413 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
414 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100,
415 msg->add_conn.me.updown, msg->add_conn.dpd.route);
416 policy->add_my_traffic_selector(policy, my_ts);
417 policy->add_other_traffic_selector(policy, other_ts);
418 policy->add_authorities(policy, my_ca, other_ca);
419
420 if (msg->add_conn.algorithms.esp)
421 {
422 char *proposal_string;
423 char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
424
425 if (*strict == '!')
426 *strict = '\0';
427 else
428 strict = NULL;
429
430 while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
431 {
432 proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
433 if (proposal == NULL)
434 {
435 this->logger->log(this->logger, ERROR,
436 "invalid ESP proposal string: %s", msg->add_conn.algorithms.esp);
437 policy->destroy(policy);
438 connection->destroy(connection);
439 return;
440 }
441 policy->add_proposal(policy, proposal);
442 }
443 if (!strict)
444 {
445 proposal = proposal_create_default(PROTO_ESP);
446 policy->add_proposal(policy, proposal);
447 }
448 }
449 else
450 {
451 proposal = proposal_create_default(PROTO_ESP);
452 policy->add_proposal(policy, proposal);
453 }
454
455 /* add to global connection list */
456 charon->connections->add_connection(charon->connections, connection);
457 this->logger->log(this->logger, CONTROL, "added connection \"%s\": %s[%s]...%s[%s]",
458 msg->add_conn.name,
459 my_host->get_string(my_host),
460 my_id->get_string(my_id),
461 other_host->get_string(other_host),
462 other_id->get_string(other_id));
463 /* add to global policy list */
464 charon->policies->add_policy(charon->policies, policy);
465 return;
466
467 /* mopping up after parsing errors */
468
469 destroy_ids:
470 my_id->destroy(my_id);
471 other_id->destroy(other_id);
472
473 destroy_hosts:
474 my_host->destroy(my_host);
475 other_host->destroy(other_host);
476 }
477
478 /**
479 * Delete a connection from the list
480 */
481 static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg)
482 {
483 status_t status;
484
485 pop_string(msg, &(msg->del_conn.name));
486 this->logger->log(this->logger, CONTROL, "received stroke: delete \"%s\"", msg->del_conn.name);
487
488 status = charon->connections->delete_connection(charon->connections,
489 msg->del_conn.name);
490 charon->policies->delete_policy(charon->policies, msg->del_conn.name);
491 if (status == SUCCESS)
492 {
493 this->stroke_logger->log(this->stroke_logger, CONTROL,
494 "Deleted connection '%s'", msg->del_conn.name);
495 }
496 else
497 {
498 this->stroke_logger->log(this->stroke_logger, ERROR,
499 "No connection named '%s'", msg->del_conn.name);
500 }
501 }
502
503 /**
504 * initiate a connection by name
505 */
506 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
507 {
508 initiate_job_t *job;
509 connection_t *connection;
510 policy_t *policy;
511
512 pop_string(msg, &(msg->initiate.name));
513 this->logger->log(this->logger, CONTROL,
514 "received stroke: initiate \"%s\"",
515 msg->initiate.name);
516
517 connection = charon->connections->get_connection_by_name(charon->connections,
518 msg->initiate.name);
519 if (connection == NULL)
520 {
521 this->stroke_logger->log(this->stroke_logger, ERROR,
522 "no connection named \"%s\"",
523 msg->initiate.name);
524 return;
525 }
526 if (!connection->is_ikev2(connection))
527 {
528 connection->destroy(connection);
529 return;
530 }
531
532 policy = charon->policies->get_policy_by_name(charon->policies,
533 msg->initiate.name);
534 if (policy == NULL)
535 {
536 this->stroke_logger->log(this->stroke_logger, ERROR,
537 "no policy named \"%s\"",
538 msg->initiate.name);
539 connection->destroy(connection);
540 return;
541 }
542 this->stroke_logger->log(this->stroke_logger, CONTROL,
543 "initiating connection \"%s\" (see log)...",
544 msg->initiate.name);
545 job = initiate_job_create(connection, policy);
546 charon->job_queue->add(charon->job_queue, (job_t*)job);
547 }
548
549 /**
550 * route/unroute a policy (install SPD entries)
551 */
552 static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, bool route)
553 {
554 route_job_t *job;
555 connection_t *connection;
556 policy_t *policy;
557
558 pop_string(msg, &(msg->route.name));
559 this->logger->log(this->logger, CONTROL,
560 "received stroke: %s \"%s\"",
561 route ? "route" : "unroute",
562 msg->route.name);
563
564 /* we wouldn't need a connection, but we only want to route policies
565 * whose connections are keyexchange=ikev2. */
566 connection = charon->connections->get_connection_by_name(charon->connections,
567 msg->route.name);
568 if (connection == NULL)
569 {
570 this->stroke_logger->log(this->stroke_logger, ERROR,
571 "no connection named \"%s\"",
572 msg->route.name);
573 return;
574 }
575 if (!connection->is_ikev2(connection))
576 {
577 connection->destroy(connection);
578 return;
579 }
580
581 policy = charon->policies->get_policy_by_name(charon->policies,
582 msg->route.name);
583 if (policy == NULL)
584 {
585 this->stroke_logger->log(this->stroke_logger, ERROR,
586 "no policy named \"%s\"",
587 msg->route.name);
588 connection->destroy(connection);
589 return;
590 }
591 this->stroke_logger->log(this->stroke_logger, CONTROL,
592 "%s policy \"%s\"",
593 route ? "routing" : "unrouting",
594 msg->route.name);
595 job = route_job_create(connection, policy, route);
596 charon->job_queue->add(charon->job_queue, (job_t*)job);
597 }
598
599 /**
600 * terminate a connection by name
601 */
602 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
603 {
604 linked_list_t *ike_sas;
605 iterator_t *iterator;
606 int instances = 0;
607 connection_t *conn;
608
609 pop_string(msg, &(msg->terminate.name));
610 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
611
612 /* we have to do tricky tricks to give the most comprehensive output to the user.
613 * There are different cases:
614 * 1. Connection is available, but IKEv1:
615 * => just ignore it, let pluto print it
616 * 2. Connection is not available, but instances of a deleted connection template:
617 * => terminate them, and print their termination
618 * 3. Connection is not available, and and no instances are there:
619 * => show error about bad connection name
620 * 4. An IKEv2 connection is available, and may contain instances:
621 * => terminate and print, simple
622 */
623 conn = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name);
624 if (conn == NULL || conn->is_ikev2(conn))
625 {
626 ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->terminate.name);
627
628 iterator = ike_sas->create_iterator(ike_sas, TRUE);
629 while (iterator->has_next(iterator))
630 {
631 ike_sa_id_t *ike_sa_id;
632 iterator->current(iterator, (void**)&ike_sa_id);
633 charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id);
634 ike_sa_id->destroy(ike_sa_id);
635 instances++;
636 }
637 iterator->destroy(iterator);
638 ike_sas->destroy(ike_sas);
639 if (conn == NULL && instances == 0)
640 {
641 this->stroke_logger->log(this->stroke_logger, CONTROL,
642 "no connection named \"%s\"",
643 msg->terminate.name);
644 }
645 else
646 {
647 this->stroke_logger->log(this->stroke_logger, CONTROL,
648 "terminated %d instances of \"%s\"",
649 instances, msg->terminate.name);
650 }
651 }
652 if (conn)
653 {
654 conn->destroy(conn);
655 }
656 }
657
658 /**
659 * show status of (established) connections
660 */
661 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
662 {
663 linked_list_t *list;
664 host_t *host;
665
666 list = charon->socket->create_local_address_list(charon->socket);
667 this->logger->log(this->logger, CONTROL|LEVEL1,
668 "listening on %d addresses:",
669 list->get_count(list));
670 while (list->remove_first(list, (void**)&host) == SUCCESS)
671 {
672 this->logger->log(this->logger, CONTROL|LEVEL1,
673 " %s", host->get_string(host));
674 host->destroy(host);
675
676 }
677 list->destroy(list);
678
679 if (msg->status.name)
680 {
681 pop_string(msg, &(msg->status.name));
682 }
683 charon->connections->log_connections(charon->connections, this->stroke_logger, msg->status.name);
684 charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name);
685 }
686
687 /**
688 * list various information
689 */
690 static void stroke_list(private_stroke_t *this, stroke_msg_t *msg)
691 {
692 if (msg->list.flags & LIST_CERTS)
693 {
694 charon->credentials->log_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
695 }
696 if (msg->list.flags & LIST_CACERTS)
697 {
698 charon->credentials->log_ca_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
699 }
700 if (msg->list.flags & LIST_CRLS)
701 {
702 charon->credentials->log_crls(charon->credentials, this->stroke_logger, msg->list.utc);
703 }
704 }
705
706 /**
707 * reread various information
708 */
709 static void stroke_reread(private_stroke_t *this, stroke_msg_t *msg)
710 {
711 if (msg->reread.flags & REREAD_CACERTS)
712 {
713 charon->credentials->load_ca_certificates(charon->credentials);
714 }
715 if (msg->reread.flags & REREAD_CRLS)
716 {
717 charon->credentials->load_crls(charon->credentials);
718 }
719 }
720
721 logger_context_t get_context(char *context)
722 {
723 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
724 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
725 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
726 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
727 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
728 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
729 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
730 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
731 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
732 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
733 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
734 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
735 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
736 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
737 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
738 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
739 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
740 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
741 else if (strcasecmp(context, "XFRM") == 0) return XFRM;
742 else return -2;
743 }
744
745 /**
746 * set the type of logged messages in a context
747 */
748 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
749 {
750 pop_string(msg, &(msg->logtype.context));
751 pop_string(msg, &(msg->logtype.type));
752
753 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
754
755 log_level_t level;
756 logger_context_t context = get_context(msg->logtype.context);
757 if (context == -2)
758 {
759 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
760 return;
761 }
762
763 if (strcasecmp(msg->logtype.type, "CONTROL") == 0)
764 level = CONTROL;
765 else if (strcasecmp(msg->logtype.type, "ERROR") == 0)
766 level = ERROR;
767 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0)
768 level = AUDIT;
769 else if (strcasecmp(msg->logtype.type, "RAW") == 0)
770 level = RAW;
771 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0)
772 level = PRIVATE;
773 else
774 {
775 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
776 return;
777 }
778
779 if (msg->logtype.enable)
780 {
781 logger_manager->enable_log_level(logger_manager, context, level);
782 }
783 else
784 {
785 logger_manager->disable_log_level(logger_manager, context, level);
786 }
787 }
788
789 /**
790 * set the verbosity of a logger
791 */
792 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
793 {
794 log_level_t level;
795 logger_context_t context;
796
797 pop_string(msg, &(msg->loglevel.context));
798 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
799
800 context = get_context(msg->loglevel.context);
801 if (context == -2)
802 {
803 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
804 return;
805 }
806
807 if (msg->loglevel.level == 0)
808 level = LEVEL0;
809 else if (msg->loglevel.level == 1)
810 level = LEVEL1;
811 else if (msg->loglevel.level == 2)
812 level = LEVEL2;
813 else if (msg->loglevel.level == 3)
814 level = LEVEL3;
815 else
816 {
817 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
818 return;
819 }
820
821 logger_manager->enable_log_level(logger_manager, context, level);
822 }
823
824 /**
825 * Implementation of private_stroke_t.stroke_receive.
826 */
827 static void stroke_receive(private_stroke_t *this)
828 {
829 stroke_msg_t *msg;
830 u_int16_t msg_length;
831 struct sockaddr_un strokeaddr;
832 int strokeaddrlen = sizeof(strokeaddr);
833 ssize_t bytes_read;
834 int strokefd;
835 FILE *strokefile;
836 int oldstate;
837
838 /* disable cancellation by default */
839 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
840
841 while (1)
842 {
843 /* wait for connections, but allow thread to terminate */
844 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
845 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
846 pthread_setcancelstate(oldstate, NULL);
847
848 if (strokefd < 0)
849 {
850 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
851 continue;
852 }
853
854 /* peek the length */
855 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
856 if (bytes_read != sizeof(msg_length))
857 {
858 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
859 close(strokefd);
860 continue;
861 }
862
863 /* read message */
864 msg = malloc(msg_length);
865 bytes_read = recv(strokefd, msg, msg_length, 0);
866 if (bytes_read != msg_length)
867 {
868 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
869 close(strokefd);
870 continue;
871 }
872
873 strokefile = fdopen(dup(strokefd), "w");
874 if (strokefile == NULL)
875 {
876 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
877 close(strokefd);
878 free(msg);
879 continue;
880 }
881
882 /* setup a logger which writes status to the unix socket */
883 this->stroke_logger = logger_create("", CONTROL|ERROR, FALSE, strokefile);
884
885 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
886
887 switch (msg->type)
888 {
889 case STR_INITIATE:
890 stroke_initiate(this, msg);
891 break;
892 case STR_ROUTE:
893 stroke_route(this, msg, TRUE);
894 break;
895 case STR_UNROUTE:
896 stroke_route(this, msg, FALSE);
897 break;
898 case STR_TERMINATE:
899 stroke_terminate(this, msg);
900 break;
901 case STR_STATUS:
902 stroke_status(this, msg);
903 break;
904 case STR_STATUS_ALL:
905 this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
906 stroke_status(this, msg);
907 break;
908 case STR_ADD_CONN:
909 stroke_add_conn(this, msg);
910 break;
911 case STR_DEL_CONN:
912 stroke_del_conn(this, msg);
913 break;
914 case STR_LOGTYPE:
915 stroke_logtype(this, msg);
916 break;
917 case STR_LOGLEVEL:
918 stroke_loglevel(this, msg);
919 break;
920 case STR_LIST:
921 stroke_list(this, msg);
922 break;
923 case STR_REREAD:
924 stroke_reread(this, msg);
925 break;
926 default:
927 this->logger->log(this->logger, ERROR, "received invalid stroke");
928 }
929 this->stroke_logger->destroy(this->stroke_logger);
930 fclose(strokefile);
931 close(strokefd);
932 free(msg);
933 }
934 }
935
936 /**
937 * Implementation of stroke_t.destroy.
938 */
939 static void destroy(private_stroke_t *this)
940 {
941
942 pthread_cancel(this->assigned_thread);
943 pthread_join(this->assigned_thread, NULL);
944
945 close(this->socket);
946 unlink(socket_addr.sun_path);
947 free(this);
948 }
949
950
951 /*
952 * Described in header-file
953 */
954 stroke_t *stroke_create()
955 {
956 private_stroke_t *this = malloc_thing(private_stroke_t);
957 mode_t old;
958
959 /* public functions */
960 this->public.destroy = (void (*)(stroke_t*))destroy;
961
962 /* private functions */
963 this->stroke_receive = stroke_receive;
964
965 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
966
967 /* set up unix socket */
968 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
969 if (this->socket == -1)
970 {
971 this->logger->log(this->logger, ERROR, "could not create whack socket");
972 free(this);
973 return NULL;
974 }
975
976 old = umask(~S_IRWXU);
977 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
978 {
979 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
980 close(this->socket);
981 free(this);
982 return NULL;
983 }
984 umask(old);
985
986 if (listen(this->socket, 0) < 0)
987 {
988 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
989 close(this->socket);
990 unlink(socket_addr.sun_path);
991 free(this);
992 return NULL;
993 }
994
995 /* start a thread reading from the socket */
996 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
997 {
998 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
999 close(this->socket);
1000 unlink(socket_addr.sun_path);
1001 free(this);
1002 return NULL;
1003 }
1004
1005 return (&this->public);
1006 }