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