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