Annotation of embedaddon/strongswan/src/charon-nm/nm/nm_service.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2017 Lubomir Rintel
                      3:  *
                      4:  * Copyright (C) 2013-2020 Tobias Brunner
                      5:  * Copyright (C) 2008-2009 Martin Willi
                      6:  * HSR Hochschule fuer Technik Rapperswil
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify it
                      9:  * under the terms of the GNU General Public License as published by the
                     10:  * Free Software Foundation; either version 2 of the License, or (at your
                     11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     12:  *
                     13:  * This program is distributed in the hope that it will be useful, but
                     14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     16:  * for more details.
                     17:  */
                     18: 
                     19: #include "nm_service.h"
                     20: 
                     21: #include <daemon.h>
                     22: #include <networking/host.h>
                     23: #include <utils/identification.h>
                     24: #include <config/peer_cfg.h>
                     25: #include <credentials/certificates/x509.h>
                     26: 
                     27: #include <stdio.h>
                     28: 
                     29: /**
                     30:  * Private data of NMStrongswanPlugin
                     31:  */
                     32: typedef struct {
                     33:        /* implements bus listener interface */
                     34:        listener_t listener;
                     35:        /* IKE_SA we are listening on */
                     36:        ike_sa_t *ike_sa;
                     37:        /* backref to public plugin */
                     38:        NMVpnServicePlugin *plugin;
                     39:        /* credentials to use for authentication */
                     40:        nm_creds_t *creds;
                     41:        /* attribute handler for DNS/NBNS server information */
                     42:        nm_handler_t *handler;
                     43:        /* name of the connection */
                     44:        char *name;
                     45: } NMStrongswanPluginPrivate;
                     46: 
                     47: G_DEFINE_TYPE_WITH_PRIVATE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_SERVICE_PLUGIN)
                     48: 
                     49: #define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \
                     50:                        ((NMStrongswanPluginPrivate*) \
                     51:                                nm_strongswan_plugin_get_instance_private (o))
                     52: 
                     53: /**
                     54:  * Convert an address chunk to a GValue
                     55:  */
                     56: static GVariant *addr_to_variant(chunk_t addr)
                     57: {
                     58:        GVariantBuilder builder;
                     59:        int i;
                     60: 
                     61:        switch (addr.len)
                     62:        {
                     63:                case 4:
                     64:                        return g_variant_new_uint32 (*(uint32_t*)addr.ptr);
                     65:                case 16:
                     66:                        g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay"));
                     67:                        for (i = 0; i < addr.len; i++)
                     68:                        {
                     69:                                g_variant_builder_add (&builder, "y", addr.ptr[i]);
                     70: 
                     71:                        }
                     72:                        return g_variant_builder_end (&builder);
                     73:                default:
                     74:                        return NULL;
                     75:        }
                     76: }
                     77: 
                     78: /**
                     79:  * Convert a host to a GValue
                     80:  */
                     81: static GVariant *host_to_variant(host_t *host)
                     82: {
                     83:        return addr_to_variant(host->get_address(host));
                     84: }
                     85: 
                     86: /**
                     87:  * Convert enumerated handler chunks to a GValue
                     88:  */
                     89: static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
                     90:                                                         configuration_attribute_type_t type)
                     91: {
                     92:        GVariantBuilder builder;
                     93:        enumerator_t *enumerator;
                     94:        chunk_t *chunk;
                     95: 
                     96:        g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type));
                     97: 
                     98:        enumerator = handler->create_enumerator(handler, type);
                     99:        while (enumerator->enumerate(enumerator, &chunk))
                    100:        {
                    101:                g_variant_builder_add_value (&builder, addr_to_variant(*chunk));
                    102:        }
                    103:        enumerator->destroy(enumerator);
                    104: 
                    105:        return g_variant_builder_end (&builder);
                    106: }
                    107: 
                    108: /**
                    109:  * Signal IP config to NM, set connection as established
                    110:  */
                    111: static void signal_ip_config(NMVpnServicePlugin *plugin,
                    112:                                                         ike_sa_t *ike_sa, child_sa_t *child_sa)
                    113: {
                    114:        NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
                    115:        NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub);
                    116:        GVariantBuilder builder, ip4builder, ip6builder;
                    117:        GVariant *ip4config, *ip6config;
                    118:        enumerator_t *enumerator;
                    119:        host_t *me, *other, *vip4 = NULL, *vip6 = NULL;
                    120:        nm_handler_t *handler;
                    121: 
                    122:        g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
                    123:        g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT);
                    124:        g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT);
                    125: 
                    126:        handler = priv->handler;
                    127: 
                    128:        /* NM apparently requires to know the gateway */
                    129:        other = ike_sa->get_other_host(ike_sa);
                    130:        g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
                    131:                               host_to_variant(other));
                    132: 
                    133:        /* pass the first virtual IPs we got or use the physical IP */
                    134:        enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
                    135:        while (enumerator->enumerate(enumerator, &me))
                    136:        {
                    137:                switch (me->get_family(me))
                    138:                {
                    139:                        case AF_INET:
                    140:                                if (!vip4)
                    141:                                {
                    142:                                        vip4 = me;
                    143:                                }
                    144:                                break;
                    145:                        case AF_INET6:
                    146:                                if (!vip6)
                    147:                                {
                    148:                                        vip6 = me;
                    149:                                }
                    150:                                break;
                    151:                }
                    152:        }
                    153:        enumerator->destroy(enumerator);
                    154:        if (!vip4 && !vip6)
                    155:        {
                    156:                me = ike_sa->get_my_host(ike_sa);
                    157:                switch (me->get_family(me))
                    158:                {
                    159:                        case AF_INET:
                    160:                                vip4 = me;
                    161:                                break;
                    162:                        case AF_INET6:
                    163:                                vip6 = me;
                    164:                                break;
                    165:                }
                    166:        }
                    167: 
                    168:        if (vip4)
                    169:        {
                    170:                g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
                    171:                                                           host_to_variant(vip4));
                    172:                g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
                    173:                                                           g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
                    174: 
                    175:                /* prevent NM from changing the default route. we set our own route in our
                    176:                 * own routing table
                    177:                 */
                    178:                g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
                    179:                                                           g_variant_new_boolean (TRUE));
                    180: 
                    181:                g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
                    182:                                                           handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
                    183: 
                    184:                g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
                    185:                                                           handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
                    186:        }
                    187: 
                    188:        if (vip6)
                    189:        {
                    190:                g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS,
                    191:                                                           host_to_variant(vip6));
                    192:                g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
                    193:                                                           g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
                    194:                g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
                    195:                                                           g_variant_new_boolean (TRUE));
                    196:                g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
                    197:                                                           handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
                    198:                /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
                    199:        }
                    200: 
                    201:        ip4config = g_variant_builder_end (&ip4builder);
                    202:        if (g_variant_n_children (ip4config))
                    203:        {
                    204:                g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4,
                    205:                                                           g_variant_new_boolean (TRUE));
                    206:        }
                    207:        else
                    208:        {
                    209:                g_variant_unref (ip4config);
                    210:                ip4config = NULL;
                    211:        }
                    212: 
                    213:        ip6config = g_variant_builder_end (&ip6builder);
                    214:        if (g_variant_n_children (ip6config))
                    215:        {
                    216:                g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6,
                    217:                                                           g_variant_new_boolean (TRUE));
                    218:        }
                    219:        else
                    220:        {
                    221:                g_variant_unref (ip6config);
                    222:                ip6config = NULL;
                    223:        }
                    224: 
                    225:        handler->reset(handler);
                    226: 
                    227:        nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder));
                    228:        if (ip4config)
                    229:        {
                    230:                nm_vpn_service_plugin_set_ip4_config (plugin, ip4config);
                    231:        }
                    232:        if (ip6config)
                    233:        {
                    234:                nm_vpn_service_plugin_set_ip6_config (plugin, ip6config);
                    235:        }
                    236: }
                    237: 
                    238: /**
                    239:  * signal failure to NM, connecting failed
                    240:  */
                    241: static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failure)
                    242: {
                    243:        NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
                    244:        nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub)->handler;
                    245: 
                    246:        handler->reset(handler);
                    247: 
                    248:        nm_vpn_service_plugin_failure(plugin, failure);
                    249: }
                    250: 
                    251: METHOD(listener_t, ike_state_change, bool,
                    252:        NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, ike_sa_state_t state)
                    253: {
                    254:        if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
                    255:        {
                    256:                signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
                    257:        }
                    258:        return TRUE;
                    259: }
                    260: 
                    261: METHOD(listener_t, child_state_change, bool,
                    262:        NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
                    263:        child_sa_state_t state)
                    264: {
                    265:        if (this->ike_sa == ike_sa && state == CHILD_DESTROYING)
                    266:        {
                    267:                signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
                    268:        }
                    269:        return TRUE;
                    270: }
                    271: 
                    272: METHOD(listener_t, ike_rekey, bool,
                    273:        NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
                    274: {
                    275:        if (this->ike_sa == old)
                    276:        {       /* follow a rekeyed IKE_SA */
                    277:                this->ike_sa = new;
                    278:        }
                    279:        return TRUE;
                    280: }
                    281: 
                    282: METHOD(listener_t, ike_reestablish_pre, bool,
                    283:        NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
                    284: {
                    285:        if (this->ike_sa == old)
                    286:        {       /* ignore child state changes during redirects etc. (task migration) */
                    287:                this->listener.child_state_change = NULL;
                    288:        }
                    289:        return TRUE;
                    290: }
                    291: 
                    292: METHOD(listener_t, ike_reestablish_post, bool,
                    293:        NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new,
                    294:        bool initiated)
                    295: {
                    296:        if (this->ike_sa == old && initiated)
                    297:        {       /* if we get redirected during IKE_AUTH we just migrate to the new SA */
                    298:                this->ike_sa = new;
                    299:                /* re-register hooks to detect initiation failures */
                    300:                this->listener.ike_state_change = _ike_state_change;
                    301:                this->listener.child_state_change = _child_state_change;
                    302:        }
                    303:        return TRUE;
                    304: }
                    305: 
                    306: METHOD(listener_t, child_updown, bool,
                    307:        NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
                    308:        bool up)
                    309: {
                    310:        if (this->ike_sa == ike_sa)
                    311:        {
                    312:                if (up)
                    313:                {       /* disable initiate-failure-detection hooks */
                    314:                        this->listener.ike_state_change = NULL;
                    315:                        this->listener.child_state_change = NULL;
                    316:                        signal_ip_config(this->plugin, ike_sa, child_sa);
                    317:                }
                    318:                else
                    319:                {
                    320:                        if (ike_sa->has_condition(ike_sa, COND_REAUTHENTICATING))
                    321:                        {       /* we ignore this during reauthentication */
                    322:                                return TRUE;
                    323:                        }
                    324:                        signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
                    325:                }
                    326:        }
                    327:        return TRUE;
                    328: }
                    329: 
                    330: /**
                    331:  * Find a certificate for which we have a private key on a smartcard
                    332:  */
                    333: static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
                    334:                                                                                        char *pin)
                    335: {
                    336:        enumerator_t *enumerator, *sans;
                    337:        identification_t *id = NULL;
                    338:        certificate_t *cert;
                    339:        x509_t *x509;
                    340:        private_key_t *key;
                    341:        chunk_t keyid;
                    342: 
                    343:        enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
                    344:                                                                                        CERT_X509, KEY_ANY, NULL, FALSE);
                    345:        while (enumerator->enumerate(enumerator, &cert))
                    346:        {
                    347:                x509 = (x509_t*)cert;
                    348: 
                    349:                /* there might be a lot of certificates, filter them by usage */
                    350:                if ((x509->get_flags(x509) & X509_CLIENT_AUTH) &&
                    351:                        !(x509->get_flags(x509) & X509_CA))
                    352:                {
                    353:                        keyid = x509->get_subjectKeyIdentifier(x509);
                    354:                        if (keyid.ptr)
                    355:                        {
                    356:                                /* try to find a private key by the certificate keyid */
                    357:                                priv->creds->set_pin(priv->creds, keyid, pin);
                    358:                                key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
                    359:                                                                KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
                    360:                                if (key)
                    361:                                {
                    362:                                        /* prefer a more convenient subjectAltName */
                    363:                                        sans = x509->create_subjectAltName_enumerator(x509);
                    364:                                        if (!sans->enumerate(sans, &id))
                    365:                                        {
                    366:                                                id = cert->get_subject(cert);
                    367:                                        }
                    368:                                        id = id->clone(id);
                    369:                                        sans->destroy(sans);
                    370: 
                    371:                                        DBG1(DBG_CFG, "using smartcard certificate '%Y'", id);
                    372:                                        priv->creds->set_cert_and_key(priv->creds,
                    373:                                                                                                  cert->get_ref(cert), key);
                    374:                                        break;
                    375:                                }
                    376:                        }
                    377:                }
                    378:        }
                    379:        enumerator->destroy(enumerator);
                    380:        return id;
                    381: }
                    382: 
                    383: /**
                    384:  * Add a client auth config for certificate authentication
                    385:  */
                    386: static bool add_auth_cfg_cert(NMStrongswanPluginPrivate *priv,
                    387:                                                          NMSettingVpn *vpn, peer_cfg_t *peer_cfg,
                    388:                                                          GError **err)
                    389: {
                    390:        identification_t *id = NULL;
                    391:        certificate_t *cert = NULL;
                    392:        auth_cfg_t *auth;
                    393:        const char *str, *method, *cert_source;
                    394: 
                    395:        method = nm_setting_vpn_get_data_item(vpn, "method");
                    396:        cert_source = nm_setting_vpn_get_data_item(vpn, "cert-source") ?: method;
                    397: 
                    398:        if (streq(cert_source, "smartcard"))
                    399:        {
                    400:                char *pin;
                    401: 
                    402:                pin = (char*)nm_setting_vpn_get_secret(vpn, "password");
                    403:                if (pin)
                    404:                {
                    405:                        id = find_smartcard_key(priv, pin);
                    406:                }
                    407:                if (!id)
                    408:                {
                    409:                        g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    410:                                                NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    411:                                                "No usable smartcard certificate found.");
                    412:                        return FALSE;
                    413:                }
                    414:        }
                    415:        /* ... or certificate/private key authentication */
                    416:        else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert")))
                    417:        {
                    418:                public_key_t *public;
                    419:                private_key_t *private = NULL;
                    420: 
                    421:                bool agent = streq(cert_source, "agent");
                    422: 
                    423:                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                    424:                                                                  BUILD_FROM_FILE, str, BUILD_END);
                    425:                if (!cert)
                    426:                {
                    427:                        g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    428:                                                NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    429:                                                "Loading peer certificate failed.");
                    430:                        return FALSE;
                    431:                }
                    432:                /* try agent */
                    433:                str = nm_setting_vpn_get_secret(vpn, "agent");
                    434:                if (agent && str)
                    435:                {
                    436:                        public = cert->get_public_key(cert);
                    437:                        if (public)
                    438:                        {
                    439:                                private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
                    440:                                                                                         public->get_type(public),
                    441:                                                                                         BUILD_AGENT_SOCKET, str,
                    442:                                                                                         BUILD_PUBLIC_KEY, public,
                    443:                                                                                         BUILD_END);
                    444:                                public->destroy(public);
                    445:                        }
                    446:                        if (!private)
                    447:                        {
                    448:                                g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    449:                                                        NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    450:                                                        "Connecting to SSH agent failed.");
                    451:                        }
                    452:                }
                    453:                /* ... or key file */
                    454:                str = nm_setting_vpn_get_data_item(vpn, "userkey");
                    455:                if (!agent && str)
                    456:                {
                    457:                        char *secret;
                    458: 
                    459:                        secret = (char*)nm_setting_vpn_get_secret(vpn, "password");
                    460:                        if (secret)
                    461:                        {
                    462:                                priv->creds->set_key_password(priv->creds, secret);
                    463:                        }
                    464:                        private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
                    465:                                                                        KEY_ANY, BUILD_FROM_FILE, str, BUILD_END);
                    466:                        if (!private)
                    467:                        {
                    468:                                g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    469:                                                        NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    470:                                                        "Loading private key failed.");
                    471:                        }
                    472:                }
                    473:                if (private)
                    474:                {
                    475:                        id = cert->get_subject(cert);
                    476:                        id = id->clone(id);
                    477:                        priv->creds->set_cert_and_key(priv->creds, cert, private);
                    478:                }
                    479:                else
                    480:                {
                    481:                        DESTROY_IF(cert);
                    482:                        return FALSE;
                    483:                }
                    484:        }
                    485:        else
                    486:        {
                    487:                g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    488:                                        "Certificate is missing.");
                    489:                return FALSE;
                    490:        }
                    491: 
                    492:        auth = auth_cfg_create();
                    493:        if (streq(method, "eap-tls"))
                    494:        {
                    495:                auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
                    496:                auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_TLS);
                    497:                auth->add(auth, AUTH_RULE_AAA_IDENTITY,
                    498:                                  identification_create_from_string("%any"));
                    499:        }
                    500:        else
                    501:        {
                    502:                auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    503:        }
                    504:        if (cert)
                    505:        {
                    506:                auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert));
                    507:        }
                    508:        str = nm_setting_vpn_get_data_item(vpn, "local-identity");
                    509:        if (str)
                    510:        {
                    511:                identification_t *local_id;
                    512: 
                    513:                local_id = identification_create_from_string((char*)str);
                    514:                if (local_id)
                    515:                {
                    516:                        id->destroy(id);
                    517:                        id = local_id;
                    518:                }
                    519:        }
                    520:        auth->add(auth, AUTH_RULE_IDENTITY, id);
                    521:        peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
                    522:        return TRUE;
                    523: }
                    524: 
                    525: /**
                    526:  * Add a client auth config for username/password authentication
                    527:  */
                    528: static bool add_auth_cfg_pw(NMStrongswanPluginPrivate *priv,
                    529:                                                        NMSettingVpn *vpn, peer_cfg_t *peer_cfg,
                    530:                                                        GError **err)
                    531: {
                    532:        identification_t *user = NULL, *id = NULL;
                    533:        auth_cfg_t *auth;
                    534:        const char *str, *method;
                    535: 
                    536:        method = nm_setting_vpn_get_data_item(vpn, "method");
                    537: 
                    538:        str = nm_setting_vpn_get_data_item(vpn, "user");
                    539:        if (str)
                    540:        {
                    541:                user = identification_create_from_string((char*)str);
                    542:        }
                    543:        else
                    544:        {
                    545:                user = identification_create_from_string("%any");
                    546:        }
                    547:        str = nm_setting_vpn_get_data_item(vpn, "local-identity");
                    548:        if (str)
                    549:        {
                    550:                id = identification_create_from_string((char*)str);
                    551:        }
                    552:        else
                    553:        {
                    554:                id = user->clone(user);
                    555:        }
                    556:        str = nm_setting_vpn_get_secret(vpn, "password");
                    557:        if (streq(method, "psk"))
                    558:        {
                    559:                if (strlen(str) < 20)
                    560:                {
                    561:                        g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    562:                                                NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    563:                                                "Pre-shared key is too short.");
                    564:                        user->destroy(user);
                    565:                        id->destroy(id);
                    566:                        return FALSE;
                    567:                }
                    568:                priv->creds->set_username_password(priv->creds, id, (char*)str);
                    569:        }
                    570:        else
                    571:        {
                    572:                priv->creds->set_username_password(priv->creds, user, (char*)str);
                    573:        }
                    574: 
                    575:        auth = auth_cfg_create();
                    576:        auth->add(auth, AUTH_RULE_AUTH_CLASS,
                    577:                          streq(method, "psk") ? AUTH_CLASS_PSK : AUTH_CLASS_EAP);
                    578:        /* in case EAP-PEAP or EAP-TTLS is used we currently accept any identity */
                    579:        auth->add(auth, AUTH_RULE_AAA_IDENTITY,
                    580:                          identification_create_from_string("%any"));
                    581:        auth->add(auth, AUTH_RULE_EAP_IDENTITY, user);
                    582:        auth->add(auth, AUTH_RULE_IDENTITY, id);
                    583:        peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
                    584:        return TRUE;
                    585: }
                    586: 
                    587: /**
                    588:  * Connect function called from NM via DBUS
                    589:  */
                    590: static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
                    591:                                                 GError **err)
                    592: {
                    593:        NMStrongswanPlugin *pub = (NMStrongswanPlugin*)plugin;
                    594:        NMStrongswanPluginPrivate *priv;
                    595:        NMSettingConnection *conn;
                    596:        NMSettingVpn *vpn;
                    597:        enumerator_t *enumerator;
                    598:        identification_t *gateway = NULL;
                    599:        const char *str, *method;
                    600:        bool virtual, proposal;
                    601:        proposal_t *prop;
                    602:        ike_cfg_t *ike_cfg;
                    603:        peer_cfg_t *peer_cfg;
                    604:        child_cfg_t *child_cfg;
                    605:        traffic_selector_t *ts;
                    606:        ike_sa_t *ike_sa;
                    607:        auth_cfg_t *auth;
                    608:        certificate_t *cert = NULL;
                    609:        x509_t *x509;
                    610:        bool loose_gateway_id = FALSE;
                    611:        ike_cfg_create_t ike = {
                    612:                .version = IKEV2,
                    613:                .local = "%any",
                    614:                .local_port = charon->socket->get_port(charon->socket, FALSE),
                    615:                .remote_port = IKEV2_UDP_PORT,
                    616:                .fragmentation = FRAGMENTATION_YES,
                    617:        };
                    618:        peer_cfg_create_t peer = {
                    619:                .cert_policy = CERT_SEND_IF_ASKED,
                    620:                .unique = UNIQUE_REPLACE,
                    621:                .keyingtries = 1,
                    622:                .rekey_time = 36000, /* 10h */
                    623:                .jitter_time = 600, /* 10min */
                    624:                .over_time = 600, /* 10min */
                    625:        };
                    626:        child_cfg_create_t child = {
                    627:                .lifetime = {
                    628:                        .time = {
                    629:                                .life = 10800 /* 3h */,
                    630:                                .rekey = 10200 /* 2h50min */,
                    631:                                .jitter = 300 /* 5min */
                    632:                        },
                    633:                },
                    634:                .mode = MODE_TUNNEL,
                    635:        };
                    636: 
                    637:        /**
                    638:         * Read parameters
                    639:         */
                    640:        priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(pub);
                    641:        conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection,
                    642:                                                                                                NM_TYPE_SETTING_CONNECTION));
                    643:        vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
                    644:                                                                                                NM_TYPE_SETTING_VPN));
                    645:        if (priv->name)
                    646:        {
                    647:                free(priv->name);
                    648:        }
                    649:        priv->name = strdup(nm_setting_connection_get_id(conn));
                    650:        DBG1(DBG_CFG, "received initiate for NetworkManager connection %s",
                    651:                 priv->name);
                    652:        DBG4(DBG_CFG, "%s",
                    653:                 nm_setting_to_string(NM_SETTING(vpn)));
                    654:        ike.remote = (char*)nm_setting_vpn_get_data_item(vpn, "address");
                    655:        if (!ike.remote || !*ike.remote)
                    656:        {
                    657:                g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    658:                                        "Gateway address missing.");
                    659:                return FALSE;
                    660:        }
                    661:        str = nm_setting_vpn_get_data_item(vpn, "server-port");
                    662:        if (str && strlen(str))
                    663:        {
                    664:                ike.remote_port = settings_value_as_int((char*)str, ike.remote_port);
                    665:        }
                    666:        str = nm_setting_vpn_get_data_item(vpn, "virtual");
                    667:        virtual = streq(str, "yes");
                    668:        str = nm_setting_vpn_get_data_item(vpn, "encap");
                    669:        ike.force_encap = streq(str, "yes");
                    670:        str = nm_setting_vpn_get_data_item(vpn, "ipcomp");
                    671:        child.options |= streq(str, "yes") ? OPT_IPCOMP : 0;
                    672: 
                    673:        /**
                    674:         * Register credentials
                    675:         */
                    676:        priv->creds->clear(priv->creds);
                    677: 
                    678:        /* gateway/CA cert */
                    679:        str = nm_setting_vpn_get_data_item(vpn, "certificate");
                    680:        if (str)
                    681:        {
                    682:                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                    683:                                                                  BUILD_FROM_FILE, str, BUILD_END);
                    684:                if (!cert)
                    685:                {
                    686:                        g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    687:                                                NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    688:                                                "Loading gateway certificate failed.");
                    689:                        return FALSE;
                    690:                }
                    691:                priv->creds->add_certificate(priv->creds, cert);
                    692:        }
                    693:        else
                    694:        {
                    695:                /* no certificate defined, fall back to system-wide CA certificates */
                    696:                priv->creds->load_ca_dir(priv->creds, lib->settings->get_str(
                    697:                                                                 lib->settings, "charon-nm.ca_dir", NM_CA_DIR));
                    698:        }
                    699: 
                    700:        str = nm_setting_vpn_get_data_item(vpn, "remote-identity");
                    701:        if (str)
                    702:        {
                    703:                gateway = identification_create_from_string((char*)str);
                    704:        }
                    705:        else if (cert)
                    706:        {
                    707:                x509 = (x509_t*)cert;
                    708:                if (!(x509->get_flags(x509) & X509_CA))
                    709:                {       /* for server certificates, we use the subject as identity */
                    710:                        gateway = cert->get_subject(cert);
                    711:                        gateway = gateway->clone(gateway);
                    712:                }
                    713:        }
                    714:        if (!gateway || gateway->get_type(gateway) == ID_ANY)
                    715:        {
                    716:                /* if the user configured a CA certificate (or an invalid identity),
                    717:                 * we use the IP/hostname of the server */
                    718:                gateway = identification_create_from_string(ike.remote);
                    719:                loose_gateway_id = TRUE;
                    720:        }
                    721:        DBG1(DBG_CFG, "using gateway identity '%Y'", gateway);
                    722: 
                    723:        /**
                    724:         * Set up configurations
                    725:         */
                    726:        ike_cfg = ike_cfg_create(&ike);
                    727: 
                    728:        str = nm_setting_vpn_get_data_item(vpn, "proposal");
                    729:        proposal = streq(str, "yes");
                    730:        str = nm_setting_vpn_get_data_item(vpn, "ike");
                    731:        if (proposal && str && strlen(str))
                    732:        {
                    733:                enumerator = enumerator_create_token(str, ";", "");
                    734:                while (enumerator->enumerate(enumerator, &str))
                    735:                {
                    736:                        prop = proposal_create_from_string(PROTO_IKE, str);
                    737:                        if (!prop)
                    738:                        {
                    739:                                g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    740:                                                        NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
                    741:                                                        "Invalid IKE proposal.");
                    742:                                enumerator->destroy(enumerator);
                    743:                                ike_cfg->destroy(ike_cfg);
                    744:                                gateway->destroy(gateway);
                    745:                                return FALSE;
                    746:                        }
                    747:                        ike_cfg->add_proposal(ike_cfg, prop);
                    748:                }
                    749:                enumerator->destroy(enumerator);
                    750:        }
                    751:        else
                    752:        {
                    753:                ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
                    754:                ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
                    755:        }
                    756: 
                    757:        peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
                    758:        if (virtual)
                    759:        {
                    760:                peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
                    761:                peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
                    762:        }
                    763: 
                    764:        method = nm_setting_vpn_get_data_item(vpn, "method");
                    765:        if (streq(method, "cert") ||
                    766:                streq(method, "eap-tls") ||
                    767:                streq(method, "key") ||
                    768:                streq(method, "agent") ||
                    769:                streq(method, "smartcard"))
                    770:        {
                    771:                if (!add_auth_cfg_cert (priv, vpn, peer_cfg, err))
                    772:                {
                    773:                        peer_cfg->destroy(peer_cfg);
                    774:                        ike_cfg->destroy(ike_cfg);
                    775:                        gateway->destroy(gateway);
                    776:                        return FALSE;
                    777:                }
                    778:        }
                    779:        else if (streq(method, "eap") ||
                    780:                         streq(method, "psk"))
                    781:        {
                    782:                if (!add_auth_cfg_pw(priv, vpn, peer_cfg, err))
                    783:                {
                    784:                        peer_cfg->destroy(peer_cfg);
                    785:                        ike_cfg->destroy(ike_cfg);
                    786:                        gateway->destroy(gateway);
                    787:                        return FALSE;
                    788:                }
                    789:        }
                    790:        else
                    791:        {
                    792:                g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
                    793:                                        "Configuration parameters missing.");
                    794:                peer_cfg->destroy(peer_cfg);
                    795:                ike_cfg->destroy(ike_cfg);
                    796:                gateway->destroy(gateway);
                    797:                return FALSE;
                    798:        }
                    799: 
                    800:        auth = auth_cfg_create();
                    801:        if (streq(method, "psk"))
                    802:        {
                    803:                auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
                    804:        }
                    805:        else
                    806:        {
                    807:                auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
                    808:        }
                    809:        auth->add(auth, AUTH_RULE_IDENTITY, gateway);
                    810:        auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id);
                    811:        peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
                    812: 
                    813:        child_cfg = child_cfg_create(priv->name, &child);
                    814:        str = nm_setting_vpn_get_data_item(vpn, "esp");
                    815:        if (proposal && str && strlen(str))
                    816:        {
                    817:                enumerator = enumerator_create_token(str, ";", "");
                    818:                while (enumerator->enumerate(enumerator, &str))
                    819:                {
                    820:                        prop = proposal_create_from_string(PROTO_ESP, str);
                    821:                        if (!prop)
                    822:                        {
                    823:                                g_set_error(err, NM_VPN_PLUGIN_ERROR,
                    824:                                                        NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
                    825:                                                        "Invalid ESP proposal.");
                    826:                                enumerator->destroy(enumerator);
                    827:                                child_cfg->destroy(child_cfg);
                    828:                                peer_cfg->destroy(peer_cfg);
                    829:                                return FALSE;
                    830:                        }
                    831:                        child_cfg->add_proposal(child_cfg, prop);
                    832:                }
                    833:                enumerator->destroy(enumerator);
                    834:        }
                    835:        else
                    836:        {
                    837:                child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
                    838:                child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
                    839:        }
                    840:        ts = traffic_selector_create_dynamic(0, 0, 65535);
                    841:        child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
                    842:        ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
                    843:        child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
                    844:        ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
                    845:        child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
                    846:        peer_cfg->add_child_cfg(peer_cfg, child_cfg);
                    847: 
                    848:        /**
                    849:         * Prepare IKE_SA
                    850:         */
                    851:        ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
                    852:                                                                                                                peer_cfg);
                    853:        if (!ike_sa)
                    854:        {
                    855:                peer_cfg->destroy(peer_cfg);
                    856:                g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
                    857:                                        "IKE version not supported.");
                    858:                return FALSE;
                    859:        }
                    860:        if (!ike_sa->get_peer_cfg(ike_sa))
                    861:        {
                    862:                ike_sa->set_peer_cfg(ike_sa, peer_cfg);
                    863:        }
                    864:        peer_cfg->destroy(peer_cfg);
                    865: 
                    866:        /**
                    867:         * Register listener, enable  initiate-failure-detection hooks
                    868:         */
                    869:        priv->ike_sa = ike_sa;
                    870:        priv->listener.ike_state_change = _ike_state_change;
                    871:        priv->listener.child_state_change = _child_state_change;
                    872: 
                    873:        /**
                    874:         * Initiate
                    875:         */
                    876:        child_cfg->get_ref(child_cfg);
                    877:        if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
                    878:        {
                    879:                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
                    880: 
                    881:                g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
                    882:                                        "Initiating failed.");
                    883:                return FALSE;
                    884:        }
                    885:        charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    886:        return TRUE;
                    887: }
                    888: 
                    889: /**
                    890:  * NeedSecrets called from NM via DBUS
                    891:  */
                    892: static gboolean need_secrets(NMVpnServicePlugin *plugin, NMConnection *connection,
                    893:                                                         const char **setting_name, GError **error)
                    894: {
                    895:        NMSettingVpn *settings;
                    896:        const char *method, *cert_source, *path;
                    897:        bool need_secret = FALSE;
                    898: 
                    899:        settings = NM_SETTING_VPN(nm_connection_get_setting(connection,
                    900:                                                                                                                NM_TYPE_SETTING_VPN));
                    901:        method = nm_setting_vpn_get_data_item(settings, "method");
                    902:        if (method)
                    903:        {
                    904:                if (streq(method, "cert") ||
                    905:                        streq(method, "eap-tls") ||
                    906:                        streq(method, "key") ||
                    907:                        streq(method, "agent") ||
                    908:                        streq(method, "smartcard"))
                    909:                {
                    910:                        cert_source = nm_setting_vpn_get_data_item(settings, "cert-source");
                    911:                        if (!cert_source)
                    912:                        {
                    913:                                cert_source = method;
                    914:                        }
                    915:                        if (streq(cert_source, "agent"))
                    916:                        {
                    917:                                need_secret = !nm_setting_vpn_get_secret(settings, "agent");
                    918:                        }
                    919:                        else if (streq(cert_source, "smartcard"))
                    920:                        {
                    921:                                need_secret = !nm_setting_vpn_get_secret(settings, "password");
                    922:                        }
                    923:                        else
                    924:                        {
                    925:                                need_secret = TRUE;
                    926:                                path = nm_setting_vpn_get_data_item(settings, "userkey");
                    927:                                if (path)
                    928:                                {
                    929:                                        private_key_t *key;
                    930: 
                    931:                                        /* try to load/decrypt the private key */
                    932:                                        key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
                    933:                                                                        KEY_ANY, BUILD_FROM_FILE, path, BUILD_END);
                    934:                                        if (key)
                    935:                                        {
                    936:                                                key->destroy(key);
                    937:                                                need_secret = FALSE;
                    938:                                        }
                    939:                                        else if (nm_setting_vpn_get_secret(settings, "password"))
                    940:                                        {
                    941:                                                need_secret = FALSE;
                    942:                                        }
                    943:                                }
                    944:                        }
                    945:                }
                    946:                else if (streq(method, "eap") ||
                    947:                                 streq(method, "psk"))
                    948:                {
                    949:                        need_secret = !nm_setting_vpn_get_secret(settings, "password");
                    950:                }
                    951:        }
                    952:        *setting_name = NM_SETTING_VPN_SETTING_NAME;
                    953:        return need_secret;
                    954: }
                    955: 
                    956: /**
                    957:  * The actual disconnection
                    958:  */
                    959: static gboolean do_disconnect(gpointer plugin)
                    960: {
                    961:        NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
                    962:        enumerator_t *enumerator;
                    963:        ike_sa_t *ike_sa;
                    964:        u_int id;
                    965: 
                    966:        /* our ike_sa pointer might be invalid, lookup sa */
                    967:        enumerator = charon->controller->create_ike_sa_enumerator(
                    968:                                                                                                        charon->controller, TRUE);
                    969:        while (enumerator->enumerate(enumerator, &ike_sa))
                    970:        {
                    971:                if (priv->ike_sa == ike_sa)
                    972:                {
                    973:                        id = ike_sa->get_unique_id(ike_sa);
                    974:                        enumerator->destroy(enumerator);
                    975:                        charon->controller->terminate_ike(charon->controller, id, FALSE,
                    976:                                                                                          controller_cb_empty, NULL, 0);
                    977:                        return FALSE;
                    978:                }
                    979:        }
                    980:        enumerator->destroy(enumerator);
                    981: 
                    982:        g_debug("Connection not found.");
                    983:        return FALSE;
                    984: }
                    985: 
                    986: /**
                    987:  * Disconnect called from NM via DBUS
                    988:  */
                    989: static gboolean disconnect(NMVpnServicePlugin *plugin, GError **err)
                    990: {
                    991:        /* enqueue the actual disconnection, because we may be called in
                    992:         * response to a listener_t callback and the SA enumeration would
                    993:         * possibly deadlock. */
                    994:        g_idle_add(do_disconnect, plugin);
                    995: 
                    996:        return TRUE;
                    997: }
                    998: 
                    999: /**
                   1000:  * Initializer
                   1001:  */
                   1002: static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
                   1003: {
                   1004:        NMStrongswanPluginPrivate *priv;
                   1005: 
                   1006:        priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
                   1007:        priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
                   1008:        memset(&priv->listener, 0, sizeof(listener_t));
                   1009:        priv->listener.child_updown = _child_updown;
                   1010:        priv->listener.ike_rekey = _ike_rekey;
                   1011:        priv->listener.ike_reestablish_pre = _ike_reestablish_pre;
                   1012:        priv->listener.ike_reestablish_post = _ike_reestablish_post;
                   1013:        charon->bus->add_listener(charon->bus, &priv->listener);
                   1014:        priv->name = NULL;
                   1015: }
                   1016: 
                   1017: /**
                   1018:  * Class constructor
                   1019:  */
                   1020: static void nm_strongswan_plugin_class_init(
                   1021:                                                                        NMStrongswanPluginClass *strongswan_class)
                   1022: {
                   1023:        NMVpnServicePluginClass *parent_class = NM_VPN_SERVICE_PLUGIN_CLASS(strongswan_class);
                   1024: 
                   1025:        parent_class->connect = connect_;
                   1026:        parent_class->need_secrets = need_secrets;
                   1027:        parent_class->disconnect = disconnect;
                   1028: }
                   1029: 
                   1030: /**
                   1031:  * Object constructor
                   1032:  */
                   1033: NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds,
                   1034:                                                                                         nm_handler_t *handler)
                   1035: {
                   1036:        GError *error = NULL;
                   1037: 
                   1038:        NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_initable_new (
                   1039:                                        NM_TYPE_STRONGSWAN_PLUGIN,
                   1040:                                        NULL,
                   1041:                                        &error,
                   1042:                                        NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN,
                   1043:                                        NULL);
                   1044: 
                   1045:        if (plugin)
                   1046:        {
                   1047:                NMStrongswanPluginPrivate *priv;
                   1048: 
                   1049:                /* the rest of the initialization happened in _init above */
                   1050:                priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
                   1051:                priv->creds = creds;
                   1052:                priv->handler = handler;
                   1053:        }
                   1054:        else
                   1055:        {
                   1056:                g_warning ("Failed to initialize a plugin instance: %s", error->message);
                   1057:                g_error_free (error);
                   1058:        }
                   1059: 
                   1060:        return plugin;
                   1061: }

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