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