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