Annotation of embedaddon/strongswan/src/libcharon/plugins/medcli/medcli_config.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2008 Martin Willi
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #define _GNU_SOURCE
                     17: #include <string.h>
                     18: 
                     19: #include "medcli_config.h"
                     20: 
                     21: #include <daemon.h>
                     22: #include <processing/jobs/callback_job.h>
                     23: 
                     24: typedef struct private_medcli_config_t private_medcli_config_t;
                     25: 
                     26: /**
                     27:  * Name of the mediation connection
                     28:  */
                     29: #define MEDIATION_CONN_NAME "medcli-mediation"
                     30: 
                     31: /**
                     32:  * Private data of an medcli_config_t object
                     33:  */
                     34: struct private_medcli_config_t {
                     35: 
                     36:        /**
                     37:         * Public part
                     38:         */
                     39:        medcli_config_t public;
                     40: 
                     41:        /**
                     42:         * database connection
                     43:         */
                     44:        database_t *db;
                     45: 
                     46:        /**
                     47:         * rekey time
                     48:         */
                     49:        int rekey;
                     50: 
                     51:        /**
                     52:         * dpd delay
                     53:         */
                     54:        int dpd;
                     55: 
                     56:        /**
                     57:         * default ike config
                     58:         */
                     59:        ike_cfg_t *ike;
                     60: };
                     61: 
                     62: /**
                     63:  * create a traffic selector from a CIDR notation string
                     64:  */
                     65: static traffic_selector_t *ts_from_string(char *str)
                     66: {
                     67:        if (str)
                     68:        {
                     69:                traffic_selector_t *ts;
                     70: 
                     71:                ts = traffic_selector_create_from_cidr(str, 0, 0, 65535);
                     72:                if (ts)
                     73:                {
                     74:                        return ts;
                     75:                }
                     76:        }
                     77:        return traffic_selector_create_dynamic(0, 0, 65535);
                     78: }
                     79: 
                     80: /**
                     81:  * Build a mediation config
                     82:  */
                     83: static peer_cfg_t *build_mediation_config(private_medcli_config_t *this,
                     84:                                                                                  peer_cfg_create_t *defaults)
                     85: {
                     86:        enumerator_t *e;
                     87:        auth_cfg_t *auth;
                     88:        ike_cfg_t *ike_cfg;
                     89:        peer_cfg_t *med_cfg;
                     90:        ike_cfg_create_t ike = {
                     91:                .version = IKEV2,
                     92:                .local = "0.0.0.0",
                     93:                .local_port = charon->socket->get_port(charon->socket, FALSE),
                     94:                .remote_port = IKEV2_UDP_PORT,
                     95:                .no_certreq = TRUE,
                     96:        };
                     97:        peer_cfg_create_t peer = *defaults;
                     98:        chunk_t me, other;
                     99: 
                    100:        /* query mediation server config:
                    101:         * - build ike_cfg/peer_cfg for mediation connection on-the-fly
                    102:         */
                    103:        e = this->db->query(this->db,
                    104:                        "SELECT Address, ClientConfig.KeyId, MediationServerConfig.KeyId "
                    105:                        "FROM MediationServerConfig JOIN ClientConfig",
                    106:                        DB_TEXT, DB_BLOB, DB_BLOB);
                    107:        if (!e || !e->enumerate(e, &ike.remote, &me, &other))
                    108:        {
                    109:                DESTROY_IF(e);
                    110:                return NULL;
                    111:        }
                    112:        ike_cfg = ike_cfg_create(&ike);
                    113:        ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
                    114:        ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
                    115: 
                    116:        peer.mediation = TRUE;
                    117:        med_cfg = peer_cfg_create(MEDIATION_CONN_NAME, ike_cfg, &peer);
                    118:        e->destroy(e);
                    119: 
                    120:        auth = auth_cfg_create();
                    121:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    122:        auth->add(auth, AUTH_RULE_IDENTITY,
                    123:                          identification_create_from_encoding(ID_KEY_ID, me));
                    124:        med_cfg->add_auth_cfg(med_cfg, auth, TRUE);
                    125:        auth = auth_cfg_create();
                    126:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    127:        auth->add(auth, AUTH_RULE_IDENTITY,
                    128:                          identification_create_from_encoding(ID_KEY_ID, other));
                    129:        med_cfg->add_auth_cfg(med_cfg, auth, FALSE);
                    130:        return med_cfg;
                    131: }
                    132: 
                    133: METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
                    134:        private_medcli_config_t *this, char *name)
                    135: {
                    136:        enumerator_t *e;
                    137:        auth_cfg_t *auth;
                    138:        peer_cfg_t *peer_cfg;
                    139:        child_cfg_t *child_cfg;
                    140:        chunk_t me, other;
                    141:        char *local_net, *remote_net;
                    142:        peer_cfg_create_t peer = {
                    143:                .cert_policy = CERT_NEVER_SEND,
                    144:                .unique = UNIQUE_REPLACE,
                    145:                .keyingtries = 1,
                    146:                .rekey_time = this->rekey * 60,
                    147:                .jitter_time = this->rekey * 5,
                    148:                .over_time = this->rekey * 3,
                    149:                .dpd = this->dpd,
                    150:        };
                    151:        child_cfg_create_t child = {
                    152:                .lifetime = {
                    153:                        .time = {
                    154:                                .life = this->rekey * 60 + this->rekey,
                    155:                                .rekey = this->rekey,
                    156:                                .jitter = this->rekey
                    157:                        },
                    158:                },
                    159:                .mode = MODE_TUNNEL,
                    160:        };
                    161: 
                    162:        if (streq(name, "medcli-mediation"))
                    163:        {
                    164:                return build_mediation_config(this, &peer);
                    165:        }
                    166: 
                    167:        /* query mediated config:
                    168:         * - use any-any ike_cfg
                    169:         * - build peer_cfg on-the-fly using med_cfg
                    170:         * - add a child_cfg
                    171:         */
                    172:        e = this->db->query(this->db,
                    173:                        "SELECT ClientConfig.KeyId, Connection.KeyId, "
                    174:                        "Connection.LocalSubnet, Connection.RemoteSubnet "
                    175:                        "FROM ClientConfig JOIN Connection "
                    176:                        "WHERE Active AND Alias = ?", DB_TEXT, name,
                    177:                        DB_BLOB, DB_BLOB, DB_TEXT, DB_TEXT);
                    178:        if (!e || !e->enumerate(e, &me, &other, &local_net, &remote_net))
                    179:        {
                    180:                DESTROY_IF(e);
                    181:                return NULL;
                    182:        }
                    183:        peer.mediated_by = MEDIATION_CONN_NAME;
                    184:        peer.peer_id = identification_create_from_encoding(ID_KEY_ID, other);
                    185:        peer_cfg = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer);
                    186: 
                    187:        auth = auth_cfg_create();
                    188:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    189:        auth->add(auth, AUTH_RULE_IDENTITY,
                    190:                          identification_create_from_encoding(ID_KEY_ID, me));
                    191:        peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
                    192:        auth = auth_cfg_create();
                    193:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    194:        auth->add(auth, AUTH_RULE_IDENTITY,
                    195:                          identification_create_from_encoding(ID_KEY_ID, other));
                    196:        peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
                    197: 
                    198:        child_cfg = child_cfg_create(name, &child);
                    199:        child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
1.1.1.2 ! misho     200:        child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
1.1       misho     201:        child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net));
                    202:        child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net));
                    203:        peer_cfg->add_child_cfg(peer_cfg, child_cfg);
                    204:        e->destroy(e);
                    205:        return peer_cfg;
                    206: }
                    207: 
                    208: METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
                    209:        private_medcli_config_t *this, host_t *me, host_t *other)
                    210: {
                    211:        return enumerator_create_single(this->ike, NULL);
                    212: }
                    213: 
                    214: typedef struct {
                    215:        /** implements enumerator */
                    216:        enumerator_t public;
                    217:        /** inner SQL enumerator */
                    218:        enumerator_t *inner;
                    219:        /** currently enumerated peer config */
                    220:        peer_cfg_t *current;
                    221:        /** ike cfg to use in peer cfg */
                    222:        ike_cfg_t *ike;
                    223:        /** rekey time */
                    224:        int rekey;
                    225:        /** dpd time */
                    226:        int dpd;
                    227: } peer_enumerator_t;
                    228: 
                    229: METHOD(enumerator_t, peer_enumerator_enumerate, bool,
                    230:        peer_enumerator_t *this, va_list args)
                    231: {
                    232:        char *name, *local_net, *remote_net;
                    233:        chunk_t me, other;
                    234:        peer_cfg_t **cfg;
                    235:        child_cfg_t *child_cfg;
                    236:        auth_cfg_t *auth;
                    237:        peer_cfg_create_t peer = {
                    238:                .cert_policy = CERT_NEVER_SEND,
                    239:                .unique = UNIQUE_REPLACE,
                    240:                .keyingtries = 1,
                    241:                .rekey_time = this->rekey * 60,
                    242:                .jitter_time = this->rekey * 5,
                    243:                .over_time = this->rekey * 3,
                    244:                .dpd = this->dpd,
                    245:        };
                    246:        child_cfg_create_t child = {
                    247:                .lifetime = {
                    248:                        .time = {
                    249:                                .life = this->rekey * 60 + this->rekey,
                    250:                                .rekey = this->rekey,
                    251:                                .jitter = this->rekey
                    252:                        },
                    253:                },
                    254:                .mode = MODE_TUNNEL,
                    255:        };
                    256: 
                    257:        VA_ARGS_VGET(args, cfg);
                    258: 
                    259:        DESTROY_IF(this->current);
                    260:        if (!this->inner->enumerate(this->inner, &name, &me, &other,
                    261:                                                                &local_net, &remote_net))
                    262:        {
                    263:                this->current = NULL;
                    264:                return FALSE;
                    265:        }
                    266:        this->current = peer_cfg_create(name, this->ike->get_ref(this->ike), &peer);
                    267: 
                    268:        auth = auth_cfg_create();
                    269:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    270:        auth->add(auth, AUTH_RULE_IDENTITY,
                    271:                          identification_create_from_encoding(ID_KEY_ID, me));
                    272:        this->current->add_auth_cfg(this->current, auth, TRUE);
                    273:        auth = auth_cfg_create();
                    274:        auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    275:        auth->add(auth, AUTH_RULE_IDENTITY,
                    276:                          identification_create_from_encoding(ID_KEY_ID, other));
                    277:        this->current->add_auth_cfg(this->current, auth, FALSE);
                    278: 
                    279:        child_cfg = child_cfg_create(name, &child);
                    280:        child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
1.1.1.2 ! misho     281:        child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
1.1       misho     282:        child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net));
                    283:        child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net));
                    284:        this->current->add_child_cfg(this->current, child_cfg);
                    285:        *cfg = this->current;
                    286:        return TRUE;
                    287: }
                    288: 
                    289: METHOD(enumerator_t, peer_enumerator_destroy, void,
                    290:        peer_enumerator_t *this)
                    291: {
                    292:        DESTROY_IF(this->current);
                    293:        this->inner->destroy(this->inner);
                    294:        free(this);
                    295: }
                    296: 
                    297: METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
                    298:        private_medcli_config_t *this, identification_t *me,
                    299:        identification_t *other)
                    300: {
                    301:        peer_enumerator_t *e;
                    302: 
                    303:        INIT(e,
                    304:                .public = {
                    305:                        .enumerate = enumerator_enumerate_default,
                    306:                        .venumerate = _peer_enumerator_enumerate,
                    307:                        .destroy = _peer_enumerator_destroy,
                    308:                },
                    309:                .ike = this->ike,
                    310:                .rekey = this->rekey,
                    311:                .dpd = this->dpd,
                    312:        );
                    313: 
                    314:        /* filter on IDs: NULL or ANY or matching KEY_ID */
                    315:        e->inner = this->db->query(this->db,
                    316:                        "SELECT Alias, ClientConfig.KeyId, Connection.KeyId, "
                    317:                        "Connection.LocalSubnet, Connection.RemoteSubnet "
                    318:                        "FROM ClientConfig JOIN Connection "
                    319:                        "WHERE Active AND "
                    320:                        "(? OR ClientConfig.KeyId = ?) AND (? OR Connection.KeyId = ?)",
                    321:                        DB_INT, me == NULL || me->get_type(me) == ID_ANY,
                    322:                        DB_BLOB, me && me->get_type(me) == ID_KEY_ID ?
                    323:                                me->get_encoding(me) : chunk_empty,
                    324:                        DB_INT, other == NULL || other->get_type(other) == ID_ANY,
                    325:                        DB_BLOB, other && other->get_type(other) == ID_KEY_ID ?
                    326:                                other->get_encoding(other) : chunk_empty,
                    327:                        DB_TEXT, DB_BLOB, DB_BLOB, DB_TEXT, DB_TEXT);
                    328:        if (!e->inner)
                    329:        {
                    330:                free(e);
                    331:                return NULL;
                    332:        }
                    333:        return &e->public;
                    334: }
                    335: 
                    336: /**
                    337:  * initiate a peer config
                    338:  */
                    339: static job_requeue_t initiate_config(peer_cfg_t *peer_cfg)
                    340: {
                    341:        enumerator_t *enumerator;
                    342:        child_cfg_t *child_cfg = NULL;;
                    343: 
                    344:        enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
                    345:        enumerator->enumerate(enumerator, &child_cfg);
                    346:        if (child_cfg)
                    347:        {
                    348:                child_cfg->get_ref(child_cfg);
                    349:                peer_cfg->get_ref(peer_cfg);
                    350:                enumerator->destroy(enumerator);
                    351:                charon->controller->initiate(charon->controller,
                    352:                                                                         peer_cfg, child_cfg, NULL, NULL, 0, FALSE);
                    353:        }
                    354:        else
                    355:        {
                    356:                enumerator->destroy(enumerator);
                    357:        }
                    358:        return JOB_REQUEUE_NONE;
                    359: }
                    360: 
                    361: /**
                    362:  * schedule initiation of all "active" connections
                    363:  */
                    364: static void schedule_autoinit(private_medcli_config_t *this)
                    365: {
                    366:        enumerator_t *e;
                    367:        char *name;
                    368: 
                    369:        e = this->db->query(this->db, "SELECT Alias FROM Connection WHERE Active",
                    370:                                                DB_TEXT);
                    371:        if (e)
                    372:        {
                    373:                while (e->enumerate(e, &name))
                    374:                {
                    375:                        peer_cfg_t *peer_cfg;
                    376: 
                    377:                        peer_cfg = get_peer_cfg_by_name(this, name);
                    378:                        if (peer_cfg)
                    379:                        {
                    380:                                /* schedule asynchronous initiation job */
                    381:                                lib->processor->queue_job(lib->processor,
                    382:                                                (job_t*)callback_job_create(
                    383:                                                                        (callback_job_cb_t)initiate_config,
                    384:                                                                        peer_cfg, (void*)peer_cfg->destroy, NULL));
                    385:                        }
                    386:                }
                    387:                e->destroy(e);
                    388:        }
                    389: }
                    390: 
                    391: METHOD(medcli_config_t, destroy, void,
                    392:        private_medcli_config_t *this)
                    393: {
                    394:        this->ike->destroy(this->ike);
                    395:        free(this);
                    396: }
                    397: 
                    398: /**
                    399:  * Described in header.
                    400:  */
                    401: medcli_config_t *medcli_config_create(database_t *db)
                    402: {
                    403:        private_medcli_config_t *this;
                    404:        ike_cfg_create_t ike = {
                    405:                .version = IKEV2,
                    406:                .local = "0.0.0.0",
                    407:                .local_port = charon->socket->get_port(charon->socket, FALSE),
                    408:                .remote = "0.0.0.0",
                    409:                .remote_port = IKEV2_UDP_PORT,
                    410:                .no_certreq = TRUE,
                    411:        };
                    412: 
                    413:        INIT(this,
                    414:                .public = {
                    415:                        .backend = {
                    416:                                .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
                    417:                                .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
                    418:                                .get_peer_cfg_by_name = _get_peer_cfg_by_name,
                    419:                        },
                    420:                        .destroy = _destroy,
                    421:                },
                    422:                .db = db,
                    423:                .rekey = lib->settings->get_time(lib->settings, "medcli.rekey", 1200),
                    424:                .dpd = lib->settings->get_time(lib->settings, "medcli.dpd", 300),
                    425:                .ike = ike_cfg_create(&ike),
                    426:        );
                    427:        this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE));
                    428:        this->ike->add_proposal(this->ike, proposal_create_default_aead(PROTO_IKE));
                    429: 
                    430:        schedule_autoinit(this);
                    431: 
                    432:        return &this->public;
                    433: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>