2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include "stroke_socket.h"
21 #include <sys/types.h>
23 #include <sys/socket.h>
25 #include <sys/fcntl.h>
29 #include <processing/jobs/callback_job.h>
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"
38 typedef struct stroke_job_context_t stroke_job_context_t
;
39 typedef struct private_stroke_socket_t private_stroke_socket_t
;
42 * private data of stroke_socket
44 struct private_stroke_socket_t
{
49 stroke_socket_t
public;
52 * Unix socket to listen for strokes
57 * job accepting stroke messages
62 * configuration backend
64 stroke_config_t
*config
;
67 * controller to control daemon
69 stroke_control_t
*control
;
82 * Status information logging
88 * job context to pass to processing thread
90 struct stroke_job_context_t
{
93 * file descriptor to read from
98 * global stroke interface
100 private_stroke_socket_t
*this;
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
110 static void pop_string(stroke_msg_t
*msg
, char **string
)
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
)
123 *string
= "(invalid pointer in stroke msg)";
127 *string
= (char*)msg
+ (unsigned long)*string
;
132 * Pop the strings of a stroke_end_t struct and log them for debugging purposes
134 static void pop_end(stroke_msg_t
*msg
, const char* label
, stroke_end_t
*end
)
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
);
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
);
156 * Add a connection to the configuration list
158 static void stroke_add_conn(private_stroke_socket_t
*this, stroke_msg_t
*msg
)
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
);
175 this->config
->add(this->config
, msg
);
179 * Delete a connection from the list
181 static void stroke_del_conn(private_stroke_socket_t
*this, stroke_msg_t
*msg
)
183 pop_string(msg
, &msg
->del_conn
.name
);
184 DBG1(DBG_CFG
, "received stroke: delete connection '%s'", msg
->del_conn
.name
);
186 this->config
->del(this->config
, msg
);
190 * initiate a connection by name
192 static void stroke_initiate(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
194 pop_string(msg
, &msg
->initiate
.name
);
195 DBG1(DBG_CFG
, "received stroke: initiate '%s'", msg
->initiate
.name
);
197 this->control
->initiate(this->control
, msg
, out
);
201 * terminate a connection by name
203 static void stroke_terminate(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
205 pop_string(msg
, &msg
->terminate
.name
);
206 DBG1(DBG_CFG
, "received stroke: terminate '%s'", msg
->terminate
.name
);
208 this->control
->terminate(this->control
, msg
, out
);
212 * route a policy (install SPD entries)
214 static void stroke_route(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
216 pop_string(msg
, &msg
->route
.name
);
217 DBG1(DBG_CFG
, "received stroke: route '%s'", msg
->route
.name
);
219 this->control
->route(this->control
, msg
, out
);
225 static void stroke_unroute(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
227 pop_string(msg
, &msg
->terminate
.name
);
228 DBG1(DBG_CFG
, "received stroke: unroute '%s'", msg
->route
.name
);
230 this->control
->unroute(this->control
, msg
, out
);
234 * Add a ca information record to the cainfo list
236 static void stroke_add_ca(private_stroke_socket_t
*this,
237 stroke_msg_t
*msg
, FILE *out
)
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
);
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
);
253 DBG1(DBG_CFG
, "received stroke: add ca '%s'", msg
->add_ca
.name
);
255 this->ca
->add(this->ca
, msg
);
259 * Delete a ca information record from the cainfo list
261 static void stroke_del_ca(private_stroke_socket_t
*this,
262 stroke_msg_t
*msg
, FILE *out
)
264 pop_string(msg
, &msg
->del_ca
.name
);
265 DBG1(DBG_CFG
, "received stroke: delete ca '%s'", msg
->del_ca
.name
);
267 this->ca
->del(this->ca
, msg
);
272 * show status of daemon
274 static void stroke_status(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
,
277 pop_string(msg
, &(msg
->status
.name
));
279 this->list
->status(this->list
, msg
, out
, all
);
283 * list various information
285 static void stroke_list(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
287 if (msg
->list
.flags
& LIST_CAINFOS
)
289 this->ca
->list(this->ca
, msg
, out
);
291 this->list
->list(this->list
, msg
, out
);
295 * reread various information
297 static void stroke_reread(private_stroke_socket_t
*this,
298 stroke_msg_t
*msg
, FILE *out
)
300 this->cred
->reread(this->cred
, msg
);
304 * purge various information
306 static void stroke_purge(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
308 /* TODO: flush cache */
311 signal_t
get_signal_from_logtype(char *type
)
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
;
327 * set the verbosity debug output
329 static void stroke_loglevel(private_stroke_socket_t
*this, stroke_msg_t
*msg
, FILE *out
)
333 pop_string(msg
, &(msg
->loglevel
.type
));
334 DBG1(DBG_CFG
, "received stroke: loglevel %d for %s",
335 msg
->loglevel
.level
, msg
->loglevel
.type
);
337 signal
= get_signal_from_logtype(msg
->loglevel
.type
);
340 fprintf(out
, "invalid type (%s)!\n", msg
->loglevel
.type
);
344 charon
->outlog
->set_level(charon
->outlog
, signal
, msg
->loglevel
.level
);
345 charon
->syslog
->set_level(charon
->syslog
, signal
, msg
->loglevel
.level
);
350 * destroy a job context
352 static void stroke_job_context_destroy(stroke_job_context_t
*this)
359 * process a stroke request from the socket pointed by "fd"
361 static job_requeue_t
process(stroke_job_context_t
*ctx
)
364 u_int16_t msg_length
;
367 private_stroke_socket_t
*this = ctx
->this;
368 int strokefd
= ctx
->fd
;
370 /* peek the length */
371 bytes_read
= recv(strokefd
, &msg_length
, sizeof(msg_length
), MSG_PEEK
);
372 if (bytes_read
!= sizeof(msg_length
))
374 DBG1(DBG_CFG
, "reading length of stroke message failed: %s",
377 return JOB_REQUEUE_NONE
;
381 msg
= malloc(msg_length
);
382 bytes_read
= recv(strokefd
, msg
, msg_length
, 0);
383 if (bytes_read
!= msg_length
)
385 DBG1(DBG_CFG
, "reading stroke message failed: %s", strerror(errno
));
387 return JOB_REQUEUE_NONE
;
390 out
= fdopen(strokefd
, "w");
393 DBG1(DBG_CFG
, "opening stroke output channel failed: %s", strerror(errno
));
396 return JOB_REQUEUE_NONE
;
399 DBG3(DBG_CFG
, "stroke message %b", (void*)msg
, msg_length
);
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
);
409 stroke_initiate(this, msg
, out
);
412 stroke_route(this, msg
, out
);
415 stroke_unroute(this, msg
, out
);
418 stroke_terminate(this, msg
, out
);
421 stroke_status(this, msg
, out
, FALSE
);
424 stroke_status(this, msg
, out
, TRUE
);
427 stroke_add_conn(this, msg
);
430 stroke_del_conn(this, msg
);
433 stroke_add_ca(this, msg
, out
);
436 stroke_del_ca(this, msg
, out
);
439 stroke_loglevel(this, msg
, out
);
442 stroke_list(this, msg
, out
);
445 stroke_reread(this, msg
, out
);
448 stroke_purge(this, msg
, out
);
451 DBG1(DBG_CFG
, "received unknown stroke");
453 /* remove and execute cancellation handlers */
454 pthread_cleanup_pop(1);
455 pthread_cleanup_pop(1);
457 return JOB_REQUEUE_NONE
;
461 * Implementation of private_stroke_socket_t.stroke_receive.
463 static job_requeue_t
receive(private_stroke_socket_t
*this)
465 struct sockaddr_un strokeaddr
;
466 int strokeaddrlen
= sizeof(strokeaddr
);
470 stroke_job_context_t
*ctx
;
472 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, &oldstate
);
473 strokefd
= accept(this->socket
, (struct sockaddr
*)&strokeaddr
, &strokeaddrlen
);
474 pthread_setcancelstate(oldstate
, NULL
);
478 DBG1(DBG_CFG
, "accepting stroke connection failed: %s", strerror(errno
));
479 return JOB_REQUEUE_FAIR
;
482 ctx
= malloc_thing(stroke_job_context_t
);
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
);
489 return JOB_REQUEUE_FAIR
;
494 * initialize and open stroke socket
496 static bool open_socket(private_stroke_socket_t
*this)
498 struct sockaddr_un socket_addr
= { AF_UNIX
, STROKE_SOCKET
};
501 /* set up unix socket */
502 this->socket
= socket(AF_UNIX
, SOCK_STREAM
, 0);
503 if (this->socket
== -1)
505 DBG1(DBG_CFG
, "could not create stroke socket");
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)
513 DBG1(DBG_CFG
, "could not bind stroke socket: %s", strerror(errno
));
518 if (chown(socket_addr
.sun_path
, IPSEC_UID
, IPSEC_GID
) != 0)
520 DBG1(DBG_CFG
, "changing stroke socket permissions failed: %s",
524 if (listen(this->socket
, 0) < 0)
526 DBG1(DBG_CFG
, "could not listen on stroke socket: %s", strerror(errno
));
528 unlink(socket_addr
.sun_path
);
535 * Implementation of stroke_socket_t.destroy
537 static void destroy(private_stroke_socket_t
*this)
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
);
554 stroke_socket_t
*stroke_socket_create()
556 private_stroke_socket_t
*this = malloc_thing(private_stroke_socket_t
);
558 this->public.destroy
= (void(*)(stroke_socket_t
*))destroy
;
560 if (!open_socket(this))
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();
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
);
576 this->job
= callback_job_create((callback_job_cb_t
)receive
,
578 charon
->processor
->queue_job(charon
->processor
, (job_t
*)this->job
);
580 return &this->public;