vici: Match identity with wildcards against remote ID in redirect command
[strongswan.git] / src / swanctl / commands / load_authorities.c
1 /*
2 * Copyright (C) 2015 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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_authorities.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 * Add a vici certificate blob value given by its file patch
45 */
46 static bool add_file_key_value(vici_req_t *req, char *key, char *value)
47 {
48 chunk_t *map;
49 char *path, buf[PATH_MAX];
50
51 if (path_absolute(value))
52 {
53 path = value;
54 }
55 else
56 {
57 path = buf;
58 snprintf(path, PATH_MAX, "%s%s%s",
59 SWANCTL_X509CADIR, DIRECTORY_SEPARATOR, value);
60 }
61 map = chunk_map(path, FALSE);
62
63 if (map)
64 {
65 vici_add_key_value(req, key, map->ptr, map->len);
66 chunk_unmap(map);
67 return TRUE;
68 }
69 else
70 {
71 fprintf(stderr, "loading ca certificate '%s' failed: %s\n",
72 path, strerror(errno));
73 return FALSE;
74 }
75 }
76
77 /**
78 * Translate sletting key/values from a section into vici key-values/lists
79 */
80 static bool add_key_values(vici_req_t *req, settings_t *cfg, char *section)
81 {
82 enumerator_t *enumerator;
83 char *key, *value;
84 bool ret = TRUE;
85
86 enumerator = cfg->create_key_value_enumerator(cfg, section);
87 while (enumerator->enumerate(enumerator, &key, &value))
88 {
89 /* pool subnet is encoded as key/value, all other attributes as list */
90 if (streq(key, "cacert"))
91 {
92 ret = add_file_key_value(req, key, value);
93 }
94 else if (streq(key, "cert_uri_base"))
95 {
96 vici_add_key_valuef(req, key, "%s", value);
97 }
98 else
99 {
100 add_list_key(req, key, value);
101 }
102 if (!ret)
103 {
104 break;
105 }
106 }
107 enumerator->destroy(enumerator);
108
109 return ret;
110 }
111
112 /**
113 * Load an authority configuration
114 */
115 static bool load_authority(vici_conn_t *conn, settings_t *cfg,
116 char *section, command_format_options_t format)
117 {
118 vici_req_t *req;
119 vici_res_t *res;
120 bool ret = TRUE;
121 char buf[128];
122
123 snprintf(buf, sizeof(buf), "%s.%s", "authorities", section);
124
125 req = vici_begin("load-authority");
126
127 vici_begin_section(req, section);
128 if (!add_key_values(req, cfg, buf))
129 {
130 vici_free_req(req);
131 return FALSE;
132 }
133 vici_end_section(req);
134
135 res = vici_submit(req, conn);
136 if (!res)
137 {
138 fprintf(stderr, "load-authority request failed: %s\n", strerror(errno));
139 return FALSE;
140 }
141 if (format & COMMAND_FORMAT_RAW)
142 {
143 vici_dump(res, "load-authority reply", format & COMMAND_FORMAT_PRETTY,
144 stdout);
145 }
146 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
147 {
148 fprintf(stderr, "loading authority '%s' failed: %s\n",
149 section, vici_find_str(res, "", "errmsg"));
150 ret = FALSE;
151 }
152 else
153 {
154 printf("loaded authority '%s'\n", section);
155 }
156 vici_free_res(res);
157 return ret;
158 }
159
160 CALLBACK(list_authority, int,
161 linked_list_t *list, vici_res_t *res, char *name, void *value, int len)
162 {
163 if (streq(name, "authorities"))
164 {
165 char *str;
166
167 if (asprintf(&str, "%.*s", len, value) != -1)
168 {
169 list->insert_last(list, str);
170 }
171 }
172 return 0;
173 }
174
175 /**
176 * Create a list of currently loaded authorities
177 */
178 static linked_list_t* list_authorities(vici_conn_t *conn,
179 command_format_options_t format)
180 {
181 linked_list_t *list;
182 vici_res_t *res;
183
184 list = linked_list_create();
185
186 res = vici_submit(vici_begin("get-authorities"), conn);
187 if (res)
188 {
189 if (format & COMMAND_FORMAT_RAW)
190 {
191 vici_dump(res, "get-authorities reply", format & COMMAND_FORMAT_PRETTY,
192 stdout);
193 }
194 vici_parse_cb(res, NULL, NULL, list_authority, list);
195 vici_free_res(res);
196 }
197 return list;
198 }
199
200 /**
201 * Remove and free a string from a list
202 */
203 static void remove_from_list(linked_list_t *list, char *str)
204 {
205 enumerator_t *enumerator;
206 char *current;
207
208 enumerator = list->create_enumerator(list);
209 while (enumerator->enumerate(enumerator, &current))
210 {
211 if (streq(current, str))
212 {
213 list->remove_at(list, enumerator);
214 free(current);
215 }
216 }
217 enumerator->destroy(enumerator);
218 }
219
220 /**
221 * Unload a authority by name
222 */
223 static bool unload_authority(vici_conn_t *conn, char *name,
224 command_format_options_t format)
225 {
226 vici_req_t *req;
227 vici_res_t *res;
228 bool ret = TRUE;
229
230 req = vici_begin("unload-authority");
231 vici_add_key_valuef(req, "name", "%s", name);
232 res = vici_submit(req, conn);
233 if (!res)
234 {
235 fprintf(stderr, "unload-authority request failed: %s\n", strerror(errno));
236 return FALSE;
237 }
238 if (format & COMMAND_FORMAT_RAW)
239 {
240 vici_dump(res, "unload-authority reply", format & COMMAND_FORMAT_PRETTY,
241 stdout);
242 }
243 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
244 {
245 fprintf(stderr, "unloading authority '%s' failed: %s\n",
246 name, vici_find_str(res, "", "errmsg"));
247 ret = FALSE;
248 }
249 vici_free_res(res);
250 return ret;
251 }
252
253 /**
254 * See header.
255 */
256 int load_authorities_cfg(vici_conn_t *conn, command_format_options_t format,
257 settings_t *cfg)
258 {
259 u_int found = 0, loaded = 0, unloaded = 0;
260 char *section;
261 enumerator_t *enumerator;
262 linked_list_t *authorities;
263
264 authorities = list_authorities(conn, format);
265
266 enumerator = cfg->create_section_enumerator(cfg, "authorities");
267 while (enumerator->enumerate(enumerator, &section))
268 {
269 remove_from_list(authorities, section);
270 found++;
271 if (load_authority(conn, cfg, section, format))
272 {
273 loaded++;
274 }
275 }
276 enumerator->destroy(enumerator);
277
278 /* unload all authorities in daemon, but not in file */
279 while (authorities->remove_first(authorities, (void**)&section) == SUCCESS)
280 {
281 if (unload_authority(conn, section, format))
282 {
283 unloaded++;
284 }
285 free(section);
286 }
287 authorities->destroy(authorities);
288
289 if (format & COMMAND_FORMAT_RAW)
290 {
291 return 0;
292 }
293 if (found == 0)
294 {
295 printf("no authorities found, %u unloaded\n", unloaded);
296 return 0;
297 }
298 if (loaded == found)
299 {
300 printf("successfully loaded %u authorities, %u unloaded\n",
301 loaded, unloaded);
302 return 0;
303 }
304 fprintf(stderr, "loaded %u of %u authorities, %u failed to load, "
305 "%u unloaded\n", loaded, found, found - loaded, unloaded);
306 return EINVAL;
307 }
308
309 static int load_authorities(vici_conn_t *conn)
310 {
311 command_format_options_t format = COMMAND_FORMAT_NONE;
312 settings_t *cfg;
313 char *arg;
314 int ret;
315
316 while (TRUE)
317 {
318 switch (command_getopt(&arg))
319 {
320 case 'h':
321 return command_usage(NULL);
322 case 'P':
323 format |= COMMAND_FORMAT_PRETTY;
324 /* fall through to raw */
325 case 'r':
326 format |= COMMAND_FORMAT_RAW;
327 continue;
328 case EOF:
329 break;
330 default:
331 return command_usage("invalid --load-authorities option");
332 }
333 break;
334 }
335
336 cfg = settings_create(SWANCTL_CONF);
337 if (!cfg)
338 {
339 fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
340 return EINVAL;
341 }
342
343 ret = load_authorities_cfg(conn, format, cfg);
344
345 cfg->destroy(cfg);
346
347 return ret;
348 }
349
350 /**
351 * Register the command.
352 */
353 static void __attribute__ ((constructor))reg()
354 {
355 command_register((command_t) {
356 load_authorities, 'b',
357 "load-authorities", "(re-)load authority configuration",
358 {"[--raw|--pretty]"},
359 {
360 {"help", 'h', 0, "show usage information"},
361 {"raw", 'r', 0, "dump raw response message"},
362 {"pretty", 'P', 0, "dump raw response message in pretty print"},
363 }
364 });
365 }