3c84415f465e5c69597a6ad48197e8b3f327ff23
[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, NULL))
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, NULL))
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.action);
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 pop_string(msg, &(msg->terminate.name));
605 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
606
607 charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name);
608 }
609
610 /**
611 * show status of (established) connections
612 */
613 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
614 {
615 linked_list_t *list;
616 host_t *host;
617
618 list = charon->socket->create_local_address_list(charon->socket);
619 this->logger->log(this->logger, CONTROL|LEVEL1,
620 "listening on %d addresses:",
621 list->get_count(list));
622 while (list->remove_first(list, (void**)&host) == SUCCESS)
623 {
624 this->logger->log(this->logger, CONTROL|LEVEL1,
625 " %s", host->get_string(host));
626 host->destroy(host);
627
628 }
629 list->destroy(list);
630
631 if (msg->status.name)
632 {
633 pop_string(msg, &(msg->status.name));
634 }
635 charon->connections->log_connections(charon->connections, this->stroke_logger, msg->status.name);
636 charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name);
637 }
638
639 /**
640 * list various information
641 */
642 static void stroke_list(private_stroke_t *this, stroke_msg_t *msg)
643 {
644 if (msg->list.flags & LIST_CERTS)
645 {
646 charon->credentials->log_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
647 }
648 if (msg->list.flags & LIST_CACERTS)
649 {
650 charon->credentials->log_ca_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
651 }
652 if (msg->list.flags & LIST_CRLS)
653 {
654 charon->credentials->log_crls(charon->credentials, this->stroke_logger, msg->list.utc);
655 }
656 }
657
658 /**
659 * reread various information
660 */
661 static void stroke_reread(private_stroke_t *this, stroke_msg_t *msg)
662 {
663 if (msg->reread.flags & REREAD_CACERTS)
664 {
665 charon->credentials->load_ca_certificates(charon->credentials);
666 }
667 if (msg->reread.flags & REREAD_CRLS)
668 {
669 charon->credentials->load_crls(charon->credentials);
670 }
671 }
672
673 logger_context_t get_context(char *context)
674 {
675 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
676 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
677 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
678 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
679 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
680 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
681 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
682 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
683 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
684 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
685 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
686 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
687 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
688 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
689 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
690 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
691 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
692 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
693 else if (strcasecmp(context, "XFRM") == 0) return XFRM;
694 else return -2;
695 }
696
697 /**
698 * set the type of logged messages in a context
699 */
700 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
701 {
702 pop_string(msg, &(msg->logtype.context));
703 pop_string(msg, &(msg->logtype.type));
704
705 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
706
707 log_level_t level;
708 logger_context_t context = get_context(msg->logtype.context);
709 if (context == -2)
710 {
711 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
712 return;
713 }
714
715 if (strcasecmp(msg->logtype.type, "CONTROL") == 0)
716 level = CONTROL;
717 else if (strcasecmp(msg->logtype.type, "ERROR") == 0)
718 level = ERROR;
719 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0)
720 level = AUDIT;
721 else if (strcasecmp(msg->logtype.type, "RAW") == 0)
722 level = RAW;
723 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0)
724 level = PRIVATE;
725 else
726 {
727 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
728 return;
729 }
730
731 if (msg->logtype.enable)
732 {
733 logger_manager->enable_log_level(logger_manager, context, level);
734 }
735 else
736 {
737 logger_manager->disable_log_level(logger_manager, context, level);
738 }
739 }
740
741 /**
742 * set the verbosity of a logger
743 */
744 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
745 {
746 log_level_t level;
747 logger_context_t context;
748
749 pop_string(msg, &(msg->loglevel.context));
750 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
751
752 context = get_context(msg->loglevel.context);
753 if (context == -2)
754 {
755 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
756 return;
757 }
758
759 if (msg->loglevel.level == 0)
760 level = LEVEL0;
761 else if (msg->loglevel.level == 1)
762 level = LEVEL1;
763 else if (msg->loglevel.level == 2)
764 level = LEVEL2;
765 else if (msg->loglevel.level == 3)
766 level = LEVEL3;
767 else
768 {
769 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
770 return;
771 }
772
773 logger_manager->enable_log_level(logger_manager, context, level);
774 }
775
776 /**
777 * Implementation of private_stroke_t.stroke_receive.
778 */
779 static void stroke_receive(private_stroke_t *this)
780 {
781 stroke_msg_t *msg;
782 u_int16_t msg_length;
783 struct sockaddr_un strokeaddr;
784 int strokeaddrlen = sizeof(strokeaddr);
785 ssize_t bytes_read;
786 int strokefd;
787 FILE *strokefile;
788 int oldstate;
789
790 /* disable cancellation by default */
791 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
792
793 while (1)
794 {
795 /* wait for connections, but allow thread to terminate */
796 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
797 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
798 pthread_setcancelstate(oldstate, NULL);
799
800 if (strokefd < 0)
801 {
802 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
803 continue;
804 }
805
806 /* peek the length */
807 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
808 if (bytes_read != sizeof(msg_length))
809 {
810 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
811 close(strokefd);
812 continue;
813 }
814
815 /* read message */
816 msg = malloc(msg_length);
817 bytes_read = recv(strokefd, msg, msg_length, 0);
818 if (bytes_read != msg_length)
819 {
820 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
821 close(strokefd);
822 continue;
823 }
824
825 strokefile = fdopen(dup(strokefd), "w");
826 if (strokefile == NULL)
827 {
828 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
829 close(strokefd);
830 free(msg);
831 continue;
832 }
833
834 /* setup a logger which writes status to the unix socket */
835 this->stroke_logger = logger_create("", CONTROL|ERROR, FALSE, strokefile);
836
837 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
838
839 switch (msg->type)
840 {
841 case STR_INITIATE:
842 stroke_initiate(this, msg);
843 break;
844 case STR_ROUTE:
845 stroke_route(this, msg, TRUE);
846 break;
847 case STR_UNROUTE:
848 stroke_route(this, msg, FALSE);
849 break;
850 case STR_TERMINATE:
851 stroke_terminate(this, msg);
852 break;
853 case STR_STATUS:
854 stroke_status(this, msg);
855 break;
856 case STR_STATUS_ALL:
857 this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
858 stroke_status(this, msg);
859 break;
860 case STR_ADD_CONN:
861 stroke_add_conn(this, msg);
862 break;
863 case STR_DEL_CONN:
864 stroke_del_conn(this, msg);
865 break;
866 case STR_LOGTYPE:
867 stroke_logtype(this, msg);
868 break;
869 case STR_LOGLEVEL:
870 stroke_loglevel(this, msg);
871 break;
872 case STR_LIST:
873 stroke_list(this, msg);
874 break;
875 case STR_REREAD:
876 stroke_reread(this, msg);
877 break;
878 default:
879 this->logger->log(this->logger, ERROR, "received invalid stroke");
880 }
881 this->stroke_logger->destroy(this->stroke_logger);
882 fclose(strokefile);
883 close(strokefd);
884 free(msg);
885 }
886 }
887
888 /**
889 * Implementation of stroke_t.destroy.
890 */
891 static void destroy(private_stroke_t *this)
892 {
893
894 pthread_cancel(this->assigned_thread);
895 pthread_join(this->assigned_thread, NULL);
896
897 close(this->socket);
898 unlink(socket_addr.sun_path);
899 free(this);
900 }
901
902
903 /*
904 * Described in header-file
905 */
906 stroke_t *stroke_create()
907 {
908 private_stroke_t *this = malloc_thing(private_stroke_t);
909 mode_t old;
910
911 /* public functions */
912 this->public.destroy = (void (*)(stroke_t*))destroy;
913
914 /* private functions */
915 this->stroke_receive = stroke_receive;
916
917 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
918
919 /* set up unix socket */
920 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
921 if (this->socket == -1)
922 {
923 this->logger->log(this->logger, ERROR, "could not create whack socket");
924 free(this);
925 return NULL;
926 }
927
928 old = umask(~S_IRWXU);
929 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
930 {
931 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
932 close(this->socket);
933 free(this);
934 return NULL;
935 }
936 umask(old);
937
938 if (listen(this->socket, 0) < 0)
939 {
940 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
941 close(this->socket);
942 unlink(socket_addr.sun_path);
943 free(this);
944 return NULL;
945 }
946
947 /* start a thread reading from the socket */
948 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
949 {
950 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
951 close(this->socket);
952 unlink(socket_addr.sun_path);
953 free(this);
954 return NULL;
955 }
956
957 return (&this->public);
958 }