1 /*
2 * Leak values functions
3 *
4 * Copyright (C) 2009-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 <byte_stream.h>
24 #include <memory.h>
25 #include <system_string.h>
26 #include <types.h>
27
28 #include "libmsiecf_debug.h"
29 #include "libmsiecf_definitions.h"
30 #include "libmsiecf_libbfio.h"
31 #include "libmsiecf_libcerror.h"
32 #include "libmsiecf_libcnotify.h"
33 #include "libmsiecf_libfdatetime.h"
34 #include "libmsiecf_libfvalue.h"
35 #include "libmsiecf_leak_values.h"
36
37 #include "msiecf_leak_record.h"
38
39 /* Creates leak values
40 * Make sure the value leak_values is referencing, is set to NULL
41 * Returns 1 if successful or -1 on error
42 */
libmsiecf_leak_values_initialize(libmsiecf_leak_values_t ** leak_values,libcerror_error_t ** error)43 int libmsiecf_leak_values_initialize(
44 libmsiecf_leak_values_t **leak_values,
45 libcerror_error_t **error )
46 {
47 static char *function = "libmsiecf_leak_values_initialize";
48
49 if( leak_values == NULL )
50 {
51 libcerror_error_set(
52 error,
53 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55 "%s: invalid leak values.",
56 function );
57
58 return( -1 );
59 }
60 if( *leak_values != NULL )
61 {
62 libcerror_error_set(
63 error,
64 LIBCERROR_ERROR_DOMAIN_RUNTIME,
65 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66 "%s: invalid leak values value already set.",
67 function );
68
69 return( -1 );
70 }
71 *leak_values = memory_allocate_structure(
72 libmsiecf_leak_values_t );
73
74 if( *leak_values == NULL )
75 {
76 libcerror_error_set(
77 error,
78 LIBCERROR_ERROR_DOMAIN_MEMORY,
79 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
80 "%s: unable to create leak values.",
81 function );
82
83 goto on_error;
84 }
85 if( memory_set(
86 *leak_values,
87 0,
88 sizeof( libmsiecf_leak_values_t ) ) == NULL )
89 {
90 libcerror_error_set(
91 error,
92 LIBCERROR_ERROR_DOMAIN_MEMORY,
93 LIBCERROR_MEMORY_ERROR_SET_FAILED,
94 "%s: unable to clear leak values.",
95 function );
96
97 goto on_error;
98 }
99 return( 1 );
100
101 on_error:
102 if( *leak_values != NULL )
103 {
104 memory_free(
105 *leak_values );
106
107 *leak_values = NULL;
108 }
109 return( -1 );
110 }
111
112 /* Frees leak values
113 * Returns 1 if successful or -1 on error
114 */
libmsiecf_leak_values_free(libmsiecf_leak_values_t ** leak_values,libcerror_error_t ** error)115 int libmsiecf_leak_values_free(
116 libmsiecf_leak_values_t **leak_values,
117 libcerror_error_t **error )
118 {
119 static char *function = "libmsiecf_leak_values_free";
120 int result = 1;
121
122 if( leak_values == NULL )
123 {
124 libcerror_error_set(
125 error,
126 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
127 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
128 "%s: invalid leak values.",
129 function );
130
131 return( -1 );
132 }
133 if( *leak_values != NULL )
134 {
135 if( ( *leak_values )->filename != NULL )
136 {
137 if( libfvalue_value_free(
138 &( ( *leak_values )->filename ),
139 error ) != 1 )
140 {
141 libcerror_error_set(
142 error,
143 LIBCERROR_ERROR_DOMAIN_RUNTIME,
144 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
145 "%s: unable to free filename value.",
146 function );
147
148 result = -1;
149 }
150 }
151 memory_free(
152 *leak_values );
153
154 *leak_values = NULL;
155 }
156 return( result );
157 }
158
159 /* Reads the leak values from a LEAK record
160 * Returns 1 if successful or -1 on error
161 */
libmsiecf_leak_values_read_data(libmsiecf_leak_values_t * leak_values,const uint8_t * data,size_t data_size,int ascii_codepage,uint8_t item_flags,libcerror_error_t ** error)162 int libmsiecf_leak_values_read_data(
163 libmsiecf_leak_values_t *leak_values,
164 const uint8_t *data,
165 size_t data_size,
166 int ascii_codepage,
167 uint8_t item_flags,
168 libcerror_error_t **error )
169 {
170 static char *function = "libmsiecf_leak_values_read_data";
171 ssize_t value_size = 0;
172 uint32_t filename_offset = 0;
173
174 #if defined( HAVE_DEBUG_OUTPUT )
175 uint32_t value_32bit = 0;
176 #endif
177
178 if( leak_values == NULL )
179 {
180 libcerror_error_set(
181 error,
182 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
183 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
184 "%s: invalid leak values.",
185 function );
186
187 return( -1 );
188 }
189 if( data == NULL )
190 {
191 libcerror_error_set(
192 error,
193 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195 "%s: invalid data.",
196 function );
197
198 return( -1 );
199 }
200 if( data_size < sizeof( msiecf_leak_record_header_t ) )
201 {
202 libcerror_error_set(
203 error,
204 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
205 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
206 "%s: invalid data size value too small.",
207 function );
208
209 return( -1 );
210 }
211 if( data_size > (size_t) SSIZE_MAX )
212 {
213 libcerror_error_set(
214 error,
215 LIBCERROR_ERROR_DOMAIN_RUNTIME,
216 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
217 "%s: invalid data size value exceeds maximum.",
218 function );
219
220 return( -1 );
221 }
222 #if defined( HAVE_DEBUG_OUTPUT )
223 if( libcnotify_verbose != 0 )
224 {
225 libcnotify_printf(
226 "%s: LEAK record data:\n",
227 function );
228 libcnotify_print_data(
229 data,
230 data_size,
231 0 );
232 }
233 #endif
234 if( memory_compare(
235 ( (msiecf_leak_record_header_t *) data )->signature,
236 "LEAK",
237 4 ) != 0 )
238 {
239 libcerror_error_set(
240 error,
241 LIBCERROR_ERROR_DOMAIN_RUNTIME,
242 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
243 "%s: unsupported signature.",
244 function );
245
246 goto on_error;
247 }
248 byte_stream_copy_to_uint32_little_endian(
249 ( (msiecf_leak_record_header_t *) data )->cached_file_size,
250 leak_values->cached_file_size );
251
252 leak_values->cache_directory_index = ( (msiecf_leak_record_header_t *) data )->cache_directory_index;
253
254 byte_stream_copy_to_uint32_little_endian(
255 ( (msiecf_leak_record_header_t *) data )->filename_offset,
256 filename_offset );
257
258 #if defined( HAVE_DEBUG_OUTPUT )
259 if( libcnotify_verbose != 0 )
260 {
261 libcnotify_printf(
262 "%s: signature\t\t\t\t: %c%c%c%c\n",
263 function,
264 ( (msiecf_leak_record_header_t *) data )->signature[ 0 ],
265 ( (msiecf_leak_record_header_t *) data )->signature[ 1 ],
266 ( (msiecf_leak_record_header_t *) data )->signature[ 2 ],
267 ( (msiecf_leak_record_header_t *) data )->signature[ 3 ] );
268
269 byte_stream_copy_to_uint32_little_endian(
270 ( (msiecf_leak_record_header_t *) data )->number_of_blocks,
271 value_32bit );
272 libcnotify_printf(
273 "%s: number of blocks\t\t\t: %" PRIu32 "\n",
274 function,
275 value_32bit );
276
277 libcnotify_printf(
278 "%s: unknown1:\n",
279 function );
280 libcnotify_print_data(
281 ( (msiecf_leak_record_header_t *) data )->unknown1,
282 24,
283 0 );
284
285 libcnotify_printf(
286 "%s: cached file size\t\t\t: %" PRIu32 " bytes\n",
287 function,
288 leak_values->cached_file_size );
289
290 libcnotify_printf(
291 "%s: unknown3:\n",
292 function );
293 libcnotify_print_data(
294 ( (msiecf_leak_record_header_t *) data )->unknown3,
295 8,
296 0 );
297
298 byte_stream_copy_to_uint32_little_endian(
299 ( (msiecf_leak_record_header_t *) data )->unknown4,
300 value_32bit );
301 libcnotify_printf(
302 "%s: unknown4\t\t\t\t: %" PRIu32 "\n",
303 function,
304 value_32bit );
305
306 libcnotify_printf(
307 "%s: unknown5:\n",
308 function );
309 libcnotify_print_data(
310 ( (msiecf_leak_record_header_t *) data )->unknown5,
311 8,
312 0 );
313
314 libcnotify_printf(
315 "%s: cache directory index\t\t\t: %" PRIu8 "\n",
316 function,
317 leak_values->cache_directory_index );
318
319 libcnotify_printf(
320 "%s: unknown7:\n",
321 function );
322 libcnotify_print_data(
323 ( (msiecf_leak_record_header_t *) data )->unknown7,
324 3,
325 0 );
326
327 libcnotify_printf(
328 "%s: filename offset\t\t\t: %" PRIu32 "\n",
329 function,
330 filename_offset );
331
332 libcnotify_printf(
333 "%s: unknown9:\n",
334 function );
335 libcnotify_print_data(
336 ( (msiecf_leak_record_header_t *) data )->unknown9,
337 24,
338 0 );
339
340 byte_stream_copy_to_uint32_little_endian(
341 ( (msiecf_leak_record_header_t *) data )->unknown10,
342 value_32bit );
343 libcnotify_printf(
344 "%s: unknown10\t\t\t\t: %" PRIu32 "\n",
345 function,
346 value_32bit );
347
348 if( libmsiecf_debug_print_fat_date_time_value(
349 function,
350 "unknown time\t\t\t\t",
351 ( (msiecf_leak_record_header_t *) data )->unknown_time,
352 4,
353 LIBFDATETIME_ENDIAN_LITTLE,
354 LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
355 error ) != 1 )
356 {
357 libcerror_error_set(
358 error,
359 LIBCERROR_ERROR_DOMAIN_RUNTIME,
360 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
361 "%s: unable to print FAT date time value.",
362 function );
363
364 goto on_error;
365 }
366 }
367 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
368
369 if( filename_offset > 0 )
370 {
371 if( filename_offset > data_size )
372 {
373 if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
374 {
375 libcerror_error_set(
376 error,
377 LIBCERROR_ERROR_DOMAIN_RUNTIME,
378 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
379 "%s: filename offset exceeds size of URL record data.",
380 function );
381
382 goto on_error;
383 }
384 }
385 else
386 {
387 /* TODO remove need for libfvalue */
388 if( libfvalue_value_type_initialize(
389 &( leak_values->filename ),
390 LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
391 error ) != 1 )
392 {
393 libcerror_error_set(
394 error,
395 LIBCERROR_ERROR_DOMAIN_RUNTIME,
396 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
397 "%s: unable to create filename value.",
398 function );
399
400 goto on_error;
401 }
402 value_size = libfvalue_value_type_set_data_string(
403 leak_values->filename,
404 &( data[ filename_offset ] ),
405 data_size - filename_offset,
406 ascii_codepage,
407 LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
408 error );
409
410 if( value_size == -1 )
411 {
412 libcerror_error_set(
413 error,
414 LIBCERROR_ERROR_DOMAIN_RUNTIME,
415 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
416 "%s: unable to set data of filename value.",
417 function );
418
419 goto on_error;
420 }
421 #if defined( HAVE_DEBUG_OUTPUT )
422 if( libcnotify_verbose != 0 )
423 {
424 libcnotify_printf(
425 "%s: filename\t\t\t\t: ",
426 function );
427
428 if( libfvalue_value_print(
429 leak_values->filename,
430 0,
431 0,
432 error ) != 1 )
433 {
434 libcerror_error_set(
435 error,
436 LIBCERROR_ERROR_DOMAIN_RUNTIME,
437 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
438 "%s: unable to print filename value.",
439 function );
440
441 goto on_error;
442 }
443 libcnotify_printf(
444 "\n" );
445 }
446 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
447
448 if( ( data[ filename_offset + value_size - 1 ] != 0 )
449 && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
450 {
451 libcerror_error_set(
452 error,
453 LIBCERROR_ERROR_DOMAIN_RUNTIME,
454 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
455 "%s: unsupported unterminated filename string.",
456 function );
457
458 goto on_error;
459 }
460 }
461 }
462 #if defined( HAVE_DEBUG_OUTPUT )
463 if( libcnotify_verbose != 0 )
464 {
465 libcnotify_printf(
466 "\n" );
467 }
468 #endif
469 return( 1 );
470
471 on_error:
472 if( leak_values->filename != NULL )
473 {
474 libfvalue_value_free(
475 &( leak_values->filename ),
476 NULL );
477 }
478 return( 1 );
479 }
480
481 /* Reads the leak values from a LEAK record
482 * Returns 1 if successful or -1 on error
483 */
libmsiecf_leak_values_read_file_io_handle(libmsiecf_leak_values_t * leak_values,libbfio_handle_t * file_io_handle,off64_t leak_record_offset,size32_t record_size,int ascii_codepage,uint8_t item_flags,libcerror_error_t ** error)484 int libmsiecf_leak_values_read_file_io_handle(
485 libmsiecf_leak_values_t *leak_values,
486 libbfio_handle_t *file_io_handle,
487 off64_t leak_record_offset,
488 size32_t record_size,
489 int ascii_codepage,
490 uint8_t item_flags,
491 libcerror_error_t **error )
492 {
493 uint8_t *record_data = NULL;
494 static char *function = "libmsiecf_leak_values_read_file_io_handle";
495 ssize_t read_count = 0;
496
497 if( leak_values == NULL )
498 {
499 libcerror_error_set(
500 error,
501 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
502 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
503 "%s: invalid leak values.",
504 function );
505
506 return( -1 );
507 }
508 if( record_size > (size32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
509 {
510 libcerror_error_set(
511 error,
512 LIBCERROR_ERROR_DOMAIN_RUNTIME,
513 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
514 "%s: invalid record size value exceeds maximum allocation size.",
515 function );
516
517 return( -1 );
518 }
519 if( ( record_size == 0 )
520 || ( ( record_size % 8 ) != 0 ) )
521 {
522 libcerror_error_set(
523 error,
524 LIBCERROR_ERROR_DOMAIN_RUNTIME,
525 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
526 "%s: unsupported record size.",
527 function );
528
529 return( -1 );
530 }
531 record_data = (uint8_t *) memory_allocate(
532 sizeof( uint8_t ) * record_size );
533
534 if( record_data == NULL )
535 {
536 libcerror_error_set(
537 error,
538 LIBCERROR_ERROR_DOMAIN_MEMORY,
539 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
540 "%s: unable to create LEAK record data.",
541 function );
542
543 goto on_error;
544 }
545 #if defined( HAVE_DEBUG_OUTPUT )
546 if( libcnotify_verbose != 0 )
547 {
548 libcnotify_printf(
549 "%s: reading LEAK record at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
550 function,
551 leak_record_offset,
552 leak_record_offset );
553 }
554 #endif
555 read_count = libbfio_handle_read_buffer_at_offset(
556 file_io_handle,
557 record_data,
558 (size_t) record_size,
559 leak_record_offset,
560 error );
561
562 if( read_count != (ssize_t) record_size )
563 {
564 libcerror_error_set(
565 error,
566 LIBCERROR_ERROR_DOMAIN_IO,
567 LIBCERROR_IO_ERROR_READ_FAILED,
568 "%s: unable to read LEAK record data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
569 function,
570 leak_record_offset,
571 leak_record_offset );
572
573 goto on_error;
574 }
575 if( libmsiecf_leak_values_read_data(
576 leak_values,
577 record_data,
578 (size_t) record_size,
579 ascii_codepage,
580 item_flags,
581 error ) != 1 )
582 {
583 libcerror_error_set(
584 error,
585 LIBCERROR_ERROR_DOMAIN_IO,
586 LIBCERROR_IO_ERROR_READ_FAILED,
587 "%s: unable to read LEAK record.",
588 function );
589
590 goto on_error;
591 }
592 memory_free(
593 record_data );
594
595 return( 1 );
596
597 on_error:
598 if( record_data != NULL )
599 {
600 memory_free(
601 record_data );
602 }
603 return( -1 );
604 }
605
606