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