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

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;
                    198: 
                    199:        if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
                    200:        {
                    201:                fprintf(stderr, "encoding private key from '%s' failed\n", path);
                    202:                return FALSE;
                    203:        }
                    204:        switch (private->get_type(private))
                    205:        {
                    206:                case KEY_RSA:
                    207:                        loaded = load_key(ctx, path, "rsa", encoding);
                    208:                        break;
                    209:                case KEY_ECDSA:
                    210:                        loaded = load_key(ctx, path, "ecdsa", encoding);
                    211:                        break;
                    212:                case KEY_BLISS:
                    213:                        loaded = load_key(ctx, path, "bliss", encoding);
                    214:                        break;
                    215:                default:
                    216:                        fprintf(stderr, "unsupported key type in '%s'\n", path);
                    217:                        break;
                    218:        }
                    219:        chunk_clear(&encoding);
                    220:        return loaded;
                    221: }
                    222: 
                    223: /**
                    224:  * Data passed to password callback
                    225:  */
                    226: typedef struct {
                    227:        char prompt[128];
                    228:        mem_cred_t *cache;
                    229: } cb_data_t;
                    230: 
                    231: /**
                    232:  * Callback function to prompt for private key passwords
                    233:  */
                    234: CALLBACK(password_cb, shared_key_t*,
                    235:        cb_data_t *data, shared_key_type_t type,
                    236:        identification_t *me, identification_t *other,
                    237:        id_match_t *match_me, id_match_t *match_other)
                    238: {
                    239:        shared_key_t *shared;
                    240:        char *pwd = NULL;
                    241: 
                    242:        if (type != SHARED_PRIVATE_KEY_PASS)
                    243:        {
                    244:                return NULL;
                    245:        }
                    246: #ifdef HAVE_GETPASS
                    247:        pwd = getpass(data->prompt);
                    248: #endif
                    249:        if (!pwd || strlen(pwd) == 0)
                    250:        {
                    251:                return NULL;
                    252:        }
                    253:        if (match_me)
                    254:        {
                    255:                *match_me = ID_MATCH_PERFECT;
                    256:        }
                    257:        if (match_other)
                    258:        {
                    259:                *match_other = ID_MATCH_PERFECT;
                    260:        }
                    261:        shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
                    262:        /* cache secret if it is required more than once (PKCS#12) */
                    263:        data->cache->add_shared(data->cache, shared, NULL);
                    264:        return shared->get_ref(shared);
                    265: }
                    266: 
                    267: /**
                    268:  * Determine credential type and subtype from a type string
                    269:  */
                    270: static bool determine_credtype(char *type, credential_type_t *credtype,
                    271:                                                           int *subtype)
                    272: {
                    273:        struct {
                    274:                char *type;
                    275:                credential_type_t credtype;
                    276:                int subtype;
                    277:        } map[] = {
                    278:                { "private",            CRED_PRIVATE_KEY,               KEY_ANY,                        },
                    279:                { "pkcs8",                      CRED_PRIVATE_KEY,               KEY_ANY,                        },
                    280:                { "rsa",                        CRED_PRIVATE_KEY,               KEY_RSA,                        },
                    281:                { "ecdsa",                      CRED_PRIVATE_KEY,               KEY_ECDSA,                      },
                    282:                { "bliss",                      CRED_PRIVATE_KEY,               KEY_BLISS,                      },
                    283:                { "pkcs12",                     CRED_CONTAINER,                 CONTAINER_PKCS12,       },
                    284:        };
                    285:        int i;
                    286: 
                    287:        for (i = 0; i < countof(map); i++)
                    288:        {
                    289:                if (streq(map[i].type, type))
                    290:                {
                    291:                        *credtype = map[i].credtype;
                    292:                        *subtype = map[i].subtype;
                    293:                        return TRUE;
                    294:                }
                    295:        }
                    296:        return FALSE;
                    297: }
                    298: 
                    299: /**
                    300:  * Try to parse a potentially encrypted credential using password prompt
                    301:  */
                    302: static void* decrypt(char *name, char *type, chunk_t encoding)
                    303: {
                    304:        credential_type_t credtype;
                    305:        int subtype;
                    306:        void *cred;
                    307:        callback_cred_t *cb;
                    308:        cb_data_t data;
                    309: 
                    310:        if (!determine_credtype(type, &credtype, &subtype))
                    311:        {
                    312:                return NULL;
                    313:        }
                    314: 
                    315:        snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
                    316:                         type, name);
                    317: 
                    318:        data.cache = mem_cred_create();
                    319:        lib->credmgr->add_set(lib->credmgr, &data.cache->set);
                    320:        cb = callback_cred_create_shared(password_cb, &data);
                    321:        lib->credmgr->add_set(lib->credmgr, &cb->set);
                    322: 
                    323:        cred = lib->creds->create(lib->creds, credtype, subtype,
                    324:                                                          BUILD_BLOB_PEM, encoding, BUILD_END);
                    325: 
                    326:        lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
                    327:        data.cache->destroy(data.cache);
                    328:        lib->credmgr->remove_set(lib->credmgr, &cb->set);
                    329:        cb->destroy(cb);
                    330: 
                    331:        return cred;
                    332: }
                    333: 
                    334: /**
                    335:  * Try to parse a potentially encrypted credential using configured secret
                    336:  */
                    337: static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
                    338:                                                                 chunk_t encoding)
                    339: {
                    340:        credential_type_t credtype;
                    341:        int subtype;
                    342:        enumerator_t *enumerator, *secrets;
                    343:        char *section, *key, *value, *file;
                    344:        shared_key_t *shared;
                    345:        void *cred = NULL;
                    346:        mem_cred_t *mem = NULL;
                    347: 
                    348:        if (!determine_credtype(type, &credtype, &subtype))
                    349:        {
                    350:                return NULL;
                    351:        }
                    352: 
                    353:        /* load all secrets for this key type */
                    354:        enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
                    355:        while (enumerator->enumerate(enumerator, &section))
                    356:        {
                    357:                if (strpfx(section, type))
                    358:                {
                    359:                        file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section);
                    360:                        if (file && strcaseeq(file, name))
                    361:                        {
                    362:                                secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg,
                    363:                                                                                                                "secrets.%s", section);
                    364:                                while (secrets->enumerate(secrets, &key, &value))
                    365:                                {
                    366:                                        if (strpfx(key, "secret"))
                    367:                                        {
                    368:                                                if (!mem)
                    369:                                                {
                    370:                                                        mem = mem_cred_create();
                    371:                                                }
                    372:                                                shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
                    373:                                                                                        chunk_clone(chunk_from_str(value)));
                    374:                                                mem->add_shared(mem, shared, NULL);
                    375:                                        }
                    376:                                }
                    377:                                secrets->destroy(secrets);
                    378:                        }
                    379:                }
                    380:        }
                    381:        enumerator->destroy(enumerator);
                    382: 
                    383:        if (mem)
                    384:        {
                    385:                lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
                    386: 
                    387:                cred = lib->creds->create(lib->creds, credtype, subtype,
                    388:                                                                  BUILD_BLOB_PEM, encoding, BUILD_END);
                    389: 
                    390:                lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
                    391: 
                    392:                if (!cred)
                    393:                {
                    394:                        fprintf(stderr, "configured decryption secret for '%s' invalid\n",
                    395:                                        name);
                    396:                }
                    397: 
                    398:                mem->destroy(mem);
                    399:        }
                    400: 
                    401:        return cred;
                    402: }
                    403: 
                    404: /**
                    405:  * Try to decrypt and load a private key
                    406:  */
                    407: static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
                    408:                                                           char *type, chunk_t data)
                    409: {
                    410:        private_key_t *private;
                    411:        bool loaded = FALSE;
                    412: 
                    413:        private = decrypt_with_config(ctx, rel, type, data);
                    414:        if (!private && !ctx->noprompt)
                    415:        {
                    416:                private = decrypt(rel, type, data);
                    417:        }
                    418:        if (private)
                    419:        {
                    420:                loaded = load_key_anytype(ctx, path, private);
                    421:                private->destroy(private);
                    422:        }
                    423:        return loaded;
                    424: }
                    425: 
                    426: /**
                    427:  * Load private keys from a directory
                    428:  */
                    429: static void load_keys(load_ctx_t *ctx, char *type, char *dir)
                    430: {
                    431:        enumerator_t *enumerator;
                    432:        struct stat st;
                    433:        chunk_t *map;
                    434:        char *path, *rel, buf[PATH_MAX];
                    435: 
                    436:        snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
                    437:        dir = buf;
                    438: 
                    439:        enumerator = enumerator_create_directory(dir);
                    440:        if (enumerator)
                    441:        {
                    442:                while (enumerator->enumerate(enumerator, &rel, &path, &st))
                    443:                {
                    444:                        if (S_ISREG(st.st_mode))
                    445:                        {
                    446:                                map = chunk_map(path, FALSE);
                    447:                                if (map)
                    448:                                {
                    449:                                        if (!load_encrypted_key(ctx, rel, path, type, *map))
                    450:                                        {
                    451:                                                load_key(ctx, path, type, *map);
                    452:                                        }
                    453:                                        chunk_unmap(map);
                    454:                                }
                    455:                                else
                    456:                                {
                    457:                                        fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
                    458:                                                        path, strerror(errno));
                    459:                                }
                    460:                        }
                    461:                }
                    462:                enumerator->destroy(enumerator);
                    463:        }
                    464: }
                    465: 
                    466: /**
                    467:  * Load credentials from a PKCS#12 container over vici
                    468:  */
                    469: static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12)
                    470: {
                    471:        enumerator_t *enumerator;
                    472:        certificate_t *cert;
                    473:        private_key_t *private;
                    474:        chunk_t encoding;
                    475:        bool loaded = TRUE;
                    476: 
                    477:        enumerator = p12->create_cert_enumerator(p12);
                    478:        while (loaded && enumerator->enumerate(enumerator, &cert))
                    479:        {
                    480:                loaded = FALSE;
                    481:                if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
                    482:                {
                    483:                        loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding);
                    484:                        if (loaded)
                    485:                        {
                    486:                                fprintf(stderr, "  %Y\n", cert->get_subject(cert));
                    487:                        }
                    488:                        free(encoding.ptr);
                    489:                }
                    490:                else
                    491:                {
                    492:                        fprintf(stderr, "encoding certificate from '%s' failed\n", path);
                    493:                }
                    494:        }
                    495:        enumerator->destroy(enumerator);
                    496: 
                    497:        enumerator = p12->create_key_enumerator(p12);
                    498:        while (loaded && enumerator->enumerate(enumerator, &private))
                    499:        {
                    500:                loaded = load_key_anytype(ctx, path, private);
                    501:        }
                    502:        enumerator->destroy(enumerator);
                    503: 
                    504:        return loaded;
                    505: }
                    506: 
                    507: /**
                    508:  * Try to decrypt and load credentials from a container
                    509:  */
                    510: static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path,
                    511:                                                                         char *type, chunk_t data)
                    512: {
                    513:        container_t *container;
                    514:        bool loaded = FALSE;
                    515: 
                    516:        container = decrypt_with_config(ctx, rel, type, data);
                    517:        if (!container && !ctx->noprompt)
                    518:        {
                    519:                container = decrypt(rel, type, data);
                    520:        }
                    521:        if (container)
                    522:        {
                    523:                switch (container->get_type(container))
                    524:                {
                    525:                        case CONTAINER_PKCS12:
                    526:                                loaded = load_pkcs12(ctx, path, (pkcs12_t*)container);
                    527:                                break;
                    528:                        default:
                    529:                                break;
                    530:                }
                    531:                container->destroy(container);
                    532:        }
                    533:        return loaded;
                    534: }
                    535: 
                    536: /**
                    537:  * Load credential containers from a directory
                    538:  */
                    539: static void load_containers(load_ctx_t *ctx, char *type, char *dir)
                    540: {
                    541:        enumerator_t *enumerator;
                    542:        struct stat st;
                    543:        chunk_t *map;
                    544:        char *path, *rel, buf[PATH_MAX];
                    545: 
                    546:        snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
                    547:        dir = buf;
                    548: 
                    549:        enumerator = enumerator_create_directory(dir);
                    550:        if (enumerator)
                    551:        {
                    552:                while (enumerator->enumerate(enumerator, &rel, &path, &st))
                    553:                {
                    554:                        if (S_ISREG(st.st_mode))
                    555:                        {
                    556:                                map = chunk_map(path, FALSE);
                    557:                                if (map)
                    558:                                {
                    559:                                        load_encrypted_container(ctx, rel, path, type, *map);
                    560:                                        chunk_unmap(map);
                    561:                                }
                    562:                                else
                    563:                                {
                    564:                                        fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
                    565:                                                        path, strerror(errno));
                    566:                                }
                    567:                        }
                    568:                }
                    569:                enumerator->destroy(enumerator);
                    570:        }
                    571: }
                    572: 
                    573: /**
                    574:  * Load a single private key on a token over vici
                    575:  */
                    576: static bool load_token(load_ctx_t *ctx, char *name, char *pin)
                    577: {
                    578:        vici_req_t *req;
                    579:        vici_res_t *res;
                    580:        enumerator_t *enumerator;
                    581:        char *key, *value, *id;
                    582:        bool ret = TRUE;
                    583: 
                    584:        req = vici_begin("load-token");
                    585: 
                    586:        enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
                    587:                                                                                                           name);
                    588:        while (enumerator->enumerate(enumerator, &key, &value))
                    589:        {
                    590:                vici_add_key_valuef(req, key, "%s", value);
                    591:        }
                    592:        enumerator->destroy(enumerator);
                    593: 
                    594:        if (pin)
                    595:        {
                    596:                vici_add_key_valuef(req, "pin", "%s", pin);
                    597:        }
                    598:        res = vici_submit(req, ctx->conn);
                    599:        if (!res)
                    600:        {
                    601:                fprintf(stderr, "load-token request failed: %s\n", strerror(errno));
                    602:                return FALSE;
                    603:        }
                    604:        if (ctx->format & COMMAND_FORMAT_RAW)
                    605:        {
                    606:                vici_dump(res, "load-token reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    607:                                  stdout);
                    608:        }
                    609:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    610:        {
                    611:                fprintf(stderr, "loading '%s' failed: %s\n",
                    612:                                name, vici_find_str(res, "", "errmsg"));
                    613:                ret = FALSE;
                    614:        }
                    615:        else
                    616:        {
                    617:                id = vici_find_str(res, "", "id");
                    618:                printf("loaded key %s from token [keyid: %s]\n", name, id);
                    619:                free(ctx->keys->remove(ctx->keys, id));
                    620:        }
                    621:        vici_free_res(res);
                    622:        return ret;
                    623: }
                    624: 
                    625: /**
                    626:  * Load keys from tokens
                    627:  */
                    628: static void load_tokens(load_ctx_t *ctx)
                    629: {
                    630:        enumerator_t *enumerator;
                    631:        char *section, *pin = NULL, prompt[128];
                    632: 
                    633:        enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
                    634:        while (enumerator->enumerate(enumerator, &section))
                    635:        {
                    636:                if (strpfx(section, "token"))
                    637:                {
                    638:                        if (!ctx->noprompt &&
                    639:                                !ctx->cfg->get_str(ctx->cfg, "secrets.%s.pin", NULL, section))
                    640:                        {
                    641: #ifdef HAVE_GETPASS
                    642:                                snprintf(prompt, sizeof(prompt), "PIN for %s: ", section);
                    643:                                pin = strdupnull(getpass(prompt));
                    644: #endif
                    645:                        }
                    646:                        load_token(ctx, section, pin);
                    647:                        if (pin)
                    648:                        {
                    649:                                memwipe(pin, strlen(pin));
                    650:                                free(pin);
                    651:                                pin = NULL;
                    652:                        }
                    653:                }
                    654:        }
                    655:        enumerator->destroy(enumerator);
                    656: }
                    657: 
                    658: 
                    659: 
                    660: /**
                    661:  * Load a single secret over VICI
                    662:  */
                    663: static bool load_secret(load_ctx_t *ctx, char *section)
                    664: {
                    665:        enumerator_t *enumerator;
                    666:        vici_req_t *req;
                    667:        vici_res_t *res;
                    668:        chunk_t data;
                    669:        char *key, *value, *type = NULL;
                    670:        bool ret = TRUE;
                    671:        int i;
                    672:        char *types[] = {
                    673:                "eap",
                    674:                "xauth",
                    675:                "ntlm",
                    676:                "ike",
                    677:                "ppk",
                    678:                "private",
                    679:                "rsa",
                    680:                "ecdsa",
                    681:                "bliss",
                    682:                "pkcs8",
                    683:                "pkcs12",
                    684:                "token",
                    685:        };
                    686: 
                    687:        for (i = 0; i < countof(types); i++)
                    688:        {
                    689:                if (strpfx(section, types[i]))
                    690:                {
                    691:                        type = types[i];
                    692:                        break;
                    693:                }
                    694:        }
                    695:        if (!type)
                    696:        {
                    697:                fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
                    698:                return FALSE;
                    699:        }
                    700:        if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ntlm") &&
                    701:                !streq(type, "ike") && !streq(type, "ppk"))
                    702:        {       /* skip non-shared secrets */
                    703:                return TRUE;
                    704:        }
                    705: 
                    706:        value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section);
                    707:        if (!value)
                    708:        {
                    709:                fprintf(stderr, "missing secret in '%s', ignored\n", section);
                    710:                return FALSE;
                    711:        }
                    712:        if (strcasepfx(value, "0x"))
                    713:        {
                    714:                data = chunk_from_hex(chunk_from_str(value + 2), NULL);
                    715:        }
                    716:        else if (strcasepfx(value, "0s"))
                    717:        {
                    718:                data = chunk_from_base64(chunk_from_str(value + 2), NULL);
                    719:        }
                    720:        else
                    721:        {
                    722:                data = chunk_clone(chunk_from_str(value));
                    723:        }
                    724: 
                    725:        req = vici_begin("load-shared");
                    726: 
                    727:        vici_add_key_valuef(req, "id", "%s", section);
                    728:        vici_add_key_valuef(req, "type", "%s", type);
                    729:        vici_add_key_value(req, "data", data.ptr, data.len);
                    730:        chunk_clear(&data);
                    731: 
                    732:        vici_begin_list(req, "owners");
                    733:        enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
                    734:                                                                                                           section);
                    735:        while (enumerator->enumerate(enumerator, &key, &value))
                    736:        {
                    737:                if (strpfx(key, "id"))
                    738:                {
                    739:                        vici_add_list_itemf(req, "%s", value);
                    740:                }
                    741:        }
                    742:        enumerator->destroy(enumerator);
                    743:        vici_end_list(req);
                    744: 
                    745:        res = vici_submit(req, ctx->conn);
                    746:        if (!res)
                    747:        {
                    748:                fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
                    749:                return FALSE;
                    750:        }
                    751:        if (ctx->format & COMMAND_FORMAT_RAW)
                    752:        {
                    753:                vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    754:                                  stdout);
                    755:        }
                    756:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    757:        {
                    758:                fprintf(stderr, "loading shared secret failed: %s\n",
                    759:                                vici_find_str(res, "", "errmsg"));
                    760:                ret = FALSE;
                    761:        }
                    762:        else
                    763:        {
                    764:                printf("loaded %s secret '%s'\n", type, section);
                    765:        }
                    766:        if (ret)
                    767:        {
                    768:                free(ctx->shared->remove(ctx->shared, section));
                    769:        }
                    770:        vici_free_res(res);
                    771:        return ret;
                    772: }
                    773: 
                    774: CALLBACK(get_id, int,
                    775:        hashtable_t *ht, vici_res_t *res, char *name, void *value, int len)
                    776: {
                    777:        if (streq(name, "keys"))
                    778:        {
                    779:                char *str;
                    780: 
                    781:                if (asprintf(&str, "%.*s", len, value) != -1)
                    782:                {
                    783:                        free(ht->put(ht, str, str));
                    784:                }
                    785:        }
                    786:        return 0;
                    787: }
                    788: 
                    789: /**
                    790:  * Get a list of currently loaded private and shared keys
                    791:  */
                    792: static void get_creds(load_ctx_t *ctx)
                    793: {
                    794:        vici_res_t *res;
                    795: 
                    796:        res = vici_submit(vici_begin("get-keys"), ctx->conn);
                    797:        if (res)
                    798:        {
                    799:                if (ctx->format & COMMAND_FORMAT_RAW)
                    800:                {
                    801:                        vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    802:                                          stdout);
                    803:                }
                    804:                vici_parse_cb(res, NULL, NULL, get_id, ctx->keys);
                    805:                vici_free_res(res);
                    806:        }
                    807:        res = vici_submit(vici_begin("get-shared"), ctx->conn);
                    808:        if (res)
                    809:        {
                    810:                if (ctx->format & COMMAND_FORMAT_RAW)
                    811:                {
                    812:                        vici_dump(res, "get-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
                    813:                                          stdout);
                    814:                }
                    815:                vici_parse_cb(res, NULL, NULL, get_id, ctx->shared);
                    816:                vici_free_res(res);
                    817:        }
                    818: }
                    819: 
                    820: /**
                    821:  * Remove a given key
                    822:  */
                    823: static bool unload_key(load_ctx_t *ctx, char *command, char *id)
                    824: {
                    825:        vici_req_t *req;
                    826:        vici_res_t *res;
                    827:        char buf[BUF_LEN];
                    828:        bool ret = TRUE;
                    829: 
                    830:        req = vici_begin(command);
                    831: 
                    832:        vici_add_key_valuef(req, "id", "%s", id);
                    833: 
                    834:        res = vici_submit(req, ctx->conn);
                    835:        if (!res)
                    836:        {
                    837:                fprintf(stderr, "%s request failed: %s\n", command, strerror(errno));
                    838:                return FALSE;
                    839:        }
                    840:        if (ctx->format & COMMAND_FORMAT_RAW)
                    841:        {
                    842:                snprintf(buf, sizeof(buf), "%s reply", command);
                    843:                vici_dump(res, buf, ctx->format & COMMAND_FORMAT_PRETTY, stdout);
                    844:        }
                    845:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    846:        {
                    847:                fprintf(stderr, "unloading key '%s' failed: %s\n",
                    848:                                id, vici_find_str(res, "", "errmsg"));
                    849:                ret = FALSE;
                    850:        }
                    851:        vici_free_res(res);
                    852:        return ret;
                    853: }
                    854: 
                    855: /**
                    856:  * Remove all keys in the given hashtable using the given command
                    857:  */
                    858: static void unload_keys(load_ctx_t *ctx, hashtable_t *ht, char *command)
                    859: {
                    860:        enumerator_t *enumerator;
                    861:        char *id;
                    862: 
                    863:        enumerator = ht->create_enumerator(ht);
                    864:        while (enumerator->enumerate(enumerator, &id, NULL))
                    865:        {
                    866:                unload_key(ctx, command, id);
                    867:        }
                    868:        enumerator->destroy(enumerator);
                    869: }
                    870: 
                    871: /**
                    872:  * Clear all currently loaded credentials
                    873:  */
                    874: static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
                    875: {
                    876:        vici_res_t *res;
                    877: 
                    878:        res = vici_submit(vici_begin("clear-creds"), conn);
                    879:        if (!res)
                    880:        {
                    881:                fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
                    882:                return FALSE;
                    883:        }
                    884:        if (format & COMMAND_FORMAT_RAW)
                    885:        {
                    886:                vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
                    887:                                  stdout);
                    888:        }
                    889:        vici_free_res(res);
                    890:        return TRUE;
                    891: }
                    892: 
                    893: /**
                    894:  * See header.
                    895:  */
                    896: int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
                    897:                                   settings_t *cfg, bool clear, bool noprompt)
                    898: {
                    899:        enumerator_t *enumerator;
                    900:        char *section;
                    901:        load_ctx_t ctx = {
                    902:                .conn = conn,
                    903:                .format = format,
                    904:                .noprompt = noprompt,
                    905:                .cfg = cfg,
                    906:                .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
                    907:                .shared = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
                    908:        };
                    909: 
                    910:        if (clear)
                    911:        {
                    912:                if (!clear_creds(conn, format))
                    913:                {
                    914:                        return ECONNREFUSED;
                    915:                }
                    916:        }
                    917: 
                    918:        get_creds(&ctx);
                    919: 
                    920:        load_certs(&ctx, "x509",     SWANCTL_X509DIR);
                    921:        load_certs(&ctx, "x509ca",   SWANCTL_X509CADIR);
                    922:        load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR);
                    923:        load_certs(&ctx, "x509aa",   SWANCTL_X509AADIR);
                    924:        load_certs(&ctx, "x509ac",   SWANCTL_X509ACDIR);
                    925:        load_certs(&ctx, "x509crl",  SWANCTL_X509CRLDIR);
                    926:        load_certs(&ctx, "pubkey",   SWANCTL_PUBKEYDIR);
                    927: 
                    928:        load_keys(&ctx, "private", SWANCTL_PRIVATEDIR);
                    929:        load_keys(&ctx, "rsa",     SWANCTL_RSADIR);
                    930:        load_keys(&ctx, "ecdsa",   SWANCTL_ECDSADIR);
                    931:        load_keys(&ctx, "bliss",   SWANCTL_BLISSDIR);
                    932:        load_keys(&ctx, "pkcs8",   SWANCTL_PKCS8DIR);
                    933: 
                    934:        load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR);
                    935: 
                    936:        load_tokens(&ctx);
                    937: 
                    938:        enumerator = cfg->create_section_enumerator(cfg, "secrets");
                    939:        while (enumerator->enumerate(enumerator, &section))
                    940:        {
                    941:                load_secret(&ctx, section);
                    942:        }
                    943:        enumerator->destroy(enumerator);
                    944: 
                    945:        unload_keys(&ctx, ctx.keys, "unload-key");
                    946:        unload_keys(&ctx, ctx.shared, "unload-shared");
                    947: 
                    948:        ctx.keys->destroy_function(ctx.keys, (void*)free);
                    949:        ctx.shared->destroy_function(ctx.shared, (void*)free);
                    950:        return 0;
                    951: }
                    952: 
                    953: static int load_creds(vici_conn_t *conn)
                    954: {
                    955:        bool clear = FALSE, noprompt = FALSE;
                    956:        command_format_options_t format = COMMAND_FORMAT_NONE;
                    957:        settings_t *cfg;
                    958:        char *arg, *file = NULL;
                    959:        int ret;
                    960: 
                    961:        while (TRUE)
                    962:        {
                    963:                switch (command_getopt(&arg))
                    964:                {
                    965:                        case 'h':
                    966:                                return command_usage(NULL);
                    967:                        case 'c':
                    968:                                clear = TRUE;
                    969:                                continue;
                    970:                        case 'n':
                    971:                                noprompt = TRUE;
                    972:                                continue;
                    973:                        case 'P':
                    974:                                format |= COMMAND_FORMAT_PRETTY;
                    975:                                /* fall through to raw */
                    976:                        case 'r':
                    977:                                format |= COMMAND_FORMAT_RAW;
                    978:                                continue;
                    979:                        case 'f':
                    980:                                file = arg;
                    981:                                continue;
                    982:                        case EOF:
                    983:                                break;
                    984:                        default:
                    985:                                return command_usage("invalid --load-creds option");
                    986:                }
                    987:                break;
                    988:        }
                    989: 
                    990:        cfg = load_swanctl_conf(file);
                    991:        if (!cfg)
                    992:        {
                    993:                return EINVAL;
                    994:        }
                    995: 
                    996:        ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
                    997: 
                    998:        cfg->destroy(cfg);
                    999: 
                   1000:        return ret;
                   1001: }
                   1002: 
                   1003: /**
                   1004:  * Register the command.
                   1005:  */
                   1006: static void __attribute__ ((constructor))reg()
                   1007: {
                   1008:        command_register((command_t) {
                   1009:                load_creds, 's', "load-creds", "(re-)load credentials",
                   1010:                {"[--raw|--pretty] [--clear] [--noprompt]"},
                   1011:                {
                   1012:                        {"help",                'h', 0, "show usage information"},
                   1013:                        {"clear",               'c', 0, "clear previously loaded credentials"},
                   1014:                        {"noprompt",    'n', 0, "do not prompt for passwords"},
                   1015:                        {"raw",                 'r', 0, "dump raw response message"},
                   1016:                        {"pretty",              'P', 0, "dump raw response message in pretty print"},
                   1017:                        {"file",                'f', 1, "custom path to swanctl.conf"},
                   1018:                }
                   1019:        });
                   1020: }

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