Coverage Report

Created: 2025-06-24 07:14

/src/libregf/libregf/libregf_key_tree.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Key tree 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 <types.h>
24
25
#if defined( HAVE_WCTYPE_H )
26
#include <wctype.h>
27
#endif
28
29
#include "libregf_definitions.h"
30
#include "libregf_hive_bins_list.h"
31
#include "libregf_io_handle.h"
32
#include "libregf_key.h"
33
#include "libregf_key_descriptor.h"
34
#include "libregf_key_item.h"
35
#include "libregf_key_tree.h"
36
#include "libregf_libbfio.h"
37
#include "libregf_libcerror.h"
38
#include "libregf_libuna.h"
39
40
/* Retrieves the key for the specific UTF-8 encoded path
41
 * The path separator is the \ character
42
 * Creates a new key
43
 * Returns 1 if successful, 0 if no such key or -1 on error
44
 */
45
int libregf_key_tree_get_sub_key_by_utf8_path(
46
     libregf_io_handle_t *io_handle,
47
     libbfio_handle_t *file_io_handle,
48
     libregf_hive_bins_list_t *hive_bins_list,
49
     uint32_t key_offset,
50
     const uint8_t *utf8_string,
51
     size_t utf8_string_length,
52
     libregf_key_t **sub_key,
53
     libcerror_error_t **error )
54
0
{
55
0
  libregf_key_descriptor_t *sub_key_descriptor = NULL;
56
0
  libregf_key_item_t *sub_key_item             = NULL;
57
0
  uint8_t *utf8_string_segment                 = NULL;
58
0
  static char *function                        = "libregf_key_tree_get_sub_key_by_utf8_path";
59
0
  libuna_unicode_character_t unicode_character = 0;
60
0
  size_t utf8_string_index                     = 0;
61
0
  size_t utf8_string_segment_length            = 0;
62
0
  uint32_t name_hash                           = 0;
63
0
  uint32_t sub_key_offset                      = 0;
64
0
  int result                                   = 0;
65
66
0
  if( utf8_string == NULL )
67
0
  {
68
0
    libcerror_error_set(
69
0
     error,
70
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
71
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
72
0
     "%s: invalid UTF-8 string.",
73
0
     function );
74
75
0
    return( -1 );
76
0
  }
77
0
  if( utf8_string_length > (size_t) SSIZE_MAX )
78
0
  {
79
0
    libcerror_error_set(
80
0
     error,
81
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
82
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
83
0
     "%s: invalid UTF-8 string length value exceeds maximum.",
84
0
     function );
85
86
0
    return( -1 );
87
0
  }
88
0
  if( sub_key == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
93
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
94
0
     "%s: invalid sub key.",
95
0
     function );
96
97
0
    return( -1 );
98
0
  }
99
0
  if( *sub_key != NULL )
100
0
  {
101
0
    libcerror_error_set(
102
0
     error,
103
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
104
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
105
0
     "%s: sub key already set.",
106
0
     function );
107
108
0
    return( -1 );
109
0
  }
110
0
  sub_key_offset = key_offset;
111
112
0
  if( utf8_string_length > 0 )
113
0
  {
114
    /* Ignore a leading separator
115
     */
116
0
    if( utf8_string[ utf8_string_index ] == (uint8_t) LIBREGF_SEPARATOR )
117
0
    {
118
0
      utf8_string_index++;
119
0
    }
120
0
  }
121
  /* If the string is empty return the current key
122
   */
123
0
  if( utf8_string_length == utf8_string_index )
124
0
  {
125
0
    result = 1;
126
0
  }
127
0
  else while( utf8_string_index < utf8_string_length )
128
0
  {
129
0
    utf8_string_segment        = (uint8_t *) &( utf8_string[ utf8_string_index ] );
130
0
    utf8_string_segment_length = utf8_string_index;
131
0
    name_hash                  = 0;
132
133
0
    while( utf8_string_index < utf8_string_length )
134
0
    {
135
0
      if( libuna_unicode_character_copy_from_utf8(
136
0
           &unicode_character,
137
0
           utf8_string,
138
0
           utf8_string_length,
139
0
           &utf8_string_index,
140
0
           error ) != 1 )
141
0
      {
142
0
        libcerror_error_set(
143
0
         error,
144
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
145
0
         LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
146
0
         "%s: unable to copy UTF-8 string to Unicode character.",
147
0
         function );
148
149
0
        goto on_error;
150
0
      }
151
0
      if( ( unicode_character == (libuna_unicode_character_t) LIBREGF_SEPARATOR )
152
0
       || ( unicode_character == 0 ) )
153
0
      {
154
0
        utf8_string_segment_length += 1;
155
156
0
        break;
157
0
      }
158
0
      name_hash *= 37;
159
0
      name_hash += (uint32_t) towupper( (wint_t) unicode_character );
160
0
    }
161
0
    utf8_string_segment_length = utf8_string_index - utf8_string_segment_length;
162
163
0
    if( utf8_string_segment_length == 0 )
164
0
    {
165
0
      result = 0;
166
0
    }
167
0
    else
168
0
    {
169
/* TODO: instead of key item directory read key descriptors ? */
170
0
      if( libregf_key_item_initialize(
171
0
           &sub_key_item,
172
0
           error ) != 1 )
173
0
      {
174
0
        libcerror_error_set(
175
0
         error,
176
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
177
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
178
0
         "%s: unable to create sub key item.",
179
0
         function );
180
181
0
        goto on_error;
182
0
      }
183
0
      if( libregf_key_item_read(
184
0
           sub_key_item,
185
0
           file_io_handle,
186
0
           hive_bins_list,
187
0
           sub_key_offset,
188
0
           name_hash,
189
0
           error ) != 1 )
190
0
      {
191
0
        libcerror_error_set(
192
0
         error,
193
0
         LIBCERROR_ERROR_DOMAIN_IO,
194
0
         LIBCERROR_IO_ERROR_READ_FAILED,
195
0
         "%s: unable to read sub key item at offset: %" PRIu32 " (0x%08" PRIx32 ").",
196
0
         function,
197
0
         sub_key_offset,
198
0
         sub_key_offset );
199
200
0
        goto on_error;
201
0
      }
202
0
      result = libregf_key_item_get_sub_key_descriptor_by_utf8_name(
203
0
                sub_key_item,
204
0
                file_io_handle,
205
0
                hive_bins_list,
206
0
                name_hash,
207
0
          utf8_string_segment,
208
0
          utf8_string_segment_length,
209
0
                &sub_key_descriptor,
210
0
                error );
211
212
0
      if( result == 1 )
213
0
      {
214
0
        sub_key_offset = sub_key_descriptor->key_offset;
215
0
      }
216
0
      if( libregf_key_item_free(
217
0
           &sub_key_item,
218
0
           error ) != 1 )
219
0
      {
220
0
        libcerror_error_set(
221
0
         error,
222
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
223
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
224
0
         "%s: unable to free sub key item.",
225
0
         function );
226
227
0
        goto on_error;
228
0
      }
229
0
    }
230
0
    if( result == -1 )
231
0
    {
232
0
      libcerror_error_set(
233
0
       error,
234
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
235
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
236
0
       "%s: unable to retrieve sub key values by name.",
237
0
       function );
238
239
0
      goto on_error;
240
0
    }
241
0
    else if( result == 0 )
242
0
    {
243
0
      break;
244
0
    }
245
0
  }
246
0
  if( result != 0 )
247
0
  {
248
0
    if( libregf_key_initialize(
249
0
         sub_key,
250
0
         io_handle,
251
0
         file_io_handle,
252
0
         sub_key_offset,
253
0
         hive_bins_list,
254
0
         error ) != 1 )
255
0
    {
256
0
      libcerror_error_set(
257
0
       error,
258
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
259
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
260
0
       "%s: unable to create sub key.",
261
0
       function );
262
263
0
      goto on_error;
264
0
    }
265
0
  }
266
0
  return( result );
267
268
0
on_error:
269
0
  if( sub_key_item != NULL )
270
0
  {
271
0
    libregf_key_item_free(
272
0
     &sub_key_item,
273
0
     NULL );
274
0
  }
275
0
  return( -1 );
276
0
}
277
278
/* Retrieves the key for the specific UTF-16 encoded path
279
 * The path separator is the \ character
280
 * Creates a new key
281
 * Returns 1 if successful, 0 if no such key or -1 on error
282
 */
283
int libregf_key_tree_get_sub_key_by_utf16_path(
284
     libregf_io_handle_t *io_handle,
285
     libbfio_handle_t *file_io_handle,
286
     libregf_hive_bins_list_t *hive_bins_list,
287
     uint32_t key_offset,
288
     const uint16_t *utf16_string,
289
     size_t utf16_string_length,
290
     libregf_key_t **sub_key,
291
     libcerror_error_t **error )
292
0
{
293
0
  libregf_key_descriptor_t *sub_key_descriptor = NULL;
294
0
  libregf_key_item_t *sub_key_item             = NULL;
295
0
  uint16_t *utf16_string_segment               = NULL;
296
0
  static char *function                        = "libregf_key_tree_get_sub_key_by_utf16_path";
297
0
  libuna_unicode_character_t unicode_character = 0;
298
0
  size_t utf16_string_index                    = 0;
299
0
  size_t utf16_string_segment_length           = 0;
300
0
  uint32_t name_hash                           = 0;
301
0
  uint32_t sub_key_offset                      = 0;
302
0
  int result                                   = 0;
303
304
0
  if( utf16_string == NULL )
305
0
  {
306
0
    libcerror_error_set(
307
0
     error,
308
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
309
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
310
0
     "%s: invalid UTF-16 string.",
311
0
     function );
312
313
0
    return( -1 );
314
0
  }
315
0
  if( utf16_string_length > (size_t) SSIZE_MAX )
316
0
  {
317
0
    libcerror_error_set(
318
0
     error,
319
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
320
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
321
0
     "%s: invalid UTF-16 string length value exceeds maximum.",
322
0
     function );
323
324
0
    return( -1 );
325
0
  }
326
0
  if( sub_key == NULL )
327
0
  {
328
0
    libcerror_error_set(
329
0
     error,
330
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
331
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
332
0
     "%s: invalid sub key.",
333
0
     function );
334
335
0
    return( -1 );
336
0
  }
337
0
  if( *sub_key != NULL )
338
0
  {
339
0
    libcerror_error_set(
340
0
     error,
341
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
342
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
343
0
     "%s: sub key already set.",
344
0
     function );
345
346
0
    return( -1 );
347
0
  }
348
0
  sub_key_offset = key_offset;
349
350
0
  if( utf16_string_length > 0 )
351
0
  {
352
    /* Ignore a leading separator
353
     */
354
0
    if( utf16_string[ utf16_string_index ] == (uint16_t) LIBREGF_SEPARATOR )
355
0
    {
356
0
      utf16_string_index++;
357
0
    }
358
0
  }
359
  /* If the string is empty return the current key
360
   */
361
0
  if( utf16_string_length == utf16_string_index )
362
0
  {
363
0
    result = 1;
364
0
  }
365
0
  else while( utf16_string_index < utf16_string_length )
366
0
  {
367
0
    utf16_string_segment        = (uint16_t *) &( utf16_string[ utf16_string_index ] );
368
0
    utf16_string_segment_length = utf16_string_index;
369
0
    name_hash                   = 0;
370
371
0
    while( utf16_string_index < utf16_string_length )
372
0
    {
373
0
      if( libuna_unicode_character_copy_from_utf16(
374
0
           &unicode_character,
375
0
           utf16_string,
376
0
           utf16_string_length,
377
0
           &utf16_string_index,
378
0
           error ) != 1 )
379
0
      {
380
0
        libcerror_error_set(
381
0
         error,
382
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
383
0
         LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
384
0
         "%s: unable to copy UTF-16 string to Unicode character.",
385
0
         function );
386
387
0
        goto on_error;
388
0
      }
389
0
      if( ( unicode_character == (libuna_unicode_character_t) LIBREGF_SEPARATOR )
390
0
       || ( unicode_character == 0 ) )
391
0
      {
392
0
        utf16_string_segment_length += 1;
393
394
0
        break;
395
0
      }
396
0
      name_hash *= 37;
397
0
      name_hash += (uint32_t) towupper( (wint_t) unicode_character );
398
0
    }
399
0
    utf16_string_segment_length = utf16_string_index - utf16_string_segment_length;
400
401
0
    if( utf16_string_segment_length == 0 )
402
0
    {
403
0
      result = 0;
404
0
    }
405
0
    else
406
0
    {
407
/* TODO: instead of key item directory read key descriptors ? */
408
0
      if( libregf_key_item_initialize(
409
0
           &sub_key_item,
410
0
           error ) != 1 )
411
0
      {
412
0
        libcerror_error_set(
413
0
         error,
414
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
415
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
416
0
         "%s: unable to create sub key item.",
417
0
         function );
418
419
0
        goto on_error;
420
0
      }
421
0
      if( libregf_key_item_read(
422
0
           sub_key_item,
423
0
           file_io_handle,
424
0
           hive_bins_list,
425
0
           sub_key_offset,
426
0
           name_hash,
427
0
           error ) != 1 )
428
0
      {
429
0
        libcerror_error_set(
430
0
         error,
431
0
         LIBCERROR_ERROR_DOMAIN_IO,
432
0
         LIBCERROR_IO_ERROR_READ_FAILED,
433
0
         "%s: unable to read sub key item at offset: %" PRIu32 " (0x%08" PRIx32 ").",
434
0
         function,
435
0
         sub_key_offset,
436
0
         sub_key_offset );
437
438
0
        goto on_error;
439
0
      }
440
0
      result = libregf_key_item_get_sub_key_descriptor_by_utf16_name(
441
0
                sub_key_item,
442
0
                file_io_handle,
443
0
                hive_bins_list,
444
0
                name_hash,
445
0
          utf16_string_segment,
446
0
          utf16_string_segment_length,
447
0
                &sub_key_descriptor,
448
0
                error );
449
450
0
      if( result == 1 )
451
0
      {
452
0
        sub_key_offset = sub_key_descriptor->key_offset;
453
0
      }
454
0
      if( libregf_key_item_free(
455
0
           &sub_key_item,
456
0
           error ) != 1 )
457
0
      {
458
0
        libcerror_error_set(
459
0
         error,
460
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
461
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
462
0
         "%s: unable to free sub key item.",
463
0
         function );
464
465
0
        goto on_error;
466
0
      }
467
0
    }
468
0
    if( result == -1 )
469
0
    {
470
0
      libcerror_error_set(
471
0
       error,
472
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
473
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
474
0
       "%s: unable to retrieve sub key values by name.",
475
0
       function );
476
477
0
      goto on_error;
478
0
    }
479
0
    else if( result == 0 )
480
0
    {
481
0
      break;
482
0
    }
483
0
  }
484
0
  if( result != 0 )
485
0
  {
486
0
    if( libregf_key_initialize(
487
0
         sub_key,
488
0
         io_handle,
489
0
         file_io_handle,
490
0
         sub_key_offset,
491
0
         hive_bins_list,
492
0
         error ) != 1 )
493
0
    {
494
0
      libcerror_error_set(
495
0
       error,
496
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
497
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
498
0
       "%s: unable to create sub key.",
499
0
       function );
500
501
0
      goto on_error;
502
0
    }
503
0
  }
504
0
  return( result );
505
506
0
on_error:
507
0
  if( sub_key_item != NULL )
508
0
  {
509
0
    libregf_key_item_free(
510
0
     &sub_key_item,
511
0
     NULL );
512
0
  }
513
0
  return( -1 );
514
0
}
515