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