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