/src/sleuthkit/tsk/fs/fs_open.c
Line | Count | Source |
1 | | /* |
2 | | ** tsk_fs_open_img |
3 | | ** The Sleuth Kit |
4 | | ** |
5 | | ** Brian Carrier [carrier <at> sleuthkit [dot] org] |
6 | | ** Copyright (c) 2006-2011 Brian Carrier, Basis Technology. All Rights reserved |
7 | | ** Copyright (c) 2003-2005 Brian Carrier. All rights reserved |
8 | | ** |
9 | | ** TASK |
10 | | ** Copyright (c) 2002 Brian Carrier, @stake Inc. All rights reserved |
11 | | ** |
12 | | ** Copyright (c) 1997,1998,1999, International Business Machines |
13 | | ** Corporation and others. All Rights Reserved. |
14 | | */ |
15 | | |
16 | | /* TCT */ |
17 | | /*++ |
18 | | * LICENSE |
19 | | * This software is distributed under the IBM Public License. |
20 | | * AUTHOR(S) |
21 | | * Wietse Venema |
22 | | * IBM T.J. Watson Research |
23 | | * P.O. Box 704 |
24 | | * Yorktown Heights, NY 10598, USA |
25 | | --*/ |
26 | | |
27 | | #include "tsk_fs_i.h" |
28 | | #include "tsk/util/detect_encryption.h" |
29 | | #include "encryptionHelper.h" |
30 | | #include "tsk/img/unsupported_types.h" |
31 | | |
32 | | /** |
33 | | * \file fs_open.c |
34 | | * Contains the general code to open a file system -- this calls |
35 | | * the file system -specific opening routines. |
36 | | */ |
37 | | |
38 | | |
39 | | /** |
40 | | * \ingroup fslib |
41 | | * Tries to process data in a volume as a file system. |
42 | | * Returns a structure that can be used for analysis and reporting. |
43 | | * |
44 | | * @param a_part_info Open volume to read from and analyze |
45 | | * @param a_ftype Type of file system (or autodetect) |
46 | | * |
47 | | * @return NULL on error |
48 | | */ |
49 | | TSK_FS_INFO * |
50 | | tsk_fs_open_vol(const TSK_VS_PART_INFO * a_part_info, |
51 | | TSK_FS_TYPE_ENUM a_ftype) |
52 | 0 | { |
53 | 0 | return tsk_fs_open_vol_decrypt(a_part_info, a_ftype, ""); |
54 | 0 | } |
55 | | |
56 | | /** |
57 | | * \ingroup fslib |
58 | | * Tries to process data in a volume as a file system. |
59 | | * Allows for providing an optional password for decryption. |
60 | | * Returns a structure that can be used for analysis and reporting. |
61 | | * |
62 | | * @param a_part_info Open volume to read from and analyze |
63 | | * @param a_ftype Type of file system (or autodetect) |
64 | | * @param a_pass Password to decrypt filesystem |
65 | | * |
66 | | * @return NULL on error |
67 | | */ |
68 | | TSK_FS_INFO * |
69 | | tsk_fs_open_vol_decrypt(const TSK_VS_PART_INFO * a_part_info, |
70 | | TSK_FS_TYPE_ENUM a_ftype, const char * a_pass) |
71 | 0 | { |
72 | 0 | TSK_OFF_T offset; |
73 | 0 | if (a_part_info == NULL) { |
74 | 0 | tsk_error_reset(); |
75 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
76 | 0 | tsk_error_set_errstr("tsk_fs_open_vol: Null vpart handle"); |
77 | 0 | return NULL; |
78 | 0 | } |
79 | 0 | else if ((a_part_info->vs == NULL) |
80 | 0 | || (a_part_info->vs->tag != TSK_VS_INFO_TAG)) { |
81 | 0 | tsk_error_reset(); |
82 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
83 | 0 | tsk_error_set_errstr("tsk_fs_open_vol: Null vs handle"); |
84 | 0 | return NULL; |
85 | 0 | } |
86 | | |
87 | 0 | offset = |
88 | 0 | a_part_info->start * a_part_info->vs->block_size + |
89 | 0 | a_part_info->vs->offset; |
90 | 0 | return tsk_fs_open_img_decrypt(a_part_info->vs->img_info, offset, |
91 | 0 | a_ftype, a_pass); |
92 | 0 | } |
93 | | |
94 | | /** |
95 | | * \ingroup fslib |
96 | | * Tries to process data in a disk image at a given offset as a file system. |
97 | | * Returns a structure that can be used for analysis and reporting. |
98 | | * |
99 | | * @param a_img_info Disk image to analyze |
100 | | * @param a_offset Byte offset to start analyzing from |
101 | | * @param a_ftype Type of file system (or autodetect) |
102 | | * |
103 | | * @return NULL on error |
104 | | */ |
105 | | TSK_FS_INFO * |
106 | | tsk_fs_open_img(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset, |
107 | | TSK_FS_TYPE_ENUM a_ftype) |
108 | 11.5k | { |
109 | 11.5k | return tsk_fs_open_img_decrypt(a_img_info, a_offset, a_ftype, ""); |
110 | 11.5k | } |
111 | | |
112 | | /** |
113 | | * \ingroup fslib |
114 | | * Tries to process data in a disk image at a given offset as a file system. |
115 | | * Allows for providing an optional password for decryption. |
116 | | * Returns a structure that can be used for analysis and reporting. |
117 | | * |
118 | | * @param a_img_info Disk image to analyze |
119 | | * @param a_offset Byte offset to start analyzing from |
120 | | * @param a_ftype Type of file system (or autodetect) |
121 | | * @param a_pass Password to decrypt filesystem. Currently only used if type is specified. |
122 | | * |
123 | | * @return NULL on error |
124 | | */ |
125 | | TSK_FS_INFO * |
126 | | tsk_fs_open_img_decrypt(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset, |
127 | | TSK_FS_TYPE_ENUM a_ftype, const char * a_pass) |
128 | 11.5k | { |
129 | 11.5k | TSK_FS_INFO *fs_info; |
130 | 11.5k | const struct { |
131 | 11.5k | char* name; |
132 | 11.5k | TSK_FS_INFO* (*open)(TSK_IMG_INFO*, TSK_OFF_T, |
133 | 11.5k | TSK_FS_TYPE_ENUM, const char*, uint8_t); |
134 | | // This type should be the _DETECT version because it used |
135 | | // during autodetection |
136 | 11.5k | TSK_FS_TYPE_ENUM type; |
137 | 11.5k | } FS_OPENERS[] = { |
138 | 11.5k | { "NTFS", ntfs_open, TSK_FS_TYPE_NTFS_DETECT }, |
139 | 11.5k | { "FAT", fatfs_open, TSK_FS_TYPE_FAT_DETECT }, |
140 | 11.5k | { "EXT2/3/4", ext2fs_open, TSK_FS_TYPE_EXT_DETECT }, |
141 | 11.5k | { "UFS", ffs_open, TSK_FS_TYPE_FFS_DETECT }, |
142 | 11.5k | { "YAFFS2", yaffs2_open, TSK_FS_TYPE_YAFFS2_DETECT }, |
143 | 11.5k | { "XFS", xfs_open, TSK_FS_TYPE_XFS_DETECT }, |
144 | 11.5k | #if TSK_USE_HFS |
145 | 11.5k | { "HFS", hfs_open, TSK_FS_TYPE_HFS_DETECT }, |
146 | 11.5k | #endif |
147 | 11.5k | { "ISO9660", iso9660_open, TSK_FS_TYPE_ISO9660_DETECT }, |
148 | 11.5k | { "APFS", apfs_open_auto_detect, TSK_FS_TYPE_APFS_DETECT }, |
149 | 11.5k | { "BTRFS", btrfs_open, TSK_FS_TYPE_BTRFS_DETECT }, |
150 | 11.5k | }; |
151 | 11.5k | if (a_img_info == NULL) { |
152 | 0 | tsk_error_reset(); |
153 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
154 | 0 | tsk_error_set_errstr("tsk_fs_open_img: Null image handle"); |
155 | 0 | return NULL; |
156 | 0 | } |
157 | | |
158 | | /* If the image is type IMG_DIR_INFO, then the file system is |
159 | | * automatically the logical directory file system type. It is an |
160 | | * error to try to use any other file system type in that case. |
161 | | */ |
162 | 11.5k | if (a_img_info->itype == TSK_IMG_TYPE_LOGICAL) { |
163 | 0 | if (!(a_ftype == TSK_FS_TYPE_DETECT || a_ftype == TSK_FS_TYPE_LOGICAL)) { |
164 | 0 | tsk_error_reset(); |
165 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
166 | 0 | tsk_error_set_errstr("tsk_fs_open_img: Incompatible file system type given for logical file image"); |
167 | 0 | return NULL; |
168 | 0 | } |
169 | | |
170 | 0 | return logical_fs_open(a_img_info); |
171 | 0 | } |
172 | | |
173 | | /* We will try different file systems ... |
174 | | * We need to try all of them in case more than one matches |
175 | | */ |
176 | 11.5k | if (a_ftype == TSK_FS_TYPE_DETECT) { |
177 | 0 | unsigned long i; |
178 | 0 | const char *name_first = ""; |
179 | 0 | TSK_FS_INFO *fs_first = NULL; |
180 | |
|
181 | 0 | if (tsk_verbose) |
182 | 0 | tsk_fprintf(stderr, |
183 | 0 | "fsopen: Auto detection mode at offset %" PRIdOFF "\n", |
184 | 0 | a_offset); |
185 | |
|
186 | 0 | int haveErrorToPreserve = 0; |
187 | 0 | uint32_t errorCodeToPreserve; |
188 | 0 | char errorStrToPreserve[TSK_ERROR_STRING_MAX_LENGTH + 1]; |
189 | |
|
190 | 0 | for (i = 0; i < sizeof(FS_OPENERS)/sizeof(FS_OPENERS[0]); ++i) { |
191 | 0 | if ((fs_info = FS_OPENERS[i].open( |
192 | 0 | a_img_info, a_offset, FS_OPENERS[i].type, a_pass, 1)) != NULL) { |
193 | | // fs opens as type i |
194 | 0 | if (fs_first == NULL) { |
195 | | // first success opening fs |
196 | 0 | name_first = FS_OPENERS[i].name; |
197 | 0 | fs_first = fs_info; |
198 | 0 | } |
199 | 0 | else { |
200 | | // second success opening fs, which means we |
201 | | // cannot autodetect the fs type and must give up |
202 | 0 | fs_first->close(fs_first); |
203 | 0 | fs_info->close(fs_info); |
204 | 0 | tsk_error_reset(); |
205 | 0 | tsk_error_set_errno(TSK_ERR_FS_MULTTYPE); |
206 | 0 | tsk_error_set_errstr( |
207 | 0 | "%s or %s", FS_OPENERS[i].name, name_first); |
208 | 0 | return NULL; |
209 | 0 | } |
210 | 0 | } |
211 | 0 | else { |
212 | | // fs does not open as type i |
213 | | |
214 | | // TSK_ERR_FS_BITLOCKER_ERROR is used when we get pretty far into the BitLocker processing but |
215 | | // need something different from the user or find something we can't currently parse. We need |
216 | | // to keep trying file systems (we might have a FAT system so we don't want to return after |
217 | | // failing to open as NTFS) but we also want to be able to get the error back to the user. |
218 | 0 | if (tsk_error_get_errno() == TSK_ERR_FS_BITLOCKER_ERROR) { |
219 | 0 | haveErrorToPreserve = 1; |
220 | 0 | errorCodeToPreserve = tsk_error_get_errno(); |
221 | 0 | memset(errorStrToPreserve, 0, TSK_ERROR_STRING_MAX_LENGTH + 1); |
222 | 0 | strncpy(errorStrToPreserve, tsk_error_get_errstr(), TSK_ERROR_STRING_MAX_LENGTH); |
223 | 0 | } |
224 | |
|
225 | 0 | tsk_error_reset(); |
226 | 0 | } |
227 | 0 | } |
228 | | |
229 | | // If we have an error to report, set it now and return |
230 | 0 | if (haveErrorToPreserve) { |
231 | 0 | tsk_error_reset(); |
232 | 0 | tsk_error_set_errno(errorCodeToPreserve); |
233 | 0 | tsk_error_set_errstr("%s", errorStrToPreserve); |
234 | 0 | return NULL; |
235 | 0 | } |
236 | | |
237 | 0 | if (fs_first == NULL) { |
238 | 0 | tsk_error_reset(); |
239 | | |
240 | | // If we're still at the start of the image and haven't identified any volume systems or file |
241 | | // systems, check if the image type is a known unsupported type. |
242 | 0 | int unsupportedSignatureFound = 0; |
243 | 0 | if (a_offset == 0) { |
244 | 0 | char * imageType = detectUnsupportedImageType(a_img_info); |
245 | 0 | if (imageType != NULL) { |
246 | 0 | unsupportedSignatureFound = 1; |
247 | 0 | tsk_error_reset(); |
248 | 0 | tsk_error_set_errno(TSK_ERR_IMG_UNSUPTYPE); |
249 | 0 | tsk_error_set_errstr("%s", imageType); |
250 | 0 | free(imageType); |
251 | 0 | } |
252 | 0 | } |
253 | |
|
254 | 0 | if (!unsupportedSignatureFound) { |
255 | | // Check if the file system appears to be encrypted |
256 | 0 | encryption_detected_result* result = detectVolumeEncryption(a_img_info, a_offset); |
257 | 0 | if (result != NULL) { |
258 | 0 | if (result->encryptionType == ENCRYPTION_DETECTED_SIGNATURE) { |
259 | 0 | tsk_error_set_errno(TSK_ERR_FS_ENCRYPTED); |
260 | 0 | tsk_error_set_errstr("%s", result->desc); |
261 | 0 | } |
262 | 0 | else if (result->encryptionType == ENCRYPTION_DETECTED_ENTROPY) { |
263 | 0 | tsk_error_set_errno(TSK_ERR_FS_POSSIBLY_ENCRYPTED); |
264 | 0 | tsk_error_set_errstr("%s", result->desc); |
265 | 0 | } |
266 | 0 | else { |
267 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNKTYPE); |
268 | 0 | } |
269 | 0 | free(result); |
270 | 0 | result = NULL; |
271 | 0 | } |
272 | 0 | else { |
273 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNKTYPE); |
274 | 0 | } |
275 | 0 | } |
276 | 0 | } |
277 | 0 | return fs_first; |
278 | 0 | } |
279 | 11.5k | else if (TSK_FS_TYPE_ISNTFS(a_ftype)) { |
280 | 2.82k | return ntfs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
281 | 2.82k | } |
282 | 8.72k | else if (TSK_FS_TYPE_ISFAT(a_ftype)) { |
283 | 39 | return fatfs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
284 | 39 | } |
285 | 8.68k | else if (TSK_FS_TYPE_ISFFS(a_ftype)) { |
286 | 0 | return ffs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
287 | 0 | } |
288 | 8.68k | else if (TSK_FS_TYPE_ISEXT(a_ftype)) { |
289 | 3.47k | return ext2fs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
290 | 3.47k | } |
291 | 5.21k | else if (TSK_FS_TYPE_ISHFS(a_ftype)) { |
292 | 3.37k | return hfs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
293 | 3.37k | } |
294 | 1.83k | else if (TSK_FS_TYPE_ISISO9660(a_ftype)) { |
295 | 1.52k | return iso9660_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
296 | 1.52k | } |
297 | 304 | else if (TSK_FS_TYPE_ISRAW(a_ftype)) { |
298 | 0 | return rawfs_open(a_img_info, a_offset); |
299 | 0 | } |
300 | 304 | else if (TSK_FS_TYPE_ISSWAP(a_ftype)) { |
301 | 0 | return swapfs_open(a_img_info, a_offset); |
302 | 0 | } |
303 | 304 | else if (TSK_FS_TYPE_ISYAFFS2(a_ftype)) { |
304 | 0 | return yaffs2_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
305 | 0 | } |
306 | 304 | else if (TSK_FS_TYPE_ISBTRFS(a_ftype)) { |
307 | 302 | return btrfs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
308 | 302 | } |
309 | 2 | else if (TSK_FS_TYPE_ISAPFS(a_ftype)) { |
310 | 2 | return apfs_open(a_img_info, a_offset, a_ftype, a_pass); |
311 | 2 | } |
312 | 0 | else if (TSK_FS_TYPE_ISXFS(a_ftype)) { |
313 | 0 | return xfs_open(a_img_info, a_offset, a_ftype, a_pass, 0); |
314 | 0 | } |
315 | 0 | tsk_error_reset(); |
316 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNSUPTYPE); |
317 | 0 | tsk_error_set_errstr("%X", (int) a_ftype); |
318 | 0 | return NULL; |
319 | 11.5k | } |
320 | | |
321 | | /** |
322 | | * \ingroup fslib |
323 | | * Close an open file system. |
324 | | * @param a_fs File system to close. |
325 | | */ |
326 | | void |
327 | | tsk_fs_close(TSK_FS_INFO * a_fs) |
328 | 9.32k | { |
329 | 9.32k | if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) |
330 | 0 | return; |
331 | | |
332 | | // each file system is supposed to call tsk_fs_free() |
333 | | |
334 | 9.32k | a_fs->close(a_fs); |
335 | 9.32k | } |
336 | | |
337 | | /* tsk_fs_malloc - init lock after tsk_malloc |
338 | | * This is for fs module and all it's inheritances |
339 | | */ |
340 | | TSK_FS_INFO * |
341 | | tsk_fs_malloc(size_t a_len) |
342 | 32.3k | { |
343 | 32.3k | TSK_FS_INFO *fs_info; |
344 | 32.3k | if ((fs_info = (TSK_FS_INFO *) tsk_malloc(a_len)) == NULL) |
345 | 0 | return NULL; |
346 | 32.3k | tsk_init_lock(&fs_info->list_inum_named_lock); |
347 | 32.3k | tsk_init_lock(&fs_info->orphan_dir_lock); |
348 | | |
349 | 32.3k | fs_info->list_inum_named = NULL; |
350 | | |
351 | 32.3k | return fs_info; |
352 | 32.3k | } |
353 | | |
354 | | /* tsk_fs_free - deinit lock before free memory |
355 | | * This is for fs module and all it's inheritances |
356 | | */ |
357 | | void |
358 | | tsk_fs_free(TSK_FS_INFO * a_fs_info) |
359 | 32.3k | { |
360 | 32.3k | if (a_fs_info->list_inum_named) { |
361 | 1.19k | tsk_list_free(a_fs_info->list_inum_named); |
362 | 1.19k | a_fs_info->list_inum_named = NULL; |
363 | 1.19k | } |
364 | | |
365 | | /* Free any encryption structures */ |
366 | 32.3k | freeEncryptionData(a_fs_info); |
367 | | |
368 | | /* we should probably get the lock, but we're |
369 | | * about to kill the entire object so there are |
370 | | * bigger problems if another thread is still |
371 | | * using the fs */ |
372 | 32.3k | if (a_fs_info->orphan_dir) { |
373 | 1.65k | tsk_fs_dir_close(a_fs_info->orphan_dir); |
374 | 1.65k | a_fs_info->orphan_dir = NULL; |
375 | 1.65k | } |
376 | | |
377 | | |
378 | 32.3k | tsk_deinit_lock(&a_fs_info->list_inum_named_lock); |
379 | 32.3k | tsk_deinit_lock(&a_fs_info->orphan_dir_lock); |
380 | | |
381 | 32.3k | free(a_fs_info); |
382 | 32.3k | } |