list ca certificates
[strongswan.git] / src / charon / threads / stroke_interface.c
1 /**
2 * @file stroke.c
3 *
4 * @brief Implementation of stroke_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <sys/fcntl.h>
29 #include <unistd.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <pthread.h>
33
34 #include "stroke_interface.h"
35
36 #include <stroke.h>
37 #include <types.h>
38 #include <daemon.h>
39 #include <crypto/x509.h>
40 #include <queues/jobs/initiate_ike_sa_job.h>
41
42 #define IKE_PORT 500
43 #define PATH_BUF 256
44
45 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
46
47
48 typedef struct private_stroke_t private_stroke_t;
49
50 /**
51 * Private data of an stroke_t object.
52 */
53 struct private_stroke_t {
54
55 /**
56 * Public part of stroke_t object.
57 */
58 stroke_t public;
59
60 /**
61 * Assigned logger_t object in charon.
62 */
63 logger_t *logger;
64
65 /**
66 * Logger which logs to stroke
67 */
68 logger_t *stroke_logger;
69
70 /**
71 * Unix socket to listen for strokes
72 */
73 int socket;
74
75 /**
76 * Thread which reads from the socket
77 */
78 pthread_t assigned_thread;
79
80 /**
81 * Read from the socket and handle stroke messages
82 */
83 void (*stroke_receive) (private_stroke_t *this);
84 };
85
86 /**
87 * Helper function which corrects the string pointers
88 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
89 * contains RELATIVE addresses (relative to the beginning of the
90 * stroke_msg). They must be corrected if they reach our address
91 * space...
92 */
93 static void pop_string(stroke_msg_t *msg, char **string)
94 {
95 if (*string == NULL)
96 return;
97
98 /* check for sanity of string pointer and string */
99 if (string < (char**)msg
100 || string > (char**)msg + sizeof(stroke_msg_t)
101 || (u_int)*string < (u_int)((char*)msg->buffer - (char*)msg)
102 || (u_int)*string > msg->length)
103 {
104 *string = "(invalid pointer in stroke msg)";
105 }
106 else
107 {
108 *string = (char*)msg + (u_int)*string;
109 }
110 }
111
112 /**
113 * Load end entitity certificate
114 */
115 static void load_end_certificate(const char *filename, identification_t **idp)
116 {
117 char path[PATH_BUF];
118 x509_t *cert;
119
120 if (*filename == '/')
121 {
122 /* absolute path name */
123 snprintf(path, sizeof(path), "%s", filename);
124 }
125 else
126 {
127 /* relative path name */
128 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
129 }
130
131 cert = x509_create_from_file(path, "end entity certificate");
132
133 if (cert)
134 {
135 identification_t *id = *idp;
136 identification_t *subject = cert->get_subject(cert);
137
138 if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
139 {
140 id->destroy(id);
141 id = subject;
142 *idp = id->clone(id);
143 }
144 charon->credentials->add_certificate(charon->credentials, cert);
145 }
146 }
147
148 /**
149 * Add a connection to the configuration list
150 */
151 static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
152 {
153 connection_t *connection;
154 policy_t *policy;
155 identification_t *my_id, *other_id;
156 host_t *my_host, *other_host, *my_subnet, *other_subnet;
157 proposal_t *proposal;
158 traffic_selector_t *my_ts, *other_ts;
159
160 pop_string(msg, &msg->add_conn.name);
161 pop_string(msg, &msg->add_conn.me.address);
162 pop_string(msg, &msg->add_conn.other.address);
163 pop_string(msg, &msg->add_conn.me.id);
164 pop_string(msg, &msg->add_conn.other.id);
165 pop_string(msg, &msg->add_conn.me.cert);
166 pop_string(msg, &msg->add_conn.other.cert);
167 pop_string(msg, &msg->add_conn.me.subnet);
168 pop_string(msg, &msg->add_conn.other.subnet);
169
170 this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
171
172 my_host = msg->add_conn.me.address?
173 host_create(AF_INET, msg->add_conn.me.address, IKE_PORT) : NULL;
174 if (my_host == NULL)
175 {
176 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
177 return;
178 }
179
180 other_host = msg->add_conn.other.address ?
181 host_create(AF_INET, msg->add_conn.other.address, IKE_PORT) : NULL;
182 if (other_host == NULL)
183 {
184 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
185 my_host->destroy(my_host);
186 return;
187 }
188
189 my_id = identification_create_from_string(msg->add_conn.me.id ?
190 msg->add_conn.me.id : msg->add_conn.me.address);
191 if (my_id == NULL)
192 {
193 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
194 my_host->destroy(my_host);
195 other_host->destroy(other_host);
196 return;
197 }
198
199 other_id = identification_create_from_string(msg->add_conn.other.id ?
200 msg->add_conn.other.id : msg->add_conn.other.address);
201 if (other_id == NULL)
202 {
203 my_host->destroy(my_host);
204 other_host->destroy(other_host);
205 my_id->destroy(my_id);
206 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
207 return;
208 }
209
210 my_subnet = host_create(AF_INET, msg->add_conn.me.subnet ?
211 msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
212 if (my_subnet == NULL)
213 {
214 my_host->destroy(my_host);
215 other_host->destroy(other_host);
216 my_id->destroy(my_id);
217 other_id->destroy(other_id);
218 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
219 return;
220 }
221
222 other_subnet = host_create(AF_INET, msg->add_conn.other.subnet ?
223 msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
224 if (other_subnet == NULL)
225 {
226 my_host->destroy(my_host);
227 other_host->destroy(other_host);
228 my_id->destroy(my_id);
229 other_id->destroy(other_id);
230 my_subnet->destroy(my_subnet);
231 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
232 return;
233 }
234
235 my_ts = traffic_selector_create_from_subnet(my_subnet, msg->add_conn.me.subnet ?
236 msg->add_conn.me.subnet_mask : 32);
237 my_subnet->destroy(my_subnet);
238
239 other_ts = traffic_selector_create_from_subnet(other_subnet, msg->add_conn.other.subnet ?
240 msg->add_conn.other.subnet_mask : 32);
241 other_subnet->destroy(other_subnet);
242
243 if (charon->socket->is_listening_on(charon->socket, other_host))
244 {
245 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, switching");
246
247 host_t *tmp_host;
248 identification_t *tmp_id;
249 traffic_selector_t *tmp_ts;
250 char *tmp_cert;
251
252 tmp_host = my_host;
253 my_host = other_host;
254 other_host = tmp_host;
255
256 tmp_id = my_id;
257 my_id = other_id;
258 other_id = tmp_id;
259
260 tmp_ts = my_ts;
261 my_ts = other_ts;
262 other_ts = tmp_ts;
263
264 tmp_cert = msg->add_conn.me.cert;
265 msg->add_conn.me.cert = msg->add_conn.other.cert;
266 msg->add_conn.other.cert = tmp_cert;
267 }
268 else if (charon->socket->is_listening_on(charon->socket, my_host))
269 {
270 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is own host, not switching");
271 }
272 else
273 {
274 this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our, aborting");
275
276 my_host->destroy(my_host);
277 other_host->destroy(other_host);
278 my_id->destroy(my_id);
279 other_id->destroy(other_id);
280 my_ts->destroy(my_ts);
281 other_ts->destroy(other_ts);
282 return;
283 }
284
285 if (msg->add_conn.me.cert)
286 {
287 load_end_certificate(msg->add_conn.me.cert, &my_id);
288 }
289 if (msg->add_conn.other.cert)
290 {
291 load_end_certificate(msg->add_conn.other.cert, &other_id);
292 }
293
294 connection = connection_create(msg->add_conn.name, msg->add_conn.ikev2,
295 my_host, other_host,
296 RSA_DIGITAL_SIGNATURE);
297 proposal = proposal_create(1);
298 proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
299 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
300 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
301 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
302 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
303 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
304 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
305 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
306 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
307 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
308 connection->add_proposal(connection, proposal);
309
310 /* add to global connection list */
311 charon->connections->add_connection(charon->connections, connection);
312 this->logger->log(this->logger, CONTROL, "added connection \"%s\": %s[%s]...%s[%s]",
313 msg->add_conn.name,
314 my_host->get_address(my_host),
315 my_id->get_string(my_id),
316 other_host->get_address(other_host),
317 other_id->get_string(other_id));
318
319 policy = policy_create(msg->add_conn.name, my_id, other_id);
320 proposal = proposal_create(1);
321 proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
322 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
323 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
324 policy->add_proposal(policy, proposal);
325 policy->add_my_traffic_selector(policy, my_ts);
326 policy->add_other_traffic_selector(policy, other_ts);
327
328 /* add to global policy list */
329 charon->policies->add_policy(charon->policies, policy);
330 }
331
332 /**
333 * Delete a connection from the list
334 */
335 static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg)
336 {
337 status_t status;
338
339 pop_string(msg, &(msg->del_conn.name));
340 this->logger->log(this->logger, CONTROL, "received stroke: delete \"%s\"", msg->del_conn.name);
341
342 status = charon->connections->delete_connection(charon->connections,
343 msg->del_conn.name);
344 charon->policies->delete_policy(charon->policies, msg->del_conn.name);
345 if (status == SUCCESS)
346 {
347 this->stroke_logger->log(this->stroke_logger, CONTROL,
348 "Deleted connection '%s'", msg->del_conn.name);
349 }
350 else
351 {
352 this->stroke_logger->log(this->stroke_logger, ERROR,
353 "No connection named '%s'", msg->del_conn.name);
354 }
355 }
356
357 /**
358 * initiate a connection by name
359 */
360 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
361 {
362 initiate_ike_sa_job_t *job;
363 connection_t *connection;
364 linked_list_t *ike_sas;
365 ike_sa_id_t *ike_sa_id;
366
367 pop_string(msg, &(msg->initiate.name));
368 this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
369 connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name);
370 if (connection == NULL)
371 {
372 this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name);
373 }
374 /* only initiate if it is an IKEv2 connection, ignore IKEv1 */
375 else if (connection->is_ikev2(connection))
376 {
377 /* check for already set up IKE_SAs befor initiating */
378 ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->initiate.name);
379 if (ike_sas->get_count(ike_sas) == 0)
380 {
381 this->stroke_logger->log(this->stroke_logger, CONTROL, "initiating connection \"%s\" (see log)...", msg->initiate.name);
382 job = initiate_ike_sa_job_create(connection);
383 charon->job_queue->add(charon->job_queue, (job_t*)job);
384 }
385 else
386 {
387 this->stroke_logger->log(this->stroke_logger, CONTROL, "connection \"%s\" already up", msg->initiate.name);
388 }
389 while (ike_sas->remove_last(ike_sas, (void**)&ike_sa_id) == SUCCESS)
390 {
391 ike_sa_id->destroy(ike_sa_id);
392 }
393 ike_sas->destroy(ike_sas);
394 }
395 }
396
397 /**
398 * terminate a connection by name
399 */
400 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
401 {
402 linked_list_t *ike_sas;
403 iterator_t *iterator;
404 int instances = 0;
405 connection_t *conn;
406
407 pop_string(msg, &(msg->terminate.name));
408 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
409
410 /* we have to do tricky tricks to give the most comprehensive output to the user.
411 * There are different cases:
412 * 1. Connection is available, but IKEv1:
413 * => just ignore it, let pluto print it
414 * 2. Connection is not available, but instances of a deleted connection template:
415 * => terminate them, and print their termination
416 * 3. Connection is not available, and and no instances are there:
417 * => show error about bad connection name
418 * 4. An IKEv2 connection is available, and may contain instances:
419 * => terminate and print, simple
420 */
421 conn = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name);
422 if (conn == NULL || conn->is_ikev2(conn))
423 {
424 ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->terminate.name);
425
426 iterator = ike_sas->create_iterator(ike_sas, TRUE);
427 while (iterator->has_next(iterator))
428 {
429 ike_sa_id_t *ike_sa_id;
430 iterator->current(iterator, (void**)&ike_sa_id);
431 charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id);
432 ike_sa_id->destroy(ike_sa_id);
433 instances++;
434 }
435 iterator->destroy(iterator);
436 ike_sas->destroy(ike_sas);
437 if (conn == NULL && instances == 0)
438 {
439 this->stroke_logger->log(this->stroke_logger, CONTROL,
440 "no connection named \"%s\"",
441 msg->terminate.name);
442 }
443 else
444 {
445 this->stroke_logger->log(this->stroke_logger, CONTROL,
446 "terminated %d instances of \"%s\"",
447 instances, msg->terminate.name);
448 }
449 }
450 if (conn)
451 {
452 conn->destroy(conn);
453 }
454 }
455
456 /**
457 * show status of (established) connections
458 */
459 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
460 {
461 if (msg->status.name)
462 {
463 pop_string(msg, &(msg->status.name));
464 }
465 charon->connections->log_connections(charon->connections, this->stroke_logger, msg->status.name);
466 charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name);
467 }
468
469 /**
470 * list various information
471 */
472 static void stroke_list(private_stroke_t *this, stroke_msg_t *msg, bool utc)
473 {
474 if (msg->type = STR_LIST_CERTS)
475 {
476 charon->credentials->log_certificates(charon->credentials, this->stroke_logger, utc);
477 charon->credentials->log_ca_certificates(charon->credentials, this->stroke_logger, utc);
478 }
479 }
480
481 logger_context_t get_context(char *context)
482 {
483 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
484 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
485 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
486 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
487 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
488 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
489 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
490 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
491 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
492 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
493 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
494 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
495 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
496 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
497 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
498 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
499 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
500 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
501 else return -2;
502 }
503
504 /**
505 * set the type of logged messages in a context
506 */
507 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
508 {
509 pop_string(msg, &(msg->logtype.context));
510 pop_string(msg, &(msg->logtype.type));
511
512 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
513
514 log_level_t level;
515 logger_context_t context = get_context(msg->logtype.context);
516 if (context == -2)
517 {
518 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
519 return;
520 }
521
522 if (strcasecmp(msg->logtype.type, "CONTROL") == 0)
523 level = CONTROL;
524 else if (strcasecmp(msg->logtype.type, "ERROR") == 0)
525 level = ERROR;
526 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0)
527 level = AUDIT;
528 else if (strcasecmp(msg->logtype.type, "RAW") == 0)
529 level = RAW;
530 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0)
531 level = PRIVATE;
532 else
533 {
534 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
535 return;
536 }
537
538 if (msg->logtype.enable)
539 {
540 logger_manager->enable_log_level(logger_manager, context, level);
541 }
542 else
543 {
544 logger_manager->disable_log_level(logger_manager, context, level);
545 }
546 }
547
548 /**
549 * set the verbosity of a logger
550 */
551 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
552 {
553 log_level_t level;
554 logger_context_t context;
555
556 pop_string(msg, &(msg->loglevel.context));
557 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
558
559 context = get_context(msg->loglevel.context);
560 if (context == -2)
561 {
562 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
563 return;
564 }
565
566 if (msg->loglevel.level == 0)
567 level = LEVEL0;
568 else if (msg->loglevel.level == 1)
569 level = LEVEL1;
570 else if (msg->loglevel.level == 2)
571 level = LEVEL2;
572 else if (msg->loglevel.level == 3)
573 level = LEVEL3;
574 else
575 {
576 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
577 return;
578 }
579
580 logger_manager->enable_log_level(logger_manager, context, level);
581 }
582
583 /**
584 * Implementation of private_stroke_t.stroke_receive.
585 */
586 static void stroke_receive(private_stroke_t *this)
587 {
588 stroke_msg_t *msg;
589 u_int16_t msg_length;
590 struct sockaddr_un strokeaddr;
591 int strokeaddrlen = sizeof(strokeaddr);
592 ssize_t bytes_read;
593 int strokefd;
594 FILE *strokefile;
595 int oldstate;
596
597 /* disable cancellation by default */
598 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
599
600 while (1)
601 {
602 /* wait for connections, but allow thread to terminate */
603 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
604 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
605 pthread_setcancelstate(oldstate, NULL);
606
607 if (strokefd < 0)
608 {
609 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
610 continue;
611 }
612
613 /* peek the length */
614 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
615 if (bytes_read != sizeof(msg_length))
616 {
617 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
618 close(strokefd);
619 continue;
620 }
621
622 /* read message */
623 msg = malloc(msg_length);
624 bytes_read = recv(strokefd, msg, msg_length, 0);
625 if (bytes_read != msg_length)
626 {
627 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
628 close(strokefd);
629 continue;
630 }
631
632 strokefile = fdopen(dup(strokefd), "w");
633 if (strokefile == NULL)
634 {
635 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
636 close(strokefd);
637 free(msg);
638 continue;
639 }
640
641 /* setup a logger which writes status to the unix socket */
642 this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
643
644 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
645
646 switch (msg->type)
647 {
648 case STR_INITIATE:
649 stroke_initiate(this, msg);
650 break;
651 case STR_TERMINATE:
652 stroke_terminate(this, msg);
653 break;
654 case STR_STATUS:
655 stroke_status(this, msg);
656 break;
657 case STR_STATUS_ALL:
658 this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
659 stroke_status(this, msg);
660 break;
661 case STR_ADD_CONN:
662 stroke_add_conn(this, msg);
663 break;
664 case STR_DEL_CONN:
665 stroke_del_conn(this, msg);
666 break;
667 case STR_LOGTYPE:
668 stroke_logtype(this, msg);
669 break;
670 case STR_LOGLEVEL:
671 stroke_loglevel(this, msg);
672 break;
673 case STR_LIST_CERTS:
674 stroke_list(this, msg, FALSE);
675 break;
676 default:
677 this->logger->log(this->logger, ERROR, "received invalid stroke");
678 }
679 this->stroke_logger->destroy(this->stroke_logger);
680 fclose(strokefile);
681 close(strokefd);
682 free(msg);
683 }
684 }
685
686 /**
687 * Implementation of stroke_t.destroy.
688 */
689 static void destroy(private_stroke_t *this)
690 {
691
692 pthread_cancel(this->assigned_thread);
693 pthread_join(this->assigned_thread, NULL);
694
695 close(this->socket);
696 unlink(socket_addr.sun_path);
697 free(this);
698 }
699
700
701 /*
702 * Described in header-file
703 */
704 stroke_t *stroke_create()
705 {
706 private_stroke_t *this = malloc_thing(private_stroke_t);
707 mode_t old;
708
709 /* public functions */
710 this->public.destroy = (void (*)(stroke_t*))destroy;
711
712 /* private functions */
713 this->stroke_receive = stroke_receive;
714
715 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
716
717 /* set up unix socket */
718 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
719 if (this->socket == -1)
720 {
721 this->logger->log(this->logger, ERROR, "could not create whack socket");
722 free(this);
723 return NULL;
724 }
725
726 old = umask(~S_IRWXU);
727 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
728 {
729 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
730 close(this->socket);
731 free(this);
732 return NULL;
733 }
734 umask(old);
735
736 if (listen(this->socket, 0) < 0)
737 {
738 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
739 close(this->socket);
740 unlink(socket_addr.sun_path);
741 free(this);
742 return NULL;
743 }
744
745 /* start a thread reading from the socket */
746 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
747 {
748 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
749 close(this->socket);
750 unlink(socket_addr.sun_path);
751 free(this);
752 return NULL;
753 }
754
755 return (&this->public);
756 }