mirror of
https://github.com/Aorimn/dislocker
synced 2026-06-08 10:24:29 +00:00
Big changes
Remove disk_op_data global variable in the library Extract file & fuse outputs in two standalone binaries Provide global stub functions for dislocker library Add FIXMEs & TODOs everywhere...
This commit is contained in:
+24
-30
@@ -27,10 +27,11 @@ CFLAGS = $(WFLAGS) $(DEFINES) $(INC) $(CHARDEN)
|
||||
override LDFLAGS += $(LIB) $(LHARDEN)
|
||||
LIBNAME = lib$(PROGNAME).so
|
||||
|
||||
BINS = dislocker dislocker-metadata dislocker-bek
|
||||
SUFFIXES = fuse file metadata bek
|
||||
BINS = $(foreach suf, $(SUFFIXES), $(BIN)-$(suf))
|
||||
BINS_OBJECTS = $(foreach bin, $(BINS), $(bin).o)
|
||||
|
||||
SOURCES = common.c config.c sectors.c \
|
||||
SOURCES = dislocker.c common.c config.c sectors.c \
|
||||
xstd/xstdio.c xstd/xstdlib.c \
|
||||
metadata/datums.c metadata/metadata.c metadata/vmk.c \
|
||||
metadata/fvek.c metadata/extended_info.c \
|
||||
@@ -55,8 +56,6 @@ MAN_NUMBER = 1
|
||||
MAN_PATH = $(DESTDIR)/share/man/man$(MAN_NUMBER)/
|
||||
MAN_ROOT = ../man/
|
||||
|
||||
FUSE_ROOT := outputs/fuse/fuse
|
||||
FILE_ROOT := outputs/file/file
|
||||
|
||||
|
||||
|
||||
@@ -85,41 +84,25 @@ endif
|
||||
|
||||
export
|
||||
|
||||
.PHONY : all libs static $(BIN) file fuse common clean
|
||||
.PHONY : all libs $(BIN) $(SUFFIXES) install uninstall clean travis-install valgrind snapshot release
|
||||
|
||||
.c.o :
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
all : fuse
|
||||
all : $(BIN)
|
||||
|
||||
libs: $(OBJECTS)
|
||||
$(CC) -shared $(CFLAGS) -o $(LIBNAME) $(OBJECTS)
|
||||
|
||||
# Default rules for final binaries
|
||||
touch :
|
||||
touch $(BIN).c
|
||||
|
||||
$(BIN) : touch libs $(BINS_OBJECTS)
|
||||
for prog in $(BINS); do \
|
||||
$(CC) $(CFLAGS) -o $${prog} $${prog}.o $(LDFLAGS); \
|
||||
done
|
||||
|
||||
|
||||
static : touch libs
|
||||
$(CC) -static $(CFLAGS) -o $(BIN)-static $(OBJECTS) $(LDFLAGS) -lz -ldl
|
||||
$(BIN) : libs $(SUFFIXES)
|
||||
|
||||
|
||||
# Build the binary for the file output
|
||||
file: CFLAGS += -D__RUN_FILE
|
||||
file: SOURCES += $(FILE_ROOT).c
|
||||
file: $(FILE_ROOT).o
|
||||
|
||||
file: $(BIN)
|
||||
|
||||
file: libs $(BIN)-file
|
||||
|
||||
# Build the binary for the fuse output
|
||||
fuse: CFLAGS += -D__RUN_FUSE -DFUSE_USE_VERSION=26
|
||||
fuse: SOURCES += $(FUSE_ROOT).c
|
||||
fuse: CFLAGS += -DFUSE_USE_VERSION=26
|
||||
|
||||
# Don't link with the same library on MacOSX
|
||||
ifeq ($(OS), Darwin)
|
||||
@@ -128,17 +111,28 @@ else
|
||||
fuse: LDFLAGS += -lfuse
|
||||
endif # Darwin
|
||||
|
||||
fuse: $(FUSE_ROOT).o
|
||||
fuse: libs $(BIN)-fuse
|
||||
|
||||
|
||||
# Build the binary for getting metadata only
|
||||
metadata: libs $(BIN)-metadata
|
||||
|
||||
# Build the binary for getting bek information only
|
||||
bek: libs $(BIN)-bek
|
||||
|
||||
fuse: $(BIN)
|
||||
|
||||
|
||||
# Check if the installed binary is present, make it if it isn't
|
||||
check-install:
|
||||
@[ -e $(BIN) ] && echo "Found $(BIN) binary, installing it" || make clean fuse
|
||||
@if [ -e $(BIN)-fuse ] ; then \
|
||||
echo "Found $(BIN) binary, installing it"; \
|
||||
else \
|
||||
make clean all; \
|
||||
fi
|
||||
|
||||
install: check-install
|
||||
install: all
|
||||
install -pm755 $(BINS) $(BINARIES_PATH)
|
||||
cd $(BINARIES_PATH) && ln $(BIN)-fuse $(BIN) && cd -
|
||||
install -pm755 $(LIBNAME) $(LIBRARY_PATH)
|
||||
if [ "$(OS)" = "Darwin" ]; then \
|
||||
cp $(MAN_ROOT)$(BIN)_osx_man $(MAN_ROOT)$(BIN).$(MAN_NUMBER); \
|
||||
@@ -162,7 +156,7 @@ uninstall: clean
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf -- $(OBJECTS) $(FILE_ROOT).o $(FUSE_ROOT).o *~ *.swp $(BINS) $(BINS_OBJECTS) $(LIBNAME)
|
||||
rm -rf -- $(OBJECTS) *~ *.swp $(BINS) $(BINS_OBJECTS) $(LIBNAME)
|
||||
|
||||
travis-install:
|
||||
if [ "$$TRAVIS_OS_NAME" = "linux" ]; then \
|
||||
|
||||
+3
-2
@@ -54,7 +54,7 @@ PROGNAME " by " AUTHOR ", v"VERSION " (compiled for " __OS "/" __ARCH ")\n"
|
||||
" decrypt volume using the recovery password method\n"
|
||||
" -q, --quiet do NOT display anything\n"
|
||||
" -r, --readonly do not allow to write on the BitLocker volume\n"
|
||||
" -s, --stateok do not check the volume's state, assume it's ok to mount it"
|
||||
" -s, --stateok do not check the volume's state, assume it's ok to mount it\n"
|
||||
" -u, --user-password 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"
|
||||
@@ -92,7 +92,7 @@ static void hide_opt(char* opt)
|
||||
* @param argv Arguments given to the program
|
||||
* @return Return the number of arguments which are still waiting to be studied
|
||||
*/
|
||||
int parse_args(dis_config_t* cfg, int argc, char** argv)
|
||||
int parse_args(dis_config_t* cfg, int argc, char** argv) // TODO change into dis_parge_args()
|
||||
{
|
||||
/** See man getopt_long(3) */
|
||||
extern int optind;
|
||||
@@ -269,6 +269,7 @@ void print_args(dis_config_t* cfg)
|
||||
xprintf(L_DEBUG, " Verbosity: %d\n", cfg->verbosity);
|
||||
xprintf(L_DEBUG, " Trying to decrypt '%s'\n", cfg->volume_path);
|
||||
|
||||
// FIXME decryption_mean is a bitfield
|
||||
switch(cfg->decryption_mean)
|
||||
{
|
||||
case USE_CLEAR_KEY:
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ typedef struct _dis_cfg {
|
||||
* By default, dislocker will check for unstable state that may corrupt data
|
||||
* if mounted using fuse
|
||||
*/
|
||||
char check_state;
|
||||
char dont_check_state;
|
||||
} dis_config_t;
|
||||
|
||||
|
||||
|
||||
+3
-2
@@ -74,18 +74,19 @@ int main (int argc, char **argv)
|
||||
{
|
||||
xprintf(L_CRITICAL, "Filename must be provided\n");
|
||||
usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(( fd = open(filename, O_RDONLY) ) < 0)
|
||||
{
|
||||
xprintf(L_CRITICAL, "Failed to open file %s\n", filename);
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(!get_bek_dataset(fd, &bek_dataset))
|
||||
{
|
||||
xprintf(L_CRITICAL, "Unable to get the dataset from the BEK file\n");
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
@@ -21,28 +21,22 @@
|
||||
* USA.
|
||||
*/
|
||||
|
||||
|
||||
/* This define is for the O_LARGEFILE definition */
|
||||
#define _GNU_SOURCE
|
||||
|
||||
|
||||
#include "encommon.h"
|
||||
#include "dislocker.h"
|
||||
#include "encryption/decrypt.h"
|
||||
#include "sectors.h"
|
||||
#include "metadata/metadata.h"
|
||||
#include "file.h"
|
||||
|
||||
|
||||
#ifdef __DARWIN
|
||||
#if defined(__DARWIN) || defined(__FREEBSD)
|
||||
# define O_LARGEFILE 0
|
||||
#endif /* __DARWIN */
|
||||
#endif /* __DARWIN || __FREEBSD */
|
||||
|
||||
|
||||
/** Data used globally for operation on disk (encryption/decryption) */
|
||||
extern dis_iodata_t disk_op_data;
|
||||
/* Number of sectors we're reading at a time */
|
||||
#define NB_READ_SECTOR 16
|
||||
|
||||
|
||||
int file_main(char* ntfs_file)
|
||||
|
||||
int file_main(char* ntfs_file, dis_context_t* dis_ctx)
|
||||
{
|
||||
// Check parameter
|
||||
if(!ntfs_file)
|
||||
@@ -51,11 +45,18 @@ int file_main(char* ntfs_file)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(!dis_ctx)
|
||||
{
|
||||
xprintf(L_ERROR, "Error, no context given. Abort.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint8_t* buffer = xmalloc((size_t)(NB_READ_SECTOR * disk_op_data.sector_size));
|
||||
dis_iodata_t io_data = dis_ctx->io_data;
|
||||
size_t buf_size = (size_t)(NB_READ_SECTOR * io_data.sector_size);
|
||||
uint8_t* buffer = xmalloc(buf_size);
|
||||
|
||||
mode_t mode = S_IRUSR|S_IWUSR;
|
||||
if(disk_op_data.cfg->is_ro & READ_ONLY)
|
||||
if(dis_ctx->cfg.is_ro & READ_ONLY)
|
||||
mode = S_IRUSR;
|
||||
|
||||
int fd_ntfs = xopen2(ntfs_file, O_CREAT|O_RDWR|O_LARGEFILE, mode);
|
||||
@@ -64,30 +65,24 @@ int file_main(char* ntfs_file)
|
||||
off_t offset = 0;
|
||||
long long int percent = 0;
|
||||
|
||||
xprintf(L_INFO, "File size: %llu bytes\n", disk_op_data.volume_size);
|
||||
xprintf(L_INFO, "File size: %llu bytes\n", io_data.volume_size);
|
||||
|
||||
/* Read all sectors and decrypt them if necessary */
|
||||
xprintf(L_INFO, "\rDecrypting... 0%%");
|
||||
fflush(stdout);
|
||||
|
||||
off_t decrypting_size = (off_t)disk_op_data.volume_size;
|
||||
off_t decrypting_size = (off_t)io_data.volume_size;
|
||||
|
||||
while(offset < decrypting_size)
|
||||
{
|
||||
/* Read and decrypt an entire region of the disk */
|
||||
disk_op_data.decrypt_region(
|
||||
disk_op_data.volume_fd,
|
||||
NB_READ_SECTOR,
|
||||
disk_op_data.sector_size,
|
||||
offset,
|
||||
buffer
|
||||
);
|
||||
dislock(dis_ctx, buffer, offset, buf_size);
|
||||
|
||||
offset += NB_READ_SECTOR * disk_op_data.sector_size;
|
||||
offset += (off_t) buf_size;
|
||||
|
||||
|
||||
/* Now copy the required amount of data to the user file */
|
||||
xwrite(fd_ntfs, buffer, (size_t)(NB_READ_SECTOR * disk_op_data.sector_size));
|
||||
xwrite(fd_ntfs, buffer, buf_size);
|
||||
|
||||
/* Screen update */
|
||||
if(percent != (offset*100)/decrypting_size)
|
||||
@@ -105,3 +100,57 @@ int file_main(char* ntfs_file)
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Main function ran initially
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Check parameters number
|
||||
if(argc < 2)
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int param_idx = 0;
|
||||
int ret = 0;
|
||||
|
||||
dis_context_t dis_ctx;
|
||||
memset(&dis_ctx, 0, sizeof(dis_context_t));
|
||||
|
||||
|
||||
/* Get command line options */
|
||||
param_idx = parse_args(&dis_ctx.cfg, argc, argv);
|
||||
|
||||
/* Check that we have the file where to put NTFS data */
|
||||
if(param_idx >= argc || param_idx <= 0)
|
||||
{
|
||||
fprintf(stderr, "Error, no file given. Abort.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Initialize dislocker */
|
||||
if(dis_initialize(&dis_ctx) == EXIT_FAILURE)
|
||||
{
|
||||
xprintf(L_CRITICAL, "Can't initialize dislocker. Abort.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a NTFS file which could be mounted using `mount -o loop...`
|
||||
*/
|
||||
|
||||
char* ntfs_file = argv[param_idx];
|
||||
xprintf(L_INFO, "Putting NTFS data into '%s'...\n", ntfs_file);
|
||||
|
||||
/* Run the decryption */
|
||||
ret = file_main(ntfs_file, &dis_ctx);
|
||||
|
||||
dis_destroy(&dis_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/* -*- 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dislocker.h"
|
||||
|
||||
|
||||
|
||||
#ifdef __DARWIN
|
||||
# include <osxfuse/fuse.h>
|
||||
#else
|
||||
# include <fuse.h>
|
||||
#endif /* __DARWIN */
|
||||
|
||||
|
||||
/** NTFS virtual partition's name */
|
||||
#define NTFS_FILENAME "/dislocker-file"
|
||||
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "encommon.h"
|
||||
#include "dislocker.h"
|
||||
#include "metadata/metadata.h"
|
||||
|
||||
|
||||
/**
|
||||
* Data used globally for operation on disk (encryption/decryption) and in the
|
||||
* dislocker library.
|
||||
*/
|
||||
dis_context_t dis_ctx;
|
||||
|
||||
|
||||
/**
|
||||
* Stubs used for FUSE operations.
|
||||
*/
|
||||
static int fs_getattr(const char *path, struct stat *stbuf)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if(!path || !stbuf)
|
||||
return -EINVAL;
|
||||
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
if(strcmp(path, "/") == 0)
|
||||
{
|
||||
stbuf->st_mode = S_IFDIR | 0555;
|
||||
stbuf->st_nlink = 2;
|
||||
}
|
||||
else if(strcmp(path, NTFS_FILENAME) == 0)
|
||||
{
|
||||
mode_t m = (dis_ctx.cfg.is_ro & READ_ONLY) ? 0444 : 0666;
|
||||
stbuf->st_mode = S_IFREG | m;
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = (off_t)dis_ctx.io_data.volume_size;
|
||||
}
|
||||
else
|
||||
res = -ENOENT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
{
|
||||
/* Both variables aren't used here */
|
||||
(void) offset;
|
||||
(void) fi;
|
||||
|
||||
if(!path || !buf || !filler)
|
||||
return -EINVAL;
|
||||
|
||||
if(strcmp(path, "/") != 0)
|
||||
return -ENOENT;
|
||||
|
||||
filler(buf, ".", NULL, 0);
|
||||
filler(buf, "..", NULL, 0);
|
||||
filler(buf, NTFS_FILENAME + 1, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
if(!path || !fi)
|
||||
return -EINVAL;
|
||||
|
||||
if(strcmp(path, NTFS_FILENAME) != 0)
|
||||
return -ENOENT;
|
||||
|
||||
|
||||
if(dis_ctx.cfg.is_ro & READ_ONLY)
|
||||
{
|
||||
if((fi->flags & 3) != O_RDONLY)
|
||||
return -EACCES;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Authorize read/write, readonly and writeonly operations */
|
||||
if((fi->flags & 3) != O_RDWR &&
|
||||
(fi->flags & 3) != O_RDONLY &&
|
||||
(fi->flags & 3) != O_WRONLY)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_read(
|
||||
const char *path,
|
||||
char *buf,
|
||||
size_t size,
|
||||
off_t offset,
|
||||
__attribute__ ((unused)) struct fuse_file_info *fi)
|
||||
{
|
||||
if(!path || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Perform basic checks
|
||||
*/
|
||||
if(strcmp(path, NTFS_FILENAME) != 0)
|
||||
{
|
||||
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return dislock(&dis_ctx, (uint8_t*) buf, offset, size);
|
||||
}
|
||||
|
||||
static int fs_write(
|
||||
const char *path,
|
||||
const char *buf,
|
||||
size_t size,
|
||||
off_t offset,
|
||||
__attribute__ ((unused)) struct fuse_file_info *fi)
|
||||
{
|
||||
// Check parameters
|
||||
if(!path || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
if(strcmp(path, NTFS_FILENAME) != 0)
|
||||
{
|
||||
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return enlock(&dis_ctx, (uint8_t*) buf, offset, size);
|
||||
}
|
||||
|
||||
|
||||
/* Structure used by the FUSE driver */
|
||||
struct fuse_operations fs_oper = {
|
||||
.getattr = fs_getattr,
|
||||
.readdir = fs_readdir,
|
||||
.open = fs_open,
|
||||
.read = fs_read,
|
||||
.write = fs_write,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Main function ran initially
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Check parameters number
|
||||
if(argc < 2)
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int param_idx = 0;
|
||||
int ret = EXIT_SUCCESS;
|
||||
|
||||
|
||||
memset(&dis_ctx, 0, sizeof(dis_context_t));
|
||||
|
||||
|
||||
/* Get command line options */
|
||||
param_idx = parse_args(&dis_ctx.cfg, argc, argv);
|
||||
|
||||
/* Check we got enough arguments for at least one more, the mount point */
|
||||
if(param_idx >= argc || param_idx <= 0)
|
||||
{
|
||||
xprintf(L_CRITICAL, "Error, no mount point given. Abort.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize dislocker */
|
||||
if(dis_initialize(&dis_ctx) == EXIT_FAILURE)
|
||||
{
|
||||
xprintf(L_CRITICAL, "Can't initialize dislocker. Abort.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create the parameters table needed for FUSE and run it
|
||||
* This is as we're running argv[0] followed by ARGS (see usage())
|
||||
*/
|
||||
/* Compute the new argc given to FUSE */
|
||||
size_t new_argc = (size_t)(argc - param_idx + 1);
|
||||
xprintf(L_DEBUG, "New value for argc: %d\n", new_argc);
|
||||
|
||||
char** new_argv = xmalloc(new_argc * sizeof(char*));
|
||||
|
||||
/* Get argv[0] */
|
||||
size_t lg = strlen(argv[0]) + 1;
|
||||
*new_argv = xmalloc(lg);
|
||||
memcpy(*new_argv, argv[0], lg);
|
||||
|
||||
/* Get all of the parameters from param_idx till the end */
|
||||
size_t loop = 0;
|
||||
for(loop = 1; loop < new_argc; ++loop)
|
||||
{
|
||||
lg = strlen(argv[(size_t)param_idx + loop - 1]) + 1;
|
||||
*(new_argv + loop) = xmalloc(lg);
|
||||
memcpy(*(new_argv + loop), argv[(size_t)param_idx + loop - 1], lg);
|
||||
}
|
||||
|
||||
|
||||
xprintf(L_INFO, "Running FUSE with these arguments: \n");
|
||||
for(loop = 0; loop < new_argc; ++loop)
|
||||
xprintf(L_INFO, " `--> '%s'\n", *(new_argv + loop));
|
||||
|
||||
|
||||
/* Run FUSE */
|
||||
ret = fuse_main((int)new_argc, new_argv, &fs_oper, NULL);
|
||||
|
||||
/* Free FUSE params */
|
||||
for(loop = 0; loop < new_argc; ++loop)
|
||||
xfree(new_argv[loop]);
|
||||
xfree(new_argv);
|
||||
|
||||
|
||||
/* Destroy dislocker structures */
|
||||
dis_destroy(&dis_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
+31
-76
@@ -27,9 +27,9 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include "dislocker.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
@@ -57,21 +57,13 @@ int main(int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int ret = EXIT_SUCCESS;
|
||||
|
||||
int optchar = 0;
|
||||
char *volume_path = NULL;
|
||||
|
||||
int fd = 0;
|
||||
volume_header_t volume_header;
|
||||
|
||||
void* bl_metadata = NULL;
|
||||
|
||||
bitlocker_dataset_t* dataset = NULL;
|
||||
datum_vmk_t* vmk_clear_key_datum = NULL;
|
||||
|
||||
dis_config_t cfg;
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
off_t offset = 0;
|
||||
|
||||
while((optchar = getopt(argc, argv, "o:V:h")) != -1)
|
||||
{
|
||||
@@ -81,7 +73,7 @@ int main(int argc, char **argv)
|
||||
usage();
|
||||
return EXIT_SUCCESS;
|
||||
case 'o':
|
||||
cfg.offset = (off_t) strtoll(optarg, NULL, 10);
|
||||
offset = (off_t) strtoll(optarg, NULL, 10);
|
||||
break;
|
||||
case 'V':
|
||||
volume_path = strdup(optarg);
|
||||
@@ -94,102 +86,65 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
xstdio_init(L_INFO, NULL);
|
||||
|
||||
if(!volume_path)
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Open the volume as a normal file
|
||||
fd = xopen(volume_path, O_RDONLY|O_LARGEFILE);
|
||||
dis_context_t dis_ctx;
|
||||
memset(&dis_ctx, 0, sizeof(dis_context_t));
|
||||
|
||||
/*
|
||||
* Initialize dislocker's configuration
|
||||
*/
|
||||
dis_ctx.cfg.volume_path = volume_path;
|
||||
dis_ctx.cfg.verbosity = L_INFO;
|
||||
dis_ctx.cfg.offset = offset;
|
||||
|
||||
/* To print UTF-32 strings */
|
||||
setlocale(LC_ALL, "");
|
||||
/* We don't want to give decryption mean, we only want the metadata */
|
||||
dis_ctx.stop_at = AFTER_BITLOCKER_INFORMATION_CHECK;
|
||||
|
||||
|
||||
// Initialize structures
|
||||
memset(&volume_header, 0, sizeof(volume_header_t));
|
||||
|
||||
|
||||
// Getting volume infos
|
||||
if(!get_volume_header(&volume_header, fd, cfg.offset))
|
||||
/* Initialize dislocker */
|
||||
if(dis_initialize(&dis_ctx) == EXIT_FAILURE)
|
||||
{
|
||||
xprintf(L_ERROR, "Error during reading the volume: not enough byte read.\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto error;
|
||||
xprintf(L_CRITICAL, "Can't initialize dislocker. Abort.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Printing them
|
||||
print_volume_header(L_INFO, &volume_header);
|
||||
|
||||
// Checking the volume signature
|
||||
if(memcmp(BITLOCKER_SIGNATURE, volume_header.signature,
|
||||
BITLOCKER_SIGNATURE_SIZE) != 0)
|
||||
{
|
||||
xprintf(L_CRITICAL,
|
||||
"The signature of the volume (%.8s) doesn't match the "
|
||||
"BitLocker's one (-FVE-FS-). Abort.\n",
|
||||
volume_header.signature);
|
||||
ret = EXIT_FAILURE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Getting BitLocker metadata and validate them
|
||||
if(!get_metadata_check_validations(&volume_header, fd, &bl_metadata, &cfg))
|
||||
{
|
||||
xprintf(L_CRITICAL, "A problem occured during the retrieving of metadata. Abort.\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(cfg.force_block == 0 || !bl_metadata)
|
||||
{
|
||||
xprintf(L_CRITICAL, "Can't find a valid set of metadata on the disk. Abort.\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Printing BitLocker metadata
|
||||
print_bl_metadata(L_INFO, bl_metadata);
|
||||
// Printing volume header
|
||||
print_volume_header(L_INFO, dis_ctx.io_data.volume_header);
|
||||
xprintf(L_INFO, "\n");
|
||||
|
||||
// Printing BitLocker metadata
|
||||
print_bl_metadata(L_INFO, dis_ctx.io_data.metadata);
|
||||
xprintf(L_INFO, "\n");
|
||||
|
||||
// Now we're looking at the data
|
||||
print_data(L_INFO, bl_metadata);
|
||||
// Now we're looking at the data themselves
|
||||
print_data(L_INFO, dis_ctx.io_data.metadata);
|
||||
|
||||
|
||||
// Get the metadata's dataset
|
||||
if(!get_dataset(bl_metadata, &dataset))
|
||||
if(!get_dataset(dis_ctx.io_data.metadata, &dataset))
|
||||
{
|
||||
xprintf(L_CRITICAL, "Can't find a valid dataset. Abort.\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto error;
|
||||
dis_destroy(&dis_ctx);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Search for a clear key
|
||||
if(has_clear_key(dataset, &vmk_clear_key_datum))
|
||||
{
|
||||
xprintf(L_INFO, "\n===== There's a clear key here!\n===== Take a look at it:\n");
|
||||
xprintf(L_INFO, "=======[ There's a clear key here ]========\n");
|
||||
print_one_datum(L_INFO, (void*)vmk_clear_key_datum);
|
||||
xprintf(L_INFO, "============[ Clear key end ]============\n");
|
||||
xprintf(L_INFO, "=============[ Clear key end ]=============\n");
|
||||
}
|
||||
else
|
||||
xprintf(L_INFO, "No clear key found.\n");
|
||||
|
||||
|
||||
error:
|
||||
// Do some cleaning stuff
|
||||
if(volume_path)
|
||||
xfree(volume_path);
|
||||
dis_destroy(&dis_ctx);
|
||||
|
||||
if(bl_metadata)
|
||||
xfree(bl_metadata);
|
||||
|
||||
xclose(fd);
|
||||
xstdio_end();
|
||||
|
||||
return ret;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+726
-385
File diff suppressed because it is too large
Load Diff
+87
-5
@@ -23,14 +23,96 @@
|
||||
#ifndef DISLOCKER_MAIN_H
|
||||
#define DISLOCKER_MAIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__RUN_FUSE)
|
||||
# include "outputs/fuse/fuse.h"
|
||||
#elif defined(__RUN_FILE)
|
||||
# include "outputs/file/file.h"
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "encommon.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dis_initialize() function does a lot of things. So, in order to provide
|
||||
* flexibility, place some kind of breakpoint after majors steps.
|
||||
*/
|
||||
typedef enum {
|
||||
COMPLETE_EVERYTHING = 0,
|
||||
AFTER_OPEN_VOLUME,
|
||||
AFTER_VOLUME_HEADER,
|
||||
AFTER_VOLUME_CHECK,
|
||||
AFTER_BITLOCKER_INFORMATION,
|
||||
AFTER_BITLOCKER_INFORMATION_CHECK,
|
||||
AFTER_VMK,
|
||||
AFTER_FVEK,
|
||||
BEFORE_DECRYPTION_CHECKING,
|
||||
} dis_stopat_e;
|
||||
|
||||
|
||||
/**
|
||||
* Main structure to pass to dislocker functions. These keeps various
|
||||
* information in it.
|
||||
*/
|
||||
typedef struct _dis_ctx {
|
||||
|
||||
dis_config_t cfg;
|
||||
|
||||
dis_iodata_t io_data;
|
||||
|
||||
dis_stopat_e stop_at;
|
||||
} dis_context_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public prototypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize dislocker. As stated above, the initialisation process may be
|
||||
* stopped at any major step in order to retrieve different information. Note
|
||||
* that you have to provide an already allocated dis_ctx with an already filled
|
||||
* dis_ctx->cfg with parameters for dislocker to initialize correctly.
|
||||
* This function malloc(3)s structures, see dis_destroy() below for free(3)ing
|
||||
* it.
|
||||
* dislock() & enlock() function may not be called before executing this
|
||||
* function.
|
||||
*
|
||||
* @param dis_ctx The dislocker context needed for all operations. As stated
|
||||
* above, this parameter has to be pre-allocated. Furthermore, the dis_ctx->cfg
|
||||
* structure has to be filled with parameters to properly initialize dislocker.
|
||||
*/
|
||||
int dis_initialize(dis_context_t* dis_ctx);
|
||||
|
||||
/**
|
||||
* Once dis_initialize() has been called, this function is able to decrypt the
|
||||
* BitLocker-encrypted volume.
|
||||
*
|
||||
* @param dis_ctx The same parameter passed to dis_initialize.
|
||||
* @param offset The offset from where to start decrypting.
|
||||
* @param buffer The buffer to put decrypted data to.
|
||||
* @param size The size of a region to decrypt.
|
||||
*/
|
||||
int dislock(dis_context_t* dis_ctx, uint8_t* buffer, off_t offset, size_t size);
|
||||
|
||||
/**
|
||||
* Once dis_initialize() has been called, this function is able to encrypt data
|
||||
* to the BitLocker-encrypted volume.
|
||||
*
|
||||
* @param dis_ctx The same parameter passed to dis_initialize.
|
||||
* @param offset The offset where to put the data.
|
||||
* @param buffer The buffer from where to take data to encrypt.
|
||||
* @param size The size of a region to decrypt.
|
||||
*/
|
||||
int enlock(dis_context_t* dis_ctx, uint8_t* buffer, off_t offset, size_t size);
|
||||
|
||||
/**
|
||||
* Destroy dislocker structures. This is important to call this function after
|
||||
* dislocker is not needed -- if dis_initialize() has been called -- in order
|
||||
* for dislocker to free(3) the used memory.
|
||||
* dislock() & enlock() functions may not be called anymore after executing this
|
||||
* function.
|
||||
*/
|
||||
int dis_destroy(dis_context_t* dis_ctx);
|
||||
|
||||
|
||||
#endif /* DISLOCKER_MAIN_H */
|
||||
|
||||
|
||||
+29
-7
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "metadata/vmk.h"
|
||||
#include "metadata/metadata.h"
|
||||
#include "metadata/extended_info.h"
|
||||
|
||||
@@ -59,6 +60,15 @@ typedef struct _data {
|
||||
/* Volume metadata */
|
||||
bitlocker_header_t* metadata;
|
||||
|
||||
/* The volume header, 512 bytes */
|
||||
volume_header_t* volume_header;
|
||||
|
||||
/* The VMK */
|
||||
datum_key_t* vmk;
|
||||
|
||||
/* The FVEK */
|
||||
datum_key_t* fvek;
|
||||
|
||||
/*
|
||||
* Virtualized regions are presented as zeroes when queried from the NTFS
|
||||
* layer. In these virtualized regions, we find the 3 BitLocker metadata
|
||||
@@ -88,17 +98,29 @@ typedef struct _data {
|
||||
int volume_fd;
|
||||
|
||||
/* Contexts used to encrypt or decrypt */
|
||||
contexts_t* ctx;
|
||||
|
||||
/* Configuration parameters */
|
||||
dis_config_t* cfg;
|
||||
contexts_t* enc_ctx;
|
||||
|
||||
/* Function to decrypt a region of the volume */
|
||||
int(*decrypt_region)(int fd, size_t nb_read_sector, uint16_t sector_size, off_t sector_start, uint8_t* output);
|
||||
int(*decrypt_region)(
|
||||
struct _data* io_data,
|
||||
size_t nb_read_sector,
|
||||
uint16_t sector_size,
|
||||
off_t sector_start,
|
||||
uint8_t* output
|
||||
);
|
||||
/* Function to encrypt a region of the volume */
|
||||
int(*encrypt_region)(int fd, size_t nb_write_sector, uint16_t sector_size, off_t sector_start, uint8_t* input);
|
||||
int(*encrypt_region)(
|
||||
struct _data* io_data,
|
||||
size_t nb_write_sector,
|
||||
uint16_t sector_size,
|
||||
off_t sector_start,
|
||||
uint8_t* input
|
||||
);
|
||||
|
||||
/* FUSE uses threads. We need to protect our "lseek/read" and "lseek/write" sequences */
|
||||
/*
|
||||
* FUSE uses threads. We need to protect our "lseek/read" and "lseek/write"
|
||||
* sequences
|
||||
*/
|
||||
pthread_mutex_t mutex_lseek_rw;
|
||||
} dis_iodata_t;
|
||||
|
||||
|
||||
@@ -402,11 +402,11 @@ int decrypt_sector(dis_iodata_t* global_data, uint8_t* sector, off_t sector_addr
|
||||
{
|
||||
case AES_128_DIFFUSER:
|
||||
case AES_256_DIFFUSER:
|
||||
decrypt_with_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
decrypt_with_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
break;
|
||||
case AES_128_NO_DIFFUSER:
|
||||
case AES_256_NO_DIFFUSER:
|
||||
decrypt_without_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
decrypt_without_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,11 +57,11 @@ int encrypt_sector(dis_iodata_t* global_data, uint8_t* sector, off_t sector_addr
|
||||
{
|
||||
case AES_128_DIFFUSER:
|
||||
case AES_256_DIFFUSER:
|
||||
encrypt_with_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
encrypt_with_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
break;
|
||||
case AES_128_NO_DIFFUSER:
|
||||
case AES_256_NO_DIFFUSER:
|
||||
encrypt_without_diffuser(global_data->ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
encrypt_without_diffuser(global_data->enc_ctx, global_data->sector_size, sector, sector_address, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/* -*- 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.
|
||||
*/
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
|
||||
|
||||
#define NB_READ_SECTOR 16
|
||||
|
||||
|
||||
/*
|
||||
* Only function others can use
|
||||
*/
|
||||
int file_main(char* ntfs_file);
|
||||
|
||||
|
||||
|
||||
#endif /* FILE_H */
|
||||
@@ -1,500 +0,0 @@
|
||||
/* -*- 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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Special thanks to Nitin Kumar and Vipin Kumar for helping me building this
|
||||
* file
|
||||
*/
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "encommon.h"
|
||||
#include "dislocker.h"
|
||||
#include "encryption/decrypt.h"
|
||||
#include "sectors.h"
|
||||
#include "metadata/metadata.h"
|
||||
#include "fuse.h"
|
||||
|
||||
|
||||
/** Data used globally for operation on disk (encryption/decryption) */
|
||||
extern dis_iodata_t disk_op_data;
|
||||
|
||||
|
||||
static int fs_getattr(const char *path, struct stat *stbuf)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if(!path || !stbuf)
|
||||
return -EINVAL;
|
||||
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
if(strcmp(path, "/") == 0)
|
||||
{
|
||||
stbuf->st_mode = S_IFDIR | 0555;
|
||||
stbuf->st_nlink = 2;
|
||||
}
|
||||
else if(strcmp(path, NTFS_FILENAME) == 0)
|
||||
{
|
||||
mode_t m = disk_op_data.cfg->is_ro ? 0444 : 0666;
|
||||
stbuf->st_mode = S_IFREG | m;
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = (off_t)disk_op_data.volume_size;
|
||||
}
|
||||
else
|
||||
res = -ENOENT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
{
|
||||
/* Both variables aren't used here */
|
||||
(void) offset;
|
||||
(void) fi;
|
||||
|
||||
if(!path || !buf || !filler)
|
||||
return -EINVAL;
|
||||
|
||||
if(strcmp(path, "/") != 0)
|
||||
return -ENOENT;
|
||||
|
||||
filler(buf, ".", NULL, 0);
|
||||
filler(buf, "..", NULL, 0);
|
||||
filler(buf, NTFS_FILENAME + 1, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
if(!path || !fi)
|
||||
return -EINVAL;
|
||||
|
||||
if(strcmp(path, NTFS_FILENAME) != 0)
|
||||
return -ENOENT;
|
||||
|
||||
|
||||
if(disk_op_data.cfg->is_ro & READ_ONLY)
|
||||
{
|
||||
if((fi->flags & 3) != O_RDONLY)
|
||||
return -EACCES;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Authorize read/write, readonly and writeonly operations */
|
||||
if((fi->flags & 3) != O_RDWR &&
|
||||
(fi->flags & 3) != O_RDONLY &&
|
||||
(fi->flags & 3) != O_WRONLY)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_read(const char *path, char *buf, size_t size,
|
||||
off_t offset, UNUSED struct fuse_file_info *fi)
|
||||
{
|
||||
if(!path || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
uint8_t* buffer = NULL;
|
||||
|
||||
size_t sector_count;
|
||||
off_t sector_start;
|
||||
size_t sector_to_add = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Perform basic checks
|
||||
*/
|
||||
if(strcmp(path, NTFS_FILENAME) != 0)
|
||||
{
|
||||
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
xprintf(L_DEBUG, "Received a request with a null size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(offset < 0)
|
||||
{
|
||||
xprintf(L_ERROR, "Offset under 0: %#" F_OFF_T "\n", offset);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if(offset >= (off_t)disk_op_data.volume_size)
|
||||
{
|
||||
xprintf(L_ERROR, "Offset (%#" F_OFF_T ") exceeds volume's size (%#"
|
||||
F_OFF_T ")\n",
|
||||
offset, (off_t)disk_op_data.volume_size);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The offset may not be at a sector limit, so we need to decrypt the entire
|
||||
* sector where it starts. Idem for the end.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* Sector number: 1 2 3 4 5 6 7...
|
||||
* Data, continuous sectors: |___|___|___|___|___|___|__...
|
||||
* The data the user want: |__________|
|
||||
*
|
||||
* The user don't want all of the data from sectors 2 and 5, but as the data
|
||||
* are encrypted sector by sector, we have to decrypt them even though we
|
||||
* won't give him the beginning of the sector 2 and the end of the sector 5.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Logic to do this is below :
|
||||
* - count the number of full sectors
|
||||
* - decode all sectors
|
||||
* - select and copy the data to user and deallocate all buffers
|
||||
*/
|
||||
|
||||
/* Do not add sectors if we're at the edge of one already */
|
||||
if((offset % disk_op_data.sector_size) != 0)
|
||||
sector_to_add += 1;
|
||||
if(((offset + (off_t)size) % disk_op_data.sector_size) != 0)
|
||||
sector_to_add += 1;
|
||||
|
||||
sector_count = ( size / disk_op_data.sector_size ) + sector_to_add;
|
||||
sector_start = offset / disk_op_data.sector_size;
|
||||
|
||||
xprintf(L_DEBUG,
|
||||
"--------------------{ Fuse reading }-----------------------\n");
|
||||
xprintf(L_DEBUG, " Offset and size needed: %#" F_OFF_T
|
||||
" and %#" F_SIZE_T "\n", offset, size);
|
||||
xprintf(L_DEBUG, " Start sector number: %#" F_OFF_T
|
||||
" || Number of sectors: %#" F_SIZE_T "\n",
|
||||
sector_start, sector_count);
|
||||
|
||||
|
||||
/*
|
||||
* NOTE: DO NOT use xmalloc() here, we don't want to mess everything up!
|
||||
* In general, do not use xfunctions() but xprintf() here.
|
||||
*/
|
||||
|
||||
size_t to_allocate = size + sector_to_add*(size_t)disk_op_data.sector_size;
|
||||
xprintf(L_DEBUG, " Trying to allocate %#" F_SIZE_T " bytes\n",to_allocate);
|
||||
buffer = malloc(to_allocate);
|
||||
|
||||
/* If buffer could not be allocated, return an error */
|
||||
if(!buffer)
|
||||
{
|
||||
xprintf(L_ERROR, "Cannot allocate buffer for reading, abort.\n");
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
if(errno < 0)
|
||||
return errno;
|
||||
else
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
if(!disk_op_data.decrypt_region(
|
||||
disk_op_data.volume_fd,
|
||||
sector_count,
|
||||
disk_op_data.sector_size,
|
||||
sector_start * disk_op_data.sector_size,
|
||||
buffer
|
||||
))
|
||||
{
|
||||
free(buffer);
|
||||
xprintf(L_ERROR, "Cannot decrypt sectors, abort.\n");
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Now copy the required amount of data to the user buffer */
|
||||
memcpy(buf, buffer + (offset % disk_op_data.sector_size), size);
|
||||
|
||||
free(buffer);
|
||||
|
||||
xprintf(L_DEBUG, " Outsize which will be returned: %d\n", (int)size);
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
|
||||
return (int)size;
|
||||
}
|
||||
|
||||
static int fs_write(const char *path, const char *buf, size_t size,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
{
|
||||
// Check parameters
|
||||
if(!path || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
uint8_t* buffer = NULL;
|
||||
int ret = 0;
|
||||
|
||||
size_t sector_count;
|
||||
off_t sector_start;
|
||||
size_t sector_to_add = 0;
|
||||
|
||||
|
||||
/* Perform basic checks */
|
||||
if(disk_op_data.cfg->is_ro & READ_ONLY)
|
||||
{
|
||||
xprintf(L_DEBUG, "Only decrypting (-r or --read-only option passed)\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if(strcmp(path, NTFS_FILENAME) != 0)
|
||||
{
|
||||
xprintf(L_DEBUG, "Unknown entry requested: \"%s\"\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
xprintf(L_DEBUG, "Received a request with a null size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(offset < 0)
|
||||
{
|
||||
xprintf(L_ERROR, "Offset under 0: %#" F_OFF_T "\n", offset);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if(offset >= (off_t)disk_op_data.volume_size)
|
||||
{
|
||||
xprintf(L_ERROR, "Offset (%#" F_OFF_T ") exceeds volume's size (%#"
|
||||
F_OFF_T ")\n",
|
||||
offset, (off_t)disk_op_data.volume_size);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if((size_t)offset + size >= (size_t)disk_op_data.volume_size)
|
||||
{
|
||||
size_t nsize = (size_t)disk_op_data.volume_size
|
||||
- (size_t)offset;
|
||||
xprintf(L_WARNING, "Size modified as exceeding volume's end (offset=%#"
|
||||
F_SIZE_T " + size=%#" F_SIZE_T " >= volume_size=%#"
|
||||
F_SIZE_T ") ; new size: %#" F_SIZE_T "\n",
|
||||
(size_t)offset, size, (size_t)disk_op_data.volume_size, nsize);
|
||||
size = nsize;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Don't authorize to write on metadata, NTFS firsts sectors and on another
|
||||
* area we shouldn't write to (don't know its signification yet).
|
||||
*/
|
||||
off_t metadata_offset = 0;
|
||||
off_t metadata_size = 0;
|
||||
size_t virt_loop = 0;
|
||||
|
||||
for(virt_loop = 0; virt_loop < disk_op_data.nb_virt_region; virt_loop++)
|
||||
{
|
||||
metadata_size = (off_t)disk_op_data.virt_region[virt_loop].size;
|
||||
if(metadata_size == 0)
|
||||
continue;
|
||||
|
||||
metadata_offset = (off_t)disk_op_data.virt_region[virt_loop].addr;
|
||||
|
||||
if(offset >= metadata_offset &&
|
||||
offset <= metadata_offset + metadata_size)
|
||||
{
|
||||
xprintf(L_INFO, "Denying write request on the metadata (1:%#"
|
||||
F_OFF_T ")\n", offset);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if(offset < metadata_offset &&
|
||||
offset + (off_t)size >= metadata_offset)
|
||||
{
|
||||
xprintf(L_INFO, "Denying write request on the metadata (2:%#"
|
||||
F_OFF_T "+ %#" F_SIZE_T ")\n", offset, size);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For BitLocker 7's volume, redirect writes to firsts sectors to the backed
|
||||
* up ones
|
||||
*/
|
||||
if(disk_op_data.metadata->version == V_SEVEN &&
|
||||
offset < disk_op_data.virtualized_size)
|
||||
{
|
||||
xprintf(L_DEBUG, " Entering virtualized area\n");
|
||||
if(offset + (off_t)size <= disk_op_data.virtualized_size)
|
||||
{
|
||||
/*
|
||||
* If all the request is within the virtualized area, just change
|
||||
* the offset
|
||||
*/
|
||||
offset = offset + (off_t)disk_op_data.metadata->boot_sectors_backup;
|
||||
xprintf(L_DEBUG, " `-> Just redirecting to %#"F_OFF_T"\n", offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* But if the buffer is within the virtualized area and overflow it,
|
||||
* split the request in two:
|
||||
* - One for the virtualized area completely (which will be handled
|
||||
* by "recursing" and entering the case above)
|
||||
* - One for the rest by changing the offset to the end of the
|
||||
* virtualized area and the size to the rest to be dec/encrypted
|
||||
*/
|
||||
xprintf(L_DEBUG, " `-> Splitting the request in two, recursing\n");
|
||||
|
||||
size_t nsize = (size_t)(disk_op_data.virtualized_size - offset);
|
||||
ret = fs_write(path, buf, nsize, offset, fi);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
offset = disk_op_data.virtualized_size;
|
||||
size -= nsize;
|
||||
buf += nsize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As in the read function, the offset may not be at a sector limit, so we
|
||||
* need to decrypt the entire sector where it starts till the entire sector
|
||||
* where it ends, then push the changes into the sectors at correct offset
|
||||
* and finally encrypt all of these sectors and write them back to the disk.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* Sector number: 1 2 3 4 5 6 7...
|
||||
* Data, continuous sectors: |___|___|___|___|___|___|__...
|
||||
* Where the user want to write: |__________|
|
||||
*
|
||||
* The user don't want to write everywhere, just from the middle of sector 2
|
||||
* till a part of sector 5. But we're writing sectors by sectors to be able
|
||||
* to encrypt using AES. So we'll need entire sectors 2 to 5 included.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Logic to do this is below :
|
||||
* - read and decrypt all sectors completely (2 to 5 in the example above)
|
||||
* - replace some data by the user's one
|
||||
* - encrypt and write the read sectors
|
||||
*/
|
||||
|
||||
/* Do not add sectors if we're at the edge of one already */
|
||||
if((offset % disk_op_data.sector_size) != 0)
|
||||
sector_to_add += 1;
|
||||
if(((offset + (off_t)size) % disk_op_data.sector_size) != 0)
|
||||
sector_to_add += 1;
|
||||
|
||||
|
||||
sector_count = ( size / disk_op_data.sector_size ) + sector_to_add;
|
||||
sector_start = offset / disk_op_data.sector_size;
|
||||
|
||||
xprintf(L_DEBUG,
|
||||
"--------------------{ Fuse writing }-----------------------\n");
|
||||
xprintf(L_DEBUG, " Offset and size requested: %#" F_OFF_T " and %#"
|
||||
F_SIZE_T "\n", offset, size);
|
||||
xprintf(L_DEBUG, " Start sector number: %#" F_OFF_T
|
||||
" || Number of sectors: %#" F_SIZE_T "\n",
|
||||
sector_start, sector_count);
|
||||
|
||||
|
||||
/*
|
||||
* NOTE: DO NOT use xmalloc() here, we don't want to mess everything up!
|
||||
* In general, do not use xfunctions() but xprintf() here.
|
||||
*/
|
||||
|
||||
buffer = malloc(size + sector_to_add * (size_t)disk_op_data.sector_size);
|
||||
|
||||
/* If buffer could not be allocated */
|
||||
if(!buffer)
|
||||
{
|
||||
xprintf(L_ERROR, "Cannot allocate buffer for writing, abort.\n");
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
if(!disk_op_data.decrypt_region(
|
||||
disk_op_data.volume_fd,
|
||||
sector_count,
|
||||
disk_op_data.sector_size,
|
||||
sector_start * disk_op_data.sector_size,
|
||||
buffer
|
||||
))
|
||||
{
|
||||
free(buffer);
|
||||
xprintf(L_ERROR, "Cannot decrypt sectors, abort.\n");
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
/* Now copy the user's buffer to the received data */
|
||||
memcpy(buffer + (offset % disk_op_data.sector_size), buf, size);
|
||||
|
||||
|
||||
/* Finally, encrypt the buffer and write it to the disk */
|
||||
if(!disk_op_data.encrypt_region(
|
||||
disk_op_data.volume_fd,
|
||||
sector_count,
|
||||
disk_op_data.sector_size,
|
||||
sector_start * disk_op_data.sector_size,
|
||||
buffer
|
||||
))
|
||||
{
|
||||
free(buffer);
|
||||
xprintf(L_ERROR, "Cannot encrypt sectors, abort.\n");
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
free(buffer);
|
||||
|
||||
|
||||
/* Note that ret is zero when no recursion occurs */
|
||||
int outsize = (int)size + ret;
|
||||
|
||||
xprintf(L_DEBUG, " Outsize which will be returned: %d\n", outsize);
|
||||
xprintf(L_DEBUG,
|
||||
"-----------------------------------------------------------\n");
|
||||
|
||||
return outsize;
|
||||
}
|
||||
|
||||
|
||||
struct fuse_operations fs_oper = {
|
||||
.getattr = fs_getattr,
|
||||
.readdir = fs_readdir,
|
||||
.open = fs_open,
|
||||
.read = fs_read,
|
||||
.write = fs_write,
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
/* -*- 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.
|
||||
*/
|
||||
#ifndef FUSE_H
|
||||
#define FUSE_H
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __DARWIN
|
||||
# include <osxfuse/fuse.h>
|
||||
#else
|
||||
# include <fuse.h>
|
||||
#endif /* __DARWIN */
|
||||
|
||||
|
||||
|
||||
|
||||
/** NTFS virtual partition's name */
|
||||
#define NTFS_FILENAME "/dislocker-file"
|
||||
|
||||
|
||||
|
||||
#endif /* FUSE_H */
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU GPL.
|
||||
See the file COPYING.
|
||||
*/
|
||||
|
||||
#if defined(__DARWIN) || defined(__FREEBSD)
|
||||
# include <osxfuse/fuse.h>
|
||||
#else
|
||||
# include <fuse.h>
|
||||
#endif /* __DARWIN || __FREEBSD */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char *hello_str = "Hello World!\n";
|
||||
static const char *hello_path = "/hello";
|
||||
|
||||
static int hello_getattr(const char *path, struct stat *stbuf)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
if(strcmp(path, "/") == 0) {
|
||||
stbuf->st_mode = S_IFDIR | 0755;
|
||||
stbuf->st_nlink = 2;
|
||||
}
|
||||
else if(strcmp(path, hello_path) == 0) {
|
||||
stbuf->st_mode = S_IFREG | 0444;
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = (off_t)strlen(hello_str);
|
||||
}
|
||||
else
|
||||
res = -ENOENT;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
{
|
||||
(void) offset;
|
||||
(void) fi;
|
||||
|
||||
if(strcmp(path, "/") != 0)
|
||||
return -ENOENT;
|
||||
|
||||
filler(buf, ".", NULL, 0);
|
||||
filler(buf, "..", NULL, 0);
|
||||
filler(buf, hello_path + 1, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hello_open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
if(strcmp(path, hello_path) != 0)
|
||||
return -ENOENT;
|
||||
|
||||
if((fi->flags & 3) != O_RDONLY)
|
||||
return -EACCES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
size_t len;
|
||||
(void) fi;
|
||||
if(strcmp(path, hello_path) != 0)
|
||||
return -ENOENT;
|
||||
|
||||
len = strlen(hello_str);
|
||||
if (offset < (off_t)len) {
|
||||
if ((size_t)offset + size > len)
|
||||
size = len - (size_t)offset;
|
||||
memcpy(buf, hello_str + offset, size);
|
||||
} else
|
||||
size = 0;
|
||||
|
||||
return (int)size;
|
||||
}
|
||||
|
||||
static struct fuse_operations hello_oper = {
|
||||
.getattr = hello_getattr,
|
||||
.readdir = hello_readdir,
|
||||
.open = hello_open,
|
||||
.read = hello_read,
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return fuse_main(argc, argv, &hello_oper, NULL);
|
||||
}
|
||||
+58
-74
@@ -30,9 +30,7 @@
|
||||
/**
|
||||
* Getting the real volume size is proving to be quite difficult.
|
||||
*/
|
||||
static uint64_t get_volume_size(volume_header_t* volume_header,
|
||||
bitlocker_header_t* metadata,
|
||||
int fd_volume);
|
||||
static uint64_t get_volume_size(dis_iodata_t* io_data);
|
||||
|
||||
|
||||
|
||||
@@ -122,40 +120,26 @@ int init_keys(bitlocker_dataset_t* dataset, datum_key_t* fvek_datum,
|
||||
/**
|
||||
* Prepare a structure which hold data used for decryption/encryption
|
||||
*
|
||||
* @param metadata The BitLocker metadata block
|
||||
* @param ctx Contexts used to encrypt/decrypt data
|
||||
* @param cfg Invoked configuration
|
||||
* @param volume_header First-sector data
|
||||
* @param offset Where the real volume begins
|
||||
* @param fd_volume The volume's file descriptor
|
||||
* @param dis_ctx The dislocker context used everywhere.
|
||||
* @return TRUE if result can be trusted, FALSE otherwise
|
||||
*/
|
||||
int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
|
||||
dis_config_t* cfg, volume_header_t* volume_header,
|
||||
off_t offset, int fd_volume)
|
||||
int prepare_crypt(dis_context_t* dis_ctx)
|
||||
{
|
||||
size_t loop = 0;
|
||||
uint16_t sector_size = volume_header->sector_size;
|
||||
uint8_t sectors_per_cluster = volume_header->sectors_per_cluster;
|
||||
dis_iodata_t* io_data = &dis_ctx->io_data;
|
||||
bitlocker_header_t* metadata = io_data->metadata;
|
||||
uint16_t sector_size = io_data->volume_header->sector_size;
|
||||
uint8_t sectors_per_cluster = io_data->volume_header->sectors_per_cluster;
|
||||
uint32_t cluster_size = 0;
|
||||
uint64_t metafiles_size = 0;
|
||||
|
||||
/** @see dislocker.c */
|
||||
extern dis_iodata_t disk_op_data;
|
||||
io_data->xinfo = NULL;
|
||||
io_data->sector_size = sector_size;
|
||||
io_data->part_off = dis_ctx->cfg.offset;
|
||||
io_data->decrypt_region = read_decrypt_sectors;
|
||||
io_data->encrypt_region = encrypt_write_sectors;
|
||||
|
||||
memset(&disk_op_data, 0, sizeof(dis_iodata_t));
|
||||
|
||||
disk_op_data.metadata = metadata;
|
||||
disk_op_data.xinfo = NULL;
|
||||
disk_op_data.sector_size = sector_size;
|
||||
disk_op_data.part_off = offset;
|
||||
disk_op_data.ctx = ctx;
|
||||
disk_op_data.cfg = cfg;
|
||||
disk_op_data.volume_fd = fd_volume;
|
||||
disk_op_data.decrypt_region = read_decrypt_sectors;
|
||||
disk_op_data.encrypt_region = encrypt_write_sectors;
|
||||
|
||||
if(pthread_mutex_init(&disk_op_data.mutex_lseek_rw, NULL) != 0)
|
||||
if(pthread_mutex_init(&io_data->mutex_lseek_rw, NULL) != 0)
|
||||
{
|
||||
xprintf(L_ERROR, "Can't initialize mutex: %s\n", strerror(errno));
|
||||
return FALSE;
|
||||
@@ -165,16 +149,18 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
|
||||
* We need to grab the volume's size from the first sector, so we can
|
||||
* announce it on a getattr call
|
||||
*/
|
||||
disk_op_data.volume_size = get_volume_size(volume_header, metadata,
|
||||
fd_volume);
|
||||
if(disk_op_data.volume_size == 0)
|
||||
io_data->volume_size = get_volume_size(io_data);
|
||||
if(io_data->volume_size == 0)
|
||||
{
|
||||
xprintf(L_ERROR, "Can't initialize the volume's size\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xprintf(L_INFO, "Found volume's size: 0x%1$" F_U64_T " (%1$llu) bytes\n",
|
||||
disk_op_data.volume_size);
|
||||
xprintf(
|
||||
L_INFO,
|
||||
"Found volume's size: 0x%1$" F_U64_T " (%1$llu) bytes\n",
|
||||
io_data->volume_size
|
||||
);
|
||||
|
||||
/*
|
||||
* Alignment isn't the same for W$ Vista (size-of-a-cluster aligned on
|
||||
@@ -197,11 +183,11 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
|
||||
* Initialize region to report as filled with zeroes, if asked from the NTFS
|
||||
* layer. This is to mimic BitLocker's behaviour.
|
||||
*/
|
||||
disk_op_data.nb_virt_region = 3;
|
||||
for(loop = 0; loop < disk_op_data.nb_virt_region; loop++)
|
||||
io_data->nb_virt_region = 3;
|
||||
for(loop = 0; loop < io_data->nb_virt_region; loop++)
|
||||
{
|
||||
disk_op_data.virt_region[loop].addr = metadata->offset_bl_header[loop];
|
||||
disk_op_data.virt_region[loop].size = metafiles_size;
|
||||
io_data->virt_region[loop].addr = metadata->offset_bl_header[loop];
|
||||
io_data->virt_region[loop].size = metafiles_size;
|
||||
}
|
||||
|
||||
if(metadata->version == V_VISTA)
|
||||
@@ -221,38 +207,46 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
|
||||
DATUM_VIRTUALIZATION_INFO, NULL, (void**)&datum))
|
||||
{
|
||||
char* type_str = datumtypestr(DATUM_VIRTUALIZATION_INFO);
|
||||
xprintf(L_ERROR, "Error looking for the VIRTUALIZATION datum type"
|
||||
" %hd (%s). Internal failure, abort.\n",
|
||||
DATUM_VIRTUALIZATION_INFO, type_str);
|
||||
xprintf(
|
||||
L_ERROR,
|
||||
"Error looking for the VIRTUALIZATION datum type"
|
||||
" %hd (%s). Internal failure, abort.\n",
|
||||
DATUM_VIRTUALIZATION_INFO,
|
||||
type_str
|
||||
);
|
||||
xfree(type_str);
|
||||
datum = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
disk_op_data.nb_virt_region++;
|
||||
disk_op_data.virt_region[3].addr = metadata->boot_sectors_backup;
|
||||
disk_op_data.virt_region[3].size = datum->nb_bytes;
|
||||
disk_op_data.virtualized_size = (off_t)datum->nb_bytes;
|
||||
io_data->nb_virt_region++;
|
||||
io_data->virt_region[3].addr = metadata->boot_sectors_backup;
|
||||
io_data->virt_region[3].size = datum->nb_bytes;
|
||||
io_data->virtualized_size = (off_t)datum->nb_bytes;
|
||||
|
||||
xprintf(L_DEBUG, "Virtualized info size: %#" F_OFF_T "\n",
|
||||
disk_op_data.virtualized_size);
|
||||
xprintf(
|
||||
L_DEBUG,
|
||||
"Virtualized info size: %#" F_OFF_T "\n",
|
||||
io_data->virtualized_size
|
||||
);
|
||||
|
||||
|
||||
/* Extended info is new to Windows 8 */
|
||||
// TODO add check on datum_types_prop's size against datum->header.datum_type
|
||||
size_t win7_size = datum_types_prop[datum->header.datum_type].size_header;
|
||||
size_t actual_size = ((size_t)datum->header.datum_size) & 0xffff;
|
||||
if(actual_size > win7_size)
|
||||
{
|
||||
disk_op_data.xinfo = &datum->xinfo;
|
||||
io_data->xinfo = &datum->xinfo;
|
||||
xprintf(L_DEBUG, "Got extended info\n");
|
||||
}
|
||||
|
||||
/* Another area to report as filled with zeroes, new to W8 as well */
|
||||
if(metadata->curr_state == SWITCHING_ENCRYPTION)
|
||||
{
|
||||
disk_op_data.nb_virt_region++;
|
||||
disk_op_data.virt_region[4].addr = metadata->encrypted_volume_size;
|
||||
disk_op_data.virt_region[4].size = metadata->unknown_size;
|
||||
io_data->nb_virt_region++;
|
||||
io_data->virt_region[4].addr = metadata->encrypted_volume_size;
|
||||
io_data->virt_region[4].size = metadata->unknown_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -262,17 +256,6 @@ int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check we can safely run without leaking information or breaking metadata
|
||||
*/
|
||||
extern guid_t INFORMATION_OFFSET_GUID;
|
||||
|
||||
if(!check_match_guid(volume_header->guid, INFORMATION_OFFSET_GUID))
|
||||
{
|
||||
xprintf(L_ERROR, "Unsupported volume GUID.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -310,31 +293,32 @@ static uint64_t get_volume_size_from_mbr(volume_header_t* volume_header)
|
||||
/**
|
||||
* Compute the real volume's size.
|
||||
*
|
||||
* @param volume_header First-sector data
|
||||
* @param metadata The BitLocker metadata block
|
||||
* @param fd The volume's file descriptor
|
||||
* @param io_data The structure holding major information for accessing the
|
||||
* volume
|
||||
* @return The volume size or 0 if it can't be determined
|
||||
*/
|
||||
static uint64_t get_volume_size(volume_header_t* volume_header,
|
||||
bitlocker_header_t* metadata,
|
||||
int fd_volume)
|
||||
static uint64_t get_volume_size(dis_iodata_t* io_data)
|
||||
{
|
||||
uint64_t volume_size = 0;
|
||||
|
||||
volume_size = get_volume_size_from_mbr(volume_header);
|
||||
volume_size = get_volume_size_from_mbr(io_data->volume_header);
|
||||
|
||||
if(!volume_size && metadata->version == V_SEVEN)
|
||||
if(!volume_size && io_data->metadata->version == V_SEVEN)
|
||||
{
|
||||
/*
|
||||
* For version V_SEVEN, volumes can be partially encrypted.
|
||||
* Therefore, try to get the real size from the NTFS data
|
||||
*/
|
||||
|
||||
uint8_t* input = xmalloc(volume_header->sector_size);
|
||||
memset(input, 0, volume_header->sector_size);
|
||||
uint8_t* input = xmalloc(io_data->volume_header->sector_size);
|
||||
memset(input, 0, io_data->volume_header->sector_size);
|
||||
|
||||
if(!read_decrypt_sectors(fd_volume, 1, volume_header->sector_size, 0,
|
||||
input))
|
||||
if(!read_decrypt_sectors(
|
||||
io_data,
|
||||
1,
|
||||
io_data->volume_header->sector_size,
|
||||
0,
|
||||
input))
|
||||
{
|
||||
xprintf(L_ERROR,
|
||||
"Unable to read the NTFS header to get the volume's size\n");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dislocker.h"
|
||||
#include "config.h"
|
||||
#include "encommon.h"
|
||||
#include "metadata/datums.h"
|
||||
@@ -42,9 +43,7 @@ int init_keys(bitlocker_dataset_t* dataset, datum_key_t* fvek, contexts_t* ctx);
|
||||
* Function used to prepare a structure which hold data used for
|
||||
* decryption/encryption
|
||||
*/
|
||||
int prepare_crypt(bitlocker_header_t* metadata, contexts_t* ctx,
|
||||
dis_config_t* cfg, volume_header_t* volume_header,
|
||||
off_t offset, int fd_volume);
|
||||
int prepare_crypt(dis_context_t* dis_ctx);
|
||||
|
||||
|
||||
#endif /* PREPARE_H */
|
||||
+104
-78
@@ -31,19 +31,25 @@
|
||||
#include "sectors.h"
|
||||
|
||||
|
||||
/** Data used globally for operation on disk (encryption/decryption) */
|
||||
dis_iodata_t disk_op_data;
|
||||
|
||||
|
||||
/** Prototype of functions used internally */
|
||||
static void* thread_decrypt(void* args);
|
||||
static void* thread_encrypt(void* args);
|
||||
static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
off_t sector_address, uint8_t *output);
|
||||
static void fix_read_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
|
||||
uint8_t *output);
|
||||
static void fix_write_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
|
||||
uint8_t *output);
|
||||
static void fix_read_sector_seven(
|
||||
dis_iodata_t* io_data,
|
||||
off_t sector_address,
|
||||
uint8_t *output
|
||||
);
|
||||
static void fix_read_sector_vista(
|
||||
dis_iodata_t* io_data,
|
||||
uint8_t* input,
|
||||
uint8_t *output
|
||||
);
|
||||
static void fix_write_sector_vista(
|
||||
dis_iodata_t* io_data,
|
||||
uint8_t* input,
|
||||
uint8_t *output
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +58,7 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
|
||||
* Read and decrypt one or more sectors
|
||||
* @warning The sector_start has to be correctly aligned
|
||||
*
|
||||
* @param fd The file descriptor to the volume
|
||||
* @param io_data The data structure containing volume's information
|
||||
* @param nb_read_sector The number of sectors to read
|
||||
* @param sector_size The size of one sector
|
||||
* @param sector_start The offset of the first sector to read; See the warning
|
||||
@@ -60,8 +66,12 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data, uint8_t* input,
|
||||
* @param output The output buffer where to put decrypted data
|
||||
* @return TRUE if result can be trusted, FALSE otherwise
|
||||
*/
|
||||
int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
off_t sector_start, uint8_t* output)
|
||||
int read_decrypt_sectors(
|
||||
dis_iodata_t* io_data,
|
||||
size_t nb_read_sector,
|
||||
uint16_t sector_size,
|
||||
off_t sector_start,
|
||||
uint8_t* output)
|
||||
{
|
||||
// Check parameters
|
||||
if(!output)
|
||||
@@ -77,7 +87,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
|
||||
|
||||
/* Be sure to lock for lseek/read */
|
||||
if(pthread_mutex_lock(&disk_op_data.mutex_lseek_rw) != 0)
|
||||
if(pthread_mutex_lock(&io_data->mutex_lseek_rw) != 0)
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Can't lock rw mutex: %s\n", strerror(errno));
|
||||
@@ -86,8 +96,8 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
|
||||
|
||||
/* Go where we need to read data */
|
||||
off_t off = sector_start + disk_op_data.part_off;
|
||||
if(lseek(fd, off, SEEK_SET) < 0)
|
||||
off_t off = sector_start + io_data->part_off;
|
||||
if(lseek(io_data->volume_fd, off, SEEK_SET) < 0)
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Unable to lseek to %#" F_OFF_T "\n", off);
|
||||
@@ -95,7 +105,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
}
|
||||
|
||||
/* Read the sectors we need */
|
||||
ssize_t read_size = read(fd, input, size);
|
||||
ssize_t read_size = read(io_data->volume_fd, input, size);
|
||||
|
||||
if(read_size <= 0)
|
||||
{
|
||||
@@ -106,7 +116,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
}
|
||||
|
||||
/* Unlock the previously locked mutex */
|
||||
if(pthread_mutex_unlock(&disk_op_data.mutex_lseek_rw) != 0)
|
||||
if(pthread_mutex_unlock(&io_data->mutex_lseek_rw) != 0)
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Can't unlock rw mutex: %s\n", strerror(errno));
|
||||
@@ -140,6 +150,8 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
args[loop].modulo = NB_THREAD;
|
||||
args[loop].modulo_result = loop;
|
||||
|
||||
args[loop].io_data = io_data;
|
||||
|
||||
pthread_create( &thread[loop], NULL,
|
||||
thread_decrypt, (void*) &args[loop] );
|
||||
}
|
||||
@@ -160,6 +172,8 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
arg.modulo = 0;
|
||||
arg.modulo_result = 42;
|
||||
|
||||
args.io_data = io_data;
|
||||
|
||||
thread_decrypt(&arg);
|
||||
}
|
||||
#endif
|
||||
@@ -175,7 +189,7 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
* Encrypt and write one or more sectors
|
||||
* @warning The sector_start has to be correctly aligned
|
||||
*
|
||||
* @param fd The file descriptor to the volume
|
||||
* @param io_data The data structure containing volume's information
|
||||
* @param nb_write_sector The number of sectors to write
|
||||
* @param sector_size The size of one sector
|
||||
* @param sector_start The offset of the first sector to write; See the warning
|
||||
@@ -183,8 +197,12 @@ int read_decrypt_sectors(int fd, size_t nb_read_sector, uint16_t sector_size,
|
||||
* @param output The input buffer which has to be encrypted and written
|
||||
* @return TRUE if result can be trusted, FALSE otherwise
|
||||
*/
|
||||
int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
|
||||
off_t sector_start, uint8_t* input)
|
||||
int encrypt_write_sectors(
|
||||
dis_iodata_t* io_data,
|
||||
size_t nb_write_sector,
|
||||
uint16_t sector_size,
|
||||
off_t sector_start,
|
||||
uint8_t* input)
|
||||
{
|
||||
// Check parameter
|
||||
if(!input)
|
||||
@@ -213,6 +231,8 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
|
||||
args[loop].modulo = NB_THREAD;
|
||||
args[loop].modulo_result = loop;
|
||||
|
||||
args[loop].io_data = io_data;
|
||||
|
||||
pthread_create( &thread[loop], NULL,
|
||||
thread_encrypt, (void*) &args[loop] );
|
||||
}
|
||||
@@ -233,12 +253,14 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
|
||||
arg.modulo = 0;
|
||||
arg.modulo_result = 42;
|
||||
|
||||
args.io_data = io_data;
|
||||
|
||||
thread_encrypt(&arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Be sure to lock for lseek/write */
|
||||
if(pthread_mutex_lock(&disk_op_data.mutex_lseek_rw) != 0)
|
||||
if(pthread_mutex_lock(&io_data->mutex_lseek_rw) != 0)
|
||||
{
|
||||
free(output);
|
||||
xprintf(L_ERROR, "Can't lock rw mutex: %s\n", strerror(errno));
|
||||
@@ -246,8 +268,8 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
|
||||
}
|
||||
|
||||
/* Go where we need to write data */
|
||||
off_t off = sector_start + disk_op_data.part_off;
|
||||
if(lseek(fd, off, SEEK_SET) < 0)
|
||||
off_t off = sector_start + io_data->part_off;
|
||||
if(lseek(io_data->volume_fd, off, SEEK_SET) < 0)
|
||||
{
|
||||
free(output);
|
||||
xprintf(L_ERROR, "Unable to lseek to %#" F_OFF_T "\n", off);
|
||||
@@ -255,13 +277,17 @@ int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size,
|
||||
}
|
||||
|
||||
/* Write the sectors we want */
|
||||
ssize_t write_size = write(fd, output, nb_write_sector * sector_size);
|
||||
ssize_t write_size = write(
|
||||
io_data->volume_fd,
|
||||
output,
|
||||
nb_write_sector * sector_size
|
||||
);
|
||||
|
||||
/* Unlock the previously locked mutex */
|
||||
if(pthread_mutex_unlock(&disk_op_data.mutex_lseek_rw) != 0)
|
||||
if(pthread_mutex_unlock(&io_data->mutex_lseek_rw) != 0)
|
||||
{
|
||||
free(output);
|
||||
xprintf(L_ERROR, "Can't unlock rw mutex: %s\n", strerror(errno));
|
||||
free(output);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -283,7 +309,8 @@ static void* thread_decrypt(void* params)
|
||||
if(!params)
|
||||
return NULL;
|
||||
|
||||
thread_arg_t* args = (thread_arg_t*)params;
|
||||
thread_arg_t* args = (thread_arg_t*)params;
|
||||
dis_iodata_t* io_data = args->io_data;
|
||||
|
||||
off_t loop = 0;
|
||||
off_t offset = args->sector_start;
|
||||
@@ -293,7 +320,7 @@ static void* thread_decrypt(void* params)
|
||||
|
||||
size_t virt_loop = 0;
|
||||
off_t metadata_offset = 0;
|
||||
uint16_t version = disk_op_data.metadata->version;
|
||||
uint16_t version = io_data->metadata->version;
|
||||
|
||||
off_t size = 0;
|
||||
|
||||
@@ -325,13 +352,13 @@ static void* thread_decrypt(void* params)
|
||||
off_t sector_offset = args->sector_start / args->sector_size + loop;
|
||||
|
||||
/* Check for zero out areas */
|
||||
for(virt_loop = 0; virt_loop < disk_op_data.nb_virt_region; virt_loop++)
|
||||
for(virt_loop = 0; virt_loop < io_data->nb_virt_region; virt_loop++)
|
||||
{
|
||||
size = (off_t)disk_op_data.virt_region[virt_loop].size;
|
||||
size = (off_t)io_data->virt_region[virt_loop].size;
|
||||
if(size == 0)
|
||||
continue;
|
||||
|
||||
metadata_offset = (off_t)disk_op_data.virt_region[virt_loop].addr;
|
||||
metadata_offset = (off_t)io_data->virt_region[virt_loop].addr;
|
||||
if(offset >= metadata_offset &&
|
||||
offset <= metadata_offset + size)
|
||||
{
|
||||
@@ -348,20 +375,20 @@ static void* thread_decrypt(void* params)
|
||||
|
||||
/* Check for sectors fixing and non-encrypted sectors */
|
||||
if(version == V_SEVEN &&
|
||||
(uint64_t)sector_offset < disk_op_data.metadata->nb_backup_sectors)
|
||||
(uint64_t)sector_offset < io_data->metadata->nb_backup_sectors)
|
||||
{
|
||||
/*
|
||||
* The firsts sectors are encrypted in a different place on a
|
||||
* Windows 7 volume
|
||||
*/
|
||||
fix_read_sector_seven(
|
||||
&disk_op_data,
|
||||
io_data,
|
||||
offset,
|
||||
loop_output
|
||||
);
|
||||
}
|
||||
else if(version == V_SEVEN &&
|
||||
(uint64_t)offset >= disk_op_data.metadata->encrypted_volume_size)
|
||||
(uint64_t)offset >= io_data->metadata->encrypted_volume_size)
|
||||
{
|
||||
/* Do not decrypt when there's nothing to */
|
||||
xprintf(L_DEBUG,
|
||||
@@ -378,9 +405,9 @@ static void* thread_decrypt(void* params)
|
||||
*/
|
||||
if(sector_offset < 1)
|
||||
fix_read_sector_vista(
|
||||
&disk_op_data,
|
||||
loop_input,
|
||||
loop_output
|
||||
io_data,
|
||||
loop_input,
|
||||
loop_output
|
||||
);
|
||||
else
|
||||
{
|
||||
@@ -396,7 +423,7 @@ static void* thread_decrypt(void* params)
|
||||
{
|
||||
/* Decrypt the sector */
|
||||
if(!decrypt_sector(
|
||||
&disk_op_data,
|
||||
io_data,
|
||||
loop_input,
|
||||
offset,
|
||||
loop_output
|
||||
@@ -420,7 +447,8 @@ static void* thread_encrypt(void* params)
|
||||
if(!params)
|
||||
return NULL;
|
||||
|
||||
thread_arg_t* args = (thread_arg_t*)params;
|
||||
thread_arg_t* args = (thread_arg_t*)params;
|
||||
dis_iodata_t* io_data = args->io_data;
|
||||
|
||||
off_t loop = 0;
|
||||
off_t offset = args->sector_start;
|
||||
@@ -428,7 +456,7 @@ static void* thread_encrypt(void* params)
|
||||
uint8_t* loop_input = args->input;
|
||||
uint8_t* loop_output = args->output;
|
||||
|
||||
uint16_t version = disk_op_data.metadata->version;
|
||||
uint16_t version = io_data->metadata->version;
|
||||
|
||||
|
||||
for(loop = 0; loop < (off_t)args->nb_loop; ++loop,
|
||||
@@ -451,7 +479,7 @@ static void* thread_encrypt(void* params)
|
||||
|
||||
/*
|
||||
* NOTE: Seven specificities are dealt with earlier in the process
|
||||
* see fuse.c:fs_write()
|
||||
* see dislocker.c:enlock()
|
||||
*/
|
||||
if(version == V_VISTA && sector_offset < 16)
|
||||
{
|
||||
@@ -460,22 +488,22 @@ static void* thread_encrypt(void* params)
|
||||
*/
|
||||
if(sector_offset < 1)
|
||||
fix_write_sector_vista(
|
||||
&disk_op_data,
|
||||
loop_input,
|
||||
loop_output
|
||||
io_data,
|
||||
loop_input,
|
||||
loop_output
|
||||
);
|
||||
else
|
||||
memcpy(loop_output, loop_input, args->sector_size);
|
||||
}
|
||||
else if(version == V_SEVEN &&
|
||||
(uint64_t)offset >= disk_op_data.metadata->encrypted_volume_size)
|
||||
(uint64_t)offset >= io_data->metadata->encrypted_volume_size)
|
||||
{
|
||||
memcpy(loop_output, loop_input, args->sector_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!encrypt_sector(
|
||||
&disk_op_data,
|
||||
io_data,
|
||||
loop_input,
|
||||
offset,
|
||||
loop_output
|
||||
@@ -497,12 +525,11 @@ static void* thread_encrypt(void* params)
|
||||
* "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Seven for
|
||||
* read operation
|
||||
*
|
||||
* @param disk_op_data Data needed by FUSE and the decryption to deal with
|
||||
* encrypted data
|
||||
* @param io_data Data needed by the decryption to deal with encrypted data
|
||||
* @param sector_address Address of the sector to decrypt
|
||||
* @param output The buffer where to put fixed data
|
||||
*/
|
||||
static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
static void fix_read_sector_seven(dis_iodata_t* io_data,
|
||||
off_t sector_address, uint8_t *output)
|
||||
{
|
||||
// Check parameter
|
||||
@@ -515,19 +542,19 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
* So we can use them here to give a good NTFS partition's beginning.
|
||||
*/
|
||||
off_t from = sector_address;
|
||||
off_t to = from + (off_t)disk_op_data->metadata->boot_sectors_backup;
|
||||
off_t to = from + (off_t)io_data->metadata->boot_sectors_backup;
|
||||
|
||||
xprintf(L_DEBUG, " Fixing sector (7): from %#" F_OFF_T " to %#" F_OFF_T
|
||||
"\n", from, to);
|
||||
|
||||
to += disk_op_data->part_off;
|
||||
to += io_data->part_off;
|
||||
|
||||
|
||||
uint8_t* input = malloc(disk_op_data->sector_size);
|
||||
memset(input, 0, disk_op_data->sector_size);
|
||||
uint8_t* input = malloc(io_data->sector_size);
|
||||
memset(input, 0, io_data->sector_size);
|
||||
|
||||
/* Be sure to lock for lseek/read */
|
||||
if(pthread_mutex_lock(&disk_op_data->mutex_lseek_rw) != 0)
|
||||
if(pthread_mutex_lock(&io_data->mutex_lseek_rw) != 0)
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Can't lock rw mutex: %s\n", strerror(errno));
|
||||
@@ -535,7 +562,7 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
}
|
||||
|
||||
/* Go where we need to read the new sector */
|
||||
if(lseek(disk_op_data->volume_fd, to, SEEK_SET) <0)
|
||||
if(lseek(io_data->volume_fd, to, SEEK_SET) <0)
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Unable to lseek to %#" F_OFF_T "\n", to);
|
||||
@@ -543,12 +570,11 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
}
|
||||
|
||||
/* Read the real sector we need */
|
||||
ssize_t read_size = read(disk_op_data->volume_fd, input,
|
||||
disk_op_data->sector_size);
|
||||
ssize_t read_size = read(io_data->volume_fd, input, io_data->sector_size);
|
||||
|
||||
|
||||
/* Unlock the previously locked mutex */
|
||||
if(pthread_mutex_unlock(&disk_op_data->mutex_lseek_rw) != 0)
|
||||
if(pthread_mutex_unlock(&io_data->mutex_lseek_rw) != 0)
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Can't unlock rw mutex: %s\n", strerror(errno));
|
||||
@@ -560,21 +586,21 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
{
|
||||
free(input);
|
||||
xprintf(L_ERROR, "Unable to read %#" F_SIZE_T " bytes from %#" F_OFF_T
|
||||
"\n", disk_op_data->sector_size, to);
|
||||
"\n", io_data->sector_size, to);
|
||||
return;
|
||||
}
|
||||
|
||||
to -= disk_op_data->part_off;
|
||||
to -= io_data->part_off;
|
||||
|
||||
/* If the sector wasn't yet encrypted, don't decrypt it */
|
||||
if((uint64_t)to >= disk_op_data->metadata->encrypted_volume_size)
|
||||
if((uint64_t)to >= io_data->metadata->encrypted_volume_size)
|
||||
{
|
||||
memcpy(output, input, disk_op_data->sector_size);
|
||||
memcpy(output, input, io_data->sector_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
decrypt_sector(
|
||||
disk_op_data,
|
||||
io_data,
|
||||
input,
|
||||
to,
|
||||
output
|
||||
@@ -589,12 +615,11 @@ static void fix_read_sector_seven(dis_iodata_t* disk_op_data,
|
||||
* "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Vista for
|
||||
* read operation
|
||||
*
|
||||
* @param disk_op_data Data needed by FUSE and the decryption to deal with
|
||||
* encrypted data
|
||||
* @param io_data Data needed by the decryption to deal with encrypted data
|
||||
* @param input The sector which needs a fix
|
||||
* @param output The buffer where to put fixed data
|
||||
*/
|
||||
static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
|
||||
static void fix_read_sector_vista(dis_iodata_t* io_data,
|
||||
uint8_t* input, uint8_t *output)
|
||||
{
|
||||
// Check parameter
|
||||
@@ -603,12 +628,12 @@ static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
|
||||
|
||||
xprintf(L_DEBUG, " Fixing sector (Vista): replacing signature "
|
||||
"and MFTMirror field by: %#llx\n",
|
||||
disk_op_data->metadata->mftmirror_backup);
|
||||
io_data->metadata->mftmirror_backup);
|
||||
|
||||
/*
|
||||
* Only two fields need to be changed: the NTFS signature and the MFT mirror
|
||||
*/
|
||||
memcpy(output, input, disk_op_data->sector_size);
|
||||
memcpy(output, input, io_data->sector_size);
|
||||
|
||||
volume_header_t* formatted_output = (volume_header_t*)output;
|
||||
|
||||
@@ -616,7 +641,7 @@ static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
|
||||
memcpy(formatted_output->signature, NTFS_SIGNATURE, NTFS_SIGNATURE_SIZE);
|
||||
|
||||
/* And this is for the MFT Mirror field */
|
||||
formatted_output->mft_mirror = disk_op_data->metadata->mftmirror_backup;
|
||||
formatted_output->mft_mirror = io_data->metadata->mftmirror_backup;
|
||||
}
|
||||
|
||||
|
||||
@@ -624,12 +649,11 @@ static void fix_read_sector_vista(dis_iodata_t* disk_op_data,
|
||||
* "Fix" the firsts sectors of a BitLocker volume encrypted with W$ Vista for
|
||||
* write operation
|
||||
*
|
||||
* @param disk_op_data Data needed by FUSE and the decryption to deal with
|
||||
* encrypted data
|
||||
* @param io_data Data needed by the decryption to deal with encrypted data
|
||||
* @param input The sector which needs a fix
|
||||
* @param output The buffer where to put fixed data
|
||||
*/
|
||||
static void fix_write_sector_vista(dis_iodata_t* disk_op_data,
|
||||
static void fix_write_sector_vista(dis_iodata_t* io_data,
|
||||
uint8_t* input, uint8_t *output)
|
||||
{
|
||||
// Check parameter
|
||||
@@ -639,7 +663,7 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data,
|
||||
/*
|
||||
* Only two fields need to be changed: the NTFS signature and the MFT mirror
|
||||
*/
|
||||
memcpy(output, input, disk_op_data->sector_size);
|
||||
memcpy(output, input, io_data->sector_size);
|
||||
|
||||
volume_header_t* formatted_output = (volume_header_t*)output;
|
||||
|
||||
@@ -649,15 +673,17 @@ static void fix_write_sector_vista(dis_iodata_t* disk_op_data,
|
||||
|
||||
/* And this is for the metadata LCN */
|
||||
formatted_output->metadata_lcn =
|
||||
disk_op_data->metadata->offset_bl_header[0] /
|
||||
io_data->metadata->offset_bl_header[0] /
|
||||
(uint64_t)(
|
||||
formatted_output->sectors_per_cluster *
|
||||
formatted_output->sector_size
|
||||
);
|
||||
|
||||
xprintf(L_DEBUG, " Fixing sector (Vista): replacing signature "
|
||||
"and MFTMirror field by: %#llx\n",
|
||||
formatted_output->metadata_lcn);
|
||||
|
||||
xprintf(
|
||||
L_DEBUG,
|
||||
" Fixing sector (Vista): replacing signature "
|
||||
"and MFTMirror field by: %#llx\n",
|
||||
formatted_output->metadata_lcn
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+18
-2
@@ -34,6 +34,8 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "dislocker.h"
|
||||
|
||||
|
||||
/* Struct we pass to a thread for buffer enc/decryption */
|
||||
typedef struct _thread_arg
|
||||
@@ -48,6 +50,8 @@ typedef struct _thread_arg
|
||||
|
||||
unsigned int modulo;
|
||||
unsigned int modulo_result;
|
||||
|
||||
dis_iodata_t* io_data;
|
||||
} thread_arg_t;
|
||||
|
||||
|
||||
@@ -56,7 +60,19 @@ typedef struct _thread_arg
|
||||
/*
|
||||
* Functions prototypes
|
||||
*/
|
||||
int read_decrypt_sectors( int fd, size_t nb_read_sector, uint16_t sector_size, off_t sector_start, uint8_t* output);
|
||||
int encrypt_write_sectors(int fd, size_t nb_write_sector, uint16_t sector_size, off_t sector_start, uint8_t* input);
|
||||
int read_decrypt_sectors(
|
||||
dis_iodata_t* io_data,
|
||||
size_t nb_read_sector,
|
||||
uint16_t sector_size,
|
||||
off_t sector_start,
|
||||
uint8_t* output
|
||||
);
|
||||
int encrypt_write_sectors(
|
||||
dis_iodata_t* io_data,
|
||||
size_t nb_write_sector,
|
||||
uint16_t sector_size,
|
||||
off_t sector_start,
|
||||
uint8_t* input
|
||||
);
|
||||
|
||||
#endif /* SECTORS_H */
|
||||
|
||||
Reference in New Issue
Block a user