912213b1c7a0e947c5aa5270dd22b8f0c92b7a1f
[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 static bool strict = FALSE;
46
47 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
48
49
50 typedef struct private_stroke_t private_stroke_t;
51
52 /**
53 * Private data of an stroke_t object.
54 */
55 struct private_stroke_t {
56
57 /**
58 * Public part of stroke_t object.
59 */
60 stroke_t public;
61
62 /**
63 * Assigned logger_t object in charon.
64 */
65 logger_t *logger;
66
67 /**
68 * Logger which logs to stroke
69 */
70 logger_t *stroke_logger;
71
72 /**
73 * Unix socket to listen for strokes
74 */
75 int socket;
76
77 /**
78 * Thread which reads from the \ 1ocket
79 */
80 pthread_t assigned_thread;
81
82 /**
83 * Read from the socket and handle stroke messages
84 */
85 void (*stroke_receive) (private_stroke_t *this);
86 };
87
88 /**
89 * Helper function which corrects the string pointers
90 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
91 * contains RELATIVE addresses (relative to the beginning of the
92 * stroke_msg). They must be corrected if they reach our address
93 * space...
94 */
95 static void pop_string(stroke_msg_t *msg, char **string)
96 {
97 if (*string == NULL)
98 return;
99
100 /* check for sanity of string pointer and string */
101 if (string < (char**)msg
102 || string > (char**)msg + sizeof(stroke_msg_t)
103 || (u_int)*string < (u_int)((char*)msg->buffer - (char*)msg)
104 || (u_int)*string > msg->length)
105 {
106 *string = "(invalid pointer in stroke msg)";
107 }
108 else
109 {
110 *string = (char*)msg + (u_int)*string;
111 }
112 }
113
114 /**
115 * Load end entitity certificate
116 */
117 static x509_t* load_end_certificate(const char *filename, identification_t **idp, logger_t *logger)
118 {
119 char path[PATH_BUF];
120 x509_t *cert;
121
122 if (*filename == '/')
123 {
124 /* absolute path name */
125 snprintf(path, sizeof(path), "%s", filename);
126 }
127 else
128 {
129 /* relative path name */
130 snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
131 }
132
133 cert = x509_create_from_file(path, "end entity certificate");
134
135 if (cert)
136 {
137 identification_t *id = *idp;
138 identification_t *subject = cert->get_subject(cert);
139 time_t until;
140
141 err_t ugh = cert->is_valid(cert, NULL);
142
143 if (ugh != NULL)
144 {
145 logger->log(logger, ERROR, "warning: certificate %s", ugh);
146 }
147 if (!id->equals(id, subject) && !cert->equals_subjectAltName(cert, id))
148 {
149 id->destroy(id);
150 id = subject;
151 *idp = id->clone(id);
152 }
153 /* test output */
154 if (charon->credentials->verify(charon->credentials, cert, &until))
155 {
156 char buf[TIMETOA_BUF];
157
158 timetoa(buf, TIMETOA_BUF, &until, TRUE);
159 logger->log(logger, CONTROL, " end entity certificate is trusted until %s", buf);
160 cert->set_until(cert, until);
161 }
162 else
163 {
164 logger->log(logger, ERROR, " end entity certificate is not trusted");
165 }
166 /* end of test output */
167 return charon->credentials->add_end_certificate(charon->credentials, cert);
168 }
169 return NULL;
170 }
171
172 /**
173 * Add a connection to the configuration list
174 */
175 static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
176 {
177 connection_t *connection;
178 policy_t *policy;
179 identification_t *my_id, *other_id;
180 identification_t *my_ca = NULL;
181 identification_t *other_ca = NULL;
182 bool my_ca_same = FALSE;
183 bool other_ca_same =FALSE;
184 host_t *my_host, *other_host, *my_subnet, *other_subnet;
185 proposal_t *proposal;
186 traffic_selector_t *my_ts, *other_ts;
187
188 pop_string(msg, &msg->add_conn.name);
189 pop_string(msg, &msg->add_conn.me.address);
190 pop_string(msg, &msg->add_conn.other.address);
191 pop_string(msg, &msg->add_conn.me.subnet);
192 pop_string(msg, &msg->add_conn.other.subnet);
193 pop_string(msg, &msg->add_conn.me.id);
194 pop_string(msg, &msg->add_conn.other.id);
195 pop_string(msg, &msg->add_conn.me.cert);
196 pop_string(msg, &msg->add_conn.other.cert);
197 pop_string(msg, &msg->add_conn.me.ca);
198 pop_string(msg, &msg->add_conn.other.ca);
199 pop_string(msg, &msg->add_conn.algorithms.ike);
200 pop_string(msg, &msg->add_conn.algorithms.esp);
201
202 this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
203
204 my_host = msg->add_conn.me.address?
205 host_create(AF_INET, msg->add_conn.me.address, IKE_PORT) : NULL;
206 if (my_host == NULL)
207 {
208 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
209 return;
210 }
211
212 other_host = msg->add_conn.other.address ?
213 host_create(AF_INET, msg->add_conn.other.address, IKE_PORT) : NULL;
214 if (other_host == NULL)
215 {
216 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
217 my_host->destroy(my_host);
218 return;
219 }
220
221 if (charon->interfaces->is_local_address(charon->interfaces, other_host))
222 {
223 stroke_end_t tmp_end;
224 host_t *tmp_host;
225
226 this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, swapping ends");
227
228 tmp_host = my_host;
229 my_host = other_host;
230 other_host = tmp_host;
231
232 tmp_end = msg->add_conn.me;
233 msg->add_conn.me = msg->add_conn.other;
234 msg->add_conn.other = tmp_end;
235 }
236 else if (!charon->interfaces->is_local_address(charon->interfaces, my_host))
237 {
238 this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our side, aborting");
239
240 my_host->destroy(my_host);
241 other_host->destroy(other_host);
242 return;
243 }
244
245 my_id = identification_create_from_string(msg->add_conn.me.id ?
246 msg->add_conn.me.id : msg->add_conn.me.address);
247 if (my_id == NULL)
248 {
249 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
250 my_host->destroy(my_host);
251 other_host->destroy(other_host);
252 return;
253 }
254
255 other_id = identification_create_from_string(msg->add_conn.other.id ?
256 msg->add_conn.other.id : msg->add_conn.other.address);
257 if (other_id == NULL)
258 {
259 my_host->destroy(my_host);
260 other_host->destroy(other_host);
261 my_id->destroy(my_id);
262 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
263 return;
264 }
265
266 my_subnet = host_create(AF_INET, msg->add_conn.me.subnet ?
267 msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
268 if (my_subnet == NULL)
269 {
270 my_host->destroy(my_host);
271 other_host->destroy(other_host);
272 my_id->destroy(my_id);
273 other_id->destroy(other_id);
274 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
275 return;
276 }
277
278 other_subnet = host_create(AF_INET, msg->add_conn.other.subnet ?
279 msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
280 if (other_subnet == NULL)
281 {
282 my_host->destroy(my_host);
283 other_host->destroy(other_host);
284 my_id->destroy(my_id);
285 other_id->destroy(other_id);
286 my_subnet->destroy(my_subnet);
287 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
288 return;
289 }
290
291 my_ts = traffic_selector_create_from_subnet(my_subnet, msg->add_conn.me.subnet ?
292 msg->add_conn.me.subnet_mask : 32);
293 my_subnet->destroy(my_subnet);
294
295 other_ts = traffic_selector_create_from_subnet(other_subnet, msg->add_conn.other.subnet ?
296 msg->add_conn.other.subnet_mask : 32);
297 other_subnet->destroy(other_subnet);
298
299 if (msg->add_conn.me.ca)
300 {
301 if (streq(msg->add_conn.me.ca, "%same"))
302 {
303 my_ca_same = TRUE;
304 }
305 else
306 {
307 my_ca = identification_create_from_string(msg->add_conn.me.ca);
308 }
309 }
310 if (msg->add_conn.other.ca)
311 {
312 if (streq(msg->add_conn.other.ca, "%same"))
313 {
314 other_ca_same = TRUE;
315 }
316 else
317 {
318 other_ca = identification_create_from_string(msg->add_conn.other.ca);
319 }
320 }
321 if (msg->add_conn.me.cert)
322 {
323 x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id, this->logger);
324
325 if (my_ca == NULL && !my_ca_same && cert)
326 {
327 identification_t *issuer = cert->get_issuer(cert);
328
329 my_ca = issuer->clone(issuer);
330 }
331 }
332 if (msg->add_conn.other.cert)
333 {
334 x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id, this->logger);
335
336 if (other_ca == NULL && !other_ca_same && cert)
337 {
338 identification_t *issuer = cert->get_issuer(cert);
339
340 other_ca = issuer->clone(issuer);
341 }
342 }
343 if (other_ca_same && my_ca)
344 {
345 other_ca = my_ca->clone(my_ca);
346 }
347 else if (my_ca_same && other_ca)
348 {
349 my_ca = other_ca->clone(other_ca);
350 }
351 if (my_ca == NULL)
352 {
353 my_ca = identification_create_from_string("%any");
354 }
355 if (other_ca == NULL)
356 {
357 other_ca = identification_create_from_string("%any");
358 }
359 this->logger->log(this->logger, CONTROL|LEVEL1, " my ca: '%s'", my_ca->get_string(my_ca));
360 this->logger->log(this->logger, CONTROL|LEVEL1, " other ca:'%s'", other_ca->get_string(other_ca));
361
362 connection = connection_create(msg->add_conn.name, msg->add_conn.ikev2,
363 msg->add_conn.me.sendcert, msg->add_conn.other.sendcert,
364 my_host, other_host,
365 RSA_DIGITAL_SIGNATURE);
366 if (msg->add_conn.algorithms.ike)
367 {
368 char *proposal_string;
369 char *strict = msg->add_conn.algorithms.ike + strlen(msg->add_conn.algorithms.ike) - 1;
370 if (*strict == '!')
371 {
372 *strict = '\0';
373 }
374 else
375 {
376 strict = NULL;
377 }
378 while ((proposal_string = strsep(&msg->add_conn.algorithms.ike, ",")))
379 {
380 proposal = proposal_create_from_string(PROTO_IKE, proposal_string);
381 if (proposal == NULL)
382 {
383 this->logger->log(this->logger, ERROR, "invalid IKE proposal string: %s", msg->add_conn.algorithms.esp);
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 my_ca->destroy(my_ca);
389 other_ca->destroy(other_ca);
390 connection->destroy(connection);
391 return;
392 }
393 connection->add_proposal(connection, proposal);
394 }
395 if (!strict)
396 {
397 proposal = proposal_create_default(PROTO_IKE);
398 connection->add_proposal(connection, proposal);
399 }
400 }
401 else
402 {
403 proposal = proposal_create_default(PROTO_IKE);
404 connection->add_proposal(connection, proposal);
405 }
406
407 policy = policy_create(msg->add_conn.name, my_id, other_id,
408 msg->add_conn.rekey.ipsec_lifetime,
409 msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
410 msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100);
411 policy->add_my_traffic_selector(policy, my_ts);
412 policy->add_other_traffic_selector(policy, other_ts);
413 policy->add_authorities(policy, my_ca, other_ca);
414
415 if (msg->add_conn.algorithms.esp)
416 {
417 char *proposal_string;
418 char *strict = msg->add_conn.algorithms.esp + strlen(msg->add_conn.algorithms.esp) - 1;
419 if (*strict == '!')
420 {
421 *strict = '\0';
422 }
423 else
424 {
425 strict = NULL;
426 }
427
428 while ((proposal_string = strsep(&msg->add_conn.algorithms.esp, ",")))
429 {
430 proposal = proposal_create_from_string(PROTO_ESP, proposal_string);
431 if (proposal == NULL)
432 {
433 this->logger->log(this->logger, ERROR,
434 "invalid ESP proposal string: %s", msg->add_conn.algorithms.esp);
435 policy->destroy(policy);
436 connection->destroy(connection);
437 return;
438 }
439 policy->add_proposal(policy, proposal);
440 }
441 if (!strict)
442 {
443 proposal = proposal_create_default(PROTO_ESP);
444 policy->add_proposal(policy, proposal);
445 }
446 }
447 else
448 {
449 proposal = proposal_create_default(PROTO_ESP);
450 policy->add_proposal(policy, proposal);
451 }
452
453 /* add to global connection list */
454 charon->connections->add_connection(charon->connections, connection);
455 this->logger->log(this->logger, CONTROL, "added connection \"%s\": %s[%s]...%s[%s]",
456 msg->add_conn.name,
457 my_host->get_address(my_host),
458 my_id->get_string(my_id),
459 other_host->get_address(other_host),
460 other_id->get_string(other_id));
461 /* add to global policy list */
462 charon->policies->add_policy(charon->policies, policy);
463 }
464
465 /**
466 * Delete a connection from the list
467 */
468 static void stroke_del_conn(private_stroke_t *this, stroke_msg_t *msg)
469 {
470 status_t status;
471
472 pop_string(msg, &(msg->del_conn.name));
473 this->logger->log(this->logger, CONTROL, "received stroke: delete \"%s\"", msg->del_conn.name);
474
475 status = charon->connections->delete_connection(charon->connections,
476 msg->del_conn.name);
477 charon->policies->delete_policy(charon->policies, msg->del_conn.name);
478 if (status == SUCCESS)
479 {
480 this->stroke_logger->log(this->stroke_logger, CONTROL,
481 "Deleted connection '%s'", msg->del_conn.name);
482 }
483 else
484 {
485 this->stroke_logger->log(this->stroke_logger, ERROR,
486 "No connection named '%s'", msg->del_conn.name);
487 }
488 }
489
490 /**
491 * initiate a connection by name
492 */
493 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
494 {
495 initiate_ike_sa_job_t *job;
496 connection_t *connection;
497 linked_list_t *ike_sas;
498 ike_sa_id_t *ike_sa_id;
499
500 pop_string(msg, &(msg->initiate.name));
501 this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
502 connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name);
503 if (connection == NULL)
504 {
505 this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name);
506 }
507 /* only initiate if it is an IKEv2 connection, ignore IKEv1 */
508 else if (connection->is_ikev2(connection))
509 {
510 /* check for already set up IKE_SAs befor initiating */
511 ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->initiate.name);
512 if (ike_sas->get_count(ike_sas) == 0)
513 {
514 this->stroke_logger->log(this->stroke_logger, CONTROL,
515 "initiating connection \"%s\" (see log)...", msg->initiate.name);
516 job = initiate_ike_sa_job_create(connection);
517 charon->job_queue->add(charon->job_queue, (job_t*)job);
518 }
519 else
520 {
521 this->stroke_logger->log(this->stroke_logger, CONTROL,
522 "connection \"%s\" already up", msg->initiate.name);
523 }
524 while (ike_sas->remove_last(ike_sas, (void**)&ike_sa_id) == SUCCESS)
525 {
526 ike_sa_id->destroy(ike_sa_id);
527 }
528 ike_sas->destroy(ike_sas);
529 }
530 }
531
532 /**
533 * terminate a connection by name
534 */
535 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
536 {
537 linked_list_t *ike_sas;
538 iterator_t *iterator;
539 int instances = 0;
540 connection_t *conn;
541
542 pop_string(msg, &(msg->terminate.name));
543 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
544
545 /* we have to do tricky tricks to give the most comprehensive output to the user.
546 * There are different cases:
547 * 1. Connection is available, but IKEv1:
548 * => just ignore it, let pluto print it
549 * 2. Connection is not available, but instances of a deleted connection template:
550 * => terminate them, and print their termination
551 * 3. Connection is not available, and and no instances are there:
552 * => show error about bad connection name
553 * 4. An IKEv2 connection is available, and may contain instances:
554 * => terminate and print, simple
555 */
556 conn = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name);
557 if (conn == NULL || conn->is_ikev2(conn))
558 {
559 ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->terminate.name);
560
561 iterator = ike_sas->create_iterator(ike_sas, TRUE);
562 while (iterator->has_next(iterator))
563 {
564 ike_sa_id_t *ike_sa_id;
565 iterator->current(iterator, (void**)&ike_sa_id);
566 charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id);
567 ike_sa_id->destroy(ike_sa_id);
568 instances++;
569 }
570 iterator->destroy(iterator);
571 ike_sas->destroy(ike_sas);
572 if (conn == NULL && instances == 0)
573 {
574 this->stroke_logger->log(this->stroke_logger, CONTROL,
575 "no connection named \"%s\"",
576 msg->terminate.name);
577 }
578 else
579 {
580 this->stroke_logger->log(this->stroke_logger, CONTROL,
581 "terminated %d instances of \"%s\"",
582 instances, msg->terminate.name);
583 }
584 }
585 if (conn)
586 {
587 conn->destroy(conn);
588 }
589 }
590
591 /**
592 * show status of (established) connections
593 */
594 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
595 {
596 if (msg->status.name)
597 {
598 pop_string(msg, &(msg->status.name));
599 }
600 charon->connections->log_connections(charon->connections, this->stroke_logger, msg->status.name);
601 charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name);
602 }
603
604 /**
605 * list various information
606 */
607 static void stroke_list(private_stroke_t *this, stroke_msg_t *msg)
608 {
609 if (msg->list.flags & LIST_CERTS)
610 {
611 charon->credentials->log_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
612 }
613 if (msg->list.flags & LIST_CACERTS)
614 {
615 charon->credentials->log_ca_certificates(charon->credentials, this->stroke_logger, msg->list.utc);
616 }
617 if (msg->list.flags & LIST_CRLS)
618 {
619 charon->credentials->log_crls(charon->credentials, this->stroke_logger, msg->list.utc);
620 }
621 }
622
623 /**
624 * reread various information
625 */
626 static void stroke_reread(private_stroke_t *this, stroke_msg_t *msg)
627 {
628 if (msg->reread.flags & REREAD_CACERTS)
629 {
630 charon->credentials->load_ca_certificates(charon->credentials);
631 }
632 if (msg->reread.flags & REREAD_CRLS)
633 {
634 charon->credentials->load_crls(charon->credentials);
635 }
636 }
637
638 logger_context_t get_context(char *context)
639 {
640 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
641 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
642 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
643 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
644 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
645 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
646 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
647 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
648 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
649 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
650 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
651 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
652 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
653 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
654 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
655 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
656 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
657 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
658 else if (strcasecmp(context, "XFRM") == 0) return XFRM;
659 else return -2;
660 }
661
662 /**
663 * set the type of logged messages in a context
664 */
665 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
666 {
667 pop_string(msg, &(msg->logtype.context));
668 pop_string(msg, &(msg->logtype.type));
669
670 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
671
672 log_level_t level;
673 logger_context_t context = get_context(msg->logtype.context);
674 if (context == -2)
675 {
676 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
677 return;
678 }
679
680 if (strcasecmp(msg->logtype.type, "CONTROL") == 0)
681 level = CONTROL;
682 else if (strcasecmp(msg->logtype.type, "ERROR") == 0)
683 level = ERROR;
684 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0)
685 level = AUDIT;
686 else if (strcasecmp(msg->logtype.type, "RAW") == 0)
687 level = RAW;
688 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0)
689 level = PRIVATE;
690 else
691 {
692 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
693 return;
694 }
695
696 if (msg->logtype.enable)
697 {
698 logger_manager->enable_log_level(logger_manager, context, level);
699 }
700 else
701 {
702 logger_manager->disable_log_level(logger_manager, context, level);
703 }
704 }
705
706 /**
707 * set the verbosity of a logger
708 */
709 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
710 {
711 log_level_t level;
712 logger_context_t context;
713
714 pop_string(msg, &(msg->loglevel.context));
715 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
716
717 context = get_context(msg->loglevel.context);
718 if (context == -2)
719 {
720 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
721 return;
722 }
723
724 if (msg->loglevel.level == 0)
725 level = LEVEL0;
726 else if (msg->loglevel.level == 1)
727 level = LEVEL1;
728 else if (msg->loglevel.level == 2)
729 level = LEVEL2;
730 else if (msg->loglevel.level == 3)
731 level = LEVEL3;
732 else
733 {
734 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
735 return;
736 }
737
738 logger_manager->enable_log_level(logger_manager, context, level);
739 }
740
741 /**
742 * Implementation of private_stroke_t.stroke_receive.
743 */
744 static void stroke_receive(private_stroke_t *this)
745 {
746 stroke_msg_t *msg;
747 u_int16_t msg_length;
748 struct sockaddr_un strokeaddr;
749 int strokeaddrlen = sizeof(strokeaddr);
750 ssize_t bytes_read;
751 int strokefd;
752 FILE *strokefile;
753 int oldstate;
754
755 /* disable cancellation by default */
756 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
757
758 while (1)
759 {
760 /* wait for connections, but allow thread to terminate */
761 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
762 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
763 pthread_setcancelstate(oldstate, NULL);
764
765 if (strokefd < 0)
766 {
767 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
768 continue;
769 }
770
771 /* peek the length */
772 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
773 if (bytes_read != sizeof(msg_length))
774 {
775 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
776 close(strokefd);
777 continue;
778 }
779
780 /* read message */
781 msg = malloc(msg_length);
782 bytes_read = recv(strokefd, msg, msg_length, 0);
783 if (bytes_read != msg_length)
784 {
785 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
786 close(strokefd);
787 continue;
788 }
789
790 strokefile = fdopen(dup(strokefd), "w");
791 if (strokefile == NULL)
792 {
793 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
794 close(strokefd);
795 free(msg);
796 continue;
797 }
798
799 /* setup a logger which writes status to the unix socket */
800 this->stroke_logger = logger_create("", CONTROL|ERROR, FALSE, strokefile);
801
802 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
803
804 switch (msg->type)
805 {
806 case STR_INITIATE:
807 stroke_initiate(this, msg);
808 break;
809 case STR_TERMINATE:
810 stroke_terminate(this, msg);
811 break;
812 case STR_STATUS:
813 stroke_status(this, msg);
814 break;
815 case STR_STATUS_ALL:
816 this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
817 stroke_status(this, msg);
818 break;
819 case STR_ADD_CONN:
820 stroke_add_conn(this, msg);
821 break;
822 case STR_DEL_CONN:
823 stroke_del_conn(this, msg);
824 break;
825 case STR_LOGTYPE:
826 stroke_logtype(this, msg);
827 break;
828 case STR_LOGLEVEL:
829 stroke_loglevel(this, msg);
830 break;
831 case STR_LIST:
832 stroke_list(this, msg);
833 break;
834 case STR_REREAD:
835 stroke_reread(this, msg);
836 break;
837 default:
838 this->logger->log(this->logger, ERROR, "received invalid stroke");
839 }
840 this->stroke_logger->destroy(this->stroke_logger);
841 fclose(strokefile);
842 close(strokefd);
843 free(msg);
844 }
845 }
846
847 /**
848 * Implementation of stroke_t.destroy.
849 */
850 static void destroy(private_stroke_t *this)
851 {
852
853 pthread_cancel(this->assigned_thread);
854 pthread_join(this->assigned_thread, NULL);
855
856 close(this->socket);
857 unlink(socket_addr.sun_path);
858 free(this);
859 }
860
861
862 /*
863 * Described in header-file
864 */
865 stroke_t *stroke_create()
866 {
867 private_stroke_t *this = malloc_thing(private_stroke_t);
868 mode_t old;
869
870 /* public functions */
871 this->public.destroy = (void (*)(stroke_t*))destroy;
872
873 /* private functions */
874 this->stroke_receive = stroke_receive;
875
876 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
877
878 /* set up unix socket */
879 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
880 if (this->socket == -1)
881 {
882 this->logger->log(this->logger, ERROR, "could not create whack socket");
883 free(this);
884 return NULL;
885 }
886
887 old = umask(~S_IRWXU);
888 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
889 {
890 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
891 close(this->socket);
892 free(this);
893 return NULL;
894 }
895 umask(old);
896
897 if (listen(this->socket, 0) < 0)
898 {
899 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
900 close(this->socket);
901 unlink(socket_addr.sun_path);
902 free(this);
903 return NULL;
904 }
905
906 /* start a thread reading from the socket */
907 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
908 {
909 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
910 close(this->socket);
911 unlink(socket_addr.sun_path);
912 free(this);
913 return NULL;
914 }
915
916 return (&this->public);
917 }