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