1 /*
2 * Mounts a BitLocker Drive Encrypted (BDE) volume
3 *
4 * Copyright (C) 2011-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <file_stream.h>
24 #include <memory.h>
25 #include <system_string.h>
26 #include <types.h>
27
28 #include <stdio.h>
29
30 #if defined( HAVE_IO_H ) || defined( WINAPI )
31 #include <io.h>
32 #endif
33
34 #if defined( HAVE_STDLIB_H ) || defined( WINAPI )
35 #include <stdlib.h>
36 #endif
37
38 #if defined( HAVE_UNISTD_H )
39 #include <unistd.h>
40 #endif
41
42 #include "bdetools_getopt.h"
43 #include "bdetools_i18n.h"
44 #include "bdetools_libbde.h"
45 #include "bdetools_libcerror.h"
46 #include "bdetools_libclocale.h"
47 #include "bdetools_libcnotify.h"
48 #include "bdetools_output.h"
49 #include "bdetools_signal.h"
50 #include "bdetools_unused.h"
51 #include "mount_dokan.h"
52 #include "mount_fuse.h"
53 #include "mount_handle.h"
54
55 mount_handle_t *bdemount_mount_handle = NULL;
56 int bdemount_abort = 0;
57
58 /* Prints usage information
59 */
usage_fprint(FILE * stream)60 void usage_fprint(
61 FILE *stream )
62 {
63 if( stream == NULL )
64 {
65 return;
66 }
67 fprintf( stream, "Use bdemount to mount a BitLocker Drive Encrypted (BDE) volume\n\n" );
68
69 fprintf( stream, "Usage: bdemount [ -k keys ] [ -o offset ] [ -p password ]\n"
70 " [ -r recovery_password ] [ -s startup_key_path ]\n"
71 " [ -X extended_options ] [ -hvV ] volume mount_point\n\n" );
72
73 fprintf( stream, "\tvolume: a BitLocker Drive Encrypted (BDE) volume\n\n" );
74 fprintf( stream, "\tmount_point: the directory to serve as mount point\n\n" );
75
76 fprintf( stream, "\t-h: shows this help\n" );
77 fprintf( stream, "\t-k: specify the full volume encryption key and tweak key formatted in\n"
78 "\t base16 and separated by a : character e.g. FVEK:TWEAK\n" );
79 fprintf( stream, "\t-o: specify the volume offset in bytes\n" );
80 fprintf( stream, "\t-p: specify the password/passphrase\n" );
81 fprintf( stream, "\t-r: specify the recovery password/passphrase\n" );
82 fprintf( stream, "\t-s: specify the path of the file containing the startup key. Typically\n"
83 "\t this file has the extension .BEK\n" );
84 fprintf( stream, "\t-v: verbose output to stderr, while bdemount will remain running in the\n"
85 "\t foreground\n" );
86 fprintf( stream, "\t-V: print version\n" );
87 fprintf( stream, "\t-X: extended options to pass to sub system\n" );
88 }
89
90 /* Signal handler for bdemount
91 */
bdemount_signal_handler(bdetools_signal_t signal BDETOOLS_ATTRIBUTE_UNUSED)92 void bdemount_signal_handler(
93 bdetools_signal_t signal BDETOOLS_ATTRIBUTE_UNUSED )
94 {
95 libcerror_error_t *error = NULL;
96 static char *function = "bdemount_signal_handler";
97
98 BDETOOLS_UNREFERENCED_PARAMETER( signal )
99
100 bdemount_abort = 1;
101
102 if( bdemount_mount_handle != NULL )
103 {
104 if( mount_handle_signal_abort(
105 bdemount_mount_handle,
106 &error ) != 1 )
107 {
108 libcnotify_printf(
109 "%s: unable to signal mount handle to abort.\n",
110 function );
111
112 libcnotify_print_error_backtrace(
113 error );
114 libcerror_error_free(
115 &error );
116 }
117 }
118 /* Force stdin to close otherwise any function reading it will remain blocked
119 */
120 #if defined( WINAPI ) && !defined( __CYGWIN__ )
121 if( _close(
122 0 ) != 0 )
123 #else
124 if( close(
125 0 ) != 0 )
126 #endif
127 {
128 libcnotify_printf(
129 "%s: unable to close stdin.\n",
130 function );
131 }
132 }
133
134 /* The main program
135 */
136 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
wmain(int argc,wchar_t * const argv[])137 int wmain( int argc, wchar_t * const argv[] )
138 #else
139 int main( int argc, char * const argv[] )
140 #endif
141 {
142 libbde_error_t *error = NULL;
143 system_character_t *mount_point = NULL;
144 system_character_t *option_extended_options = NULL;
145 system_character_t *option_keys = NULL;
146 system_character_t *option_offset = NULL;
147 system_character_t *option_password = NULL;
148 system_character_t *option_recovery_password = NULL;
149 system_character_t *option_startup_key_path = NULL;
150 const system_character_t *path_prefix = NULL;
151 system_character_t *source = NULL;
152 char *program = "bdemount";
153 system_integer_t option = 0;
154 size_t path_prefix_size = 0;
155 int result = 0;
156 int verbose = 0;
157
158 #if defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE )
159 struct fuse_operations bdemount_fuse_operations;
160
161 struct fuse_args bdemount_fuse_arguments = FUSE_ARGS_INIT(0, NULL);
162 struct fuse_chan *bdemount_fuse_channel = NULL;
163 struct fuse *bdemount_fuse_handle = NULL;
164
165 #elif defined( HAVE_LIBDOKAN )
166 DOKAN_OPERATIONS bdemount_dokan_operations;
167 DOKAN_OPTIONS bdemount_dokan_options;
168 #endif
169
170 libcnotify_stream_set(
171 stderr,
172 NULL );
173 libcnotify_verbose_set(
174 1 );
175
176 if( libclocale_initialize(
177 "bdetools",
178 &error ) != 1 )
179 {
180 fprintf(
181 stderr,
182 "Unable to initialize locale values.\n" );
183
184 goto on_error;
185 }
186 if( bdetools_output_initialize(
187 _IONBF,
188 &error ) != 1 )
189 {
190 fprintf(
191 stderr,
192 "Unable to initialize output settings.\n" );
193
194 goto on_error;
195 }
196 bdetools_output_version_fprint(
197 stdout,
198 program );
199
200 while( ( option = bdetools_getopt(
201 argc,
202 argv,
203 _SYSTEM_STRING( "hk:o:p:r:s:vVX:" ) ) ) != (system_integer_t) -1 )
204 {
205 switch( option )
206 {
207 case (system_integer_t) '?':
208 default:
209 fprintf(
210 stderr,
211 "Invalid argument: %" PRIs_SYSTEM "\n",
212 argv[ optind - 1 ] );
213
214 usage_fprint(
215 stdout );
216
217 return( EXIT_FAILURE );
218
219 case (system_integer_t) 'h':
220 usage_fprint(
221 stdout );
222
223 return( EXIT_SUCCESS );
224
225 case (system_integer_t) 'k':
226 option_keys = optarg;
227
228 break;
229
230 case (system_integer_t) 'o':
231 option_offset = optarg;
232
233 break;
234
235 case (system_integer_t) 'p':
236 option_password = optarg;
237
238 break;
239
240 case (system_integer_t) 'r':
241 option_recovery_password = optarg;
242
243 break;
244
245 case (system_integer_t) 's':
246 option_startup_key_path = optarg;
247
248 break;
249
250 case (system_integer_t) 'v':
251 verbose = 1;
252
253 break;
254
255 case (system_integer_t) 'V':
256 bdetools_output_copyright_fprint(
257 stdout );
258
259 return( EXIT_SUCCESS );
260
261 case (system_integer_t) 'X':
262 option_extended_options = optarg;
263
264 break;
265 }
266 }
267 if( optind == argc )
268 {
269 fprintf(
270 stderr,
271 "Missing source volume.\n" );
272
273 usage_fprint(
274 stdout );
275
276 return( EXIT_FAILURE );
277 }
278 source = argv[ optind++ ];
279
280 if( optind == argc )
281 {
282 fprintf(
283 stderr,
284 "Missing mount point.\n" );
285
286 usage_fprint(
287 stdout );
288
289 return( EXIT_FAILURE );
290 }
291 mount_point = argv[ optind ];
292
293 libcnotify_verbose_set(
294 verbose );
295 libbde_notify_set_stream(
296 stderr,
297 NULL );
298 libbde_notify_set_verbose(
299 verbose );
300
301 if( mount_handle_initialize(
302 &bdemount_mount_handle,
303 &error ) != 1 )
304 {
305 fprintf(
306 stderr,
307 "Unable to initialize mount handle.\n" );
308
309 goto on_error;
310 }
311 if( option_keys != NULL )
312 {
313 if( mount_handle_set_keys(
314 bdemount_mount_handle,
315 option_keys,
316 &error ) != 1 )
317 {
318 fprintf(
319 stderr,
320 "Unable to set keys.\n" );
321
322 goto on_error;
323 }
324 }
325 if( option_offset != NULL )
326 {
327 if( mount_handle_set_offset(
328 bdemount_mount_handle,
329 option_offset,
330 &error ) != 1 )
331 {
332 fprintf(
333 stderr,
334 "Unable to set volume offset.\n" );
335
336 goto on_error;
337 }
338 }
339 if( option_password != NULL )
340 {
341 if( mount_handle_set_password(
342 bdemount_mount_handle,
343 option_password,
344 &error ) != 1 )
345 {
346 fprintf(
347 stderr,
348 "Unable to set password.\n" );
349
350 goto on_error;
351 }
352 }
353 if( option_recovery_password != NULL )
354 {
355 if( mount_handle_set_recovery_password(
356 bdemount_mount_handle,
357 option_recovery_password,
358 &error ) != 1 )
359 {
360 fprintf(
361 stderr,
362 "Unable to set recovery password.\n" );
363
364 goto on_error;
365 }
366 }
367 if( option_startup_key_path != NULL )
368 {
369 if( mount_handle_set_startup_key(
370 bdemount_mount_handle,
371 option_startup_key_path,
372 &error ) != 1 )
373 {
374 fprintf(
375 stderr,
376 "Unable to set startup key.\n" );
377
378 goto on_error;
379 }
380 }
381 #if defined( WINAPI )
382 path_prefix = _SYSTEM_STRING( "\\BDE" );
383 #else
384 path_prefix = _SYSTEM_STRING( "/bde" );
385 #endif
386 path_prefix_size = 1 + system_string_length(
387 path_prefix );
388
389 if( mount_handle_set_path_prefix(
390 bdemount_mount_handle,
391 path_prefix,
392 path_prefix_size,
393 &error ) != 1 )
394 {
395 fprintf(
396 stderr,
397 "Unable to set path prefix.\n" );
398
399 goto on_error;
400 }
401 if( mount_handle_open(
402 bdemount_mount_handle,
403 source,
404 &error ) != 1 )
405 {
406 fprintf(
407 stderr,
408 "Unable to open source volume\n" );
409
410 goto on_error;
411 }
412 if( mount_handle_is_locked(
413 bdemount_mount_handle,
414 &error ) != 0 )
415 {
416 fprintf(
417 stderr,
418 "Unable to unlock source volume\n" );
419
420 goto on_error;
421 }
422 #if defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE )
423 if( option_extended_options != NULL )
424 {
425 /* This argument is required but ignored
426 */
427 if( fuse_opt_add_arg(
428 &bdemount_fuse_arguments,
429 "" ) != 0 )
430 {
431 fprintf(
432 stderr,
433 "Unable add fuse arguments.\n" );
434
435 goto on_error;
436 }
437 if( fuse_opt_add_arg(
438 &bdemount_fuse_arguments,
439 "-o" ) != 0 )
440 {
441 fprintf(
442 stderr,
443 "Unable add fuse arguments.\n" );
444
445 goto on_error;
446 }
447 if( fuse_opt_add_arg(
448 &bdemount_fuse_arguments,
449 option_extended_options ) != 0 )
450 {
451 fprintf(
452 stderr,
453 "Unable add fuse arguments.\n" );
454
455 goto on_error;
456 }
457 }
458 if( memory_set(
459 &bdemount_fuse_operations,
460 0,
461 sizeof( struct fuse_operations ) ) == NULL )
462 {
463 fprintf(
464 stderr,
465 "Unable to clear fuse operations.\n" );
466
467 goto on_error;
468 }
469 bdemount_fuse_operations.open = &mount_fuse_open;
470 bdemount_fuse_operations.read = &mount_fuse_read;
471 bdemount_fuse_operations.release = &mount_fuse_release;
472 bdemount_fuse_operations.opendir = &mount_fuse_opendir;
473 bdemount_fuse_operations.readdir = &mount_fuse_readdir;
474 bdemount_fuse_operations.releasedir = &mount_fuse_releasedir;
475 bdemount_fuse_operations.getattr = &mount_fuse_getattr;
476 bdemount_fuse_operations.destroy = &mount_fuse_destroy;
477
478 bdemount_fuse_channel = fuse_mount(
479 mount_point,
480 &bdemount_fuse_arguments );
481
482 if( bdemount_fuse_channel == NULL )
483 {
484 fprintf(
485 stderr,
486 "Unable to create fuse channel.\n" );
487
488 goto on_error;
489 }
490 bdemount_fuse_handle = fuse_new(
491 bdemount_fuse_channel,
492 &bdemount_fuse_arguments,
493 &bdemount_fuse_operations,
494 sizeof( struct fuse_operations ),
495 bdemount_mount_handle );
496
497 if( bdemount_fuse_handle == NULL )
498 {
499 fprintf(
500 stderr,
501 "Unable to create fuse handle.\n" );
502
503 goto on_error;
504 }
505 if( verbose == 0 )
506 {
507 if( fuse_daemonize(
508 0 ) != 0 )
509 {
510 fprintf(
511 stderr,
512 "Unable to daemonize fuse.\n" );
513
514 goto on_error;
515 }
516 }
517 result = fuse_loop(
518 bdemount_fuse_handle );
519
520 if( result != 0 )
521 {
522 fprintf(
523 stderr,
524 "Unable to run fuse loop.\n" );
525
526 goto on_error;
527 }
528 fuse_destroy(
529 bdemount_fuse_handle );
530
531 fuse_opt_free_args(
532 &bdemount_fuse_arguments );
533
534 return( EXIT_SUCCESS );
535
536 #elif defined( HAVE_LIBDOKAN )
537 if( memory_set(
538 &bdemount_dokan_operations,
539 0,
540 sizeof( DOKAN_OPERATIONS ) ) == NULL )
541 {
542 fprintf(
543 stderr,
544 "Unable to clear dokan operations.\n" );
545
546 goto on_error;
547 }
548 if( memory_set(
549 &bdemount_dokan_options,
550 0,
551 sizeof( DOKAN_OPTIONS ) ) == NULL )
552 {
553 fprintf(
554 stderr,
555 "Unable to clear dokan options.\n" );
556
557 goto on_error;
558 }
559 bdemount_dokan_options.Version = DOKAN_VERSION;
560 bdemount_dokan_options.ThreadCount = 0;
561 bdemount_dokan_options.MountPoint = mount_point;
562
563 if( verbose != 0 )
564 {
565 bdemount_dokan_options.Options |= DOKAN_OPTION_STDERR;
566 #if defined( HAVE_DEBUG_OUTPUT )
567 bdemount_dokan_options.Options |= DOKAN_OPTION_DEBUG;
568 #endif
569 }
570 /* This will only affect the drive properties
571 bdemount_dokan_options.Options |= DOKAN_OPTION_REMOVABLE;
572 */
573
574 #if ( DOKAN_VERSION >= 600 ) && ( DOKAN_VERSION < 800 )
575 bdemount_dokan_options.Options |= DOKAN_OPTION_KEEP_ALIVE;
576
577 bdemount_dokan_operations.CreateFile = &mount_dokan_CreateFile;
578 bdemount_dokan_operations.OpenDirectory = &mount_dokan_OpenDirectory;
579 bdemount_dokan_operations.CreateDirectory = NULL;
580 bdemount_dokan_operations.Cleanup = NULL;
581 bdemount_dokan_operations.CloseFile = &mount_dokan_CloseFile;
582 bdemount_dokan_operations.ReadFile = &mount_dokan_ReadFile;
583 bdemount_dokan_operations.WriteFile = NULL;
584 bdemount_dokan_operations.FlushFileBuffers = NULL;
585 bdemount_dokan_operations.GetFileInformation = &mount_dokan_GetFileInformation;
586 bdemount_dokan_operations.FindFiles = &mount_dokan_FindFiles;
587 bdemount_dokan_operations.FindFilesWithPattern = NULL;
588 bdemount_dokan_operations.SetFileAttributes = NULL;
589 bdemount_dokan_operations.SetFileTime = NULL;
590 bdemount_dokan_operations.DeleteFile = NULL;
591 bdemount_dokan_operations.DeleteDirectory = NULL;
592 bdemount_dokan_operations.MoveFile = NULL;
593 bdemount_dokan_operations.SetEndOfFile = NULL;
594 bdemount_dokan_operations.SetAllocationSize = NULL;
595 bdemount_dokan_operations.LockFile = NULL;
596 bdemount_dokan_operations.UnlockFile = NULL;
597 bdemount_dokan_operations.GetFileSecurity = NULL;
598 bdemount_dokan_operations.SetFileSecurity = NULL;
599 bdemount_dokan_operations.GetDiskFreeSpace = NULL;
600 bdemount_dokan_operations.GetVolumeInformation = &mount_dokan_GetVolumeInformation;
601 bdemount_dokan_operations.Unmount = &mount_dokan_Unmount;
602
603 #else
604 bdemount_dokan_operations.ZwCreateFile = &mount_dokan_ZwCreateFile;
605 bdemount_dokan_operations.Cleanup = NULL;
606 bdemount_dokan_operations.CloseFile = &mount_dokan_CloseFile;
607 bdemount_dokan_operations.ReadFile = &mount_dokan_ReadFile;
608 bdemount_dokan_operations.WriteFile = NULL;
609 bdemount_dokan_operations.FlushFileBuffers = NULL;
610 bdemount_dokan_operations.GetFileInformation = &mount_dokan_GetFileInformation;
611 bdemount_dokan_operations.FindFiles = &mount_dokan_FindFiles;
612 bdemount_dokan_operations.FindFilesWithPattern = NULL;
613 bdemount_dokan_operations.SetFileAttributes = NULL;
614 bdemount_dokan_operations.SetFileTime = NULL;
615 bdemount_dokan_operations.DeleteFile = NULL;
616 bdemount_dokan_operations.DeleteDirectory = NULL;
617 bdemount_dokan_operations.MoveFile = NULL;
618 bdemount_dokan_operations.SetEndOfFile = NULL;
619 bdemount_dokan_operations.SetAllocationSize = NULL;
620 bdemount_dokan_operations.LockFile = NULL;
621 bdemount_dokan_operations.UnlockFile = NULL;
622 bdemount_dokan_operations.GetFileSecurity = NULL;
623 bdemount_dokan_operations.SetFileSecurity = NULL;
624 bdemount_dokan_operations.GetDiskFreeSpace = NULL;
625 bdemount_dokan_operations.GetVolumeInformation = &mount_dokan_GetVolumeInformation;
626 bdemount_dokan_operations.Unmounted = NULL;
627 bdemount_dokan_operations.FindStreams = NULL;
628 bdemount_dokan_operations.Mounted = NULL;
629
630 #endif /* ( DOKAN_VERSION >= 600 ) && ( DOKAN_VERSION < 800 ) */
631
632 result = DokanMain(
633 &bdemount_dokan_options,
634 &bdemount_dokan_operations );
635
636 switch( result )
637 {
638 case DOKAN_SUCCESS:
639 break;
640
641 case DOKAN_ERROR:
642 fprintf(
643 stderr,
644 "Unable to run dokan main: generic error\n" );
645 break;
646
647 case DOKAN_DRIVE_LETTER_ERROR:
648 fprintf(
649 stderr,
650 "Unable to run dokan main: bad drive letter\n" );
651 break;
652
653 case DOKAN_DRIVER_INSTALL_ERROR:
654 fprintf(
655 stderr,
656 "Unable to run dokan main: unable to load driver\n" );
657 break;
658
659 case DOKAN_START_ERROR:
660 fprintf(
661 stderr,
662 "Unable to run dokan main: driver error\n" );
663 break;
664
665 case DOKAN_MOUNT_ERROR:
666 fprintf(
667 stderr,
668 "Unable to run dokan main: unable to assign drive letter\n" );
669 break;
670
671 case DOKAN_MOUNT_POINT_ERROR:
672 fprintf(
673 stderr,
674 "Unable to run dokan main: mount point error\n" );
675 break;
676
677 default:
678 fprintf(
679 stderr,
680 "Unable to run dokan main: unknown error: %d\n",
681 result );
682 break;
683 }
684 return( EXIT_SUCCESS );
685
686 #else
687 fprintf(
688 stderr,
689 "No sub system to mount BDE format.\n" );
690
691 return( EXIT_FAILURE );
692
693 #endif /* defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE ) */
694
695 on_error:
696 if( error != NULL )
697 {
698 libcnotify_print_error_backtrace(
699 error );
700 libcerror_error_free(
701 &error );
702 }
703 #if defined( HAVE_LIBFUSE ) || defined( HAVE_LIBOSXFUSE )
704 if( bdemount_fuse_handle != NULL )
705 {
706 fuse_destroy(
707 bdemount_fuse_handle );
708 }
709 fuse_opt_free_args(
710 &bdemount_fuse_arguments );
711 #endif
712 if( bdemount_mount_handle != NULL )
713 {
714 mount_handle_free(
715 &bdemount_mount_handle,
716 NULL );
717 }
718 return( EXIT_FAILURE );
719 }
720
721