kernel - support dummy reallocblks in devfs
[dragonfly.git] / sbin / tcplay / main.c
blob1d15a7764e5ae39f88ea45bd93c922ff8fd507ff
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 <sys/types.h>
31 #include <getopt.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <inttypes.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <signal.h>
38 #include <time.h>
40 #include "tcplay.h"
42 #ifndef SIGINFO
43 #define SIGINFO SIGUSR1
44 #endif
46 #define FLAG_LONG_FDE 0xff01
47 #define FLAG_LONG_USE_BACKUP 0xff02
48 #define FLAG_LONG_MOD 0xff04
49 #define FLAG_LONG_MOD_KF 0xff08
50 #define FLAG_LONG_MOD_PRF 0xff10
51 #define FLAG_LONG_MOD_NONE 0xff20
52 #define FLAG_LONG_MOD_TO_FILE 0xff40
53 #define FLAG_LONG_USE_HDR_FILE 0xfe01
54 #define FLAG_LONG_USE_HHDR_FILE 0xfe02
55 #define FLAG_LONG_NO_RETRIES 0xfabc
58 static
59 void
60 sig_handler(int sig)
62 if ((sig == SIGUSR1 || sig == SIGINFO) && (summary_fn != NULL))
63 summary_fn();
66 static
67 void
68 usage(void)
70 fprintf(stderr,
71 "usage: tcplay -c -d device [-g] [-z] [-w] [-a pbkdf_hash] [-b cipher]\n"
72 " [-f keyfile_hidden] [-k keyfile] [-x pbkdf_hash] [-y cipher]\n"
73 " tcplay -i -d device [-e] [-f keyfile_hidden] [-k keyfile]\n"
74 " [-s system_device] [--fde] [--use-backup]\n"
75 " [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n"
76 " tcplay -m mapping -d device [-e] [-f keyfile_hidden] [-k keyfile]\n"
77 " [-s system_device] [--fde] [--use-backup] [--allow-trim]\n"
78 " [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n"
79 " tcplay --modify -d device [-k keyfile] [--new-keyfile=keyfile]\n"
80 " [--new-pbkdf-prf=pbkdf_hash] [-s system_device] [--fde]\n"
81 " [--use-backup] [--save-hdr-to-file=hdr_file] [-w]\n"
82 " [--use-hdr-file=hdr_file] [--use-hidden-hdr-file=hdr_file]\n"
83 " tcplay --modify -d device [-k keyfile] --restore-from-backup-hdr [-w]\n"
84 " tcplay -j mapping\n"
85 " tcplay -u mapping\n"
86 " tcplay -h | -v\n"
87 "\n"
88 "Valid commands are:\n"
89 " -c, --create\n"
90 "\t Creates a new TC volume on the device specified by -d or --device.\n"
91 " -h, --help\n"
92 "\t Print help message and exit.\n"
93 " -i, --info\n"
94 "\t Gives information about the TC volume specified by -d or --device.\n"
95 " -j <mapping name>, --info-mapped=<mapping name>\n"
96 "\t Gives information about the mapped TC volume under the given mapping.\n"
97 " -m <mapping name>, --map=<mapping name>\n"
98 "\t Creates a dm-crypt mapping with the given name for the device\n"
99 "\t specified by -d or --device.\n"
100 " -u <mapping name>, --unmap=<mapping name>\n"
101 "\t Removes a dm-crypt mapping with the given name.\n"
102 " --modify\n"
103 "\t Changes the volume's passphrase, keyfile and optionally the hashing\n"
104 "\t function used for the PBKDF password derivation.\n"
105 " -v, --version\n"
106 "\t Print version message and exit.\n"
107 "\n"
108 "Valid options for --create are:\n"
109 " -a <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
110 "\t Specifies which hashing function to use for the PBKDF password\n"
111 "\t derivation when creating a new volume.\n"
112 "\t To see valid options, specify '-a help'.\n"
113 " -b <cipher>, --cipher=<cipher>\n"
114 "\t Specifies which cipher to use when creating a new TC volume.\n"
115 "\t To see valid options, specify '-b help'.\n"
116 " -g, --hidden\n"
117 "\t Specifies that the newly created volume will contain a hidden volume.\n"
118 " -x <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
119 "\t Specifies which hashing function to use for the PBKDF password\n"
120 "\t derivation when creating a new hidden volume. By default, the\n"
121 "\t same as for the outer volume will be used.\n"
122 "\t To see valid options, specify '-x help'.\n"
123 " -y <cipher>, --cipher=<cipher>\n"
124 "\t Specifies which cipher to use when creating a new hidden volume.\n"
125 "\t By default, the same as for the outer volume will be used.\n"
126 "\t To see valid options, specify '-y help'.\n"
127 " -z, --insecure-erase\n"
128 "\t Skips the erase of the disk. Possible security hazard.\n"
129 " -w, --weak-keys\n"
130 "\t Uses a weak source of entropy (urandom) for key material.\n"
131 "\t WARNING: This is a REALLY REALLY bad idea for anything but\n"
132 "\t testing.\n"
133 "\n"
134 "Valid options for --modify are:\n"
135 " --new-keyfile=<key file>\n"
136 "\t Specifies a key file to use for the password derivation, when\n"
137 "\t re-encrypting the header, can appear multiple times.\n"
138 " --new-pbkdf-prf=<pbkdf prf algorithm>\n"
139 "\t Specifies which hashing function to use for the PBKDF password\n"
140 "\t derivation when re-encrypting the header.\n"
141 "\t To see valid options, specify '-a help'.\n"
142 " -s <disk path>, --system-encryption=<disk path>\n"
143 "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n"
144 " --fde\n"
145 "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n"
146 " --use-backup\n"
147 "\t Uses the backup headers (at the end of the volume) instead of the\n"
148 "\t primary headers. Both normal and backup headers will be modified!\n"
149 "\t This is useful when your primary headers have been corrupted.\n"
150 " --use-hdr-file=<header file>\n"
151 "\t Use the header in the specified file instead of the main header on the\n"
152 "\t disk as source for the modify operation.\n"
153 " --use-hidden-hdr-file=<header file>\n"
154 "\t Use the header in the specified file instead of the hidden header on the\n"
155 "\t disk as source for the modify operation.\n"
156 " --restore-from-backup-hdr\n"
157 "\t Implies --use-backup, no new PBKDF hashing function, no new keyfiles\n"
158 "\t and no new passphrase.\n"
159 "\t In other words, this will simply restore both headers from the backup\n"
160 "\t header. This option cannot be used to restore from a backup header file.\n"
161 " -w, --weak-keys\n"
162 "\t Uses a weak source of entropy (urandom) for salt material. The\n"
163 "\t key material is not affected, as the master keys are kept intact.\n"
164 "\t WARNING: This is a bad idea for anything but testing.\n"
165 " --save-hdr-backup=<header file>\n"
166 "\t Saves the modified header in the specified file instead of updating\n"
167 "\t the header files on disk.\n"
168 "\n"
169 "Valid options for --info and --map are:\n"
170 " -e, --protect-hidden\n"
171 "\t Protect a hidden volume when mounting the outer volume.\n"
172 " -s <disk path>, --system-encryption=<disk path>\n"
173 "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n"
174 " -t, --allow-trim\n"
175 "\t Allow discards (TRIM command) on mapped volume.\n"
176 " --fde\n"
177 "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n"
178 " --use-backup\n"
179 "\t Uses the backup headers (at the end of the volume) instead of the\n"
180 "\t primary headers.\n"
181 "\t This is useful when your primary headers have been corrupted.\n"
182 " --use-hdr-file=<header file>\n"
183 "\t Use the header in the specified file instead of the main header on the\n"
184 "\t disk.\n"
185 " --use-hidden-hdr-file=<header file>\n"
186 "\t Use the header in the specified file instead of the hidden header on the\n"
187 "\t disk.\n"
188 "\n"
189 "Valid options common to all commands are:\n"
190 " -d <device path>, --device=<device path>\n"
191 "\t Specifies the path to the volume to operate on (e.g. /dev/da0s1).\n"
192 " -f <key file>, --keyfile-hidden=<key file>\n"
193 "\t Specifies a key file to use for the hidden volume password derivation.\n"
194 "\t This option is only valid in combination with -e, --protect-hidden\n"
195 "\t or -g, --hidden.\n"
196 " -k <key file>, --keyfile=<key file>\n"
197 "\t Specifies a key file to use for the password derivation, can appear\n"
198 "\t multiple times.\n"
201 exit(EXIT_FAILURE);
204 static struct option longopts[] = {
205 { "create", no_argument, NULL, 'c' },
206 { "cipher", required_argument, NULL, 'b' },
207 { "cipher-hidden", required_argument, NULL, 'y' },
208 { "hidden", no_argument, NULL, 'g' },
209 { "pbkdf-prf", required_argument, NULL, 'a' },
210 { "pbkdf-prf-hidden", required_argument, NULL, 'x' },
211 { "info", no_argument, NULL, 'i' },
212 { "info-mapped", required_argument, NULL, 'j' },
213 { "map", required_argument, NULL, 'm' },
214 { "keyfile", required_argument, NULL, 'k' },
215 { "keyfile-hidden", required_argument, NULL, 'f' },
216 { "protect-hidden", no_argument, NULL, 'e' },
217 { "device", required_argument, NULL, 'd' },
218 { "system-encryption", required_argument, NULL, 's' },
219 { "allow-trim", no_argument, NULL, 't' },
220 { "fde", no_argument, NULL, FLAG_LONG_FDE },
221 { "use-backup", no_argument, NULL, FLAG_LONG_USE_BACKUP },
222 { "use-hdr-file", required_argument, NULL, FLAG_LONG_USE_HDR_FILE },
223 { "use-hidden-hdr-file",required_argument, NULL, FLAG_LONG_USE_HHDR_FILE },
224 { "modify", no_argument, NULL, FLAG_LONG_MOD },
225 { "new-keyfile", required_argument, NULL, FLAG_LONG_MOD_KF },
226 { "new-pbkdf-prf", required_argument, NULL, FLAG_LONG_MOD_PRF },
227 { "restore-from-backup-hdr", no_argument, NULL, FLAG_LONG_MOD_NONE },
228 { "save-hdr-backup", required_argument, NULL, FLAG_LONG_MOD_TO_FILE },
229 { "unmap", required_argument, NULL, 'u' },
230 { "version", no_argument, NULL, 'v' },
231 { "weak-keys", no_argument, NULL, 'w' },
232 { "insecure-erase", no_argument, NULL, 'z' },
233 { "help", no_argument, NULL, 'h' },
234 { "no-retries", no_argument, NULL, FLAG_LONG_NO_RETRIES },
235 { NULL, 0, NULL, 0 },
238 #define _set_str_opt(opt) \
239 do { \
240 if ((opts->opt = strdup_safe_mem(optarg)) == NULL) { \
241 fprintf(stderr, "Could not allocate safe mem.\n"); \
242 exit(EXIT_FAILURE); \
244 } while(0)
247 main(int argc, char *argv[])
249 struct tcplay_opts *opts;
250 int ch, error;
251 int info_vol = 0, map_vol = 0,
252 unmap_vol = 0, info_map = 0,
253 create_vol = 0, modify_vol = 0;
255 if ((error = tc_play_init()) != 0) {
256 fprintf(stderr, "Initialization failed, exiting.");
257 exit(EXIT_FAILURE);
260 atexit(check_and_purge_safe_mem);
261 signal(SIGUSR1, sig_handler);
262 signal(SIGINFO, sig_handler);
264 if ((opts = opts_init()) == NULL) {
265 fprintf(stderr, "Initialization failed (opts), exiting.");
266 exit(EXIT_FAILURE);
269 opts->interactive = 1;
271 while ((ch = getopt_long(argc, argv, "a:b:cd:ef:ghij:k:m:s:tu:vwx:y:z",
272 longopts, NULL)) != -1) {
273 switch(ch) {
274 case 'a':
275 if (opts->prf_algo != NULL)
276 usage();
277 if ((opts->prf_algo = check_prf_algo(optarg, 0)) == NULL) {
278 if (strcmp(optarg, "help") == 0)
279 exit(EXIT_SUCCESS);
280 else
281 usage();
282 /* NOT REACHED */
284 break;
285 case 'b':
286 if (opts->cipher_chain != NULL)
287 usage();
288 if ((opts->cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
289 if (strcmp(optarg, "help") == 0)
290 exit(EXIT_SUCCESS);
291 else
292 usage();
293 /* NOT REACHED */
295 break;
296 case 'c':
297 create_vol = 1;
298 break;
299 case 'd':
300 _set_str_opt(dev);
301 break;
302 case 'e':
303 opts->protect_hidden = 1;
304 break;
305 case 'f':
306 if ((error = opts_add_keyfile_hidden(opts, optarg)) != 0) {
307 fprintf(stderr, "Could not add keyfile: %s\n", optarg);
308 exit(EXIT_FAILURE);
310 break;
311 case 'g':
312 opts->hidden = 1;
313 break;
314 case 'i':
315 info_vol = 1;
316 break;
317 case 'j':
318 info_map = 1;
319 _set_str_opt(map_name);
320 break;
321 case 'k':
322 if ((error = opts_add_keyfile(opts, optarg)) != 0) {
323 fprintf(stderr, "Could not add keyfile: %s\n", optarg);
324 exit(EXIT_FAILURE);
326 break;
327 case 'm':
328 map_vol = 1;
329 _set_str_opt(map_name);
330 break;
331 case 's':
332 opts->flags |= TC_FLAG_SYS;
333 _set_str_opt(sys_dev);
334 break;
335 case 't':
336 opts->flags |= TC_FLAG_ALLOW_TRIM;
337 break;
338 case 'u':
339 unmap_vol = 1;
340 _set_str_opt(map_name);
341 break;
342 case 'v':
343 printf("tcplay v%d.%d\n", MAJ_VER, MIN_VER);
344 exit(EXIT_SUCCESS);
345 /* NOT REACHED */
346 case 'w':
347 fprintf(stderr, "WARNING: Using urandom as source of "
348 "entropy for key material is a really bad idea.\n");
349 opts->weak_keys_and_salt = 1;
350 break;
351 case 'x':
352 if (opts->h_prf_algo != NULL)
353 usage();
354 if ((opts->h_prf_algo = check_prf_algo(optarg, 0)) == NULL) {
355 if (strcmp(optarg, "help") == 0)
356 exit(EXIT_SUCCESS);
357 else
358 usage();
359 /* NOT REACHED */
361 break;
362 case 'y':
363 if (opts->h_cipher_chain != NULL)
364 usage();
365 if ((opts->h_cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
366 if (strcmp(optarg, "help") == 0)
367 exit(EXIT_SUCCESS);
368 else
369 usage();
370 /* NOT REACHED */
372 break;
373 case 'z':
374 opts->secure_erase = 0;
375 break;
376 case FLAG_LONG_FDE:
377 opts->flags |= TC_FLAG_FDE;
378 break;
379 case FLAG_LONG_USE_BACKUP:
380 opts->flags |= TC_FLAG_BACKUP;
381 break;
382 case FLAG_LONG_USE_HDR_FILE:
383 opts->flags |= TC_FLAG_HDR_FROM_FILE;
384 _set_str_opt(hdr_file_in);
385 break;
386 case FLAG_LONG_USE_HHDR_FILE:
387 opts->flags |= TC_FLAG_H_HDR_FROM_FILE;
388 _set_str_opt(h_hdr_file_in);
389 break;
390 case FLAG_LONG_MOD:
391 modify_vol = 1;
392 break;
393 case FLAG_LONG_MOD_KF:
394 if ((error = opts_add_keyfile_new(opts, optarg)) != 0) {
395 fprintf(stderr, "Could not add keyfile: %s\n", optarg);
396 exit(EXIT_FAILURE);
398 break;
399 case FLAG_LONG_MOD_PRF:
400 if (opts->new_prf_algo != NULL)
401 usage();
402 if ((opts->new_prf_algo = check_prf_algo(optarg, 0)) == NULL) {
403 if (strcmp(optarg, "help") == 0)
404 exit(EXIT_SUCCESS);
405 else
406 usage();
407 /* NOT REACHED */
409 break;
410 case FLAG_LONG_MOD_NONE:
411 opts->new_prf_algo = NULL;
412 opts->flags |= TC_FLAG_ONLY_RESTORE;
413 opts->flags |= TC_FLAG_BACKUP;
414 break;
415 case FLAG_LONG_MOD_TO_FILE:
416 opts->flags |= TC_FLAG_SAVE_TO_FILE;
417 _set_str_opt(hdr_file_out);
418 break;
419 case FLAG_LONG_NO_RETRIES:
420 opts->retries = 1;
421 break;
422 case 'h':
423 case '?':
424 default:
425 usage();
426 /* NOT REACHED */
430 argc -= optind;
431 argv += optind;
433 /* Check arguments */
434 if (!(((map_vol || info_vol || create_vol || modify_vol) && opts->dev != NULL) ||
435 ((unmap_vol || info_map) && opts->map_name != NULL)) ||
436 (TC_FLAG_SET(opts->flags, SYS) && TC_FLAG_SET(opts->flags, FDE)) ||
437 (map_vol + info_vol + create_vol + unmap_vol + info_map + modify_vol > 1) ||
438 (opts->hidden && !create_vol) ||
439 (TC_FLAG_SET(opts->flags, SYS) && (opts->sys_dev == NULL)) ||
440 (TC_FLAG_SET(opts->flags, ONLY_RESTORE) && (opts->n_newkeyfiles > 0 || opts->new_prf_algo != NULL)) ||
441 (TC_FLAG_SET(opts->flags, BACKUP) && (opts->sys_dev != NULL || TC_FLAG_SET(opts->flags, FDE))) ||
442 (map_vol && (opts->map_name == NULL)) ||
443 (unmap_vol && (opts->map_name == NULL)) ||
444 (!modify_vol && opts->n_newkeyfiles > 0) ||
445 (!modify_vol && opts->new_prf_algo != NULL) ||
446 (!modify_vol && TC_FLAG_SET(opts->flags, ONLY_RESTORE)) ||
447 (!modify_vol && TC_FLAG_SET(opts->flags, SAVE_TO_FILE)) ||
448 (!(opts->protect_hidden || create_vol) && opts->n_hkeyfiles > 0)) {
449 usage();
450 /* NOT REACHED */
453 /* Create a new volume */
454 if (create_vol) {
455 error = create_volume(opts);
456 if (error) {
457 tc_log(1, "could not create new volume on %s\n", opts->dev);
459 } else if (info_map) {
460 error = info_mapped_volume(opts);
461 } else if (info_vol) {
462 error = info_volume(opts);
463 } else if (map_vol) {
464 error = map_volume(opts);
465 } else if (unmap_vol) {
466 error = dm_teardown(opts->map_name, NULL);
467 } else if (modify_vol) {
468 error = modify_volume(opts);
471 return error;
474 #undef _set_str_opt