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