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