1 /*
2 * MTP storage device volume (shell item) values functions
3 *
4 * Copyright (C) 2010-2020, 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 <types.h>
26
27 #include "libfwsi_debug.h"
28 #include "libfwsi_libcerror.h"
29 #include "libfwsi_libcnotify.h"
30 #include "libfwsi_libfguid.h"
31 #include "libfwsi_libfole.h"
32 #include "libfwsi_libuna.h"
33 #include "libfwsi_mtp_volume_values.h"
34
35 /* Creates MTP volume values
36 * Make sure the value mtp_volume_values is referencing, is set to NULL
37 * Returns 1 if successful or -1 on error
38 */
libfwsi_mtp_volume_values_initialize(libfwsi_mtp_volume_values_t ** mtp_volume_values,libcerror_error_t ** error)39 int libfwsi_mtp_volume_values_initialize(
40 libfwsi_mtp_volume_values_t **mtp_volume_values,
41 libcerror_error_t **error )
42 {
43 static char *function = "libfwsi_mtp_volume_values_initialize";
44
45 if( mtp_volume_values == NULL )
46 {
47 libcerror_error_set(
48 error,
49 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
50 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
51 "%s: invalid MTP volume values.",
52 function );
53
54 return( -1 );
55 }
56 if( *mtp_volume_values != NULL )
57 {
58 libcerror_error_set(
59 error,
60 LIBCERROR_ERROR_DOMAIN_RUNTIME,
61 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
62 "%s: invalid MTP volume values value already set.",
63 function );
64
65 return( -1 );
66 }
67 *mtp_volume_values = memory_allocate_structure(
68 libfwsi_mtp_volume_values_t );
69
70 if( *mtp_volume_values == NULL )
71 {
72 libcerror_error_set(
73 error,
74 LIBCERROR_ERROR_DOMAIN_MEMORY,
75 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
76 "%s: unable to create MTP volume values.",
77 function );
78
79 goto on_error;
80 }
81 if( memory_set(
82 *mtp_volume_values,
83 0,
84 sizeof( libfwsi_mtp_volume_values_t ) ) == NULL )
85 {
86 libcerror_error_set(
87 error,
88 LIBCERROR_ERROR_DOMAIN_MEMORY,
89 LIBCERROR_MEMORY_ERROR_SET_FAILED,
90 "%s: unable to clear MTP volume values.",
91 function );
92
93 goto on_error;
94 }
95 return( 1 );
96
97 on_error:
98 if( *mtp_volume_values != NULL )
99 {
100 memory_free(
101 *mtp_volume_values );
102
103 *mtp_volume_values = NULL;
104 }
105 return( -1 );
106 }
107
108 /* Frees MTP volume values
109 * Returns 1 if successful or -1 on error
110 */
libfwsi_mtp_volume_values_free(libfwsi_mtp_volume_values_t ** mtp_volume_values,libcerror_error_t ** error)111 int libfwsi_mtp_volume_values_free(
112 libfwsi_mtp_volume_values_t **mtp_volume_values,
113 libcerror_error_t **error )
114 {
115 static char *function = "libfwsi_mtp_volume_values_free";
116
117 if( mtp_volume_values == NULL )
118 {
119 libcerror_error_set(
120 error,
121 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
122 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
123 "%s: invalid MTP volume values.",
124 function );
125
126 return( -1 );
127 }
128 if( *mtp_volume_values != NULL )
129 {
130 memory_free(
131 *mtp_volume_values );
132
133 *mtp_volume_values = NULL;
134 }
135 return( 1 );
136 }
137
138 /* Reads the MTP volume values
139 * Returns 1 if successful, 0 if not supported or -1 on error
140 */
libfwsi_mtp_volume_values_read_data(libfwsi_mtp_volume_values_t * mtp_volume_values,const uint8_t * data,size_t data_size,libcerror_error_t ** error)141 int libfwsi_mtp_volume_values_read_data(
142 libfwsi_mtp_volume_values_t *mtp_volume_values,
143 const uint8_t *data,
144 size_t data_size,
145 libcerror_error_t **error )
146 {
147 static char *function = "libfwsi_mtp_volume_values_read_data";
148 size_t data_offset = 0;
149 uint32_t file_system_string_size = 0;
150 uint32_t guid_string_index = 0;
151 uint32_t identifier_string_size = 0;
152 uint32_t name_string_size = 0;
153 uint32_t number_of_guid_strings = 0;
154 uint32_t number_of_properties = 0;
155 uint32_t property_index = 0;
156 uint32_t property_value_type = 0;
157 uint32_t signature = 0;
158 uint32_t string_size = 0;
159 uint16_t item_data_size = 0;
160
161 #if defined( HAVE_DEBUG_OUTPUT )
162 uint32_t value_32bit = 0;
163 uint16_t value_16bit = 0;
164 #endif
165
166 if( mtp_volume_values == NULL )
167 {
168 libcerror_error_set(
169 error,
170 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
171 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
172 "%s: invalid MTP volume values.",
173 function );
174
175 return( -1 );
176 }
177 if( data == NULL )
178 {
179 libcerror_error_set(
180 error,
181 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
182 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
183 "%s: invalid data.",
184 function );
185
186 return( -1 );
187 }
188 if( data_size > (size_t) SSIZE_MAX )
189 {
190 libcerror_error_set(
191 error,
192 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
193 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
194 "%s: data size exceeds maximum.",
195 function );
196
197 return( -1 );
198 }
199 /* Do not try to parse unsupported data sizes
200 */
201 if( data_size < 10 )
202 {
203 return( 0 );
204 }
205 /* Do not try to parse unsupported shell item signatures
206 */
207 byte_stream_copy_to_uint32_little_endian(
208 &( data[ 6 ] ),
209 signature );
210
211 if( signature != 0x10312005UL )
212 {
213 return( 0 );
214 }
215 byte_stream_copy_to_uint32_little_endian(
216 &( data[ 4 ] ),
217 item_data_size );
218
219 #if defined( HAVE_DEBUG_OUTPUT )
220 if( libcnotify_verbose != 0 )
221 {
222 libcnotify_printf(
223 "%s: class type indicator\t\t\t: 0x%02" PRIx8 "\n",
224 function,
225 data[ 2 ] );
226
227 libcnotify_printf(
228 "%s: unknown1\t\t\t\t: 0x%02" PRIx8 "\n",
229 function,
230 data[ 3 ] );
231
232 libcnotify_printf(
233 "%s: data size\t\t\t\t: %" PRIu16 "\n",
234 function,
235 item_data_size );
236
237 libcnotify_printf(
238 "%s: signature\t\t\t\t: 0x%08" PRIx32 "\n",
239 function,
240 signature );
241 }
242 #endif
243 if( item_data_size == 0 )
244 {
245 return( 10 );
246 }
247 if( ( item_data_size < 44 )
248 && ( item_data_size > ( data_size - 10 ) ) )
249 {
250 libcerror_error_set(
251 error,
252 LIBCERROR_ERROR_DOMAIN_RUNTIME,
253 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
254 "%s: invalid data size value out of bounds.",
255 function );
256
257 return( -1 );
258 }
259 byte_stream_copy_to_uint32_little_endian(
260 &( data[ 38 ] ),
261 name_string_size );
262
263 byte_stream_copy_to_uint32_little_endian(
264 &( data[ 42 ] ),
265 identifier_string_size );
266
267 byte_stream_copy_to_uint32_little_endian(
268 &( data[ 46 ] ),
269 file_system_string_size );
270
271 byte_stream_copy_to_uint32_little_endian(
272 &( data[ 50 ] ),
273 number_of_guid_strings );
274
275 #if defined( HAVE_DEBUG_OUTPUT )
276 if( libcnotify_verbose != 0 )
277 {
278 byte_stream_copy_to_uint32_little_endian(
279 &( data[ 10 ] ),
280 value_32bit );
281 libcnotify_printf(
282 "%s: unknown2\t\t\t\t: 0x%08" PRIx32 "\n",
283 function,
284 value_32bit );
285
286 byte_stream_copy_to_uint16_little_endian(
287 &( data[ 14 ] ),
288 value_16bit );
289 libcnotify_printf(
290 "%s: unknown3\t\t\t\t: 0x%04" PRIx16 "\n",
291 function,
292 value_16bit );
293
294 byte_stream_copy_to_uint16_little_endian(
295 &( data[ 16 ] ),
296 value_16bit );
297 libcnotify_printf(
298 "%s: unknown4\t\t\t\t: 0x%04" PRIx16 "\n",
299 function,
300 value_16bit );
301
302 byte_stream_copy_to_uint16_little_endian(
303 &( data[ 18 ] ),
304 value_16bit );
305 libcnotify_printf(
306 "%s: unknown5\t\t\t\t: 0x%04" PRIx16 "\n",
307 function,
308 value_16bit );
309
310 byte_stream_copy_to_uint16_little_endian(
311 &( data[ 20 ] ),
312 value_16bit );
313 libcnotify_printf(
314 "%s: unknown6\t\t\t\t: 0x%04" PRIx16 "\n",
315 function,
316 value_16bit );
317
318 byte_stream_copy_to_uint32_little_endian(
319 &( data[ 22 ] ),
320 value_32bit );
321 libcnotify_printf(
322 "%s: unknown7\t\t\t\t: 0x%08" PRIx32 "\n",
323 function,
324 value_32bit );
325
326 libcnotify_printf(
327 "%s: unknown8:\n",
328 function );
329 libcnotify_print_data(
330 &( data[ 26 ] ),
331 8,
332 0 );
333
334 byte_stream_copy_to_uint32_little_endian(
335 &( data[ 34 ] ),
336 value_32bit );
337 libcnotify_printf(
338 "%s: unknown9\t\t\t\t: 0x%08" PRIx32 "\n",
339 function,
340 value_32bit );
341
342 libcnotify_printf(
343 "%s: name string size\t\t\t: %" PRIu32 "\n",
344 function,
345 name_string_size );
346
347 libcnotify_printf(
348 "%s: identifier string size\t\t\t: %" PRIu32 "\n",
349 function,
350 identifier_string_size );
351
352 libcnotify_printf(
353 "%s: file system string size\t\t\t: %" PRIu32 "\n",
354 function,
355 file_system_string_size );
356
357 libcnotify_printf(
358 "%s: number of GUID strings\t\t\t: %" PRIu32 "\n",
359 function,
360 number_of_guid_strings );
361 }
362 #endif
363 data_offset = 54;
364
365 if( name_string_size > 0 )
366 {
367 name_string_size *= 2;
368
369 /* TODO check bounds */
370 #if defined( HAVE_DEBUG_OUTPUT )
371 if( libcnotify_verbose != 0 )
372 {
373 if( libfwsi_debug_print_utf16_string_value(
374 function,
375 "name\t\t\t\t\t",
376 &( data[ data_offset ] ),
377 name_string_size,
378 LIBUNA_ENDIAN_LITTLE,
379 error ) != 1 )
380 {
381 libcerror_error_set(
382 error,
383 LIBCERROR_ERROR_DOMAIN_RUNTIME,
384 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
385 "%s: unable to print UTF-16 string value.",
386 function );
387
388 return( -1 );
389 }
390 }
391 #endif
392 data_offset += name_string_size;
393 }
394 if( identifier_string_size > 0 )
395 {
396 identifier_string_size *= 2;
397
398 /* TODO check bounds */
399 #if defined( HAVE_DEBUG_OUTPUT )
400 if( libcnotify_verbose != 0 )
401 {
402 if( libfwsi_debug_print_utf16_string_value(
403 function,
404 "identifier\t\t\t\t",
405 &( data[ data_offset ] ),
406 identifier_string_size,
407 LIBUNA_ENDIAN_LITTLE,
408 error ) != 1 )
409 {
410 libcerror_error_set(
411 error,
412 LIBCERROR_ERROR_DOMAIN_RUNTIME,
413 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
414 "%s: unable to print UTF-16 string value.",
415 function );
416
417 return( -1 );
418 }
419 }
420 #endif
421 data_offset += identifier_string_size;
422 }
423 if( file_system_string_size > 0 )
424 {
425 file_system_string_size *= 2;
426
427 /* TODO check bounds */
428 #if defined( HAVE_DEBUG_OUTPUT )
429 if( libcnotify_verbose != 0 )
430 {
431 if( libfwsi_debug_print_utf16_string_value(
432 function,
433 "file system\t\t\t\t",
434 &( data[ data_offset ] ),
435 file_system_string_size,
436 LIBUNA_ENDIAN_LITTLE,
437 error ) != 1 )
438 {
439 libcerror_error_set(
440 error,
441 LIBCERROR_ERROR_DOMAIN_RUNTIME,
442 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
443 "%s: unable to print UTF-16 string value.",
444 function );
445
446 return( -1 );
447 }
448 }
449 #endif
450 data_offset += file_system_string_size;
451 }
452 for( guid_string_index = 0;
453 guid_string_index < number_of_guid_strings;
454 guid_string_index++ )
455 {
456 /* TODO check bounds */
457 #if defined( HAVE_DEBUG_OUTPUT )
458 if( libcnotify_verbose != 0 )
459 {
460 if( libfwsi_debug_print_utf16_string_value(
461 function,
462 "GUID\t\t\t\t\t",
463 &( data[ data_offset ] ),
464 78,
465 LIBUNA_ENDIAN_LITTLE,
466 error ) != 1 )
467 {
468 libcerror_error_set(
469 error,
470 LIBCERROR_ERROR_DOMAIN_RUNTIME,
471 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
472 "%s: unable to print UTF-16 string value.",
473 function );
474
475 return( -1 );
476 }
477 }
478 #endif
479 data_offset += 78;
480 }
481 /* TODO move to common MTP property values function */
482 if( data_offset < ( data_size - 4 ) )
483 {
484 #if defined( HAVE_DEBUG_OUTPUT )
485 if( libcnotify_verbose != 0 )
486 {
487 byte_stream_copy_to_uint32_little_endian(
488 &( data[ data_offset ] ),
489 value_32bit );
490 libcnotify_printf(
491 "%s: unknown10\t\t\t\t: 0x%08" PRIx32 "\n",
492 function,
493 value_32bit );
494 }
495 #endif
496 data_offset += 4;
497 }
498 if( data_offset < ( data_size - 16 ) )
499 {
500 #if defined( HAVE_DEBUG_OUTPUT )
501 if( libcnotify_verbose != 0 )
502 {
503 if( libfwsi_debug_print_guid_value(
504 function,
505 "class identifier\t\t\t",
506 &( data[ data_offset ] ),
507 16,
508 LIBFGUID_ENDIAN_LITTLE,
509 LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
510 error ) != 1 )
511 {
512 libcerror_error_set(
513 error,
514 LIBCERROR_ERROR_DOMAIN_RUNTIME,
515 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
516 "%s: unable to print GUID value.",
517 function );
518
519 return( -1 );
520 }
521 }
522 #endif
523 data_offset += 16;
524 }
525 if( data_offset < ( data_size - 4 ) )
526 {
527 byte_stream_copy_to_uint32_little_endian(
528 &( data[ data_offset ] ),
529 number_of_properties );
530
531 #if defined( HAVE_DEBUG_OUTPUT )
532 if( libcnotify_verbose != 0 )
533 {
534 libcnotify_printf(
535 "%s: number of properties\t\t\t: %" PRIu32 "\n",
536 function,
537 number_of_properties );
538 }
539 #endif
540 data_offset += 4;
541 }
542 #if defined( HAVE_DEBUG_OUTPUT )
543 if( libcnotify_verbose != 0 )
544 {
545 libcnotify_printf(
546 "\n" );
547 }
548 #endif
549 for( property_index = 0;
550 property_index < number_of_properties;
551 property_index++ )
552 {
553 #if defined( HAVE_DEBUG_OUTPUT )
554 if( libcnotify_verbose != 0 )
555 {
556 libcnotify_printf(
557 "%s: property value: %" PRIu32 "\n",
558 function,
559 property_index );
560 }
561 #endif
562 /* TODO at least 24 bytes in size ? */
563 if( data_offset < ( data_size - 16 ) )
564 {
565 #if defined( HAVE_DEBUG_OUTPUT )
566 if( libcnotify_verbose != 0 )
567 {
568 if( libfwsi_debug_print_guid_value(
569 function,
570 "property set identifier\t\t\t",
571 &( data[ data_offset ] ),
572 16,
573 LIBFGUID_ENDIAN_LITTLE,
574 LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
575 error ) != 1 )
576 {
577 libcerror_error_set(
578 error,
579 LIBCERROR_ERROR_DOMAIN_RUNTIME,
580 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
581 "%s: unable to print GUID value.",
582 function );
583
584 return( -1 );
585 }
586 }
587 #endif
588 data_offset += 16;
589 }
590 if( data_offset < ( data_size - 4 ) )
591 {
592 #if defined( HAVE_DEBUG_OUTPUT )
593 if( libcnotify_verbose != 0 )
594 {
595 byte_stream_copy_to_uint32_little_endian(
596 &( data[ data_offset ] ),
597 value_32bit );
598 libcnotify_printf(
599 "%s: property value identifier\t\t: %" PRIu32 "\n",
600 function,
601 value_32bit );
602 }
603 #endif
604 data_offset += 4;
605 }
606 if( data_offset < ( data_size - 4 ) )
607 {
608 byte_stream_copy_to_uint32_little_endian(
609 &( data[ data_offset ] ),
610 property_value_type );
611
612 #if defined( HAVE_DEBUG_OUTPUT )
613 if( libcnotify_verbose != 0 )
614 {
615 libcnotify_printf(
616 "%s: property value type\t\t\t: 0x%08" PRIx32 " (%s : %s)\n",
617 function,
618 property_value_type,
619 libfole_value_type_get_identifier(
620 property_value_type ),
621 libfole_value_type_get_description(
622 property_value_type ) );
623 }
624 #endif
625 data_offset += 4;
626 }
627 /* TODO merge with FOLE */
628 switch( property_value_type )
629 {
630 case 0x00000005UL:
631 case 0x00000007UL:
632 case 0x00000015UL:
633 #if defined( HAVE_DEBUG_OUTPUT )
634 if( libcnotify_verbose != 0 )
635 {
636 libcnotify_printf(
637 "%s: value data:\n",
638 function );
639 libcnotify_print_data(
640 &( data[ data_offset ] ),
641 8,
642 0 );
643 }
644 #endif
645 data_offset += 8;
646
647 break;
648
649 case 0x0000000bUL:
650 case 0x00000012UL:
651 if( data_offset < ( data_size - 2 ) )
652 {
653 #if defined( HAVE_DEBUG_OUTPUT )
654 if( libcnotify_verbose != 0 )
655 {
656 byte_stream_copy_to_uint16_little_endian(
657 &( data[ data_offset ] ),
658 value_16bit );
659 libcnotify_printf(
660 "%s: value\t\t\t\t\t: 0x%04" PRIx16 "\n",
661 function,
662 value_16bit );
663
664 libcnotify_printf(
665 "\n" );
666 }
667 #endif
668 data_offset += 2;
669 }
670 break;
671
672 case 0x0000000aUL:
673 case 0x00000013UL:
674 if( data_offset < ( data_size - 4 ) )
675 {
676 #if defined( HAVE_DEBUG_OUTPUT )
677 if( libcnotify_verbose != 0 )
678 {
679 byte_stream_copy_to_uint32_little_endian(
680 &( data[ data_offset ] ),
681 value_32bit );
682 libcnotify_printf(
683 "%s: value\t\t\t\t\t: 0x%08" PRIx32 "\n",
684 function,
685 value_32bit );
686
687 libcnotify_printf(
688 "\n" );
689 }
690 #endif
691 data_offset += 4;
692 }
693 break;
694
695 case 0x0000001fUL:
696 if( data_offset < ( data_size - 4 ) )
697 {
698 byte_stream_copy_to_uint32_little_endian(
699 &( data[ data_offset ] ),
700 string_size );
701
702 #if defined( HAVE_DEBUG_OUTPUT )
703 if( libcnotify_verbose != 0 )
704 {
705 libcnotify_printf(
706 "%s: string size\t\t\t\t: %" PRIu32 "\n",
707 function,
708 string_size );
709 }
710 #endif
711 data_offset += 4;
712
713 if( string_size > 0 )
714 {
715 #if defined( HAVE_DEBUG_OUTPUT )
716 if( libcnotify_verbose != 0 )
717 {
718 if( libfwsi_debug_print_utf16_string_value(
719 function,
720 "string\t\t\t\t\t",
721 &( data[ data_offset ] ),
722 string_size,
723 LIBUNA_ENDIAN_LITTLE,
724 error ) != 1 )
725 {
726 libcerror_error_set(
727 error,
728 LIBCERROR_ERROR_DOMAIN_RUNTIME,
729 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
730 "%s: unable to print UTF-16 string value.",
731 function );
732
733 return( -1 );
734 }
735 libcnotify_printf(
736 "\n" );
737 }
738 #endif
739 data_offset += string_size;
740 }
741 }
742 break;
743
744 case 0x00000048UL:
745 if( data_offset < ( data_size - 16 ) )
746 {
747 #if defined( HAVE_DEBUG_OUTPUT )
748 if( libcnotify_verbose != 0 )
749 {
750 if( libfwsi_debug_print_guid_value(
751 function,
752 "GUID\t\t\t\t\t",
753 &( data[ data_offset ] ),
754 16,
755 LIBFGUID_ENDIAN_LITTLE,
756 LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
757 error ) != 1 )
758 {
759 libcerror_error_set(
760 error,
761 LIBCERROR_ERROR_DOMAIN_RUNTIME,
762 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
763 "%s: unable to print GUID value.",
764 function );
765
766 return( -1 );
767 }
768 libcnotify_printf(
769 "\n" );
770 }
771 #endif
772 data_offset += 16;
773 }
774 break;
775 }
776 }
777 /* TODO */
778
779 #if defined( HAVE_DEBUG_OUTPUT )
780 if( libcnotify_verbose != 0 )
781 {
782 libcnotify_printf(
783 "\n" );
784 }
785 #endif
786 return( 1 );
787 }
788
789