Annotation of embedaddon/strongswan/src/swanctl/commands/load_conns.c, revision 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>