]> git.ipfire.org Git - people/ms/strongswan.git/blob - Source/charon/threads/stroke_interface.c
2881cb26ad8cbeb1fa811425b854d46d039dfb8e
[people/ms/strongswan.git] / Source / 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_ike_sa_job.h>
41
42
43 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
44
45 typedef struct configuration_entry_t configuration_entry_t;
46
47 /**
48 * A configuration entry combines a configuration name with a connection
49 * and a policy.
50 *
51 * @b Constructors:
52 * - configuration_entry_create()
53 */
54 struct configuration_entry_t {
55
56 /**
57 * Configuration name.
58 *
59 */
60 char *name;
61
62 /**
63 * Configuration for IKE_SA_INIT exchange.
64 */
65 connection_t *connection;
66
67 /**
68 * Configuration for all phases after IKE_SA_INIT exchange.
69 */
70 policy_t *policy;
71
72 /**
73 * Public key of other peer
74 */
75 rsa_public_key_t *public_key;
76
77 /**
78 * Own private key
79 */
80 rsa_private_key_t *private_key;
81
82 /**
83 * Destroys a configuration_entry_t
84 */
85 void (*destroy) (configuration_entry_t *this);
86 };
87
88 /**
89 * Implementation of configuration_entry_t.destroy.
90 */
91 static void configuration_entry_destroy (configuration_entry_t *this)
92 {
93 this->connection->destroy(this->connection);
94 this->policy->destroy(this->policy);
95 if (this->public_key)
96 {
97 this->public_key->destroy(this->public_key);
98 }
99 free(this->name);
100 free(this);
101 }
102
103 /**
104 * Creates a configuration_entry_t object.
105 */
106 static configuration_entry_t * configuration_entry_create(char *name, connection_t* connection, policy_t *policy,
107 rsa_private_key_t *private_key, rsa_public_key_t *public_key)
108 {
109 configuration_entry_t *entry = malloc_thing(configuration_entry_t);
110
111 /* functions */
112 entry->destroy = configuration_entry_destroy;
113
114 /* private data */
115 entry->connection = connection;
116 entry->policy = policy;
117 entry->public_key = public_key;
118 entry->private_key = private_key;
119 entry->name = malloc(strlen(name) + 1);
120 strcpy(entry->name, name);
121
122 return entry;
123 }
124
125 typedef struct private_stroke_t private_stroke_t;
126
127 /**
128 * Private data of an stroke_t object.
129 */
130 struct private_stroke_t {
131
132 /**
133 * Public part of stroke_t object.
134 */
135 stroke_t public;
136
137 /**
138 * Holding all configurations.
139 */
140 linked_list_t *configurations;
141
142 /**
143 * The list of RSA private keys accessible through crendial_store_t interface
144 */
145 linked_list_t *private_keys;
146
147 /**
148 * Assigned logger_t object in charon.
149 */
150 logger_t *logger;
151
152 /**
153 * Logger which logs to stroke
154 */
155 logger_t *stroke_logger;
156
157 /**
158 * Unix socket to listen for strokes
159 */
160 int socket;
161
162 /**
163 * Thread which reads from the socket
164 */
165 pthread_t assigned_thread;
166
167 /**
168 * Read from the socket and handle stroke messages
169 */
170 void (*stroke_receive) (private_stroke_t *this);
171
172 /**
173 * find a connection in the config list by name
174 */
175 connection_t *(*get_connection_by_name) (private_stroke_t *this, char *name);
176 };
177
178 /**
179 * Helper function which corrects the string pointers
180 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
181 * contains RELATIVE addresses (relative to the beginning of the
182 * stroke_msg). They must be corrected if they reach our address
183 * space...
184 */
185 static void pop_string(stroke_msg_t *msg, char **string)
186 {
187 /* check for sanity of string pointer and string */
188 if (*string == NULL)
189 {
190 *string = "";
191 }
192 else if (string < (char**)msg ||
193 string > (char**)msg + sizeof(stroke_msg_t) ||
194 *string < (char*)msg->buffer - (u_int)msg ||
195 *string > (char*)(u_int)msg->length)
196 {
197 *string = "(invalid char* in stroke msg)";
198 }
199 else
200 {
201 *string = (char*)msg + (u_int)*string;
202 }
203 }
204
205 /**
206 * Find the private key for a public key
207 */
208 static rsa_private_key_t *find_private_key(private_stroke_t *this, rsa_public_key_t *public_key)
209 {
210 rsa_private_key_t *private_key = NULL;
211 iterator_t *iterator;
212
213 this->logger->log(this->logger, CONTROL|LEVEL2, "Looking up private key by public key...");
214
215 iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
216 while (iterator->has_next(iterator))
217 {
218 iterator->current(iterator, (void**)&private_key);
219 if (private_key->belongs_to(private_key, public_key))
220 {
221 this->logger->log(this->logger, CONTROL|LEVEL2, "found a match");
222 break;
223 }
224 this->logger->log(this->logger, CONTROL|LEVEL2, "this one did not match");
225 }
226 iterator->destroy(iterator);
227 return private_key;
228 }
229
230 /**
231 * Load all private keys form "/etc/ipsec.d/private/"
232 */
233 static void load_private_keys(private_stroke_t *this)
234 {
235 struct dirent* entry;
236 struct stat stb;
237 DIR* dir;
238 rsa_private_key_t *key;
239
240 /* currently only unencrypted binary DER files are loaded */
241 dir = opendir(PRIVATE_KEY_DIR);
242 if (dir == NULL || chdir(PRIVATE_KEY_DIR) == -1) {
243 this->logger->log(this->logger, ERROR, "error opening private key directory \"%s\"", PRIVATE_KEY_DIR);
244 return;
245 }
246 while ((entry = readdir(dir)) != NULL)
247 {
248 if (stat(entry->d_name, &stb) == -1)
249 {
250 continue;
251 }
252 /* try to parse all regular files */
253 if (stb.st_mode & S_IFREG)
254 {
255 key = rsa_private_key_create_from_file(entry->d_name, NULL);
256 if (key)
257 {
258 this->private_keys->insert_last(this->private_keys, (void*)key);
259 this->logger->log(this->logger, CONTROL|LEVEL1, "loaded private key \"%s%s\"",
260 PRIVATE_KEY_DIR, entry->d_name);
261 }
262 else
263 {
264 this->logger->log(this->logger, ERROR, "private key \"%s%s\" invalid, skipped",
265 PRIVATE_KEY_DIR, entry->d_name);
266 }
267 }
268 }
269 closedir(dir);
270 }
271
272 /**
273 * Add a connection to the configuration list
274 */
275 static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
276 {
277 connection_t *connection;
278 policy_t *policy;
279 identification_t *my_id, *other_id;
280 host_t *my_host, *other_host, *my_subnet, *other_subnet;
281 proposal_t *proposal;
282 traffic_selector_t *my_ts, *other_ts;
283 x509_t *my_cert, *other_cert;
284 rsa_private_key_t *private_key = NULL;
285 rsa_public_key_t *public_key = NULL;
286
287 pop_string(msg, &msg->add_conn.name);
288 pop_string(msg, &msg->add_conn.me.address);
289 pop_string(msg, &msg->add_conn.other.address);
290 pop_string(msg, &msg->add_conn.me.id);
291 pop_string(msg, &msg->add_conn.other.id);
292 pop_string(msg, &msg->add_conn.me.cert);
293 pop_string(msg, &msg->add_conn.other.cert);
294 pop_string(msg, &msg->add_conn.me.subnet);
295 pop_string(msg, &msg->add_conn.other.subnet);
296
297 this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
298
299 my_host = host_create(AF_INET, msg->add_conn.me.address, 500);
300 if (my_host == NULL)
301 {
302 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
303 return;
304 }
305 other_host = host_create(AF_INET, msg->add_conn.other.address, 500);
306 if (other_host == NULL)
307 {
308 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
309 my_host->destroy(my_host);
310 return;
311 }
312 my_id = identification_create_from_string(*msg->add_conn.me.id ?
313 msg->add_conn.me.id : msg->add_conn.me.address);
314 if (my_id == NULL)
315 {
316 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
317 my_host->destroy(my_host);
318 other_host->destroy(other_host);
319 return;
320 }
321 other_id = identification_create_from_string(*msg->add_conn.other.id ?
322 msg->add_conn.other.id : msg->add_conn.other.address);
323 if (other_id == NULL)
324 {
325 my_host->destroy(my_host);
326 other_host->destroy(other_host);
327 my_id->destroy(my_id);
328 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
329 return;
330 }
331
332 my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
333 if (my_subnet == NULL)
334 {
335 my_host->destroy(my_host);
336 other_host->destroy(other_host);
337 my_id->destroy(my_id);
338 other_id->destroy(other_id);
339 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
340 return;
341 }
342
343 other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
344 if (other_subnet == NULL)
345 {
346 my_host->destroy(my_host);
347 other_host->destroy(other_host);
348 my_id->destroy(my_id);
349 other_id->destroy(other_id);
350 my_subnet->destroy(my_subnet);
351 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
352 return;
353 }
354
355 my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32);
356 my_subnet->destroy(my_subnet);
357 other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32);
358 other_subnet->destroy(other_subnet);
359
360 if (charon->socket->is_listening_on(charon->socket, other_host))
361 {
362 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching");
363
364 host_t *tmp_host = my_host;
365 identification_t *tmp_id = my_id;
366 traffic_selector_t *tmp_ts = my_ts;
367 char *tmp_cert = msg->add_conn.me.cert;
368
369 my_host = other_host;
370 other_host = tmp_host;
371 my_id = other_id;
372 other_id = tmp_id;
373 my_ts = other_ts;
374 other_ts = tmp_ts;
375 msg->add_conn.me.cert = msg->add_conn.other.cert;
376 msg->add_conn.other.cert = tmp_cert;
377 }
378 else if (charon->socket->is_listening_on(charon->socket, my_host))
379 {
380 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching");
381 }
382 else
383 {
384 this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting");
385
386 my_host->destroy(my_host);
387 other_host->destroy(other_host);
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 return;
393 }
394
395
396 connection = connection_create(my_host, other_host, my_id->clone(my_id), other_id->clone(other_id),
397 RSA_DIGITAL_SIGNATURE);
398 proposal = proposal_create(1);
399 proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
400 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
401 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
402 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
403 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
404 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
405 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
406 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
407 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
408 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
409 connection->add_proposal(connection, proposal);
410
411 policy = policy_create(my_id, other_id);
412 proposal = proposal_create(1);
413 proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
414 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
415 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
416 policy->add_proposal(policy, proposal);
417 policy->add_my_traffic_selector(policy, my_ts);
418 policy->add_other_traffic_selector(policy, other_ts);
419
420
421 chdir(CERTIFICATE_DIR);
422 my_cert = x509_create_from_file(msg->add_conn.me.cert);
423 if (my_cert == NULL)
424 {
425 this->stroke_logger->log(this->stroke_logger, ERROR, "loading own certificate \"%s%s\" failed",
426 CERTIFICATE_DIR, msg->add_conn.me.cert);
427 }
428 else
429 {
430 public_key = my_cert->get_public_key(my_cert);
431 private_key = find_private_key(this, public_key);
432 public_key->destroy(public_key);
433 if (private_key)
434 {
435 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "found private key for certificate \"%s%s\"",
436 CERTIFICATE_DIR, msg->add_conn.me.cert);
437 }
438 else
439 {
440 this->stroke_logger->log(this->stroke_logger, ERROR, "no private key for certificate \"%s%s\" found",
441 CERTIFICATE_DIR, msg->add_conn.me.cert);
442 }
443 my_cert->destroy(my_cert);
444 }
445 other_cert = x509_create_from_file(msg->add_conn.other.cert);
446 public_key = NULL;
447 if (other_cert == NULL)
448 {
449 this->stroke_logger->log(this->stroke_logger, ERROR, "loading peers certificate \"%s%s\" failed",
450 CERTIFICATE_DIR, msg->add_conn.other.cert);
451 }
452 else
453 {
454 public_key = other_cert->get_public_key(other_cert);
455 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "loaded certificate \"%s%s\" (%p)",
456 CERTIFICATE_DIR, msg->add_conn.other.cert, public_key);
457 other_cert->destroy(other_cert);
458 }
459
460 this->configurations->insert_last(this->configurations,
461 configuration_entry_create(msg->add_conn.name, connection, policy, private_key, public_key));
462
463 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "connection \"%s\" added (%d in store)",
464 msg->add_conn.name,
465 this->configurations->get_count(this->configurations));
466 }
467
468 /**
469 * initiate a connection by name
470 */
471 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
472 {
473 initiate_ike_sa_job_t *job;
474 connection_t *connection;
475
476 pop_string(msg, &(msg->initiate.name));
477 this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
478 connection = this->get_connection_by_name(this, msg->initiate.name);
479 if (connection == NULL)
480 {
481 this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
482 }
483 else
484 {
485 job = initiate_ike_sa_job_create(connection->clone(connection));
486 charon->job_queue->add(charon->job_queue, (job_t*)job);
487 }
488 }
489
490 /**
491 * terminate a connection by name
492 */
493 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
494 {
495 connection_t *connection;
496 ike_sa_t *ike_sa;
497 host_t *my_host, *other_host;
498 status_t status;
499
500 pop_string(msg, &(msg->terminate.name));
501 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
502 connection = this->get_connection_by_name(this, msg->terminate.name);
503
504 if (connection)
505 {
506 my_host = connection->get_my_host(connection);
507 other_host = connection->get_other_host(connection);
508
509 status = charon->ike_sa_manager->checkout_by_hosts(charon->ike_sa_manager,
510 my_host, other_host, &ike_sa);
511
512 if (status == SUCCESS)
513 {
514 this->stroke_logger->log(this->stroke_logger, CONTROL, "deleting IKE SA between %s - %s",
515 my_host->get_address(my_host), other_host->get_address(other_host));
516
517 charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
518 }
519 else
520 {
521 this->stroke_logger->log(this->stroke_logger, ERROR, "no active connection found between %s - %s",
522 my_host->get_address(my_host), other_host->get_address(other_host));
523 }
524 }
525 else
526 {
527 this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->terminate.name);
528 }
529
530 }
531
532 /**
533 * show status of (established) connections
534 */
535 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
536 {
537 linked_list_t *list;
538 iterator_t *iterator;
539 status_t status;
540
541
542 list = charon->ike_sa_manager->get_ike_sa_list(charon->ike_sa_manager);
543 iterator = list->create_iterator(list, TRUE);
544 while (iterator->has_next(iterator))
545 {
546 ike_sa_id_t *ike_sa_id;
547 ike_sa_t *ike_sa;
548 iterator->current(iterator, (void**)&ike_sa_id);
549
550 status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa);
551 if (status == SUCCESS)
552 {
553 host_t *me, *other;
554 me = ike_sa->get_my_host(ike_sa);
555 other = ike_sa->get_other_host(ike_sa);
556
557
558 this->stroke_logger->log(this->stroke_logger, CONTROL, "IKE SA in state %s as %s",
559 mapping_find(ike_sa_state_m, ike_sa->get_state(ike_sa)),
560 ike_sa_id->is_initiator ? "initiator" : "responder");
561
562 this->stroke_logger->log(this->stroke_logger, CONTROL, " SPIs: %15lld - %-15lld",
563 ike_sa_id->get_initiator_spi(ike_sa_id),
564 ike_sa_id->get_responder_spi(ike_sa_id));
565
566
567 this->stroke_logger->log(this->stroke_logger, CONTROL, " Addr: %15s - %-15s",
568 me->get_address(me), other->get_address(other));
569
570 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
571 }
572
573 ike_sa_id->destroy(ike_sa_id);
574 }
575 iterator->destroy(iterator);
576 list->destroy(list);
577 }
578
579 logger_context_t get_context(char *context)
580 {
581 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
582 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
583 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
584 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
585 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
586 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
587 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
588 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
589 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
590 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
591 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
592 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
593 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
594 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
595 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
596 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
597 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
598 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
599 else return -2;
600 }
601
602 /**
603 * set the type of logged messages in a context
604 */
605 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
606 {
607 pop_string(msg, &(msg->logtype.context));
608 pop_string(msg, &(msg->logtype.type));
609
610 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
611
612 log_level_t level;
613 logger_context_t context = get_context(msg->logtype.context);
614 if (context == -2)
615 {
616 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
617 return;
618 }
619
620 if (strcasecmp(msg->logtype.type, "CONTROL") == 0) level = CONTROL;
621 else if (strcasecmp(msg->logtype.type, "ERROR") == 0) level = ERROR;
622 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0) level = AUDIT;
623 else if (strcasecmp(msg->logtype.type, "RAW") == 0) level = RAW;
624 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0) level = PRIVATE;
625 else
626 {
627 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
628 return;
629 }
630
631 if (msg->logtype.enable)
632 {
633 logger_manager->enable_log_level(logger_manager, context, level);
634 }
635 else
636 {
637 logger_manager->disable_log_level(logger_manager, context, level);
638 }
639 }
640
641 /**
642 * set the verbosity of a logger
643 */
644 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
645 {
646 pop_string(msg, &(msg->loglevel.context));
647
648 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
649
650 log_level_t level;
651 logger_context_t context = get_context(msg->loglevel.context);
652
653 if (context == -2)
654 {
655 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
656 return;
657 }
658
659 if (msg->loglevel.level == 0)
660 {
661 level = LEVEL0;
662 }
663 else if (msg->loglevel.level == 1)
664 {
665 level = LEVEL1;
666 }
667 else if (msg->loglevel.level == 2)
668 {
669 level = LEVEL2;
670 }
671 else if (msg->loglevel.level == 3)
672 {
673 level = LEVEL3;
674 }
675 else
676 {
677 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
678 return;
679 }
680
681 logger_manager->enable_log_level(logger_manager, context, level);
682 }
683
684 /**
685 * Implementation of private_stroke_t.stroke_receive.
686 */
687 static void stroke_receive(private_stroke_t *this)
688 {
689 stroke_msg_t *msg;
690 u_int16_t msg_length;
691 struct sockaddr_un strokeaddr;
692 int strokeaddrlen = sizeof(strokeaddr);
693 ssize_t bytes_read;
694 int strokefd;
695 FILE *strokefile;
696 int oldstate;
697
698 /* disable cancellation by default */
699 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
700
701 while (1)
702 {
703 /* wait for connections, but allow thread to terminate */
704 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
705 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
706 pthread_setcancelstate(oldstate, NULL);
707
708 if (strokefd < 0)
709 {
710 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
711 continue;
712 }
713
714 /* peek the length */
715 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
716 if (bytes_read != sizeof(msg_length))
717 {
718 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
719 close(strokefd);
720 continue;
721 }
722
723 /* read message */
724 msg = malloc(msg_length);
725 bytes_read = recv(strokefd, msg, msg_length, 0);
726 if (bytes_read != msg_length)
727 {
728 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
729 close(strokefd);
730 continue;
731 }
732
733 strokefile = fdopen(dup(strokefd), "w");
734 if (strokefile == NULL)
735 {
736 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
737 close(strokefd);
738 free(msg);
739 continue;
740 }
741
742 this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
743
744 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
745
746 switch (msg->type)
747 {
748 case STR_INITIATE:
749 {
750 stroke_initiate(this, msg);
751 break;
752 }
753 case STR_TERMINATE:
754 {
755 stroke_terminate(this, msg);
756 break;
757 }
758 case STR_STATUS:
759 {
760 stroke_status(this, msg);
761 break;
762 }
763 case STR_ADD_CONN:
764 {
765 stroke_add_conn(this, msg);
766 break;
767 }
768 case STR_LOGTYPE:
769 {
770 stroke_logtype(this, msg);
771 break;
772 }
773 case STR_LOGLEVEL:
774 {
775 stroke_loglevel(this, msg);
776 break;
777 }
778 default:
779 this->logger->log(this->logger, ERROR, "received invalid stroke");
780 }
781 this->stroke_logger->destroy(this->stroke_logger);
782 fclose(strokefile);
783 close(strokefd);
784 free(msg);
785 }
786 }
787
788 /**
789 * Implementation of connection_store_t.get_connection_by_hosts.
790 */
791 static connection_t *get_connection_by_hosts(connection_store_t *store, host_t *my_host, host_t *other_host)
792 {
793 private_stroke_t *this = (private_stroke_t*)((u_int8_t*)store - offsetof(stroke_t, connections));
794 iterator_t *iterator;
795 connection_t *found = NULL;
796
797 this->logger->log(this->logger, CONTROL|LEVEL1, "getting config for hosts %s - %s",
798 my_host->get_address(my_host), other_host->get_address(other_host));
799
800 iterator = this->configurations->create_iterator(this->configurations,TRUE);
801 while (iterator->has_next(iterator))
802 {
803 configuration_entry_t *entry;
804 host_t *config_my_host, *config_other_host;
805
806 iterator->current(iterator,(void **) &entry);
807
808 config_my_host = entry->connection->get_my_host(entry->connection);
809 config_other_host = entry->connection->get_other_host(entry->connection);
810
811 /* first check if ip is equal */
812 if(config_other_host->ip_equals(config_other_host, other_host))
813 {
814 this->logger->log(this->logger, CONTROL|LEVEL2, "config entry with remote host %s",
815 config_other_host->get_address(config_other_host));
816 /* could be right one, check my_host for default route*/
817 if (config_my_host->is_default_route(config_my_host))
818 {
819 found = entry->connection->clone(entry->connection);
820 break;
821 }
822 /* check now if host informations are the same */
823 else if (config_my_host->ip_equals(config_my_host,my_host))
824 {
825 found = entry->connection->clone(entry->connection);
826 break;
827 }
828
829 }
830 /* Then check for wildcard hosts!
831 * TODO
832 * actually its only checked if other host with default route can be found! */
833 else if (config_other_host->is_default_route(config_other_host))
834 {
835 /* could be right one, check my_host for default route*/
836 if (config_my_host->is_default_route(config_my_host))
837 {
838 found = entry->connection->clone(entry->connection);
839 break;
840 }
841 /* check now if host informations are the same */
842 else if (config_my_host->ip_equals(config_my_host,my_host))
843 {
844 found = entry->connection->clone(entry->connection);
845 break;
846 }
847 }
848 }
849 iterator->destroy(iterator);
850
851 /* apply hosts as they are supplied since my_host may be %defaultroute, and other_host may be %any. */
852 if (found)
853 {
854 found->update_my_host(found, my_host->clone(my_host));
855 found->update_other_host(found, other_host->clone(other_host));
856 }
857
858 return found;
859 }
860
861 /**
862 * Implementation of connection_store_t.get_connection_by_ids.
863 */
864 static connection_t *get_connection_by_ids(connection_store_t *store, identification_t *my_id, identification_t *other_id)
865 {
866 private_stroke_t *this = (private_stroke_t*)((u_int8_t*)store - offsetof(stroke_t, connections));
867 iterator_t *iterator;
868 connection_t *found = NULL;
869
870 this->logger->log(this->logger, CONTROL|LEVEL1, "getting config for ids %s - %s",
871 my_id->get_string(my_id), other_id->get_string(other_id));
872
873 iterator = this->configurations->create_iterator(this->configurations,TRUE);
874 while (iterator->has_next(iterator))
875 {
876 configuration_entry_t *entry;
877 identification_t *config_my_id, *config_other_id;
878
879 iterator->current(iterator,(void **) &entry);
880
881 config_my_id = entry->connection->get_my_id(entry->connection);
882 config_other_id = entry->connection->get_other_id(entry->connection);
883
884 /* first check if ids are equal
885 * TODO: Add wildcard checks */
886 if (config_other_id->equals(config_other_id, other_id) &&
887 config_my_id->equals(config_my_id, my_id))
888 {
889 this->logger->log(this->logger, CONTROL|LEVEL2, "config entry with remote id %s",
890 config_other_id->get_string(config_other_id));
891 found = entry->connection->clone(entry->connection);
892 break;
893 }
894 }
895 iterator->destroy(iterator);
896
897 return found;
898 }
899
900 /**
901 * Implementation of private_stroke_t.get_connection_by_name.
902 */
903 static connection_t *get_connection_by_name(private_stroke_t *this, char *name)
904 {
905 iterator_t *iterator;
906 connection_t *found = NULL;
907
908 iterator = this->configurations->create_iterator(this->configurations, TRUE);
909 while (iterator->has_next(iterator))
910 {
911 configuration_entry_t *entry;
912 iterator->current(iterator,(void **) &entry);
913
914 if (strcmp(entry->name,name) == 0)
915 {
916 /* found configuration */
917 found = entry->connection;
918 break;
919 }
920 }
921 iterator->destroy(iterator);
922
923 return found;
924 }
925
926 /**
927 * Implementation of policy_store_t.get_policy.
928 */
929 static policy_t *get_policy(policy_store_t *store,identification_t *my_id, identification_t *other_id)
930 {
931 private_stroke_t *this = (private_stroke_t*)((u_int8_t*)store - offsetof(stroke_t, policies));
932 iterator_t *iterator;
933 policy_t *found = NULL;
934
935 iterator = this->configurations->create_iterator(this->configurations, TRUE);
936 while (iterator->has_next(iterator))
937 {
938 configuration_entry_t *entry;
939 iterator->current(iterator,(void **) &entry);
940 identification_t *config_my_id = entry->policy->get_my_id(entry->policy);
941 identification_t *config_other_id = entry->policy->get_other_id(entry->policy);
942
943 /* check other host first */
944 if (config_other_id->belongs_to(config_other_id, other_id))
945 {
946 /* get it if my_id not specified */
947 if (my_id == NULL)
948 {
949 found = entry->policy->clone(entry->policy);
950 break;
951 }
952
953 if (config_my_id->belongs_to(config_my_id, my_id))
954 {
955 found = entry->policy->clone(entry->policy);
956 break;
957 }
958 }
959 }
960 iterator->destroy(iterator);
961
962 /* apply IDs as they are requsted, since they may be configured as %any or such */
963 if (found)
964 {
965 if (my_id)
966 {
967 found->update_my_id(found, my_id->clone(my_id));
968 }
969 found->update_other_id(found, other_id->clone(other_id));
970 }
971 return found;
972 }
973
974 /**
975 * Implementation of credential_store_t.get_shared_secret.
976 */
977 static status_t get_shared_secret(credential_store_t *this, identification_t *identification, chunk_t *preshared_secret)
978 {
979 char *secret = "schluessel\n";
980 preshared_secret->ptr = secret;
981 preshared_secret->len = strlen(secret) + 1;
982
983 *preshared_secret = chunk_clone(*preshared_secret);
984 return SUCCESS;
985 }
986
987 /**
988 * Implementation of credential_store_t.get_rsa_public_key.
989 */
990 static status_t get_rsa_public_key(credential_store_t *store, identification_t *identification, rsa_public_key_t **public_key)
991 {
992 private_stroke_t *this = (private_stroke_t*)((u_int8_t*)store - offsetof(stroke_t, credentials));
993 iterator_t *iterator;
994
995 this->logger->log(this->logger, CONTROL|LEVEL2, "Looking for public key for %s",
996 identification->get_string(identification));
997 iterator = this->configurations->create_iterator(this->configurations, TRUE);
998 while (iterator->has_next(iterator))
999 {
1000 configuration_entry_t *config;
1001 iterator->current(iterator, (void**)&config);
1002 identification_t *stored = config->policy->get_other_id(config->policy);
1003 this->logger->log(this->logger, CONTROL|LEVEL2, "there is one for %s",
1004 stored->get_string(stored));
1005 if (identification->equals(identification, stored))
1006 {
1007 this->logger->log(this->logger, CONTROL|LEVEL2, "found a match: %p",
1008 config->public_key);
1009 if (config->public_key)
1010 {
1011 iterator->destroy(iterator);
1012 *public_key = config->public_key->clone(config->public_key);
1013 return SUCCESS;
1014 }
1015 }
1016 }
1017 iterator->destroy(iterator);
1018 return NOT_FOUND;
1019 }
1020
1021 /**
1022 * Implementation of credential_store_t.get_rsa_private_key.
1023 */
1024 static status_t get_rsa_private_key(credential_store_t *store, identification_t *identification, rsa_private_key_t **private_key)
1025 {
1026 private_stroke_t *this = (private_stroke_t*)((u_int8_t*)store - offsetof(stroke_t, credentials));
1027 iterator_t *iterator;
1028
1029 iterator = this->configurations->create_iterator(this->configurations, TRUE);
1030 while (iterator->has_next(iterator))
1031 {
1032 configuration_entry_t *config;
1033 iterator->current(iterator, (void**)&config);
1034 identification_t *stored = config->policy->get_my_id(config->policy);
1035 if (identification->equals(identification, stored))
1036 {
1037 if (config->private_key)
1038 {
1039 iterator->destroy(iterator);
1040 *private_key = config->private_key->clone(config->private_key);
1041 return SUCCESS;
1042 }
1043 }
1044 }
1045 iterator->destroy(iterator);
1046 return NOT_FOUND;
1047 }
1048
1049 /**
1050 * Implementation of stroke_t.destroy.
1051 */
1052 static void destroy(private_stroke_t *this)
1053 {
1054 configuration_entry_t *entry;
1055 rsa_private_key_t *priv_key;
1056
1057 pthread_cancel(this->assigned_thread);
1058 pthread_join(this->assigned_thread, NULL);
1059
1060 while (this->configurations->remove_first(this->configurations, (void **)&entry) == SUCCESS)
1061 {
1062 entry->destroy(entry);
1063 }
1064 this->configurations->destroy(this->configurations);
1065
1066 while (this->private_keys->remove_first(this->private_keys, (void **)&priv_key) == SUCCESS)
1067 {
1068 priv_key->destroy(priv_key);
1069 }
1070 this->private_keys->destroy(this->private_keys);
1071
1072 close(this->socket);
1073 unlink(socket_addr.sun_path);
1074 free(this);
1075 }
1076
1077 /**
1078 * Dummy function which does nothing.
1079 * Used for connection_store_t.destroy and policy_store_t.destroy,
1080 * since destruction is done in store_t's destructor...
1081 */
1082 void do_nothing(void *nothing)
1083 {
1084 return;
1085 }
1086
1087 /*
1088 * Described in header-file
1089 */
1090 stroke_t *stroke_create()
1091 {
1092 private_stroke_t *this = malloc_thing(private_stroke_t);
1093 mode_t old;
1094
1095 /* public functions */
1096 this->public.connections.get_connection_by_ids = get_connection_by_ids;
1097 this->public.connections.get_connection_by_hosts = get_connection_by_hosts;
1098 this->public.connections.destroy = (void (*) (connection_store_t*))do_nothing;
1099 this->public.policies.get_policy = get_policy;
1100 this->public.policies.destroy = (void (*) (policy_store_t*))do_nothing;
1101 this->public.credentials.get_shared_secret = (status_t (*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret;
1102 this->public.credentials.get_rsa_public_key = (status_t (*)(credential_store_t*,identification_t*,rsa_public_key_t**))get_rsa_public_key;
1103 this->public.credentials.get_rsa_private_key = (status_t (*)(credential_store_t*,identification_t*,rsa_private_key_t**))get_rsa_private_key;
1104 this->public.credentials.destroy = (void (*) (credential_store_t*))do_nothing;
1105 this->public.destroy = (void (*)(stroke_t*))destroy;
1106
1107 /* private functions */
1108 this->stroke_receive = stroke_receive;
1109 this->get_connection_by_name = get_connection_by_name;
1110
1111 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
1112
1113 /* set up unix socket */
1114 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
1115 if (this->socket == -1)
1116 {
1117 this->logger->log(this->logger, ERROR, "could not create whack socket");
1118 free(this);
1119 return NULL;
1120 }
1121
1122 old = umask(~S_IRWXU);
1123 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
1124 {
1125 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
1126 close(this->socket);
1127 free(this);
1128 return NULL;
1129 }
1130 umask(old);
1131
1132 if (listen(this->socket, 0) < 0)
1133 {
1134 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
1135 close(this->socket);
1136 unlink(socket_addr.sun_path);
1137 free(this);
1138 return NULL;
1139 }
1140
1141 /* start a thread reading from the socket */
1142 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
1143 {
1144 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
1145 close(this->socket);
1146 unlink(socket_addr.sun_path);
1147 free(this);
1148 return NULL;
1149 }
1150
1151 /* private variables */
1152 this->configurations = linked_list_create();
1153 this->private_keys = linked_list_create();
1154
1155 load_private_keys(this);
1156
1157 return (&this->public);
1158 }