]>
Commit | Line | Data |
---|---|---|
0b14fdb9 | 1 | /* |
5ab03863 | 2 | * Copyright (C) 2011-2013 Tobias Brunner |
0b14fdb9 | 3 | * Copyright (C) 2008 Martin Willi |
19ef2aec TB |
4 | * |
5 | * Copyright (C) secunet Security Networks AG | |
0b14fdb9 MW |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
0b14fdb9 MW |
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> | |
0b14fdb9 MW |
25 | #include <unistd.h> |
26 | #include <errno.h> | |
27 | ||
0b14fdb9 MW |
28 | #include <daemon.h> |
29 | ||
30 | #include "stroke_config.h" | |
31 | #include "stroke_control.h" | |
32 | #include "stroke_cred.h" | |
33 | #include "stroke_ca.h" | |
ad81e51a | 34 | #include "stroke_attribute.h" |
63e46054 | 35 | #include "stroke_handler.h" |
0b14fdb9 | 36 | #include "stroke_list.h" |
8554895b | 37 | #include "stroke_counter.h" |
0b14fdb9 | 38 | |
8ff513a8 TB |
39 | /** |
40 | * To avoid clogging the thread pool with (blocking) jobs, we limit the number | |
41 | * of concurrently handled stroke commands. | |
42 | */ | |
7c0c2349 | 43 | #define MAX_CONCURRENT_DEFAULT 4 |
8ff513a8 | 44 | |
0b14fdb9 MW |
45 | typedef struct stroke_job_context_t stroke_job_context_t; |
46 | typedef struct private_stroke_socket_t private_stroke_socket_t; | |
47 | ||
48 | /** | |
49 | * private data of stroke_socket | |
50 | */ | |
51 | struct private_stroke_socket_t { | |
52 | ||
53 | /** | |
54 | * public functions | |
55 | */ | |
56 | stroke_socket_t public; | |
7daf5226 | 57 | |
0b14fdb9 | 58 | /** |
065907b9 | 59 | * Service accepting stroke connections |
0b14fdb9 | 60 | */ |
065907b9 | 61 | stream_service_t *service; |
7c0c2349 | 62 | |
0b14fdb9 MW |
63 | /** |
64 | * configuration backend | |
65 | */ | |
66 | stroke_config_t *config; | |
7daf5226 | 67 | |
ad81e51a MW |
68 | /** |
69 | * attribute provider | |
70 | */ | |
71 | stroke_attribute_t *attribute; | |
7daf5226 | 72 | |
63e46054 MW |
73 | /** |
74 | * attribute handler (requests only) | |
75 | */ | |
76 | stroke_handler_t *handler; | |
77 | ||
0b14fdb9 MW |
78 | /** |
79 | * controller to control daemon | |
80 | */ | |
81 | stroke_control_t *control; | |
7daf5226 | 82 | |
0b14fdb9 MW |
83 | /** |
84 | * credential set | |
85 | */ | |
86 | stroke_cred_t *cred; | |
7daf5226 | 87 | |
0b14fdb9 MW |
88 | /** |
89 | * CA sections | |
90 | */ | |
91 | stroke_ca_t *ca; | |
7daf5226 | 92 | |
0b14fdb9 | 93 | /** |
8ff513a8 | 94 | * status information logging |
0b14fdb9 MW |
95 | */ |
96 | stroke_list_t *list; | |
8554895b MW |
97 | |
98 | /** | |
99 | * Counter values for IKE events | |
100 | */ | |
101 | stroke_counter_t *counter; | |
5ab03863 TB |
102 | |
103 | /** | |
104 | * TRUE if log level changes are not allowed | |
105 | */ | |
106 | bool prevent_loglevel_changes; | |
0b14fdb9 MW |
107 | }; |
108 | ||
28a79e4e TB |
109 | /** |
110 | * Helper macro to log configuration options, but only if they are defined. | |
111 | */ | |
112 | #define DBG_OPT(...) VA_ARGS_DISPATCH(DBG_OPT, __VA_ARGS__)(__VA_ARGS__) | |
113 | #define DBG_OPT2(fmt, val) ({ \ | |
114 | typeof(val) _val = val; \ | |
115 | if (_val) { DBG2(DBG_CFG, fmt, _val); } \ | |
116 | }) | |
117 | #define DBG_OPT3(fmt, label, val) ({ \ | |
118 | typeof(val) _val = val; \ | |
119 | if (_val) { DBG2(DBG_CFG, fmt, label, _val); } \ | |
120 | }) | |
121 | ||
0b14fdb9 MW |
122 | /** |
123 | * Helper function which corrects the string pointers | |
124 | * in a stroke_msg_t. Strings in a stroke_msg sent over "wire" | |
125 | * contains RELATIVE addresses (relative to the beginning of the | |
126 | * stroke_msg). They must be corrected if they reach our address | |
127 | * space... | |
128 | */ | |
129 | static void pop_string(stroke_msg_t *msg, char **string) | |
130 | { | |
131 | if (*string == NULL) | |
132 | { | |
133 | return; | |
134 | } | |
135 | ||
136 | /* check for sanity of string pointer and string */ | |
137 | if (string < (char**)msg || | |
aee071ed | 138 | string > (char**)((char*)msg + sizeof(stroke_msg_t)) || |
0b14fdb9 MW |
139 | (unsigned long)*string < (unsigned long)((char*)msg->buffer - (char*)msg) || |
140 | (unsigned long)*string > msg->length) | |
141 | { | |
142 | *string = "(invalid pointer in stroke msg)"; | |
143 | } | |
144 | else | |
145 | { | |
146 | *string = (char*)msg + (unsigned long)*string; | |
147 | } | |
148 | } | |
149 | ||
150 | /** | |
151 | * Pop the strings of a stroke_end_t struct and log them for debugging purposes | |
152 | */ | |
153 | static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) | |
154 | { | |
155 | pop_string(msg, &end->address); | |
34443902 | 156 | pop_string(msg, &end->subnets); |
0b14fdb9 | 157 | pop_string(msg, &end->sourceip); |
17319aa2 | 158 | pop_string(msg, &end->dns); |
a44bb934 MW |
159 | pop_string(msg, &end->auth); |
160 | pop_string(msg, &end->auth2); | |
0b14fdb9 | 161 | pop_string(msg, &end->id); |
a44bb934 | 162 | pop_string(msg, &end->id2); |
5f1931ad | 163 | pop_string(msg, &end->rsakey); |
0b14fdb9 | 164 | pop_string(msg, &end->cert); |
a44bb934 | 165 | pop_string(msg, &end->cert2); |
0b14fdb9 | 166 | pop_string(msg, &end->ca); |
a44bb934 | 167 | pop_string(msg, &end->ca2); |
0b14fdb9 | 168 | pop_string(msg, &end->groups); |
46df61df | 169 | pop_string(msg, &end->groups2); |
6367de28 | 170 | pop_string(msg, &end->cert_policy); |
0b14fdb9 | 171 | pop_string(msg, &end->updown); |
7daf5226 | 172 | |
28a79e4e TB |
173 | DBG_OPT(" %s=%s", label, end->address); |
174 | DBG_OPT(" %ssubnet=%s", label, end->subnets); | |
175 | DBG_OPT(" %ssourceip=%s", label, end->sourceip); | |
176 | DBG_OPT(" %sdns=%s", label, end->dns); | |
177 | DBG_OPT(" %sauth=%s", label, end->auth); | |
178 | DBG_OPT(" %sauth2=%s", label, end->auth2); | |
179 | DBG_OPT(" %sid=%s", label, end->id); | |
180 | DBG_OPT(" %sid2=%s", label, end->id2); | |
181 | DBG_OPT(" %srsakey=%s", label, end->rsakey); | |
182 | DBG_OPT(" %scert=%s", label, end->cert); | |
183 | DBG_OPT(" %scert2=%s", label, end->cert2); | |
184 | DBG_OPT(" %sca=%s", label, end->ca); | |
185 | DBG_OPT(" %sca2=%s", label, end->ca2); | |
186 | DBG_OPT(" %sgroups=%s", label, end->groups); | |
187 | DBG_OPT(" %sgroups2=%s", label, end->groups2); | |
188 | DBG_OPT(" %supdown=%s", label, end->updown); | |
0b14fdb9 MW |
189 | } |
190 | ||
191 | /** | |
192 | * Add a connection to the configuration list | |
193 | */ | |
194 | static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) | |
195 | { | |
196 | pop_string(msg, &msg->add_conn.name); | |
197 | DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); | |
7c8eff1e | 198 | |
0b14fdb9 MW |
199 | DBG2(DBG_CFG, "conn %s", msg->add_conn.name); |
200 | pop_end(msg, "left", &msg->add_conn.me); | |
201 | pop_end(msg, "right", &msg->add_conn.other); | |
82290106 | 202 | pop_string(msg, &msg->add_conn.eap_identity); |
64d7b073 | 203 | pop_string(msg, &msg->add_conn.aaa_identity); |
21a4fc83 | 204 | pop_string(msg, &msg->add_conn.xauth_identity); |
0b14fdb9 MW |
205 | pop_string(msg, &msg->add_conn.algorithms.ike); |
206 | pop_string(msg, &msg->add_conn.algorithms.esp); | |
05764129 | 207 | pop_string(msg, &msg->add_conn.algorithms.ah); |
dc04b7c7 TB |
208 | pop_string(msg, &msg->add_conn.ikeme.mediated_by); |
209 | pop_string(msg, &msg->add_conn.ikeme.peerid); | |
28a79e4e TB |
210 | DBG_OPT(" eap_identity=%s", msg->add_conn.eap_identity); |
211 | DBG_OPT(" aaa_identity=%s", msg->add_conn.aaa_identity); | |
212 | DBG_OPT(" xauth_identity=%s", msg->add_conn.xauth_identity); | |
213 | DBG_OPT(" ike=%s", msg->add_conn.algorithms.ike); | |
214 | DBG_OPT(" esp=%s", msg->add_conn.algorithms.esp); | |
215 | DBG_OPT(" ah=%s", msg->add_conn.algorithms.ah); | |
216 | DBG_OPT(" dpddelay=%d", msg->add_conn.dpd.delay); | |
217 | DBG_OPT(" dpdtimeout=%d", msg->add_conn.dpd.timeout); | |
218 | DBG_OPT(" dpdaction=%d", msg->add_conn.dpd.action); | |
219 | DBG_OPT(" closeaction=%d", msg->add_conn.close_action); | |
4270c8fc | 220 | DBG_OPT(" sha256_96=%s", msg->add_conn.sha256_96 ? "yes" : "no"); |
28a79e4e TB |
221 | DBG_OPT(" mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); |
222 | DBG_OPT(" mediated_by=%s", msg->add_conn.ikeme.mediated_by); | |
223 | DBG_OPT(" me_peerid=%s", msg->add_conn.ikeme.peerid); | |
224 | DBG_OPT(" keyexchange=ikev%u", msg->add_conn.version); | |
0b14fdb9 MW |
225 | |
226 | this->config->add(this->config, msg); | |
96c2b3cf | 227 | this->attribute->add_dns(this->attribute, msg); |
63e46054 | 228 | this->handler->add_attributes(this->handler, msg); |
0b14fdb9 MW |
229 | } |
230 | ||
231 | /** | |
232 | * Delete a connection from the list | |
233 | */ | |
234 | static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg) | |
235 | { | |
236 | pop_string(msg, &msg->del_conn.name); | |
237 | DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name); | |
7daf5226 | 238 | |
0b14fdb9 | 239 | this->config->del(this->config, msg); |
96c2b3cf | 240 | this->attribute->del_dns(this->attribute, msg); |
63e46054 | 241 | this->handler->del_attributes(this->handler, msg); |
0b14fdb9 MW |
242 | } |
243 | ||
244 | /** | |
245 | * initiate a connection by name | |
246 | */ | |
247 | static void stroke_initiate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) | |
248 | { | |
249 | pop_string(msg, &msg->initiate.name); | |
250 | DBG1(DBG_CFG, "received stroke: initiate '%s'", msg->initiate.name); | |
7daf5226 | 251 | |
0b14fdb9 MW |
252 | this->control->initiate(this->control, msg, out); |
253 | } | |
254 | ||
255 | /** | |
256 | * terminate a connection by name | |
257 | */ | |
258 | static void stroke_terminate(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) | |
259 | { | |
260 | pop_string(msg, &msg->terminate.name); | |
261 | DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name); | |
262 | ||
263 | this->control->terminate(this->control, msg, out); | |
7daf5226 | 264 | } |
13106499 MW |
265 | |
266 | /** | |
267 | * terminate a connection by peers virtual IP | |
268 | */ | |
269 | static void stroke_terminate_srcip(private_stroke_socket_t *this, | |
270 | stroke_msg_t *msg, FILE *out) | |
271 | { | |
272 | pop_string(msg, &msg->terminate_srcip.start); | |
273 | pop_string(msg, &msg->terminate_srcip.end); | |
274 | DBG1(DBG_CFG, "received stroke: terminate-srcip %s-%s", | |
275 | msg->terminate_srcip.start, msg->terminate_srcip.end); | |
276 | ||
277 | this->control->terminate_srcip(this->control, msg, out); | |
0b14fdb9 MW |
278 | } |
279 | ||
851d6048 MW |
280 | /** |
281 | * rekey a connection by name/id | |
282 | */ | |
283 | static void stroke_rekey(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) | |
284 | { | |
285 | pop_string(msg, &msg->terminate.name); | |
286 | DBG1(DBG_CFG, "received stroke: rekey '%s'", msg->rekey.name); | |
287 | ||
288 | this->control->rekey(this->control, msg, out); | |
289 | } | |
290 | ||
0b14fdb9 MW |
291 | /** |
292 | * route a policy (install SPD entries) | |
293 | */ | |
294 | static void stroke_route(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) | |
295 | { | |
296 | pop_string(msg, &msg->route.name); | |
297 | DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name); | |
7daf5226 | 298 | |
0b14fdb9 MW |
299 | this->control->route(this->control, msg, out); |
300 | } | |
301 | ||
302 | /** | |
303 | * unroute a policy | |
304 | */ | |
305 | static void stroke_unroute(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out) | |
306 | { | |
307 | pop_string(msg, &msg->terminate.name); | |
308 | DBG1(DBG_CFG, "received stroke: unroute '%s'", msg->route.name); | |
7daf5226 | 309 | |
0b14fdb9 MW |
310 | this->control->unroute(this->control, msg, out); |
311 | } | |
312 | ||
313 | /** | |
314 | * Add a ca information record to the cainfo list | |
315 | */ | |
316 | static void stroke_add_ca(private_stroke_socket_t *this, | |
317 | stroke_msg_t *msg, FILE *out) | |
318 | { | |
319 | pop_string(msg, &msg->add_ca.name); | |
7c8eff1e AS |
320 | DBG1(DBG_CFG, "received stroke: add ca '%s'", msg->add_ca.name); |
321 | ||
0b14fdb9 MW |
322 | pop_string(msg, &msg->add_ca.cacert); |
323 | pop_string(msg, &msg->add_ca.crluri); | |
324 | pop_string(msg, &msg->add_ca.crluri2); | |
325 | pop_string(msg, &msg->add_ca.ocspuri); | |
326 | pop_string(msg, &msg->add_ca.ocspuri2); | |
6439267a | 327 | pop_string(msg, &msg->add_ca.certuribase); |
28a79e4e TB |
328 | DBG2(DBG_CFG, "ca %s", msg->add_ca.name); |
329 | DBG_OPT(" cacert=%s", msg->add_ca.cacert); | |
330 | DBG_OPT(" crluri=%s", msg->add_ca.crluri); | |
331 | DBG_OPT(" crluri2=%s", msg->add_ca.crluri2); | |
332 | DBG_OPT(" ocspuri=%s", msg->add_ca.ocspuri); | |
333 | DBG_OPT(" ocspuri2=%s", msg->add_ca.ocspuri2); | |
334 | DBG_OPT(" certuribase=%s", msg->add_ca.certuribase); | |
7daf5226 | 335 | |
0b14fdb9 MW |
336 | this->ca->add(this->ca, msg); |
337 | } | |
338 | ||
339 | /** | |
340 | * Delete a ca information record from the cainfo list | |
341 | */ | |
342 | static void stroke_del_ca(private_stroke_socket_t *this, | |
343 | stroke_msg_t *msg, FILE *out) | |
344 | { | |
345 | pop_string(msg, &msg->del_ca.name); | |
346 | DBG1(DBG_CFG, "received stroke: delete ca '%s'", msg->del_ca.name); | |
7daf5226 | 347 | |
0b14fdb9 MW |
348 | this->ca->del(this->ca, msg); |
349 | } | |
350 | ||
351 | ||
352 | /** | |
353 | * show status of daemon | |
354 | */ | |
f957f7df | 355 | static void stroke_status(private_stroke_socket_t *this, |
a694b481 | 356 | stroke_msg_t *msg, FILE *out, bool all, bool wait) |
0b14fdb9 MW |
357 | { |
358 | pop_string(msg, &(msg->status.name)); | |
7daf5226 | 359 | |
a694b481 | 360 | this->list->status(this->list, msg, out, all, wait); |
0b14fdb9 MW |
361 | } |
362 | ||
363 | /** | |
364 | * list various information | |
365 | */ | |
d022322b MW |
366 | static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, |
367 | FILE *out) | |
0b14fdb9 MW |
368 | { |
369 | if (msg->list.flags & LIST_CAINFOS) | |
370 | { | |
371 | this->ca->list(this->ca, msg, out); | |
372 | } | |
373 | this->list->list(this->list, msg, out); | |
374 | } | |
375 | ||
376 | /** | |
377 | * reread various information | |
378 | */ | |
379 | static void stroke_reread(private_stroke_socket_t *this, | |
380 | stroke_msg_t *msg, FILE *out) | |
381 | { | |
750bbcf9 | 382 | this->cred->reread(this->cred, msg, out); |
0b14fdb9 MW |
383 | } |
384 | ||
385 | /** | |
386 | * purge various information | |
387 | */ | |
f957f7df MW |
388 | static void stroke_purge(private_stroke_socket_t *this, |
389 | stroke_msg_t *msg, FILE *out) | |
0b14fdb9 | 390 | { |
83242706 MW |
391 | if (msg->purge.flags & PURGE_OCSP) |
392 | { | |
2ccc02a4 | 393 | lib->credmgr->flush_cache(lib->credmgr, CERT_X509_OCSP_RESPONSE); |
83242706 | 394 | } |
cf5866b9 | 395 | if (msg->purge.flags & PURGE_CRLS) |
6aa144dd MW |
396 | { |
397 | lib->credmgr->flush_cache(lib->credmgr, CERT_X509_CRL); | |
398 | } | |
cf5866b9 | 399 | if (msg->purge.flags & PURGE_CERTS) |
6aa144dd MW |
400 | { |
401 | lib->credmgr->flush_cache(lib->credmgr, CERT_X509); | |
402 | } | |
83242706 MW |
403 | if (msg->purge.flags & PURGE_IKE) |
404 | { | |
405 | this->control->purge_ike(this->control, msg, out); | |
406 | } | |
0b14fdb9 MW |
407 | } |
408 | ||
de2debf8 MW |
409 | /** |
410 | * Print a certificate in PEM to out | |
411 | */ | |
412 | static void print_pem_cert(FILE *out, certificate_t *cert) | |
413 | { | |
414 | chunk_t encoded; | |
415 | ||
416 | if (cert->get_encoding(cert, CERT_PEM, &encoded)) | |
417 | { | |
418 | fprintf(out, "%.*s", (int)encoded.len, encoded.ptr); | |
419 | free(encoded.ptr); | |
420 | } | |
421 | } | |
422 | ||
3d711a68 MW |
423 | /** |
424 | * Export in-memory credentials | |
425 | */ | |
426 | static void stroke_export(private_stroke_socket_t *this, | |
427 | stroke_msg_t *msg, FILE *out) | |
428 | { | |
429 | pop_string(msg, &msg->export.selector); | |
430 | ||
4c31657d | 431 | if (msg->export.flags & EXPORT_X509) |
3d711a68 MW |
432 | { |
433 | enumerator_t *enumerator; | |
434 | identification_t *id; | |
435 | certificate_t *cert; | |
3d711a68 MW |
436 | |
437 | id = identification_create_from_string(msg->export.selector); | |
438 | enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, | |
439 | CERT_X509, KEY_ANY, id, FALSE); | |
440 | while (enumerator->enumerate(enumerator, &cert)) | |
441 | { | |
de2debf8 | 442 | print_pem_cert(out, cert); |
3d711a68 MW |
443 | } |
444 | enumerator->destroy(enumerator); | |
445 | id->destroy(id); | |
446 | } | |
de2debf8 MW |
447 | |
448 | if (msg->export.flags & (EXPORT_CONN_CERT | EXPORT_CONN_CHAIN)) | |
449 | { | |
450 | enumerator_t *sas, *auths, *certs; | |
451 | ike_sa_t *ike_sa; | |
452 | auth_cfg_t *auth; | |
453 | certificate_t *cert; | |
454 | auth_rule_t rule; | |
455 | ||
456 | sas = charon->ike_sa_manager->create_enumerator( | |
457 | charon->ike_sa_manager, TRUE); | |
458 | while (sas->enumerate(sas, &ike_sa)) | |
459 | { | |
460 | if (streq(msg->export.selector, ike_sa->get_name(ike_sa))) | |
461 | { | |
462 | auths = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE); | |
463 | while (auths->enumerate(auths, &auth)) | |
464 | { | |
465 | bool got_subject = FALSE; | |
466 | ||
467 | certs = auth->create_enumerator(auth); | |
468 | while (certs->enumerate(certs, &rule, &cert)) | |
469 | { | |
470 | switch (rule) | |
471 | { | |
472 | case AUTH_RULE_CA_CERT: | |
473 | case AUTH_RULE_IM_CERT: | |
474 | if (msg->export.flags & EXPORT_CONN_CHAIN) | |
475 | { | |
476 | print_pem_cert(out, cert); | |
477 | } | |
478 | break; | |
479 | case AUTH_RULE_SUBJECT_CERT: | |
480 | if (!got_subject) | |
481 | { | |
482 | print_pem_cert(out, cert); | |
483 | got_subject = TRUE; | |
484 | } | |
485 | break; | |
486 | default: | |
487 | break; | |
488 | } | |
489 | } | |
490 | certs->destroy(certs); | |
491 | } | |
492 | auths->destroy(auths); | |
493 | } | |
494 | } | |
495 | sas->destroy(sas); | |
496 | } | |
3d711a68 MW |
497 | } |
498 | ||
6b83549d MW |
499 | /** |
500 | * list pool leases | |
501 | */ | |
502 | static void stroke_leases(private_stroke_socket_t *this, | |
503 | stroke_msg_t *msg, FILE *out) | |
504 | { | |
505 | pop_string(msg, &msg->leases.pool); | |
506 | pop_string(msg, &msg->leases.address); | |
7daf5226 | 507 | |
6b83549d MW |
508 | this->list->leases(this->list, msg, out); |
509 | } | |
510 | ||
a426851f MW |
511 | /** |
512 | * Callback function for usage report | |
513 | */ | |
514 | static void report_usage(FILE *out, int count, size_t bytes, | |
515 | backtrace_t *bt, bool detailed) | |
516 | { | |
5a040562 | 517 | fprintf(out, "%zu bytes total, %d allocations, %zu bytes average:\n", |
a426851f MW |
518 | bytes, count, bytes / count); |
519 | bt->log(bt, out, detailed); | |
520 | } | |
521 | ||
522 | /** | |
523 | * Callback function for memusage summary | |
524 | */ | |
525 | static void sum_usage(FILE *out, int count, size_t bytes, int whitelisted) | |
526 | { | |
527 | fprintf(out, "Total memory usage: %zu\n", bytes); | |
528 | } | |
529 | ||
dfe9bad9 MW |
530 | /** |
531 | * Show memory usage | |
532 | */ | |
533 | static void stroke_memusage(private_stroke_socket_t *this, | |
534 | stroke_msg_t *msg, FILE *out) | |
535 | { | |
536 | if (lib->leak_detective) | |
537 | { | |
a426851f MW |
538 | lib->leak_detective->usage(lib->leak_detective, |
539 | (leak_detective_report_cb_t)report_usage, | |
540 | (leak_detective_summary_cb_t)sum_usage, out); | |
dfe9bad9 MW |
541 | } |
542 | } | |
543 | ||
9f1b303a TB |
544 | /** |
545 | * Set username and password for a connection | |
546 | */ | |
547 | static void stroke_user_creds(private_stroke_socket_t *this, | |
548 | stroke_msg_t *msg, FILE *out) | |
549 | { | |
550 | pop_string(msg, &msg->user_creds.name); | |
551 | pop_string(msg, &msg->user_creds.username); | |
552 | pop_string(msg, &msg->user_creds.password); | |
553 | ||
554 | DBG1(DBG_CFG, "received stroke: user-creds '%s'", msg->user_creds.name); | |
555 | ||
556 | this->config->set_user_credentials(this->config, msg, out); | |
557 | } | |
558 | ||
d022322b MW |
559 | /** |
560 | * Print stroke counter values | |
561 | */ | |
562 | static void stroke_counters(private_stroke_socket_t *this, | |
563 | stroke_msg_t *msg, FILE *out) | |
564 | { | |
565 | pop_string(msg, &msg->counters.name); | |
566 | ||
cf729248 MW |
567 | if (msg->counters.reset) |
568 | { | |
569 | this->counter->reset(this->counter, msg->counters.name); | |
570 | } | |
571 | else | |
572 | { | |
573 | this->counter->print(this->counter, out, msg->counters.name); | |
574 | } | |
d022322b MW |
575 | } |
576 | ||
0b14fdb9 MW |
577 | /** |
578 | * set the verbosity debug output | |
579 | */ | |
a985db3f MW |
580 | static void stroke_loglevel(private_stroke_socket_t *this, |
581 | stroke_msg_t *msg, FILE *out) | |
0b14fdb9 | 582 | { |
a985db3f | 583 | debug_t group; |
7daf5226 | 584 | |
0b14fdb9 MW |
585 | pop_string(msg, &(msg->loglevel.type)); |
586 | DBG1(DBG_CFG, "received stroke: loglevel %d for %s", | |
587 | msg->loglevel.level, msg->loglevel.type); | |
7daf5226 | 588 | |
5ab03863 TB |
589 | if (this->prevent_loglevel_changes) |
590 | { | |
591 | DBG1(DBG_CFG, "prevented log level change"); | |
592 | fprintf(out, "command not allowed!\n"); | |
593 | return; | |
594 | } | |
10c5981d | 595 | if (!enum_from_name(debug_names, msg->loglevel.type, &group)) |
0b14fdb9 | 596 | { |
10c5981d TB |
597 | fprintf(out, "unknown type '%s'!\n", msg->loglevel.type); |
598 | return; | |
0b14fdb9 | 599 | } |
3555baca | 600 | charon->set_level(charon, group, msg->loglevel.level); |
0b14fdb9 MW |
601 | } |
602 | ||
b360e393 MW |
603 | /** |
604 | * set various config options | |
605 | */ | |
a985db3f MW |
606 | static void stroke_config(private_stroke_socket_t *this, |
607 | stroke_msg_t *msg, FILE *out) | |
b360e393 MW |
608 | { |
609 | this->cred->cachecrl(this->cred, msg->config.cachecrl); | |
610 | } | |
0b14fdb9 MW |
611 | |
612 | /** | |
065907b9 | 613 | * process a stroke request |
0b14fdb9 | 614 | */ |
065907b9 | 615 | static bool on_accept(private_stroke_socket_t *this, stream_t *stream) |
0b14fdb9 MW |
616 | { |
617 | stroke_msg_t *msg; | |
b12c53ce | 618 | uint16_t len; |
0b14fdb9 | 619 | FILE *out; |
7daf5226 | 620 | |
065907b9 MW |
621 | /* read length */ |
622 | if (!stream->read_all(stream, &len, sizeof(len))) | |
0b14fdb9 | 623 | { |
065907b9 MW |
624 | if (errno != EWOULDBLOCK) |
625 | { | |
626 | DBG1(DBG_CFG, "reading length of stroke message failed: %s", | |
627 | strerror(errno)); | |
628 | } | |
629 | return FALSE; | |
0b14fdb9 | 630 | } |
0acd1ab4 TB |
631 | if (len < offsetof(stroke_msg_t, buffer)) |
632 | { | |
633 | DBG1(DBG_CFG, "invalid stroke message length %d", len); | |
634 | return FALSE; | |
635 | } | |
7daf5226 | 636 | |
f44b1eb4 TB |
637 | /* read message (we need an additional byte to terminate the buffer) */ |
638 | msg = malloc(len + 1); | |
065907b9 MW |
639 | msg->length = len; |
640 | if (!stream->read_all(stream, (char*)msg + sizeof(len), len - sizeof(len))) | |
0b14fdb9 | 641 | { |
065907b9 MW |
642 | if (errno != EWOULDBLOCK) |
643 | { | |
644 | DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); | |
645 | } | |
646 | free(msg); | |
647 | return FALSE; | |
0b14fdb9 | 648 | } |
f44b1eb4 TB |
649 | /* make sure even incorrectly unterminated strings don't extend over the |
650 | * message boundaries */ | |
651 | ((char*)msg)[len] = '\0'; | |
7daf5226 | 652 | |
065907b9 MW |
653 | DBG3(DBG_CFG, "stroke message %b", (void*)msg, len); |
654 | ||
655 | out = stream->get_file(stream); | |
656 | if (!out) | |
0b14fdb9 | 657 | { |
065907b9 MW |
658 | DBG1(DBG_CFG, "creating stroke output stream failed"); |
659 | free(msg); | |
660 | return FALSE; | |
0b14fdb9 | 661 | } |
0b14fdb9 MW |
662 | switch (msg->type) |
663 | { | |
664 | case STR_INITIATE: | |
665 | stroke_initiate(this, msg, out); | |
666 | break; | |
667 | case STR_ROUTE: | |
668 | stroke_route(this, msg, out); | |
669 | break; | |
670 | case STR_UNROUTE: | |
671 | stroke_unroute(this, msg, out); | |
672 | break; | |
673 | case STR_TERMINATE: | |
674 | stroke_terminate(this, msg, out); | |
675 | break; | |
13106499 MW |
676 | case STR_TERMINATE_SRCIP: |
677 | stroke_terminate_srcip(this, msg, out); | |
678 | break; | |
851d6048 MW |
679 | case STR_REKEY: |
680 | stroke_rekey(this, msg, out); | |
681 | break; | |
0b14fdb9 | 682 | case STR_STATUS: |
a694b481 | 683 | stroke_status(this, msg, out, FALSE, TRUE); |
0b14fdb9 MW |
684 | break; |
685 | case STR_STATUS_ALL: | |
a694b481 MW |
686 | stroke_status(this, msg, out, TRUE, TRUE); |
687 | break; | |
688 | case STR_STATUS_ALL_NOBLK: | |
689 | stroke_status(this, msg, out, TRUE, FALSE); | |
0b14fdb9 MW |
690 | break; |
691 | case STR_ADD_CONN: | |
692 | stroke_add_conn(this, msg); | |
693 | break; | |
694 | case STR_DEL_CONN: | |
695 | stroke_del_conn(this, msg); | |
696 | break; | |
697 | case STR_ADD_CA: | |
698 | stroke_add_ca(this, msg, out); | |
699 | break; | |
700 | case STR_DEL_CA: | |
701 | stroke_del_ca(this, msg, out); | |
702 | break; | |
703 | case STR_LOGLEVEL: | |
704 | stroke_loglevel(this, msg, out); | |
705 | break; | |
b360e393 MW |
706 | case STR_CONFIG: |
707 | stroke_config(this, msg, out); | |
708 | break; | |
0b14fdb9 MW |
709 | case STR_LIST: |
710 | stroke_list(this, msg, out); | |
711 | break; | |
712 | case STR_REREAD: | |
713 | stroke_reread(this, msg, out); | |
714 | break; | |
715 | case STR_PURGE: | |
716 | stroke_purge(this, msg, out); | |
717 | break; | |
3d711a68 MW |
718 | case STR_EXPORT: |
719 | stroke_export(this, msg, out); | |
720 | break; | |
6b83549d MW |
721 | case STR_LEASES: |
722 | stroke_leases(this, msg, out); | |
723 | break; | |
dfe9bad9 MW |
724 | case STR_MEMUSAGE: |
725 | stroke_memusage(this, msg, out); | |
726 | break; | |
9f1b303a TB |
727 | case STR_USER_CREDS: |
728 | stroke_user_creds(this, msg, out); | |
729 | break; | |
d022322b MW |
730 | case STR_COUNTERS: |
731 | stroke_counters(this, msg, out); | |
cf729248 | 732 | break; |
0b14fdb9 MW |
733 | default: |
734 | DBG1(DBG_CFG, "received unknown stroke"); | |
857ba357 | 735 | break; |
0b14fdb9 | 736 | } |
065907b9 | 737 | free(msg); |
857ba357 | 738 | fclose(out); |
065907b9 | 739 | return FALSE; |
0b14fdb9 MW |
740 | } |
741 | ||
0d430d4f TB |
742 | METHOD(stroke_socket_t, destroy, void, |
743 | private_stroke_socket_t *this) | |
0b14fdb9 | 744 | { |
065907b9 | 745 | DESTROY_IF(this->service); |
2ccc02a4 MW |
746 | lib->credmgr->remove_set(lib->credmgr, &this->ca->set); |
747 | lib->credmgr->remove_set(lib->credmgr, &this->cred->set); | |
0b14fdb9 | 748 | charon->backends->remove_backend(charon->backends, &this->config->backend); |
75136327 MW |
749 | charon->attributes->remove_provider(charon->attributes, |
750 | &this->attribute->provider); | |
751 | charon->attributes->remove_handler(charon->attributes, | |
752 | &this->handler->handler); | |
0b14fdb9 MW |
753 | this->cred->destroy(this->cred); |
754 | this->ca->destroy(this->ca); | |
755 | this->config->destroy(this->config); | |
ad81e51a | 756 | this->attribute->destroy(this->attribute); |
63e46054 | 757 | this->handler->destroy(this->handler); |
0b14fdb9 MW |
758 | this->control->destroy(this->control); |
759 | this->list->destroy(this->list); | |
8554895b | 760 | this->counter->destroy(this->counter); |
0b14fdb9 MW |
761 | free(this); |
762 | } | |
763 | ||
764 | /* | |
765 | * see header file | |
766 | */ | |
767 | stroke_socket_t *stroke_socket_create() | |
768 | { | |
0d430d4f | 769 | private_stroke_socket_t *this; |
065907b9 MW |
770 | int max_concurrent; |
771 | char *uri; | |
7daf5226 | 772 | |
0d430d4f TB |
773 | INIT(this, |
774 | .public = { | |
775 | .destroy = _destroy, | |
776 | }, | |
5ab03863 | 777 | .prevent_loglevel_changes = lib->settings->get_bool(lib->settings, |
d223fe80 | 778 | "%s.plugins.stroke.prevent_loglevel_changes", FALSE, lib->ns), |
0d430d4f | 779 | ); |
7daf5226 | 780 | |
517cc501 TB |
781 | this->ca = stroke_ca_create(); |
782 | this->cred = stroke_cred_create(this->ca); | |
ad81e51a | 783 | this->attribute = stroke_attribute_create(); |
63e46054 | 784 | this->handler = stroke_handler_create(); |
96c2b3cf | 785 | this->config = stroke_config_create(this->ca, this->cred, this->attribute); |
0b14fdb9 | 786 | this->control = stroke_control_create(); |
2e031965 | 787 | this->list = stroke_list_create(this->attribute); |
8554895b | 788 | this->counter = stroke_counter_create(); |
7daf5226 | 789 | |
2ccc02a4 MW |
790 | lib->credmgr->add_set(lib->credmgr, &this->ca->set); |
791 | lib->credmgr->add_set(lib->credmgr, &this->cred->set); | |
0b14fdb9 | 792 | charon->backends->add_backend(charon->backends, &this->config->backend); |
75136327 MW |
793 | charon->attributes->add_provider(charon->attributes, |
794 | &this->attribute->provider); | |
795 | charon->attributes->add_handler(charon->attributes, | |
796 | &this->handler->handler); | |
6f74b874 | 797 | |
7daf5226 | 798 | |
065907b9 | 799 | max_concurrent = lib->settings->get_int(lib->settings, |
d223fe80 TB |
800 | "%s.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT, |
801 | lib->ns); | |
065907b9 | 802 | uri = lib->settings->get_str(lib->settings, |
d223fe80 | 803 | "%s.plugins.stroke.socket", "unix://" STROKE_SOCKET, lib->ns); |
065907b9 MW |
804 | this->service = lib->streams->create_service(lib->streams, uri, 10); |
805 | if (!this->service) | |
806 | { | |
807 | DBG1(DBG_CFG, "creating stroke socket failed"); | |
808 | destroy(this); | |
809 | return NULL; | |
810 | } | |
811 | this->service->on_accept(this->service, (stream_service_cb_t)on_accept, | |
812 | this, JOB_PRIO_CRITICAL, max_concurrent); | |
7daf5226 | 813 | |
0b14fdb9 MW |
814 | return &this->public; |
815 | } |