"Fossies" - the Fresh Open Source Software Archive

Member "tc-play-3.3/main.c" (2 Mar 2020, 17138 Bytes) of package /linux/misc/tc-play-3.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.1_vs_3.3.

    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 #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
   56 
   57 
   58 static
   59 void
   60 sig_handler(int sig)
   61 {
   62     if ((sig == SIGUSR1 || sig == SIGINFO) && (summary_fn != NULL))
   63         summary_fn();
   64 }
   65 
   66 static
   67 void
   68 usage(void)
   69 {
   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] [-p] [-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] [-p] [-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         " -p, --prompt-passphrase\n"
  173         "\t Immediately prompt for a passphrase even if a keyfile is supplied.\n"
  174         " -s <disk path>, --system-encryption=<disk path>\n"
  175         "\t Specifies that the disk (e.g. /dev/da0) is using system encryption.\n"
  176         " -t, --allow-trim\n"
  177         "\t Allow discards (TRIM command) on mapped volume.\n"
  178         " --fde\n"
  179         "\t Specifies that the disk (e.g. /dev/da0) is using full disk encryption.\n"
  180         " --use-backup\n"
  181         "\t Uses the backup headers (at the end of the volume) instead of the\n"
  182         "\t primary headers.\n"
  183         "\t This is useful when your primary headers have been corrupted.\n"
  184         " --use-hdr-file=<header file>\n"
  185         "\t Use the header in the specified file instead of the main header on the\n"
  186         "\t disk.\n"
  187         " --use-hidden-hdr-file=<header file>\n"
  188         "\t Use the header in the specified file instead of the hidden header on the\n"
  189         "\t disk.\n"
  190         "\n"
  191         "Valid options common to all commands are:\n"
  192         " -d <device path>, --device=<device path>\n"
  193         "\t Specifies the path to the volume to operate on (e.g. /dev/da0s1).\n"
  194         " -f <key file>, --keyfile-hidden=<key file>\n"
  195         "\t Specifies a key file to use for the hidden volume password derivation.\n"
  196         "\t This option is only valid in combination with -e, --protect-hidden\n"
  197         "\t or -g, --hidden.\n"
  198         " -k <key file>, --keyfile=<key file>\n"
  199         "\t Specifies a key file to use for the password derivation, can appear\n"
  200         "\t multiple times.\n"
  201         );
  202 
  203     exit(EXIT_FAILURE);
  204 }
  205 
  206 static struct option longopts[] = {
  207     { "create",     no_argument,        NULL, 'c' },
  208     { "cipher",     required_argument,  NULL, 'b' },
  209     { "cipher-hidden",  required_argument,  NULL, 'y' },
  210     { "hidden",     no_argument,        NULL, 'g' },
  211     { "pbkdf-prf",      required_argument,  NULL, 'a' },
  212     { "pbkdf-prf-hidden",   required_argument,  NULL, 'x' },
  213     { "info",       no_argument,        NULL, 'i' },
  214     { "info-mapped",    required_argument,  NULL, 'j' },
  215     { "map",        required_argument,  NULL, 'm' },
  216     { "keyfile",        required_argument,  NULL, 'k' },
  217     { "keyfile-hidden", required_argument,  NULL, 'f' },
  218     { "protect-hidden", no_argument,        NULL, 'e' },
  219     { "device",     required_argument,  NULL, 'd' },
  220     { "prompt-passphrase",  no_argument,        NULL, 'p' },
  221     { "system-encryption",  required_argument,  NULL, 's' },
  222     { "allow-trim",     no_argument,        NULL, 't' },
  223     { "fde",        no_argument,        NULL, FLAG_LONG_FDE },
  224     { "use-backup",     no_argument,        NULL, FLAG_LONG_USE_BACKUP },
  225     { "use-hdr-file",   required_argument,  NULL, FLAG_LONG_USE_HDR_FILE },
  226     { "use-hidden-hdr-file",required_argument,  NULL, FLAG_LONG_USE_HHDR_FILE },
  227     { "modify",     no_argument,        NULL, FLAG_LONG_MOD },
  228     { "new-keyfile",    required_argument,  NULL, FLAG_LONG_MOD_KF },
  229     { "new-pbkdf-prf",  required_argument,  NULL, FLAG_LONG_MOD_PRF },
  230     { "restore-from-backup-hdr", no_argument,   NULL, FLAG_LONG_MOD_NONE },
  231     { "save-hdr-backup",    required_argument,  NULL, FLAG_LONG_MOD_TO_FILE },
  232     { "unmap",      required_argument,  NULL, 'u' },
  233     { "version",        no_argument,        NULL, 'v' },
  234     { "weak-keys",      no_argument,        NULL, 'w' },
  235     { "insecure-erase", no_argument,        NULL, 'z' },
  236     { "help",       no_argument,        NULL, 'h' },
  237     { "no-retries",         no_argument,            NULL, FLAG_LONG_NO_RETRIES },
  238     { NULL,         0,          NULL, 0   },
  239 };
  240 
  241 #define _set_str_opt(opt) \
  242     do {                                    \
  243         if ((opts->opt = strdup_safe_mem(optarg)) == NULL) {        \
  244             fprintf(stderr, "Could not allocate safe mem.\n");  \
  245             exit(EXIT_FAILURE);                 \
  246         }                               \
  247     } while(0)
  248 
  249 int
  250 main(int argc, char *argv[])
  251 {
  252     struct tcplay_opts *opts;
  253     int ch, error;
  254     int info_vol = 0, map_vol = 0,
  255         unmap_vol = 0, info_map = 0,
  256         create_vol = 0, modify_vol = 0;
  257 
  258     if ((error = tc_play_init()) != 0) {
  259         fprintf(stderr, "Initialization failed, exiting.");
  260         exit(EXIT_FAILURE);
  261     }
  262 
  263     atexit(check_and_purge_safe_mem);
  264     signal(SIGUSR1, sig_handler);
  265     signal(SIGINFO, sig_handler);
  266 
  267     if ((opts = opts_init()) == NULL) {
  268         fprintf(stderr, "Initialization failed (opts), exiting.");
  269         exit(EXIT_FAILURE);
  270     }
  271 
  272     opts->interactive = 1;
  273 
  274     while ((ch = getopt_long(argc, argv, "a:b:cd:ef:ghij:k:m:ps:tu:vwx:y:z",
  275         longopts, NULL)) != -1) {
  276         switch(ch) {
  277         case 'a':
  278             if (opts->prf_algo != NULL)
  279                 usage();
  280             if ((opts->prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) {
  281                 if (strcmp(optarg, "help") == 0)
  282                     exit(EXIT_SUCCESS);
  283                 else
  284                     usage();
  285                 /* NOT REACHED */
  286             }
  287             break;
  288         case 'b':
  289             if (opts->cipher_chain != NULL)
  290                 usage();
  291             if ((opts->cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
  292                 if (strcmp(optarg, "help") == 0)
  293                     exit(EXIT_SUCCESS);
  294                 else
  295                     usage();
  296                 /* NOT REACHED */
  297             }
  298             break;
  299         case 'c':
  300             create_vol = 1;
  301             break;
  302         case 'd':
  303             _set_str_opt(dev);
  304             break;
  305         case 'e':
  306             opts->protect_hidden = 1;
  307             break;
  308         case 'f':
  309             if ((error = opts_add_keyfile_hidden(opts, optarg)) != 0) {
  310                 fprintf(stderr, "Could not add keyfile: %s\n", optarg);
  311                 exit(EXIT_FAILURE);
  312             }
  313             break;
  314         case 'g':
  315             opts->hidden = 1;
  316             break;
  317         case 'i':
  318             info_vol = 1;
  319             break;
  320         case 'j':
  321             info_map = 1;
  322             _set_str_opt(map_name);
  323             break;
  324         case 'k':
  325             if ((error = opts_add_keyfile(opts, optarg)) != 0) {
  326                 fprintf(stderr, "Could not add keyfile: %s\n", optarg);
  327                 exit(EXIT_FAILURE);
  328             }
  329             break;
  330         case 'm':
  331             map_vol = 1;
  332             _set_str_opt(map_name);
  333             break;
  334         case 'p':
  335             opts->prompt_passphrase = 1;
  336             break;
  337         case 's':
  338             opts->flags |= TC_FLAG_SYS;
  339             _set_str_opt(sys_dev);
  340             break;
  341         case 't':
  342             opts->flags |= TC_FLAG_ALLOW_TRIM;
  343             break;
  344         case 'u':
  345             unmap_vol = 1;
  346             _set_str_opt(map_name);
  347             break;
  348         case 'v':
  349             printf("tcplay v%d.%d\n", MAJ_VER, MIN_VER);
  350             exit(EXIT_SUCCESS);
  351             /* NOT REACHED */
  352         case 'w':
  353             fprintf(stderr, "WARNING: Using urandom as source of "
  354                 "entropy for key material is a really bad idea.\n");
  355             opts->weak_keys_and_salt = 1;
  356             break;
  357         case 'x':
  358             if (opts->h_prf_algo != NULL)
  359                 usage();
  360             if ((opts->h_prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) {
  361                 if (strcmp(optarg, "help") == 0)
  362                     exit(EXIT_SUCCESS);
  363                 else
  364                     usage();
  365                 /* NOT REACHED */
  366             }
  367             break;
  368         case 'y':
  369             if (opts->h_cipher_chain != NULL)
  370                 usage();
  371             if ((opts->h_cipher_chain = check_cipher_chain(optarg, 0)) == NULL) {
  372                 if (strcmp(optarg, "help") == 0)
  373                     exit(EXIT_SUCCESS);
  374                 else
  375                     usage();
  376                 /* NOT REACHED */
  377             }
  378             break;
  379         case 'z':
  380             opts->secure_erase = 0;
  381             break;
  382         case FLAG_LONG_FDE:
  383             opts->flags |= TC_FLAG_FDE;
  384             break;
  385         case FLAG_LONG_USE_BACKUP:
  386             opts->flags |= TC_FLAG_BACKUP;
  387             break;
  388         case FLAG_LONG_USE_HDR_FILE:
  389             opts->flags |= TC_FLAG_HDR_FROM_FILE;
  390             _set_str_opt(hdr_file_in);
  391             break;
  392         case FLAG_LONG_USE_HHDR_FILE:
  393             opts->flags |= TC_FLAG_H_HDR_FROM_FILE;
  394             _set_str_opt(h_hdr_file_in);
  395             break;
  396         case FLAG_LONG_MOD:
  397             modify_vol = 1;
  398             break;
  399         case FLAG_LONG_MOD_KF:
  400             if ((error = opts_add_keyfile_new(opts, optarg)) != 0) {
  401                 fprintf(stderr, "Could not add keyfile: %s\n", optarg);
  402                 exit(EXIT_FAILURE);
  403             }
  404             break;
  405         case FLAG_LONG_MOD_PRF:
  406             if (opts->new_prf_algo != NULL)
  407                 usage();
  408             if ((opts->new_prf_algo = check_prf_algo(optarg, 0, 0)) == NULL) {
  409                 if (strcmp(optarg, "help") == 0)
  410                     exit(EXIT_SUCCESS);
  411                 else
  412                     usage();
  413                 /* NOT REACHED */
  414             }
  415             break;
  416         case FLAG_LONG_MOD_NONE:
  417             opts->new_prf_algo = NULL;
  418             opts->flags |= TC_FLAG_ONLY_RESTORE;
  419             opts->flags |= TC_FLAG_BACKUP;
  420             break;
  421         case FLAG_LONG_MOD_TO_FILE:
  422             opts->flags |= TC_FLAG_SAVE_TO_FILE;
  423             _set_str_opt(hdr_file_out);
  424             break;
  425         case FLAG_LONG_NO_RETRIES:
  426             opts->retries = 1;
  427             break;
  428         case 'h':
  429         case '?':
  430         default:
  431             usage();
  432             /* NOT REACHED */
  433         }
  434     }
  435 
  436     argc -= optind;
  437     argv += optind;
  438 
  439     /* Check arguments */
  440     if (!(((map_vol || info_vol || create_vol || modify_vol) && opts->dev != NULL) ||
  441         ((unmap_vol || info_map) && opts->map_name != NULL)) ||
  442         (TC_FLAG_SET(opts->flags, SYS) && TC_FLAG_SET(opts->flags, FDE)) ||
  443         (map_vol + info_vol + create_vol + unmap_vol + info_map + modify_vol > 1) ||
  444         (opts->hidden && !create_vol) ||
  445         (TC_FLAG_SET(opts->flags, SYS) && (opts->sys_dev == NULL)) ||
  446         (TC_FLAG_SET(opts->flags, ONLY_RESTORE) && (opts->n_newkeyfiles > 0 || opts->new_prf_algo != NULL)) ||
  447         (TC_FLAG_SET(opts->flags, BACKUP) && (opts->sys_dev != NULL || TC_FLAG_SET(opts->flags, FDE))) ||
  448         (map_vol && (opts->map_name == NULL)) ||
  449         (unmap_vol && (opts->map_name == NULL)) ||
  450         (!modify_vol && opts->n_newkeyfiles > 0) ||
  451         (!modify_vol && opts->new_prf_algo != NULL) ||
  452         (!modify_vol && TC_FLAG_SET(opts->flags, ONLY_RESTORE)) ||
  453         (!modify_vol && TC_FLAG_SET(opts->flags, SAVE_TO_FILE)) ||
  454         (!(opts->protect_hidden || create_vol) && opts->n_hkeyfiles > 0)) {
  455         usage();
  456         /* NOT REACHED */
  457     }
  458 
  459     /* Create a new volume */
  460     if (create_vol) {
  461         error = create_volume(opts);
  462         if (error) {
  463             tc_log(1, "could not create new volume on %s\n", opts->dev);
  464         }
  465     } else if (info_map) {
  466         error = info_mapped_volume(opts);
  467     } else if (info_vol) {
  468         error = info_volume(opts);
  469     } else if (map_vol) {
  470         error = map_volume(opts);
  471     } else if (unmap_vol) {
  472         error = dm_teardown(opts->map_name, NULL);
  473     } else if (modify_vol) {
  474         error = modify_volume(opts);
  475     }
  476 
  477     return error;
  478 }
  479 
  480 #undef _set_str_opt