kernel - support dummy reallocblks in devfs
[dragonfly.git] / lib / libtcplay / tcplay_api.c
blob1d7cba648fcc32e45e05149cd972f16f35355239
1 /*
2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <stdarg.h>
37 #include "tcplay.h"
38 #include "tcplay_api.h"
39 #include "tcplay_api_internal.h"
42 int
43 tc_api_init(int verbose)
45 int error;
47 tc_internal_verbose = verbose;
49 if ((error = tc_play_init()) != 0)
50 return TC_ERR;
51 else
52 return TC_OK;
55 int
56 tc_api_uninit(void)
58 check_and_purge_safe_mem();
59 return TC_OK;
63 static const char *_caps[] = {
64 "trim",
65 NULL
68 int
69 tc_api_has(const char *feature)
71 const char *cap;
72 int i;
74 for (cap = _caps[0], i = 0; cap != NULL; cap = _caps[++i]) {
75 if ((strcmp(cap, feature)) == 0)
76 return TC_OK;
79 return TC_ERR_UNIMPL;
82 int
83 tc_api_cipher_iterate(tc_api_cipher_iterator_fn fn, void *priv)
85 int i;
86 struct tc_cipher_chain *chain;
87 int klen;
88 int length;
89 char buf[1024];
91 if (fn == NULL) {
92 errno = EFAULT;
93 return TC_ERR;
96 for (i = 0, chain = tc_cipher_chains[0]; chain != NULL;
97 chain = tc_cipher_chains[++i]) {
98 tc_cipher_chain_sprint(buf, sizeof(buf), chain);
99 klen = tc_cipher_chain_klen(chain);
100 length = tc_cipher_chain_length(chain);
101 if ((fn(priv, buf, klen, length)) < 0)
102 break;
105 return TC_OK;
109 tc_api_prf_iterate(tc_api_prf_iterator_fn fn, void *priv)
111 int i;
113 if (fn == NULL) {
114 errno = EFAULT;
115 return TC_ERR;
118 /* start at 1 due to RIPEMD weirdness... */
119 for (i = 1; pbkdf_prf_algos[i].name != NULL; i++) {
120 if ((fn(priv, pbkdf_prf_algos[i].name)) < 0)
121 break;
124 return TC_OK;
128 const char *
129 tc_api_task_get_error(tc_api_task task __unused)
131 return tc_internal_log_buffer;
135 #define _match(k, v) (strcmp(k, v) == 0)
137 tc_api_task
138 tc_api_task_init(const char *op)
140 tc_api_task task = NULL;
141 int fail = 1;
143 if ((task = alloc_safe_mem(sizeof(*task))) == NULL) {
144 errno = ENOMEM;
145 goto out;
148 if ((task->opts = opts_init()) == NULL) {
149 errno = ENOMEM;
150 goto out;
153 if (_match(op, "create")) {
154 task->op = TC_OP_CREATE;
155 } else if (_match(op, "map")) {
156 task->op = TC_OP_MAP;
157 } else if (_match(op, "unmap")) {
158 task->op = TC_OP_UNMAP;
159 } else if (_match(op, "info")) {
160 task->op = TC_OP_INFO;
161 } else if (_match(op, "info_mapped")) {
162 task->op = TC_OP_INFO_MAPPED;
163 } else if (_match(op, "modify")) {
164 task->op = TC_OP_MODIFY;
165 } else if (_match(op, "restore")) {
166 task->op = TC_OP_RESTORE;
167 } else {
168 errno = EINVAL;
169 goto out;
172 fail = 0;
174 out:
175 if (fail && task != NULL) {
176 if (task->opts != NULL)
177 opts_free(task->opts);
178 free_safe_mem(task);
181 return fail ? NULL : task;
185 tc_api_task_uninit(tc_api_task task)
187 if (task->last_info != NULL)
188 free_info(task->last_info);
189 opts_free(task->opts);
190 free_safe_mem(task);
192 return TC_OK;
196 #define _set_str(k) \
197 do { \
198 if ((opts->k = strdup_safe_mem(s)) == NULL) { \
199 errno = ENOMEM; \
200 r = TC_ERR; \
201 goto out; \
203 } while (0)
205 #define _clr_str(k) \
206 do { \
207 if (opts->k) \
208 free_safe_mem(opts->k); \
209 opts->k = NULL; \
210 } while (0)
213 tc_api_task_set(tc_api_task task, const char *key, ...)
215 struct tcplay_opts *opts;
216 va_list ap;
217 const char *s;
218 int64_t i64;
219 int i;
220 tc_api_state_change_fn sc_fn;
221 void *vp;
222 int r = TC_OK;
224 if (task == NULL || ((opts = task->opts) == NULL)) {
225 errno = EFAULT;
226 return TC_ERR;
229 va_start(ap, key);
231 if (_match(key, "interactive")) {
232 i = va_arg(ap, int);
233 opts->interactive = i;
234 } else if (_match(key, "weak_keys_and_salt")) {
235 i = va_arg(ap, int);
236 opts->weak_keys_and_salt = i;
237 } else if (_match(key, "secure_erase")) {
238 i = va_arg(ap, int);
239 opts->secure_erase = i;
240 } else if (_match(key, "protect_hidden")) {
241 i = va_arg(ap, int);
242 opts->protect_hidden = i;
243 } else if (_match(key, "fde")) {
244 i = va_arg(ap, int);
245 if (i)
246 opts->flags |= TC_FLAG_FDE;
247 else
248 opts->flags &= ~TC_FLAG_FDE;
249 } else if (_match(key, "use_backup_header")) {
250 i = va_arg(ap, int);
251 if (i)
252 opts->flags |= TC_FLAG_BACKUP;
253 else
254 opts->flags &= ~TC_FLAG_BACKUP;
255 } else if (_match(key, "allow_trim")) {
256 i = va_arg(ap, int);
257 if (i)
258 opts->flags |= TC_FLAG_ALLOW_TRIM;
259 else
260 opts->flags &= ~TC_FLAG_ALLOW_TRIM;
261 } else if (_match(key, "hidden_size_bytes")) {
262 i64 = va_arg(ap, int64_t);
263 opts->hidden_size_bytes = (disksz_t)i64;
264 opts->hidden = (i64 > 0);
265 } else if (_match(key, "retries")) {
266 i = va_arg(ap, int);
267 opts->retries = i;
268 } else if (_match(key, "timeout")) {
269 i = va_arg(ap, int);
270 opts->timeout = (time_t)i;
271 } else if (_match(key, "save_header_to_file")) {
272 s = va_arg(ap, const char *);
273 if (s != NULL) {
274 _set_str(hdr_file_out);
275 opts->flags |= TC_FLAG_SAVE_TO_FILE;
276 } else {
277 _clr_str(hdr_file_out);
278 opts->flags &= ~TC_FLAG_SAVE_TO_FILE;
280 } else if (_match(key, "header_from_file")) {
281 s = va_arg(ap, const char *);
282 if (s != NULL) {
283 _set_str(hdr_file_in);
284 opts->flags |= TC_FLAG_HDR_FROM_FILE;
285 } else {
286 _clr_str(hdr_file_in);
287 opts->flags &= ~TC_FLAG_HDR_FROM_FILE;
289 } else if (_match(key, "hidden_header_from_file")) {
290 s = va_arg(ap, const char *);
291 if (s != NULL) {
292 _set_str(h_hdr_file_in);
293 opts->flags |= TC_FLAG_H_HDR_FROM_FILE;
294 } else {
295 _clr_str(h_hdr_file_in);
296 opts->flags &= ~TC_FLAG_H_HDR_FROM_FILE;
298 } else if (_match(key, "sys")) {
299 s = va_arg(ap, const char *);
300 if (s != NULL) {
301 _set_str(sys_dev);
302 opts->flags |= TC_FLAG_SYS;
303 } else {
304 _clr_str(sys_dev);
305 opts->flags &= ~TC_FLAG_SYS;
307 } else if (_match(key, "passphrase")) {
308 s = va_arg(ap, const char *);
309 if (s != NULL) {
310 _set_str(passphrase);
311 } else {
312 _clr_str(passphrase);
314 } else if (_match(key, "h_passphrase")) {
315 s = va_arg(ap, const char *);
316 if (s != NULL) {
317 _set_str(h_passphrase);
318 } else {
319 _clr_str(h_passphrase);
321 } else if (_match(key, "new_passphrase")) {
322 s = va_arg(ap, const char *);
323 if (s != NULL) {
324 _set_str(new_passphrase);
325 } else {
326 _clr_str(new_passphrase);
328 } else if (_match(key, "dev")) {
329 s = va_arg(ap, const char *);
330 if (s != NULL) {
331 _set_str(dev);
332 } else {
333 _clr_str(dev);
335 } else if (_match(key, "map_name")) {
336 s = va_arg(ap, const char *);
337 if (s != NULL) {
338 _set_str(map_name);
339 } else {
340 _clr_str(map_name);
342 } else if (_match(key, "keyfiles")) {
343 s = va_arg(ap, const char *);
344 if (s != NULL) {
345 opts_add_keyfile(opts, s);
346 } else {
347 opts_clear_keyfile(opts);
349 } else if (_match(key, "h_keyfiles")) {
350 s = va_arg(ap, const char *);
351 if (s != NULL) {
352 opts_add_keyfile_hidden(opts, s);
353 } else {
354 opts_clear_keyfile_hidden(opts);
356 } else if (_match(key, "new_keyfiles")) {
357 s = va_arg(ap, const char *);
358 if (s != NULL) {
359 opts_add_keyfile_new(opts, s);
360 } else {
361 opts_clear_keyfile_new(opts);
363 } else if (_match(key, "prf_algo")) {
364 s = va_arg(ap, const char *);
365 if (s != NULL) {
366 if ((opts->prf_algo = check_prf_algo(s, 1)) == NULL) {
367 errno = ENOENT;
368 r = TC_ERR;
369 goto out;
371 } else {
372 opts->prf_algo = NULL;
374 } else if (_match(key, "h_prf_algo")) {
375 s = va_arg(ap, const char *);
376 if (s != NULL) {
377 if ((opts->h_prf_algo = check_prf_algo(s, 1)) == NULL) {
378 errno = ENOENT;
379 r = TC_ERR;
380 goto out;
382 } else {
383 opts->h_prf_algo = NULL;
385 } else if (_match(key, "new_prf_algo")) {
386 s = va_arg(ap, const char *);
387 if (s != NULL) {
388 if ((opts->new_prf_algo = check_prf_algo(s, 1)) == NULL) {
389 errno = ENOENT;
390 r = TC_ERR;
391 goto out;
393 } else {
394 opts->new_prf_algo = NULL;
396 } else if (_match(key, "cipher_chain")) {
397 s = va_arg(ap, const char *);
398 if (s != NULL) {
399 if ((opts->cipher_chain = check_cipher_chain(s, 1)) == NULL) {
400 errno = ENOENT;
401 r = TC_ERR;
402 goto out;
404 } else {
405 opts->cipher_chain = NULL;
407 } else if (_match(key, "h_cipher_chain")) {
408 s = va_arg(ap, const char *);
409 if (s != NULL) {
410 if ((opts->h_cipher_chain = check_cipher_chain(s, 1)) == NULL) {
411 errno = ENOENT;
412 r = TC_ERR;
413 goto out;
415 } else {
416 opts->h_cipher_chain = NULL;
418 } else if (_match(key, "state_change_fn")) {
419 sc_fn = va_arg(ap, tc_api_state_change_fn);
420 opts->state_change_fn = sc_fn;
421 vp = va_arg(ap, void *);
422 opts->api_ctx = vp;
423 } else {
424 r = TC_ERR_UNIMPL;
427 out:
428 va_end(ap);
430 return r;
433 #define _not_null(x) \
434 if (opts->x == NULL) { \
435 return -1; \
438 #define _null(x) \
439 if (opts->x != NULL) { \
440 return -1; \
443 #define _zero(x) \
444 if (opts->x != 0) { \
445 return -1; \
448 #define _not_set(x) \
449 if (TC_FLAG_SET(opts->flags, x)) { \
450 return -1; \
453 static
455 _opts_check_create(struct tcplay_opts *opts)
457 _not_null(dev);
458 _not_set(SYS);
459 _not_set(FDE);
460 _not_set(BACKUP);
461 _not_set(ONLY_RESTORE);
462 _not_set(ALLOW_TRIM);
463 _not_set(SAVE_TO_FILE);
464 _not_set(HDR_FROM_FILE);
465 _not_set(H_HDR_FROM_FILE);
467 _null(map_name);
468 _zero(protect_hidden);
469 _null(new_passphrase);
470 _null(new_prf_algo);
471 _zero(n_newkeyfiles);
473 if (opts->hidden_size_bytes && !opts->hidden) {
474 return -1;
477 return 0;
480 static
482 _opts_check_map(struct tcplay_opts *opts)
484 _not_null(dev);
485 _not_null(map_name);
486 _not_set(ONLY_RESTORE);
487 _not_set(SAVE_TO_FILE);
488 _zero(hidden);
489 _zero(hidden_size_bytes);
490 _null(new_passphrase);
491 _null(new_prf_algo);
492 _zero(n_newkeyfiles);
493 _null(prf_algo);
494 _null(h_prf_algo);
495 _null(cipher_chain);
496 _null(h_cipher_chain);
498 if (!opts->protect_hidden) {
499 _zero(n_hkeyfiles);
500 //_null(h_passphrase);
503 return 0;
506 static
508 _opts_check_unmap(struct tcplay_opts *opts)
510 _not_null(map_name);
511 /* XXX: _not_null(dev); ? */
512 _zero(nkeyfiles);
513 _zero(n_hkeyfiles);
514 _null(prf_algo);
515 _null(cipher_chain);
516 _null(h_prf_algo);
517 _null(h_cipher_chain);
518 _null(passphrase);
519 _null(h_passphrase);
520 _zero(hidden);
521 _zero(protect_hidden);
522 _null(new_prf_algo);
523 _null(new_passphrase);
524 _zero(n_newkeyfiles);
525 _not_set(SYS);
526 _not_set(FDE);
527 _not_set(BACKUP);
528 _not_set(ONLY_RESTORE);
529 _not_set(ALLOW_TRIM);
530 _not_set(SAVE_TO_FILE);
531 _not_set(HDR_FROM_FILE);
532 _not_set(H_HDR_FROM_FILE);
534 return 0;
537 static
539 _opts_check_info(struct tcplay_opts *opts)
541 _not_null(dev);
542 _null(map_name);
543 _not_set(ONLY_RESTORE);
544 _not_set(SAVE_TO_FILE);
545 _zero(hidden);
546 _zero(hidden_size_bytes);
547 _null(new_passphrase);
548 _null(new_prf_algo);
549 _zero(n_newkeyfiles);
550 _null(prf_algo);
551 _null(h_prf_algo);
552 _null(cipher_chain);
553 _null(h_cipher_chain);
555 if (!opts->protect_hidden) {
556 _zero(n_hkeyfiles);
557 //_null(h_passphrase);
560 return 0;
563 static
565 _opts_check_info_mapped(struct tcplay_opts *opts)
567 _not_null(map_name);
568 /* XXX: _not_null(dev); ? */
569 _zero(nkeyfiles);
570 _zero(n_hkeyfiles);
571 _null(prf_algo);
572 _null(cipher_chain);
573 _null(h_prf_algo);
574 _null(h_cipher_chain);
575 _null(passphrase);
576 _null(h_passphrase);
577 _zero(hidden);
578 _zero(protect_hidden);
579 _null(new_prf_algo);
580 _null(new_passphrase);
581 _zero(n_newkeyfiles);
582 _not_set(SYS);
583 _not_set(FDE);
584 _not_set(BACKUP);
585 _not_set(ONLY_RESTORE);
586 _not_set(ALLOW_TRIM);
587 _not_set(SAVE_TO_FILE);
588 _not_set(HDR_FROM_FILE);
589 _not_set(H_HDR_FROM_FILE);
591 return 0;
594 static
596 _opts_check_modify(struct tcplay_opts *opts)
598 _not_null(dev);
599 _null(map_name);
600 _zero(hidden);
601 _zero(hidden_size_bytes);
602 _null(prf_algo);
603 _null(h_prf_algo);
604 _null(cipher_chain);
605 _null(h_cipher_chain);
607 if (!opts->protect_hidden) {
608 _zero(n_hkeyfiles);
609 _null(h_passphrase);
612 return 0;
616 static
618 _opts_check_restore(struct tcplay_opts *opts)
620 if ((_opts_check_modify(opts)) < 0)
621 return -1;
623 _null(new_prf_algo);
624 _zero(n_newkeyfiles);
625 _null(new_passphrase);
627 return 0;
631 tc_api_task_do(tc_api_task task)
633 struct tcplay_opts *opts;
634 int r = TC_OK;
636 if (task == NULL || ((opts = task->opts) == NULL)) {
637 errno = EFAULT;
638 return TC_ERR;
641 if (task->last_info != NULL) {
642 free_info(task->last_info);
645 switch (task->op) {
646 case TC_OP_CREATE:
647 if ((r = _opts_check_create(task->opts)) != 0) {
648 errno = EINVAL;
649 return r;
651 r = create_volume(opts);
652 break;
654 case TC_OP_MAP:
655 if ((r = _opts_check_map(task->opts)) != 0) {
656 errno = EINVAL;
657 return r;
659 r = map_volume(opts);
660 break;
662 case TC_OP_UNMAP:
663 if ((r = _opts_check_unmap(task->opts)) != 0) {
664 errno = EINVAL;
665 return r;
667 r = dm_teardown(opts->map_name, opts->dev);
668 break;
670 case TC_OP_INFO:
671 if ((r = _opts_check_info(task->opts)) != 0) {
672 errno = EINVAL;
673 return r;
675 if ((task->last_info = info_map_common(opts, NULL)) == NULL) {
676 r = TC_ERR;
678 break;
680 case TC_OP_INFO_MAPPED:
681 if ((r = _opts_check_info_mapped(task->opts)) != 0) {
682 errno = EINVAL;
683 return r;
685 if ((task->last_info = dm_info_map(opts->map_name)) == NULL) {
686 r = TC_ERR;
688 break;
690 case TC_OP_MODIFY:
691 if ((r = _opts_check_modify(task->opts)) != 0) {
692 errno = EINVAL;
693 return r;
695 r = modify_volume(opts);
696 break;
698 case TC_OP_RESTORE:
699 if ((r = _opts_check_restore(task->opts)) != 0) {
700 errno = EINVAL;
701 return r;
703 opts->flags |= TC_FLAG_ONLY_RESTORE;
704 r = modify_volume(opts);
705 opts->flags &= ~TC_FLAG_ONLY_RESTORE;
706 break;
709 return r;
714 tc_api_task_info_get(tc_api_task task, const char *key, ...)
716 char buf[1024];
717 va_list ap;
718 struct tcplay_info *info;
719 char *s;
720 int *ip;
721 int64_t *i64p;
722 int r = TC_OK;
723 size_t sz;
725 if (task == NULL || ((info = task->last_info) == NULL)) {
726 errno = EFAULT;
727 return TC_ERR;
730 va_start(ap, key);
731 sz = va_arg(ap, size_t);
732 if (sz < 1) {
733 errno = EINVAL;
734 r = TC_ERR;
735 goto out;
738 if (_match(key, "device")) {
739 s = va_arg(ap, char *);
740 strncpy(s, info->dev, sz);
741 s[sz-1] = '\0';
742 } else if (_match(key, "cipher")) {
743 s = va_arg(ap, char *);
744 tc_cipher_chain_sprint(buf, sizeof(buf), info->cipher_chain);
745 strncpy(s, buf, sz);
746 s[sz-1] = '\0';
747 } else if (_match(key, "prf")) {
748 s = va_arg(ap, char *);
749 if (info->pbkdf_prf)
750 strncpy(s, info->pbkdf_prf->name, sz);
751 else
752 strncpy(s, "(unknown)", sz);
753 s[sz-1] = '\0';
754 } else if (_match(key, "key_bits")) {
755 if (sz != sizeof(int)) {
756 errno = EFAULT;
757 r = TC_ERR;
758 goto out;
760 ip = va_arg(ap, int *);
761 *ip = 8*tc_cipher_chain_klen(info->cipher_chain);
762 } else if (_match(key, "size")) {
763 if (sz != sizeof(int64_t)) {
764 errno = EFAULT;
765 r = TC_ERR;
766 goto out;
768 i64p = va_arg(ap, int64_t *);
769 if (info->hdr)
770 *i64p = (int64_t)info->size * (int64_t)info->hdr->sec_sz;
771 else
772 *i64p = (int64_t)info->size * (int64_t)info->blk_sz;
773 } else if (_match(key, "iv_offset")) {
774 if (sz != sizeof(int64_t)) {
775 errno = EFAULT;
776 r = TC_ERR;
777 goto out;
779 i64p = va_arg(ap, int64_t *);
780 if (info->hdr)
781 *i64p = (int64_t)info->skip * (int64_t)info->hdr->sec_sz;
782 else
783 *i64p = (int64_t)info->skip * (int64_t)info->blk_sz;
784 } else if (_match(key, "block_offset")) {
785 if (sz != sizeof(int64_t)) {
786 errno = EFAULT;
787 r = TC_ERR;
788 goto out;
790 i64p = va_arg(ap, int64_t *);
791 if (info->hdr)
792 *i64p = (int64_t)info->offset * (int64_t)info->hdr->sec_sz;
793 else
794 *i64p = (int64_t)info->offset * (int64_t)info->blk_sz;
795 } else {
796 r = TC_ERR_UNIMPL;
799 out:
800 va_end(ap);
802 return r;