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