1 /*
2  * Shows information obtained from 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 <memory.h>
24 #include <system_string.h>
25 #include <types.h>
26 
27 #include <stdio.h>
28 
29 #if defined( HAVE_UNISTD_H )
30 #include <unistd.h>
31 #endif
32 
33 #if defined( HAVE_STDLIB_H ) || defined( WINAPI )
34 #include <stdlib.h>
35 #endif
36 
37 #include "bdetools_getopt.h"
38 #include "bdetools_libbde.h"
39 #include "bdetools_libcerror.h"
40 #include "bdetools_libclocale.h"
41 #include "bdetools_libcnotify.h"
42 #include "bdetools_output.h"
43 #include "bdetools_signal.h"
44 #include "bdetools_unused.h"
45 #include "info_handle.h"
46 
47 info_handle_t *bdeinfo_info_handle = NULL;
48 int bdeinfo_abort                  = 0;
49 
50 /* Prints the executable usage information
51  */
usage_fprint(FILE * stream)52 void usage_fprint(
53       FILE *stream )
54 {
55 	if( stream == NULL )
56 	{
57 		return;
58 	}
59 	fprintf( stream, "Use bdeinfo to determine information about a BitLocker Drive\n"
60 	                 " Encrypted (BDE) volume\n\n" );
61 
62 	fprintf( stream, "Usage: bdeinfo [ -k keys ] [ -o offset ] [ -p password ]\n"
63 	                 "               [ -r password ] [ -s filename ] [ -hvV ] source\n\n" );
64 
65 	fprintf( stream, "\tsource: the source file or device\n\n" );
66 
67 	fprintf( stream, "\t-h:     shows this help\n" );
68 	fprintf( stream, "\t-k:     the full volume encryption key and tweak key\n"
69 	                 "\t        formatted in base16 and separated by a : character\n"
70 	                 "\t        e.g. FVEK:TWEAK\n" );
71 	fprintf( stream, "\t-o:     specify the volume offset in bytes\n" );
72 	fprintf( stream, "\t-p:     specify the password/passphrase\n" );
73 	fprintf( stream, "\t-r:     specify the recovery password\n" );
74 	fprintf( stream, "\t-s:     specify the file containing the startup key.\n"
75 	                 "\t        typically this file has the extension .BEK\n" );
76 	fprintf( stream, "\t-v:     verbose output to stderr\n" );
77 	fprintf( stream, "\t-V:     print version\n" );
78 }
79 
80 /* Signal handler for bdeinfo
81  */
bdeinfo_signal_handler(bdetools_signal_t signal BDETOOLS_ATTRIBUTE_UNUSED)82 void bdeinfo_signal_handler(
83       bdetools_signal_t signal BDETOOLS_ATTRIBUTE_UNUSED )
84 {
85 	libcerror_error_t *error = NULL;
86 	static char *function   = "bdeinfo_signal_handler";
87 
88 	BDETOOLS_UNREFERENCED_PARAMETER( signal )
89 
90 	bdeinfo_abort = 1;
91 
92 	if( bdeinfo_info_handle != NULL )
93 	{
94 		if( info_handle_signal_abort(
95 		     bdeinfo_info_handle,
96 		     &error ) != 1 )
97 		{
98 			libcnotify_printf(
99 			 "%s: unable to signal info handle to abort.\n",
100 			 function );
101 
102 			libcnotify_print_error_backtrace(
103 			 error );
104 			libcerror_error_free(
105 			 &error );
106 		}
107 	}
108 	/* Force stdin to close otherwise any function reading it will remain blocked
109 	 */
110 #if defined( WINAPI ) && !defined( __CYGWIN__ )
111 	if( _close(
112 	     0 ) != 0 )
113 #else
114 	if( close(
115 	     0 ) != 0 )
116 #endif
117 	{
118 		libcnotify_printf(
119 		 "%s: unable to close stdin.\n",
120 		 function );
121 	}
122 }
123 
124 /* The main program
125  */
126 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
wmain(int argc,wchar_t * const argv[])127 int wmain( int argc, wchar_t * const argv[] )
128 #else
129 int main( int argc, char * const argv[] )
130 #endif
131 {
132 	libbde_error_t *error                           = NULL;
133 	system_character_t *option_keys                 = NULL;
134 	system_character_t *option_password             = NULL;
135 	system_character_t *option_recovery_password    = NULL;
136 	system_character_t *option_startup_key_filename = NULL;
137 	system_character_t *option_volume_offset        = NULL;
138 	system_character_t *source                      = NULL;
139 	char *program                                   = "bdeinfo";
140 	system_integer_t option                         = 0;
141 	int result                                      = 0;
142 	int verbose                                     = 0;
143 
144 	libcnotify_stream_set(
145 	 stderr,
146 	 NULL );
147 	libcnotify_verbose_set(
148 	 1 );
149 
150 	if( libclocale_initialize(
151              "bdetools",
152 	     &error ) != 1 )
153 	{
154 		fprintf(
155 		 stderr,
156 		 "Unable to initialize locale values.\n" );
157 
158 		goto on_error;
159 	}
160 	if( bdetools_output_initialize(
161              _IONBF,
162              &error ) != 1 )
163 	{
164 		fprintf(
165 		 stderr,
166 		 "Unable to initialize output settings.\n" );
167 
168 		goto on_error;
169 	}
170 	bdetools_output_version_fprint(
171 	 stdout,
172 	 program );
173 
174 	while( ( option = bdetools_getopt(
175 	                   argc,
176 	                   argv,
177 	                   _SYSTEM_STRING( "hk:o:p:r:s:vV" ) ) ) != (system_integer_t) -1 )
178 	{
179 		switch( option )
180 		{
181 			case (system_integer_t) '?':
182 			default:
183 				fprintf(
184 				 stderr,
185 				 "Invalid argument: %" PRIs_SYSTEM "\n",
186 				 argv[ optind - 1 ] );
187 
188 				usage_fprint(
189 				 stdout );
190 
191 				return( EXIT_FAILURE );
192 
193 			case (system_integer_t) 'h':
194 				usage_fprint(
195 				 stdout );
196 
197 				return( EXIT_SUCCESS );
198 
199 			case (system_integer_t) 'k':
200 				option_keys = optarg;
201 
202 				break;
203 
204 			case (system_integer_t) 'o':
205 				option_volume_offset = optarg;
206 
207 				break;
208 
209 			case (system_integer_t) 'p':
210 				option_password = optarg;
211 
212 				break;
213 
214 			case (system_integer_t) 'r':
215 				option_recovery_password = optarg;
216 
217 				break;
218 
219 			case (system_integer_t) 's':
220 				option_startup_key_filename = optarg;
221 
222 				break;
223 
224 			case (system_integer_t) 'v':
225 				verbose = 1;
226 
227 				break;
228 
229 			case (system_integer_t) 'V':
230 				bdetools_output_copyright_fprint(
231 				 stdout );
232 
233 				return( EXIT_SUCCESS );
234 		}
235 	}
236 	if( optind == argc )
237 	{
238 		fprintf(
239 		 stderr,
240 		 "Missing source file or device.\n" );
241 
242 		usage_fprint(
243 		 stdout );
244 
245 		return( EXIT_FAILURE );
246 	}
247 	source = argv[ optind ];
248 
249 	libcnotify_verbose_set(
250 	 verbose );
251 	libbde_notify_set_stream(
252 	 stderr,
253 	 NULL );
254 	libbde_notify_set_verbose(
255 	 verbose );
256 
257 	if( info_handle_initialize(
258 	     &bdeinfo_info_handle,
259 	     &error ) != 1 )
260 	{
261 		fprintf(
262 		 stderr,
263 		 "Unable to initialize info handle.\n" );
264 
265 		goto on_error;
266 	}
267 	if( option_keys != NULL )
268 	{
269 		if( info_handle_set_keys(
270 		     bdeinfo_info_handle,
271 		     option_keys,
272 		     &error ) != 1 )
273 		{
274 			fprintf(
275 			 stderr,
276 			 "Unable to set keys.\n" );
277 
278 			goto on_error;
279 		}
280 	}
281 	if( option_password != NULL )
282 	{
283 		if( info_handle_set_password(
284 		     bdeinfo_info_handle,
285 		     option_password,
286 		     &error ) != 1 )
287 		{
288 			fprintf(
289 			 stderr,
290 			 "Unable to set password.\n" );
291 
292 			goto on_error;
293 		}
294 	}
295 	if( option_recovery_password != NULL )
296 	{
297 		if( info_handle_set_recovery_password(
298 		     bdeinfo_info_handle,
299 		     option_recovery_password,
300 		     &error ) != 1 )
301 		{
302 			fprintf(
303 			 stderr,
304 			 "Unable to set recovery password.\n" );
305 
306 			goto on_error;
307 		}
308 	}
309 	if( option_startup_key_filename != NULL )
310 	{
311 		if( info_handle_read_startup_key(
312 		     bdeinfo_info_handle,
313 		     option_startup_key_filename,
314 		     &error ) != 1 )
315 		{
316 			fprintf(
317 			 stderr,
318 			 "Unable to read startup key.\n" );
319 
320 			goto on_error;
321 		}
322 	}
323 	if( option_volume_offset != NULL )
324 	{
325 		if( info_handle_set_volume_offset(
326 		     bdeinfo_info_handle,
327 		     option_volume_offset,
328 		     &error ) != 1 )
329 		{
330 			fprintf(
331 			 stderr,
332 			 "Unable to set volume offset.\n" );
333 
334 			goto on_error;
335 		}
336 	}
337 	result = info_handle_open_input(
338 	          bdeinfo_info_handle,
339 	          source,
340 	          &error );
341 
342 	if( result != 1 )
343 	{
344 		fprintf(
345 		 stderr,
346 		 "Unable to open: %" PRIs_SYSTEM ".\n",
347 		 source );
348 
349 		goto on_error;
350 	}
351 	if( info_handle_volume_fprint(
352 	     bdeinfo_info_handle,
353 	     &error ) != 1 )
354 	{
355 		fprintf(
356 		 stderr,
357 		 "Unable to print volume information.\n" );
358 
359 		goto on_error;
360 	}
361 	result = info_handle_input_is_locked(
362 	          bdeinfo_info_handle,
363 	          &error );
364 
365 	if( result != 0 )
366 	{
367 		fprintf(
368 		 stderr,
369 		 "Unable to unlock volume.\n" );
370 
371 		goto on_error;
372 	}
373 	if( info_handle_close_input(
374 	     bdeinfo_info_handle,
375 	     &error ) != 0 )
376 	{
377 		fprintf(
378 		 stderr,
379 		 "Unable to close info handle.\n" );
380 
381 		goto on_error;
382 	}
383 	if( info_handle_free(
384 	     &bdeinfo_info_handle,
385 	     &error ) != 1 )
386 	{
387 		fprintf(
388 		 stderr,
389 		 "Unable to free info handle.\n" );
390 
391 		goto on_error;
392 	}
393 	return( EXIT_SUCCESS );
394 
395 on_error:
396 	if( error != NULL )
397 	{
398 		libcnotify_print_error_backtrace(
399 		 error );
400 		libcerror_error_free(
401 		 &error );
402 	}
403 	if( bdeinfo_info_handle != NULL )
404 	{
405 		info_handle_free(
406 		 &bdeinfo_info_handle,
407 		 NULL );
408 	}
409 	return( EXIT_FAILURE );
410 }
411 
412