swanctl: Automatically unload removed private keys
[strongswan.git] / src / swanctl / commands / load_creds.c
1 /*
2 * Copyright (C) 2016 Tobias Brunner
3 * Copyright (C) 2015 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * Copyright (C) 2014 Martin Willi
7 * Copyright (C) 2014 revosec AG
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25
26 #include "command.h"
27 #include "swanctl.h"
28 #include "load_creds.h"
29
30 #include <credentials/sets/mem_cred.h>
31 #include <credentials/sets/callback_cred.h>
32 #include <credentials/containers/pkcs12.h>
33 #include <collections/hashtable.h>
34
35 #include <vici_cert_info.h>
36
37 #define HASH_SIZE_SHA1_HEX (2 * HASH_SIZE_SHA1)
38
39 /**
40 * Context used to track loaded secrets
41 */
42 typedef struct {
43 /** vici connection */
44 vici_conn_t *conn;
45 /** format options */
46 command_format_options_t format;
47 /** read setting */
48 settings_t *cfg;
49 /** don't prompt user for password */
50 bool noprompt;
51 /** list of key ids of loaded private keys */
52 hashtable_t *keys;
53 } load_ctx_t;
54
55 /**
56 * Load a single certificate over vici
57 */
58 static bool load_cert(load_ctx_t *ctx, char *dir, certificate_type_t type,
59 x509_flag_t flag, chunk_t data)
60 {
61 vici_req_t *req;
62 vici_res_t *res;
63 bool ret = TRUE;
64
65 req = vici_begin("load-cert");
66
67 vici_add_key_valuef(req, "type", "%N", certificate_type_names, type);
68 if (type == CERT_X509)
69 {
70 vici_add_key_valuef(req, "flag", "%N", x509_flag_names, flag);
71 }
72 vici_add_key_value(req, "data", data.ptr, data.len);
73
74 res = vici_submit(req, ctx->conn);
75 if (!res)
76 {
77 fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
78 return FALSE;
79 }
80 if (ctx->format & COMMAND_FORMAT_RAW)
81 {
82 vici_dump(res, "load-cert reply", ctx->format & COMMAND_FORMAT_PRETTY,
83 stdout);
84 }
85 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
86 {
87 fprintf(stderr, "loading '%s' failed: %s\n",
88 dir, vici_find_str(res, "", "errmsg"));
89 ret = FALSE;
90 }
91 else
92 {
93 printf("loaded certificate from '%s'\n", dir);
94 }
95 vici_free_res(res);
96 return ret;
97 }
98
99 /**
100 * Load certficiates from a directory
101 */
102 static void load_certs(load_ctx_t *ctx, char *type_str, char *dir)
103 {
104 enumerator_t *enumerator;
105 certificate_type_t type;
106 x509_flag_t flag;
107 struct stat st;
108 chunk_t *map;
109 char *path;
110
111 vici_cert_info_from_str(type_str, &type, &flag);
112
113 enumerator = enumerator_create_directory(dir);
114 if (enumerator)
115 {
116 while (enumerator->enumerate(enumerator, NULL, &path, &st))
117 {
118 if (S_ISREG(st.st_mode))
119 {
120 map = chunk_map(path, FALSE);
121 if (map)
122 {
123 load_cert(ctx, path, type, flag, *map);
124 chunk_unmap(map);
125 }
126 else
127 {
128 fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
129 path, strerror(errno));
130 }
131 }
132 }
133 enumerator->destroy(enumerator);
134 }
135 }
136
137 /**
138 * Load a single private key over vici
139 */
140 static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
141 {
142 vici_req_t *req;
143 vici_res_t *res;
144 bool ret = TRUE;
145
146 req = vici_begin("load-key");
147
148 if (streq(type, "private") ||
149 streq(type, "pkcs8"))
150 { /* as used by vici */
151 vici_add_key_valuef(req, "type", "any");
152 }
153 else
154 {
155 vici_add_key_valuef(req, "type", "%s", type);
156 }
157 vici_add_key_value(req, "data", data.ptr, data.len);
158
159 res = vici_submit(req, ctx->conn);
160 if (!res)
161 {
162 fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
163 return FALSE;
164 }
165 if (ctx->format & COMMAND_FORMAT_RAW)
166 {
167 vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY,
168 stdout);
169 }
170 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
171 {
172 fprintf(stderr, "loading '%s' failed: %s\n",
173 dir, vici_find_str(res, "", "errmsg"));
174 ret = FALSE;
175 }
176 else
177 {
178 printf("loaded %s key from '%s'\n", type, dir);
179 }
180 vici_free_res(res);
181 return ret;
182 }
183
184 /**
185 * Load a private key of any type to vici
186 */
187 static bool load_key_anytype(load_ctx_t *ctx, char *path,
188 private_key_t *private)
189 {
190 bool loaded = FALSE;
191 chunk_t encoding, keyid;
192 char hex[HASH_SIZE_SHA1_HEX + 1];
193
194 if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
195 {
196 fprintf(stderr, "encoding private key from '%s' failed\n", path);
197 return FALSE;
198 }
199 switch (private->get_type(private))
200 {
201 case KEY_RSA:
202 loaded = load_key(ctx, path, "rsa", encoding);
203 break;
204 case KEY_ECDSA:
205 loaded = load_key(ctx, path, "ecdsa", encoding);
206 break;
207 case KEY_BLISS:
208 loaded = load_key(ctx, path, "bliss", encoding);
209 break;
210 default:
211 fprintf(stderr, "unsupported key type in '%s'\n", path);
212 break;
213 }
214
215 if (loaded &&
216 private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid) &&
217 snprintf(hex, sizeof(hex), "%+B", &keyid) == HASH_SIZE_SHA1_HEX)
218 {
219 free(ctx->keys->remove(ctx->keys, hex));
220 }
221 chunk_clear(&encoding);
222 return loaded;
223 }
224
225 /**
226 * Data passed to password callback
227 */
228 typedef struct {
229 char prompt[128];
230 mem_cred_t *cache;
231 } cb_data_t;
232
233 /**
234 * Callback function to prompt for private key passwords
235 */
236 CALLBACK(password_cb, shared_key_t*,
237 cb_data_t *data, shared_key_type_t type,
238 identification_t *me, identification_t *other,
239 id_match_t *match_me, id_match_t *match_other)
240 {
241 shared_key_t *shared;
242 char *pwd = NULL;
243
244 if (type != SHARED_PRIVATE_KEY_PASS)
245 {
246 return NULL;
247 }
248 #ifdef HAVE_GETPASS
249 pwd = getpass(data->prompt);
250 #endif
251 if (!pwd || strlen(pwd) == 0)
252 {
253 return NULL;
254 }
255 if (match_me)
256 {
257 *match_me = ID_MATCH_PERFECT;
258 }
259 if (match_other)
260 {
261 *match_other = ID_MATCH_PERFECT;
262 }
263 shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
264 /* cache secret if it is required more than once (PKCS#12) */
265 data->cache->add_shared(data->cache, shared, NULL);
266 return shared->get_ref(shared);
267 }
268
269 /**
270 * Determine credential type and subtype from a type string
271 */
272 static bool determine_credtype(char *type, credential_type_t *credtype,
273 int *subtype)
274 {
275 struct {
276 char *type;
277 credential_type_t credtype;
278 int subtype;
279 } map[] = {
280 { "private", CRED_PRIVATE_KEY, KEY_ANY, },
281 { "pkcs8", CRED_PRIVATE_KEY, KEY_ANY, },
282 { "rsa", CRED_PRIVATE_KEY, KEY_RSA, },
283 { "ecdsa", CRED_PRIVATE_KEY, KEY_ECDSA, },
284 { "bliss", CRED_PRIVATE_KEY, KEY_BLISS, },
285 { "pkcs12", CRED_CONTAINER, CONTAINER_PKCS12, },
286 };
287 int i;
288
289 for (i = 0; i < countof(map); i++)
290 {
291 if (streq(map[i].type, type))
292 {
293 *credtype = map[i].credtype;
294 *subtype = map[i].subtype;
295 return TRUE;
296 }
297 }
298 return FALSE;
299 }
300
301 /**
302 * Try to parse a potentially encrypted credential using password prompt
303 */
304 static void* decrypt(char *name, char *type, chunk_t encoding)
305 {
306 credential_type_t credtype;
307 int subtype;
308 void *cred;
309 callback_cred_t *cb;
310 cb_data_t data;
311
312 if (!determine_credtype(type, &credtype, &subtype))
313 {
314 return NULL;
315 }
316
317 snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
318 type, name);
319
320 data.cache = mem_cred_create();
321 lib->credmgr->add_set(lib->credmgr, &data.cache->set);
322 cb = callback_cred_create_shared(password_cb, &data);
323 lib->credmgr->add_set(lib->credmgr, &cb->set);
324
325 cred = lib->creds->create(lib->creds, credtype, subtype,
326 BUILD_BLOB_PEM, encoding, BUILD_END);
327
328 lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
329 data.cache->destroy(data.cache);
330 lib->credmgr->remove_set(lib->credmgr, &cb->set);
331 cb->destroy(cb);
332
333 return cred;
334 }
335
336 /**
337 * Try to parse a potentially encrypted credential using configured secret
338 */
339 static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
340 chunk_t encoding)
341 {
342 credential_type_t credtype;
343 int subtype;
344 enumerator_t *enumerator, *secrets;
345 char *section, *key, *value, *file, buf[128];
346 shared_key_t *shared;
347 void *cred = NULL;
348 mem_cred_t *mem = NULL;
349
350 if (!determine_credtype(type, &credtype, &subtype))
351 {
352 return NULL;
353 }
354
355 /* load all secrets for this key type */
356 enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
357 while (enumerator->enumerate(enumerator, &section))
358 {
359 if (strpfx(section, type))
360 {
361 file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section);
362 if (file && strcaseeq(file, name))
363 {
364 snprintf(buf, sizeof(buf), "secrets.%s", section);
365 secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg, buf);
366 while (secrets->enumerate(secrets, &key, &value))
367 {
368 if (strpfx(key, "secret"))
369 {
370 if (!mem)
371 {
372 mem = mem_cred_create();
373 }
374 shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
375 chunk_clone(chunk_from_str(value)));
376 mem->add_shared(mem, shared, NULL);
377 }
378 }
379 secrets->destroy(secrets);
380 }
381 }
382 }
383 enumerator->destroy(enumerator);
384
385 if (mem)
386 {
387 lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
388
389 cred = lib->creds->create(lib->creds, credtype, subtype,
390 BUILD_BLOB_PEM, encoding, BUILD_END);
391
392 lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
393
394 if (!cred)
395 {
396 fprintf(stderr, "configured decryption secret for '%s' invalid\n",
397 name);
398 }
399
400 mem->destroy(mem);
401 }
402
403 return cred;
404 }
405
406 /**
407 * Try to decrypt and load a private key
408 */
409 static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
410 char *type, chunk_t data)
411 {
412 private_key_t *private;
413 bool loaded = FALSE;
414
415 private = decrypt_with_config(ctx, rel, type, data);
416 if (!private && !ctx->noprompt)
417 {
418 private = decrypt(rel, type, data);
419 }
420 if (private)
421 {
422 loaded = load_key_anytype(ctx, path, private);
423 private->destroy(private);
424 }
425 return loaded;
426 }
427
428 /**
429 * Load private keys from a directory
430 */
431 static void load_keys(load_ctx_t *ctx, char *type, char *dir)
432 {
433 enumerator_t *enumerator;
434 struct stat st;
435 chunk_t *map;
436 char *path, *rel;
437
438 enumerator = enumerator_create_directory(dir);
439 if (enumerator)
440 {
441 while (enumerator->enumerate(enumerator, &rel, &path, &st))
442 {
443 if (S_ISREG(st.st_mode))
444 {
445 map = chunk_map(path, FALSE);
446 if (map)
447 {
448 if (!load_encrypted_key(ctx, rel, path, type, *map))
449 {
450 load_key(ctx, path, type, *map);
451 }
452 chunk_unmap(map);
453 }
454 else
455 {
456 fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
457 path, strerror(errno));
458 }
459 }
460 }
461 enumerator->destroy(enumerator);
462 }
463 }
464
465 /**
466 * Load credentials from a PKCS#12 container over vici
467 */
468 static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12)
469 {
470 enumerator_t *enumerator;
471 certificate_t *cert;
472 private_key_t *private;
473 chunk_t encoding;
474 bool loaded = TRUE;
475
476 enumerator = p12->create_cert_enumerator(p12);
477 while (loaded && enumerator->enumerate(enumerator, &cert))
478 {
479 loaded = FALSE;
480 if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
481 {
482 loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding);
483 if (loaded)
484 {
485 fprintf(stderr, " %Y\n", cert->get_subject(cert));
486 }
487 free(encoding.ptr);
488 }
489 else
490 {
491 fprintf(stderr, "encoding certificate from '%s' failed\n", path);
492 }
493 }
494 enumerator->destroy(enumerator);
495
496 enumerator = p12->create_key_enumerator(p12);
497 while (loaded && enumerator->enumerate(enumerator, &private))
498 {
499 loaded = load_key_anytype(ctx, path, private);
500 }
501 enumerator->destroy(enumerator);
502
503 return loaded;
504 }
505
506 /**
507 * Try to decrypt and load credentials from a container
508 */
509 static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path,
510 char *type, chunk_t data)
511 {
512 container_t *container;
513 bool loaded = FALSE;
514
515 container = decrypt_with_config(ctx, rel, type, data);
516 if (!container && !ctx->noprompt)
517 {
518 container = decrypt(rel, type, data);
519 }
520 if (container)
521 {
522 switch (container->get_type(container))
523 {
524 case CONTAINER_PKCS12:
525 loaded = load_pkcs12(ctx, path, (pkcs12_t*)container);
526 break;
527 default:
528 break;
529 }
530 container->destroy(container);
531 }
532 return loaded;
533 }
534
535 /**
536 * Load credential containers from a directory
537 */
538 static void load_containers(load_ctx_t *ctx, char *type, char *dir)
539 {
540 enumerator_t *enumerator;
541 struct stat st;
542 chunk_t *map;
543 char *path, *rel;
544
545 enumerator = enumerator_create_directory(dir);
546 if (enumerator)
547 {
548 while (enumerator->enumerate(enumerator, &rel, &path, &st))
549 {
550 if (S_ISREG(st.st_mode))
551 {
552 map = chunk_map(path, FALSE);
553 if (map)
554 {
555 load_encrypted_container(ctx, rel, path, type, *map);
556 chunk_unmap(map);
557 }
558 else
559 {
560 fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
561 path, strerror(errno));
562 }
563 }
564 }
565 enumerator->destroy(enumerator);
566 }
567 }
568
569 /**
570 * Load a single secret over VICI
571 */
572 static bool load_secret(load_ctx_t *ctx, char *section)
573 {
574 enumerator_t *enumerator;
575 vici_req_t *req;
576 vici_res_t *res;
577 chunk_t data;
578 char *key, *value, buf[128], *type = NULL;
579 bool ret = TRUE;
580 int i;
581 char *types[] = {
582 "eap",
583 "xauth",
584 "ike",
585 "private",
586 "rsa",
587 "ecdsa",
588 "bliss",
589 "pkcs8",
590 "pkcs12",
591 };
592
593 for (i = 0; i < countof(types); i++)
594 {
595 if (strpfx(section, types[i]))
596 {
597 type = types[i];
598 break;
599 }
600 }
601 if (!type)
602 {
603 fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
604 return FALSE;
605 }
606 if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ike"))
607 { /* skip non-shared secrets */
608 return TRUE;
609 }
610
611 value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section);
612 if (!value)
613 {
614 fprintf(stderr, "missing secret in '%s', ignored\n", section);
615 return FALSE;
616 }
617 if (strcasepfx(value, "0x"))
618 {
619 data = chunk_from_hex(chunk_from_str(value + 2), NULL);
620 }
621 else if (strcasepfx(value, "0s"))
622 {
623 data = chunk_from_base64(chunk_from_str(value + 2), NULL);
624 }
625 else
626 {
627 data = chunk_clone(chunk_from_str(value));
628 }
629
630 req = vici_begin("load-shared");
631
632 vici_add_key_valuef(req, "type", "%s", type);
633 vici_add_key_value(req, "data", data.ptr, data.len);
634 chunk_clear(&data);
635
636 vici_begin_list(req, "owners");
637 snprintf(buf, sizeof(buf), "secrets.%s", section);
638 enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, buf);
639 while (enumerator->enumerate(enumerator, &key, &value))
640 {
641 if (strpfx(key, "id"))
642 {
643 vici_add_list_itemf(req, "%s", value);
644 }
645 }
646 enumerator->destroy(enumerator);
647 vici_end_list(req);
648
649 res = vici_submit(req, ctx->conn);
650 if (!res)
651 {
652 fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
653 return FALSE;
654 }
655 if (ctx->format & COMMAND_FORMAT_RAW)
656 {
657 vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
658 stdout);
659 }
660 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
661 {
662 fprintf(stderr, "loading shared secret failed: %s\n",
663 vici_find_str(res, "", "errmsg"));
664 ret = FALSE;
665 }
666 else
667 {
668 printf("loaded %s secret '%s'\n", type, section);
669 }
670 vici_free_res(res);
671 return ret;
672 }
673
674 CALLBACK(get_id, int,
675 hashtable_t *ht, vici_res_t *res, char *name, void *value, int len)
676 {
677 if (streq(name, "keys"))
678 {
679 char *str;
680
681 if (asprintf(&str, "%.*s", len, value) != -1)
682 {
683 free(ht->put(ht, str, str));
684 }
685 }
686 return 0;
687 }
688
689 /**
690 * Get a list of currently loaded private keys
691 */
692 static void get_keys(load_ctx_t *ctx)
693 {
694 vici_res_t *res;
695
696 res = vici_submit(vici_begin("get-keys"), ctx->conn);
697 if (res)
698 {
699 if (ctx->format & COMMAND_FORMAT_RAW)
700 {
701 vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY,
702 stdout);
703 }
704 vici_parse_cb(res, NULL, NULL, get_id, ctx->keys);
705 vici_free_res(res);
706 }
707 }
708
709 /**
710 * Remove a given key
711 */
712 static bool unload_key(load_ctx_t *ctx, char *id)
713 {
714 vici_req_t *req;
715 vici_res_t *res;
716 bool ret = TRUE;
717
718 req = vici_begin("unload-key");
719
720 vici_add_key_valuef(req, "id", "%s", id);
721
722 res = vici_submit(req, ctx->conn);
723 if (!res)
724 {
725 fprintf(stderr, "unload-key request failed: %s\n", strerror(errno));
726 return FALSE;
727 }
728 if (ctx->format & COMMAND_FORMAT_RAW)
729 {
730 vici_dump(res, "unload-key reply", ctx->format & COMMAND_FORMAT_PRETTY,
731 stdout);
732 }
733 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
734 {
735 fprintf(stderr, "unloading key '%s' failed: %s\n",
736 id, vici_find_str(res, "", "errmsg"));
737 ret = FALSE;
738 }
739 vici_free_res(res);
740 return ret;
741 }
742
743 /**
744 * Clear all currently loaded credentials
745 */
746 static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
747 {
748 vici_res_t *res;
749
750 res = vici_submit(vici_begin("clear-creds"), conn);
751 if (!res)
752 {
753 fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
754 return FALSE;
755 }
756 if (format & COMMAND_FORMAT_RAW)
757 {
758 vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
759 stdout);
760 }
761 vici_free_res(res);
762 return TRUE;
763 }
764
765 /**
766 * See header.
767 */
768 int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
769 settings_t *cfg, bool clear, bool noprompt)
770 {
771 enumerator_t *enumerator;
772 char *section, *id;
773 load_ctx_t ctx = {
774 .conn = conn,
775 .format = format,
776 .noprompt = noprompt,
777 .cfg = cfg,
778 .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
779 };
780
781 if (clear)
782 {
783 if (!clear_creds(conn, format))
784 {
785 return ECONNREFUSED;
786 }
787 }
788
789 get_keys(&ctx);
790
791 load_certs(&ctx, "x509", SWANCTL_X509DIR);
792 load_certs(&ctx, "x509ca", SWANCTL_X509CADIR);
793 load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR);
794 load_certs(&ctx, "x509aa", SWANCTL_X509AADIR);
795 load_certs(&ctx, "x509ac", SWANCTL_X509ACDIR);
796 load_certs(&ctx, "x509crl", SWANCTL_X509CRLDIR);
797 load_certs(&ctx, "pubkey", SWANCTL_PUBKEYDIR);
798
799 load_keys(&ctx, "private", SWANCTL_PRIVATEDIR);
800 load_keys(&ctx, "rsa", SWANCTL_RSADIR);
801 load_keys(&ctx, "ecdsa", SWANCTL_ECDSADIR);
802 load_keys(&ctx, "bliss", SWANCTL_BLISSDIR);
803 load_keys(&ctx, "pkcs8", SWANCTL_PKCS8DIR);
804
805 load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR);
806
807 enumerator = cfg->create_section_enumerator(cfg, "secrets");
808 while (enumerator->enumerate(enumerator, &section))
809 {
810 load_secret(&ctx, section);
811 }
812 enumerator->destroy(enumerator);
813
814 enumerator = ctx.keys->create_enumerator(ctx.keys);
815 while (enumerator->enumerate(enumerator, &id, NULL))
816 {
817 unload_key(&ctx, id);
818 }
819 enumerator->destroy(enumerator);
820 ctx.keys->destroy_function(ctx.keys, (void*)free);
821 return 0;
822 }
823
824 static int load_creds(vici_conn_t *conn)
825 {
826 bool clear = FALSE, noprompt = FALSE;
827 command_format_options_t format = COMMAND_FORMAT_NONE;
828 settings_t *cfg;
829 char *arg;
830 int ret;
831
832 while (TRUE)
833 {
834 switch (command_getopt(&arg))
835 {
836 case 'h':
837 return command_usage(NULL);
838 case 'c':
839 clear = TRUE;
840 continue;
841 case 'n':
842 noprompt = TRUE;
843 continue;
844 case 'P':
845 format |= COMMAND_FORMAT_PRETTY;
846 /* fall through to raw */
847 case 'r':
848 format |= COMMAND_FORMAT_RAW;
849 continue;
850 case EOF:
851 break;
852 default:
853 return command_usage("invalid --load-creds option");
854 }
855 break;
856 }
857
858 cfg = settings_create(SWANCTL_CONF);
859 if (!cfg)
860 {
861 fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
862 return EINVAL;
863 }
864
865 ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
866
867 cfg->destroy(cfg);
868
869 return ret;
870 }
871
872 /**
873 * Register the command.
874 */
875 static void __attribute__ ((constructor))reg()
876 {
877 command_register((command_t) {
878 load_creds, 's', "load-creds", "(re-)load credentials",
879 {"[--raw|--pretty] [--clear] [--noprompt]"},
880 {
881 {"help", 'h', 0, "show usage information"},
882 {"clear", 'c', 0, "clear previously loaded credentials"},
883 {"noprompt", 'n', 0, "do not prompt for passwords"},
884 {"raw", 'r', 0, "dump raw response message"},
885 {"pretty", 'P', 0, "dump raw response message in pretty print"},
886 }
887 });
888 }