stroke now uses constant size string buffer
[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);
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 cert->destroy(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 my_id->clone(my_id), other_id->clone(other_id),
297 RSA_DIGITAL_SIGNATURE);
298 proposal = proposal_create(1);
299 proposal->add_algorithm(proposal, PROTO_IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
300 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
301 proposal->add_algorithm(proposal, PROTO_IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
302 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
303 proposal->add_algorithm(proposal, PROTO_IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
304 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
305 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
306 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
307 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
308 proposal->add_algorithm(proposal, PROTO_IKE, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
309 connection->add_proposal(connection, proposal);
310
311 /* add to global connection list */
312 charon->connections->add_connection(charon->connections, connection);
313 this->logger->log(this->logger, CONTROL, "added connection \"%s\": %s[%s]...%s[%s]",
314 msg->add_conn.name,
315 my_host->get_address(my_host),
316 my_id->get_string(my_id),
317 other_host->get_address(other_host),
318 other_id->get_string(other_id));
319
320 policy = policy_create(my_id, other_id);
321 proposal = proposal_create(1);
322 proposal->add_algorithm(proposal, PROTO_ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16);
323 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
324 proposal->add_algorithm(proposal, PROTO_ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
325 policy->add_proposal(policy, proposal);
326 policy->add_my_traffic_selector(policy, my_ts);
327 policy->add_other_traffic_selector(policy, other_ts);
328
329 /* add to global policy list */
330 charon->policies->add_policy(charon->policies, policy);
331 }
332
333 /**
334 * initiate a connection by name
335 */
336 static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg)
337 {
338 initiate_ike_sa_job_t *job;
339 connection_t *connection;
340
341 pop_string(msg, &(msg->initiate.name));
342 this->logger->log(this->logger, CONTROL, "received stroke: initiate \"%s\"", msg->initiate.name);
343 connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name);
344 if (connection == NULL)
345 {
346 this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name);
347 }
348 /* only initiate if it is an IKEv2 connection, ignore IKEv1 */
349 else if (connection->is_ikev2(connection))
350 {
351 this->stroke_logger->log(this->stroke_logger, CONTROL, "initiating connection \"%s\" (see log)...", msg->initiate.name);
352
353 job = initiate_ike_sa_job_create(connection);
354 charon->job_queue->add(charon->job_queue, (job_t*)job);
355 }
356 }
357
358 /**
359 * terminate a connection by name
360 */
361 static void stroke_terminate(private_stroke_t *this, stroke_msg_t *msg)
362 {
363 linked_list_t *ike_sas;
364 iterator_t *iterator;
365 int instances = 0;
366 connection_t *conn;
367
368 pop_string(msg, &(msg->terminate.name));
369 this->logger->log(this->logger, CONTROL, "received stroke: terminate \"%s\"", msg->terminate.name);
370
371 /* we have to do tricky tricks to give the most comprehensive output to the user.
372 * There are different cases:
373 * 1. Connection is available, but IKEv1:
374 * => just ignore it, let pluto print it
375 * 2. Connection is not available, but instances of a deleted connection template:
376 * => terminate them, and print their termination
377 * 3. Connection is not available, and and no instances are there:
378 * => show error about bad connection name
379 * 4. An IKEv2 connection is available, and may contain instances:
380 * => terminate and print, simple
381 */
382 conn = charon->connections->get_connection_by_name(charon->connections, msg->terminate.name);
383 if (conn == NULL || conn->is_ikev2(conn))
384 {
385 ike_sas = charon->ike_sa_manager->get_ike_sa_list_by_name(charon->ike_sa_manager, msg->terminate.name);
386
387 iterator = ike_sas->create_iterator(ike_sas, TRUE);
388 while (iterator->has_next(iterator))
389 {
390 ike_sa_id_t *ike_sa_id;
391 iterator->current(iterator, (void**)&ike_sa_id);
392 charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id);
393 ike_sa_id->destroy(ike_sa_id);
394 instances++;
395 }
396 iterator->destroy(iterator);
397 ike_sas->destroy(ike_sas);
398 if (conn == NULL && instances == 0)
399 {
400 this->stroke_logger->log(this->stroke_logger, CONTROL,
401 "no connection named \"%s\"",
402 msg->terminate.name);
403 }
404 else
405 {
406 this->stroke_logger->log(this->stroke_logger, CONTROL,
407 "terminated %d instances of \"%s\"",
408 instances, msg->terminate.name);
409 }
410 }
411 if (conn)
412 {
413 conn->destroy(conn);
414 }
415 }
416
417 /**
418 * show status of (established) connections
419 */
420 static void stroke_status(private_stroke_t *this, stroke_msg_t *msg)
421 {
422 if (msg->status.name)
423 {
424 pop_string(msg, &(msg->status.name));
425 }
426 charon->connections->log_connections(charon->connections, this->stroke_logger, msg->status.name);
427 charon->ike_sa_manager->log_status(charon->ike_sa_manager, this->stroke_logger, msg->status.name);
428 }
429
430 /**
431 * list various information
432 */
433 static void stroke_list(private_stroke_t *this, stroke_msg_t *msg, bool utc)
434 {
435 if (msg->type = STR_LIST_CERTS)
436 {
437 charon->credentials->log_certificates(charon->credentials, this->stroke_logger, utc);
438 }
439 }
440
441 logger_context_t get_context(char *context)
442 {
443 if (strcasecmp(context, "ALL") == 0) return ALL_LOGGERS;
444 else if (strcasecmp(context, "PARSR") == 0) return PARSER;
445 else if (strcasecmp(context, "GNRAT") == 0) return GENERATOR;
446 else if (strcasecmp(context, "IKESA") == 0) return IKE_SA;
447 else if (strcasecmp(context, "SAMGR") == 0) return IKE_SA_MANAGER;
448 else if (strcasecmp(context, "CHDSA") == 0) return CHILD_SA;
449 else if (strcasecmp(context, "MESSG") == 0) return MESSAGE;
450 else if (strcasecmp(context, "TPOOL") == 0) return THREAD_POOL;
451 else if (strcasecmp(context, "WORKR") == 0) return WORKER;
452 else if (strcasecmp(context, "SCHED") == 0) return SCHEDULER;
453 else if (strcasecmp(context, "SENDR") == 0) return SENDER;
454 else if (strcasecmp(context, "RECVR") == 0) return RECEIVER;
455 else if (strcasecmp(context, "SOCKT") == 0) return SOCKET;
456 else if (strcasecmp(context, "TESTR") == 0) return TESTER;
457 else if (strcasecmp(context, "DAEMN") == 0) return DAEMON;
458 else if (strcasecmp(context, "CONFG") == 0) return CONFIG;
459 else if (strcasecmp(context, "ENCPL") == 0) return ENCRYPTION_PAYLOAD;
460 else if (strcasecmp(context, "PAYLD") == 0) return PAYLOAD;
461 else return -2;
462 }
463
464 /**
465 * set the type of logged messages in a context
466 */
467 static void stroke_logtype(private_stroke_t *this, stroke_msg_t *msg)
468 {
469 pop_string(msg, &(msg->logtype.context));
470 pop_string(msg, &(msg->logtype.type));
471
472 this->logger->log(this->logger, CONTROL, "received stroke: logtype for %s", msg->logtype.context);
473
474 log_level_t level;
475 logger_context_t context = get_context(msg->logtype.context);
476 if (context == -2)
477 {
478 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->logtype.context);
479 return;
480 }
481
482 if (strcasecmp(msg->logtype.type, "CONTROL") == 0)
483 level = CONTROL;
484 else if (strcasecmp(msg->logtype.type, "ERROR") == 0)
485 level = ERROR;
486 else if (strcasecmp(msg->logtype.type, "AUDIT") == 0)
487 level = AUDIT;
488 else if (strcasecmp(msg->logtype.type, "RAW") == 0)
489 level = RAW;
490 else if (strcasecmp(msg->logtype.type, "PRIVATE") == 0)
491 level = PRIVATE;
492 else
493 {
494 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid type (%s)!", msg->logtype.type);
495 return;
496 }
497
498 if (msg->logtype.enable)
499 {
500 logger_manager->enable_log_level(logger_manager, context, level);
501 }
502 else
503 {
504 logger_manager->disable_log_level(logger_manager, context, level);
505 }
506 }
507
508 /**
509 * set the verbosity of a logger
510 */
511 static void stroke_loglevel(private_stroke_t *this, stroke_msg_t *msg)
512 {
513 log_level_t level;
514 logger_context_t context;
515
516 pop_string(msg, &(msg->loglevel.context));
517 this->logger->log(this->logger, CONTROL, "received stroke: loglevel for %s", msg->loglevel.context);
518
519 context = get_context(msg->loglevel.context);
520 if (context == -2)
521 {
522 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid context (%s)!", msg->loglevel.context);
523 return;
524 }
525
526 if (msg->loglevel.level == 0)
527 level = LEVEL0;
528 else if (msg->loglevel.level == 1)
529 level = LEVEL1;
530 else if (msg->loglevel.level == 2)
531 level = LEVEL2;
532 else if (msg->loglevel.level == 3)
533 level = LEVEL3;
534 else
535 {
536 this->stroke_logger->log(this->stroke_logger, ERROR, "invalid level (%d)!", msg->loglevel.level);
537 return;
538 }
539
540 logger_manager->enable_log_level(logger_manager, context, level);
541 }
542
543 /**
544 * Implementation of private_stroke_t.stroke_receive.
545 */
546 static void stroke_receive(private_stroke_t *this)
547 {
548 stroke_msg_t *msg;
549 u_int16_t msg_length;
550 struct sockaddr_un strokeaddr;
551 int strokeaddrlen = sizeof(strokeaddr);
552 ssize_t bytes_read;
553 int strokefd;
554 FILE *strokefile;
555 int oldstate;
556
557 /* disable cancellation by default */
558 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
559
560 while (1)
561 {
562 /* wait for connections, but allow thread to terminate */
563 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
564 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
565 pthread_setcancelstate(oldstate, NULL);
566
567 if (strokefd < 0)
568 {
569 this->logger->log(this->logger, ERROR, "accepting stroke connection failed: %s", strerror(errno));
570 continue;
571 }
572
573 /* peek the length */
574 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
575 if (bytes_read != sizeof(msg_length))
576 {
577 this->logger->log(this->logger, ERROR, "reading lenght of stroke message failed");
578 close(strokefd);
579 continue;
580 }
581
582 /* read message */
583 msg = malloc(msg_length);
584 bytes_read = recv(strokefd, msg, msg_length, 0);
585 if (bytes_read != msg_length)
586 {
587 this->logger->log(this->logger, ERROR, "reading stroke message failed: %s");
588 close(strokefd);
589 continue;
590 }
591
592 strokefile = fdopen(dup(strokefd), "w");
593 if (strokefile == NULL)
594 {
595 this->logger->log(this->logger, ERROR, "opening stroke output channel failed:", strerror(errno));
596 close(strokefd);
597 free(msg);
598 continue;
599 }
600
601 /* setup a logger which writes status to the unix socket */
602 this->stroke_logger = logger_create("-", CONTROL|ERROR, FALSE, strokefile);
603
604 this->logger->log_bytes(this->logger, RAW, "stroke message", (void*)msg, msg_length);
605
606 switch (msg->type)
607 {
608 case STR_INITIATE:
609 stroke_initiate(this, msg);
610 break;
611 case STR_TERMINATE:
612 stroke_terminate(this, msg);
613 break;
614 case STR_STATUS:
615 stroke_status(this, msg);
616 break;
617 case STR_STATUS_ALL:
618 this->stroke_logger->enable_level(this->stroke_logger, LEVEL1);
619 stroke_status(this, msg);
620 break;
621 case STR_ADD_CONN:
622 stroke_add_conn(this, msg);
623 break;
624 case STR_LOGTYPE:
625 stroke_logtype(this, msg);
626 break;
627 case STR_LOGLEVEL:
628 stroke_loglevel(this, msg);
629 break;
630 case STR_LIST_CERTS:
631 stroke_list(this, msg, FALSE);
632 break;
633 default:
634 this->logger->log(this->logger, ERROR, "received invalid stroke");
635 }
636 this->stroke_logger->destroy(this->stroke_logger);
637 fclose(strokefile);
638 close(strokefd);
639 free(msg);
640 }
641 }
642
643 /**
644 * Implementation of stroke_t.destroy.
645 */
646 static void destroy(private_stroke_t *this)
647 {
648
649 pthread_cancel(this->assigned_thread);
650 pthread_join(this->assigned_thread, NULL);
651
652 close(this->socket);
653 unlink(socket_addr.sun_path);
654 free(this);
655 }
656
657
658 /*
659 * Described in header-file
660 */
661 stroke_t *stroke_create()
662 {
663 private_stroke_t *this = malloc_thing(private_stroke_t);
664 mode_t old;
665
666 /* public functions */
667 this->public.destroy = (void (*)(stroke_t*))destroy;
668
669 /* private functions */
670 this->stroke_receive = stroke_receive;
671
672 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
673
674 /* set up unix socket */
675 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
676 if (this->socket == -1)
677 {
678 this->logger->log(this->logger, ERROR, "could not create whack socket");
679 free(this);
680 return NULL;
681 }
682
683 old = umask(~S_IRWXU);
684 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
685 {
686 this->logger->log(this->logger, ERROR, "could not bind stroke socket: %s", strerror(errno));
687 close(this->socket);
688 free(this);
689 return NULL;
690 }
691 umask(old);
692
693 if (listen(this->socket, 0) < 0)
694 {
695 this->logger->log(this->logger, ERROR, "could not listen on stroke socket: %s", strerror(errno));
696 close(this->socket);
697 unlink(socket_addr.sun_path);
698 free(this);
699 return NULL;
700 }
701
702 /* start a thread reading from the socket */
703 if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->stroke_receive, this) != 0)
704 {
705 this->logger->log(this->logger, ERROR, "Could not spawn stroke thread");
706 close(this->socket);
707 unlink(socket_addr.sun_path);
708 free(this);
709 return NULL;
710 }
711
712 return (&this->public);
713 }