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