Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_config.c, revision 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>