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