moved auth_method to policy
[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|LEVEL2, " my ca: '%s'", my_ca->get_string(my_ca));
358 this->logger->log(this->logger, CONTROL|LEVEL2, " other ca:'%s'", other_ca->get_string(other_ca));
359 this->logger->log(this->logger, CONTROL|LEVEL2, " 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.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,
388 "invalid IKE proposal string: %s", proposal_string);
389 my_id->destroy(my_id);
390 other_id->destroy(other_id);
391 my_ts->destroy(my_ts);
392 other_ts->destroy(other_ts);
393 my_ca->destroy(my_ca);
394 other_ca->destroy(other_ca);
395 connection->destroy(connection);
396 return;
397 }
398 connection->add_proposal(connection, proposal);
399 }
400 if (!strict)
401 {
402 proposal = proposal_create_default(PROTO_IKE);
403 connection->add_proposal(connection, proposal);
404 }
405 }
406 else
407 {
408 proposal = proposal_create_default(PROTO_IKE);
409 connection->add_proposal(connection, proposal);
410 }
411
412 policy = policy_create(msg->add_conn.name, my_id, other_id,
413 msg->add_conn.auth_method,
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.me.hostaccess,
418 msg->add_conn.dpd.action);
419 policy->add_my_traffic_selector(policy, my_ts);
420 policy->add_other_traffic_selector(policy, other_ts);
421 policy->add_authorities(policy, my_ca, other_ca);
422
423 if (msg->add_conn.algorithms.esp)
424 {
425 char *proposal_string;
426 char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
427
428 if (*strict == '!')
429 *strict = '\0';
430 else
431 strict = NULL;
432
433 while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
434 {
435 proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
436 if (proposal == NULL)
437 {
438 this->logger->log(this->logger, ERROR,
439 "invalid ESP proposal string: %s", proposal_string);
440 policy->destroy(policy);
441 connection->destroy(connection);
442 return;
443 }
444 policy->add_proposal(policy, proposal);
445 }
446 if (!strict)
447 {
448 proposal = proposal_create_default(PROTO_ESP);
449 policy->add_proposal(policy, proposal);
450 }
451 }
452 else
453 {
454 proposal = proposal_create_default(PROTO_ESP);
455 policy->add_proposal(policy, proposal);
456 }
457
458 /* add to global connection list */
459 charon->connections->add_connection(charon->connections, connection);
460 this->logger->log(this->logger, CONTROL, "added connection \"%s\": %s[%s]...%s[%s]",
461 msg->add_conn.name,
462 my_host->get_string(my_host),
463 my_id->get_string(my_id),
464 other_host->get_string(other_host),
465 other_id->get_string(other_id));
466 /* add to global policy list */
467 charon->policies->add_policy(charon->policies, policy);
468 return;
469
470 /* mopping up after parsing errors */
471
472 destroy_ids:
473 my_id->destroy(my_id);
474 other_id->destroy(other_id);
475
476 destroy_hosts:
477 my_host->destroy(my_host);
478 other_host->destroy(other_host);
479 }
480
481 /**
482 * Delete a connection from the list
483 */
484 static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg)
485 {
486 status_t status;
487
488 pop_string(msg, &(msg->del_conn.name));
489 this->logger->log(this->logger, CONTROL, "received stroke: delete \"%s\"", msg->del_conn.name);
490
491 status = charon->connections->delete_connection(charon->connections,
492 msg->del_conn.name);
493 charon->policies->delete_policy(charon->policies, msg->del_conn.name);
494 if (status == SUCCESS)
495 {
496 this->stroke_logger->log(this->stroke_logger, CONTROL,
497 "Deleted connection '%s'", msg->del_conn.name);
498 }
499 else
500 {
501 this->stroke_logger->log(this->stroke_logger, ERROR,
502 "No connection named '%s'", msg->del_conn.name);
503 }
504 }
505
506 /**
507 * initiate a connection by name
508 */
509 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
510 {
511 initiate_job_t *job;
512 connection_t *connection;
513 policy_t *policy;
514
515 pop_string(msg, &(msg->initiate.name));
516 this->logger->log(this->logger, CONTROL,
517 "received stroke: initiate \"%s\"",
518 msg->initiate.name);
519
520 connection = charon->connections->get_connection_by_name(charon->connections,
521 msg->initiate.name);
522 if (connection == NULL)
523 {
524 this->stroke_logger->log(this->stroke_logger, ERROR,
525 "no connection named \"%s\"",
526 msg->initiate.name);
527 return;
528 }
529 if (!connection->is_ikev2(connection))
530 {
531 connection->destroy(connection);
532 return;
533 }
534
535 policy = charon->policies->get_policy_by_name(charon->policies,
536 msg->initiate.name);
537 if (policy == NULL)
538 {
539 this->stroke_logger->log(this->stroke_logger, ERROR,
540 "no policy named \"%s\"",
541 msg->initiate.name);
542 connection->destroy(connection);
543 return;
544 }
545 this->stroke_logger->log(this->stroke_logger, CONTROL,
546 "initiating connection \"%s\" (see log)...",
547 msg->initiate.name);
548 job = initiate_job_create(connection, policy);
549 charon->job_queue->add(charon->job_queue, (job_t*)job);
550 }
551
552 /**
553 * route/unroute a policy (install SPD entries)
554 */
555 static void stroke_route(private_stroke_t *this, stroke_msg_t *msg, bool route)
556 {
557 route_job_t *job;
558 connection_t *connection;
559 policy_t *policy;
560
561 pop_string(msg, &(msg->route.name));
562 this->logger->log(this->logger, CONTROL,
563 "received stroke: %s \"%s\"",
564 route ? "route" : "unroute",
565 msg->route.name);
566
567 /* we wouldn't need a connection, but we only want to route policies
568 * whose connections are keyexchange=ikev2. */
569 connection = charon->connections->get_connection_by_name(charon->connections,
570 msg->route.name);
571 if (connection == NULL)
572 {
573 this->stroke_logger->log(this->stroke_logger, ERROR,
574 "no connection named \"%s\"",
575 msg->route.name);
576 return;
577 }
578 if (!connection->is_ikev2(connection))
579 {
580 connection->destroy(connection);
581 return;
582 }
583
584 policy = charon->policies->get_policy_by_name(charon->policies,
585 msg->route.name);
586 if (policy == NULL)
587 {
588 this->stroke_logger->log(this->stroke_logger, ERROR,
589 "no policy named \"%s\"",
590 msg->route.name);
591 connection->destroy(connection);
592 return;
593 }
594 this->stroke_logger->log(this->stroke_logger, CONTROL,
595 "%s policy \"%s\"",
596 route ? "routing" : "unrouting",
597 msg->route.name);
598 job = route_job_create(connection, policy, route);
599 charon->job_queue->add(charon->job_queue, (job_t*)job);
600 }
601
602 /**
603 * terminate a connection by name
604 */
605 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
606 {
607 pop_string(msg, &(msg->terminate.name));
608 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
609
610 charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name);
611 }
612
613 /**
614 * show status of (established) connections
615 */
616 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
617 {
618 linked_list_t *list;
619 host_t *host;
620
621 leak_detective_status(this->stroke_logger);
622
623 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
624 "job queue load: %d",
625 charon->job_queue->get_count(charon->job_queue));
626 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
627 "scheduled events: %d",
628 charon->event_queue->get_count(charon->event_queue));
629 list = charon->socket->create_local_address_list(charon->socket);
630 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
631 "listening on %d addresses:",
632 list->get_count(list));
633 while (list->remove_first(list, (void**)&host) == SUCCESS)
634 {
635 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
636 " %s", host->get_string(host));
637 host->destroy(host);
638
639 }
640 list->destroy(list);
641
642 if (msg->status.name)
643 {
644 pop_string(msg, &(msg->status.name));
645 }
646 charon->connections->log_connections(charon->connections,
647 this->stroke_logger, msg->status.name);
648 charon->ike_sa_manager->log_status(charon->ike_sa_manager,
649 this->stroke_logger, msg->status.name);
650 }
651
652 /**
653 * list various information
654 */
655 static void stroke_list(private_stroke_t *this, stroke_msg_t *msg)
656 {
657 if (msg->list.flags & LIST_CERTS)
658 {
659 charon->credentials->log_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
660 }
661 if (msg->list.flags & LIST_CACERTS)
662 {
663 charon->credentials->log_ca_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
664 }
665 if (msg->list.flags & LIST_CRLS)
666 {
667 charon->credentials->log_crls(charon->credentials, this->stroke_logger, msg->list.utc);
668 }
669 }
670
671 /**
672 * reread various information
673 */
674 static void stroke_reread(private_stroke_t *this, stroke_msg_t *msg)
675 {
676 if (msg->reread.flags & REREAD_CACERTS)
677 {
678 charon->credentials->load_ca_certificates(charon->credentials);
679 }
680 if (msg->reread.flags & REREAD_CRLS)
681 {
682 charon->credentials->load_crls(charon->credentials);
683 }
684 }
685
686 logger_context_t get_context(char *context)
687 {
688 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
689 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
690 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
691 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
692 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
693 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
694 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
695 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
696 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
697 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
698 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
699 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
700 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
701 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
702 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
703 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
704 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
705 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
706 else if (strcasecmp(context, "XFRM") == 0) return XFRM;
707 else return -2;
708 }
709
710 /**
711 * set the type of logged messages in a context
712 */
713 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
714 {
715 pop_string(msg, &(msg->logtype.context));
716 pop_string(msg, &(msg->logtype.type));
717
718 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
719
720 log_level_t level;
721 logger_context_t context = get_context(msg->logtype.context);
722 if (context == -2)
723 {
724 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
725 return;
726 }
727
728 if (strcasecmp(msg->logtype.type, "CONTROL") == 0)
729 level = CONTROL;
730 else if (strcasecmp(msg->logtype.type, "ERROR") == 0)
731 level = ERROR;
732 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0)
733 level = AUDIT;
734 else if (strcasecmp(msg->logtype.type, "RAW") == 0)
735 level = RAW;
736 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0)
737 level = PRIVATE;
738 else
739 {
740 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
741 return;
742 }
743
744 if (msg->logtype.enable)
745 {
746 logger_manager->enable_log_level(logger_manager, context, level);
747 }
748 else
749 {
750 logger_manager->disable_log_level(logger_manager, context, level);
751 }
752 }
753
754 /**
755 * set the verbosity of a logger
756 */
757 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
758 {
759 log_level_t level;
760 logger_context_t context;
761
762 pop_string(msg, &(msg->loglevel.context));
763 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
764
765 context = get_context(msg->loglevel.context);
766 if (context == -2)
767 {
768 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
769 return;
770 }
771
772 if (msg->loglevel.level == 0)
773 level = LEVEL0;
774 else if (msg->loglevel.level == 1)
775 level = LEVEL1;
776 else if (msg->loglevel.level == 2)
777 level = LEVEL2;
778 else if (msg->loglevel.level == 3)
779 level = LEVEL3;
780 else
781 {
782 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
783 return;
784 }
785
786 logger_manager->enable_log_level(logger_manager, context, level);
787 }
788
789 /**
790 * Implementation of private_stroke_t.stroke_receive.
791 */
792 static void stroke_receive(private_stroke_t *this)
793 {
794 stroke_msg_t *msg;
795 u_int16_t msg_length;
796 struct sockaddr_un strokeaddr;
797 int strokeaddrlen = sizeof(strokeaddr);
798 ssize_t bytes_read;
799 int strokefd;
800 FILE *strokefile;
801 int oldstate;
802
803 /* disable cancellation by default */
804 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
805
806 while (1)
807 {
808 /* wait for connections, but allow thread to terminate */
809 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
810 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
811 pthread_setcancelstate(oldstate, NULL);
812
813 if (strokefd < 0)
814 {
815 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
816 continue;
817 }
818
819 /* peek the length */
820 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
821 if (bytes_read != sizeof(msg_length))
822 {
823 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
824 close(strokefd);
825 continue;
826 }
827
828 /* read message */
829 msg = malloc(msg_length);
830 bytes_read = recv(strokefd, msg, msg_length, 0);
831 if (bytes_read != msg_length)
832 {
833 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
834 close(strokefd);
835 continue;
836 }
837
838 strokefile = fdopen(dup(strokefd), "w");
839 if (strokefile == NULL)
840 {
841 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
842 close(strokefd);
843 free(msg);
844 continue;
845 }
846
847 /* setup a logger which writes status to the unix socket */
848 this->stroke_logger = logger_create("", CONTROL|ERROR, FALSE, strokefile);
849
850 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
851
852 switch (msg->type)
853 {
854 case STR_INITIATE:
855 stroke_initiate(this, msg);
856 break;
857 case STR_ROUTE:
858 stroke_route(this, msg, TRUE);
859 break;
860 case STR_UNROUTE:
861 stroke_route(this, msg, FALSE);
862 break;
863 case STR_TERMINATE:
864 stroke_terminate(this, msg);
865 break;
866 case STR_STATUS:
867 stroke_status(this, msg);
868 break;
869 case STR_STATUS_ALL:
870 this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
871 stroke_status(this, msg);
872 break;
873 case STR_ADD_CONN:
874 stroke_add_conn(this, msg);
875 break;
876 case STR_DEL_CONN:
877 stroke_del_conn(this, msg);
878 break;
879 case STR_LOGTYPE:
880 stroke_logtype(this, msg);
881 break;
882 case STR_LOGLEVEL:
883 stroke_loglevel(this, msg);
884 break;
885 case STR_LIST:
886 stroke_list(this, msg);
887 break;
888 case STR_REREAD:
889 stroke_reread(this, msg);
890 break;
891 default:
892 this->logger->log(this->logger, ERROR, "received invalid stroke");
893 }
894 this->stroke_logger->destroy(this->stroke_logger);
895 fclose(strokefile);
896 close(strokefd);
897 free(msg);
898 }
899 }
900
901 /**
902 * Implementation of stroke_t.destroy.
903 */
904 static void destroy(private_stroke_t *this)
905 {
906
907 pthread_cancel(this->assigned_thread);
908 pthread_join(this->assigned_thread, NULL);
909
910 close(this->socket);
911 unlink(socket_addr.sun_path);
912 free(this);
913 }
914
915
916 /*
917 * Described in header-file
918 */
919 stroke_t *stroke_create()
920 {
921 private_stroke_t *this = malloc_thing(private_stroke_t);
922 mode_t old;
923
924 /* public functions */
925 this->public.destroy = (void (*)(stroke_t*))destroy;
926
927 /* private functions */
928 this->stroke_receive = stroke_receive;
929
930 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
931
932 /* set up unix socket */
933 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
934 if (this->socket == -1)
935 {
936 this->logger->log(this->logger, ERROR, "could not create whack socket");
937 free(this);
938 return NULL;
939 }
940
941 old = umask(~S_IRWXU);
942 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
943 {
944 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
945 close(this->socket);
946 free(this);
947 return NULL;
948 }
949 umask(old);
950
951 if (listen(this->socket, 0) < 0)
952 {
953 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
954 close(this->socket);
955 unlink(socket_addr.sun_path);
956 free(this);
957 return NULL;
958 }
959
960 /* start a thread reading from the socket */
961 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
962 {
963 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
964 close(this->socket);
965 unlink(socket_addr.sun_path);
966 free(this);
967 return NULL;
968 }
969
970 return (&this->public);
971 }