Annotation of embedaddon/strongswan/src/swanctl/commands/load_creds.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2016-2017 Tobias Brunner
                      3:  * Copyright (C) 2015 Andreas Steffen
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * Copyright (C) 2014 Martin Willi
                      7:  * Copyright (C) 2014 revosec AG
                      8:  *
                      9:  * This program is free software; you can redistribute it and/or modify it
                     10:  * under the terms of the GNU General Public License as published by the
                     11:  * Free Software Foundation; either version 2 of the License, or (at your
                     12:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     13:  *
                     14:  * This program is distributed in the hope that it will be useful, but
                     15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     16:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     17:  * for more details.
                     18:  */
                     19: 
                     20: #define _GNU_SOURCE
                     21: #include <stdio.h>
                     22: #include <errno.h>
                     23: #include <unistd.h>
                     24: #include <sys/stat.h>
                     25: 
                     26: #include "command.h"
                     27: #include "swanctl.h"
                     28: #include "load_creds.h"
                     29: 
                     30: #include <credentials/sets/mem_cred.h>
                     31: #include <credentials/sets/callback_cred.h>
                     32: #include <credentials/containers/pkcs12.h>
                     33: #include <collections/hashtable.h>
                     34: 
                     35: #include <vici_cert_info.h>
                     36: 
                     37: /**
                     38:  * Context used to track loaded secrets
                     39:  */
                     40: typedef struct {
                     41:        /** vici connection */
                     42:        vici_conn_t *conn;
                     43:        /** format options */
                     44:        command_format_options_t format;
                     45:        /** read setting */
                     46:        settings_t *cfg;
                     47:        /** don't prompt user for password */
                     48:        bool noprompt;
                     49:        /** list of key ids of loaded private keys */
                     50:        hashtable_t *keys;
                     51:        /** list of unique ids of loaded shared keys */
                     52:        hashtable_t *shared;
                     53: } load_ctx_t;
                     54: 
                     55: /**
                     56:  * Load a single certificate over vici
                     57:  */
                     58: static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type,
                     59:                                          x509_flag_t flag, chunk_t data)
                     60: {
                     61:        vici_req_t *req;
                     62:        vici_res_t *res;
                     63:        bool ret = TRUE;
                     64: 
                     65:        req = vici_begin("load-cert");
                     66: 
                     67:        vici_add_key_valuef(req, "type", "%N", certificate_type_names, type);
                     68:        if (type == CERT_X509)
                     69:        {
                     70:                vici_add_key_valuef(req, "flag", "%N", x509_flag_names, flag);
                     71:        }
                     72:        vici_add_key_value(req, "data", data.ptr, data.len);
                     73: 
                     74:        res = vici_submit(req, ctx->conn);
                     75:        if (!res)
                     76:        {
                     77:                fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
                     78:                return FALSE;
                     79:        }
                     80:        if (ctx->format & COMMAND_FORMAT_RAW)
                     81:        {
                     82:                vici_dump(res, "load-cert reply", ctx->format & COMMAND_FORMAT_PRETTY,
                     83:                                  stdout);
                     84:        }
                     85:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                     86:        {
                     87:                fprintf(stderr, "loading '%s' failed: %s\n",
                     88:                                dir, vici_find_str(res, "", "errmsg"));
                     89:                ret = FALSE;
                     90:        }
                     91:        else
                     92:        {
                     93:                printf("loaded certificate from '%s'\n", dir);
                     94:        }
                     95:        vici_free_res(res);
                     96:        return ret;
                     97: }
                     98: 
                     99: /**
                    100:  * Load certificates from a directory
                    101:  */
                    102: static void load_certs(load_ctx_t *ctx, char *type_str, char *dir)
                    103: {
                    104:        enumerator_t *enumerator;
                    105:        certificate_type_t type;
                    106:        x509_flag_t flag;
                    107:        struct stat st;
                    108:        chunk_t *map;
                    109:        char *path, buf[PATH_MAX];
                    110: 
                    111:        vici_cert_info_from_str(type_str, &type, &flag);
                    112: 
                    113:        snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
                    114:        dir = buf;
                    115: 
                    116:        enumerator = enumerator_create_directory(dir);
                    117:        if (enumerator)
                    118:        {
                    119:                while (enumerator->enumerate(enumerator, NULL, &path, &st))
                    120:                {
                    121:                        if (S_ISREG(st.st_mode))
                    122:                        {
                    123:                                map = chunk_map(path, FALSE);
                    124:                                if (map)
                    125:                                {
                    126:                                        load_cert(ctx, path, type, flag, *map);
                    127:                                        chunk_unmap(map);
                    128:                                }
                    129:                                else
                    130:                                {
                    131:                                        fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
                    132:                                                        path, strerror(errno));
                    133:                                }
                    134:                        }
                    135:                }
                    136:                enumerator->destroy(enumerator);
                    137:        }
                    138: }
                    139: 
                    140: /**
                    141:  * Load a single private key over vici
                    142:  */
                    143: static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
                    144: {
                    145:        vici_req_t *req;
                    146:        vici_res_t *res;
                    147:        bool ret = TRUE;
                    148:        char *id;
                    149: 
                    150:        req = vici_begin("load-key");
                    151: 
                    152:        if (streq(type, "private") ||
                    153:                streq(type, "pkcs8"))
                    154:        {       /* as used by vici */
                    155:                vici_add_key_valuef(req, "type", "any");
                    156:        }
                    157:        else
                    158:        {
                    159:                vici_add_key_valuef(req, "type", "%s", type);
                    160:        }
                    161:        vici_add_key_value(req, "data", data.ptr, data.len);
                    162: 
                    163:        res = vici_submit(req, ctx->conn);
                    164:        if (!res)
                    165:        {
                    166:                fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
                    167:                return FALSE;
                    168:        }
                    169:        if (ctx->format & COMMAND_FORMAT_RAW)
                    170:        {
                    171:                vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    172:                                  stdout);
                    173:        }
                    174:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    175:        {
                    176:                fprintf(stderr, "loading '%s' failed: %s\n",
                    177:                                dir, vici_find_str(res, "", "errmsg"));
                    178:                ret = FALSE;
                    179:        }
                    180:        else
                    181:        {
                    182:                printf("loaded %s key from '%s'\n", type, dir);
                    183:                id = vici_find_str(res, "", "id");
                    184:                free(ctx->keys->remove(ctx->keys, id));
                    185:        }
                    186:        vici_free_res(res);
                    187:        return ret;
                    188: }
                    189: 
                    190: /**
                    191:  * Load a private key of any type to vici
                    192:  */
                    193: static bool load_key_anytype(load_ctx_t *ctx, char *path,
                    194:                                                         private_key_t *private)
                    195: {
                    196:        bool loaded = FALSE;
                    197:        chunk_t encoding;
1.1.1.2 ! misho     198:        char *type;
1.1       misho     199: 
                    200:        if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
                    201:        {
                    202:                fprintf(stderr, "encoding private key from '%s' failed\n", path);
                    203:                return FALSE;
                    204:        }
1.1.1.2 ! misho     205:        type = enum_to_name(key_type_names, private->get_type(private));
        !           206:        if (type)
1.1       misho     207:        {
1.1.1.2 ! misho     208:                loaded = load_key(ctx, path, type, encoding);
        !           209:        }
        !           210:        if (!loaded)
        !           211:        {
        !           212:                fprintf(stderr, "unsupported key type in '%s'\n", path);
1.1       misho     213:        }
                    214:        chunk_clear(&encoding);
                    215:        return loaded;
                    216: }
                    217: 
                    218: /**
                    219:  * Data passed to password callback
                    220:  */
                    221: typedef struct {
                    222:        char prompt[128];
                    223:        mem_cred_t *cache;
                    224: } cb_data_t;
                    225: 
                    226: /**
                    227:  * Callback function to prompt for private key passwords
                    228:  */
                    229: CALLBACK(password_cb, shared_key_t*,
                    230:        cb_data_t *data, shared_key_type_t type,
                    231:        identification_t *me, identification_t *other,
                    232:        id_match_t *match_me, id_match_t *match_other)
                    233: {
                    234:        shared_key_t *shared;
                    235:        char *pwd = NULL;
                    236: 
                    237:        if (type != SHARED_PRIVATE_KEY_PASS)
                    238:        {
                    239:                return NULL;
                    240:        }
                    241: #ifdef HAVE_GETPASS
                    242:        pwd = getpass(data->prompt);
                    243: #endif
                    244:        if (!pwd || strlen(pwd) == 0)
                    245:        {
                    246:                return NULL;
                    247:        }
                    248:        if (match_me)
                    249:        {
                    250:                *match_me = ID_MATCH_PERFECT;
                    251:        }
                    252:        if (match_other)
                    253:        {
                    254:                *match_other = ID_MATCH_PERFECT;
                    255:        }
                    256:        shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
                    257:        /* cache secret if it is required more than once (PKCS#12) */
                    258:        data->cache->add_shared(data->cache, shared, NULL);
                    259:        return shared->get_ref(shared);
                    260: }
                    261: 
                    262: /**
                    263:  * Determine credential type and subtype from a type string
                    264:  */
                    265: static bool determine_credtype(char *type, credential_type_t *credtype,
                    266:                                                           int *subtype)
                    267: {
                    268:        struct {
                    269:                char *type;
                    270:                credential_type_t credtype;
                    271:                int subtype;
                    272:        } map[] = {
                    273:                { "private",            CRED_PRIVATE_KEY,               KEY_ANY,                        },
                    274:                { "pkcs8",                      CRED_PRIVATE_KEY,               KEY_ANY,                        },
                    275:                { "rsa",                        CRED_PRIVATE_KEY,               KEY_RSA,                        },
                    276:                { "ecdsa",                      CRED_PRIVATE_KEY,               KEY_ECDSA,                      },
                    277:                { "bliss",                      CRED_PRIVATE_KEY,               KEY_BLISS,                      },
                    278:                { "pkcs12",                     CRED_CONTAINER,                 CONTAINER_PKCS12,       },
                    279:        };
                    280:        int i;
                    281: 
                    282:        for (i = 0; i < countof(map); i++)
                    283:        {
                    284:                if (streq(map[i].type, type))
                    285:                {
                    286:                        *credtype = map[i].credtype;
                    287:                        *subtype = map[i].subtype;
                    288:                        return TRUE;
                    289:                }
                    290:        }
                    291:        return FALSE;
                    292: }
                    293: 
                    294: /**
                    295:  * Try to parse a potentially encrypted credential using password prompt
                    296:  */
                    297: static void* decrypt(char *name, char *type, chunk_t encoding)
                    298: {
                    299:        credential_type_t credtype;
                    300:        int subtype;
                    301:        void *cred;
                    302:        callback_cred_t *cb;
                    303:        cb_data_t data;
                    304: 
                    305:        if (!determine_credtype(type, &credtype, &subtype))
                    306:        {
                    307:                return NULL;
                    308:        }
                    309: 
                    310:        snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
                    311:                         type, name);
                    312: 
                    313:        data.cache = mem_cred_create();
                    314:        lib->credmgr->add_set(lib->credmgr, &data.cache->set);
                    315:        cb = callback_cred_create_shared(password_cb, &data);
                    316:        lib->credmgr->add_set(lib->credmgr, &cb->set);
                    317: 
                    318:        cred = lib->creds->create(lib->creds, credtype, subtype,
                    319:                                                          BUILD_BLOB_PEM, encoding, BUILD_END);
                    320: 
                    321:        lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
                    322:        data.cache->destroy(data.cache);
                    323:        lib->credmgr->remove_set(lib->credmgr, &cb->set);
                    324:        cb->destroy(cb);
                    325: 
                    326:        return cred;
                    327: }
                    328: 
                    329: /**
                    330:  * Try to parse a potentially encrypted credential using configured secret
                    331:  */
                    332: static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
                    333:                                                                 chunk_t encoding)
                    334: {
                    335:        credential_type_t credtype;
                    336:        int subtype;
                    337:        enumerator_t *enumerator, *secrets;
                    338:        char *section, *key, *value, *file;
                    339:        shared_key_t *shared;
                    340:        void *cred = NULL;
                    341:        mem_cred_t *mem = NULL;
                    342: 
                    343:        if (!determine_credtype(type, &credtype, &subtype))
                    344:        {
                    345:                return NULL;
                    346:        }
                    347: 
                    348:        /* load all secrets for this key type */
                    349:        enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
                    350:        while (enumerator->enumerate(enumerator, &section))
                    351:        {
                    352:                if (strpfx(section, type))
                    353:                {
                    354:                        file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section);
                    355:                        if (file && strcaseeq(file, name))
                    356:                        {
                    357:                                secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg,
                    358:                                                                                                                "secrets.%s", section);
                    359:                                while (secrets->enumerate(secrets, &key, &value))
                    360:                                {
                    361:                                        if (strpfx(key, "secret"))
                    362:                                        {
                    363:                                                if (!mem)
                    364:                                                {
                    365:                                                        mem = mem_cred_create();
                    366:                                                }
                    367:                                                shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
                    368:                                                                                        chunk_clone(chunk_from_str(value)));
                    369:                                                mem->add_shared(mem, shared, NULL);
                    370:                                        }
                    371:                                }
                    372:                                secrets->destroy(secrets);
                    373:                        }
                    374:                }
                    375:        }
                    376:        enumerator->destroy(enumerator);
                    377: 
                    378:        if (mem)
                    379:        {
                    380:                lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
                    381: 
                    382:                cred = lib->creds->create(lib->creds, credtype, subtype,
                    383:                                                                  BUILD_BLOB_PEM, encoding, BUILD_END);
                    384: 
                    385:                lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
                    386: 
                    387:                if (!cred)
                    388:                {
                    389:                        fprintf(stderr, "configured decryption secret for '%s' invalid\n",
                    390:                                        name);
                    391:                }
                    392: 
                    393:                mem->destroy(mem);
                    394:        }
                    395: 
                    396:        return cred;
                    397: }
                    398: 
                    399: /**
                    400:  * Try to decrypt and load a private key
                    401:  */
                    402: static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
                    403:                                                           char *type, chunk_t data)
                    404: {
                    405:        private_key_t *private;
                    406:        bool loaded = FALSE;
                    407: 
                    408:        private = decrypt_with_config(ctx, rel, type, data);
                    409:        if (!private && !ctx->noprompt)
                    410:        {
                    411:                private = decrypt(rel, type, data);
                    412:        }
                    413:        if (private)
                    414:        {
                    415:                loaded = load_key_anytype(ctx, path, private);
                    416:                private->destroy(private);
                    417:        }
                    418:        return loaded;
                    419: }
                    420: 
                    421: /**
                    422:  * Load private keys from a directory
                    423:  */
                    424: static void load_keys(load_ctx_t *ctx, char *type, char *dir)
                    425: {
                    426:        enumerator_t *enumerator;
                    427:        struct stat st;
                    428:        chunk_t *map;
                    429:        char *path, *rel, buf[PATH_MAX];
                    430: 
                    431:        snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
                    432:        dir = buf;
                    433: 
                    434:        enumerator = enumerator_create_directory(dir);
                    435:        if (enumerator)
                    436:        {
                    437:                while (enumerator->enumerate(enumerator, &rel, &path, &st))
                    438:                {
                    439:                        if (S_ISREG(st.st_mode))
                    440:                        {
                    441:                                map = chunk_map(path, FALSE);
                    442:                                if (map)
                    443:                                {
                    444:                                        if (!load_encrypted_key(ctx, rel, path, type, *map))
                    445:                                        {
                    446:                                                load_key(ctx, path, type, *map);
                    447:                                        }
                    448:                                        chunk_unmap(map);
                    449:                                }
                    450:                                else
                    451:                                {
                    452:                                        fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
                    453:                                                        path, strerror(errno));
                    454:                                }
                    455:                        }
                    456:                }
                    457:                enumerator->destroy(enumerator);
                    458:        }
                    459: }
                    460: 
                    461: /**
                    462:  * Load credentials from a PKCS#12 container over vici
                    463:  */
                    464: static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12)
                    465: {
                    466:        enumerator_t *enumerator;
                    467:        certificate_t *cert;
                    468:        private_key_t *private;
                    469:        chunk_t encoding;
                    470:        bool loaded = TRUE;
                    471: 
                    472:        enumerator = p12->create_cert_enumerator(p12);
                    473:        while (loaded && enumerator->enumerate(enumerator, &cert))
                    474:        {
                    475:                loaded = FALSE;
                    476:                if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
                    477:                {
                    478:                        loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding);
                    479:                        if (loaded)
                    480:                        {
                    481:                                fprintf(stderr, "  %Y\n", cert->get_subject(cert));
                    482:                        }
                    483:                        free(encoding.ptr);
                    484:                }
                    485:                else
                    486:                {
                    487:                        fprintf(stderr, "encoding certificate from '%s' failed\n", path);
                    488:                }
                    489:        }
                    490:        enumerator->destroy(enumerator);
                    491: 
                    492:        enumerator = p12->create_key_enumerator(p12);
                    493:        while (loaded && enumerator->enumerate(enumerator, &private))
                    494:        {
                    495:                loaded = load_key_anytype(ctx, path, private);
                    496:        }
                    497:        enumerator->destroy(enumerator);
                    498: 
                    499:        return loaded;
                    500: }
                    501: 
                    502: /**
                    503:  * Try to decrypt and load credentials from a container
                    504:  */
                    505: static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path,
                    506:                                                                         char *type, chunk_t data)
                    507: {
                    508:        container_t *container;
                    509:        bool loaded = FALSE;
                    510: 
                    511:        container = decrypt_with_config(ctx, rel, type, data);
                    512:        if (!container && !ctx->noprompt)
                    513:        {
                    514:                container = decrypt(rel, type, data);
                    515:        }
                    516:        if (container)
                    517:        {
                    518:                switch (container->get_type(container))
                    519:                {
                    520:                        case CONTAINER_PKCS12:
                    521:                                loaded = load_pkcs12(ctx, path, (pkcs12_t*)container);
                    522:                                break;
                    523:                        default:
                    524:                                break;
                    525:                }
                    526:                container->destroy(container);
                    527:        }
                    528:        return loaded;
                    529: }
                    530: 
                    531: /**
                    532:  * Load credential containers from a directory
                    533:  */
                    534: static void load_containers(load_ctx_t *ctx, char *type, char *dir)
                    535: {
                    536:        enumerator_t *enumerator;
                    537:        struct stat st;
                    538:        chunk_t *map;
                    539:        char *path, *rel, buf[PATH_MAX];
                    540: 
                    541:        snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
                    542:        dir = buf;
                    543: 
                    544:        enumerator = enumerator_create_directory(dir);
                    545:        if (enumerator)
                    546:        {
                    547:                while (enumerator->enumerate(enumerator, &rel, &path, &st))
                    548:                {
                    549:                        if (S_ISREG(st.st_mode))
                    550:                        {
                    551:                                map = chunk_map(path, FALSE);
                    552:                                if (map)
                    553:                                {
                    554:                                        load_encrypted_container(ctx, rel, path, type, *map);
                    555:                                        chunk_unmap(map);
                    556:                                }
                    557:                                else
                    558:                                {
                    559:                                        fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
                    560:                                                        path, strerror(errno));
                    561:                                }
                    562:                        }
                    563:                }
                    564:                enumerator->destroy(enumerator);
                    565:        }
                    566: }
                    567: 
                    568: /**
                    569:  * Load a single private key on a token over vici
                    570:  */
                    571: static bool load_token(load_ctx_t *ctx, char *name, char *pin)
                    572: {
                    573:        vici_req_t *req;
                    574:        vici_res_t *res;
                    575:        enumerator_t *enumerator;
                    576:        char *key, *value, *id;
                    577:        bool ret = TRUE;
                    578: 
                    579:        req = vici_begin("load-token");
                    580: 
                    581:        enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
                    582:                                                                                                           name);
                    583:        while (enumerator->enumerate(enumerator, &key, &value))
                    584:        {
                    585:                vici_add_key_valuef(req, key, "%s", value);
                    586:        }
                    587:        enumerator->destroy(enumerator);
                    588: 
                    589:        if (pin)
                    590:        {
                    591:                vici_add_key_valuef(req, "pin", "%s", pin);
                    592:        }
                    593:        res = vici_submit(req, ctx->conn);
                    594:        if (!res)
                    595:        {
                    596:                fprintf(stderr, "load-token request failed: %s\n", strerror(errno));
                    597:                return FALSE;
                    598:        }
                    599:        if (ctx->format & COMMAND_FORMAT_RAW)
                    600:        {
                    601:                vici_dump(res, "load-token reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    602:                                  stdout);
                    603:        }
                    604:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    605:        {
                    606:                fprintf(stderr, "loading '%s' failed: %s\n",
                    607:                                name, vici_find_str(res, "", "errmsg"));
                    608:                ret = FALSE;
                    609:        }
                    610:        else
                    611:        {
                    612:                id = vici_find_str(res, "", "id");
                    613:                printf("loaded key %s from token [keyid: %s]\n", name, id);
                    614:                free(ctx->keys->remove(ctx->keys, id));
                    615:        }
                    616:        vici_free_res(res);
                    617:        return ret;
                    618: }
                    619: 
                    620: /**
                    621:  * Load keys from tokens
                    622:  */
                    623: static void load_tokens(load_ctx_t *ctx)
                    624: {
                    625:        enumerator_t *enumerator;
                    626:        char *section, *pin = NULL, prompt[128];
                    627: 
                    628:        enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
                    629:        while (enumerator->enumerate(enumerator, &section))
                    630:        {
                    631:                if (strpfx(section, "token"))
                    632:                {
                    633:                        if (!ctx->noprompt &&
                    634:                                !ctx->cfg->get_str(ctx->cfg, "secrets.%s.pin", NULL, section))
                    635:                        {
                    636: #ifdef HAVE_GETPASS
                    637:                                snprintf(prompt, sizeof(prompt), "PIN for %s: ", section);
                    638:                                pin = strdupnull(getpass(prompt));
                    639: #endif
                    640:                        }
                    641:                        load_token(ctx, section, pin);
                    642:                        if (pin)
                    643:                        {
                    644:                                memwipe(pin, strlen(pin));
                    645:                                free(pin);
                    646:                                pin = NULL;
                    647:                        }
                    648:                }
                    649:        }
                    650:        enumerator->destroy(enumerator);
                    651: }
                    652: 
                    653: 
                    654: 
                    655: /**
                    656:  * Load a single secret over VICI
                    657:  */
                    658: static bool load_secret(load_ctx_t *ctx, char *section)
                    659: {
                    660:        enumerator_t *enumerator;
                    661:        vici_req_t *req;
                    662:        vici_res_t *res;
                    663:        chunk_t data;
                    664:        char *key, *value, *type = NULL;
                    665:        bool ret = TRUE;
                    666:        int i;
                    667:        char *types[] = {
                    668:                "eap",
                    669:                "xauth",
                    670:                "ntlm",
                    671:                "ike",
                    672:                "ppk",
                    673:                "private",
                    674:                "rsa",
                    675:                "ecdsa",
                    676:                "bliss",
                    677:                "pkcs8",
                    678:                "pkcs12",
                    679:                "token",
                    680:        };
                    681: 
                    682:        for (i = 0; i < countof(types); i++)
                    683:        {
                    684:                if (strpfx(section, types[i]))
                    685:                {
                    686:                        type = types[i];
                    687:                        break;
                    688:                }
                    689:        }
                    690:        if (!type)
                    691:        {
                    692:                fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
                    693:                return FALSE;
                    694:        }
                    695:        if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ntlm") &&
                    696:                !streq(type, "ike") && !streq(type, "ppk"))
                    697:        {       /* skip non-shared secrets */
                    698:                return TRUE;
                    699:        }
                    700: 
                    701:        value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section);
                    702:        if (!value)
                    703:        {
                    704:                fprintf(stderr, "missing secret in '%s', ignored\n", section);
                    705:                return FALSE;
                    706:        }
                    707:        if (strcasepfx(value, "0x"))
                    708:        {
                    709:                data = chunk_from_hex(chunk_from_str(value + 2), NULL);
                    710:        }
                    711:        else if (strcasepfx(value, "0s"))
                    712:        {
                    713:                data = chunk_from_base64(chunk_from_str(value + 2), NULL);
                    714:        }
                    715:        else
                    716:        {
                    717:                data = chunk_clone(chunk_from_str(value));
                    718:        }
                    719: 
                    720:        req = vici_begin("load-shared");
                    721: 
                    722:        vici_add_key_valuef(req, "id", "%s", section);
                    723:        vici_add_key_valuef(req, "type", "%s", type);
                    724:        vici_add_key_value(req, "data", data.ptr, data.len);
                    725:        chunk_clear(&data);
                    726: 
                    727:        vici_begin_list(req, "owners");
                    728:        enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
                    729:                                                                                                           section);
                    730:        while (enumerator->enumerate(enumerator, &key, &value))
                    731:        {
                    732:                if (strpfx(key, "id"))
                    733:                {
                    734:                        vici_add_list_itemf(req, "%s", value);
                    735:                }
                    736:        }
                    737:        enumerator->destroy(enumerator);
                    738:        vici_end_list(req);
                    739: 
                    740:        res = vici_submit(req, ctx->conn);
                    741:        if (!res)
                    742:        {
                    743:                fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
                    744:                return FALSE;
                    745:        }
                    746:        if (ctx->format & COMMAND_FORMAT_RAW)
                    747:        {
                    748:                vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    749:                                  stdout);
                    750:        }
                    751:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    752:        {
                    753:                fprintf(stderr, "loading shared secret failed: %s\n",
                    754:                                vici_find_str(res, "", "errmsg"));
                    755:                ret = FALSE;
                    756:        }
                    757:        else
                    758:        {
                    759:                printf("loaded %s secret '%s'\n", type, section);
                    760:        }
                    761:        if (ret)
                    762:        {
                    763:                free(ctx->shared->remove(ctx->shared, section));
                    764:        }
                    765:        vici_free_res(res);
                    766:        return ret;
                    767: }
                    768: 
                    769: CALLBACK(get_id, int,
                    770:        hashtable_t *ht, vici_res_t *res, char *name, void *value, int len)
                    771: {
                    772:        if (streq(name, "keys"))
                    773:        {
                    774:                char *str;
                    775: 
                    776:                if (asprintf(&str, "%.*s", len, value) != -1)
                    777:                {
                    778:                        free(ht->put(ht, str, str));
                    779:                }
                    780:        }
                    781:        return 0;
                    782: }
                    783: 
                    784: /**
                    785:  * Get a list of currently loaded private and shared keys
                    786:  */
                    787: static void get_creds(load_ctx_t *ctx)
                    788: {
                    789:        vici_res_t *res;
                    790: 
                    791:        res = vici_submit(vici_begin("get-keys"), ctx->conn);
                    792:        if (res)
                    793:        {
                    794:                if (ctx->format & COMMAND_FORMAT_RAW)
                    795:                {
                    796:                        vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    797:                                          stdout);
                    798:                }
                    799:                vici_parse_cb(res, NULL, NULL, get_id, ctx->keys);
                    800:                vici_free_res(res);
                    801:        }
                    802:        res = vici_submit(vici_begin("get-shared"), ctx->conn);
                    803:        if (res)
                    804:        {
                    805:                if (ctx->format & COMMAND_FORMAT_RAW)
                    806:                {
                    807:                        vici_dump(res, "get-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    808:                                          stdout);
                    809:                }
                    810:                vici_parse_cb(res, NULL, NULL, get_id, ctx->shared);
                    811:                vici_free_res(res);
                    812:        }
                    813: }
                    814: 
                    815: /**
                    816:  * Remove a given key
                    817:  */
                    818: static bool unload_key(load_ctx_t *ctx, char *command, char *id)
                    819: {
                    820:        vici_req_t *req;
                    821:        vici_res_t *res;
                    822:        char buf[BUF_LEN];
                    823:        bool ret = TRUE;
                    824: 
                    825:        req = vici_begin(command);
                    826: 
                    827:        vici_add_key_valuef(req, "id", "%s", id);
                    828: 
                    829:        res = vici_submit(req, ctx->conn);
                    830:        if (!res)
                    831:        {
                    832:                fprintf(stderr, "%s request failed: %s\n", command, strerror(errno));
                    833:                return FALSE;
                    834:        }
                    835:        if (ctx->format & COMMAND_FORMAT_RAW)
                    836:        {
                    837:                snprintf(buf, sizeof(buf), "%s reply", command);
                    838:                vici_dump(res, buf, ctx->format & COMMAND_FORMAT_PRETTY, stdout);
                    839:        }
                    840:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    841:        {
                    842:                fprintf(stderr, "unloading key '%s' failed: %s\n",
                    843:                                id, vici_find_str(res, "", "errmsg"));
                    844:                ret = FALSE;
                    845:        }
                    846:        vici_free_res(res);
                    847:        return ret;
                    848: }
                    849: 
                    850: /**
                    851:  * Remove all keys in the given hashtable using the given command
                    852:  */
                    853: static void unload_keys(load_ctx_t *ctx, hashtable_t *ht, char *command)
                    854: {
                    855:        enumerator_t *enumerator;
                    856:        char *id;
                    857: 
                    858:        enumerator = ht->create_enumerator(ht);
                    859:        while (enumerator->enumerate(enumerator, &id, NULL))
                    860:        {
                    861:                unload_key(ctx, command, id);
                    862:        }
                    863:        enumerator->destroy(enumerator);
                    864: }
                    865: 
                    866: /**
                    867:  * Clear all currently loaded credentials
                    868:  */
                    869: static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
                    870: {
                    871:        vici_res_t *res;
                    872: 
                    873:        res = vici_submit(vici_begin("clear-creds"), conn);
                    874:        if (!res)
                    875:        {
                    876:                fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
                    877:                return FALSE;
                    878:        }
                    879:        if (format & COMMAND_FORMAT_RAW)
                    880:        {
                    881:                vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
                    882:                                  stdout);
                    883:        }
                    884:        vici_free_res(res);
                    885:        return TRUE;
                    886: }
                    887: 
                    888: /**
                    889:  * See header.
                    890:  */
                    891: int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
                    892:                                   settings_t *cfg, bool clear, bool noprompt)
                    893: {
                    894:        enumerator_t *enumerator;
                    895:        char *section;
                    896:        load_ctx_t ctx = {
                    897:                .conn = conn,
                    898:                .format = format,
                    899:                .noprompt = noprompt,
                    900:                .cfg = cfg,
                    901:                .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
                    902:                .shared = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
                    903:        };
                    904: 
                    905:        if (clear)
                    906:        {
                    907:                if (!clear_creds(conn, format))
                    908:                {
                    909:                        return ECONNREFUSED;
                    910:                }
                    911:        }
                    912: 
                    913:        get_creds(&ctx);
                    914: 
                    915:        load_certs(&ctx, "x509",     SWANCTL_X509DIR);
                    916:        load_certs(&ctx, "x509ca",   SWANCTL_X509CADIR);
                    917:        load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR);
                    918:        load_certs(&ctx, "x509aa",   SWANCTL_X509AADIR);
                    919:        load_certs(&ctx, "x509ac",   SWANCTL_X509ACDIR);
                    920:        load_certs(&ctx, "x509crl",  SWANCTL_X509CRLDIR);
                    921:        load_certs(&ctx, "pubkey",   SWANCTL_PUBKEYDIR);
                    922: 
                    923:        load_keys(&ctx, "private", SWANCTL_PRIVATEDIR);
                    924:        load_keys(&ctx, "rsa",     SWANCTL_RSADIR);
                    925:        load_keys(&ctx, "ecdsa",   SWANCTL_ECDSADIR);
                    926:        load_keys(&ctx, "bliss",   SWANCTL_BLISSDIR);
                    927:        load_keys(&ctx, "pkcs8",   SWANCTL_PKCS8DIR);
                    928: 
                    929:        load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR);
                    930: 
                    931:        load_tokens(&ctx);
                    932: 
                    933:        enumerator = cfg->create_section_enumerator(cfg, "secrets");
                    934:        while (enumerator->enumerate(enumerator, &section))
                    935:        {
                    936:                load_secret(&ctx, section);
                    937:        }
                    938:        enumerator->destroy(enumerator);
                    939: 
                    940:        unload_keys(&ctx, ctx.keys, "unload-key");
                    941:        unload_keys(&ctx, ctx.shared, "unload-shared");
                    942: 
                    943:        ctx.keys->destroy_function(ctx.keys, (void*)free);
                    944:        ctx.shared->destroy_function(ctx.shared, (void*)free);
                    945:        return 0;
                    946: }
                    947: 
                    948: static int load_creds(vici_conn_t *conn)
                    949: {
                    950:        bool clear = FALSE, noprompt = FALSE;
                    951:        command_format_options_t format = COMMAND_FORMAT_NONE;
                    952:        settings_t *cfg;
                    953:        char *arg, *file = NULL;
                    954:        int ret;
                    955: 
                    956:        while (TRUE)
                    957:        {
                    958:                switch (command_getopt(&arg))
                    959:                {
                    960:                        case 'h':
                    961:                                return command_usage(NULL);
                    962:                        case 'c':
                    963:                                clear = TRUE;
                    964:                                continue;
                    965:                        case 'n':
                    966:                                noprompt = TRUE;
                    967:                                continue;
                    968:                        case 'P':
                    969:                                format |= COMMAND_FORMAT_PRETTY;
                    970:                                /* fall through to raw */
                    971:                        case 'r':
                    972:                                format |= COMMAND_FORMAT_RAW;
                    973:                                continue;
                    974:                        case 'f':
                    975:                                file = arg;
                    976:                                continue;
                    977:                        case EOF:
                    978:                                break;
                    979:                        default:
                    980:                                return command_usage("invalid --load-creds option");
                    981:                }
                    982:                break;
                    983:        }
                    984: 
                    985:        cfg = load_swanctl_conf(file);
                    986:        if (!cfg)
                    987:        {
                    988:                return EINVAL;
                    989:        }
                    990: 
                    991:        ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
                    992: 
                    993:        cfg->destroy(cfg);
                    994: 
                    995:        return ret;
                    996: }
                    997: 
                    998: /**
                    999:  * Register the command.
                   1000:  */
                   1001: static void __attribute__ ((constructor))reg()
                   1002: {
                   1003:        command_register((command_t) {
                   1004:                load_creds, 's', "load-creds", "(re-)load credentials",
                   1005:                {"[--raw|--pretty] [--clear] [--noprompt]"},
                   1006:                {
                   1007:                        {"help",                'h', 0, "show usage information"},
                   1008:                        {"clear",               'c', 0, "clear previously loaded credentials"},
                   1009:                        {"noprompt",    'n', 0, "do not prompt for passwords"},
                   1010:                        {"raw",                 'r', 0, "dump raw response message"},
                   1011:                        {"pretty",              'P', 0, "dump raw response message in pretty print"},
                   1012:                        {"file",                'f', 1, "custom path to swanctl.conf"},
                   1013:                }
                   1014:        });
                   1015: }

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