77c15283f975ee1fcb06f303c514844fcb4af3b2
[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 connection_entry_t connection_entry_t;
46
47 /**
48 * A connection entry combines a connection name with a connection.
49 */
50 struct connection_entry_t {
51
52 /**
53 * connection name.
54 */
55 char *name;
56
57 /**
58 * Configuration for IKE_SA_INIT exchange.
59 */
60 connection_t *connection;
61 };
62
63
64 typedef struct private_stroke_t private_stroke_t;
65
66 /**
67 * Private data of an stroke_t object.
68 */
69 struct private_stroke_t {
70
71 /**
72 * Public part of stroke_t object.
73 */
74 stroke_t public;
75
76 /**
77 * Holding all connections as connection_entry_t's.
78 */
79 linked_list_t *connections;
80
81 /**
82 * Assigned logger_t object in charon.
83 */
84 logger_t *logger;
85
86 /**
87 * Logger which logs to stroke
88 */
89 logger_t *stroke_logger;
90
91 /**
92 * Unix socket to listen for strokes
93 */
94 int socket;
95
96 /**
97 * Thread which reads from the socket
98 */
99 pthread_t assigned_thread;
100
101 /**
102 * Read from the socket and handle stroke messages
103 */
104 void (*stroke_receive) (private_stroke_t *this);
105
106 /**
107 * find a connection in the config list by name
108 */
109 connection_t *(*get_connection_by_name) (private_stroke_t *this, char *name);
110 };
111
112 /**
113 * Helper function which corrects the string pointers
114 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
115 * contains RELATIVE addresses (relative to the beginning of the
116 * stroke_msg). They must be corrected if they reach our address
117 * space...
118 */
119 static void pop_string(stroke_msg_t *msg, char **string)
120 {
121 /* check for sanity of string pointer and string */
122 if (*string == NULL)
123 {
124 *string = "";
125 }
126 else if (string < (char**)msg ||
127 string > (char**)msg + sizeof(stroke_msg_t) ||
128 *string < (char*)msg->buffer - (u_int)msg ||
129 *string > (char*)(u_int)msg->length)
130 {
131 *string = "(invalid char* in stroke msg)";
132 }
133 else
134 {
135 *string = (char*)msg + (u_int)*string;
136 }
137 }
138
139 /**
140 * Add a connection to the configuration list
141 */
142 static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
143 {
144 connection_t *connection;
145 policy_t *policy;
146 identification_t *my_id, *other_id;
147 host_t *my_host, *other_host, *my_subnet, *other_subnet;
148 proposal_t *proposal;
149 traffic_selector_t *my_ts, *other_ts;
150 connection_entry_t *entry;
151 x509_t *cert;
152
153 pop_string(msg, &msg->add_conn.name);
154 pop_string(msg, &msg->add_conn.me.address);
155 pop_string(msg, &msg->add_conn.other.address);
156 pop_string(msg, &msg->add_conn.me.id);
157 pop_string(msg, &msg->add_conn.other.id);
158 pop_string(msg, &msg->add_conn.me.cert);
159 pop_string(msg, &msg->add_conn.other.cert);
160 pop_string(msg, &msg->add_conn.me.subnet);
161 pop_string(msg, &msg->add_conn.other.subnet);
162
163 this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
164
165 my_host = host_create(AF_INET, msg->add_conn.me.address, 500);
166 if (my_host == NULL)
167 {
168 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
169 return;
170 }
171 other_host = host_create(AF_INET, msg->add_conn.other.address, 500);
172 if (other_host == NULL)
173 {
174 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
175 my_host->destroy(my_host);
176 return;
177 }
178 my_id = identification_create_from_string(*msg->add_conn.me.id ?
179 msg->add_conn.me.id : msg->add_conn.me.address);
180 if (my_id == NULL)
181 {
182 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
183 my_host->destroy(my_host);
184 other_host->destroy(other_host);
185 return;
186 }
187 other_id = identification_create_from_string(*msg->add_conn.other.id ?
188 msg->add_conn.other.id : msg->add_conn.other.address);
189 if (other_id == NULL)
190 {
191 my_host->destroy(my_host);
192 other_host->destroy(other_host);
193 my_id->destroy(my_id);
194 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
195 return;
196 }
197
198 my_subnet = host_create(AF_INET, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, 500);
199 if (my_subnet == NULL)
200 {
201 my_host->destroy(my_host);
202 other_host->destroy(other_host);
203 my_id->destroy(my_id);
204 other_id->destroy(other_id);
205 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
206 return;
207 }
208
209 other_subnet = host_create(AF_INET, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet : msg->add_conn.other.address, 500);
210 if (other_subnet == NULL)
211 {
212 my_host->destroy(my_host);
213 other_host->destroy(other_host);
214 my_id->destroy(my_id);
215 other_id->destroy(other_id);
216 my_subnet->destroy(my_subnet);
217 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
218 return;
219 }
220
221 my_ts = traffic_selector_create_from_subnet(my_subnet, *msg->add_conn.me.subnet ? msg->add_conn.me.subnet_mask : 32);
222 my_subnet->destroy(my_subnet);
223 other_ts = traffic_selector_create_from_subnet(other_subnet, *msg->add_conn.other.subnet ? msg->add_conn.other.subnet_mask : 32);
224 other_subnet->destroy(other_subnet);
225
226 if (charon->socket->is_listening_on(charon->socket, other_host))
227 {
228 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching");
229
230 host_t *tmp_host = my_host;
231 identification_t *tmp_id = my_id;
232 traffic_selector_t *tmp_ts = my_ts;
233 char *tmp_cert = msg->add_conn.me.cert;
234
235 my_host = other_host;
236 other_host = tmp_host;
237 my_id = other_id;
238 other_id = tmp_id;
239 my_ts = other_ts;
240 other_ts = tmp_ts;
241 msg->add_conn.me.cert = msg->add_conn.other.cert;
242 msg->add_conn.other.cert = tmp_cert;
243 }
244 else if (charon->socket->is_listening_on(charon->socket, my_host))
245 {
246 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching");
247 }
248 else
249 {
250 this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting");
251
252 my_host->destroy(my_host);
253 other_host->destroy(other_host);
254 my_id->destroy(my_id);
255 other_id->destroy(other_id);
256 my_ts->destroy(my_ts);
257 other_ts->destroy(other_ts);
258 return;
259 }
260
261 if (msg->add_conn.me.cert)
262 {
263 char file[128];
264 snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.me.cert);
265 cert = x509_create_from_file(file);
266 if (cert)
267 {
268 my_id->destroy(my_id);
269 my_id = cert->get_subject(cert);
270 my_id = my_id->clone(my_id);
271 cert->destroy(cert);
272 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
273 "defined a valid certificate, using its ID \"%s\"",
274 my_id->get_string(my_id));
275 }
276 }
277 if (msg->add_conn.other.cert)
278 {
279 char file[128];
280 snprintf(file, sizeof(file), "%s%s", CERTIFICATE_DIR, msg->add_conn.other.cert);
281 cert = x509_create_from_file(file);
282 if (cert)
283 {
284 other_id->destroy(other_id);
285 other_id = cert->get_subject(cert);
286 other_id = other_id->clone(other_id);
287 cert->destroy(cert);
288 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1,
289 "defined a valid certificate, using its ID \"%s\"",
290 other_id->get_string(other_id));
291 }
292 }
293
294 connection = connection_create(my_host, other_host, my_id->clone(my_id), other_id->clone(other_id),
295 RSA_DIGITAL_SIGNATURE);
296 proposal = proposal_create(1);
297 proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
298 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
299 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
300 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
301 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
302 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
303 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
304 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
305 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
306 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
307 connection->add_proposal(connection, proposal);
308 /* add in our list, so we can manipulate the connection further via name */
309 entry = malloc_thing(connection_entry_t);
310 entry->name = strdup(msg->add_conn.name);
311 entry->connection = connection;
312 this->connections->insert_last(this->connections, entry);
313 /* add to global connection list */
314 charon->connections->add_connection(charon->connections, connection);
315
316 policy = policy_create(my_id, other_id);
317 proposal = proposal_create(1);
318 proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
319 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
320 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
321 policy->add_proposal(policy, proposal);
322 policy->add_my_traffic_selector(policy, my_ts);
323 policy->add_other_traffic_selector(policy, other_ts);
324 /* add to global policy list */
325 charon->policies->add_policy(charon->policies, policy);
326
327 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "connection \"%s\" added", msg->add_conn.name);
328 }
329
330 /**
331 * initiate a connection by name
332 */
333 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
334 {
335 initiate_ike_sa_job_t *job;
336 connection_t *connection;
337
338 pop_string(msg, &(msg->initiate.name));
339 this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
340 connection = this->get_connection_by_name(this, msg->initiate.name);
341 if (connection == NULL)
342 {
343 this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name);
344 }
345 else
346 {
347 job = initiate_ike_sa_job_create(connection->clone(connection));
348 charon->job_queue->add(charon->job_queue, (job_t*)job);
349 }
350 }
351
352 /**
353 * terminate a connection by name
354 */
355 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
356 {
357 connection_t *connection;
358 ike_sa_t *ike_sa;
359 host_t *my_host, *other_host;
360 status_t status;
361
362 pop_string(msg, &(msg->terminate.name));
363 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
364 connection = this->get_connection_by_name(this, msg->terminate.name);
365
366 if (connection)
367 {
368 my_host = connection->get_my_host(connection);
369 other_host = connection->get_other_host(connection);
370
371 status = charon->ike_sa_manager->checkout_by_hosts(charon->ike_sa_manager,
372 my_host, other_host, &ike_sa);
373
374 if (status == SUCCESS)
375 {
376 this->stroke_logger->log(this->stroke_logger, CONTROL, "deleting IKE SA between %s - %s",
377 my_host->get_address(my_host), other_host->get_address(other_host));
378
379 charon->ike_sa_manager->checkin_and_delete(charon->ike_sa_manager, ike_sa);
380 }
381 else
382 {
383 this->stroke_logger->log(this->stroke_logger, ERROR, "no active connection found between %s - %s",
384 my_host->get_address(my_host), other_host->get_address(other_host));
385 }
386 }
387 else
388 {
389 this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->terminate.name);
390 }
391
392 }
393
394 /**
395 * show status of (established) connections
396 */
397 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
398 {
399 linked_list_t *list;
400 iterator_t *iterator;
401 status_t status;
402
403
404 list = charon->ike_sa_manager->get_ike_sa_list(charon->ike_sa_manager);
405 iterator = list->create_iterator(list, TRUE);
406 while (iterator->has_next(iterator))
407 {
408 ike_sa_id_t *ike_sa_id;
409 ike_sa_t *ike_sa;
410 iterator->current(iterator, (void**)&ike_sa_id);
411
412 status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa);
413 if (status == SUCCESS)
414 {
415 host_t *my_host, *other_host;
416 identification_t *my_id, *other_id;
417 my_host = ike_sa->get_my_host(ike_sa);
418 other_host = ike_sa->get_other_host(ike_sa);
419 my_id = ike_sa->get_my_id(ike_sa);
420 other_id = ike_sa->get_other_id(ike_sa);
421
422 this->stroke_logger->log(this->stroke_logger, CONTROL, "IKE_SA in state %s ",
423 mapping_find(ike_sa_state_m, ike_sa->get_state(ike_sa)));
424
425 this->stroke_logger->log(this->stroke_logger, CONTROL, " SPIs: %lld",
426 ike_sa_id->get_initiator_spi(ike_sa_id));
427 this->stroke_logger->log(this->stroke_logger, CONTROL, " %lld",
428 ike_sa_id->get_responder_spi(ike_sa_id));
429
430 this->stroke_logger->log(this->stroke_logger, CONTROL, " Addr: %s",
431 my_host->get_address(my_host));
432 this->stroke_logger->log(this->stroke_logger, CONTROL, " %s",
433 other_host->get_address(other_host));
434
435 this->stroke_logger->log(this->stroke_logger, CONTROL, " ID: %s",
436 my_id->get_string(my_id));
437 this->stroke_logger->log(this->stroke_logger, CONTROL, " %s",
438 other_id->get_string(other_id));
439
440 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
441 }
442
443 ike_sa_id->destroy(ike_sa_id);
444 }
445 iterator->destroy(iterator);
446 list->destroy(list);
447 }
448
449 logger_context_t get_context(char *context)
450 {
451 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
452 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
453 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
454 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
455 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
456 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
457 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
458 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
459 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
460 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
461 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
462 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
463 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
464 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
465 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
466 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
467 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
468 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
469 else return -2;
470 }
471
472 /**
473 * set the type of logged messages in a context
474 */
475 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
476 {
477 pop_string(msg, &(msg->logtype.context));
478 pop_string(msg, &(msg->logtype.type));
479
480 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
481
482 log_level_t level;
483 logger_context_t context = get_context(msg->logtype.context);
484 if (context == -2)
485 {
486 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
487 return;
488 }
489
490 if (strcasecmp(msg->logtype.type, "CONTROL") == 0) level = CONTROL;
491 else if (strcasecmp(msg->logtype.type, "ERROR") == 0) level = ERROR;
492 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0) level = AUDIT;
493 else if (strcasecmp(msg->logtype.type, "RAW") == 0) level = RAW;
494 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0) level = PRIVATE;
495 else
496 {
497 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
498 return;
499 }
500
501 if (msg->logtype.enable)
502 {
503 logger_manager->enable_log_level(logger_manager, context, level);
504 }
505 else
506 {
507 logger_manager->disable_log_level(logger_manager, context, level);
508 }
509 }
510
511 /**
512 * set the verbosity of a logger
513 */
514 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
515 {
516 pop_string(msg, &(msg->loglevel.context));
517
518 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
519
520 log_level_t level;
521 logger_context_t context = get_context(msg->loglevel.context);
522
523 if (context == -2)
524 {
525 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
526 return;
527 }
528
529 if (msg->loglevel.level == 0)
530 {
531 level = LEVEL0;
532 }
533 else if (msg->loglevel.level == 1)
534 {
535 level = LEVEL1;
536 }
537 else if (msg->loglevel.level == 2)
538 {
539 level = LEVEL2;
540 }
541 else if (msg->loglevel.level == 3)
542 {
543 level = LEVEL3;
544 }
545 else
546 {
547 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
548 return;
549 }
550
551 logger_manager->enable_log_level(logger_manager, context, level);
552 }
553
554 /**
555 * Implementation of private_stroke_t.stroke_receive.
556 */
557 static void stroke_receive(private_stroke_t *this)
558 {
559 stroke_msg_t *msg;
560 u_int16_t msg_length;
561 struct sockaddr_un strokeaddr;
562 int strokeaddrlen = sizeof(strokeaddr);
563 ssize_t bytes_read;
564 int strokefd;
565 FILE *strokefile;
566 int oldstate;
567
568 /* disable cancellation by default */
569 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
570
571 while (1)
572 {
573 /* wait for connections, but allow thread to terminate */
574 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
575 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
576 pthread_setcancelstate(oldstate, NULL);
577
578 if (strokefd < 0)
579 {
580 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
581 continue;
582 }
583
584 /* peek the length */
585 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
586 if (bytes_read != sizeof(msg_length))
587 {
588 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
589 close(strokefd);
590 continue;
591 }
592
593 /* read message */
594 msg = malloc(msg_length);
595 bytes_read = recv(strokefd, msg, msg_length, 0);
596 if (bytes_read != msg_length)
597 {
598 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
599 close(strokefd);
600 continue;
601 }
602
603 strokefile = fdopen(dup(strokefd), "w");
604 if (strokefile == NULL)
605 {
606 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
607 close(strokefd);
608 free(msg);
609 continue;
610 }
611
612 this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
613
614 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
615
616 switch (msg->type)
617 {
618 case STR_INITIATE:
619 {
620 stroke_initiate(this, msg);
621 break;
622 }
623 case STR_TERMINATE:
624 {
625 stroke_terminate(this, msg);
626 break;
627 }
628 case STR_STATUS:
629 {
630 stroke_status(this, msg);
631 break;
632 }
633 case STR_ADD_CONN:
634 {
635 stroke_add_conn(this, msg);
636 break;
637 }
638 case STR_LOGTYPE:
639 {
640 stroke_logtype(this, msg);
641 break;
642 }
643 case STR_LOGLEVEL:
644 {
645 stroke_loglevel(this, msg);
646 break;
647 }
648 default:
649 this->logger->log(this->logger, ERROR, "received invalid stroke");
650 }
651 this->stroke_logger->destroy(this->stroke_logger);
652 fclose(strokefile);
653 close(strokefd);
654 free(msg);
655 }
656 }
657
658
659 /**
660 * Implementation of private_stroke_t.get_connection_by_name.
661 */
662 static connection_t *get_connection_by_name(private_stroke_t *this, char *name)
663 {
664 iterator_t *iterator;
665 connection_t *found = NULL;
666
667 iterator = this->connections->create_iterator(this->connections, TRUE);
668 while (iterator->has_next(iterator))
669 {
670 connection_entry_t *entry;
671 iterator->current(iterator,(void **) &entry);
672
673 if (strcmp(entry->name,name) == 0)
674 {
675 /* found configuration */
676 found = entry->connection;
677 break;
678 }
679 }
680 iterator->destroy(iterator);
681
682 return found;
683 }
684
685 /**
686 * Implementation of stroke_t.destroy.
687 */
688 static void destroy(private_stroke_t *this)
689 {
690 connection_entry_t *entry;
691
692 pthread_cancel(this->assigned_thread);
693 pthread_join(this->assigned_thread, NULL);
694
695 while (this->connections->remove_first(this->connections, (void **)&entry) == SUCCESS)
696 {
697 /* connection is destroyed by global list */
698 free(entry->name);
699 free(entry);
700 }
701 this->connections->destroy(this->connections);
702
703 close(this->socket);
704 unlink(socket_addr.sun_path);
705 free(this);
706 }
707
708
709 /*
710 * Described in header-file
711 */
712 stroke_t *stroke_create()
713 {
714 private_stroke_t *this = malloc_thing(private_stroke_t);
715 mode_t old;
716
717 /* public functions */
718 this->public.destroy = (void (*)(stroke_t*))destroy;
719
720 /* private functions */
721 this->stroke_receive = stroke_receive;
722 this->get_connection_by_name = get_connection_by_name;
723
724 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
725
726 /* set up unix socket */
727 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
728 if (this->socket == -1)
729 {
730 this->logger->log(this->logger, ERROR, "could not create whack socket");
731 free(this);
732 return NULL;
733 }
734
735 old = umask(~S_IRWXU);
736 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
737 {
738 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
739 close(this->socket);
740 free(this);
741 return NULL;
742 }
743 umask(old);
744
745 if (listen(this->socket, 0) < 0)
746 {
747 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
748 close(this->socket);
749 unlink(socket_addr.sun_path);
750 free(this);
751 return NULL;
752 }
753
754 /* start a thread reading from the socket */
755 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
756 {
757 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
758 close(this->socket);
759 unlink(socket_addr.sun_path);
760 free(this);
761 return NULL;
762 }
763
764 /* private variables */
765 this->connections = linked_list_create();
766
767 return (&this->public);
768 }