Annotation of embedaddon/strongswan/src/swanctl/commands/load_creds.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2016-2017 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: /**
38: * Context used to track loaded secrets
39: */
40: typedef struct {
41: /** vici connection */
42: vici_conn_t *conn;
43: /** format options */
44: command_format_options_t format;
45: /** read setting */
46: settings_t *cfg;
47: /** don't prompt user for password */
48: bool noprompt;
49: /** list of key ids of loaded private keys */
50: hashtable_t *keys;
51: /** list of unique ids of loaded shared keys */
52: hashtable_t *shared;
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 certificates 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, buf[PATH_MAX];
110:
111: vici_cert_info_from_str(type_str, &type, &flag);
112:
113: snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
114: dir = buf;
115:
116: enumerator = enumerator_create_directory(dir);
117: if (enumerator)
118: {
119: while (enumerator->enumerate(enumerator, NULL, &path, &st))
120: {
121: if (S_ISREG(st.st_mode))
122: {
123: map = chunk_map(path, FALSE);
124: if (map)
125: {
126: load_cert(ctx, path, type, flag, *map);
127: chunk_unmap(map);
128: }
129: else
130: {
131: fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
132: path, strerror(errno));
133: }
134: }
135: }
136: enumerator->destroy(enumerator);
137: }
138: }
139:
140: /**
141: * Load a single private key over vici
142: */
143: static bool load_key(load_ctx_t *ctx, char *dir, char *type, chunk_t data)
144: {
145: vici_req_t *req;
146: vici_res_t *res;
147: bool ret = TRUE;
148: char *id;
149:
150: req = vici_begin("load-key");
151:
152: if (streq(type, "private") ||
153: streq(type, "pkcs8"))
154: { /* as used by vici */
155: vici_add_key_valuef(req, "type", "any");
156: }
157: else
158: {
159: vici_add_key_valuef(req, "type", "%s", type);
160: }
161: vici_add_key_value(req, "data", data.ptr, data.len);
162:
163: res = vici_submit(req, ctx->conn);
164: if (!res)
165: {
166: fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
167: return FALSE;
168: }
169: if (ctx->format & COMMAND_FORMAT_RAW)
170: {
171: vici_dump(res, "load-key reply", ctx->format & COMMAND_FORMAT_PRETTY,
172: stdout);
173: }
174: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
175: {
176: fprintf(stderr, "loading '%s' failed: %s\n",
177: dir, vici_find_str(res, "", "errmsg"));
178: ret = FALSE;
179: }
180: else
181: {
182: printf("loaded %s key from '%s'\n", type, dir);
183: id = vici_find_str(res, "", "id");
184: free(ctx->keys->remove(ctx->keys, id));
185: }
186: vici_free_res(res);
187: return ret;
188: }
189:
190: /**
191: * Load a private key of any type to vici
192: */
193: static bool load_key_anytype(load_ctx_t *ctx, char *path,
194: private_key_t *private)
195: {
196: bool loaded = FALSE;
197: chunk_t encoding;
1.1.1.2 ! misho 198: char *type;
1.1 misho 199:
200: if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
201: {
202: fprintf(stderr, "encoding private key from '%s' failed\n", path);
203: return FALSE;
204: }
1.1.1.2 ! misho 205: type = enum_to_name(key_type_names, private->get_type(private));
! 206: if (type)
1.1 misho 207: {
1.1.1.2 ! misho 208: loaded = load_key(ctx, path, type, encoding);
! 209: }
! 210: if (!loaded)
! 211: {
! 212: fprintf(stderr, "unsupported key type in '%s'\n", path);
1.1 misho 213: }
214: chunk_clear(&encoding);
215: return loaded;
216: }
217:
218: /**
219: * Data passed to password callback
220: */
221: typedef struct {
222: char prompt[128];
223: mem_cred_t *cache;
224: } cb_data_t;
225:
226: /**
227: * Callback function to prompt for private key passwords
228: */
229: CALLBACK(password_cb, shared_key_t*,
230: cb_data_t *data, shared_key_type_t type,
231: identification_t *me, identification_t *other,
232: id_match_t *match_me, id_match_t *match_other)
233: {
234: shared_key_t *shared;
235: char *pwd = NULL;
236:
237: if (type != SHARED_PRIVATE_KEY_PASS)
238: {
239: return NULL;
240: }
241: #ifdef HAVE_GETPASS
242: pwd = getpass(data->prompt);
243: #endif
244: if (!pwd || strlen(pwd) == 0)
245: {
246: return NULL;
247: }
248: if (match_me)
249: {
250: *match_me = ID_MATCH_PERFECT;
251: }
252: if (match_other)
253: {
254: *match_other = ID_MATCH_PERFECT;
255: }
256: shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
257: /* cache secret if it is required more than once (PKCS#12) */
258: data->cache->add_shared(data->cache, shared, NULL);
259: return shared->get_ref(shared);
260: }
261:
262: /**
263: * Determine credential type and subtype from a type string
264: */
265: static bool determine_credtype(char *type, credential_type_t *credtype,
266: int *subtype)
267: {
268: struct {
269: char *type;
270: credential_type_t credtype;
271: int subtype;
272: } map[] = {
273: { "private", CRED_PRIVATE_KEY, KEY_ANY, },
274: { "pkcs8", CRED_PRIVATE_KEY, KEY_ANY, },
275: { "rsa", CRED_PRIVATE_KEY, KEY_RSA, },
276: { "ecdsa", CRED_PRIVATE_KEY, KEY_ECDSA, },
277: { "bliss", CRED_PRIVATE_KEY, KEY_BLISS, },
278: { "pkcs12", CRED_CONTAINER, CONTAINER_PKCS12, },
279: };
280: int i;
281:
282: for (i = 0; i < countof(map); i++)
283: {
284: if (streq(map[i].type, type))
285: {
286: *credtype = map[i].credtype;
287: *subtype = map[i].subtype;
288: return TRUE;
289: }
290: }
291: return FALSE;
292: }
293:
294: /**
295: * Try to parse a potentially encrypted credential using password prompt
296: */
297: static void* decrypt(char *name, char *type, chunk_t encoding)
298: {
299: credential_type_t credtype;
300: int subtype;
301: void *cred;
302: callback_cred_t *cb;
303: cb_data_t data;
304:
305: if (!determine_credtype(type, &credtype, &subtype))
306: {
307: return NULL;
308: }
309:
310: snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
311: type, name);
312:
313: data.cache = mem_cred_create();
314: lib->credmgr->add_set(lib->credmgr, &data.cache->set);
315: cb = callback_cred_create_shared(password_cb, &data);
316: lib->credmgr->add_set(lib->credmgr, &cb->set);
317:
318: cred = lib->creds->create(lib->creds, credtype, subtype,
319: BUILD_BLOB_PEM, encoding, BUILD_END);
320:
321: lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
322: data.cache->destroy(data.cache);
323: lib->credmgr->remove_set(lib->credmgr, &cb->set);
324: cb->destroy(cb);
325:
326: return cred;
327: }
328:
329: /**
330: * Try to parse a potentially encrypted credential using configured secret
331: */
332: static void* decrypt_with_config(load_ctx_t *ctx, char *name, char *type,
333: chunk_t encoding)
334: {
335: credential_type_t credtype;
336: int subtype;
337: enumerator_t *enumerator, *secrets;
338: char *section, *key, *value, *file;
339: shared_key_t *shared;
340: void *cred = NULL;
341: mem_cred_t *mem = NULL;
342:
343: if (!determine_credtype(type, &credtype, &subtype))
344: {
345: return NULL;
346: }
347:
348: /* load all secrets for this key type */
349: enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
350: while (enumerator->enumerate(enumerator, §ion))
351: {
352: if (strpfx(section, type))
353: {
354: file = ctx->cfg->get_str(ctx->cfg, "secrets.%s.file", NULL, section);
355: if (file && strcaseeq(file, name))
356: {
357: secrets = ctx->cfg->create_key_value_enumerator(ctx->cfg,
358: "secrets.%s", section);
359: while (secrets->enumerate(secrets, &key, &value))
360: {
361: if (strpfx(key, "secret"))
362: {
363: if (!mem)
364: {
365: mem = mem_cred_create();
366: }
367: shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
368: chunk_clone(chunk_from_str(value)));
369: mem->add_shared(mem, shared, NULL);
370: }
371: }
372: secrets->destroy(secrets);
373: }
374: }
375: }
376: enumerator->destroy(enumerator);
377:
378: if (mem)
379: {
380: lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
381:
382: cred = lib->creds->create(lib->creds, credtype, subtype,
383: BUILD_BLOB_PEM, encoding, BUILD_END);
384:
385: lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
386:
387: if (!cred)
388: {
389: fprintf(stderr, "configured decryption secret for '%s' invalid\n",
390: name);
391: }
392:
393: mem->destroy(mem);
394: }
395:
396: return cred;
397: }
398:
399: /**
400: * Try to decrypt and load a private key
401: */
402: static bool load_encrypted_key(load_ctx_t *ctx, char *rel, char *path,
403: char *type, chunk_t data)
404: {
405: private_key_t *private;
406: bool loaded = FALSE;
407:
408: private = decrypt_with_config(ctx, rel, type, data);
409: if (!private && !ctx->noprompt)
410: {
411: private = decrypt(rel, type, data);
412: }
413: if (private)
414: {
415: loaded = load_key_anytype(ctx, path, private);
416: private->destroy(private);
417: }
418: return loaded;
419: }
420:
421: /**
422: * Load private keys from a directory
423: */
424: static void load_keys(load_ctx_t *ctx, char *type, char *dir)
425: {
426: enumerator_t *enumerator;
427: struct stat st;
428: chunk_t *map;
429: char *path, *rel, buf[PATH_MAX];
430:
431: snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
432: dir = buf;
433:
434: enumerator = enumerator_create_directory(dir);
435: if (enumerator)
436: {
437: while (enumerator->enumerate(enumerator, &rel, &path, &st))
438: {
439: if (S_ISREG(st.st_mode))
440: {
441: map = chunk_map(path, FALSE);
442: if (map)
443: {
444: if (!load_encrypted_key(ctx, rel, path, type, *map))
445: {
446: load_key(ctx, path, type, *map);
447: }
448: chunk_unmap(map);
449: }
450: else
451: {
452: fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
453: path, strerror(errno));
454: }
455: }
456: }
457: enumerator->destroy(enumerator);
458: }
459: }
460:
461: /**
462: * Load credentials from a PKCS#12 container over vici
463: */
464: static bool load_pkcs12(load_ctx_t *ctx, char *path, pkcs12_t *p12)
465: {
466: enumerator_t *enumerator;
467: certificate_t *cert;
468: private_key_t *private;
469: chunk_t encoding;
470: bool loaded = TRUE;
471:
472: enumerator = p12->create_cert_enumerator(p12);
473: while (loaded && enumerator->enumerate(enumerator, &cert))
474: {
475: loaded = FALSE;
476: if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
477: {
478: loaded = load_cert(ctx, path, CERT_X509, X509_NONE, encoding);
479: if (loaded)
480: {
481: fprintf(stderr, " %Y\n", cert->get_subject(cert));
482: }
483: free(encoding.ptr);
484: }
485: else
486: {
487: fprintf(stderr, "encoding certificate from '%s' failed\n", path);
488: }
489: }
490: enumerator->destroy(enumerator);
491:
492: enumerator = p12->create_key_enumerator(p12);
493: while (loaded && enumerator->enumerate(enumerator, &private))
494: {
495: loaded = load_key_anytype(ctx, path, private);
496: }
497: enumerator->destroy(enumerator);
498:
499: return loaded;
500: }
501:
502: /**
503: * Try to decrypt and load credentials from a container
504: */
505: static bool load_encrypted_container(load_ctx_t *ctx, char *rel, char *path,
506: char *type, chunk_t data)
507: {
508: container_t *container;
509: bool loaded = FALSE;
510:
511: container = decrypt_with_config(ctx, rel, type, data);
512: if (!container && !ctx->noprompt)
513: {
514: container = decrypt(rel, type, data);
515: }
516: if (container)
517: {
518: switch (container->get_type(container))
519: {
520: case CONTAINER_PKCS12:
521: loaded = load_pkcs12(ctx, path, (pkcs12_t*)container);
522: break;
523: default:
524: break;
525: }
526: container->destroy(container);
527: }
528: return loaded;
529: }
530:
531: /**
532: * Load credential containers from a directory
533: */
534: static void load_containers(load_ctx_t *ctx, char *type, char *dir)
535: {
536: enumerator_t *enumerator;
537: struct stat st;
538: chunk_t *map;
539: char *path, *rel, buf[PATH_MAX];
540:
541: snprintf(buf, sizeof(buf), "%s%s%s", swanctl_dir, DIRECTORY_SEPARATOR, dir);
542: dir = buf;
543:
544: enumerator = enumerator_create_directory(dir);
545: if (enumerator)
546: {
547: while (enumerator->enumerate(enumerator, &rel, &path, &st))
548: {
549: if (S_ISREG(st.st_mode))
550: {
551: map = chunk_map(path, FALSE);
552: if (map)
553: {
554: load_encrypted_container(ctx, rel, path, type, *map);
555: chunk_unmap(map);
556: }
557: else
558: {
559: fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
560: path, strerror(errno));
561: }
562: }
563: }
564: enumerator->destroy(enumerator);
565: }
566: }
567:
568: /**
569: * Load a single private key on a token over vici
570: */
571: static bool load_token(load_ctx_t *ctx, char *name, char *pin)
572: {
573: vici_req_t *req;
574: vici_res_t *res;
575: enumerator_t *enumerator;
576: char *key, *value, *id;
577: bool ret = TRUE;
578:
579: req = vici_begin("load-token");
580:
581: enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
582: name);
583: while (enumerator->enumerate(enumerator, &key, &value))
584: {
585: vici_add_key_valuef(req, key, "%s", value);
586: }
587: enumerator->destroy(enumerator);
588:
589: if (pin)
590: {
591: vici_add_key_valuef(req, "pin", "%s", pin);
592: }
593: res = vici_submit(req, ctx->conn);
594: if (!res)
595: {
596: fprintf(stderr, "load-token request failed: %s\n", strerror(errno));
597: return FALSE;
598: }
599: if (ctx->format & COMMAND_FORMAT_RAW)
600: {
601: vici_dump(res, "load-token reply", ctx->format & COMMAND_FORMAT_PRETTY,
602: stdout);
603: }
604: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
605: {
606: fprintf(stderr, "loading '%s' failed: %s\n",
607: name, vici_find_str(res, "", "errmsg"));
608: ret = FALSE;
609: }
610: else
611: {
612: id = vici_find_str(res, "", "id");
613: printf("loaded key %s from token [keyid: %s]\n", name, id);
614: free(ctx->keys->remove(ctx->keys, id));
615: }
616: vici_free_res(res);
617: return ret;
618: }
619:
620: /**
621: * Load keys from tokens
622: */
623: static void load_tokens(load_ctx_t *ctx)
624: {
625: enumerator_t *enumerator;
626: char *section, *pin = NULL, prompt[128];
627:
628: enumerator = ctx->cfg->create_section_enumerator(ctx->cfg, "secrets");
629: while (enumerator->enumerate(enumerator, §ion))
630: {
631: if (strpfx(section, "token"))
632: {
633: if (!ctx->noprompt &&
634: !ctx->cfg->get_str(ctx->cfg, "secrets.%s.pin", NULL, section))
635: {
636: #ifdef HAVE_GETPASS
637: snprintf(prompt, sizeof(prompt), "PIN for %s: ", section);
638: pin = strdupnull(getpass(prompt));
639: #endif
640: }
641: load_token(ctx, section, pin);
642: if (pin)
643: {
644: memwipe(pin, strlen(pin));
645: free(pin);
646: pin = NULL;
647: }
648: }
649: }
650: enumerator->destroy(enumerator);
651: }
652:
653:
654:
655: /**
656: * Load a single secret over VICI
657: */
658: static bool load_secret(load_ctx_t *ctx, char *section)
659: {
660: enumerator_t *enumerator;
661: vici_req_t *req;
662: vici_res_t *res;
663: chunk_t data;
664: char *key, *value, *type = NULL;
665: bool ret = TRUE;
666: int i;
667: char *types[] = {
668: "eap",
669: "xauth",
670: "ntlm",
671: "ike",
672: "ppk",
673: "private",
674: "rsa",
675: "ecdsa",
676: "bliss",
677: "pkcs8",
678: "pkcs12",
679: "token",
680: };
681:
682: for (i = 0; i < countof(types); i++)
683: {
684: if (strpfx(section, types[i]))
685: {
686: type = types[i];
687: break;
688: }
689: }
690: if (!type)
691: {
692: fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
693: return FALSE;
694: }
695: if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ntlm") &&
696: !streq(type, "ike") && !streq(type, "ppk"))
697: { /* skip non-shared secrets */
698: return TRUE;
699: }
700:
701: value = ctx->cfg->get_str(ctx->cfg, "secrets.%s.secret", NULL, section);
702: if (!value)
703: {
704: fprintf(stderr, "missing secret in '%s', ignored\n", section);
705: return FALSE;
706: }
707: if (strcasepfx(value, "0x"))
708: {
709: data = chunk_from_hex(chunk_from_str(value + 2), NULL);
710: }
711: else if (strcasepfx(value, "0s"))
712: {
713: data = chunk_from_base64(chunk_from_str(value + 2), NULL);
714: }
715: else
716: {
717: data = chunk_clone(chunk_from_str(value));
718: }
719:
720: req = vici_begin("load-shared");
721:
722: vici_add_key_valuef(req, "id", "%s", section);
723: vici_add_key_valuef(req, "type", "%s", type);
724: vici_add_key_value(req, "data", data.ptr, data.len);
725: chunk_clear(&data);
726:
727: vici_begin_list(req, "owners");
728: enumerator = ctx->cfg->create_key_value_enumerator(ctx->cfg, "secrets.%s",
729: section);
730: while (enumerator->enumerate(enumerator, &key, &value))
731: {
732: if (strpfx(key, "id"))
733: {
734: vici_add_list_itemf(req, "%s", value);
735: }
736: }
737: enumerator->destroy(enumerator);
738: vici_end_list(req);
739:
740: res = vici_submit(req, ctx->conn);
741: if (!res)
742: {
743: fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
744: return FALSE;
745: }
746: if (ctx->format & COMMAND_FORMAT_RAW)
747: {
748: vici_dump(res, "load-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
749: stdout);
750: }
751: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
752: {
753: fprintf(stderr, "loading shared secret failed: %s\n",
754: vici_find_str(res, "", "errmsg"));
755: ret = FALSE;
756: }
757: else
758: {
759: printf("loaded %s secret '%s'\n", type, section);
760: }
761: if (ret)
762: {
763: free(ctx->shared->remove(ctx->shared, section));
764: }
765: vici_free_res(res);
766: return ret;
767: }
768:
769: CALLBACK(get_id, int,
770: hashtable_t *ht, vici_res_t *res, char *name, void *value, int len)
771: {
772: if (streq(name, "keys"))
773: {
774: char *str;
775:
776: if (asprintf(&str, "%.*s", len, value) != -1)
777: {
778: free(ht->put(ht, str, str));
779: }
780: }
781: return 0;
782: }
783:
784: /**
785: * Get a list of currently loaded private and shared keys
786: */
787: static void get_creds(load_ctx_t *ctx)
788: {
789: vici_res_t *res;
790:
791: res = vici_submit(vici_begin("get-keys"), ctx->conn);
792: if (res)
793: {
794: if (ctx->format & COMMAND_FORMAT_RAW)
795: {
796: vici_dump(res, "get-keys reply", ctx->format & COMMAND_FORMAT_PRETTY,
797: stdout);
798: }
799: vici_parse_cb(res, NULL, NULL, get_id, ctx->keys);
800: vici_free_res(res);
801: }
802: res = vici_submit(vici_begin("get-shared"), ctx->conn);
803: if (res)
804: {
805: if (ctx->format & COMMAND_FORMAT_RAW)
806: {
807: vici_dump(res, "get-shared reply", ctx->format & COMMAND_FORMAT_PRETTY,
808: stdout);
809: }
810: vici_parse_cb(res, NULL, NULL, get_id, ctx->shared);
811: vici_free_res(res);
812: }
813: }
814:
815: /**
816: * Remove a given key
817: */
818: static bool unload_key(load_ctx_t *ctx, char *command, char *id)
819: {
820: vici_req_t *req;
821: vici_res_t *res;
822: char buf[BUF_LEN];
823: bool ret = TRUE;
824:
825: req = vici_begin(command);
826:
827: vici_add_key_valuef(req, "id", "%s", id);
828:
829: res = vici_submit(req, ctx->conn);
830: if (!res)
831: {
832: fprintf(stderr, "%s request failed: %s\n", command, strerror(errno));
833: return FALSE;
834: }
835: if (ctx->format & COMMAND_FORMAT_RAW)
836: {
837: snprintf(buf, sizeof(buf), "%s reply", command);
838: vici_dump(res, buf, ctx->format & COMMAND_FORMAT_PRETTY, stdout);
839: }
840: else if (!streq(vici_find_str(res, "no", "success"), "yes"))
841: {
842: fprintf(stderr, "unloading key '%s' failed: %s\n",
843: id, vici_find_str(res, "", "errmsg"));
844: ret = FALSE;
845: }
846: vici_free_res(res);
847: return ret;
848: }
849:
850: /**
851: * Remove all keys in the given hashtable using the given command
852: */
853: static void unload_keys(load_ctx_t *ctx, hashtable_t *ht, char *command)
854: {
855: enumerator_t *enumerator;
856: char *id;
857:
858: enumerator = ht->create_enumerator(ht);
859: while (enumerator->enumerate(enumerator, &id, NULL))
860: {
861: unload_key(ctx, command, id);
862: }
863: enumerator->destroy(enumerator);
864: }
865:
866: /**
867: * Clear all currently loaded credentials
868: */
869: static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
870: {
871: vici_res_t *res;
872:
873: res = vici_submit(vici_begin("clear-creds"), conn);
874: if (!res)
875: {
876: fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
877: return FALSE;
878: }
879: if (format & COMMAND_FORMAT_RAW)
880: {
881: vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
882: stdout);
883: }
884: vici_free_res(res);
885: return TRUE;
886: }
887:
888: /**
889: * See header.
890: */
891: int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
892: settings_t *cfg, bool clear, bool noprompt)
893: {
894: enumerator_t *enumerator;
895: char *section;
896: load_ctx_t ctx = {
897: .conn = conn,
898: .format = format,
899: .noprompt = noprompt,
900: .cfg = cfg,
901: .keys = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
902: .shared = hashtable_create(hashtable_hash_str, hashtable_equals_str, 8),
903: };
904:
905: if (clear)
906: {
907: if (!clear_creds(conn, format))
908: {
909: return ECONNREFUSED;
910: }
911: }
912:
913: get_creds(&ctx);
914:
915: load_certs(&ctx, "x509", SWANCTL_X509DIR);
916: load_certs(&ctx, "x509ca", SWANCTL_X509CADIR);
917: load_certs(&ctx, "x509ocsp", SWANCTL_X509OCSPDIR);
918: load_certs(&ctx, "x509aa", SWANCTL_X509AADIR);
919: load_certs(&ctx, "x509ac", SWANCTL_X509ACDIR);
920: load_certs(&ctx, "x509crl", SWANCTL_X509CRLDIR);
921: load_certs(&ctx, "pubkey", SWANCTL_PUBKEYDIR);
922:
923: load_keys(&ctx, "private", SWANCTL_PRIVATEDIR);
924: load_keys(&ctx, "rsa", SWANCTL_RSADIR);
925: load_keys(&ctx, "ecdsa", SWANCTL_ECDSADIR);
926: load_keys(&ctx, "bliss", SWANCTL_BLISSDIR);
927: load_keys(&ctx, "pkcs8", SWANCTL_PKCS8DIR);
928:
929: load_containers(&ctx, "pkcs12", SWANCTL_PKCS12DIR);
930:
931: load_tokens(&ctx);
932:
933: enumerator = cfg->create_section_enumerator(cfg, "secrets");
934: while (enumerator->enumerate(enumerator, §ion))
935: {
936: load_secret(&ctx, section);
937: }
938: enumerator->destroy(enumerator);
939:
940: unload_keys(&ctx, ctx.keys, "unload-key");
941: unload_keys(&ctx, ctx.shared, "unload-shared");
942:
943: ctx.keys->destroy_function(ctx.keys, (void*)free);
944: ctx.shared->destroy_function(ctx.shared, (void*)free);
945: return 0;
946: }
947:
948: static int load_creds(vici_conn_t *conn)
949: {
950: bool clear = FALSE, noprompt = FALSE;
951: command_format_options_t format = COMMAND_FORMAT_NONE;
952: settings_t *cfg;
953: char *arg, *file = NULL;
954: int ret;
955:
956: while (TRUE)
957: {
958: switch (command_getopt(&arg))
959: {
960: case 'h':
961: return command_usage(NULL);
962: case 'c':
963: clear = TRUE;
964: continue;
965: case 'n':
966: noprompt = TRUE;
967: continue;
968: case 'P':
969: format |= COMMAND_FORMAT_PRETTY;
970: /* fall through to raw */
971: case 'r':
972: format |= COMMAND_FORMAT_RAW;
973: continue;
974: case 'f':
975: file = arg;
976: continue;
977: case EOF:
978: break;
979: default:
980: return command_usage("invalid --load-creds option");
981: }
982: break;
983: }
984:
985: cfg = load_swanctl_conf(file);
986: if (!cfg)
987: {
988: return EINVAL;
989: }
990:
991: ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
992:
993: cfg->destroy(cfg);
994:
995: return ret;
996: }
997:
998: /**
999: * Register the command.
1000: */
1001: static void __attribute__ ((constructor))reg()
1002: {
1003: command_register((command_t) {
1004: load_creds, 's', "load-creds", "(re-)load credentials",
1005: {"[--raw|--pretty] [--clear] [--noprompt]"},
1006: {
1007: {"help", 'h', 0, "show usage information"},
1008: {"clear", 'c', 0, "clear previously loaded credentials"},
1009: {"noprompt", 'n', 0, "do not prompt for passwords"},
1010: {"raw", 'r', 0, "dump raw response message"},
1011: {"pretty", 'P', 0, "dump raw response message in pretty print"},
1012: {"file", 'f', 1, "custom path to swanctl.conf"},
1013: }
1014: });
1015: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>