Make number of concurrently handled stroke messages configurable.
[strongswan.git] / src / libcharon / plugins / stroke / stroke_socket.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "stroke_socket.h"
18
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include <hydra.h>
28 #include <daemon.h>
29 #include <threading/mutex.h>
30 #include <threading/thread.h>
31 #include <threading/condvar.h>
32 #include <utils/linked_list.h>
33 #include <processing/jobs/callback_job.h>
34
35 #include "stroke_config.h"
36 #include "stroke_control.h"
37 #include "stroke_cred.h"
38 #include "stroke_ca.h"
39 #include "stroke_attribute.h"
40 #include "stroke_list.h"
41
42 /**
43 * To avoid clogging the thread pool with (blocking) jobs, we limit the number
44 * of concurrently handled stroke commands.
45 */
46 #define MAX_CONCURRENT_DEFAULT 4
47
48 typedef struct stroke_job_context_t stroke_job_context_t;
49 typedef struct private_stroke_socket_t private_stroke_socket_t;
50
51 /**
52 * private data of stroke_socket
53 */
54 struct private_stroke_socket_t {
55
56 /**
57 * public functions
58 */
59 stroke_socket_t public;
60
61 /**
62 * Unix socket to listen for strokes
63 */
64 int socket;
65
66 /**
67 * job accepting stroke messages
68 */
69 callback_job_t *receiver;
70
71 /**
72 * job handling stroke messages
73 */
74 callback_job_t *handler;
75
76 /**
77 * queued stroke commands
78 */
79 linked_list_t *commands;
80
81 /**
82 * lock for command list
83 */
84 mutex_t *mutex;
85
86 /**
87 * condvar to signal the arrival or completion of commands
88 */
89 condvar_t *condvar;
90
91 /**
92 * the number of currently handled commands
93 */
94 u_int handling;
95
96 /**
97 * the maximum number of concurrently handled commands
98 */
99 u_int max_concurrent;
100
101 /**
102 * configuration backend
103 */
104 stroke_config_t *config;
105
106 /**
107 * attribute provider
108 */
109 stroke_attribute_t *attribute;
110
111 /**
112 * controller to control daemon
113 */
114 stroke_control_t *control;
115
116 /**
117 * credential set
118 */
119 stroke_cred_t *cred;
120
121 /**
122 * CA sections
123 */
124 stroke_ca_t *ca;
125
126 /**
127 * status information logging
128 */
129 stroke_list_t *list;
130 };
131
132 /**
133 * job context to pass to processing thread
134 */
135 struct stroke_job_context_t {
136
137 /**
138 * file descriptor to read from
139 */
140 int fd;
141
142 /**
143 * global stroke interface
144 */
145 private_stroke_socket_t *this;
146 };
147
148 /**
149 * Helper function which corrects the string pointers
150 * in a stroke_msg_t. Strings in a stroke_msg sent over "wire"
151 * contains RELATIVE addresses (relative to the beginning of the
152 * stroke_msg). They must be corrected if they reach our address
153 * space...
154 */
155 static void pop_string(stroke_msg_t *msg, char **string)
156 {
157 if (*string == NULL)
158 {
159 return;
160 }
161
162 /* check for sanity of string pointer and string */
163 if (string < (char**)msg ||
164 string > (char**)((char*)msg + sizeof(stroke_msg_t)) ||
165 (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) ||
166 (unsigned long)*string > msg->length)
167 {
168 *string = "(invalid pointer in stroke msg)";
169 }
170 else
171 {
172 *string = (char*)msg + (unsigned long)*string;
173 }
174 }
175
176 /**
177 * Pop the strings of a stroke_end_t struct and log them for debugging purposes
178 */
179 static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
180 {
181 pop_string(msg, &end->address);
182 pop_string(msg, &end->subnets);
183 pop_string(msg, &end->sourceip);
184 pop_string(msg, &end->auth);
185 pop_string(msg, &end->auth2);
186 pop_string(msg, &end->id);
187 pop_string(msg, &end->id2);
188 pop_string(msg, &end->cert);
189 pop_string(msg, &end->cert2);
190 pop_string(msg, &end->ca);
191 pop_string(msg, &end->ca2);
192 pop_string(msg, &end->groups);
193 pop_string(msg, &end->cert_policy);
194 pop_string(msg, &end->updown);
195
196 DBG2(DBG_CFG, " %s=%s", label, end->address);
197 DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets);
198 DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip);
199 DBG2(DBG_CFG, " %sauth=%s", label, end->auth);
200 DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2);
201 DBG2(DBG_CFG, " %sid=%s", label, end->id);
202 DBG2(DBG_CFG, " %sid2=%s", label, end->id2);
203 DBG2(DBG_CFG, " %scert=%s", label, end->cert);
204 DBG2(DBG_CFG, " %scert2=%s", label, end->cert2);
205 DBG2(DBG_CFG, " %sca=%s", label, end->ca);
206 DBG2(DBG_CFG, " %sca2=%s", label, end->ca2);
207 DBG2(DBG_CFG, " %sgroups=%s", label, end->groups);
208 DBG2(DBG_CFG, " %supdown=%s", label, end->updown);
209 }
210
211 /**
212 * Add a connection to the configuration list
213 */
214 static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
215 {
216 pop_string(msg, &msg->add_conn.name);
217 DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
218
219 DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
220 pop_end(msg, "left", &msg->add_conn.me);
221 pop_end(msg, "right", &msg->add_conn.other);
222 pop_string(msg, &msg->add_conn.eap_identity);
223 pop_string(msg, &msg->add_conn.aaa_identity);
224 pop_string(msg, &msg->add_conn.algorithms.ike);
225 pop_string(msg, &msg->add_conn.algorithms.esp);
226 pop_string(msg, &msg->add_conn.ikeme.mediated_by);
227 pop_string(msg, &msg->add_conn.ikeme.peerid);
228 DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity);
229 DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity);
230 DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
231 DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
232 DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay);
233 DBG2(DBG_CFG, " dpdaction=%d", msg->add_conn.dpd.action);
234 DBG2(DBG_CFG, " closeaction=%d", msg->add_conn.close_action);
235 DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
236 DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by);
237 DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid);
238
239 this->config->add(this->config, msg);
240 this->attribute->add_pool(this->attribute, msg);
241 }
242
243 /**
244 * Delete a connection from the list
245 */
246 static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
247 {
248 pop_string(msg, &msg->del_conn.name);
249 DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
250
251 this->config->del(this->config, msg);
252 this->attribute->del_pool(this->attribute, msg);
253 }
254
255 /**
256 * initiate a connection by name
257 */
258 static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
259 {
260 pop_string(msg, &msg->initiate.name);
261 DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
262
263 this->control->initiate(this->control, msg, out);
264 }
265
266 /**
267 * terminate a connection by name
268 */
269 static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
270 {
271 pop_string(msg, &msg->terminate.name);
272 DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
273
274 this->control->terminate(this->control, msg, out);
275 }
276
277 /**
278 * terminate a connection by peers virtual IP
279 */
280 static void stroke_terminate_srcip(private_stroke_socket_t *this,
281 stroke_msg_t *msg, FILE *out)
282 {
283 pop_string(msg, &msg->terminate_srcip.start);
284 pop_string(msg, &msg->terminate_srcip.end);
285 DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s",
286 msg->terminate_srcip.start, msg->terminate_srcip.end);
287
288 this->control->terminate_srcip(this->control, msg, out);
289 }
290
291 /**
292 * rekey a connection by name/id
293 */
294 static void stroke_rekey(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
295 {
296 pop_string(msg, &msg->terminate.name);
297 DBG1(DBG_CFG, "received stroke: rekey '%s'", msg->rekey.name);
298
299 this->control->rekey(this->control, msg, out);
300 }
301
302 /**
303 * route a policy (install SPD entries)
304 */
305 static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
306 {
307 pop_string(msg, &msg->route.name);
308 DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name);
309
310 this->control->route(this->control, msg, out);
311 }
312
313 /**
314 * unroute a policy
315 */
316 static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
317 {
318 pop_string(msg, &msg->terminate.name);
319 DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name);
320
321 this->control->unroute(this->control, msg, out);
322 }
323
324 /**
325 * Add a ca information record to the cainfo list
326 */
327 static void stroke_add_ca(private_stroke_socket_t *this,
328 stroke_msg_t *msg, FILE *out)
329 {
330 pop_string(msg, &msg->add_ca.name);
331 DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
332
333 pop_string(msg, &msg->add_ca.cacert);
334 pop_string(msg, &msg->add_ca.crluri);
335 pop_string(msg, &msg->add_ca.crluri2);
336 pop_string(msg, &msg->add_ca.ocspuri);
337 pop_string(msg, &msg->add_ca.ocspuri2);
338 pop_string(msg, &msg->add_ca.certuribase);
339 DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
340 DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert);
341 DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri);
342 DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2);
343 DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri);
344 DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2);
345 DBG2(DBG_CFG, " certuribase=%s", msg->add_ca.certuribase);
346
347 this->ca->add(this->ca, msg);
348 }
349
350 /**
351 * Delete a ca information record from the cainfo list
352 */
353 static void stroke_del_ca(private_stroke_socket_t *this,
354 stroke_msg_t *msg, FILE *out)
355 {
356 pop_string(msg, &msg->del_ca.name);
357 DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
358
359 this->ca->del(this->ca, msg);
360 }
361
362
363 /**
364 * show status of daemon
365 */
366 static void stroke_status(private_stroke_socket_t *this,
367 stroke_msg_t *msg, FILE *out, bool all, bool wait)
368 {
369 pop_string(msg, &(msg->status.name));
370
371 this->list->status(this->list, msg, out, all, wait);
372 }
373
374 /**
375 * list various information
376 */
377 static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
378 {
379 if (msg->list.flags & LIST_CAINFOS)
380 {
381 this->ca->list(this->ca, msg, out);
382 }
383 this->list->list(this->list, msg, out);
384 }
385
386 /**
387 * reread various information
388 */
389 static void stroke_reread(private_stroke_socket_t *this,
390 stroke_msg_t *msg, FILE *out)
391 {
392 this->cred->reread(this->cred, msg, out);
393 }
394
395 /**
396 * purge various information
397 */
398 static void stroke_purge(private_stroke_socket_t *this,
399 stroke_msg_t *msg, FILE *out)
400 {
401 if (msg->purge.flags & PURGE_OCSP)
402 {
403 lib->credmgr->flush_cache(lib->credmgr, CERT_X509_OCSP_RESPONSE);
404 }
405 if (msg->purge.flags & PURGE_CRLS)
406 {
407 lib->credmgr->flush_cache(lib->credmgr, CERT_X509_CRL);
408 }
409 if (msg->purge.flags & PURGE_CERTS)
410 {
411 lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
412 }
413 if (msg->purge.flags & PURGE_IKE)
414 {
415 this->control->purge_ike(this->control, msg, out);
416 }
417 }
418
419 /**
420 * Export in-memory credentials
421 */
422 static void stroke_export(private_stroke_socket_t *this,
423 stroke_msg_t *msg, FILE *out)
424 {
425 pop_string(msg, &msg->export.selector);
426
427 if (msg->purge.flags & EXPORT_X509)
428 {
429 enumerator_t *enumerator;
430 identification_t *id;
431 certificate_t *cert;
432 chunk_t encoded;
433
434 id = identification_create_from_string(msg->export.selector);
435 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
436 CERT_X509, KEY_ANY, id, FALSE);
437 while (enumerator->enumerate(enumerator, &cert))
438 {
439 if (cert->get_encoding(cert, CERT_PEM, &encoded))
440 {
441 fprintf(out, "%.*s", (int)encoded.len, encoded.ptr);
442 free(encoded.ptr);
443 }
444 }
445 enumerator->destroy(enumerator);
446 id->destroy(id);
447 }
448 }
449
450 /**
451 * list pool leases
452 */
453 static void stroke_leases(private_stroke_socket_t *this,
454 stroke_msg_t *msg, FILE *out)
455 {
456 pop_string(msg, &msg->leases.pool);
457 pop_string(msg, &msg->leases.address);
458
459 this->list->leases(this->list, msg, out);
460 }
461
462 /**
463 * Show memory usage
464 */
465 static void stroke_memusage(private_stroke_socket_t *this,
466 stroke_msg_t *msg, FILE *out)
467 {
468 if (lib->leak_detective)
469 {
470 lib->leak_detective->usage(lib->leak_detective, out);
471 }
472 }
473
474 /**
475 * set the verbosity debug output
476 */
477 static void stroke_loglevel(private_stroke_socket_t *this,
478 stroke_msg_t *msg, FILE *out)
479 {
480 enumerator_t *enumerator;
481 sys_logger_t *sys_logger;
482 file_logger_t *file_logger;
483 debug_t group;
484
485 pop_string(msg, &(msg->loglevel.type));
486 DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
487 msg->loglevel.level, msg->loglevel.type);
488
489 group = enum_from_name(debug_names, msg->loglevel.type);
490 if ((int)group < 0)
491 {
492 fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
493 return;
494 }
495 /* we set the loglevel on ALL sys- and file-loggers */
496 enumerator = charon->sys_loggers->create_enumerator(charon->sys_loggers);
497 while (enumerator->enumerate(enumerator, &sys_logger))
498 {
499 sys_logger->set_level(sys_logger, group, msg->loglevel.level);
500 }
501 enumerator->destroy(enumerator);
502 enumerator = charon->file_loggers->create_enumerator(charon->file_loggers);
503 while (enumerator->enumerate(enumerator, &file_logger))
504 {
505 file_logger->set_level(file_logger, group, msg->loglevel.level);
506 }
507 enumerator->destroy(enumerator);
508 }
509
510 /**
511 * set various config options
512 */
513 static void stroke_config(private_stroke_socket_t *this,
514 stroke_msg_t *msg, FILE *out)
515 {
516 this->cred->cachecrl(this->cred, msg->config.cachecrl);
517 }
518
519 /**
520 * destroy a job context
521 */
522 static void stroke_job_context_destroy(stroke_job_context_t *this)
523 {
524 if (this->fd)
525 {
526 close(this->fd);
527 }
528 free(this);
529 }
530
531 /**
532 * called to signal the completion of a command
533 */
534 static inline job_requeue_t job_processed(private_stroke_socket_t *this)
535 {
536 this->mutex->lock(this->mutex);
537 this->handling--;
538 this->condvar->signal(this->condvar);
539 this->mutex->unlock(this->mutex);
540 return JOB_REQUEUE_NONE;
541 }
542
543 /**
544 * process a stroke request from the socket pointed by "fd"
545 */
546 static job_requeue_t process(stroke_job_context_t *ctx)
547 {
548 stroke_msg_t *msg;
549 u_int16_t msg_length;
550 ssize_t bytes_read;
551 FILE *out;
552 private_stroke_socket_t *this = ctx->this;
553 int strokefd = ctx->fd;
554
555 /* peek the length */
556 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
557 if (bytes_read != sizeof(msg_length))
558 {
559 DBG1(DBG_CFG, "reading length of stroke message failed: %s",
560 strerror(errno));
561 return job_processed(this);
562 }
563
564 /* read message */
565 msg = alloca(msg_length);
566 bytes_read = recv(strokefd, msg, msg_length, 0);
567 if (bytes_read != msg_length)
568 {
569 DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
570 return job_processed(this);
571 }
572
573 out = fdopen(strokefd, "w+");
574 if (out == NULL)
575 {
576 DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
577 return job_processed(this);
578 }
579
580 DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
581
582 switch (msg->type)
583 {
584 case STR_INITIATE:
585 stroke_initiate(this, msg, out);
586 break;
587 case STR_ROUTE:
588 stroke_route(this, msg, out);
589 break;
590 case STR_UNROUTE:
591 stroke_unroute(this, msg, out);
592 break;
593 case STR_TERMINATE:
594 stroke_terminate(this, msg, out);
595 break;
596 case STR_TERMINATE_SRCIP:
597 stroke_terminate_srcip(this, msg, out);
598 break;
599 case STR_REKEY:
600 stroke_rekey(this, msg, out);
601 break;
602 case STR_STATUS:
603 stroke_status(this, msg, out, FALSE, TRUE);
604 break;
605 case STR_STATUS_ALL:
606 stroke_status(this, msg, out, TRUE, TRUE);
607 break;
608 case STR_STATUS_ALL_NOBLK:
609 stroke_status(this, msg, out, TRUE, FALSE);
610 break;
611 case STR_ADD_CONN:
612 stroke_add_conn(this, msg);
613 break;
614 case STR_DEL_CONN:
615 stroke_del_conn(this, msg);
616 break;
617 case STR_ADD_CA:
618 stroke_add_ca(this, msg, out);
619 break;
620 case STR_DEL_CA:
621 stroke_del_ca(this, msg, out);
622 break;
623 case STR_LOGLEVEL:
624 stroke_loglevel(this, msg, out);
625 break;
626 case STR_CONFIG:
627 stroke_config(this, msg, out);
628 break;
629 case STR_LIST:
630 stroke_list(this, msg, out);
631 break;
632 case STR_REREAD:
633 stroke_reread(this, msg, out);
634 break;
635 case STR_PURGE:
636 stroke_purge(this, msg, out);
637 break;
638 case STR_EXPORT:
639 stroke_export(this, msg, out);
640 break;
641 case STR_LEASES:
642 stroke_leases(this, msg, out);
643 break;
644 case STR_MEMUSAGE:
645 stroke_memusage(this, msg, out);
646 break;
647 default:
648 DBG1(DBG_CFG, "received unknown stroke");
649 break;
650 }
651 fclose(out);
652 /* fclose() closes underlying FD */
653 ctx->fd = 0;
654 return job_processed(this);
655 }
656
657 /**
658 * Handle queued stroke commands
659 */
660 static job_requeue_t handle(private_stroke_socket_t *this)
661 {
662 stroke_job_context_t *ctx;
663 callback_job_t *job;
664 bool oldstate;
665
666 this->mutex->lock(this->mutex);
667 thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
668 oldstate = thread_cancelability(TRUE);
669 while (this->commands->get_count(this->commands) == 0 ||
670 this->handling >= this->max_concurrent)
671 {
672 this->condvar->wait(this->condvar, this->mutex);
673 }
674 thread_cancelability(oldstate);
675 this->commands->remove_first(this->commands, (void**)&ctx);
676 this->handling++;
677 thread_cleanup_pop(TRUE);
678 job = callback_job_create_with_prio((callback_job_cb_t)process, ctx,
679 (void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH);
680 lib->processor->queue_job(lib->processor, (job_t*)job);
681 return JOB_REQUEUE_DIRECT;
682 }
683
684 /**
685 * Accept stroke commands and queue them to be handled
686 */
687 static job_requeue_t receive(private_stroke_socket_t *this)
688 {
689 struct sockaddr_un strokeaddr;
690 int strokeaddrlen = sizeof(strokeaddr);
691 int strokefd;
692 bool oldstate;
693 stroke_job_context_t *ctx;
694
695 oldstate = thread_cancelability(TRUE);
696 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
697 thread_cancelability(oldstate);
698
699 if (strokefd < 0)
700 {
701 DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
702 return JOB_REQUEUE_FAIR;
703 }
704
705 INIT(ctx,
706 .fd = strokefd,
707 .this = this,
708 );
709 this->mutex->lock(this->mutex);
710 this->commands->insert_last(this->commands, ctx);
711 this->condvar->signal(this->condvar);
712 this->mutex->unlock(this->mutex);
713
714 return JOB_REQUEUE_FAIR;
715 }
716
717 /**
718 * initialize and open stroke socket
719 */
720 static bool open_socket(private_stroke_socket_t *this)
721 {
722 struct sockaddr_un socket_addr;
723 mode_t old;
724
725 socket_addr.sun_family = AF_UNIX;
726 strcpy(socket_addr.sun_path, STROKE_SOCKET);
727
728 /* set up unix socket */
729 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
730 if (this->socket == -1)
731 {
732 DBG1(DBG_CFG, "could not create stroke socket");
733 return FALSE;
734 }
735
736 unlink(socket_addr.sun_path);
737 old = umask(~(S_IRWXU | S_IRWXG));
738 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
739 {
740 DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
741 close(this->socket);
742 return FALSE;
743 }
744 umask(old);
745 if (chown(socket_addr.sun_path, charon->uid, charon->gid) != 0)
746 {
747 DBG1(DBG_CFG, "changing stroke socket permissions failed: %s",
748 strerror(errno));
749 }
750
751 if (listen(this->socket, 10) < 0)
752 {
753 DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
754 close(this->socket);
755 unlink(socket_addr.sun_path);
756 return FALSE;
757 }
758 return TRUE;
759 }
760
761 METHOD(stroke_socket_t, destroy, void,
762 private_stroke_socket_t *this)
763 {
764 this->handler->cancel(this->handler);
765 this->receiver->cancel(this->receiver);
766 this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy);
767 this->condvar->destroy(this->condvar);
768 this->mutex->destroy(this->mutex);
769 lib->credmgr->remove_set(lib->credmgr, &this->ca->set);
770 lib->credmgr->remove_set(lib->credmgr, &this->cred->set);
771 charon->backends->remove_backend(charon->backends, &this->config->backend);
772 hydra->attributes->remove_provider(hydra->attributes, &this->attribute->provider);
773 this->cred->destroy(this->cred);
774 this->ca->destroy(this->ca);
775 this->config->destroy(this->config);
776 this->attribute->destroy(this->attribute);
777 this->control->destroy(this->control);
778 this->list->destroy(this->list);
779 free(this);
780 }
781
782 /*
783 * see header file
784 */
785 stroke_socket_t *stroke_socket_create()
786 {
787 private_stroke_socket_t *this;
788
789 INIT(this,
790 .public = {
791 .destroy = _destroy,
792 },
793 );
794
795 if (!open_socket(this))
796 {
797 free(this);
798 return NULL;
799 }
800
801 this->cred = stroke_cred_create();
802 this->attribute = stroke_attribute_create();
803 this->ca = stroke_ca_create(this->cred);
804 this->config = stroke_config_create(this->ca, this->cred);
805 this->control = stroke_control_create();
806 this->list = stroke_list_create(this->attribute);
807
808 this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
809 this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
810 this->commands = linked_list_create();
811 this->max_concurrent = lib->settings->get_int(lib->settings,
812 "charon.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT);
813
814 lib->credmgr->add_set(lib->credmgr, &this->ca->set);
815 lib->credmgr->add_set(lib->credmgr, &this->cred->set);
816 charon->backends->add_backend(charon->backends, &this->config->backend);
817 hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider);
818
819 this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive,
820 this, NULL, NULL, JOB_PRIO_CRITICAL);
821 lib->processor->queue_job(lib->processor, (job_t*)this->receiver);
822
823 this->handler = callback_job_create_with_prio((callback_job_cb_t)handle,
824 this, NULL, NULL, JOB_PRIO_CRITICAL);
825 lib->processor->queue_job(lib->processor, (job_t*)this->handler);
826
827 return &this->public;
828 }
829