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