vici: Match identity with wildcards against remote ID in redirect command
[strongswan.git] / src / swanctl / commands / load_pools.c
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_pools.h"
24
25 /**
26 * Add a vici list from a comma separated string value
27 */
28 static void add_list_key(vici_req_t *req, char *key, char *value)
29 {
30 enumerator_t *enumerator;
31 char *token;
32
33 vici_begin_list(req, key);
34 enumerator = enumerator_create_token(value, ",", " ");
35 while (enumerator->enumerate(enumerator, &token))
36 {
37 vici_add_list_itemf(req, "%s", token);
38 }
39 enumerator->destroy(enumerator);
40 vici_end_list(req);
41 }
42
43 /**
44 * Translate setting key/values from a section into vici key-values/lists
45 */
46 static void add_key_values(vici_req_t *req, settings_t *cfg, char *section)
47 {
48 enumerator_t *enumerator;
49 char *key, *value;
50
51 enumerator = cfg->create_key_value_enumerator(cfg, section);
52 while (enumerator->enumerate(enumerator, &key, &value))
53 {
54 /* pool subnet is encoded as key/value, all other attributes as list */
55 if (streq(key, "addrs"))
56 {
57 vici_add_key_valuef(req, key, "%s", value);
58 }
59 else
60 {
61 add_list_key(req, key, value);
62 }
63 }
64 enumerator->destroy(enumerator);
65 }
66
67 /**
68 * Load a pool configuration
69 */
70 static bool load_pool(vici_conn_t *conn, settings_t *cfg,
71 char *section, command_format_options_t format)
72 {
73 vici_req_t *req;
74 vici_res_t *res;
75 bool ret = TRUE;
76 char buf[128];
77
78 snprintf(buf, sizeof(buf), "%s.%s", "pools", section);
79
80 req = vici_begin("load-pool");
81
82 vici_begin_section(req, section);
83 add_key_values(req, cfg, buf);
84 vici_end_section(req);
85
86 res = vici_submit(req, conn);
87 if (!res)
88 {
89 fprintf(stderr, "load-pool request failed: %s\n", strerror(errno));
90 return FALSE;
91 }
92 if (format & COMMAND_FORMAT_RAW)
93 {
94 vici_dump(res, "load-pool reply", format & COMMAND_FORMAT_PRETTY,
95 stdout);
96 }
97 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
98 {
99 fprintf(stderr, "loading pool '%s' failed: %s\n",
100 section, vici_find_str(res, "", "errmsg"));
101 ret = FALSE;
102 }
103 else
104 {
105 printf("loaded pool '%s'\n", section);
106 }
107 vici_free_res(res);
108 return ret;
109 }
110
111 CALLBACK(list_pool, int,
112 linked_list_t *list, vici_res_t *res, char *name)
113 {
114 list->insert_last(list, strdup(name));
115 return 0;
116 }
117
118 /**
119 * Create a list of currently loaded pools
120 */
121 static linked_list_t* list_pools(vici_conn_t *conn,
122 command_format_options_t format)
123 {
124 linked_list_t *list;
125 vici_res_t *res;
126
127 list = linked_list_create();
128
129 res = vici_submit(vici_begin("get-pools"), conn);
130 if (res)
131 {
132 if (format & COMMAND_FORMAT_RAW)
133 {
134 vici_dump(res, "get-pools reply", format & COMMAND_FORMAT_PRETTY,
135 stdout);
136 }
137 vici_parse_cb(res, list_pool, NULL, NULL, list);
138 vici_free_res(res);
139 }
140 return list;
141 }
142
143 /**
144 * Remove and free a string from a list
145 */
146 static void remove_from_list(linked_list_t *list, char *str)
147 {
148 enumerator_t *enumerator;
149 char *current;
150
151 enumerator = list->create_enumerator(list);
152 while (enumerator->enumerate(enumerator, &current))
153 {
154 if (streq(current, str))
155 {
156 list->remove_at(list, enumerator);
157 free(current);
158 }
159 }
160 enumerator->destroy(enumerator);
161 }
162
163 /**
164 * Unload a pool by name
165 */
166 static bool unload_pool(vici_conn_t *conn, char *name,
167 command_format_options_t format)
168 {
169 vici_req_t *req;
170 vici_res_t *res;
171 bool ret = TRUE;
172
173 req = vici_begin("unload-pool");
174 vici_add_key_valuef(req, "name", "%s", name);
175 res = vici_submit(req, conn);
176 if (!res)
177 {
178 fprintf(stderr, "unload-pool request failed: %s\n", strerror(errno));
179 return FALSE;
180 }
181 if (format & COMMAND_FORMAT_RAW)
182 {
183 vici_dump(res, "unload-pool reply", format & COMMAND_FORMAT_PRETTY,
184 stdout);
185 }
186 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
187 {
188 fprintf(stderr, "unloading pool '%s' failed: %s\n",
189 name, vici_find_str(res, "", "errmsg"));
190 ret = FALSE;
191 }
192 vici_free_res(res);
193 return ret;
194 }
195
196 /**
197 * See header.
198 */
199 int load_pools_cfg(vici_conn_t *conn, command_format_options_t format,
200 settings_t *cfg)
201 {
202 u_int found = 0, loaded = 0, unloaded = 0;
203 char *section;
204 enumerator_t *enumerator;
205 linked_list_t *pools;
206
207 pools = list_pools(conn, format);
208
209 enumerator = cfg->create_section_enumerator(cfg, "pools");
210 while (enumerator->enumerate(enumerator, &section))
211 {
212 remove_from_list(pools, section);
213 found++;
214 if (load_pool(conn, cfg, section, format))
215 {
216 loaded++;
217 }
218 }
219 enumerator->destroy(enumerator);
220
221 /* unload all pools in daemon, but not in file */
222 while (pools->remove_first(pools, (void**)&section) == SUCCESS)
223 {
224 if (unload_pool(conn, section, format))
225 {
226 unloaded++;
227 }
228 free(section);
229 }
230 pools->destroy(pools);
231
232 if (format & COMMAND_FORMAT_RAW)
233 {
234 return 0;
235 }
236 if (found == 0)
237 {
238 printf("no pools found, %u unloaded\n", unloaded);
239 return 0;
240 }
241 if (loaded == found)
242 {
243 printf("successfully loaded %u pools, %u unloaded\n",
244 loaded, unloaded);
245 return 0;
246 }
247 fprintf(stderr, "loaded %u of %u pools, %u failed to load, "
248 "%u unloaded\n", loaded, found, found - loaded, unloaded);
249 return EINVAL;
250 }
251
252 static int load_pools(vici_conn_t *conn)
253 {
254 command_format_options_t format = COMMAND_FORMAT_NONE;
255 settings_t *cfg;
256 char *arg;
257 int ret;
258
259 while (TRUE)
260 {
261 switch (command_getopt(&arg))
262 {
263 case 'h':
264 return command_usage(NULL);
265 case 'P':
266 format |= COMMAND_FORMAT_PRETTY;
267 /* fall through to raw */
268 case 'r':
269 format |= COMMAND_FORMAT_RAW;
270 continue;
271 case EOF:
272 break;
273 default:
274 return command_usage("invalid --load-pools option");
275 }
276 break;
277 }
278
279 cfg = settings_create(SWANCTL_CONF);
280 if (!cfg)
281 {
282 fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
283 return EINVAL;
284 }
285
286 ret = load_pools_cfg(conn, format, cfg);
287
288 cfg->destroy(cfg);
289
290 return ret;
291 }
292
293 /**
294 * Register the command.
295 */
296 static void __attribute__ ((constructor))reg()
297 {
298 command_register((command_t) {
299 load_pools, 'a', "load-pools", "(re-)load pool configuration",
300 {"[--raw|--pretty]"},
301 {
302 {"help", 'h', 0, "show usage information"},
303 {"raw", 'r', 0, "dump raw response message"},
304 {"pretty", 'P', 0, "dump raw response message in pretty print"},
305 }
306 });
307 }