2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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
38 #include "tcplay_api.h"
39 #include "tcplay_api_internal.h"
43 tc_api_init(int verbose
)
47 tc_internal_verbose
= verbose
;
49 if ((error
= tc_play_init()) != 0)
58 check_and_purge_safe_mem();
63 static const char *_caps
[] = {
69 tc_api_has(const char *feature
)
74 for (cap
= _caps
[0], i
= 0; cap
!= NULL
; cap
= _caps
[++i
]) {
75 if ((strcmp(cap
, feature
)) == 0)
83 tc_api_cipher_iterate(tc_api_cipher_iterator_fn fn
, void *priv
)
86 struct tc_cipher_chain
*chain
;
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)
109 tc_api_prf_iterate(tc_api_prf_iterator_fn fn
, void *priv
)
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)
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)
138 tc_api_task_init(const char *op
)
140 tc_api_task task
= NULL
;
143 if ((task
= alloc_safe_mem(sizeof(*task
))) == NULL
) {
148 if ((task
->opts
= opts_init()) == NULL
) {
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
;
175 if (fail
&& task
!= NULL
) {
176 if (task
->opts
!= NULL
)
177 opts_free(task
->opts
);
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
);
196 #define _set_str(k) \
198 if ((opts->k = strdup_safe_mem(s)) == NULL) { \
205 #define _clr_str(k) \
208 free_safe_mem(opts->k); \
213 tc_api_task_set(tc_api_task task
, const char *key
, ...)
215 struct tcplay_opts
*opts
;
220 tc_api_state_change_fn sc_fn
;
224 if (task
== NULL
|| ((opts
= task
->opts
) == NULL
)) {
231 if (_match(key
, "interactive")) {
233 opts
->interactive
= i
;
234 } else if (_match(key
, "weak_keys_and_salt")) {
236 opts
->weak_keys_and_salt
= i
;
237 } else if (_match(key
, "secure_erase")) {
239 opts
->secure_erase
= i
;
240 } else if (_match(key
, "protect_hidden")) {
242 opts
->protect_hidden
= i
;
243 } else if (_match(key
, "fde")) {
246 opts
->flags
|= TC_FLAG_FDE
;
248 opts
->flags
&= ~TC_FLAG_FDE
;
249 } else if (_match(key
, "use_backup_header")) {
252 opts
->flags
|= TC_FLAG_BACKUP
;
254 opts
->flags
&= ~TC_FLAG_BACKUP
;
255 } else if (_match(key
, "allow_trim")) {
258 opts
->flags
|= TC_FLAG_ALLOW_TRIM
;
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")) {
268 } else if (_match(key
, "timeout")) {
270 opts
->timeout
= (time_t)i
;
271 } else if (_match(key
, "save_header_to_file")) {
272 s
= va_arg(ap
, const char *);
274 _set_str(hdr_file_out
);
275 opts
->flags
|= TC_FLAG_SAVE_TO_FILE
;
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 *);
283 _set_str(hdr_file_in
);
284 opts
->flags
|= TC_FLAG_HDR_FROM_FILE
;
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 *);
292 _set_str(h_hdr_file_in
);
293 opts
->flags
|= TC_FLAG_H_HDR_FROM_FILE
;
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 *);
302 opts
->flags
|= TC_FLAG_SYS
;
305 opts
->flags
&= ~TC_FLAG_SYS
;
307 } else if (_match(key
, "passphrase")) {
308 s
= va_arg(ap
, const char *);
310 _set_str(passphrase
);
312 _clr_str(passphrase
);
314 } else if (_match(key
, "h_passphrase")) {
315 s
= va_arg(ap
, const char *);
317 _set_str(h_passphrase
);
319 _clr_str(h_passphrase
);
321 } else if (_match(key
, "new_passphrase")) {
322 s
= va_arg(ap
, const char *);
324 _set_str(new_passphrase
);
326 _clr_str(new_passphrase
);
328 } else if (_match(key
, "dev")) {
329 s
= va_arg(ap
, const char *);
335 } else if (_match(key
, "map_name")) {
336 s
= va_arg(ap
, const char *);
342 } else if (_match(key
, "keyfiles")) {
343 s
= va_arg(ap
, const char *);
345 opts_add_keyfile(opts
, s
);
347 opts_clear_keyfile(opts
);
349 } else if (_match(key
, "h_keyfiles")) {
350 s
= va_arg(ap
, const char *);
352 opts_add_keyfile_hidden(opts
, s
);
354 opts_clear_keyfile_hidden(opts
);
356 } else if (_match(key
, "new_keyfiles")) {
357 s
= va_arg(ap
, const char *);
359 opts_add_keyfile_new(opts
, s
);
361 opts_clear_keyfile_new(opts
);
363 } else if (_match(key
, "prf_algo")) {
364 s
= va_arg(ap
, const char *);
366 if ((opts
->prf_algo
= check_prf_algo(s
, 1)) == NULL
) {
372 opts
->prf_algo
= NULL
;
374 } else if (_match(key
, "h_prf_algo")) {
375 s
= va_arg(ap
, const char *);
377 if ((opts
->h_prf_algo
= check_prf_algo(s
, 1)) == NULL
) {
383 opts
->h_prf_algo
= NULL
;
385 } else if (_match(key
, "new_prf_algo")) {
386 s
= va_arg(ap
, const char *);
388 if ((opts
->new_prf_algo
= check_prf_algo(s
, 1)) == NULL
) {
394 opts
->new_prf_algo
= NULL
;
396 } else if (_match(key
, "cipher_chain")) {
397 s
= va_arg(ap
, const char *);
399 if ((opts
->cipher_chain
= check_cipher_chain(s
, 1)) == NULL
) {
405 opts
->cipher_chain
= NULL
;
407 } else if (_match(key
, "h_cipher_chain")) {
408 s
= va_arg(ap
, const char *);
410 if ((opts
->h_cipher_chain
= check_cipher_chain(s
, 1)) == NULL
) {
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 *);
433 #define _not_null(x) \
434 if (opts->x == NULL) { \
439 if (opts->x != NULL) { \
444 if (opts->x != 0) { \
448 #define _not_set(x) \
449 if (TC_FLAG_SET(opts->flags, x)) { \
455 _opts_check_create(struct tcplay_opts
*opts
)
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
);
468 _zero(protect_hidden
);
469 _null(new_passphrase
);
471 _zero(n_newkeyfiles
);
473 if (opts
->hidden_size_bytes
&& !opts
->hidden
) {
482 _opts_check_map(struct tcplay_opts
*opts
)
486 _not_set(ONLY_RESTORE
);
487 _not_set(SAVE_TO_FILE
);
489 _zero(hidden_size_bytes
);
490 _null(new_passphrase
);
492 _zero(n_newkeyfiles
);
496 _null(h_cipher_chain
);
498 if (!opts
->protect_hidden
) {
500 //_null(h_passphrase);
508 _opts_check_unmap(struct tcplay_opts
*opts
)
511 /* XXX: _not_null(dev); ? */
517 _null(h_cipher_chain
);
521 _zero(protect_hidden
);
523 _null(new_passphrase
);
524 _zero(n_newkeyfiles
);
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
);
539 _opts_check_info(struct tcplay_opts
*opts
)
543 _not_set(ONLY_RESTORE
);
544 _not_set(SAVE_TO_FILE
);
546 _zero(hidden_size_bytes
);
547 _null(new_passphrase
);
549 _zero(n_newkeyfiles
);
553 _null(h_cipher_chain
);
555 if (!opts
->protect_hidden
) {
557 //_null(h_passphrase);
565 _opts_check_info_mapped(struct tcplay_opts
*opts
)
568 /* XXX: _not_null(dev); ? */
574 _null(h_cipher_chain
);
578 _zero(protect_hidden
);
580 _null(new_passphrase
);
581 _zero(n_newkeyfiles
);
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
);
596 _opts_check_modify(struct tcplay_opts
*opts
)
601 _zero(hidden_size_bytes
);
605 _null(h_cipher_chain
);
607 if (!opts
->protect_hidden
) {
618 _opts_check_restore(struct tcplay_opts
*opts
)
620 if ((_opts_check_modify(opts
)) < 0)
624 _zero(n_newkeyfiles
);
625 _null(new_passphrase
);
631 tc_api_task_do(tc_api_task task
)
633 struct tcplay_opts
*opts
;
636 if (task
== NULL
|| ((opts
= task
->opts
) == NULL
)) {
641 if (task
->last_info
!= NULL
) {
642 free_info(task
->last_info
);
647 if ((r
= _opts_check_create(task
->opts
)) != 0) {
651 r
= create_volume(opts
);
655 if ((r
= _opts_check_map(task
->opts
)) != 0) {
659 r
= map_volume(opts
);
663 if ((r
= _opts_check_unmap(task
->opts
)) != 0) {
667 r
= dm_teardown(opts
->map_name
, opts
->dev
);
671 if ((r
= _opts_check_info(task
->opts
)) != 0) {
675 if ((task
->last_info
= info_map_common(opts
, NULL
)) == NULL
) {
680 case TC_OP_INFO_MAPPED
:
681 if ((r
= _opts_check_info_mapped(task
->opts
)) != 0) {
685 if ((task
->last_info
= dm_info_map(opts
->map_name
)) == NULL
) {
691 if ((r
= _opts_check_modify(task
->opts
)) != 0) {
695 r
= modify_volume(opts
);
699 if ((r
= _opts_check_restore(task
->opts
)) != 0) {
703 opts
->flags
|= TC_FLAG_ONLY_RESTORE
;
704 r
= modify_volume(opts
);
705 opts
->flags
&= ~TC_FLAG_ONLY_RESTORE
;
714 tc_api_task_info_get(tc_api_task task
, const char *key
, ...)
718 struct tcplay_info
*info
;
725 if (task
== NULL
|| ((info
= task
->last_info
) == NULL
)) {
731 sz
= va_arg(ap
, size_t);
738 if (_match(key
, "device")) {
739 s
= va_arg(ap
, char *);
740 strncpy(s
, info
->dev
, sz
);
742 } else if (_match(key
, "cipher")) {
743 s
= va_arg(ap
, char *);
744 tc_cipher_chain_sprint(buf
, sizeof(buf
), info
->cipher_chain
);
747 } else if (_match(key
, "prf")) {
748 s
= va_arg(ap
, char *);
750 strncpy(s
, info
->pbkdf_prf
->name
, sz
);
752 strncpy(s
, "(unknown)", sz
);
754 } else if (_match(key
, "key_bits")) {
755 if (sz
!= sizeof(int)) {
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)) {
768 i64p
= va_arg(ap
, int64_t *);
770 *i64p
= (int64_t)info
->size
* (int64_t)info
->hdr
->sec_sz
;
772 *i64p
= (int64_t)info
->size
* (int64_t)info
->blk_sz
;
773 } else if (_match(key
, "iv_offset")) {
774 if (sz
!= sizeof(int64_t)) {
779 i64p
= va_arg(ap
, int64_t *);
781 *i64p
= (int64_t)info
->skip
* (int64_t)info
->hdr
->sec_sz
;
783 *i64p
= (int64_t)info
->skip
* (int64_t)info
->blk_sz
;
784 } else if (_match(key
, "block_offset")) {
785 if (sz
!= sizeof(int64_t)) {
790 i64p
= va_arg(ap
, int64_t *);
792 *i64p
= (int64_t)info
->offset
* (int64_t)info
->hdr
->sec_sz
;
794 *i64p
= (int64_t)info
->offset
* (int64_t)info
->blk_sz
;