reintegrated bus-refactoring branch
[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
29 #include <processing/jobs/callback_job.h>
30 #include <daemon.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->id);
146 pop_string(msg, &end->cert);
147 pop_string(msg, &end->ca);
148 pop_string(msg, &end->groups);
149 pop_string(msg, &end->updown);
150
151 DBG2(DBG_CFG, " %s=%s", label, end->address);
152 DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets);
153 DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip);
154 DBG2(DBG_CFG, " %sid=%s", label, end->id);
155 DBG2(DBG_CFG, " %scert=%s", label, end->cert);
156 DBG2(DBG_CFG, " %sca=%s", label, end->ca);
157 DBG2(DBG_CFG, " %sgroups=%s", label, end->groups);
158 DBG2(DBG_CFG, " %supdown=%s", label, end->updown);
159 }
160
161 /**
162 * Add a connection to the configuration list
163 */
164 static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
165 {
166 pop_string(msg, &msg->add_conn.name);
167 DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name);
168
169 DBG2(DBG_CFG, "conn %s", msg->add_conn.name);
170 pop_end(msg, "left", &msg->add_conn.me);
171 pop_end(msg, "right", &msg->add_conn.other);
172 pop_string(msg, &msg->add_conn.eap_identity);
173 pop_string(msg, &msg->add_conn.algorithms.ike);
174 pop_string(msg, &msg->add_conn.algorithms.esp);
175 pop_string(msg, &msg->add_conn.ikeme.mediated_by);
176 pop_string(msg, &msg->add_conn.ikeme.peerid);
177 DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity);
178 DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike);
179 DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp);
180 DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no");
181 DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by);
182 DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid);
183
184 this->config->add(this->config, msg);
185 this->attribute->add_pool(this->attribute, msg);
186 }
187
188 /**
189 * Delete a connection from the list
190 */
191 static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg)
192 {
193 pop_string(msg, &msg->del_conn.name);
194 DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name);
195
196 this->config->del(this->config, msg);
197 this->attribute->del_pool(this->attribute, msg);
198 }
199
200 /**
201 * initiate a connection by name
202 */
203 static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
204 {
205 pop_string(msg, &msg->initiate.name);
206 DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name);
207
208 this->control->initiate(this->control, msg, out);
209 }
210
211 /**
212 * terminate a connection by name
213 */
214 static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
215 {
216 pop_string(msg, &msg->terminate.name);
217 DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
218
219 this->control->terminate(this->control, msg, out);
220 }
221
222 /**
223 * terminate a connection by peers virtual IP
224 */
225 static void stroke_terminate_srcip(private_stroke_socket_t *this,
226 stroke_msg_t *msg, FILE *out)
227 {
228 pop_string(msg, &msg->terminate_srcip.start);
229 pop_string(msg, &msg->terminate_srcip.end);
230 DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s",
231 msg->terminate_srcip.start, msg->terminate_srcip.end);
232
233 this->control->terminate_srcip(this->control, msg, out);
234 }
235
236 /**
237 * route a policy (install SPD entries)
238 */
239 static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
240 {
241 pop_string(msg, &msg->route.name);
242 DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name);
243
244 this->control->route(this->control, msg, out);
245 }
246
247 /**
248 * unroute a policy
249 */
250 static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
251 {
252 pop_string(msg, &msg->terminate.name);
253 DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name);
254
255 this->control->unroute(this->control, msg, out);
256 }
257
258 /**
259 * Add a ca information record to the cainfo list
260 */
261 static void stroke_add_ca(private_stroke_socket_t *this,
262 stroke_msg_t *msg, FILE *out)
263 {
264 pop_string(msg, &msg->add_ca.name);
265 DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name);
266
267 pop_string(msg, &msg->add_ca.cacert);
268 pop_string(msg, &msg->add_ca.crluri);
269 pop_string(msg, &msg->add_ca.crluri2);
270 pop_string(msg, &msg->add_ca.ocspuri);
271 pop_string(msg, &msg->add_ca.ocspuri2);
272 pop_string(msg, &msg->add_ca.certuribase);
273 DBG2(DBG_CFG, "ca %s", msg->add_ca.name);
274 DBG2(DBG_CFG, " cacert=%s", msg->add_ca.cacert);
275 DBG2(DBG_CFG, " crluri=%s", msg->add_ca.crluri);
276 DBG2(DBG_CFG, " crluri2=%s", msg->add_ca.crluri2);
277 DBG2(DBG_CFG, " ocspuri=%s", msg->add_ca.ocspuri);
278 DBG2(DBG_CFG, " ocspuri2=%s", msg->add_ca.ocspuri2);
279 DBG2(DBG_CFG, " certuribase=%s", msg->add_ca.certuribase);
280
281 this->ca->add(this->ca, msg);
282 }
283
284 /**
285 * Delete a ca information record from the cainfo list
286 */
287 static void stroke_del_ca(private_stroke_socket_t *this,
288 stroke_msg_t *msg, FILE *out)
289 {
290 pop_string(msg, &msg->del_ca.name);
291 DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name);
292
293 this->ca->del(this->ca, msg);
294 }
295
296
297 /**
298 * show status of daemon
299 */
300 static void stroke_status(private_stroke_socket_t *this,
301 stroke_msg_t *msg, FILE *out, bool all)
302 {
303 pop_string(msg, &(msg->status.name));
304
305 this->list->status(this->list, msg, out, all);
306 }
307
308 /**
309 * list various information
310 */
311 static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
312 {
313 if (msg->list.flags & LIST_CAINFOS)
314 {
315 this->ca->list(this->ca, msg, out);
316 }
317 this->list->list(this->list, msg, out);
318 }
319
320 /**
321 * reread various information
322 */
323 static void stroke_reread(private_stroke_socket_t *this,
324 stroke_msg_t *msg, FILE *out)
325 {
326 this->cred->reread(this->cred, msg);
327 }
328
329 /**
330 * purge various information
331 */
332 static void stroke_purge(private_stroke_socket_t *this,
333 stroke_msg_t *msg, FILE *out)
334 {
335 charon->credentials->flush_cache(charon->credentials,
336 CERT_X509_OCSP_RESPONSE);
337 }
338
339 debug_t get_group_from_name(char *type)
340 {
341 if (strcasecmp(type, "any") == 0) return DBG_ANY;
342 else if (strcasecmp(type, "mgr") == 0) return DBG_MGR;
343 else if (strcasecmp(type, "ike") == 0) return DBG_IKE;
344 else if (strcasecmp(type, "chd") == 0) return DBG_CHD;
345 else if (strcasecmp(type, "job") == 0) return DBG_JOB;
346 else if (strcasecmp(type, "cfg") == 0) return DBG_CFG;
347 else if (strcasecmp(type, "knl") == 0) return DBG_KNL;
348 else if (strcasecmp(type, "net") == 0) return DBG_NET;
349 else if (strcasecmp(type, "enc") == 0) return DBG_ENC;
350 else if (strcasecmp(type, "lib") == 0) return DBG_LIB;
351 else return -1;
352 }
353
354 /**
355 * set the verbosity debug output
356 */
357 static void stroke_loglevel(private_stroke_socket_t *this,
358 stroke_msg_t *msg, FILE *out)
359 {
360 debug_t group;
361
362 pop_string(msg, &(msg->loglevel.type));
363 DBG1(DBG_CFG, "received stroke: loglevel %d for %s",
364 msg->loglevel.level, msg->loglevel.type);
365
366 group = get_group_from_name(msg->loglevel.type);
367 if (group < 0)
368 {
369 fprintf(out, "invalid type (%s)!\n", msg->loglevel.type);
370 return;
371 }
372
373 charon->outlog->set_level(charon->outlog, group, msg->loglevel.level);
374 charon->syslog->set_level(charon->syslog, group, msg->loglevel.level);
375 }
376
377 /**
378 * set various config options
379 */
380 static void stroke_config(private_stroke_socket_t *this,
381 stroke_msg_t *msg, FILE *out)
382 {
383 this->cred->cachecrl(this->cred, msg->config.cachecrl);
384 }
385
386 /**
387 * destroy a job context
388 */
389 static void stroke_job_context_destroy(stroke_job_context_t *this)
390 {
391 if (this->fd)
392 {
393 close(this->fd);
394 }
395 free(this);
396 }
397
398 /**
399 * process a stroke request from the socket pointed by "fd"
400 */
401 static job_requeue_t process(stroke_job_context_t *ctx)
402 {
403 stroke_msg_t *msg;
404 u_int16_t msg_length;
405 ssize_t bytes_read;
406 FILE *out;
407 private_stroke_socket_t *this = ctx->this;
408 int strokefd = ctx->fd;
409
410 /* peek the length */
411 bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
412 if (bytes_read != sizeof(msg_length))
413 {
414 DBG1(DBG_CFG, "reading length of stroke message failed: %s",
415 strerror(errno));
416 return JOB_REQUEUE_NONE;
417 }
418
419 /* read message */
420 msg = alloca(msg_length);
421 bytes_read = recv(strokefd, msg, msg_length, 0);
422 if (bytes_read != msg_length)
423 {
424 DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
425 return JOB_REQUEUE_NONE;
426 }
427
428 out = fdopen(strokefd, "w");
429 if (out == NULL)
430 {
431 DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
432 return JOB_REQUEUE_NONE;
433 }
434
435 DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
436
437 switch (msg->type)
438 {
439 case STR_INITIATE:
440 stroke_initiate(this, msg, out);
441 break;
442 case STR_ROUTE:
443 stroke_route(this, msg, out);
444 break;
445 case STR_UNROUTE:
446 stroke_unroute(this, msg, out);
447 break;
448 case STR_TERMINATE:
449 stroke_terminate(this, msg, out);
450 break;
451 case STR_TERMINATE_SRCIP:
452 stroke_terminate_srcip(this, msg, out);
453 break;
454 case STR_STATUS:
455 stroke_status(this, msg, out, FALSE);
456 break;
457 case STR_STATUS_ALL:
458 stroke_status(this, msg, out, TRUE);
459 break;
460 case STR_ADD_CONN:
461 stroke_add_conn(this, msg);
462 break;
463 case STR_DEL_CONN:
464 stroke_del_conn(this, msg);
465 break;
466 case STR_ADD_CA:
467 stroke_add_ca(this, msg, out);
468 break;
469 case STR_DEL_CA:
470 stroke_del_ca(this, msg, out);
471 break;
472 case STR_LOGLEVEL:
473 stroke_loglevel(this, msg, out);
474 break;
475 case STR_CONFIG:
476 stroke_config(this, msg, out);
477 break;
478 case STR_LIST:
479 stroke_list(this, msg, out);
480 break;
481 case STR_REREAD:
482 stroke_reread(this, msg, out);
483 break;
484 case STR_PURGE:
485 stroke_purge(this, msg, out);
486 break;
487 default:
488 DBG1(DBG_CFG, "received unknown stroke");
489 break;
490 }
491 fclose(out);
492 /* fclose() closes underlying FD */
493 ctx->fd = 0;
494 return JOB_REQUEUE_NONE;
495 }
496
497 /**
498 * Implementation of private_stroke_socket_t.stroke_receive.
499 */
500 static job_requeue_t receive(private_stroke_socket_t *this)
501 {
502 struct sockaddr_un strokeaddr;
503 int strokeaddrlen = sizeof(strokeaddr);
504 int strokefd;
505 int oldstate;
506 callback_job_t *job;
507 stroke_job_context_t *ctx;
508
509 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
510 strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
511 pthread_setcancelstate(oldstate, NULL);
512
513 if (strokefd < 0)
514 {
515 DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
516 return JOB_REQUEUE_FAIR;
517 }
518
519 ctx = malloc_thing(stroke_job_context_t);
520 ctx->fd = strokefd;
521 ctx->this = this;
522 job = callback_job_create((callback_job_cb_t)process,
523 ctx, (void*)stroke_job_context_destroy, this->job);
524 charon->processor->queue_job(charon->processor, (job_t*)job);
525
526 return JOB_REQUEUE_FAIR;
527 }
528
529
530 /**
531 * initialize and open stroke socket
532 */
533 static bool open_socket(private_stroke_socket_t *this)
534 {
535 struct sockaddr_un socket_addr = { AF_UNIX, STROKE_SOCKET};
536 mode_t old;
537
538 /* set up unix socket */
539 this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
540 if (this->socket == -1)
541 {
542 DBG1(DBG_CFG, "could not create stroke socket");
543 return FALSE;
544 }
545
546 unlink(socket_addr.sun_path);
547 old = umask(~(S_IRWXU | S_IRWXG));
548 if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
549 {
550 DBG1(DBG_CFG, "could not bind stroke socket: %s", strerror(errno));
551 close(this->socket);
552 return FALSE;
553 }
554 umask(old);
555 if (chown(socket_addr.sun_path, charon->uid, charon->gid) != 0)
556 {
557 DBG1(DBG_CFG, "changing stroke socket permissions failed: %s",
558 strerror(errno));
559 }
560
561 if (listen(this->socket, 10) < 0)
562 {
563 DBG1(DBG_CFG, "could not listen on stroke socket: %s", strerror(errno));
564 close(this->socket);
565 unlink(socket_addr.sun_path);
566 return FALSE;
567 }
568 return TRUE;
569 }
570
571 /**
572 * Implementation of stroke_socket_t.destroy
573 */
574 static void destroy(private_stroke_socket_t *this)
575 {
576 this->job->cancel(this->job);
577 charon->credentials->remove_set(charon->credentials, &this->ca->set);
578 charon->credentials->remove_set(charon->credentials, &this->cred->set);
579 charon->backends->remove_backend(charon->backends, &this->config->backend);
580 charon->attributes->remove_provider(charon->attributes, &this->attribute->provider);
581 this->cred->destroy(this->cred);
582 this->ca->destroy(this->ca);
583 this->config->destroy(this->config);
584 this->attribute->destroy(this->attribute);
585 this->control->destroy(this->control);
586 this->list->destroy(this->list);
587 free(this);
588 }
589
590 /*
591 * see header file
592 */
593 stroke_socket_t *stroke_socket_create()
594 {
595 private_stroke_socket_t *this = malloc_thing(private_stroke_socket_t);
596
597 this->public.destroy = (void(*)(stroke_socket_t*))destroy;
598
599 if (!open_socket(this))
600 {
601 free(this);
602 return NULL;
603 }
604
605 this->cred = stroke_cred_create();
606 this->attribute = stroke_attribute_create();
607 this->ca = stroke_ca_create(this->cred);
608 this->config = stroke_config_create(this->ca, this->cred);
609 this->control = stroke_control_create();
610 this->list = stroke_list_create();
611
612 charon->credentials->add_set(charon->credentials, &this->ca->set);
613 charon->credentials->add_set(charon->credentials, &this->cred->set);
614 charon->backends->add_backend(charon->backends, &this->config->backend);
615 charon->attributes->add_provider(charon->attributes, &this->attribute->provider);
616
617 this->job = callback_job_create((callback_job_cb_t)receive,
618 this, NULL, NULL);
619 charon->processor->queue_job(charon->processor, (job_t*)this->job);
620
621 return &this->public;
622 }
623