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