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