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