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