mirror of
https://github.com/Aorimn/dislocker
synced 2026-06-08 10:24:29 +00:00
d3a714dbb6
These typos has been identified in Debian and are currently patched there.
831 lines
21 KiB
C
831 lines
21 KiB
C
/* -*- coding: utf-8 -*- */
|
|
/* -*- mode: c -*- */
|
|
/*
|
|
* Dislocker -- enables to read/write on BitLocker encrypted partitions under
|
|
* Linux
|
|
* Copyright (C) 2012-2013 Romain Coltel, Hervé Schauer Consultants
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
* USA.
|
|
*/
|
|
|
|
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
|
|
#include "dislocker/common.h"
|
|
#include "dislocker/config.priv.h"
|
|
#include "dislocker/dislocker.priv.h"
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Hide a commandline option, replacing the actual optarg by 'X's.
|
|
*
|
|
* @param opt The option to hide
|
|
*/
|
|
static void hide_opt(char* opt)
|
|
{
|
|
if(!opt)
|
|
return;
|
|
|
|
size_t len = strlen(opt);
|
|
|
|
while(len)
|
|
{
|
|
opt[--len] = 'X';
|
|
}
|
|
}
|
|
|
|
|
|
/* These functions are wrappers around the appropriate dis_setopt call */
|
|
static void setclearkey(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
(void) optarg;
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_CLEAR_KEY, &trueval);
|
|
}
|
|
static void setbekfile(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_BEK_FILE, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_BEK_FILE_PATH, optarg);
|
|
}
|
|
static void setforceblock(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
off_t force;
|
|
if(optarg)
|
|
force = (unsigned char) strtol(optarg, NULL, 10);
|
|
else
|
|
force = 1;
|
|
dis_setopt(dis_ctx, DIS_OPT_FORCE_BLOCK, &force);
|
|
}
|
|
static void setfvek(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_FVEK_FILE, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_FVEK_FILE_PATH, optarg);
|
|
}
|
|
static void setvmk(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_VMK_FILE, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_VMK_FILE_PATH, optarg);
|
|
}
|
|
static void setlogfile(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_LOG_FILE_PATH, optarg);
|
|
}
|
|
static void setoffset(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
off_t offset = (off_t) strtoll(optarg, NULL, 10);
|
|
dis_setopt(dis_ctx, DIS_OPT_VOLUME_OFFSET, &offset);
|
|
}
|
|
static void setrecoverypwd(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_RECOVERY_PASSWORD, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_RECOVERY_PASSWORD, optarg);
|
|
hide_opt(optarg);
|
|
}
|
|
static void setquiet(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
(void) optarg;
|
|
DIS_LOGS l = L_QUIET;
|
|
dis_setopt(dis_ctx, DIS_OPT_VERBOSITY, &l);
|
|
}
|
|
static void setro(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
(void) optarg;
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_READ_ONLY, &trueval);
|
|
}
|
|
static void setstateok(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
(void) optarg;
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_DONT_CHECK_VOLUME_STATE, &trueval);
|
|
}
|
|
static void setuserpassword(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
int trueval = TRUE;
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_USER_PASSWORD, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_USER_PASSWORD, optarg);
|
|
hide_opt(optarg);
|
|
}
|
|
static void setverbosity(dis_context_t dis_ctx, char* optarg)
|
|
{
|
|
dis_ctx->cfg.verbosity = (DIS_LOGS)strtol(optarg, NULL, 10);
|
|
}
|
|
|
|
|
|
/* Structure used to define dislocker's options */
|
|
struct _dis_options {
|
|
struct option opt;
|
|
void (*fn)(dis_context_t dis_ctx, char* optarg);
|
|
};
|
|
|
|
static struct _dis_options dis_opt[] = {
|
|
{ {"clearkey", no_argument, NULL, 'c'}, setclearkey },
|
|
{ {"bekfile", required_argument, NULL, 'f'}, setbekfile },
|
|
{ {"force-block", optional_argument, NULL, 'F'}, setforceblock },
|
|
{ {"help", no_argument, NULL, 'h'}, NULL },
|
|
{ {"fvek", required_argument, NULL, 'k'}, setfvek },
|
|
{ {"vmk", required_argument, NULL, 'K'}, setvmk },
|
|
{ {"logfile", required_argument, NULL, 'l'}, setlogfile },
|
|
{ {"offset", required_argument, NULL, 'O'}, setoffset },
|
|
{ {"options", required_argument, NULL, 'o'}, NULL },
|
|
{ {"recovery-password", optional_argument, NULL, 'p'}, setrecoverypwd },
|
|
{ {"quiet", no_argument, NULL, 'q'}, setquiet },
|
|
{ {"readonly", no_argument, NULL, 'r'}, setro },
|
|
{ {"ro", no_argument, NULL, 'r'}, setro },
|
|
{ {"stateok", no_argument, NULL, 's'}, setstateok },
|
|
{ {"user-password", optional_argument, NULL, 'u'}, setuserpassword },
|
|
{ {"verbosity", no_argument, NULL, 'v'}, setverbosity },
|
|
{ {"volume", required_argument, NULL, 'V'}, NULL }
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Print program's usage
|
|
*/
|
|
void dis_usage()
|
|
{
|
|
fprintf(stderr,
|
|
PROGNAME " by " AUTHOR ", v" VERSION " (compiled for " __OS "/" __ARCH ")\n"
|
|
#ifdef VERSION_DBG
|
|
"Compiled version: " VERSION_DBG "\n"
|
|
#endif
|
|
"\n"
|
|
"Usage: " PROGNAME " [-hqrsv] [-l LOG_FILE] [-O OFFSET] [-V VOLUME DECRYPTMETHOD -F[N]] [-- ARGS...]\n"
|
|
" with DECRYPTMETHOD = -p[RECOVERY_PASSWORD]|-f BEK_FILE|-u[USER_PASSWORD]|-k FVEK_FILE|-K VMK_FILE|-c\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" -c, --clearkey decrypt volume using a clear key (default)\n"
|
|
" -f, --bekfile BEKFILE\n"
|
|
" decrypt volume using the bek file (on USB key)\n"
|
|
" -F, --force-block=[N] force use of metadata block number N (1, 2 or 3)\n"
|
|
" -h, --help print this help and exit\n"
|
|
" -k, --fvek FVEK_FILE decrypt volume using the FVEK directly\n"
|
|
" -K, --vmk VMK_FILE decrypt volume using the VMK directly\n"
|
|
" -l, --logfile LOG_FILE\n"
|
|
" put messages into this file (stdout by default)\n"
|
|
" -O, --offset OFFSET BitLocker partition offset, in bytes (default is 0)\n"
|
|
" -p, --recovery-password=[RECOVERY_PASSWORD]\n"
|
|
" decrypt volume using the recovery password method\n"
|
|
" -q, --quiet do NOT display anything\n"
|
|
" -r, --readonly do not allow one to write on the BitLocker volume\n"
|
|
" -s, --stateok do not check the volume's state, assume it's ok to mount it\n"
|
|
" -u, --user-password=[USER_PASSWORD]\n"
|
|
" decrypt volume using the user password method\n"
|
|
" -v, --verbosity increase verbosity (CRITICAL errors are displayed by default)\n"
|
|
" -V, --volume VOLUME volume to get metadata and keys from\n"
|
|
"\n"
|
|
" -- end of program options, beginning of FUSE's ones\n"
|
|
"\n"
|
|
" ARGS are any arguments you want to pass to FUSE. You need to pass at least\n"
|
|
"the mount-point.\n"
|
|
"\n"
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse the --options parameter's value
|
|
*
|
|
* @param dis_ctx Dislocker's context
|
|
* @param optstr The value passed with the --options parameter
|
|
*/
|
|
static void parse_options(dis_context_t dis_ctx, char* optstr)
|
|
{
|
|
char* tok = NULL;
|
|
size_t nb_options = sizeof(dis_opt)/sizeof(struct _dis_options);
|
|
size_t i;
|
|
size_t opt_len;
|
|
|
|
tok = strtok(optstr, ",");
|
|
while(tok != NULL)
|
|
{
|
|
for(i = 0; i < nb_options; i++)
|
|
{
|
|
opt_len = strlen(dis_opt[i].opt.name);
|
|
if(strncmp(dis_opt[i].opt.name, tok, opt_len) == 0)
|
|
{
|
|
if(tok[opt_len] == '=' && tok[opt_len] != '\0')
|
|
dis_opt[i].fn(dis_ctx, &tok[opt_len + 1]);
|
|
else
|
|
dis_opt[i].fn(dis_ctx, NULL);
|
|
}
|
|
}
|
|
|
|
tok = strtok(NULL, ",");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse arguments strings
|
|
*
|
|
* @warning If -h/--help is encountered, the help is printed and the program
|
|
* exits (using exit(EXIT_SUCCESS)).
|
|
*
|
|
* @param dis_ctx Dislocker's context
|
|
* @param argc Number of arguments given to the program
|
|
* @param argv Arguments given to the program
|
|
* @return Return the number of arguments which are still waiting to be studied.
|
|
* If -1 is returned, then an error occurred and the configuration isn't set.
|
|
*/
|
|
int dis_getopts(dis_context_t dis_ctx, int argc, char** argv)
|
|
{
|
|
/** See man getopt_long(3) */
|
|
extern int optind;
|
|
int optchar = 0;
|
|
size_t nb_options = sizeof(dis_opt)/sizeof(struct _dis_options);
|
|
|
|
|
|
/* Options which could be passed as argument */
|
|
const char short_opts[] = "cf:F::hk:K:l:O:o:p::qrsu::vV:";
|
|
struct option* long_opts;
|
|
|
|
if(!dis_ctx || !argv)
|
|
return -1;
|
|
|
|
dis_config_t* cfg = &dis_ctx->cfg;
|
|
int trueval = TRUE;
|
|
|
|
|
|
long_opts = malloc(nb_options * sizeof(struct option));
|
|
while(nb_options--)
|
|
{
|
|
long_opts[nb_options].name = dis_opt[nb_options].opt.name;
|
|
long_opts[nb_options].has_arg = dis_opt[nb_options].opt.has_arg;
|
|
long_opts[nb_options].flag = dis_opt[nb_options].opt.flag;
|
|
long_opts[nb_options].val = dis_opt[nb_options].opt.val;
|
|
}
|
|
|
|
|
|
while((optchar = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1)
|
|
{
|
|
switch(optchar)
|
|
{
|
|
case 'c':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_CLEAR_KEY, &trueval);
|
|
break;
|
|
}
|
|
case 'f':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_BEK_FILE, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_BEK_FILE_PATH, optarg);
|
|
break;
|
|
}
|
|
case 'F':
|
|
{
|
|
off_t force;
|
|
if(optarg)
|
|
force = (unsigned char) strtol(optarg, NULL, 10);
|
|
else
|
|
force = 1;
|
|
dis_setopt(dis_ctx, DIS_OPT_FORCE_BLOCK, &force);
|
|
break;
|
|
}
|
|
case 'h':
|
|
{
|
|
dis_usage();
|
|
dis_free_args(dis_ctx);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
case 'k':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_FVEK_FILE, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_FVEK_FILE_PATH, optarg);
|
|
break;
|
|
}
|
|
case 'K':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_VMK_FILE, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_VMK_FILE_PATH, optarg);
|
|
break;
|
|
}
|
|
case 'l':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_LOG_FILE_PATH, optarg);
|
|
break;
|
|
}
|
|
case 'O':
|
|
{
|
|
off_t offset = (off_t) strtoll(optarg, NULL, 10);
|
|
dis_setopt(dis_ctx, DIS_OPT_VOLUME_OFFSET, &offset);
|
|
break;
|
|
}
|
|
case 'o':
|
|
{
|
|
parse_options(dis_ctx, optarg);
|
|
break;
|
|
}
|
|
case 'p':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_RECOVERY_PASSWORD, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_RECOVERY_PASSWORD, optarg);
|
|
hide_opt(optarg);
|
|
break;
|
|
}
|
|
case 'q':
|
|
{
|
|
DIS_LOGS l = L_QUIET;
|
|
dis_setopt(dis_ctx, DIS_OPT_VERBOSITY, &l);
|
|
break;
|
|
}
|
|
case 'r':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_READ_ONLY, &trueval);
|
|
break;
|
|
}
|
|
case 's':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_DONT_CHECK_VOLUME_STATE, &trueval);
|
|
break;
|
|
}
|
|
case 'u':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_USE_USER_PASSWORD, &trueval);
|
|
dis_setopt(dis_ctx, DIS_OPT_SET_USER_PASSWORD, optarg);
|
|
hide_opt(optarg);
|
|
break;
|
|
}
|
|
case 'v':
|
|
{
|
|
if(cfg->verbosity != L_QUIET)
|
|
cfg->verbosity++;
|
|
break;
|
|
}
|
|
case 'V':
|
|
{
|
|
dis_setopt(dis_ctx, DIS_OPT_VOLUME_PATH, optarg);
|
|
break;
|
|
}
|
|
case '?':
|
|
default:
|
|
{
|
|
dis_usage();
|
|
free(long_opts);
|
|
dis_free_args(dis_ctx);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Check verbosity */
|
|
if(cfg->verbosity > L_DEBUG)
|
|
cfg->verbosity = L_DEBUG;
|
|
if(cfg->verbosity < L_CRITICAL)
|
|
cfg->verbosity = L_CRITICAL;
|
|
|
|
/* Check decryption method */
|
|
if(!cfg->decryption_mean)
|
|
cfg->decryption_mean |= DIS_USE_CLEAR_KEY;
|
|
|
|
/* Check if a block is forced */
|
|
if(cfg->force_block != 1 &&
|
|
cfg->force_block != 2 &&
|
|
cfg->force_block != 3)
|
|
cfg->force_block = 0;
|
|
|
|
free(long_opts);
|
|
|
|
return optind;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get dislocker's option
|
|
*
|
|
* @param dis_ctx Dislocker's context
|
|
* @param opt_name The option's name to get
|
|
* @param opt_value The retrieved value of the option. This is stored in
|
|
*opt_value.
|
|
*/
|
|
int dis_getopt(dis_context_t dis_ctx, dis_opt_e opt_name, void** opt_value)
|
|
{
|
|
if (!dis_ctx || !opt_value)
|
|
return FALSE;
|
|
|
|
dis_config_t* cfg = &dis_ctx->cfg;
|
|
|
|
switch(opt_name)
|
|
{
|
|
case DIS_OPT_VOLUME_PATH:
|
|
*opt_value = cfg->volume_path;
|
|
break;
|
|
case DIS_OPT_USE_CLEAR_KEY:
|
|
if(cfg->decryption_mean & DIS_USE_CLEAR_KEY)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_USE_BEK_FILE:
|
|
if(cfg->decryption_mean & DIS_USE_BEKFILE)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_SET_BEK_FILE_PATH:
|
|
*opt_value = cfg->bek_file;
|
|
break;
|
|
case DIS_OPT_USE_RECOVERY_PASSWORD:
|
|
if(cfg->decryption_mean & DIS_USE_RECOVERY_PASSWORD)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_SET_RECOVERY_PASSWORD:
|
|
*opt_value = cfg->recovery_password;
|
|
break;
|
|
case DIS_OPT_USE_USER_PASSWORD:
|
|
if(cfg->decryption_mean & DIS_USE_USER_PASSWORD)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_SET_USER_PASSWORD:
|
|
*opt_value = cfg->user_password;
|
|
break;
|
|
case DIS_OPT_USE_FVEK_FILE:
|
|
if(cfg->decryption_mean & DIS_USE_FVEKFILE)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_SET_FVEK_FILE_PATH:
|
|
*opt_value = cfg->fvek_file;
|
|
break;
|
|
case DIS_OPT_USE_VMK_FILE:
|
|
if(cfg->decryption_mean & DIS_USE_VMKFILE)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_SET_VMK_FILE_PATH:
|
|
*opt_value = cfg->vmk_file;
|
|
break;
|
|
case DIS_OPT_VERBOSITY:
|
|
*opt_value = (void*) cfg->verbosity;
|
|
break;
|
|
case DIS_OPT_LOG_FILE_PATH:
|
|
*opt_value = cfg->log_file;
|
|
break;
|
|
case DIS_OPT_FORCE_BLOCK:
|
|
*opt_value = (void*) ((long) cfg->force_block);
|
|
break;
|
|
case DIS_OPT_VOLUME_OFFSET:
|
|
*opt_value = (void*) cfg->offset;
|
|
break;
|
|
case DIS_OPT_READ_ONLY:
|
|
if(cfg->flags & DIS_FLAG_READ_ONLY)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_DONT_CHECK_VOLUME_STATE:
|
|
if(cfg->flags & DIS_FLAG_DONT_CHECK_VOLUME_STATE)
|
|
*opt_value = (void*) TRUE;
|
|
else
|
|
*opt_value = (void*) FALSE;
|
|
break;
|
|
case DIS_OPT_INITIALIZE_STATE:
|
|
*opt_value = (void*) cfg->init_stop_at;
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void set_decryption_mean(dis_config_t* cfg, int set, unsigned value)
|
|
{
|
|
if(set == TRUE)
|
|
cfg->decryption_mean |= value;
|
|
else
|
|
cfg->decryption_mean &= (unsigned) ~value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Modify dislocker's options one-by-one
|
|
*
|
|
* @param dis_ctx Dislocker's context
|
|
* @param opt_name The option's name to change
|
|
* @param opt_value The new value of the option. Note that this is a pointer. If
|
|
* NULL, the default value -which is not necessarily usable- will be set.
|
|
*/
|
|
int dis_setopt(dis_context_t dis_ctx, dis_opt_e opt_name, const void* opt_value)
|
|
{
|
|
if (!dis_ctx)
|
|
return FALSE;
|
|
|
|
dis_config_t* cfg = &dis_ctx->cfg;
|
|
|
|
switch(opt_name)
|
|
{
|
|
case DIS_OPT_VOLUME_PATH:
|
|
if(cfg->volume_path != NULL)
|
|
free(cfg->volume_path);
|
|
if(opt_value == NULL)
|
|
cfg->volume_path = NULL;
|
|
else
|
|
cfg->volume_path = strdup((const char*) opt_value);
|
|
break;
|
|
case DIS_OPT_USE_CLEAR_KEY:
|
|
if(opt_value == NULL)
|
|
cfg->decryption_mean &= (unsigned) ~DIS_USE_CLEAR_KEY;
|
|
else
|
|
set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_CLEAR_KEY);
|
|
break;
|
|
case DIS_OPT_USE_BEK_FILE:
|
|
if(opt_value == NULL)
|
|
cfg->decryption_mean &= (unsigned) ~DIS_USE_BEKFILE;
|
|
else
|
|
set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_BEKFILE);
|
|
break;
|
|
case DIS_OPT_SET_BEK_FILE_PATH:
|
|
if(cfg->bek_file != NULL)
|
|
free(cfg->bek_file);
|
|
if(opt_value == NULL)
|
|
cfg->bek_file = NULL;
|
|
else
|
|
cfg->bek_file = strdup((const char*) opt_value);
|
|
break;
|
|
case DIS_OPT_USE_RECOVERY_PASSWORD:
|
|
if(opt_value == NULL)
|
|
cfg->decryption_mean &= (unsigned) ~DIS_USE_RECOVERY_PASSWORD;
|
|
else
|
|
set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_RECOVERY_PASSWORD);
|
|
break;
|
|
case DIS_OPT_SET_RECOVERY_PASSWORD:
|
|
if(cfg->recovery_password != NULL)
|
|
free(cfg->recovery_password);
|
|
if(opt_value == NULL)
|
|
cfg->recovery_password = NULL;
|
|
else
|
|
{
|
|
const char* v = (const char*) opt_value;
|
|
cfg->recovery_password = (uint8_t *) strdup(v);
|
|
}
|
|
break;
|
|
case DIS_OPT_USE_USER_PASSWORD:
|
|
if(opt_value == NULL)
|
|
cfg->decryption_mean &= (unsigned) ~DIS_USE_USER_PASSWORD;
|
|
else
|
|
set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_USER_PASSWORD);
|
|
break;
|
|
case DIS_OPT_SET_USER_PASSWORD:
|
|
if(cfg->user_password != NULL)
|
|
free(cfg->user_password);
|
|
if(opt_value == NULL)
|
|
cfg->user_password = NULL;
|
|
else
|
|
{
|
|
const char* v = (const char*) opt_value;
|
|
cfg->user_password = (uint8_t *) strdup(v);
|
|
}
|
|
break;
|
|
case DIS_OPT_USE_FVEK_FILE:
|
|
if(opt_value == NULL)
|
|
cfg->decryption_mean &= (unsigned) ~DIS_USE_FVEKFILE;
|
|
else
|
|
set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_FVEKFILE);
|
|
break;
|
|
case DIS_OPT_SET_FVEK_FILE_PATH:
|
|
if(cfg->fvek_file != NULL)
|
|
free(cfg->fvek_file);
|
|
if(opt_value == NULL)
|
|
cfg->fvek_file = NULL;
|
|
else
|
|
cfg->fvek_file = strdup((const char*) opt_value);
|
|
break;
|
|
case DIS_OPT_USE_VMK_FILE:
|
|
if(opt_value == NULL)
|
|
cfg->decryption_mean &= (unsigned) ~DIS_USE_VMKFILE;
|
|
else
|
|
set_decryption_mean(cfg, *(int*) opt_value, DIS_USE_VMKFILE);
|
|
break;
|
|
case DIS_OPT_SET_VMK_FILE_PATH:
|
|
if(cfg->vmk_file != NULL)
|
|
free(cfg->vmk_file);
|
|
if(opt_value == NULL)
|
|
cfg->vmk_file = NULL;
|
|
else
|
|
cfg->vmk_file = strdup((const char*) opt_value);
|
|
break;
|
|
case DIS_OPT_VERBOSITY:
|
|
if(opt_value == NULL)
|
|
cfg->verbosity = 0;
|
|
else
|
|
{
|
|
DIS_LOGS l = *(DIS_LOGS*) opt_value;
|
|
if(l >= L_QUIET && l <= L_DEBUG)
|
|
cfg->verbosity = l;
|
|
else
|
|
cfg->verbosity = 0;
|
|
}
|
|
break;
|
|
case DIS_OPT_LOG_FILE_PATH:
|
|
if(cfg->log_file != NULL)
|
|
free(cfg->log_file);
|
|
if(opt_value == NULL)
|
|
cfg->log_file = NULL;
|
|
else
|
|
cfg->log_file = strdup((const char*) opt_value);
|
|
break;
|
|
case DIS_OPT_FORCE_BLOCK:
|
|
if(opt_value == NULL)
|
|
cfg->force_block = 0;
|
|
else
|
|
{
|
|
int uc = *(int*) opt_value;
|
|
if(uc >= 1 && uc <= 3)
|
|
cfg->force_block = (unsigned char) uc;
|
|
else
|
|
cfg->force_block = 0;
|
|
}
|
|
break;
|
|
case DIS_OPT_VOLUME_OFFSET:
|
|
if(opt_value == NULL)
|
|
cfg->offset = 0;
|
|
else
|
|
cfg->offset = *(off_t*) opt_value;
|
|
break;
|
|
case DIS_OPT_READ_ONLY:
|
|
if(opt_value == NULL)
|
|
cfg->flags &= (unsigned) ~DIS_FLAG_READ_ONLY;
|
|
else
|
|
{
|
|
int flag = *(int*) opt_value;
|
|
if(flag == TRUE)
|
|
cfg->flags |= DIS_FLAG_READ_ONLY;
|
|
else
|
|
cfg->flags &= (unsigned) ~DIS_FLAG_READ_ONLY;
|
|
}
|
|
break;
|
|
case DIS_OPT_DONT_CHECK_VOLUME_STATE:
|
|
if(opt_value == NULL)
|
|
cfg->flags &= (unsigned) ~DIS_FLAG_DONT_CHECK_VOLUME_STATE;
|
|
else
|
|
{
|
|
int flag = *(int*) opt_value;
|
|
if(flag == TRUE)
|
|
cfg->flags |= DIS_FLAG_DONT_CHECK_VOLUME_STATE;
|
|
else
|
|
cfg->flags &= (unsigned) ~DIS_FLAG_DONT_CHECK_VOLUME_STATE;
|
|
}
|
|
break;
|
|
case DIS_OPT_INITIALIZE_STATE:
|
|
if(opt_value == NULL)
|
|
cfg->init_stop_at = DIS_STATE_COMPLETE_EVERYTHING;
|
|
else
|
|
{
|
|
dis_state_e state = *(dis_state_e*) opt_value;
|
|
cfg->init_stop_at = state;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Free dis_config_t members
|
|
*
|
|
* @param cfg Dislocker's config
|
|
*/
|
|
void dis_free_args(dis_context_t dis_ctx)
|
|
{
|
|
if (!dis_ctx)
|
|
return;
|
|
|
|
dis_config_t* cfg = &dis_ctx->cfg;
|
|
|
|
if(cfg->recovery_password)
|
|
memclean(cfg->recovery_password,
|
|
strlen((char*)cfg->recovery_password) + sizeof(char));
|
|
|
|
if(cfg->user_password)
|
|
memclean(cfg->user_password,
|
|
strlen((char*)cfg->user_password) + sizeof(char));
|
|
|
|
if(cfg->bek_file)
|
|
memclean(cfg->bek_file, strlen(cfg->bek_file) + sizeof(char));
|
|
|
|
if(cfg->fvek_file)
|
|
memclean(cfg->fvek_file, strlen(cfg->fvek_file) + sizeof(char));
|
|
|
|
if(cfg->vmk_file)
|
|
memclean(cfg->vmk_file, strlen(cfg->vmk_file) + sizeof(char));
|
|
|
|
if(cfg->volume_path)
|
|
dis_free(cfg->volume_path);
|
|
|
|
if(cfg->log_file)
|
|
dis_free(cfg->log_file);
|
|
}
|
|
|
|
|
|
/**
|
|
* Print read configuration
|
|
*/
|
|
void dis_print_args(dis_context_t dis_ctx)
|
|
{
|
|
if(!dis_ctx)
|
|
return;
|
|
|
|
dis_config_t* cfg = &dis_ctx->cfg;
|
|
|
|
dis_printf(L_DEBUG, "--- Config...\n");
|
|
dis_printf(L_DEBUG, " Verbosity: %d\n", cfg->verbosity);
|
|
dis_printf(L_DEBUG, " Trying to decrypt '%s'\n", cfg->volume_path);
|
|
|
|
if(cfg->decryption_mean & DIS_USE_CLEAR_KEY)
|
|
{
|
|
dis_printf(L_DEBUG, " \tusing a clear key on the volume\n");
|
|
}
|
|
else if(cfg->decryption_mean & DIS_USE_USER_PASSWORD)
|
|
{
|
|
dis_printf(L_DEBUG, " \tusing the user's password method\n");
|
|
dis_printf(L_DEBUG, " \t\t-> '%s'\n", cfg->user_password);
|
|
}
|
|
else if(cfg->decryption_mean & DIS_USE_RECOVERY_PASSWORD)
|
|
{
|
|
dis_printf(L_DEBUG, " \tusing the recovery password method\n");
|
|
dis_printf(L_DEBUG, " \t\t-> '%s'\n", cfg->recovery_password);
|
|
}
|
|
else if(cfg->decryption_mean & DIS_USE_BEKFILE)
|
|
{
|
|
dis_printf(L_DEBUG, " \tusing the bek file at '%s'\n", cfg->bek_file);
|
|
}
|
|
else if(cfg->decryption_mean & DIS_USE_FVEKFILE)
|
|
{
|
|
dis_printf(L_DEBUG, " \tusing the FVEK file at '%s'\n", cfg->fvek_file);
|
|
}
|
|
else if(cfg->decryption_mean & DIS_USE_VMKFILE)
|
|
{
|
|
dis_printf(L_DEBUG, " \tusing the VMK file at '%s'\n", cfg->vmk_file);
|
|
}
|
|
else
|
|
{
|
|
dis_printf(L_DEBUG, " \tnot using any decryption mean\n");
|
|
}
|
|
|
|
if(cfg->force_block)
|
|
dis_printf(
|
|
L_DEBUG,
|
|
" Forced to be using metadata block n°%d\n",
|
|
cfg->force_block
|
|
);
|
|
else
|
|
dis_printf(L_DEBUG, " Using the first valid metadata block\n");
|
|
|
|
if(cfg->flags & DIS_FLAG_READ_ONLY)
|
|
dis_printf(
|
|
L_DEBUG,
|
|
" Not allowing any write on the BitLocker volume "
|
|
"(read only mode)\n"
|
|
);
|
|
|
|
dis_printf(L_DEBUG, "... End config ---\n");
|
|
}
|
|
|
|
|
|
/**
|
|
* Getters for the flags
|
|
*/
|
|
int dis_is_read_only(dis_context_t dis_ctx)
|
|
{
|
|
if(!dis_ctx)
|
|
return -1;
|
|
return (dis_ctx->cfg.flags & DIS_FLAG_READ_ONLY);
|
|
}
|
|
|
|
int dis_is_volume_state_checked(dis_context_t dis_ctx)
|
|
{
|
|
if(!dis_ctx)
|
|
return -1;
|
|
return !(dis_ctx->cfg.flags & DIS_FLAG_DONT_CHECK_VOLUME_STATE);
|
|
}
|