024f62db816c31aadafbde34e876ed425155f7bb
[dragonfly.git] / sbin / tcplay / main.c
1 /*
2  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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.
15  *
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.
28  */
29 #include <sys/types.h>
30 #include <getopt.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <err.h>
38 #include <time.h>
39 #include <libutil.h>
40
41 #include "tcplay.h"
42
43 static
44 void
45 sig_handler(int sig)
46 {
47         if ((sig == SIGUSR1 || sig == SIGINFO) && (summary_fn != NULL))
48                 summary_fn();
49 }
50
51 static
52 void
53 usage(void)
54 {
55         fprintf(stderr,
56             "Usage: tcplay <command> [options]\n"
57             "Valid commands and its arguments are:\n"
58             " -c, --create\n"
59             "\t Creates a new TC volume on the device specified by -d or --device\n"
60             " -i, --info\n"
61             "\t Gives information about the TC volume specified by -d or --device\n"
62             " -m <mapping name>, --map=<mapping name>\n"
63             "\t Creates a dm-crypt mapping with the given name for the device\n"
64             "\t specified by -d or --device\n"
65             "\n"
66             "Valid options and its arguments for 'create' are:\n"
67             " -a <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
68             "\t specifies which hashing function to use for the PBKDF password\n"
69             "\t derivation when creating a new volume\n"
70             "\t To see valid options, specify -a help\n"
71             " -b <cipher>, --cipher=<cipher>\n"
72             "\t specifies which cipher to use when creating a new TC volume\n"
73             "\t To see valid options, specify -b help\n"
74             " -x <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
75             "\t specifies which hashing function to use for the PBKDF password\n"
76             "\t derivation when creating a new hidden volume. By default, the\n"
77             "\t same as for the outer volume will be used\n"
78             "\t To see valid options, specify -a help\n"
79             " -y <cipher>, --cipher=<cipher>\n"
80             "\t specifies which cipher to use when creating a new hidden volume.\n"
81             "\t By default, the same as for the outer volume will be used\n"
82             "\t To see valid options, specify -b help\n"
83             " -g, --hidden\n"
84             "\t specifies that the newly created volume will contain a hidden volume\n"
85             "\n"
86             "Valid options and its arguments for 'info' and 'map' are:\n"
87             " -e, --protect-hidden\n"
88             "\t protect a hidden volume when mounting the outer volume\n"
89             " -s <disk path>, --system-encryption=<disk path>\n"
90             "\t specifies that the disk (e.g. /dev/da0) is using system encryption\n"
91             "\n"
92             "Valid options and its arguments common to all commands are:\n"
93             " -d <device path>, --device=<device path>\n"
94             "\t specifies the path to the volume to operate on (e.g. /dev/da0s1)\n"
95             " -k <key file>, --keyfile=<key file>\n"
96             "\t specifies a key file to use for the password derivation, can appear\n"
97             "\t multiple times\n"
98             " -f <key file>, --keyfile-hidden=<key file>\n"
99             "\t specifies a key file to use for the hidden volume password derivation\n"
100             "\t This option is only valid in combination with -e, --protect-hidden\n"
101             "\t or -g, --hidden\n"
102             );
103
104         exit(1);
105 }
106
107 static struct option longopts[] = {
108         { "create",             no_argument,            NULL, 'c' },
109         { "cipher",             required_argument,      NULL, 'b' },
110         { "cipher-hidden",      required_argument,      NULL, 'y' },
111         { "hidden",             no_argument,            NULL, 'g' },
112         { "pbkdf-prf",          required_argument,      NULL, 'a' },
113         { "pbkdf-prf-hidden",   required_argument,      NULL, 'x' },
114         { "info",               no_argument,            NULL, 'i' },
115         { "map",                required_argument,      NULL, 'm' },
116         { "keyfile",            required_argument,      NULL, 'k' },
117         { "keyfile-hidden",     required_argument,      NULL, 'f' },
118         { "protect-hidden",     no_argument,            NULL, 'e' },
119         { "device",             required_argument,      NULL, 'd' },
120         { "system-encryption",  required_argument,      NULL, 's' },
121         { "version",            no_argument,            NULL, 'v' },
122         { "help",               no_argument,            NULL, 'h' },
123         { NULL,                 0,                      NULL, 0   },
124 };
125
126 int
127 main(int argc, char *argv[])
128 {
129         const char *dev = NULL, *sys_dev = NULL, *map_name = NULL;
130         const char *keyfiles[MAX_KEYFILES];
131         const char *h_keyfiles[MAX_KEYFILES];
132         int nkeyfiles;
133         int n_hkeyfiles;
134         int ch, error;
135         int sflag = 0, info_vol = 0, map_vol = 0, protect_hidden = 0,
136             create_vol = 0, contain_hidden = 0;
137         struct pbkdf_prf_algo *prf = NULL;
138         struct tc_cipher_chain *cipher_chain = NULL;
139         struct pbkdf_prf_algo *h_prf = NULL;
140         struct tc_cipher_chain *h_cipher_chain = NULL;
141
142         if ((error = tc_play_init()) != 0) {
143                 fprintf(stderr, "Initialization failed, exiting.");
144                 exit(1);
145         }
146
147         atexit(check_and_purge_safe_mem);
148         signal(SIGUSR1, sig_handler);
149         signal(SIGINFO, sig_handler);
150
151         nkeyfiles = 0;
152         n_hkeyfiles = 0;
153
154         while ((ch = getopt_long(argc, argv, "a:b:cd:efgh:ik:m:s:vx:y:",
155             longopts, NULL)) != -1) {
156                 switch(ch) {
157                 case 'a':
158                         if (prf != NULL)
159                                 usage();
160                         if ((prf = check_prf_algo(optarg, 0)) == NULL) {
161                                 if (strcmp(optarg, "help") == 0)
162                                         exit(0);
163                                 else
164                                         usage();
165                                 /* NOT REACHED */
166                         }
167                         break;
168                 case 'b':
169                         if (cipher_chain != NULL)
170                                 usage();
171                         if ((cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
172                                 if (strcmp(optarg, "help") == 0)
173                                         exit(0);
174                                 else
175                                         usage();
176                                 /* NOT REACHED */
177                         }
178                         break;
179                 case 'c':
180                         create_vol = 1;
181                         break;
182                 case 'd':
183                         dev = optarg;
184                         break;
185                 case 'e':
186                         protect_hidden = 1;
187                         break;
188                 case 'f':
189                         h_keyfiles[n_hkeyfiles++] = optarg;
190                         break;
191                 case 'g':
192                         contain_hidden = 1;
193                         break;
194                 case 'i':
195                         info_vol = 1;
196                         break;
197                 case 'k':
198                         keyfiles[nkeyfiles++] = optarg;
199                         break;
200                 case 'm':
201                         map_vol = 1;
202                         map_name = optarg;
203                         break;
204                 case 's':
205                         sflag = 1;
206                         sys_dev = optarg;
207                         break;
208                 case 'v':
209                         printf("tcplay v%d.%d\n", MAJ_VER, MIN_VER);
210                         exit(0);
211                         /* NOT REACHED */
212                 case 'x':
213                         if (h_prf != NULL)
214                                 usage();
215                         if ((h_prf = check_prf_algo(optarg, 0)) == NULL) {
216                                 if (strcmp(optarg, "help") == 0)
217                                         exit(0);
218                                 else
219                                         usage();
220                                 /* NOT REACHED */
221                         }
222                         break;
223                 case 'y':
224                         if (h_cipher_chain != NULL)
225                                 usage();
226                         if ((h_cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
227                                 if (strcmp(optarg, "help") == 0)
228                                         exit(0);
229                                 else
230                                         usage();
231                                 /* NOT REACHED */
232                         }
233                         break;
234                 case 'h':
235                 case '?':
236                 default:
237                         usage();
238                         /* NOT REACHED */
239                 }
240         }
241
242         argc -= optind;
243         argv += optind;
244
245         /* Check arguments */
246         if (!((map_vol || info_vol || create_vol) && dev != NULL) ||
247             (map_vol && info_vol) ||
248             (map_vol && create_vol) ||
249             (create_vol && info_vol) ||
250             (contain_hidden && !create_vol) ||
251             (sflag && (sys_dev == NULL)) ||
252             (map_vol && (map_name == NULL)) ||
253             (!(protect_hidden || create_vol) && n_hkeyfiles > 0)) {
254                 usage();
255                 /* NOT REACHED */
256         }
257
258         /* Create a new volume */
259         if (create_vol) {
260                 error = create_volume(dev, contain_hidden, keyfiles, nkeyfiles,
261                     h_keyfiles, n_hkeyfiles, prf, cipher_chain, h_prf,
262                     h_cipher_chain, NULL, NULL,
263                     0, 1 /* interactive */);
264                 if (error) {
265                         tc_log(1, "could not create new volume on %s\n", dev);
266                 }
267         } else if (info_vol) {
268                 error = info_volume(dev, sflag, sys_dev, protect_hidden,
269                     keyfiles, nkeyfiles, h_keyfiles, n_hkeyfiles, NULL, NULL,
270                     1 /* interactive */, DEFAULT_RETRIES, 0);
271         } else if (map_vol) {
272                 error = map_volume(map_name,
273                     dev, sflag, sys_dev, protect_hidden,
274                     keyfiles, nkeyfiles, h_keyfiles, n_hkeyfiles, NULL, NULL,
275                     1 /* interactive */, DEFAULT_RETRIES, 0);
276         }
277
278         return error;
279 }