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, ¤t))
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, §ion))
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**)§ion) == 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>