1 /*
2  * Extracts items from a Personal Folder File (OST, PAB and PST)
3  *
4  * Copyright (C) 2008-2018, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This software 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 software 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 software.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <memory.h>
24 #include <narrow_string.h>
25 #include <system_string.h>
26 #include <types.h>
27 #include <wide_string.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 "export_handle.h"
38 #include "log_handle.h"
39 #include "pffinput.h"
40 #include "pfftools_getopt.h"
41 #include "pfftools_libcerror.h"
42 #include "pfftools_libclocale.h"
43 #include "pfftools_libcnotify.h"
44 #include "pfftools_libcpath.h"
45 #include "pfftools_libpff.h"
46 #include "pfftools_output.h"
47 #include "pfftools_signal.h"
48 #include "pfftools_unused.h"
49 
50 export_handle_t *pffexport_export_handle = NULL;
51 libpff_file_t *pffexport_file            = NULL;
52 int pffexport_abort                      = 0;
53 
54 /* Prints the executable usage information
55  */
usage_fprint(FILE * stream)56 void usage_fprint(
57       FILE *stream )
58 {
59 	if( stream == NULL )
60 	{
61 		return;
62 	}
63 	fprintf( stream, "Use pffexport to export items stored in a Personal Folder File (OST, PAB\n"
64 	                 "and PST).\n\n" );
65 
66 	fprintf( stream, "Usage: pffexport [ -c codepage ] [ -f format ] [ -l logfile ] [ -m mode ]\n"
67 	                 "                 [ -t target ] [ -dhqvV ] source\n\n" );
68 
69 	fprintf( stream, "\tsource: the source file\n\n" );
70 
71 	fprintf( stream, "\t-c:     codepage of ASCII strings, options: ascii, windows-874,\n"
72 	                 "\t        windows-932, windows-936, windows-949, windows-950,\n"
73 	                 "\t        windows-1250, windows-1251, windows-1252 (default),\n"
74 	                 "\t        windows-1253, windows-1254, windows-1255, windows-1256\n"
75 	                 "\t        windows-1257 or windows-1258\n" );
76 	fprintf( stream, "\t-d:     dumps the item values in a separate file: ItemValues.txt\n" );
77 	fprintf( stream, "\t-f:     preferred output format, options: all, html, rtf,\n"
78 	                 "\t        text (default)\n" );
79 	fprintf( stream, "\t-h:     shows this help\n" );
80 	fprintf( stream, "\t-l:     logs information about the exported items\n" );
81 	fprintf( stream, "\t-m:     export mode, option: all, debug, items (default), recovered.\n"
82 	                 "\t        'all' exports the (allocated) items, orphan and recovered\n"
83 	                 "\t        items. 'debug' exports all the (allocated) items, also those\n"
84 	                 "\t        outside the the root folder. 'items' exports the (allocated)\n"
85 	                 "\t        items. 'recovered' exports the orphan and recovered items.\n" );
86 	fprintf( stream, "\t-q:     quiet shows minimal status information\n" );
87 	fprintf( stream, "\t-t:     specify the basename of the target directory to export to\n"
88 	                 "\t        (default is the source filename) pffexport will add the\n"
89 	                 "\t        following suffixes to the basename: .export, .orphans,\n"
90 	                 "\t        .recovered\n" );
91 	fprintf( stream, "\t-v:     verbose output to stderr\n" );
92 	fprintf( stream, "\t-V:     print version\n" );
93 }
94 
95 /* Signal handler for pffexport
96  */
pffexport_signal_handler(pfftools_signal_t signal PFFTOOLS_ATTRIBUTE_UNUSED)97 void pffexport_signal_handler(
98       pfftools_signal_t signal PFFTOOLS_ATTRIBUTE_UNUSED )
99 {
100 	libcerror_error_t *error = NULL;
101 	static char *function   = "pffexport_signal_handler";
102 
103 	PFFTOOLS_UNREFERENCED_PARAMETER( signal )
104 
105 	pffexport_abort = 1;
106 
107 	if( pffexport_export_handle != NULL )
108 	{
109 		if( export_handle_signal_abort(
110 		     pffexport_export_handle,
111 		     &error ) != 1 )
112 		{
113 			libcnotify_printf(
114 			 "%s: unable to signal export handle to abort.\n",
115 			 function );
116 
117 			libcnotify_print_error_backtrace(
118 			 error );
119 			libcerror_error_free(
120 			 &error );
121 		}
122 	}
123 	if( pffexport_file != NULL )
124 	{
125 		if( libpff_file_signal_abort(
126 		     pffexport_file,
127 		     &error ) != 1 )
128 		{
129 			libcnotify_printf(
130 			 "%s: unable to signal file to abort.\n",
131 			 function );
132 
133 			libcnotify_print_error_backtrace(
134 			 error );
135 			libcerror_error_free(
136 			 &error );
137 		}
138 	}
139 	/* Force stdin to close otherwise any function reading it will remain blocked
140 	 */
141 #if defined( WINAPI ) && !defined( __CYGWIN__ )
142 	if( _close(
143 	     0 ) != 0 )
144 #else
145 	if( close(
146 	     0 ) != 0 )
147 #endif
148 	{
149 		libcnotify_printf(
150 		 "%s: unable to close stdin.\n",
151 		 function );
152 	}
153 }
154 
155 /* The main program
156  */
157 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
wmain(int argc,wchar_t * const argv[])158 int wmain( int argc, wchar_t * const argv[] )
159 #else
160 int main( int argc, char * const argv[] )
161 #endif
162 {
163 	libcerror_error_t *error                           = NULL;
164 	log_handle_t *log_handle                           = NULL;
165 	system_character_t *log_filename                   = NULL;
166 	system_character_t *option_ascii_codepage          = NULL;
167 	system_character_t *option_export_mode             = NULL;
168 	system_character_t *option_preferred_export_format = NULL;
169 	system_character_t *option_target_path             = NULL;
170 	system_character_t *path_separator                 = NULL;
171 	system_character_t *source                         = NULL;
172 	char *program                                      = "pffexport";
173 	system_integer_t option                            = 0;
174 	size_t source_length                               = 0;
175 	uint8_t dump_item_values                           = 0;
176 	uint8_t print_status_information                   = 1;
177 	int result                                         = 0;
178 	int verbose                                        = 0;
179 
180 	libcnotify_stream_set(
181 	 stderr,
182 	 NULL );
183 	libcnotify_verbose_set(
184 	 1 );
185 
186 	if( libclocale_initialize(
187 	     "pfftools",
188 	     &error ) != 1 )
189 	{
190 		fprintf(
191 		 stderr,
192 		 "Unable to initialize locale values.\n" );
193 
194 		goto on_error;
195 	}
196 	if( pfftools_output_initialize(
197 	     _IONBF,
198 	     &error ) != 1 )
199 	{
200 		fprintf(
201 		 stderr,
202 		 "Unable to initialize output settings.\n" );
203 
204 		goto on_error;
205 	}
206 	pffoutput_version_fprint(
207 	 stdout,
208 	 program );
209 
210 	while( ( option = pfftools_getopt(
211 	                   argc,
212 	                   argv,
213 	                   _SYSTEM_STRING( "c:df:hl:m:qt:vV" ) ) ) != (system_integer_t) -1 )
214 	{
215 		switch( option )
216 		{
217 			case (system_integer_t) '?':
218 			default:
219 				fprintf(
220 				 stderr,
221 				 "Invalid argument: %" PRIs_SYSTEM "\n",
222 				 argv[ optind - 1 ] );
223 
224 				usage_fprint(
225 				 stdout );
226 
227 				return( EXIT_FAILURE );
228 
229 			case (system_integer_t) 'c':
230 				option_ascii_codepage = optarg;
231 
232 				break;
233 
234 			case (system_integer_t) 'd':
235 				dump_item_values = 1;
236 
237 				break;
238 
239 			case (system_integer_t) 'f':
240 				option_preferred_export_format = optarg;
241 
242 				break;
243 
244 			case (system_integer_t) 'h':
245 				usage_fprint(
246 				 stdout );
247 
248 				return( EXIT_SUCCESS );
249 
250 			case (system_integer_t) 'l':
251 				log_filename = optarg;
252 
253 				break;
254 
255 			case (system_integer_t) 'm':
256 				option_export_mode = optarg;
257 
258 				break;
259 
260 			case (system_integer_t) 'q':
261 				print_status_information = 0;
262 
263 				break;
264 
265 			case (system_integer_t) 't':
266 				option_target_path = optarg;
267 
268 				break;
269 
270 			case (system_integer_t) 'v':
271 				verbose = 1;
272 
273 				break;
274 
275 			case (system_integer_t) 'V':
276 				pffoutput_copyright_fprint(
277 				 stdout );
278 
279 				return( EXIT_SUCCESS );
280 		}
281 	}
282 	if( optind == argc )
283 	{
284 		fprintf(
285 		 stderr,
286 		 "Missing source file.\n" );
287 
288 		usage_fprint(
289 		 stdout );
290 
291 		return( EXIT_FAILURE );
292 	}
293 	source = argv[ optind ];
294 
295 	if( option_target_path == NULL )
296 	{
297 		source_length = system_string_length(
298 		                 source );
299 
300 		path_separator = system_string_search_character_reverse(
301 		                  source,
302 		                  (system_character_t) LIBCPATH_SEPARATOR,
303 		                  source_length );
304 
305 		if( path_separator == NULL )
306 		{
307 			path_separator = source;
308 		}
309 		else
310 		{
311 			path_separator++;
312 		}
313 		option_target_path = path_separator;
314 	}
315 	libcnotify_verbose_set(
316 	 verbose );
317 	libpff_notify_set_stream(
318 	 stderr,
319 	 NULL );
320 	libpff_notify_set_verbose(
321 	 verbose );
322 
323 	if( export_handle_initialize(
324 	     &pffexport_export_handle,
325 	     &error ) != 1 )
326 	{
327 		fprintf(
328 		 stderr,
329 		 "Unable to create export handle.\n" );
330 
331 		goto on_error;
332 	}
333 	pffexport_export_handle->print_status_information = print_status_information;
334 
335 	if( option_export_mode != NULL )
336 	{
337 		result = export_handle_set_export_mode(
338 			  pffexport_export_handle,
339 			  option_export_mode,
340 			  &error );
341 
342 		if( result == -1 )
343 		{
344 			fprintf(
345 			 stderr,
346 			 "Unable to set export mode.\n" );
347 
348 			goto on_error;
349 		}
350 		else if( result == 0 )
351 		{
352 			fprintf(
353 			 stderr,
354 			 "Unsupported export mode defaulting to: items.\n" );
355 		}
356 	}
357 	pffexport_export_handle->dump_item_values = dump_item_values;
358 
359 	if( option_preferred_export_format != NULL )
360 	{
361 		result = export_handle_set_preferred_export_format(
362 			  pffexport_export_handle,
363 			  option_preferred_export_format,
364 			  &error );
365 
366 		if( result == -1 )
367 		{
368 			fprintf(
369 			 stderr,
370 			 "Unable to set preferred export format.\n" );
371 
372 			goto on_error;
373 		}
374 		else if( result == 0 )
375 		{
376 			fprintf(
377 			 stderr,
378 			 "Unsupported preferred export format defaulting to: text.\n" );
379 		}
380 	}
381 	if( option_ascii_codepage != NULL )
382 	{
383 		result = export_handle_set_ascii_codepage(
384 		          pffexport_export_handle,
385 		          option_ascii_codepage,
386 		          &error );
387 
388 		if( result == -1 )
389 		{
390 			fprintf(
391 			 stderr,
392 			 "Unable to set ASCII codepage in export handle.\n" );
393 
394 			goto on_error;
395 		}
396 		else if( result == 0 )
397 		{
398 			fprintf(
399 			 stderr,
400 			 "Unsupported ASCII codepage defaulting to: windows-1252.\n" );
401 		}
402 	}
403 	if( export_handle_set_target_path(
404 	     pffexport_export_handle,
405 	     option_target_path,
406 	     &error ) != 1 )
407 	{
408 		fprintf(
409 		 stderr,
410 		 "Unable to set target path.\n" );
411 
412 		goto on_error;
413 	}
414 	result = export_handle_create_items_export_path(
415 	          pffexport_export_handle,
416 	          &error );
417 
418 	if( result == -1 )
419 	{
420 		fprintf(
421 		 stderr,
422 		 "Unable to create items export path.\n" );
423 
424 		goto on_error;
425 	}
426 	else if( result == 0 )
427 	{
428 		fprintf(
429 		 stderr,
430 		 "%" PRIs_SYSTEM " already exists.\n",
431 		 pffexport_export_handle->items_export_path );
432 
433 		goto on_error;
434 	}
435 	result = export_handle_create_orphans_export_path(
436 	          pffexport_export_handle,
437 	          &error );
438 
439 	if( result == -1 )
440 	{
441 		fprintf(
442 		 stderr,
443 		 "Unable to create orphans export path.\n" );
444 
445 		goto on_error;
446 	}
447 	else if( result == 0 )
448 	{
449 		fprintf(
450 		 stderr,
451 		 "%" PRIs_SYSTEM " already exists.\n",
452 		 pffexport_export_handle->orphans_export_path );
453 
454 		goto on_error;
455 	}
456 	result = export_handle_create_recovered_export_path(
457 	          pffexport_export_handle,
458 	          &error );
459 
460 	if( result == -1 )
461 	{
462 		fprintf(
463 		 stderr,
464 		 "Unable to create recovered export path.\n" );
465 
466 		goto on_error;
467 	}
468 	else if( result == 0 )
469 	{
470 		fprintf(
471 		 stderr,
472 		 "%" PRIs_SYSTEM " already exists.\n",
473 		 pffexport_export_handle->recovered_export_path );
474 
475 		goto on_error;
476 	}
477 	if( log_handle_initialize(
478 	     &log_handle,
479 	     &error ) != 1 )
480 	{
481 		fprintf(
482 		 stderr,
483 		 "Unable to create log handle.\n" );
484 
485 		goto on_error;
486 	}
487 	if( log_handle_open(
488 	     log_handle,
489 	     log_filename,
490 	     &error ) != 1 )
491 	{
492 		fprintf(
493 		 stderr,
494 		 "Unable to open log file: %" PRIs_SYSTEM ".\n",
495 		 log_filename );
496 
497 		goto on_error;
498 	}
499 	if( libpff_file_initialize(
500 	     &pffexport_file,
501 	     &error ) != 1 )
502 	{
503 		fprintf(
504 		 stderr,
505 		 "Unable to create file.\n" );
506 
507 		goto on_error;
508 	}
509 	if( libpff_file_set_ascii_codepage(
510 	     pffexport_file,
511 	     pffexport_export_handle->ascii_codepage,
512 	     &error ) != 1 )
513 	{
514 		fprintf(
515 		 stderr,
516 		 "Unable to set ASCII codepage.\n" );
517 
518 		goto on_error;
519 	}
520 	if( pfftools_signal_attach(
521 	     pffexport_signal_handler,
522 	     &error ) != 1 )
523 	{
524 		fprintf(
525 		 stderr,
526 		 "Unable to attach signal handler.\n" );
527 
528 		goto on_error;
529 	}
530 	fprintf(
531 	 stdout,
532 	 "Opening file.\n" );
533 
534 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
535 	if( libpff_file_open_wide(
536 	     pffexport_file,
537 	     source,
538 	     LIBPFF_OPEN_READ,
539 	     &error ) != 1 )
540 #else
541 	if( libpff_file_open(
542 	     pffexport_file,
543 	     source,
544 	     LIBPFF_OPEN_READ,
545 	     &error ) != 1 )
546 #endif
547 	{
548 		fprintf(
549 		 stderr,
550 		 "Error opening file: %" PRIs_SYSTEM ".\n",
551 		 source );
552 
553 		goto on_error;
554 	}
555 	if( export_handle_export_file(
556 	     pffexport_export_handle,
557 	     pffexport_file,
558 	     log_handle,
559 	     &error ) != 1 )
560 	{
561 		fprintf(
562 		 stderr,
563 		 "Unable to export file.\n" );
564 
565 		goto on_error;
566 	}
567 	if( libpff_file_close(
568 	     pffexport_file,
569 	     &error ) != 0 )
570 	{
571 		fprintf(
572 		 stderr,
573 		 "Unable to close file.\n" );
574 
575 		goto on_error;
576 	}
577 	if( pfftools_signal_detach(
578 	     &error ) != 1 )
579 	{
580 		fprintf(
581 		 stderr,
582 		 "Unable to detach signal handler.\n" );
583 
584 		goto on_error;
585 	}
586 	if( libpff_file_free(
587 	     &pffexport_file,
588 	     &error ) != 1 )
589 	{
590 		fprintf(
591 		 stderr,
592 		 "Unable to free file.\n" );
593 
594 		goto on_error;
595 	}
596 	if( log_handle_close(
597 	     log_handle,
598 	     &error ) != 0 )
599 	{
600 		fprintf(
601 		 stderr,
602 		 "Unable to close log file.\n" );
603 
604 		goto on_error;
605 	}
606 	if( log_handle_free(
607 	     &log_handle,
608 	     &error ) != 1 )
609 	{
610 		fprintf(
611 		 stderr,
612 		 "Unable to free log handle.\n" );
613 
614 		goto on_error;
615 	}
616 	if( export_handle_free(
617 	     &pffexport_export_handle,
618 	     &error ) != 1 )
619 	{
620 		fprintf(
621 		 stderr,
622 		 "Unable to free export handle.\n" );
623 
624 		goto on_error;
625 	}
626 	if( pffexport_abort != 0 )
627 	{
628 		fprintf(
629 		 stdout,
630 		 "Export aborted.\n" );
631 
632 		return( EXIT_FAILURE );
633 	}
634 	fprintf(
635 	 stdout,
636 	 "Export completed.\n" );
637 
638 	return( EXIT_SUCCESS );
639 
640 on_error:
641 	if( error != NULL )
642 	{
643 		libcnotify_print_error_backtrace(
644 		 error );
645 		libcerror_error_free(
646 		 &error );
647 	}
648 	if( pffexport_file != NULL )
649 	{
650 		libpff_file_close(
651 		 pffexport_file,
652 		 NULL );
653 		libpff_file_free(
654 		 &pffexport_file,
655 		 NULL );
656 	}
657 	if( log_handle != NULL )
658 	{
659 		log_handle_close(
660 		 log_handle,
661 		 NULL );
662 		log_handle_free(
663 		 &log_handle,
664 		 NULL );
665 	}
666 	if( pffexport_export_handle != NULL )
667 	{
668 		export_handle_free(
669 		 &pffexport_export_handle,
670 		 NULL );
671 	}
672 	return( EXIT_FAILURE );
673 }
674 
675