Implemented IPsec policies restricted to given network interface
[strongswan.git] / src / libcharon / plugins / vici / vici_config.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * Copyright (C) 2015-2016 Tobias Brunner
6 * Copyright (C) 2015-2016 Andreas Steffen
7 * HSR Hochschule fuer Technik Rapperswil
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 /*
21 * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42 #define _GNU_SOURCE
43
44 #include "vici_config.h"
45 #include "vici_builder.h"
46
47 #include <daemon.h>
48 #include <threading/rwlock.h>
49 #include <threading/rwlock_condvar.h>
50 #include <collections/array.h>
51 #include <collections/linked_list.h>
52
53 #include <pubkey_cert.h>
54
55 #include <stdio.h>
56
57 /**
58 * Magic value for an undefined lifetime
59 */
60 #define LFT_UNDEFINED (~(uint64_t)0)
61
62 /**
63 * Default IKE rekey time
64 */
65 #define LFT_DEFAULT_IKE_REKEY (4 * 60 * 60)
66
67 /**
68 * Default CHILD rekey time
69 */
70 #define LFT_DEFAULT_CHILD_REKEY (1 * 60 * 60)
71
72 /**
73 * Undefined replay window
74 */
75 #define REPLAY_UNDEFINED (~(uint32_t)0)
76
77 typedef struct private_vici_config_t private_vici_config_t;
78
79 /**
80 * Private data of an vici_config_t object.
81 */
82 struct private_vici_config_t {
83
84 /**
85 * Public vici_config_t interface.
86 */
87 vici_config_t public;
88
89 /**
90 * Dispatcher
91 */
92 vici_dispatcher_t *dispatcher;
93
94 /**
95 * List of loaded connections, as peer_cfg_t
96 */
97 linked_list_t *conns;
98
99 /**
100 * Lock for conns list
101 */
102 rwlock_t *lock;
103
104 /**
105 * Condvar used to snyc running actions
106 */
107 rwlock_condvar_t *condvar;
108
109 /**
110 * True while we run or undo a start action
111 */
112 bool handling_actions;
113
114 /**
115 * Credential backend managed by VICI used for our certificates
116 */
117 vici_cred_t *cred;
118
119 /**
120 * Auxiliary certification authority information
121 */
122 vici_authority_t *authority;
123
124 };
125
126 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
127 private_vici_config_t *this, identification_t *me, identification_t *other)
128 {
129 this->lock->read_lock(this->lock);
130 return enumerator_create_cleaner(this->conns->create_enumerator(this->conns),
131 (void*)this->lock->unlock, this->lock);
132 }
133
134 /**
135 * Enumerator filter function for ike configs
136 */
137 static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
138 {
139 *out = (*in)->get_ike_cfg(*in);
140 return TRUE;
141 }
142
143 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
144 private_vici_config_t *this, host_t *me, host_t *other)
145 {
146 this->lock->read_lock(this->lock);
147 return enumerator_create_filter(this->conns->create_enumerator(this->conns),
148 (void*)ike_filter, this->lock,
149 (void*)this->lock->unlock);
150 }
151
152 METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
153 private_vici_config_t *this, char *name)
154 {
155 peer_cfg_t *current, *found = NULL;
156 enumerator_t *enumerator;
157
158 this->lock->read_lock(this->lock);
159 enumerator = this->conns->create_enumerator(this->conns);
160 while (enumerator->enumerate(enumerator, &current))
161 {
162 if (streq(current->get_name(current), name))
163 {
164 found = current;
165 found->get_ref(found);
166 break;
167 }
168 }
169 enumerator->destroy(enumerator);
170 this->lock->unlock(this->lock);
171
172 return found;
173 }
174
175 /**
176 * Create a (error) reply message
177 */
178 static vici_message_t* create_reply(char *fmt, ...)
179 {
180 vici_builder_t *builder;
181 va_list args;
182
183 builder = vici_builder_create();
184 builder->add_kv(builder, "success", fmt ? "no" : "yes");
185 if (fmt)
186 {
187 va_start(args, fmt);
188 builder->vadd_kv(builder, "errmsg", fmt, args);
189 va_end(args);
190 }
191 return builder->finalize(builder);
192 }
193
194 /**
195 * A rule to parse a key/value or list item
196 */
197 typedef struct {
198 /** name of the key/value or list */
199 char *name;
200 /** function to parse value */
201 bool (*parse)(void *out, chunk_t value);
202 /** result, passed to parse() */
203 void *out;
204 } parse_rule_t;
205
206 /**
207 * Parse key/values using a rule-set
208 */
209 static bool parse_rules(parse_rule_t *rules, int count, char *name,
210 chunk_t value, vici_message_t **reply)
211 {
212 int i;
213
214 for (i = 0; i < count; i++)
215 {
216 if (streq(name, rules[i].name))
217 {
218 if (rules[i].parse(rules[i].out, value))
219 {
220 return TRUE;
221 }
222 *reply = create_reply("invalid value for: %s, config discarded",
223 name);
224 return FALSE;
225 }
226 }
227 *reply = create_reply("unknown option: %s, config discarded", name);
228 return FALSE;
229 }
230
231 /**
232 * Parse callback data, passed to each callback
233 */
234 typedef struct {
235 private_vici_config_t *this;
236 vici_message_t *reply;
237 } request_data_t;
238
239 /**
240 * Auth config data
241 */
242 typedef struct {
243 request_data_t *request;
244 auth_cfg_t *cfg;
245 uint32_t round;
246 } auth_data_t;
247
248 /**
249 * Clean up auth config data
250 */
251 static void free_auth_data(auth_data_t *data)
252 {
253 DESTROY_IF(data->cfg);
254 free(data);
255 }
256
257 /**
258 * Data associated to a peer config
259 */
260 typedef struct {
261 request_data_t *request;
262 uint32_t version;
263 bool aggressive;
264 bool encap;
265 bool mobike;
266 bool send_certreq;
267 bool pull;
268 cert_policy_t send_cert;
269 uint64_t dpd_delay;
270 uint64_t dpd_timeout;
271 fragmentation_t fragmentation;
272 unique_policy_t unique;
273 uint32_t keyingtries;
274 uint32_t local_port;
275 uint32_t remote_port;
276 char *local_addrs;
277 char *remote_addrs;
278 linked_list_t *local;
279 linked_list_t *remote;
280 linked_list_t *proposals;
281 linked_list_t *children;
282 linked_list_t *vips;
283 char *pools;
284 uint64_t reauth_time;
285 uint64_t rekey_time;
286 uint64_t over_time;
287 uint64_t rand_time;
288 } peer_data_t;
289
290 /**
291 * Log relevant auth config data
292 */
293 static void log_auth(auth_cfg_t *auth)
294 {
295 enumerator_t *enumerator;
296 auth_rule_t rule;
297 union {
298 uintptr_t u;
299 identification_t *id;
300 char *str;
301 } v;
302
303 enumerator = auth->create_enumerator(auth);
304 while (enumerator->enumerate(enumerator, &rule, &v))
305 {
306 switch (rule)
307 {
308 case AUTH_RULE_AUTH_CLASS:
309 DBG2(DBG_CFG, " class = %N", auth_class_names, v.u);
310 break;
311 case AUTH_RULE_EAP_TYPE:
312 DBG2(DBG_CFG, " eap-type = %N", eap_type_names, v.u);
313 break;
314 case AUTH_RULE_EAP_VENDOR:
315 DBG2(DBG_CFG, " eap-vendor = %u", v.u);
316 break;
317 case AUTH_RULE_XAUTH_BACKEND:
318 DBG2(DBG_CFG, " xauth = %s", v.str);
319 break;
320 case AUTH_RULE_CRL_VALIDATION:
321 DBG2(DBG_CFG, " revocation = %N", cert_validation_names, v.u);
322 break;
323 case AUTH_RULE_IDENTITY:
324 DBG2(DBG_CFG, " id = %Y", v.id);
325 break;
326 case AUTH_RULE_AAA_IDENTITY:
327 DBG2(DBG_CFG, " aaa_id = %Y", v.id);
328 break;
329 case AUTH_RULE_EAP_IDENTITY:
330 DBG2(DBG_CFG, " eap_id = %Y", v.id);
331 break;
332 case AUTH_RULE_XAUTH_IDENTITY:
333 DBG2(DBG_CFG, " xauth_id = %Y", v.id);
334 break;
335 case AUTH_RULE_GROUP:
336 DBG2(DBG_CFG, " group = %Y", v.id);
337 break;
338 default:
339 break;
340 }
341 }
342 enumerator->destroy(enumerator);
343 }
344
345 /**
346 * Log parsed peer data
347 */
348 static void log_peer_data(peer_data_t *data)
349 {
350 enumerator_t *enumerator;
351 auth_data_t *auth;
352 host_t *host;
353
354 DBG2(DBG_CFG, " version = %u", data->version);
355 DBG2(DBG_CFG, " local_addrs = %s", data->local_addrs);
356 DBG2(DBG_CFG, " remote_addrs = %s", data->remote_addrs);
357 DBG2(DBG_CFG, " local_port = %u", data->local_port);
358 DBG2(DBG_CFG, " remote_port = %u", data->remote_port);
359 DBG2(DBG_CFG, " send_certreq = %u", data->send_certreq);
360 DBG2(DBG_CFG, " send_cert = %N", cert_policy_names, data->send_cert);
361 DBG2(DBG_CFG, " mobike = %u", data->mobike);
362 DBG2(DBG_CFG, " aggressive = %u", data->aggressive);
363 DBG2(DBG_CFG, " encap = %u", data->encap);
364 DBG2(DBG_CFG, " dpd_delay = %llu", data->dpd_delay);
365 DBG2(DBG_CFG, " dpd_timeout = %llu", data->dpd_timeout);
366 DBG2(DBG_CFG, " fragmentation = %u", data->fragmentation);
367 DBG2(DBG_CFG, " unique = %N", unique_policy_names, data->unique);
368 DBG2(DBG_CFG, " keyingtries = %u", data->keyingtries);
369 DBG2(DBG_CFG, " reauth_time = %llu", data->reauth_time);
370 DBG2(DBG_CFG, " rekey_time = %llu", data->rekey_time);
371 DBG2(DBG_CFG, " over_time = %llu", data->over_time);
372 DBG2(DBG_CFG, " rand_time = %llu", data->rand_time);
373 DBG2(DBG_CFG, " proposals = %#P", data->proposals);
374
375 if (data->vips->get_count(data->vips))
376 {
377 DBG2(DBG_CFG, " vips:");
378 }
379 enumerator = data->vips->create_enumerator(data->vips);
380 while (enumerator->enumerate(enumerator, &host))
381 {
382 DBG2(DBG_CFG, " %H", host);
383 }
384 enumerator->destroy(enumerator);
385
386 enumerator = data->local->create_enumerator(data->local);
387 while (enumerator->enumerate(enumerator, &auth))
388 {
389 DBG2(DBG_CFG, " local:");
390 log_auth(auth->cfg);
391 }
392 enumerator->destroy(enumerator);
393
394 enumerator = data->remote->create_enumerator(data->remote);
395 while (enumerator->enumerate(enumerator, &auth))
396 {
397 DBG2(DBG_CFG, " remote:");
398 log_auth(auth->cfg);
399 }
400 enumerator->destroy(enumerator);
401 }
402
403 /**
404 * Clean up peer config data
405 */
406 static void free_peer_data(peer_data_t *data)
407 {
408 data->local->destroy_function(data->local, (void*)free_auth_data);
409 data->remote->destroy_function(data->remote, (void*)free_auth_data);
410 data->children->destroy_offset(data->children,
411 offsetof(child_cfg_t, destroy));
412 data->proposals->destroy_offset(data->proposals,
413 offsetof(proposal_t, destroy));
414 data->vips->destroy_offset(data->vips, offsetof(host_t, destroy));
415 free(data->pools);
416 free(data->local_addrs);
417 free(data->remote_addrs);
418 }
419
420 /**
421 * CHILD config data
422 */
423 typedef struct {
424 request_data_t *request;
425 linked_list_t *proposals;
426 linked_list_t *local_ts;
427 linked_list_t *remote_ts;
428 uint32_t replay_window;
429 bool policies;
430 child_cfg_create_t cfg;
431 } child_data_t;
432
433 /**
434 * Log parsed CHILD config data
435 */
436 static void log_child_data(child_data_t *data, char *name)
437 {
438 child_cfg_create_t *cfg = &data->cfg;
439
440 DBG2(DBG_CFG, " child %s:", name);
441 DBG2(DBG_CFG, " rekey_time = %llu", cfg->lifetime.time.rekey);
442 DBG2(DBG_CFG, " life_time = %llu", cfg->lifetime.time.life);
443 DBG2(DBG_CFG, " rand_time = %llu", cfg->lifetime.time.jitter);
444 DBG2(DBG_CFG, " rekey_bytes = %llu", cfg->lifetime.bytes.rekey);
445 DBG2(DBG_CFG, " life_bytes = %llu", cfg->lifetime.bytes.life);
446 DBG2(DBG_CFG, " rand_bytes = %llu", cfg->lifetime.bytes.jitter);
447 DBG2(DBG_CFG, " rekey_packets = %llu", cfg->lifetime.packets.rekey);
448 DBG2(DBG_CFG, " life_packets = %llu", cfg->lifetime.packets.life);
449 DBG2(DBG_CFG, " rand_packets = %llu", cfg->lifetime.packets.jitter);
450 DBG2(DBG_CFG, " updown = %s", cfg->updown);
451 DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess);
452 DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp);
453 DBG2(DBG_CFG, " mode = %N", ipsec_mode_names, cfg->mode);
454 DBG2(DBG_CFG, " policies = %u", data->policies);
455 if (data->replay_window != REPLAY_UNDEFINED)
456 {
457 DBG2(DBG_CFG, " replay_window = %u", data->replay_window);
458 }
459 DBG2(DBG_CFG, " dpd_action = %N", action_names, cfg->dpd_action);
460 DBG2(DBG_CFG, " start_action = %N", action_names, cfg->start_action);
461 DBG2(DBG_CFG, " close_action = %N", action_names, cfg->close_action);
462 DBG2(DBG_CFG, " reqid = %u", cfg->reqid);
463 DBG2(DBG_CFG, " tfc = %d", cfg->tfc);
464 DBG2(DBG_CFG, " priority = %d", cfg->priority);
465 DBG2(DBG_CFG, " interface = %s", cfg->interface);
466 DBG2(DBG_CFG, " mark_in = %u/%u",
467 cfg->mark_in.value, cfg->mark_in.mask);
468 DBG2(DBG_CFG, " mark_out = %u/%u",
469 cfg->mark_out.value, cfg->mark_out.mask);
470 DBG2(DBG_CFG, " inactivity = %llu", cfg->inactivity);
471 DBG2(DBG_CFG, " proposals = %#P", data->proposals);
472 DBG2(DBG_CFG, " local_ts = %#R", data->local_ts);
473 DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts);
474 }
475
476 /**
477 * Clean up CHILD config data
478 */
479 static void free_child_data(child_data_t *data)
480 {
481 data->proposals->destroy_offset(data->proposals,
482 offsetof(proposal_t, destroy));
483 data->local_ts->destroy_offset(data->local_ts,
484 offsetof(traffic_selector_t, destroy));
485 data->remote_ts->destroy_offset(data->remote_ts,
486 offsetof(traffic_selector_t, destroy));
487 free(data->cfg.updown);
488 free(data->cfg.interface);
489 }
490
491 /**
492 * Common proposal parsing
493 */
494 static bool parse_proposal(linked_list_t *list, protocol_id_t proto, chunk_t v)
495 {
496 char buf[128];
497 proposal_t *proposal;
498
499 if (!vici_stringify(v, buf, sizeof(buf)))
500 {
501 return FALSE;
502 }
503 if (strcaseeq("default", buf))
504 {
505 proposal = proposal_create_default(proto);
506 if (proposal)
507 {
508 list->insert_last(list, proposal);
509 }
510 proposal = proposal_create_default_aead(proto);
511 if (proposal)
512 {
513 list->insert_last(list, proposal);
514 }
515 return TRUE;
516 }
517 proposal = proposal_create_from_string(proto, buf);
518 if (proposal)
519 {
520 list->insert_last(list, proposal);
521 return TRUE;
522 }
523 return FALSE;
524 }
525
526 /**
527 * Parse IKE proposal
528 */
529 CALLBACK(parse_ike_proposal, bool,
530 linked_list_t *out, chunk_t v)
531 {
532 return parse_proposal(out, PROTO_IKE, v);
533 }
534
535 /**
536 * Parse ESP proposal
537 */
538 CALLBACK(parse_esp_proposal, bool,
539 linked_list_t *out, chunk_t v)
540 {
541 return parse_proposal(out, PROTO_ESP, v);
542 }
543
544 /**
545 * Parse AH proposal
546 */
547 CALLBACK(parse_ah_proposal, bool,
548 linked_list_t *out, chunk_t v)
549 {
550 return parse_proposal(out, PROTO_AH, v);
551 }
552
553 /**
554 * Parse a traffic selector
555 */
556 CALLBACK(parse_ts, bool,
557 linked_list_t *out, chunk_t v)
558 {
559 char buf[128], *protoport, *sep, *port = "", *end;
560 traffic_selector_t *ts = NULL;
561 struct protoent *protoent;
562 struct servent *svc;
563 long int p;
564 uint16_t from = 0, to = 0xffff;
565 uint8_t proto = 0;
566
567 if (!vici_stringify(v, buf, sizeof(buf)))
568 {
569 return FALSE;
570 }
571
572 protoport = strchr(buf, '[');
573 if (protoport)
574 {
575 *(protoport++) = '\0';
576
577 sep = strrchr(protoport, ']');
578 if (!sep)
579 {
580 return FALSE;
581 }
582 *sep = '\0';
583
584 sep = strchr(protoport, '/');
585 if (sep)
586 { /* protocol/port */
587 *sep = '\0';
588 port = sep + 1;
589 }
590
591 if (streq(protoport, "any"))
592 {
593 proto = 0;
594 }
595 else
596 {
597 protoent = getprotobyname(protoport);
598 if (protoent)
599 {
600 proto = protoent->p_proto;
601 }
602 else
603 {
604 p = strtol(protoport, &end, 0);
605 if ((*protoport && *end) || p < 0 || p > 0xff)
606 {
607 return FALSE;
608 }
609 proto = (uint8_t)p;
610 }
611 }
612 if (streq(port, "opaque"))
613 {
614 from = 0xffff;
615 to = 0;
616 }
617 else if (*port && !streq(port, "any"))
618 {
619 svc = getservbyname(port, NULL);
620 if (svc)
621 {
622 from = to = ntohs(svc->s_port);
623 }
624 else
625 {
626 p = strtol(port, &end, 0);
627 if (p < 0 || p > 0xffff)
628 {
629 return FALSE;
630 }
631 from = p;
632 if (*end == '-')
633 {
634 port = end + 1;
635 p = strtol(port, &end, 0);
636 if (p < 0 || p > 0xffff)
637 {
638 return FALSE;
639 }
640 }
641 to = p;
642 if (*end)
643 {
644 return FALSE;
645 }
646 }
647 }
648 }
649 if (streq(buf, "dynamic"))
650 {
651 ts = traffic_selector_create_dynamic(proto, from, to);
652 }
653 else if (strchr(buf, '-'))
654 {
655 host_t *lower, *upper;
656 ts_type_t type;
657
658 if (host_create_from_range(buf, &lower, &upper))
659 {
660 type = (lower->get_family(lower) == AF_INET) ?
661 TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
662 ts = traffic_selector_create_from_bytes(proto, type,
663 lower->get_address(lower), from,
664 upper->get_address(upper), to);
665 lower->destroy(lower);
666 upper->destroy(upper);
667 }
668 }
669 else
670 {
671 ts = traffic_selector_create_from_cidr(buf, proto, from, to);
672 }
673 if (!ts)
674 {
675 return FALSE;
676 }
677 out->insert_last(out, ts);
678 return TRUE;
679 }
680
681 /**
682 * Parse a string
683 */
684 CALLBACK(parse_string, bool,
685 char **out, chunk_t v)
686 {
687 if (!chunk_printable(v, NULL, ' '))
688 {
689 return FALSE;
690 }
691 free(*out);
692 *out = NULL;
693 if (asprintf(out, "%.*s", (int)v.len, v.ptr) == -1)
694 {
695 return FALSE;
696 }
697 return TRUE;
698 }
699
700 /**
701 * Map a string to an integer
702 */
703 typedef struct {
704 char *str;
705 int d;
706 } enum_map_t;
707
708 /**
709 * Parse a string to an integer mapping
710 */
711 static bool parse_map(enum_map_t *map, int count, int *out, chunk_t v)
712 {
713 char buf[128];
714 int i;
715
716 if (!vici_stringify(v, buf, sizeof(buf)))
717 {
718 return FALSE;
719 }
720 for (i = 0; i < count; i++)
721 {
722 if (strcaseeq(map[i].str, buf))
723 {
724 *out = map[i].d;
725 return TRUE;
726 }
727 }
728 return FALSE;
729 }
730
731 /**
732 * Parse a boolean
733 */
734 CALLBACK(parse_bool, bool,
735 bool *out, chunk_t v)
736 {
737 enum_map_t map[] = {
738 { "yes", TRUE },
739 { "true", TRUE },
740 { "enabled", TRUE },
741 { "1", TRUE },
742 { "no", FALSE },
743 { "false", FALSE },
744 { "disabled", FALSE },
745 { "0", FALSE },
746 };
747 int d;
748
749 if (parse_map(map, countof(map), &d, v))
750 {
751 *out = d;
752 return TRUE;
753 }
754 return FALSE;
755 }
756
757 /**
758 * Parse a ipsec_mode_t
759 */
760 CALLBACK(parse_mode, bool,
761 ipsec_mode_t *out, chunk_t v)
762 {
763 enum_map_t map[] = {
764 { "tunnel", MODE_TUNNEL },
765 { "transport", MODE_TRANSPORT },
766 { "beet", MODE_BEET },
767 { "drop", MODE_DROP },
768 { "pass", MODE_PASS },
769 };
770 int d;
771
772 if (parse_map(map, countof(map), &d, v))
773 {
774 *out = d;
775 return TRUE;
776 }
777 return FALSE;
778 }
779
780 /**
781 * Parse an action_t
782 */
783 CALLBACK(parse_action, bool,
784 action_t *out, chunk_t v)
785 {
786 enum_map_t map[] = {
787 { "start", ACTION_RESTART },
788 { "restart", ACTION_RESTART },
789 { "route", ACTION_ROUTE },
790 { "trap", ACTION_ROUTE },
791 { "none", ACTION_NONE },
792 { "clear", ACTION_NONE },
793 };
794 int d;
795
796 if (parse_map(map, countof(map), &d, v))
797 {
798 *out = d;
799 return TRUE;
800 }
801 return FALSE;
802 }
803
804 /**
805 * Parse a uint32_t
806 */
807 CALLBACK(parse_uint32, bool,
808 uint32_t *out, chunk_t v)
809 {
810 char buf[16], *end;
811 u_long l;
812
813 if (!vici_stringify(v, buf, sizeof(buf)))
814 {
815 return FALSE;
816 }
817 l = strtoul(buf, &end, 0);
818 if (*end == 0)
819 {
820 *out = l;
821 return TRUE;
822 }
823 return FALSE;
824 }
825
826 /**
827 * Parse a uint64_t
828 */
829 CALLBACK(parse_uint64, bool,
830 uint64_t *out, chunk_t v)
831 {
832 char buf[16], *end;
833 unsigned long long l;
834
835 if (!vici_stringify(v, buf, sizeof(buf)))
836 {
837 return FALSE;
838 }
839 l = strtoull(buf, &end, 0);
840 if (*end == 0)
841 {
842 *out = l;
843 return TRUE;
844 }
845 return FALSE;
846 }
847
848 /**
849 * Parse a relative time
850 */
851 CALLBACK(parse_time, bool,
852 uint64_t *out, chunk_t v)
853 {
854 char buf[16], *end;
855 u_long l;
856
857 if (!vici_stringify(v, buf, sizeof(buf)))
858 {
859 return FALSE;
860 }
861
862 l = strtoul(buf, &end, 0);
863 while (*end == ' ')
864 {
865 end++;
866 }
867 switch (*end)
868 {
869 case 'd':
870 case 'D':
871 l *= 24;
872 /* fall */
873 case 'h':
874 case 'H':
875 l *= 60;
876 /* fall */
877 case 'm':
878 case 'M':
879 l *= 60;
880 /* fall */
881 case 's':
882 case 'S':
883 end++;
884 break;
885 case '\0':
886 break;
887 default:
888 return FALSE;
889 }
890 if (*end)
891 {
892 return FALSE;
893 }
894 *out = l;
895 return TRUE;
896 }
897
898 /**
899 * Parse byte volume
900 */
901 CALLBACK(parse_bytes, bool,
902 uint64_t *out, chunk_t v)
903 {
904 char buf[16], *end;
905 unsigned long long l;
906
907 if (!vici_stringify(v, buf, sizeof(buf)))
908 {
909 return FALSE;
910 }
911
912 l = strtoull(buf, &end, 0);
913 while (*end == ' ')
914 {
915 end++;
916 }
917 switch (*end)
918 {
919 case 'g':
920 case 'G':
921 l *= 1024;
922 /* fall */
923 case 'm':
924 case 'M':
925 l *= 1024;
926 /* fall */
927 case 'k':
928 case 'K':
929 l *= 1024;
930 end++;
931 break;
932 case '\0':
933 break;
934 default:
935 return FALSE;
936 }
937 if (*end)
938 {
939 return FALSE;
940 }
941 *out = l;
942 return TRUE;
943 }
944
945 /**
946 * Parse a mark_t
947 */
948 CALLBACK(parse_mark, bool,
949 mark_t *out, chunk_t v)
950 {
951 char buf[32];
952
953 if (!vici_stringify(v, buf, sizeof(buf)))
954 {
955 return FALSE;
956 }
957 return mark_from_string(buf, out);
958 }
959
960 /**
961 * Parse TFC padding option
962 */
963 CALLBACK(parse_tfc, bool,
964 uint32_t *out, chunk_t v)
965 {
966 if (chunk_equals(v, chunk_from_str("mtu")))
967 {
968 *out = -1;
969 return TRUE;
970 }
971 return parse_uint32(out, v);
972 }
973
974 /**
975 * Parse authentication config
976 */
977 CALLBACK(parse_auth, bool,
978 auth_cfg_t *cfg, chunk_t v)
979 {
980 char buf[64], *pos;
981 eap_vendor_type_t *type;
982
983 if (!vici_stringify(v, buf, sizeof(buf)))
984 {
985 return FALSE;
986 }
987 if (strpfx(buf, "ike:") ||
988 strpfx(buf, "pubkey") ||
989 strpfx(buf, "rsa") ||
990 strpfx(buf, "ecdsa") ||
991 strpfx(buf, "bliss"))
992 {
993 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
994 cfg->add_pubkey_constraints(cfg, buf, TRUE);
995 return TRUE;
996 }
997 if (strcaseeq(buf, "psk"))
998 {
999 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
1000 return TRUE;
1001 }
1002 if (strcasepfx(buf, "xauth"))
1003 {
1004 pos = strchr(buf, '-');
1005 if (pos)
1006 {
1007 cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos));
1008 }
1009 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH);
1010 return TRUE;
1011 }
1012 if (strcasepfx(buf, "eap"))
1013 {
1014 char *pos;
1015
1016 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
1017
1018 pos = strchr(buf, ':');
1019 if (pos)
1020 {
1021 *pos = 0;
1022 cfg->add_pubkey_constraints(cfg, pos + 1, FALSE);
1023 }
1024 type = eap_vendor_type_from_string(buf);
1025 if (type)
1026 {
1027 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type);
1028 if (type->vendor)
1029 {
1030 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor);
1031 }
1032 free(type);
1033 }
1034 return TRUE;
1035 }
1036 return FALSE;
1037 }
1038
1039 /**
1040 * Parse identity; add as auth rule to config
1041 */
1042 static bool parse_id(auth_cfg_t *cfg, auth_rule_t rule, chunk_t v)
1043 {
1044 char buf[256];
1045
1046 if (!vici_stringify(v, buf, sizeof(buf)))
1047 {
1048 return FALSE;
1049 }
1050 cfg->add(cfg, rule, identification_create_from_string(buf));
1051 return TRUE;
1052 }
1053
1054 /**
1055 * Parse IKE identity
1056 */
1057 CALLBACK(parse_ike_id, bool,
1058 auth_cfg_t *cfg, chunk_t v)
1059 {
1060 return parse_id(cfg, AUTH_RULE_IDENTITY, v);
1061 }
1062
1063 /**
1064 * Parse AAA identity
1065 */
1066 CALLBACK(parse_aaa_id, bool,
1067 auth_cfg_t *cfg, chunk_t v)
1068 {
1069 return parse_id(cfg, AUTH_RULE_AAA_IDENTITY, v);
1070 }
1071
1072 /**
1073 * Parse EAP identity
1074 */
1075 CALLBACK(parse_eap_id, bool,
1076 auth_cfg_t *cfg, chunk_t v)
1077 {
1078 return parse_id(cfg, AUTH_RULE_EAP_IDENTITY, v);
1079 }
1080
1081 /**
1082 * Parse XAuth identity
1083 */
1084 CALLBACK(parse_xauth_id, bool,
1085 auth_cfg_t *cfg, chunk_t v)
1086 {
1087 return parse_id(cfg, AUTH_RULE_XAUTH_IDENTITY, v);
1088 }
1089
1090 /**
1091 * Parse group membership
1092 */
1093 CALLBACK(parse_group, bool,
1094 auth_cfg_t *cfg, chunk_t v)
1095 {
1096 return parse_id(cfg, AUTH_RULE_GROUP, v);
1097 }
1098
1099 /**
1100 * Parse a certificate; add as auth rule to config
1101 */
1102 static bool parse_cert(auth_data_t *auth, auth_rule_t rule, chunk_t v)
1103 {
1104 vici_authority_t *authority;
1105 vici_cred_t *cred;
1106 certificate_t *cert;
1107
1108 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
1109 BUILD_BLOB_PEM, v, BUILD_END);
1110 if (cert)
1111 {
1112 if (rule == AUTH_RULE_SUBJECT_CERT)
1113 {
1114 authority = auth->request->this->authority;
1115 authority->check_for_hash_and_url(authority, cert);
1116 }
1117 cred = auth->request->this->cred;
1118 cert = cred->add_cert(cred, cert);
1119 auth->cfg->add(auth->cfg, rule, cert);
1120 return TRUE;
1121 }
1122 return FALSE;
1123 }
1124
1125 /**
1126 * Parse subject certificates
1127 */
1128 CALLBACK(parse_certs, bool,
1129 auth_data_t *auth, chunk_t v)
1130 {
1131 return parse_cert(auth, AUTH_RULE_SUBJECT_CERT, v);
1132 }
1133
1134 /**
1135 * Parse CA certificates
1136 */
1137 CALLBACK(parse_cacerts, bool,
1138 auth_data_t *auth, chunk_t v)
1139 {
1140 return parse_cert(auth, AUTH_RULE_CA_CERT, v);
1141 }
1142
1143 /**
1144 * Parse raw public keys
1145 */
1146 CALLBACK(parse_pubkeys, bool,
1147 auth_data_t *auth, chunk_t v)
1148 {
1149 vici_cred_t *cred;
1150 certificate_t *cert;
1151
1152 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
1153 BUILD_BLOB_PEM, v, BUILD_END);
1154 if (cert)
1155 {
1156 cred = auth->request->this->cred;
1157 cert = cred->add_cert(cred, cert);
1158 auth->cfg->add(auth->cfg, AUTH_RULE_SUBJECT_CERT, cert);
1159 return TRUE;
1160 }
1161 return FALSE;
1162 }
1163
1164 /**
1165 * Parse revocation status
1166 */
1167 CALLBACK(parse_revocation, bool,
1168 auth_cfg_t *cfg, chunk_t v)
1169 {
1170 enum_map_t map[] = {
1171 { "strict", VALIDATION_GOOD },
1172 { "ifuri", VALIDATION_SKIPPED },
1173 { "relaxed", VALIDATION_FAILED },
1174 };
1175 int d;
1176
1177 if (parse_map(map, countof(map), &d, v))
1178 {
1179 if (d != VALIDATION_FAILED)
1180 {
1181 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, d);
1182 }
1183 return TRUE;
1184 }
1185 return FALSE;
1186 }
1187
1188 /**
1189 * Parse list items to comma separated strings
1190 */
1191 CALLBACK(parse_stringlist, bool,
1192 char **out, chunk_t v)
1193 {
1194 char *current;
1195
1196 if (!chunk_printable(v, NULL, ' '))
1197 {
1198 return FALSE;
1199 }
1200 current = *out;
1201 if (current)
1202 {
1203 if (asprintf(out, "%s, %.*s", current, (int)v.len, v.ptr) == -1)
1204 {
1205 return FALSE;
1206 }
1207 free(current);
1208 }
1209 else
1210 {
1211 if (asprintf(out, "%.*s", (int)v.len, v.ptr) == -1)
1212 {
1213 return FALSE;
1214 }
1215 }
1216 return TRUE;
1217 }
1218
1219 /**
1220 * Parse an fragmentation_t
1221 */
1222 CALLBACK(parse_frag, bool,
1223 fragmentation_t *out, chunk_t v)
1224 {
1225 enum_map_t map[] = {
1226 { "yes", FRAGMENTATION_YES },
1227 { "no", FRAGMENTATION_NO },
1228 { "force", FRAGMENTATION_FORCE },
1229 };
1230 int d;
1231
1232 if (parse_map(map, countof(map), &d, v))
1233 {
1234 *out = d;
1235 return TRUE;
1236 }
1237 return FALSE;
1238 }
1239
1240 /**
1241 * Parse a cert_policy_t
1242 */
1243 CALLBACK(parse_send_cert, bool,
1244 cert_policy_t *out, chunk_t v)
1245 {
1246 enum_map_t map[] = {
1247 { "ifasked", CERT_SEND_IF_ASKED },
1248 { "always", CERT_ALWAYS_SEND },
1249 { "never", CERT_NEVER_SEND },
1250 };
1251 int d;
1252
1253 if (parse_map(map, countof(map), &d, v))
1254 {
1255 *out = d;
1256 return TRUE;
1257 }
1258 return FALSE;
1259 }
1260
1261 /**
1262 * Parse a unique_policy_t
1263 */
1264 CALLBACK(parse_unique, bool,
1265 unique_policy_t *out, chunk_t v)
1266 {
1267 enum_map_t map[] = {
1268 { "never", UNIQUE_NEVER },
1269 { "no", UNIQUE_NO },
1270 { "replace", UNIQUE_REPLACE },
1271 { "keep", UNIQUE_KEEP },
1272 };
1273 int d;
1274
1275 if (parse_map(map, countof(map), &d, v))
1276 {
1277 *out = d;
1278 return TRUE;
1279 }
1280 return FALSE;
1281 }
1282
1283 /**
1284 * Parse host_t into a list
1285 */
1286 CALLBACK(parse_hosts, bool,
1287 linked_list_t *list, chunk_t v)
1288 {
1289 char buf[64];
1290 host_t *host;
1291
1292 if (!vici_stringify(v, buf, sizeof(buf)))
1293 {
1294 return FALSE;
1295 }
1296 host = host_create_from_string(buf, 0);
1297 if (!host)
1298 {
1299 return FALSE;
1300 }
1301 list->insert_last(list, host);
1302 return TRUE;
1303 }
1304
1305 CALLBACK(child_li, bool,
1306 child_data_t *child, vici_message_t *message, char *name, chunk_t value)
1307 {
1308 parse_rule_t rules[] = {
1309 { "ah_proposals", parse_ah_proposal, child->proposals },
1310 { "esp_proposals", parse_esp_proposal, child->proposals },
1311 { "local_ts", parse_ts, child->local_ts },
1312 { "remote_ts", parse_ts, child->remote_ts },
1313 };
1314
1315 return parse_rules(rules, countof(rules), name, value,
1316 &child->request->reply);
1317 }
1318
1319 CALLBACK(child_kv, bool,
1320 child_data_t *child, vici_message_t *message, char *name, chunk_t value)
1321 {
1322 parse_rule_t rules[] = {
1323 { "updown", parse_string, &child->cfg.updown },
1324 { "hostaccess", parse_bool, &child->cfg.hostaccess },
1325 { "mode", parse_mode, &child->cfg.mode },
1326 { "policies", parse_bool, &child->policies },
1327 { "replay_window", parse_uint32, &child->replay_window },
1328 { "rekey_time", parse_time, &child->cfg.lifetime.time.rekey },
1329 { "life_time", parse_time, &child->cfg.lifetime.time.life },
1330 { "rand_time", parse_time, &child->cfg.lifetime.time.jitter },
1331 { "rekey_bytes", parse_bytes, &child->cfg.lifetime.bytes.rekey },
1332 { "life_bytes", parse_bytes, &child->cfg.lifetime.bytes.life },
1333 { "rand_bytes", parse_bytes, &child->cfg.lifetime.bytes.jitter },
1334 { "rekey_packets", parse_uint64, &child->cfg.lifetime.packets.rekey },
1335 { "life_packets", parse_uint64, &child->cfg.lifetime.packets.life },
1336 { "rand_packets", parse_uint64, &child->cfg.lifetime.packets.jitter },
1337 { "dpd_action", parse_action, &child->cfg.dpd_action },
1338 { "start_action", parse_action, &child->cfg.start_action },
1339 { "close_action", parse_action, &child->cfg.close_action },
1340 { "ipcomp", parse_bool, &child->cfg.ipcomp },
1341 { "inactivity", parse_time, &child->cfg.inactivity },
1342 { "reqid", parse_uint32, &child->cfg.reqid },
1343 { "mark_in", parse_mark, &child->cfg.mark_in },
1344 { "mark_out", parse_mark, &child->cfg.mark_out },
1345 { "tfc_padding", parse_tfc, &child->cfg.tfc },
1346 { "priority", parse_uint32, &child->cfg.priority },
1347 { "interface", parse_string, &child->cfg.interface },
1348 };
1349
1350 return parse_rules(rules, countof(rules), name, value,
1351 &child->request->reply);
1352 }
1353
1354 CALLBACK(auth_li, bool,
1355 auth_data_t *auth, vici_message_t *message, char *name, chunk_t value)
1356 {
1357 parse_rule_t rules[] = {
1358 { "groups", parse_group, auth->cfg },
1359 { "certs", parse_certs, auth },
1360 { "cacerts", parse_cacerts, auth },
1361 { "pubkeys", parse_pubkeys, auth },
1362 };
1363
1364 return parse_rules(rules, countof(rules), name, value,
1365 &auth->request->reply);
1366 }
1367
1368 CALLBACK(auth_kv, bool,
1369 auth_data_t *auth, vici_message_t *message, char *name, chunk_t value)
1370 {
1371 parse_rule_t rules[] = {
1372 { "auth", parse_auth, auth->cfg },
1373 { "id", parse_ike_id, auth->cfg },
1374 { "aaa_id", parse_aaa_id, auth->cfg },
1375 { "eap_id", parse_eap_id, auth->cfg },
1376 { "xauth_id", parse_xauth_id, auth->cfg },
1377 { "revocation", parse_revocation, auth->cfg },
1378 { "round", parse_uint32, &auth->round },
1379 };
1380
1381 return parse_rules(rules, countof(rules), name, value,
1382 &auth->request->reply);
1383 }
1384
1385 CALLBACK(peer_li, bool,
1386 peer_data_t *peer, vici_message_t *message, char *name, chunk_t value)
1387 {
1388 parse_rule_t rules[] = {
1389 { "local_addrs", parse_stringlist, &peer->local_addrs },
1390 { "remote_addrs", parse_stringlist, &peer->remote_addrs },
1391 { "proposals", parse_ike_proposal, peer->proposals },
1392 { "vips", parse_hosts, peer->vips },
1393 { "pools", parse_stringlist, &peer->pools },
1394 };
1395
1396 return parse_rules(rules, countof(rules), name, value,
1397 &peer->request->reply);
1398 }
1399
1400 CALLBACK(peer_kv, bool,
1401 peer_data_t *peer, vici_message_t *message, char *name, chunk_t value)
1402 {
1403 parse_rule_t rules[] = {
1404 { "version", parse_uint32, &peer->version },
1405 { "aggressive", parse_bool, &peer->aggressive },
1406 { "pull", parse_bool, &peer->pull },
1407 { "encap", parse_bool, &peer->encap },
1408 { "mobike", parse_bool, &peer->mobike },
1409 { "dpd_delay", parse_time, &peer->dpd_delay },
1410 { "dpd_timeout", parse_time, &peer->dpd_timeout },
1411 { "fragmentation", parse_frag, &peer->fragmentation },
1412 { "send_certreq", parse_bool, &peer->send_certreq },
1413 { "send_cert", parse_send_cert, &peer->send_cert },
1414 { "keyingtries", parse_uint32, &peer->keyingtries },
1415 { "unique", parse_unique, &peer->unique },
1416 { "local_port", parse_uint32, &peer->local_port },
1417 { "remote_port", parse_uint32, &peer->remote_port },
1418 { "reauth_time", parse_time, &peer->reauth_time },
1419 { "rekey_time", parse_time, &peer->rekey_time },
1420 { "over_time", parse_time, &peer->over_time },
1421 { "rand_time", parse_time, &peer->rand_time },
1422 };
1423
1424 return parse_rules(rules, countof(rules), name, value,
1425 &peer->request->reply);
1426 }
1427
1428 /**
1429 * Check and update lifetimes
1430 */
1431 static void check_lifetimes(lifetime_cfg_t *lft)
1432 {
1433 /* if no hard lifetime specified, add one at soft lifetime + 10% */
1434 if (lft->time.life == LFT_UNDEFINED)
1435 {
1436 lft->time.life = lft->time.rekey * 110 / 100;
1437 }
1438 if (lft->bytes.life == LFT_UNDEFINED)
1439 {
1440 lft->bytes.life = lft->bytes.rekey * 110 / 100;
1441 }
1442 if (lft->packets.life == LFT_UNDEFINED)
1443 {
1444 lft->packets.life = lft->packets.rekey * 110 / 100;
1445 }
1446 /* if no soft lifetime specified, add one at hard lifetime - 10% */
1447 if (lft->bytes.rekey == LFT_UNDEFINED)
1448 {
1449 lft->bytes.rekey = lft->bytes.life * 90 / 100;
1450 }
1451 if (lft->packets.rekey == LFT_UNDEFINED)
1452 {
1453 lft->packets.rekey = lft->packets.life * 90 / 100;
1454 }
1455 /* if no rand time defined, use difference of hard and soft */
1456 if (lft->time.jitter == LFT_UNDEFINED)
1457 {
1458 lft->time.jitter = lft->time.life -
1459 min(lft->time.life, lft->time.rekey);
1460 }
1461 if (lft->bytes.jitter == LFT_UNDEFINED)
1462 {
1463 lft->bytes.jitter = lft->bytes.life -
1464 min(lft->bytes.life, lft->bytes.rekey);
1465 }
1466 if (lft->packets.jitter == LFT_UNDEFINED)
1467 {
1468 lft->packets.jitter = lft->packets.life -
1469 min(lft->packets.life, lft->packets.rekey);
1470 }
1471 }
1472
1473 CALLBACK(children_sn, bool,
1474 peer_data_t *peer, vici_message_t *message, vici_parse_context_t *ctx,
1475 char *name)
1476 {
1477 child_data_t child = {
1478 .request = peer->request,
1479 .proposals = linked_list_create(),
1480 .local_ts = linked_list_create(),
1481 .remote_ts = linked_list_create(),
1482 .policies = TRUE,
1483 .replay_window = REPLAY_UNDEFINED,
1484 .cfg = {
1485 .mode = MODE_TUNNEL,
1486 .lifetime = {
1487 .time = {
1488 .rekey = LFT_DEFAULT_CHILD_REKEY,
1489 .life = LFT_UNDEFINED,
1490 .jitter = LFT_UNDEFINED,
1491 },
1492 .bytes = {
1493 .rekey = LFT_UNDEFINED,
1494 .life = LFT_UNDEFINED,
1495 .jitter = LFT_UNDEFINED,
1496 },
1497 .packets = {
1498 .rekey = LFT_UNDEFINED,
1499 .life = LFT_UNDEFINED,
1500 .jitter = LFT_UNDEFINED,
1501 },
1502 },
1503 },
1504 };
1505 child_cfg_t *cfg;
1506 proposal_t *proposal;
1507 traffic_selector_t *ts;
1508
1509 if (!message->parse(message, ctx, NULL, child_kv, child_li, &child))
1510 {
1511 free_child_data(&child);
1512 return FALSE;
1513 }
1514
1515 if (child.local_ts->get_count(child.local_ts) == 0)
1516 {
1517 child.local_ts->insert_last(child.local_ts,
1518 traffic_selector_create_dynamic(0, 0, 65535));
1519 }
1520 if (child.remote_ts->get_count(child.remote_ts) == 0)
1521 {
1522 child.remote_ts->insert_last(child.remote_ts,
1523 traffic_selector_create_dynamic(0, 0, 65535));
1524 }
1525 if (child.proposals->get_count(child.proposals) == 0)
1526 {
1527 proposal = proposal_create_default(PROTO_ESP);
1528 if (proposal)
1529 {
1530 child.proposals->insert_last(child.proposals, proposal);
1531 }
1532 proposal = proposal_create_default_aead(PROTO_ESP);
1533 if (proposal)
1534 {
1535 child.proposals->insert_last(child.proposals, proposal);
1536 }
1537 }
1538 child.cfg.suppress_policies = !child.policies;
1539
1540 check_lifetimes(&child.cfg.lifetime);
1541
1542 log_child_data(&child, name);
1543
1544 cfg = child_cfg_create(name, &child.cfg);
1545
1546 if (child.replay_window != REPLAY_UNDEFINED)
1547 {
1548 cfg->set_replay_window(cfg, child.replay_window);
1549 }
1550 while (child.local_ts->remove_first(child.local_ts,
1551 (void**)&ts) == SUCCESS)
1552 {
1553 cfg->add_traffic_selector(cfg, TRUE, ts);
1554 }
1555 while (child.remote_ts->remove_first(child.remote_ts,
1556 (void**)&ts) == SUCCESS)
1557 {
1558 cfg->add_traffic_selector(cfg, FALSE, ts);
1559 }
1560 while (child.proposals->remove_first(child.proposals,
1561 (void**)&proposal) == SUCCESS)
1562 {
1563 cfg->add_proposal(cfg, proposal);
1564 }
1565
1566 peer->children->insert_last(peer->children, cfg);
1567
1568 free_child_data(&child);
1569
1570 return TRUE;
1571 }
1572
1573 CALLBACK(peer_sn, bool,
1574 peer_data_t *peer, vici_message_t *message, vici_parse_context_t *ctx,
1575 char *name)
1576 {
1577 if (strcaseeq(name, "children"))
1578 {
1579 return message->parse(message, ctx, children_sn, NULL, NULL, peer);
1580 }
1581 if (strcasepfx(name, "local") ||
1582 strcasepfx(name, "remote"))
1583 {
1584 enumerator_t *enumerator;
1585 linked_list_t *auths;
1586 auth_data_t *auth, *current;
1587 auth_rule_t rule;
1588 certificate_t *cert;
1589 pubkey_cert_t *pubkey_cert;
1590 identification_t *id;
1591 bool default_id = FALSE;
1592
1593 INIT(auth,
1594 .request = peer->request,
1595 .cfg = auth_cfg_create(),
1596 );
1597
1598 if (!message->parse(message, ctx, NULL, auth_kv, auth_li, auth))
1599 {
1600 free_auth_data(auth);
1601 return FALSE;
1602 }
1603 id = auth->cfg->get(auth->cfg, AUTH_RULE_IDENTITY);
1604
1605 enumerator = auth->cfg->create_enumerator(auth->cfg);
1606 while (enumerator->enumerate(enumerator, &rule, &cert))
1607 {
1608 if (rule == AUTH_RULE_SUBJECT_CERT && !default_id)
1609 {
1610 if (id == NULL)
1611 {
1612 id = cert->get_subject(cert);
1613 DBG1(DBG_CFG, " id not specified, defaulting to"
1614 " cert subject '%Y'", id);
1615 auth->cfg->add(auth->cfg, AUTH_RULE_IDENTITY, id->clone(id));
1616 default_id = TRUE;
1617 }
1618 else if (cert->get_type(cert) == CERT_TRUSTED_PUBKEY &&
1619 id->get_type != ID_ANY)
1620 {
1621 /* set the subject of all raw public keys to the id */
1622 pubkey_cert = (pubkey_cert_t*)cert;
1623 pubkey_cert->set_subject(pubkey_cert, id);
1624 }
1625 }
1626 }
1627 enumerator->destroy(enumerator);
1628
1629 auths = strcasepfx(name, "local") ? peer->local : peer->remote;
1630 enumerator = auths->create_enumerator(auths);
1631 while (enumerator->enumerate(enumerator, &current))
1632 {
1633 if (auth->round < current->round)
1634 {
1635 break;
1636 }
1637 }
1638 auths->insert_before(auths, enumerator, auth);
1639 enumerator->destroy(enumerator);
1640 return TRUE;
1641 }
1642 peer->request->reply = create_reply("invalid section: %s", name);
1643 return FALSE;
1644 }
1645
1646 /**
1647 * Find reqid of an existing CHILD_SA
1648 */
1649 static uint32_t find_reqid(child_cfg_t *cfg)
1650 {
1651 enumerator_t *enumerator, *children;
1652 child_sa_t *child_sa;
1653 ike_sa_t *ike_sa;
1654 uint32_t reqid;
1655
1656 reqid = charon->traps->find_reqid(charon->traps, cfg);
1657 if (reqid)
1658 { /* already trapped */
1659 return reqid;
1660 }
1661
1662 enumerator = charon->controller->create_ike_sa_enumerator(
1663 charon->controller, TRUE);
1664 while (!reqid && enumerator->enumerate(enumerator, &ike_sa))
1665 {
1666 children = ike_sa->create_child_sa_enumerator(ike_sa);
1667 while (children->enumerate(children, &child_sa))
1668 {
1669 if (streq(cfg->get_name(cfg), child_sa->get_name(child_sa)))
1670 {
1671 reqid = child_sa->get_reqid(child_sa);
1672 break;
1673 }
1674 }
1675 children->destroy(children);
1676 }
1677 enumerator->destroy(enumerator);
1678 return reqid;
1679 }
1680
1681 /**
1682 * Perform start actions associated with a child config
1683 */
1684 static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg,
1685 child_cfg_t *child_cfg)
1686 {
1687 switch (child_cfg->get_start_action(child_cfg))
1688 {
1689 case ACTION_RESTART:
1690 DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg));
1691 charon->controller->initiate(charon->controller,
1692 peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg),
1693 NULL, NULL, 0, FALSE);
1694 break;
1695 case ACTION_ROUTE:
1696 DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg));
1697 switch (child_cfg->get_mode(child_cfg))
1698 {
1699 case MODE_PASS:
1700 case MODE_DROP:
1701 charon->shunts->install(charon->shunts, child_cfg);
1702 break;
1703 default:
1704 charon->traps->install(charon->traps, peer_cfg, child_cfg,
1705 find_reqid(child_cfg));
1706 break;
1707 }
1708 break;
1709 default:
1710 break;
1711 }
1712 }
1713
1714 /**
1715 * Undo start actions associated with a child config
1716 */
1717 static void clear_start_action(private_vici_config_t *this, char *peer_name,
1718 child_cfg_t *child_cfg)
1719 {
1720 enumerator_t *enumerator, *children;
1721 child_sa_t *child_sa;
1722 ike_sa_t *ike_sa;
1723 uint32_t id = 0, others;
1724 array_t *ids = NULL, *ikeids = NULL;
1725 char *name;
1726
1727 name = child_cfg->get_name(child_cfg);
1728
1729 switch (child_cfg->get_start_action(child_cfg))
1730 {
1731 case ACTION_RESTART:
1732 enumerator = charon->controller->create_ike_sa_enumerator(
1733 charon->controller, TRUE);
1734 while (enumerator->enumerate(enumerator, &ike_sa))
1735 {
1736 if (!streq(ike_sa->get_name(ike_sa), peer_name))
1737 {
1738 continue;
1739 }
1740 others = id = 0;
1741 children = ike_sa->create_child_sa_enumerator(ike_sa);
1742 while (children->enumerate(children, &child_sa))
1743 {
1744 if (child_sa->get_state(child_sa) != CHILD_DELETING)
1745 {
1746 if (streq(name, child_sa->get_name(child_sa)))
1747 {
1748 id = child_sa->get_unique_id(child_sa);
1749 }
1750 else
1751 {
1752 others++;
1753 }
1754 }
1755 }
1756 children->destroy(children);
1757
1758 if (id && !others)
1759 {
1760 /* found matching children only, delete full IKE_SA */
1761 id = ike_sa->get_unique_id(ike_sa);
1762 array_insert_create_value(&ikeids, sizeof(id),
1763 ARRAY_TAIL, &id);
1764 }
1765 else
1766 {
1767 children = ike_sa->create_child_sa_enumerator(ike_sa);
1768 while (children->enumerate(children, &child_sa))
1769 {
1770 if (streq(name, child_sa->get_name(child_sa)))
1771 {
1772 id = child_sa->get_unique_id(child_sa);
1773 array_insert_create_value(&ids, sizeof(id),
1774 ARRAY_TAIL, &id);
1775 }
1776 }
1777 children->destroy(children);
1778 }
1779 }
1780 enumerator->destroy(enumerator);
1781
1782 if (array_count(ids))
1783 {
1784 while (array_remove(ids, ARRAY_HEAD, &id))
1785 {
1786 DBG1(DBG_CFG, "closing '%s' #%u", name, id);
1787 charon->controller->terminate_child(charon->controller,
1788 id, NULL, NULL, 0);
1789 }
1790 array_destroy(ids);
1791 }
1792 if (array_count(ikeids))
1793 {
1794 while (array_remove(ikeids, ARRAY_HEAD, &id))
1795 {
1796 DBG1(DBG_CFG, "closing IKE_SA #%u", id);
1797 charon->controller->terminate_ike(charon->controller,
1798 id, NULL, NULL, 0);
1799 }
1800 array_destroy(ikeids);
1801 }
1802 break;
1803 case ACTION_ROUTE:
1804 DBG1(DBG_CFG, "uninstalling '%s'", name);
1805 switch (child_cfg->get_mode(child_cfg))
1806 {
1807 case MODE_PASS:
1808 case MODE_DROP:
1809 charon->shunts->uninstall(charon->shunts, name);
1810 break;
1811 default:
1812 enumerator = charon->traps->create_enumerator(charon->traps);
1813 while (enumerator->enumerate(enumerator, NULL, &child_sa))
1814 {
1815 if (streq(name, child_sa->get_name(child_sa)))
1816 {
1817 id = child_sa->get_reqid(child_sa);
1818 break;
1819 }
1820 }
1821 enumerator->destroy(enumerator);
1822 if (id)
1823 {
1824 charon->traps->uninstall(charon->traps, id);
1825 }
1826 break;
1827 }
1828 break;
1829 default:
1830 break;
1831 }
1832 }
1833
1834 /**
1835 * Run or undo a start actions associated with a child config
1836 */
1837 static void handle_start_action(private_vici_config_t *this,
1838 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
1839 bool undo)
1840 {
1841 this->handling_actions = TRUE;
1842 this->lock->unlock(this->lock);
1843
1844 if (undo)
1845 {
1846 clear_start_action(this, peer_cfg->get_name(peer_cfg), child_cfg);
1847 }
1848 else
1849 {
1850 run_start_action(this, peer_cfg, child_cfg);
1851 }
1852
1853 this->lock->write_lock(this->lock);
1854 this->handling_actions = FALSE;
1855 }
1856
1857 /**
1858 * Run or undo start actions associated with all child configs of a peer config
1859 */
1860 static void handle_start_actions(private_vici_config_t *this,
1861 peer_cfg_t *peer_cfg, bool undo)
1862 {
1863 enumerator_t *enumerator;
1864 child_cfg_t *child_cfg;
1865
1866 this->handling_actions = TRUE;
1867 this->lock->unlock(this->lock);
1868
1869 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
1870 while (enumerator->enumerate(enumerator, &child_cfg))
1871 {
1872 if (undo)
1873 {
1874 clear_start_action(this, peer_cfg->get_name(peer_cfg), child_cfg);
1875 }
1876 else
1877 {
1878 run_start_action(this, peer_cfg, child_cfg);
1879 }
1880 }
1881 enumerator->destroy(enumerator);
1882
1883 this->lock->write_lock(this->lock);
1884 this->handling_actions = FALSE;
1885 }
1886
1887 /**
1888 * Replace children of a peer config by a new config
1889 */
1890 static void replace_children(private_vici_config_t *this,
1891 peer_cfg_t *from, peer_cfg_t *to)
1892 {
1893 enumerator_t *enumerator;
1894 child_cfg_t *child;
1895 bool added;
1896
1897 enumerator = to->replace_child_cfgs(to, from);
1898 while (enumerator->enumerate(enumerator, &child, &added))
1899 {
1900 handle_start_action(this, to, child, !added);
1901 }
1902 enumerator->destroy(enumerator);
1903 }
1904
1905 /**
1906 * Merge/replace a peer config with existing configs
1907 */
1908 static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg)
1909 {
1910 enumerator_t *enumerator;
1911 peer_cfg_t *current;
1912 ike_cfg_t *ike_cfg;
1913 bool merged = FALSE;
1914
1915 this->lock->write_lock(this->lock);
1916 while (this->handling_actions)
1917 {
1918 this->condvar->wait(this->condvar, this->lock);
1919 }
1920
1921 enumerator = this->conns->create_enumerator(this->conns);
1922 while (enumerator->enumerate(enumerator, &current))
1923 {
1924 if (streq(peer_cfg->get_name(peer_cfg), current->get_name(current)))
1925 {
1926 ike_cfg = current->get_ike_cfg(current);
1927 if (peer_cfg->equals(peer_cfg, current) &&
1928 ike_cfg->equals(ike_cfg, peer_cfg->get_ike_cfg(peer_cfg)))
1929 {
1930 DBG1(DBG_CFG, "updated vici connection: %s",
1931 peer_cfg->get_name(peer_cfg));
1932 replace_children(this, peer_cfg, current);
1933 peer_cfg->destroy(peer_cfg);
1934 }
1935 else
1936 {
1937 DBG1(DBG_CFG, "replaced vici connection: %s",
1938 peer_cfg->get_name(peer_cfg));
1939 this->conns->remove_at(this->conns, enumerator);
1940 this->conns->insert_last(this->conns, peer_cfg);
1941 handle_start_actions(this, current, TRUE);
1942 handle_start_actions(this, peer_cfg, FALSE);
1943 current->destroy(current);
1944 }
1945 merged = TRUE;
1946 break;
1947 }
1948 }
1949 enumerator->destroy(enumerator);
1950
1951 if (!merged)
1952 {
1953 DBG1(DBG_CFG, "added vici connection: %s", peer_cfg->get_name(peer_cfg));
1954 this->conns->insert_last(this->conns, peer_cfg);
1955 handle_start_actions(this, peer_cfg, FALSE);
1956 }
1957 this->condvar->signal(this->condvar);
1958 this->lock->unlock(this->lock);
1959 }
1960
1961 CALLBACK(config_sn, bool,
1962 request_data_t *request, vici_message_t *message,
1963 vici_parse_context_t *ctx, char *name)
1964 {
1965 peer_data_t peer = {
1966 .request = request,
1967 .local = linked_list_create(),
1968 .remote = linked_list_create(),
1969 .vips = linked_list_create(),
1970 .children = linked_list_create(),
1971 .proposals = linked_list_create(),
1972 .mobike = TRUE,
1973 .send_certreq = TRUE,
1974 .pull = TRUE,
1975 .send_cert = CERT_SEND_IF_ASKED,
1976 .version = IKE_ANY,
1977 .remote_port = IKEV2_UDP_PORT,
1978 .fragmentation = FRAGMENTATION_NO,
1979 .unique = UNIQUE_NO,
1980 .keyingtries = 1,
1981 .rekey_time = LFT_UNDEFINED,
1982 .reauth_time = LFT_UNDEFINED,
1983 .over_time = LFT_UNDEFINED,
1984 .rand_time = LFT_UNDEFINED,
1985 };
1986 enumerator_t *enumerator;
1987 peer_cfg_create_t cfg;
1988 peer_cfg_t *peer_cfg;
1989 ike_cfg_t *ike_cfg;
1990 child_cfg_t *child_cfg;
1991 auth_data_t *auth;
1992 proposal_t *proposal;
1993 host_t *host;
1994 char *str;
1995
1996 DBG2(DBG_CFG, " conn %s:", name);
1997
1998 if (!message->parse(message, ctx, peer_sn, peer_kv, peer_li, &peer))
1999 {
2000 free_peer_data(&peer);
2001 return FALSE;
2002 }
2003
2004 if (peer.local->get_count(peer.local) == 0)
2005 {
2006 INIT(auth,
2007 .cfg = auth_cfg_create(),
2008 );
2009 peer.local->insert_last(peer.local, auth);
2010 }
2011 if (peer.remote->get_count(peer.remote) == 0)
2012 {
2013 INIT(auth,
2014 .cfg = auth_cfg_create(),
2015 );
2016 peer.remote->insert_last(peer.remote, auth);
2017 }
2018 if (peer.proposals->get_count(peer.proposals) == 0)
2019 {
2020 proposal = proposal_create_default(PROTO_IKE);
2021 if (proposal)
2022 {
2023 peer.proposals->insert_last(peer.proposals, proposal);
2024 }
2025 proposal = proposal_create_default_aead(PROTO_IKE);
2026 if (proposal)
2027 {
2028 peer.proposals->insert_last(peer.proposals, proposal);
2029 }
2030 }
2031 if (!peer.local_addrs)
2032 {
2033 peer.local_addrs = strdup("%any");
2034 }
2035 if (!peer.remote_addrs)
2036 {
2037 peer.remote_addrs = strdup("%any");
2038 }
2039 if (!peer.local_port)
2040 {
2041 peer.local_port = charon->socket->get_port(charon->socket, FALSE);
2042 }
2043
2044 if (peer.rekey_time == LFT_UNDEFINED && peer.reauth_time == LFT_UNDEFINED)
2045 {
2046 /* apply a default rekey time if no rekey/reauth time set */
2047 peer.rekey_time = LFT_DEFAULT_IKE_REKEY;
2048 peer.reauth_time = 0;
2049 }
2050 if (peer.rekey_time == LFT_UNDEFINED)
2051 {
2052 peer.rekey_time = 0;
2053 }
2054 if (peer.reauth_time == LFT_UNDEFINED)
2055 {
2056 peer.reauth_time = 0;
2057 }
2058 if (peer.over_time == LFT_UNDEFINED)
2059 {
2060 /* default over_time to 10% of rekey/reauth time if not given */
2061 peer.over_time = max(peer.rekey_time, peer.reauth_time) / 10;
2062 }
2063 if (peer.rand_time == LFT_UNDEFINED)
2064 {
2065 /* default rand_time to over_time if not given, but don't make it
2066 * longer than half of rekey/rauth time */
2067 if (peer.rekey_time && peer.reauth_time)
2068 {
2069 peer.rand_time = min(peer.rekey_time, peer.reauth_time);
2070 }
2071 else
2072 {
2073 peer.rand_time = max(peer.rekey_time, peer.reauth_time);
2074 }
2075 peer.rand_time = min(peer.over_time, peer.rand_time / 2);
2076 }
2077
2078 log_peer_data(&peer);
2079
2080 ike_cfg = ike_cfg_create(peer.version, peer.send_certreq, peer.encap,
2081 peer.local_addrs, peer.local_port,
2082 peer.remote_addrs, peer.remote_port,
2083 peer.fragmentation, 0);
2084
2085 cfg = (peer_cfg_create_t){
2086 .cert_policy = peer.send_cert,
2087 .unique = peer.unique,
2088 .keyingtries = peer.keyingtries,
2089 .rekey_time = peer.rekey_time,
2090 .reauth_time = peer.reauth_time,
2091 .jitter_time = peer.rand_time,
2092 .over_time = peer.over_time,
2093 .no_mobike = !peer.mobike,
2094 .aggressive = peer.aggressive,
2095 .push_mode = !peer.pull,
2096 .dpd = peer.dpd_delay,
2097 .dpd_timeout = peer.dpd_timeout,
2098 };
2099 peer_cfg = peer_cfg_create(name, ike_cfg, &cfg);
2100
2101 while (peer.local->remove_first(peer.local,
2102 (void**)&auth) == SUCCESS)
2103 {
2104 peer_cfg->add_auth_cfg(peer_cfg, auth->cfg, TRUE);
2105 auth->cfg = NULL;
2106 free_auth_data(auth);
2107 }
2108 while (peer.remote->remove_first(peer.remote,
2109 (void**)&auth) == SUCCESS)
2110 {
2111 peer_cfg->add_auth_cfg(peer_cfg, auth->cfg, FALSE);
2112 auth->cfg = NULL;
2113 free_auth_data(auth);
2114 }
2115 while (peer.children->remove_first(peer.children,
2116 (void**)&child_cfg) == SUCCESS)
2117 {
2118 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
2119 }
2120 while (peer.proposals->remove_first(peer.proposals,
2121 (void**)&proposal) == SUCCESS)
2122 {
2123 ike_cfg->add_proposal(ike_cfg, proposal);
2124 }
2125 while (peer.vips->remove_first(peer.vips, (void**)&host) == SUCCESS)
2126 {
2127 peer_cfg->add_virtual_ip(peer_cfg, host);
2128 }
2129 if (peer.pools)
2130 {
2131 enumerator = enumerator_create_token(peer.pools, ",", " ");
2132 while (enumerator->enumerate(enumerator, &str))
2133 {
2134 peer_cfg->add_pool(peer_cfg, str);
2135 }
2136 enumerator->destroy(enumerator);
2137 }
2138
2139 free_peer_data(&peer);
2140
2141 merge_config(request->this, peer_cfg);
2142
2143 return TRUE;
2144 }
2145
2146 CALLBACK(load_conn, vici_message_t*,
2147 private_vici_config_t *this, char *name, u_int id, vici_message_t *message)
2148 {
2149 request_data_t request = {
2150 .this = this,
2151 };
2152
2153 if (!message->parse(message, NULL, config_sn, NULL, NULL, &request))
2154 {
2155 if (request.reply)
2156 {
2157 return request.reply;
2158 }
2159 return create_reply("parsing request failed");
2160 }
2161 return create_reply(NULL);
2162 }
2163
2164 CALLBACK(unload_conn, vici_message_t*,
2165 private_vici_config_t *this, char *name, u_int id, vici_message_t *message)
2166 {
2167 enumerator_t *enumerator;
2168 peer_cfg_t *cfg;
2169 char *conn_name;
2170 bool found = FALSE;
2171
2172 conn_name = message->get_str(message, NULL, "name");
2173 if (!conn_name)
2174 {
2175 return create_reply("unload: missing connection name");
2176 }
2177
2178 this->lock->write_lock(this->lock);
2179 while (this->handling_actions)
2180 {
2181 this->condvar->wait(this->condvar, this->lock);
2182 }
2183 enumerator = this->conns->create_enumerator(this->conns);
2184 while (enumerator->enumerate(enumerator, &cfg))
2185 {
2186 if (streq(cfg->get_name(cfg), conn_name))
2187 {
2188 this->conns->remove_at(this->conns, enumerator);
2189 handle_start_actions(this, cfg, TRUE);
2190 cfg->destroy(cfg);
2191 found = TRUE;
2192 break;
2193 }
2194 }
2195 enumerator->destroy(enumerator);
2196 this->condvar->signal(this->condvar);
2197 this->lock->unlock(this->lock);
2198
2199 if (!found)
2200 {
2201 return create_reply("unload: connection '%s' not found", conn_name);
2202 }
2203 return create_reply(NULL);
2204 }
2205
2206 CALLBACK(get_conns, vici_message_t*,
2207 private_vici_config_t *this, char *name, u_int id, vici_message_t *message)
2208 {
2209 vici_builder_t *builder;
2210 enumerator_t *enumerator;
2211 peer_cfg_t *cfg;
2212
2213 builder = vici_builder_create();
2214 builder->begin_list(builder, "conns");
2215
2216 this->lock->read_lock(this->lock);
2217 enumerator = this->conns->create_enumerator(this->conns);
2218 while (enumerator->enumerate(enumerator, &cfg))
2219 {
2220 builder->add_li(builder, "%s", cfg->get_name(cfg));
2221 }
2222 enumerator->destroy(enumerator);
2223 this->lock->unlock(this->lock);
2224
2225 builder->end_list(builder);
2226
2227 return builder->finalize(builder);
2228 }
2229
2230 static void manage_command(private_vici_config_t *this,
2231 char *name, vici_command_cb_t cb, bool reg)
2232 {
2233 this->dispatcher->manage_command(this->dispatcher, name,
2234 reg ? cb : NULL, this);
2235 }
2236
2237 /**
2238 * (Un-)register dispatcher functions
2239 */
2240 static void manage_commands(private_vici_config_t *this, bool reg)
2241 {
2242 manage_command(this, "load-conn", load_conn, reg);
2243 manage_command(this, "unload-conn", unload_conn, reg);
2244 manage_command(this, "get-conns", get_conns, reg);
2245 }
2246
2247 METHOD(vici_config_t, destroy, void,
2248 private_vici_config_t *this)
2249 {
2250 manage_commands(this, FALSE);
2251 this->conns->destroy_offset(this->conns, offsetof(peer_cfg_t, destroy));
2252 this->condvar->destroy(this->condvar);
2253 this->lock->destroy(this->lock);
2254 free(this);
2255 }
2256
2257 /**
2258 * See header
2259 */
2260 vici_config_t *vici_config_create(vici_dispatcher_t *dispatcher,
2261 vici_authority_t *authority,
2262 vici_cred_t *cred)
2263 {
2264 private_vici_config_t *this;
2265
2266 INIT(this,
2267 .public = {
2268 .backend = {
2269 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
2270 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
2271 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
2272 },
2273 .destroy = _destroy,
2274 },
2275 .dispatcher = dispatcher,
2276 .conns = linked_list_create(),
2277 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
2278 .condvar = rwlock_condvar_create(),
2279 .authority = authority,
2280 .cred = cred,
2281 );
2282
2283 manage_commands(this, TRUE);
2284
2285 return &this->public;
2286 }