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

1.1       misho       1: /*
                      2:  * Copyright (C) 2014 Martin Willi
                      3:  * Copyright (C) 2014 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #define _GNU_SOURCE
                     17: #include <stdio.h>
                     18: #include <errno.h>
                     19: #include <limits.h>
                     20: 
                     21: #include "command.h"
                     22: #include "swanctl.h"
                     23: #include "load_conns.h"
                     24: 
                     25: /**
                     26:  * Check if we should handle a key as a list of comma separated values
                     27:  */
                     28: static bool is_list_key(char *key)
                     29: {
                     30:        char *keys[] = {
                     31:                "local_addrs",
                     32:                "remote_addrs",
                     33:                "proposals",
                     34:                "esp_proposals",
                     35:                "ah_proposals",
                     36:                "local_ts",
                     37:                "remote_ts",
                     38:                "vips",
                     39:                "pools",
                     40:                "groups",
                     41:                "cert_policy",
                     42:        };
                     43:        int i;
                     44: 
                     45:        for (i = 0; i < countof(keys); i++)
                     46:        {
                     47:                if (strcaseeq(keys[i], key))
                     48:                {
                     49:                        return TRUE;
                     50:                }
                     51:        }
                     52:        return FALSE;
                     53: }
                     54: 
                     55: /**
                     56:  * Check if we should handle a key as a list of comma separated files
                     57:  */
                     58: static bool is_file_list_key(char *key)
                     59: {
                     60:        char *keys[] = {
                     61:                "certs",
                     62:                "cacerts",
                     63:                "pubkeys"
                     64:        };
                     65:        int i;
                     66: 
                     67:        for (i = 0; i < countof(keys); i++)
                     68:        {
                     69:                if (strcaseeq(keys[i], key))
                     70:                {
                     71:                        return TRUE;
                     72:                }
                     73:        }
                     74:        return FALSE;
                     75: }
                     76: 
                     77: /**
                     78:  * Add a vici list from a comma separated string value
                     79:  */
                     80: static void add_list_key(vici_req_t *req, char *key, char *value)
                     81: {
                     82:        enumerator_t *enumerator;
                     83:        char *token;
                     84: 
                     85:        vici_begin_list(req, key);
                     86:        enumerator = enumerator_create_token(value, ",", " ");
                     87:        while (enumerator->enumerate(enumerator, &token))
                     88:        {
                     89:                vici_add_list_itemf(req, "%s", token);
                     90:        }
                     91:        enumerator->destroy(enumerator);
                     92:        vici_end_list(req);
                     93: }
                     94: 
                     95: /**
                     96:  * Add a vici list of blobs from a comma separated file list
                     97:  */
                     98: static bool add_file_list_key(vici_req_t *req, char *key, char *value)
                     99: {
                    100:        enumerator_t *enumerator;
                    101:        chunk_t *map, blob;
                    102:        char *token, buf[PATH_MAX];
                    103:        bool ret = TRUE;
                    104: 
                    105:        vici_begin_list(req, key);
                    106:        enumerator = enumerator_create_token(value, ",", " ");
                    107:        while (enumerator->enumerate(enumerator, &token))
                    108:        {
                    109:                if (strcasepfx(token, "0x") || strcasepfx(token, "0s"))
                    110:                {
                    111:                        blob = chunk_from_str(token + 2);
                    112:                        blob = strcasepfx(token, "0x") ? chunk_from_hex(blob, NULL)
                    113:                                                                                   : chunk_from_base64(blob, NULL);
                    114:                        vici_add_list_item(req, blob.ptr, blob.len);
                    115:                        chunk_free(&blob);
                    116:                }
                    117:                else
                    118:                {
                    119:                        if (!path_absolute(token))
                    120:                        {
                    121:                                if (streq(key, "certs"))
                    122:                                {
                    123:                                        snprintf(buf, sizeof(buf), "%s%s%s%s%s", swanctl_dir,
                    124:                                                         DIRECTORY_SEPARATOR, SWANCTL_X509DIR,
                    125:                                                         DIRECTORY_SEPARATOR, token);
                    126:                                        token = buf;
                    127:                                }
                    128:                                else if (streq(key, "cacerts"))
                    129:                                {
                    130:                                        snprintf(buf, sizeof(buf), "%s%s%s%s%s", swanctl_dir,
                    131:                                                         DIRECTORY_SEPARATOR, SWANCTL_X509CADIR,
                    132:                                                         DIRECTORY_SEPARATOR, token);
                    133:                                        token = buf;
                    134:                                }
                    135:                                else if (streq(key, "pubkeys"))
                    136:                                {
                    137:                                        snprintf(buf, sizeof(buf), "%s%s%s%s%s", swanctl_dir,
                    138:                                                         DIRECTORY_SEPARATOR, SWANCTL_PUBKEYDIR,
                    139:                                                         DIRECTORY_SEPARATOR, token);
                    140:                                        token = buf;
                    141:                                }
                    142:                        }
                    143:                        map = chunk_map(token, FALSE);
                    144:                        if (map)
                    145:                        {
                    146:                                vici_add_list_item(req, map->ptr, map->len);
                    147:                                chunk_unmap(map);
                    148:                        }
                    149:                        else
                    150:                        {
                    151:                                fprintf(stderr, "loading %s certificate '%s' failed: %s\n",
                    152:                                                key, token, strerror(errno));
                    153:                                ret = FALSE;
                    154:                                break;
                    155:                        }
                    156:                }
                    157:        }
                    158:        enumerator->destroy(enumerator);
                    159:        vici_end_list(req);
                    160: 
                    161:        return ret;
                    162: }
                    163: 
                    164: /**
                    165:  * Translate setting key/values from a section into vici key-values/lists
                    166:  */
                    167: static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section)
                    168: {
                    169:        enumerator_t *enumerator;
                    170:        char *key, *value;
                    171:        bool ret = TRUE;
                    172: 
                    173:        enumerator = cfg->create_key_value_enumerator(cfg, section);
                    174:        while (enumerator->enumerate(enumerator, &key, &value))
                    175:        {
                    176:                if (is_list_key(key))
                    177:                {
                    178:                        add_list_key(req, key, value);
                    179:                }
                    180:                else if (is_file_list_key(key))
                    181:                {
                    182:                        ret = add_file_list_key(req, key, value);
                    183:                }
                    184:                else
                    185:                {
                    186:                        vici_add_key_valuef(req, key, "%s", value);
                    187:                }
                    188:                if (!ret)
                    189:                {
                    190:                        break;
                    191:                }
                    192:        }
                    193:        enumerator->destroy(enumerator);
                    194: 
                    195:        return ret;
                    196: }
                    197: 
                    198: /**
                    199:  * Translate a settings section to a vici section
                    200:  */
                    201: static bool add_sections(vici_req_t *req, settings_t *cfg, char *section)
                    202: {
                    203:        enumerator_t *enumerator;
                    204:        char *name, buf[256];
                    205:        bool ret = TRUE;
                    206: 
                    207:        enumerator = cfg->create_section_enumerator(cfg, section);
                    208:        while (enumerator->enumerate(enumerator, &name))
                    209:        {
                    210:                vici_begin_section(req, name);
                    211:                snprintf(buf, sizeof(buf), "%s.%s", section, name);
                    212:                ret = add_key_values(req, cfg, buf);
                    213:                if (!ret)
                    214:                {
                    215:                        break;
                    216:                }
                    217:                ret = add_sections(req, cfg, buf);
                    218:                if (!ret)
                    219:                {
                    220:                        break;
                    221:                }
                    222:                vici_end_section(req);
                    223:        }
                    224:        enumerator->destroy(enumerator);
                    225: 
                    226:        return ret;
                    227: }
                    228: 
                    229: /**
                    230:  * Load an IKE_SA config with CHILD_SA configs from a section
                    231:  */
                    232: static bool load_conn(vici_conn_t *conn, settings_t *cfg,
                    233:                                          char *section, command_format_options_t format)
                    234: {
                    235:        vici_req_t *req;
                    236:        vici_res_t *res;
                    237:        bool ret = TRUE;
                    238:        char buf[BUF_LEN];
                    239: 
                    240:        snprintf(buf, sizeof(buf), "%s.%s", "connections", section);
                    241: 
                    242:        req = vici_begin("load-conn");
                    243: 
                    244:        vici_begin_section(req, section);
                    245:        if (!add_key_values(req, cfg, buf) ||
                    246:                !add_sections(req, cfg, buf))
                    247:        {
                    248:                vici_free_req(req);
                    249:                return FALSE;
                    250:        }
                    251:        vici_end_section(req);
                    252: 
                    253:        res = vici_submit(req, conn);
                    254:        if (!res)
                    255:        {
                    256:                fprintf(stderr, "load-conn request failed: %s\n", strerror(errno));
                    257:                return FALSE;
                    258:        }
                    259:        if (format & COMMAND_FORMAT_RAW)
                    260:        {
                    261:                vici_dump(res, "load-conn reply", format & COMMAND_FORMAT_PRETTY,
                    262:                                  stdout);
                    263:        }
                    264:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    265:        {
                    266:                fprintf(stderr, "loading connection '%s' failed: %s\n",
                    267:                                section, vici_find_str(res, "", "errmsg"));
                    268:                ret = FALSE;
                    269:        }
                    270:        else
                    271:        {
                    272:                printf("loaded connection '%s'\n", section);
                    273:        }
                    274:        vici_free_res(res);
                    275:        return ret;
                    276: }
                    277: 
                    278: CALLBACK(list_conn, int,
                    279:        linked_list_t *list, vici_res_t *res, char *name, void *value, int len)
                    280: {
                    281:        if (streq(name, "conns"))
                    282:        {
                    283:                char *str;
                    284: 
                    285:                if (asprintf(&str, "%.*s", len, value) != -1)
                    286:                {
                    287:                        list->insert_last(list, str);
                    288:                }
                    289:        }
                    290:        return 0;
                    291: }
                    292: 
                    293: /**
                    294:  * Create a list of currently loaded connections
                    295:  */
                    296: static linked_list_t* list_conns(vici_conn_t *conn,
                    297:                                                                 command_format_options_t format)
                    298: {
                    299:        linked_list_t *list;
                    300:        vici_res_t *res;
                    301: 
                    302:        list = linked_list_create();
                    303: 
                    304:        res = vici_submit(vici_begin("get-conns"), conn);
                    305:        if (res)
                    306:        {
                    307:                if (format & COMMAND_FORMAT_RAW)
                    308:                {
                    309:                        vici_dump(res, "get-conns reply", format & COMMAND_FORMAT_PRETTY,
                    310:                                          stdout);
                    311:                }
                    312:                vici_parse_cb(res, NULL, NULL, list_conn, list);
                    313:                vici_free_res(res);
                    314:        }
                    315:        return list;
                    316: }
                    317: 
                    318: /**
                    319:  * Remove and free a string from a list
                    320:  */
                    321: static void remove_from_list(linked_list_t *list, char *str)
                    322: {
                    323:        enumerator_t *enumerator;
                    324:        char *current;
                    325: 
                    326:        enumerator = list->create_enumerator(list);
                    327:        while (enumerator->enumerate(enumerator, &current))
                    328:        {
                    329:                if (streq(current, str))
                    330:                {
                    331:                        list->remove_at(list, enumerator);
                    332:                        free(current);
                    333:                }
                    334:        }
                    335:        enumerator->destroy(enumerator);
                    336: }
                    337: 
                    338: /**
                    339:  * Unload a connection by name
                    340:  */
                    341: static bool unload_conn(vici_conn_t *conn, char *name,
                    342:                                            command_format_options_t format)
                    343: {
                    344:        vici_req_t *req;
                    345:        vici_res_t *res;
                    346:        bool ret = TRUE;
                    347: 
                    348:        req = vici_begin("unload-conn");
                    349:        vici_add_key_valuef(req, "name", "%s", name);
                    350:        res = vici_submit(req, conn);
                    351:        if (!res)
                    352:        {
                    353:                fprintf(stderr, "unload-conn request failed: %s\n", strerror(errno));
                    354:                return FALSE;
                    355:        }
                    356:        if (format & COMMAND_FORMAT_RAW)
                    357:        {
                    358:                vici_dump(res, "unload-conn reply", format & COMMAND_FORMAT_PRETTY,
                    359:                                  stdout);
                    360:        }
                    361:        else if (!streq(vici_find_str(res, "no", "success"), "yes"))
                    362:        {
                    363:                fprintf(stderr, "unloading connection '%s' failed: %s\n",
                    364:                                name, vici_find_str(res, "", "errmsg"));
                    365:                ret = FALSE;
                    366:        }
                    367:        vici_free_res(res);
                    368:        return ret;
                    369: }
                    370: 
                    371: /**
                    372:  * See header.
                    373:  */
                    374: int load_conns_cfg(vici_conn_t *conn, command_format_options_t format,
                    375:                                   settings_t *cfg)
                    376: {
                    377:        u_int found = 0, loaded = 0, unloaded = 0;
                    378:        char *section;
                    379:        enumerator_t *enumerator;
                    380:        linked_list_t *conns;
                    381: 
                    382:        conns = list_conns(conn, format);
                    383: 
                    384:        enumerator = cfg->create_section_enumerator(cfg, "connections");
                    385:        while (enumerator->enumerate(enumerator, &section))
                    386:        {
                    387:                remove_from_list(conns, section);
                    388:                found++;
                    389:                if (load_conn(conn, cfg, section, format))
                    390:                {
                    391:                        loaded++;
                    392:                }
                    393:        }
                    394:        enumerator->destroy(enumerator);
                    395: 
                    396:        /* unload all connection in daemon, but not in file */
                    397:        while (conns->remove_first(conns, (void**)&section) == SUCCESS)
                    398:        {
                    399:                if (unload_conn(conn, section, format))
                    400:                {
                    401:                        unloaded++;
                    402:                }
                    403:                free(section);
                    404:        }
                    405:        conns->destroy(conns);
                    406: 
                    407:        if (format & COMMAND_FORMAT_RAW)
                    408:        {
                    409:                return 0;
                    410:        }
                    411:        if (found == 0)
                    412:        {
                    413:                fprintf(stderr, "no connections found, %u unloaded\n", unloaded);
                    414:                return 0;
                    415:        }
                    416:        if (loaded == found)
                    417:        {
                    418:                printf("successfully loaded %u connections, %u unloaded\n",
                    419:                           loaded, unloaded);
                    420:                return 0;
                    421:        }
                    422:        fprintf(stderr, "loaded %u of %u connections, %u failed to load, "
                    423:                        "%u unloaded\n", loaded, found, found - loaded, unloaded);
                    424:        return EINVAL;
                    425: }
                    426: 
                    427: static int load_conns(vici_conn_t *conn)
                    428: {
                    429:        command_format_options_t format = COMMAND_FORMAT_NONE;
                    430:        settings_t *cfg;
                    431:        char *arg, *file = NULL;
                    432:        int ret;
                    433: 
                    434:        while (TRUE)
                    435:        {
                    436:                switch (command_getopt(&arg))
                    437:                {
                    438:                        case 'h':
                    439:                                return command_usage(NULL);
                    440:                        case 'P':
                    441:                                format |= COMMAND_FORMAT_PRETTY;
                    442:                                /* fall through to raw */
                    443:                        case 'r':
                    444:                                format |= COMMAND_FORMAT_RAW;
                    445:                                continue;
                    446:                        case 'f':
                    447:                                file = arg;
                    448:                                continue;
                    449:                        case EOF:
                    450:                                break;
                    451:                        default:
                    452:                                return command_usage("invalid --load-conns option");
                    453:                }
                    454:                break;
                    455:        }
                    456: 
                    457:        cfg = load_swanctl_conf(file);
                    458:        if (!cfg)
                    459:        {
                    460:                return EINVAL;
                    461:        }
                    462: 
                    463:        ret = load_conns_cfg(conn, format, cfg);
                    464: 
                    465:        cfg->destroy(cfg);
                    466: 
                    467:        return ret;
                    468: }
                    469: 
                    470: /**
                    471:  * Register the command.
                    472:  */
                    473: static void __attribute__ ((constructor))reg()
                    474: {
                    475:        command_register((command_t) {
                    476:                load_conns, 'c', "load-conns", "(re-)load connection configuration",
                    477:                {"[--raw|--pretty]"},
                    478:                {
                    479:                        {"help",                'h', 0, "show usage information"},
                    480:                        {"raw",                 'r', 0, "dump raw response message"},
                    481:                        {"pretty",              'P', 0, "dump raw response message in pretty print"},
                    482:                        {"file",                'f', 1, "custom path to swanctl.conf"},
                    483:                }
                    484:        });
                    485: }

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