Coverage Report

Created: 2025-06-13 07:22

/src/libmsiecf/libmsiecf/libmsiecf_leak_values.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Leak values functions
3
 *
4
 * Copyright (C) 2009-2024, 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
 */
43
int libmsiecf_leak_values_initialize(
44
     libmsiecf_leak_values_t **leak_values,
45
     libcerror_error_t **error )
46
142
{
47
142
  static char *function = "libmsiecf_leak_values_initialize";
48
49
142
  if( leak_values == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid leak values.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
142
  if( *leak_values != NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
65
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66
0
     "%s: invalid leak values value already set.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
142
  *leak_values = memory_allocate_structure(
72
142
                  libmsiecf_leak_values_t );
73
74
142
  if( *leak_values == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
79
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
80
0
     "%s: unable to create leak values.",
81
0
     function );
82
83
0
    goto on_error;
84
0
  }
85
142
  if( memory_set(
86
142
       *leak_values,
87
142
       0,
88
142
       sizeof( libmsiecf_leak_values_t ) ) == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
93
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
94
0
     "%s: unable to clear leak values.",
95
0
     function );
96
97
0
    goto on_error;
98
0
  }
99
142
  return( 1 );
100
101
0
on_error:
102
0
  if( *leak_values != NULL )
103
0
  {
104
0
    memory_free(
105
0
     *leak_values );
106
107
0
    *leak_values = NULL;
108
0
  }
109
0
  return( -1 );
110
142
}
111
112
/* Frees leak values
113
 * Returns 1 if successful or -1 on error
114
 */
115
int libmsiecf_leak_values_free(
116
     libmsiecf_leak_values_t **leak_values,
117
     libcerror_error_t **error )
118
142
{
119
142
  static char *function = "libmsiecf_leak_values_free";
120
142
  int result            = 1;
121
122
142
  if( leak_values == NULL )
123
0
  {
124
0
    libcerror_error_set(
125
0
     error,
126
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
127
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
128
0
     "%s: invalid leak values.",
129
0
     function );
130
131
0
    return( -1 );
132
0
  }
133
142
  if( *leak_values != NULL )
134
142
  {
135
142
    if( ( *leak_values )->filename != NULL )
136
15
    {
137
15
      if( libfvalue_value_free(
138
15
           &( ( *leak_values )->filename ),
139
15
           error ) != 1 )
140
0
      {
141
0
        libcerror_error_set(
142
0
         error,
143
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
144
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
145
0
         "%s: unable to free filename value.",
146
0
         function );
147
148
0
        result = -1;
149
0
      }
150
15
    }
151
142
    memory_free(
152
142
     *leak_values );
153
154
142
    *leak_values = NULL;
155
142
  }
156
142
  return( result );
157
142
}
158
159
/* Reads the leak values from a LEAK record
160
 * Returns 1 if successful or -1 on error
161
 */
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
97
{
170
97
  static char *function    = "libmsiecf_leak_values_read_data";
171
97
  ssize_t value_size       = 0;
172
97
  uint32_t filename_offset = 0;
173
174
#if defined( HAVE_DEBUG_OUTPUT )
175
  uint32_t value_32bit     = 0;
176
#endif
177
178
97
  if( leak_values == NULL )
179
0
  {
180
0
    libcerror_error_set(
181
0
     error,
182
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
183
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
184
0
     "%s: invalid leak values.",
185
0
     function );
186
187
0
    return( -1 );
188
0
  }
189
97
  if( data == NULL )
190
0
  {
191
0
    libcerror_error_set(
192
0
     error,
193
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195
0
     "%s: invalid data.",
196
0
     function );
197
198
0
    return( -1 );
199
0
  }
200
97
  if( data_size < sizeof( msiecf_leak_record_header_t ) )
201
0
  {
202
0
    libcerror_error_set(
203
0
     error,
204
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
205
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
206
0
     "%s: invalid data size value too small.",
207
0
     function );
208
209
0
    return( -1 );
210
0
  }
211
97
  if( data_size > (size_t) SSIZE_MAX )
212
0
  {
213
0
    libcerror_error_set(
214
0
     error,
215
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
216
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
217
0
     "%s: invalid data size value exceeds maximum.",
218
0
     function );
219
220
0
    return( -1 );
221
0
  }
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
97
  if( memory_compare(
235
97
       ( (msiecf_leak_record_header_t *) data )->signature,
236
97
       "LEAK",
237
97
       4 ) != 0 )
238
0
  {
239
0
    libcerror_error_set(
240
0
     error,
241
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
242
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
243
0
     "%s: unsupported signature.",
244
0
     function );
245
246
0
    goto on_error;
247
0
  }
248
97
  byte_stream_copy_to_uint32_little_endian(
249
97
   ( (msiecf_leak_record_header_t *) data )->cached_file_size,
250
97
   leak_values->cached_file_size );
251
252
97
  leak_values->cache_directory_index = ( (msiecf_leak_record_header_t *) data )->cache_directory_index;
253
254
97
  byte_stream_copy_to_uint32_little_endian(
255
97
   ( (msiecf_leak_record_header_t *) data )->filename_offset,
256
97
   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
97
  if( filename_offset > 0 )
370
95
  {
371
95
    if( filename_offset > data_size )
372
71
    {
373
71
      if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
374
71
      {
375
71
        libcerror_error_set(
376
71
         error,
377
71
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
378
71
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
379
71
         "%s: filename offset exceeds size of URL record data.",
380
71
         function );
381
382
71
        goto on_error;
383
71
      }
384
71
    }
385
24
    else
386
24
    {
387
/* TODO remove need for libfvalue */
388
24
      if( libfvalue_value_type_initialize(
389
24
           &( leak_values->filename ),
390
24
           LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
391
24
           error ) != 1 )
392
0
      {
393
0
        libcerror_error_set(
394
0
         error,
395
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
396
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
397
0
         "%s: unable to create filename value.",
398
0
         function );
399
400
0
        goto on_error;
401
0
      }
402
24
      value_size = libfvalue_value_type_set_data_string(
403
24
                    leak_values->filename,
404
24
                    &( data[ filename_offset ] ),
405
24
                    data_size - filename_offset,
406
24
                    ascii_codepage,
407
24
                    LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
408
24
                    error );
409
410
24
      if( value_size == -1 )
411
0
      {
412
0
        libcerror_error_set(
413
0
         error,
414
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
415
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
416
0
         "%s: unable to set data of filename value.",
417
0
         function );
418
419
0
        goto on_error;
420
0
      }
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
24
      if( ( data[ filename_offset + value_size - 1 ] != 0 )
449
24
       && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
450
9
      {
451
9
        libcerror_error_set(
452
9
         error,
453
9
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
454
9
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
455
9
         "%s: unsupported unterminated filename string.",
456
9
         function );
457
458
9
        goto on_error;
459
9
      }
460
24
    }
461
95
  }
462
#if defined( HAVE_DEBUG_OUTPUT )
463
  if( libcnotify_verbose != 0 )
464
  {
465
    libcnotify_printf(
466
     "\n" );
467
  }
468
#endif
469
17
  return( 1 );
470
471
80
on_error:
472
80
  if( leak_values->filename != NULL )
473
9
  {
474
9
    libfvalue_value_free(
475
9
     &( leak_values->filename ),
476
9
     NULL );
477
9
  }
478
80
  return( 1 );
479
97
}
480
481
/* Reads the leak values from a LEAK record
482
 * Returns 1 if successful or -1 on error
483
 */
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
142
{
493
142
  uint8_t *record_data  = NULL;
494
142
  static char *function = "libmsiecf_leak_values_read_file_io_handle";
495
142
  ssize_t read_count    = 0;
496
497
142
  if( leak_values == NULL )
498
0
  {
499
0
    libcerror_error_set(
500
0
     error,
501
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
502
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
503
0
     "%s: invalid leak values.",
504
0
     function );
505
506
0
    return( -1 );
507
0
  }
508
142
  if( record_size > (size32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
509
4
  {
510
4
    libcerror_error_set(
511
4
     error,
512
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
513
4
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
514
4
     "%s: invalid record size value exceeds maximum allocation size.",
515
4
     function );
516
517
4
    return( -1 );
518
4
  }
519
138
  if( ( record_size == 0 )
520
138
   || ( ( record_size % 8 ) != 0 ) )
521
0
  {
522
0
    libcerror_error_set(
523
0
     error,
524
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
525
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
526
0
     "%s: unsupported record size.",
527
0
     function );
528
529
0
    return( -1 );
530
0
  }
531
138
  record_data = (uint8_t *) memory_allocate(
532
138
                             sizeof( uint8_t ) * record_size );
533
534
138
  if( record_data == NULL )
535
0
  {
536
0
    libcerror_error_set(
537
0
     error,
538
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
539
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
540
0
     "%s: unable to create LEAK record data.",
541
0
     function );
542
543
0
    goto on_error;
544
0
  }
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
138
  read_count = libbfio_handle_read_buffer_at_offset(
556
138
                file_io_handle,
557
138
                record_data,
558
138
                (size_t) record_size,
559
138
                leak_record_offset,
560
138
                error );
561
562
138
  if( read_count != (ssize_t) record_size )
563
41
  {
564
41
    libcerror_error_set(
565
41
     error,
566
41
     LIBCERROR_ERROR_DOMAIN_IO,
567
41
     LIBCERROR_IO_ERROR_READ_FAILED,
568
41
     "%s: unable to read LEAK record data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
569
41
     function,
570
41
     leak_record_offset,
571
41
     leak_record_offset );
572
573
41
    goto on_error;
574
41
  }
575
97
  if( libmsiecf_leak_values_read_data(
576
97
       leak_values,
577
97
       record_data,
578
97
       (size_t) record_size,
579
97
       ascii_codepage,
580
97
       item_flags,
581
97
       error ) != 1 )
582
0
  {
583
0
    libcerror_error_set(
584
0
     error,
585
0
     LIBCERROR_ERROR_DOMAIN_IO,
586
0
     LIBCERROR_IO_ERROR_READ_FAILED,
587
0
     "%s: unable to read LEAK record.",
588
0
     function );
589
590
0
    goto on_error;
591
0
  }
592
97
  memory_free(
593
97
   record_data );
594
595
97
  return( 1 );
596
597
41
on_error:
598
41
  if( record_data != NULL )
599
41
  {
600
41
    memory_free(
601
41
     record_data );
602
41
  }
603
41
  return( -1 );
604
97
}
605