1 /*
2 ** ntfs
3 ** The Sleuth Kit
4 **
5 ** Content and meta data layer support for the NTFS file system
6 **
7 ** Brian Carrier [carrier <at> sleuthkit [dot] org]
8 ** Copyright (c) 2006-2011 Brian Carrier, Basis Technology. All Rights reserved
9 ** Copyright (c) 2003-2005 Brian Carrier. All rights reserved
10 **
11 ** TASK
12 ** Copyright (c) 2002 Brian Carrier, @stake Inc. All rights reserved
13 **
14 ** This software is distributed under the Common Public License 1.0
15 **
16 ** Unicode added with support from I.D.E.A.L. Technology Corp (Aug '05)
17 **
18 */
19 #include "tsk_fs_i.h"
20 #include "tsk_ntfs.h"
21
22 #include <ctype.h>
23
24 /**
25 * \file ntfs.c
26 * Contains the TSK internal general NTFS processing code
27 */
28 /*
29 * NOTES TO SELF:
30 *
31 * - multiple ".." entries may exist
32 */
33
34 /*
35 * How are we to handle the META flag? Is the MFT $Data Attribute META?
36 */
37
38
39 /* Macro to pass in both the epoch time value and the nano time value */
40 #define WITHNANO(x) x, (unsigned int)x##_nano
41
42
43 /* mini-design note:
44 * The MFT has entries for every file and dir in the fs.
45 * The first entry ($MFT) is for the MFT itself and it is used to find
46 * the location of the entire table because it can become fragmented.
47 * Therefore, the $Data attribute of $MFT is saved in the NTFS_INFO
48 * structure for easy access. We also use the size of the MFT as
49 * a way to calculate the maximum MFT entry number (last_inum).
50 *
51 * Ok, that is simple, but getting the full $Data attribute can be tough
52 * because $MFT may not fit into one MFT entry (i.e. an attribute list).
53 * We need to process the attribute list attribute to find out which
54 * other entries to process. But, the attribute list attribute comes
55 * before any $Data attribute (so it could refer to an MFT that has not
56 * yet been 'defined'). Although, the $Data attribute seems to always
57 * exist and define at least the run for the entry in the attribute list.
58 *
59 * So, the way this is solved is that generic mft_lookup is used to get
60 * any MFT entry, even $MFT. If $MFT is not cached then we calculate
61 * the address of where to read based on multiplication and guessing.
62 * When we are loading the $MFT, we set 'loading_the_MFT' to 1 so
63 * that we can update things as we go along. When we read $MFT we
64 * read all the attributes and save info about the $Data one. If
65 * there is an attribute list, we will have the location of the
66 * additional MFT in the cached $Data location, which will be
67 * updated as we process the attribute list. After each MFT
68 * entry that we process while loading the MFT, the 'final_inum'
69 * value is updated to reflect what we can currently load so
70 * that the sanity checks still work.
71 */
72
73
74 /**********************************************************************
75 *
76 * MISC FUNCS
77 *
78 **********************************************************************/
79
80 /* convert the NT Time (UTC hundred nanoseconds from 1/1/1601)
81 * to UNIX (UTC seconds from 1/1/1970)
82 *
83 * The basic calculation is to remove the nanoseconds and then
84 * subtract the number of seconds between 1601 and 1970
85 * i.e. TIME - DELTA
86 *
87 */
88 uint32_t
nt2unixtime(uint64_t ntdate)89 nt2unixtime(uint64_t ntdate)
90 {
91 // (369*365 + 89) * 24 * 3600 * 10000000
92 #define NSEC_BTWN_1601_1970 (uint64_t)(116444736000000000ULL)
93
94 ntdate -= (uint64_t) NSEC_BTWN_1601_1970;
95 ntdate /= (uint64_t) 10000000;
96
97 return (uint32_t) ntdate;
98 }
99
100 /* convert the NT Time (UTC hundred nanoseconds from 1/1/1601)
101 * to only the nanoseconds
102 *
103 */
104 uint32_t
nt2nano(uint64_t ntdate)105 nt2nano(uint64_t ntdate)
106 {
107 return (uint32_t) (ntdate % 10000000)*100;
108 }
109
110
111 /**********************************************************************
112 *
113 * Lookup Functions
114 *
115 **********************************************************************/
116
117
118
119
120 /**
121 * Read an MFT entry and save it in raw form in the given buffer.
122 * NOTE: This will remove the update sequence integrity checks in the
123 * structure.
124 *
125 * @param a_ntfs File system to read from
126 * @param a_buf Buffer to save raw data to. Must be of size NTFS_INFO.mft_rsize_b
127 * @param a_mftnum Address of MFT entry to read
128 *
129 * @returns Error value
130 */
131 TSK_RETVAL_ENUM
ntfs_dinode_lookup(NTFS_INFO * a_ntfs,char * a_buf,TSK_INUM_T a_mftnum)132 ntfs_dinode_lookup(NTFS_INFO * a_ntfs, char *a_buf, TSK_INUM_T a_mftnum)
133 {
134 TSK_OFF_T mftaddr_b, mftaddr2_b, offset;
135 size_t mftaddr_len = 0;
136 int i;
137 TSK_FS_INFO *fs = (TSK_FS_INFO *) & a_ntfs->fs_info;
138 TSK_FS_ATTR_RUN *data_run;
139 ntfs_upd *upd;
140 uint16_t sig_seq;
141 ntfs_mft *mft;
142
143
144 /* sanity checks */
145 if (!a_buf) {
146 tsk_error_reset();
147 tsk_error_set_errno(TSK_ERR_FS_ARG);
148 tsk_error_set_errstr("mft_lookup: null mft buffer");
149 return TSK_ERR;
150 }
151
152 if (a_mftnum < fs->first_inum) {
153 tsk_error_reset();
154 tsk_error_set_errno(TSK_ERR_FS_ARG);
155 tsk_error_set_errstr("mft_lookup: inode number is too small (%"
156 PRIuINUM ")", a_mftnum);
157 return TSK_ERR;
158 }
159
160 /* Because this code reads teh actual MFT, we need to make sure we
161 * decrement the last_inum because the last value is a special value
162 * for the ORPHANS directory */
163 if (a_mftnum > fs->last_inum - 1) {
164 tsk_error_reset();
165 tsk_error_set_errno(TSK_ERR_FS_ARG);
166 tsk_error_set_errstr("mft_lookup: inode number is too large (%"
167 PRIuINUM ")", a_mftnum);
168 return TSK_ERR;
169 }
170
171
172 if (tsk_verbose)
173 tsk_fprintf(stderr,
174 "ntfs_dinode_lookup: Processing MFT %" PRIuINUM "\n",
175 a_mftnum);
176
177 /* If mft_data (the cached $Data attribute of $MFT) is not there yet,
178 * then we have not started to load $MFT yet. In that case, we will
179 * 'cheat' and calculate where it goes. This should only be for
180 * $MFT itself, in which case the calculation is easy
181 */
182 if (!a_ntfs->mft_data) {
183
184 /* This is just a random check with the assumption being that
185 * we don't want to just do a guess calculation for a very large
186 * MFT entry
187 */
188 if (a_mftnum > NTFS_LAST_DEFAULT_INO) {
189 tsk_error_reset();
190 tsk_error_set_errno(TSK_ERR_FS_ARG);
191 tsk_error_set_errstr
192 ("Error trying to load a high MFT entry when the MFT itself has not been loaded (%"
193 PRIuINUM ")", a_mftnum);
194 return TSK_ERR;
195 }
196
197 mftaddr_b = a_ntfs->root_mft_addr + a_mftnum * a_ntfs->mft_rsize_b;
198 mftaddr2_b = 0;
199 }
200 else {
201 /* The MFT may not be in consecutive clusters, so we need to use its
202 * data attribute run list to find out what address to read
203 *
204 * This is why we cached it
205 */
206
207 // will be set to the address of the MFT entry
208 mftaddr_b = mftaddr2_b = 0;
209
210 /* The byte offset within the $Data stream */
211 offset = a_mftnum * a_ntfs->mft_rsize_b;
212
213 /* NOTE: data_run values are in clusters
214 *
215 * cycle through the runs in $Data and identify which
216 * has the MFT entry that we want
217 */
218 for (data_run = a_ntfs->mft_data->nrd.run;
219 data_run != NULL; data_run = data_run->next) {
220
221 /* Test for possible overflows / error conditions */
222 if ((offset < 0) || (data_run->len >= (TSK_DADDR_T)(LLONG_MAX / a_ntfs->csize_b))){
223 tsk_error_reset();
224 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
225 tsk_error_set_errstr
226 ("ntfs_dinode_lookup: Overflow when calculating run length");
227 return TSK_COR;
228 }
229
230 /* The length of this specific run */
231 TSK_OFF_T run_len = data_run->len * a_ntfs->csize_b;
232
233 /* Is our MFT entry is in this run somewhere ? */
234 if (offset < run_len) {
235
236 if (tsk_verbose)
237 tsk_fprintf(stderr,
238 "ntfs_dinode_lookup: Found in offset: %"
239 PRIuDADDR " size: %" PRIuDADDR " at offset: %"
240 PRIdOFF "\n", data_run->addr, data_run->len,
241 offset);
242
243 /* special case where the MFT entry crosses
244 * a run (only happens when cluster size is 512-bytes
245 * and there are an odd number of clusters in the run)
246 */
247 if (run_len < offset + a_ntfs->mft_rsize_b) {
248
249 if (tsk_verbose)
250 tsk_fprintf(stderr,
251 "ntfs_dinode_lookup: Entry crosses run border\n");
252
253 if (data_run->next == NULL) {
254 tsk_error_reset();
255 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
256 tsk_error_set_errstr
257 ("mft_lookup: MFT entry crosses a cluster and there are no more clusters!");
258 return TSK_COR;
259 }
260
261 /* Assign address where the remainder of the entry is */
262 mftaddr2_b = data_run->next->addr * a_ntfs->csize_b;
263 /* this should always be 512, but just in case */
264 mftaddr_len = (size_t) (run_len - offset);
265 }
266
267 /* Assign address of where the MFT entry starts */
268 mftaddr_b = data_run->addr * a_ntfs->csize_b + offset;
269 if (tsk_verbose)
270 tsk_fprintf(stderr,
271 "ntfs_dinode_lookup: Entry address at: %"
272 PRIdOFF "\n", mftaddr_b);
273 break;
274 }
275
276 /* decrement the offset we are looking for */
277 offset -= run_len;
278 }
279
280 /* Did we find it? */
281 if (!mftaddr_b) {
282 tsk_error_reset();
283 tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
284 tsk_error_set_errstr("mft_lookup: Error finding MFT entry %"
285 PRIuINUM " in $MFT", a_mftnum);
286 return TSK_ERR;
287 }
288 }
289
290
291 /* can we do just one read or do we need multiple? */
292 if (mftaddr2_b) {
293 ssize_t cnt;
294 /* read the first part into mft */
295 cnt = tsk_fs_read(&a_ntfs->fs_info, mftaddr_b, a_buf, mftaddr_len);
296 if (cnt != (ssize_t)mftaddr_len) {
297 if (cnt >= 0) {
298 tsk_error_reset();
299 tsk_error_set_errno(TSK_ERR_FS_READ);
300 }
301 tsk_error_set_errstr2
302 ("ntfs_dinode_lookup: Error reading MFT Entry (part 1) at %"
303 PRIdOFF, mftaddr_b);
304 return TSK_ERR;
305 }
306
307 /* read the second part into mft */
308 cnt = tsk_fs_read
309 (&a_ntfs->fs_info, mftaddr2_b,
310 (char *) ((uintptr_t) a_buf + (uintptr_t) mftaddr_len),
311 a_ntfs->mft_rsize_b - mftaddr_len);
312 if (cnt != (ssize_t)(a_ntfs->mft_rsize_b - mftaddr_len)) {
313 if (cnt >= 0) {
314 tsk_error_reset();
315 tsk_error_set_errno(TSK_ERR_FS_READ);
316 }
317 tsk_error_set_errstr2
318 ("ntfs_dinode_lookup: Error reading MFT Entry (part 2) at %"
319 PRIdOFF, mftaddr2_b);
320 return TSK_ERR;
321 }
322 }
323 else {
324 ssize_t cnt;
325 /* read the raw entry into mft */
326 cnt =
327 tsk_fs_read(&a_ntfs->fs_info, mftaddr_b, a_buf,
328 a_ntfs->mft_rsize_b);
329 if (cnt != a_ntfs->mft_rsize_b) {
330 if (cnt >= 0) {
331 tsk_error_reset();
332 tsk_error_set_errno(TSK_ERR_FS_READ);
333 }
334 tsk_error_set_errstr2
335 ("ntfs_dinode_lookup: Error reading MFT Entry at %"
336 PRIdOFF, mftaddr_b);
337 return TSK_ERR;
338 }
339 }
340
341 /* Sanity Check */
342 #if 0
343 /* This is no longer applied because it caused too many problems
344 * with images that had 0 and 1 etc. as values. Testing shows that
345 * even Windows XP doesn't care if entries have an invalid entry, so
346 * this is no longer checked. The update sequence check should find
347 * corrupt entries
348 * */
349 if ((tsk_getu32(fs->endian, mft->magic) != NTFS_MFT_MAGIC)
350 && (tsk_getu32(fs->endian, mft->magic) != NTFS_MFT_MAGIC_BAAD)
351 && (tsk_getu32(fs->endian, mft->magic) != NTFS_MFT_MAGIC_ZERO)) {
352 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
353 tsk_error_set_errstr("entry %d has an invalid MFT magic: %x",
354 mftnum, tsk_getu32(fs->endian, mft->magic));
355 return 1;
356 }
357 #endif
358 /* The MFT entries have error and integrity checks in them
359 * called update sequences. They must be checked and removed
360 * so that later functions can process the data as normal.
361 * They are located in the last 2 bytes of each 512-bytes of data.
362 *
363 * We first verify that the the 2-byte value is a give value and
364 * then replace it with what should be there
365 */
366 /* sanity check so we don't run over in the next loop */
367 mft = (ntfs_mft *) a_buf;
368 if ((tsk_getu16(fs->endian, mft->upd_cnt) > 0) &&
369 (((uint32_t) (tsk_getu16(fs->endian,
370 mft->upd_cnt) - 1) * NTFS_UPDATE_SEQ_STRIDE) >
371 a_ntfs->mft_rsize_b)) {
372 tsk_error_reset();
373 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
374 tsk_error_set_errstr
375 ("dinode_lookup: More Update Sequence Entries than MFT size");
376 return TSK_COR;
377 }
378 if (tsk_getu16(fs->endian, mft->upd_off) + sizeof(ntfs_upd) > a_ntfs->mft_rsize_b) {
379 tsk_error_reset();
380 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
381 tsk_error_set_errstr
382 ("dinode_lookup: Update sequence would read past MFT size");
383 return TSK_COR;
384 }
385
386 /* Apply the update sequence structure template */
387 upd =
388 (ntfs_upd *) ((uintptr_t) a_buf + tsk_getu16(fs->endian,
389 mft->upd_off));
390 /* Get the sequence value that each 16-bit value should be */
391 sig_seq = tsk_getu16(fs->endian, upd->upd_val);
392 /* cycle through each sector */
393 for (i = 1; i < tsk_getu16(fs->endian, mft->upd_cnt); i++) {
394 uint8_t *new_val, *old_val;
395 /* The offset into the buffer of the value to analyze */
396 size_t offset = i * NTFS_UPDATE_SEQ_STRIDE - 2;
397
398 /* Check that there is room in the buffer to read the current sequence value */
399 if (offset + 2 > a_ntfs->mft_rsize_b) {
400 tsk_error_reset();
401 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
402 tsk_error_set_errstr
403 ("dinode_lookup: Ran out of data while parsing update sequence values");
404 return TSK_COR;
405 }
406
407 /* get the current sequence value */
408 uint16_t cur_seq =
409 tsk_getu16(fs->endian, (uintptr_t) a_buf + offset);
410 if (cur_seq != sig_seq) {
411 /* get the replacement value */
412 uint16_t cur_repl =
413 tsk_getu16(fs->endian, &upd->upd_seq + (i - 1) * 2);
414 tsk_error_reset();
415 tsk_error_set_errno(TSK_ERR_FS_GENFS);
416
417 tsk_error_set_errstr
418 ("Incorrect update sequence value in MFT entry\nSignature Value: 0x%"
419 PRIx16 " Actual Value: 0x%" PRIx16
420 " Replacement Value: 0x%" PRIx16
421 "\nThis is typically because of a corrupted entry",
422 sig_seq, cur_seq, cur_repl);
423 return TSK_COR;
424 }
425
426 new_val = &upd->upd_seq + (i - 1) * 2;
427 old_val = (uint8_t *) ((uintptr_t) a_buf + offset);
428 /*
429 if (tsk_verbose)
430 tsk_fprintf(stderr,
431 "ntfs_dinode_lookup: upd_seq %i Replacing: %.4"
432 PRIx16 " With: %.4" PRIx16 "\n", i,
433 tsk_getu16(fs->endian, old_val), tsk_getu16(fs->endian,
434 new_val));
435 */
436 *old_val++ = *new_val++;
437 *old_val = *new_val;
438 }
439
440 return TSK_OK;
441 }
442
443
444
445 /*
446 * given a cluster, return the allocation status or
447 * -1 if an error occurs
448 */
449 static int
is_clustalloc(NTFS_INFO * ntfs,TSK_DADDR_T addr)450 is_clustalloc(NTFS_INFO * ntfs, TSK_DADDR_T addr)
451 {
452 int bits_p_clust, b;
453 TSK_DADDR_T base;
454 int8_t ret;
455 bits_p_clust = 8 * ntfs->fs_info.block_size;
456
457 /* While we are loading the MFT, assume that everything
458 * is allocated. This should only be needed when we are
459 * dealing with an attribute list ...
460 */
461 if (ntfs->loading_the_MFT == 1) {
462 return 1;
463 }
464 else if (ntfs->bmap == NULL) {
465 tsk_error_reset();
466 tsk_error_set_errno(TSK_ERR_FS_ARG);
467
468 tsk_error_set_errstr("is_clustalloc: Bitmap pointer is null: %"
469 PRIuDADDR "\n", addr);
470 return -1;
471 }
472
473 /* Is the cluster too big? */
474 if (addr > ntfs->fs_info.last_block) {
475 tsk_error_reset();
476 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
477 tsk_error_set_errstr("is_clustalloc: cluster too large");
478 return -1;
479 }
480
481 /* identify the base cluster in the bitmap file */
482 base = addr / bits_p_clust;
483 b = (int) (addr % bits_p_clust);
484
485 tsk_take_lock(&ntfs->lock);
486
487 /* is this the same as in the cached buffer? */
488 if (base != ntfs->bmap_buf_off) {
489 TSK_DADDR_T c = base;
490 TSK_FS_ATTR_RUN *run;
491 TSK_DADDR_T fsaddr = 0;
492 ssize_t cnt;
493
494 /* get the file system address of the bitmap cluster */
495 for (run = ntfs->bmap; run; run = run->next) {
496 if (run->len <= c) {
497 c -= run->len;
498 }
499 else {
500 fsaddr = run->addr + c;
501 break;
502 }
503 }
504
505 if (fsaddr == 0) {
506 tsk_release_lock(&ntfs->lock);
507 tsk_error_reset();
508 tsk_error_set_errno(TSK_ERR_FS_BLK_NUM);
509 tsk_error_set_errstr
510 ("is_clustalloc: cluster not found in bitmap: %" PRIuDADDR
511 "", c);
512 return -1;
513 }
514 if (fsaddr > ntfs->fs_info.last_block) {
515 tsk_release_lock(&ntfs->lock);
516 tsk_error_reset();
517 tsk_error_set_errno(TSK_ERR_FS_BLK_NUM);
518 tsk_error_set_errstr
519 ("is_clustalloc: Cluster in bitmap too large for image: %"
520 PRIuDADDR, fsaddr);
521 return -1;
522 }
523 ntfs->bmap_buf_off = base;
524 cnt = tsk_fs_read_block
525 (&ntfs->fs_info, fsaddr, ntfs->bmap_buf,
526 ntfs->fs_info.block_size);
527 if (cnt != ntfs->fs_info.block_size) {
528 tsk_release_lock(&ntfs->lock);
529 if (cnt >= 0) {
530 tsk_error_reset();
531 tsk_error_set_errno(TSK_ERR_FS_READ);
532 }
533 tsk_error_set_errstr2
534 ("is_clustalloc: Error reading bitmap at %" PRIuDADDR,
535 fsaddr);
536 return -1;
537 }
538 }
539
540 /* identify if the cluster is allocated or not */
541 ret = (isset(ntfs->bmap_buf, b)) ? 1 : 0;
542
543 tsk_release_lock(&ntfs->lock);
544 return ret;
545 }
546
547
548
549 /**********************************************************************
550 *
551 * TSK_FS_ATTR functions
552 *
553 **********************************************************************/
554
555
556 /**
557 * Process a non-resident runlist and convert its contents into the generic fs_attr_run
558 * structure.
559 * @param ntfs File system that attribute is located in.
560 * @param start_vcn The starting VCN for this run.
561 * @param runlist The raw runlist data from the MFT entry.
562 * @param a_data_run_head [out] Pointer to pointer of run that is created. (NULL on error and for $BadClust - special case because it is a sparse file for the entire FS).
563 * @param totlen [out] Pointer to location where total length of run (in bytes) can be returned (or NULL)
564 * @param mnum MFT entry address
565 *
566 * @returns Return status of error, corrupt, or OK (note a_data_run can be NULL even when OK is returned if $BadClust is encountered)
567 */
568 static TSK_RETVAL_ENUM
ntfs_make_data_run(NTFS_INFO * ntfs,TSK_OFF_T start_vcn,ntfs_runlist * runlist_head,TSK_FS_ATTR_RUN ** a_data_run_head,TSK_OFF_T * totlen,TSK_INUM_T mnum)569 ntfs_make_data_run(NTFS_INFO * ntfs, TSK_OFF_T start_vcn,
570 ntfs_runlist * runlist_head, TSK_FS_ATTR_RUN ** a_data_run_head,
571 TSK_OFF_T * totlen, TSK_INUM_T mnum)
572 {
573 TSK_FS_INFO *fs = (TSK_FS_INFO *) ntfs;
574 ntfs_runlist *run;
575 TSK_FS_ATTR_RUN *data_run, *data_run_prev = NULL;
576 unsigned int i, idx;
577 TSK_DADDR_T prev_addr = 0;
578 TSK_OFF_T file_offset = start_vcn;
579
580 run = runlist_head;
581 *a_data_run_head = NULL;
582
583 /* initialize if non-NULL */
584 if (totlen)
585 *totlen = 0;
586
587 /* Cycle through each run in the runlist
588 * We go until we find an entry with no length
589 * An entry with offset of 0 is for a sparse run
590 */
591 while (NTFS_RUNL_LENSZ(run) != 0) {
592 int64_t addr_offset = 0;
593
594 /* allocate a new tsk_fs_attr_run */
595 if ((data_run = tsk_fs_attr_run_alloc()) == NULL) {
596 tsk_fs_attr_run_free(*a_data_run_head);
597 *a_data_run_head = NULL;
598 return TSK_ERR;
599 }
600
601 /* make the list, unless its the first pass & then we set the head */
602 if (data_run_prev)
603 data_run_prev->next = data_run;
604 else
605 *a_data_run_head = data_run;
606 data_run_prev = data_run;
607
608 /* These fields are a variable number of bytes long
609 * these for loops are the equivalent of the getuX macros
610 */
611 idx = 0;
612
613 /* Get the length of this run.
614 * A length of more than eight bytes will not fit in the
615 * 64-bit length field (and is likely corrupt)
616 */
617 if (NTFS_RUNL_LENSZ(run) > 8) {
618 tsk_error_reset();
619 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
620 tsk_error_set_errstr
621 ("ntfs_make_run: Run length is too large to process");
622 tsk_fs_attr_run_free(*a_data_run_head);
623 *a_data_run_head = NULL;
624 return TSK_COR;
625 }
626 for (i = 0, data_run->len = 0; i < NTFS_RUNL_LENSZ(run); i++) {
627 data_run->len |= ((uint64_t)(run->buf[idx++]) << (i * 8));
628 if (tsk_verbose)
629 tsk_fprintf(stderr,
630 "ntfs_make_data_run: Len idx: %i cur: %"
631 PRIu8 " (%" PRIx8 ") tot: %" PRIuDADDR
632 " (%" PRIxDADDR ")\n", i,
633 run->buf[idx - 1], run->buf[idx - 1],
634 data_run->len, data_run->len);
635 }
636
637 /* Sanity check on length */
638 if (data_run->len > fs->block_count) {
639 tsk_error_reset();
640 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
641 tsk_error_set_errstr
642 ("ntfs_make_run: Run length is larger than file system");
643 tsk_fs_attr_run_free(*a_data_run_head);
644 *a_data_run_head = NULL;
645 return TSK_COR;
646 }
647
648 data_run->offset = file_offset;
649 file_offset += data_run->len;
650
651 /* Update the length if we were passed a value */
652 if (totlen)
653 *totlen += (data_run->len * ntfs->csize_b);
654
655 /* Get the address of this run */
656 for (i = 0, data_run->addr = 0; i < NTFS_RUNL_OFFSZ(run); i++) {
657 //data_run->addr |= (run->buf[idx++] << (i * 8));
658 addr_offset |= (run->buf[idx++] << (i * 8));
659 if (tsk_verbose)
660 tsk_fprintf(stderr,
661 "ntfs_make_data_run: Off idx: %i cur: %"
662 PRIu8 " (%" PRIx8 ") tot: %" PRIuDADDR
663 " (%" PRIxDADDR ")\n", i,
664 run->buf[idx - 1], run->buf[idx - 1], addr_offset,
665 addr_offset);
666 }
667
668 /* addr_offset value is signed so extend it to 64-bits */
669 if ((int8_t) run->buf[idx - 1] < 0) {
670 for (; i < sizeof(addr_offset); i++)
671 addr_offset |= (int64_t) ((int64_t) 0xff << (i * 8));
672 }
673
674 if (tsk_verbose)
675 tsk_fprintf(stderr,
676 "ntfs_make_data_run: Signed addr_offset: %"
677 PRId64 " Previous address: %"
678 PRIuDADDR "\n", addr_offset, prev_addr);
679
680 /* The NT 4.0 version of NTFS uses an offset of -1 to represent
681 * a hole, so add the sparse flag and make it look like the 2K
682 * version with a offset of 0
683 *
684 * A user reported an issue where the $Bad file started with
685 * its offset as -1 and it was not NT (maybe a conversion)
686 * Change the check now to not limit to NT, but make sure
687 * that it is the first run
688 */
689 if (((addr_offset == -1) && (prev_addr == 0))
690 || ((addr_offset == -1)
691 && (ntfs->ver == NTFS_VINFO_NT))) {
692 data_run->flags |= TSK_FS_ATTR_RUN_FLAG_SPARSE;
693 data_run->addr = 0;
694 if (tsk_verbose)
695 tsk_fprintf(stderr, "ntfs_make_data_run: Sparse Run\n");
696 }
697
698 /* A Sparse file has a run with an offset of 0
699 * there is a special case though of the BOOT MFT entry which
700 * is the super block and has a legit offset of 0.
701 *
702 * The value given is a delta of the previous offset, so add
703 * them for non-sparse files
704 *
705 * For sparse files the next run will have its offset relative
706 * to the current "prev_addr" so skip that code
707 */
708 // @@@ BC: we'll need to pass in an inode value for this check
709 else if ((addr_offset) || (mnum == NTFS_MFT_BOOT)) {
710
711 data_run->addr = prev_addr + addr_offset;
712 prev_addr = data_run->addr;
713
714 /* Sanity check on length and offset */
715 if (data_run->addr + data_run->len > fs->block_count) {
716 tsk_error_reset();
717 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
718 tsk_error_set_errstr
719 ("ntfs_make_run: Run offset and length is larger than file system");
720 tsk_fs_attr_run_free(*a_data_run_head);
721 *a_data_run_head = NULL;
722 return TSK_COR;
723 }
724
725 }
726 else {
727 data_run->flags |= TSK_FS_ATTR_RUN_FLAG_SPARSE;
728 if (tsk_verbose)
729 tsk_fprintf(stderr, "ntfs_make_data_run: Sparse Run\n");
730 }
731
732 /* Advance run */
733 run = (ntfs_runlist *) ((uintptr_t) run + (1 + NTFS_RUNL_LENSZ(run)
734 + NTFS_RUNL_OFFSZ(run)));
735 }
736
737 /* special case for $BADCLUST, which is a sparse file whose size is
738 * the entire file system.
739 *
740 * If there is only one run entry and it is sparse, then there are no
741 * bad blocks, so get rid of it.
742 */
743 if ((*a_data_run_head != NULL)
744 && ((*a_data_run_head)->next == NULL)
745 && ((*a_data_run_head)->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE)
746 && ((*a_data_run_head)->len == fs->last_block + 1)) {
747 tsk_fs_attr_run_free(*a_data_run_head);
748 *a_data_run_head = NULL;
749 }
750
751 return TSK_OK;
752 }
753
754
755
756 /*********** UNCOMPRESSION CODE *************/
757
758
759 /*
760 * NTFS Breaks compressed data into compression units, which are
761 * typically 16 clusters in size. If the data in the comp unit
762 * compresses to something smaller than 16 clusters then the
763 * compressed data is stored and the rest of the compression unit
764 * is filled with sparse clusters. The entire compression unit
765 * can also be sparse.
766 *
767 * The uncompressed content in the compression unit is further broken
768 * into 4k (pre-compression) blocks. When stored, each 4k block has
769 * a 2-byte header that identifies the compressed size (and if there
770 * was compression).
771 *
772 * The compressed data is a series of token groups. Each token group
773 * contains a 1-byte header and 8 tokens. The 8-bits in the token
774 * group header identify the type of each token in the group.
775 *
776 * There are two types of tokens.
777 * Symbol tokens are 1 byte in length and the 1-byte value is the value
778 * for that position in the file and it should be direcly copied into the
779 * uncompressed data. Phrase tokens identify a previous run of data
780 * in the same compression unit that should be
781 * copied to the current location. These contain offset and length info.
782 *
783 * The attribute will have enough cluster addresses to store all of
784 * the content, but the addresses will be 0 in the compression unit
785 * if it is all sparse and the ending clusters will be 0 in the
786 * compression unit if they are not needed.
787 *
788 */
789
790 /* Variables used for ntfs_uncompress() method */
791 typedef struct {
792 char *uncomp_buf; // Buffer for uncompressed data
793 char *comp_buf; // buffer for compressed data
794 size_t comp_len; // number of bytes used in compressed data
795 size_t uncomp_idx; // Index into buffer for next byte
796 size_t buf_size_b; // size of buffer in bytes (1 compression unit)
797 } NTFS_COMP_INFO;
798
799
800 /**
801 * Reset the values in the NTFS_COMP_INFO structure. We need to
802 * do this in between every compression unit that we process in the file.
803 *
804 * @param comp Structure to reset
805 */
806 static void
ntfs_uncompress_reset(NTFS_COMP_INFO * comp)807 ntfs_uncompress_reset(NTFS_COMP_INFO * comp)
808 {
809 memset(comp->uncomp_buf, 0, comp->buf_size_b);
810 comp->uncomp_idx = 0;
811 memset(comp->comp_buf, 0, comp->buf_size_b);
812 comp->comp_len = 0;
813 }
814
815 /**
816 * Setup the NTFS_COMP_INFO structure with a buffer and
817 * initialize the basic settings.
818 *
819 * @param fs File system state information
820 * @param comp Compression state information to initialize
821 * @param compunit_size_c The size (in clusters) of a compression
822 * unit
823 * @return 1 on error and 0 on success
824 */
825 static int
ntfs_uncompress_setup(TSK_FS_INFO * fs,NTFS_COMP_INFO * comp,uint32_t compunit_size_c)826 ntfs_uncompress_setup(TSK_FS_INFO * fs, NTFS_COMP_INFO * comp,
827 uint32_t compunit_size_c)
828 {
829 comp->buf_size_b = fs->block_size * compunit_size_c;
830 if ((comp->uncomp_buf = tsk_malloc(comp->buf_size_b)) == NULL) {
831 comp->buf_size_b = 0;
832 return 1;
833 }
834 if ((comp->comp_buf = tsk_malloc(comp->buf_size_b)) == NULL) {
835 free(comp->uncomp_buf);
836 comp->uncomp_buf = NULL;
837 comp->buf_size_b = 0;
838 return 1;
839 }
840
841 ntfs_uncompress_reset(comp);
842
843 return 0;
844 }
845
846 static void
ntfs_uncompress_done(NTFS_COMP_INFO * comp)847 ntfs_uncompress_done(NTFS_COMP_INFO * comp)
848 {
849 free(comp->uncomp_buf);
850 comp->uncomp_buf = NULL;
851 free(comp->comp_buf);
852 comp->comp_buf = NULL;
853 comp->buf_size_b = 0;
854 }
855
856
857 /**
858 * Uncompress the block of data in comp->comp_buf,
859 * which has a size of comp->comp_len.
860 * Store the result in the comp->uncomp_buf.
861 *
862 * @param comp Compression unit structure
863 *
864 * @returns 1 on error and 0 on success
865 */
866 static uint8_t
ntfs_uncompress_compunit(NTFS_COMP_INFO * comp)867 ntfs_uncompress_compunit(NTFS_COMP_INFO * comp)
868 {
869 size_t cl_index;
870
871 tsk_error_reset();
872
873 comp->uncomp_idx = 0;
874
875 /* Cycle through the compressed data
876 * We maintain state using different levels of loops.
877 * We use +1 here because the size value at start of block is 2 bytes.
878 */
879 for (cl_index = 0; cl_index + 1 < comp->comp_len;) {
880 size_t blk_end; // index into the buffer to where block ends
881 size_t blk_size; // size of the current block
882 uint8_t iscomp; // set to 1 if block is compressed
883 size_t blk_st_uncomp; // index into uncompressed buffer where block started
884 uint16_t sb_header; // subblock header
885
886 sb_header = tsk_getu16(TSK_LIT_ENDIAN, comp->comp_buf + cl_index);
887
888 // If the sb_header isn't set, we just fill the rest of the buffer with zeros.
889 // This seems to be what several different NTFS implementations do.
890 if (sb_header == 0) {
891 memset(comp->uncomp_buf + comp->uncomp_idx, 0, comp->buf_size_b - comp->uncomp_idx);
892 comp->uncomp_idx = comp->buf_size_b;
893 break;
894 }
895
896 blk_size = (sb_header & 0x0FFF) + 3;
897
898 // this seems to indicate end of block
899 if (blk_size == 3)
900 break;
901
902 blk_end = cl_index + blk_size;
903 if (blk_end > comp->comp_len) {
904 tsk_error_set_errno(TSK_ERR_FS_FWALK);
905 tsk_error_set_errstr
906 ("ntfs_uncompress_compunit: Block length longer than buffer length: %"
907 PRIuSIZE "", blk_end);
908 return 1;
909 }
910
911 if (tsk_verbose)
912 tsk_fprintf(stderr,
913 "ntfs_uncompress_compunit: Block size is %" PRIuSIZE "\n",
914 blk_size);
915
916 /* The MSB identifies if the block is compressed */
917 iscomp = ((sb_header & 0x8000) != 0);
918
919 // keep track of where this block started in the buffer
920 blk_st_uncomp = comp->uncomp_idx;
921 cl_index += 2;
922
923 // the 4096 size seems to occur at the same times as no compression
924 if ((iscomp) && (blk_size - 2 != 4096)) {
925
926 // cycle through the block
927 while (cl_index < blk_end) {
928 int a;
929
930 // get the header header
931 unsigned char header = comp->comp_buf[cl_index];
932 cl_index++;
933
934 if (tsk_verbose)
935 tsk_fprintf(stderr,
936 "ntfs_uncompress_compunit: New Tag: %x\n", header);
937
938 for (a = 0; a < 8 && cl_index < blk_end; a++) {
939
940 /* Determine token type and parse appropriately. *
941 * Symbol tokens are the symbol themselves, so copy it
942 * into the uncompressed buffer
943 */
944 if ((header & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) {
945 if (tsk_verbose)
946 tsk_fprintf(stderr,
947 "ntfs_uncompress_compunit: Symbol Token: %"
948 PRIuSIZE "\n", cl_index);
949
950 if (comp->uncomp_idx >= comp->buf_size_b) {
951 tsk_error_set_errno(TSK_ERR_FS_FWALK);
952 tsk_error_set_errstr
953 ("ntfs_uncompress_compunit: Trying to write past end of uncompression buffer: %"
954 PRIuSIZE "", comp->uncomp_idx);
955 return 1;
956 }
957 comp->uncomp_buf[comp->uncomp_idx++] =
958 comp->comp_buf[cl_index];
959
960 cl_index++;
961 }
962
963 /* Otherwise, it is a phrase token, which points back
964 * to a previous sequence of bytes.
965 */
966 else {
967 size_t i;
968 int shift;
969 size_t start_position_index = 0;
970 size_t end_position_index = 0;
971 unsigned int offset = 0;
972 unsigned int length = 0;
973 uint16_t pheader;
974
975 if (cl_index + 1 >= blk_end) {
976 tsk_error_set_errno(TSK_ERR_FS_FWALK);
977 tsk_error_set_errstr
978 ("ntfs_uncompress_compunit: Phrase token index is past end of block: %d",
979 a);
980 return 1;
981 }
982
983 pheader =
984 ((((comp->comp_buf[cl_index +
985 1]) << 8) & 0xFF00) |
986 (comp->comp_buf[cl_index] & 0xFF));
987 cl_index += 2;
988
989
990 /* The number of bits for the start and length
991 * in the 2-byte header change depending on the
992 * location in the compression unit. This identifies
993 * how many bits each has */
994 shift = 0;
995 for (i =
996 comp->uncomp_idx -
997 blk_st_uncomp - 1; i >= 0x10; i >>= 1) {
998 shift++;
999 }
1000 if (shift > 12) {
1001 tsk_error_reset();
1002 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1003 tsk_error_set_errstr
1004 ("ntfs_uncompress_compunit: Shift is too large: %d", shift);
1005 return 1;
1006 }
1007
1008 //tsk_fprintf(stderr, "Start: %X Shift: %d UnComp_IDX %d BlkStart: %lu BlkIdx: %d BlkSize: %d\n", (int)(comp->uncomp_idx - comp->blk_st - 1), shift, comp->uncomp_idx, comp->blk_st, comp->blk_idx, comp->blk_size);
1009
1010 offset = (pheader >> (12 - shift)) + 1;
1011 length = (pheader & (0xFFF >> shift)) + 2;
1012
1013 start_position_index = comp->uncomp_idx - offset;
1014 end_position_index = start_position_index + length;
1015
1016 if (tsk_verbose)
1017 tsk_fprintf(stderr,
1018 "ntfs_uncompress_compunit: Phrase Token: %"
1019 PRIuSIZE "\t%d\t%d\t%x\n", cl_index,
1020 length, offset, pheader);
1021
1022 /* Sanity checks on values */
1023 if (offset > comp->uncomp_idx) {
1024 tsk_error_reset();
1025 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1026 tsk_error_set_errstr
1027 ("ntfs_uncompress_compunit: Phrase token offset is too large: %d (max: %"
1028 PRIuSIZE ")", offset, comp->uncomp_idx);
1029 return 1;
1030 }
1031 else if (length + start_position_index >
1032 comp->buf_size_b) {
1033 tsk_error_reset();
1034 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1035 tsk_error_set_errstr
1036 ("ntfs_uncompress_compunit: Phrase token length is too large: %d (max: %" PRIuSIZE")",
1037 length,
1038 comp->buf_size_b - start_position_index);
1039 return 1;
1040 }
1041 else if (end_position_index -
1042 start_position_index + 1 >
1043 comp->buf_size_b - comp->uncomp_idx) {
1044 tsk_error_reset();
1045 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1046 tsk_error_set_errstr
1047 ("ntfs_uncompress_compunit: Phrase token length is too large for rest of uncomp buf: %" PRIuSIZE" (max: %"
1048 PRIuSIZE ")",
1049 end_position_index - start_position_index +
1050 1, comp->buf_size_b - comp->uncomp_idx);
1051 return 1;
1052 }
1053
1054 for (;
1055 start_position_index <= end_position_index
1056 && comp->uncomp_idx < comp->buf_size_b;
1057 start_position_index++) {
1058
1059 // Copy the previous data to the current position
1060 comp->uncomp_buf[comp->uncomp_idx++]
1061 = comp->uncomp_buf[start_position_index];
1062 }
1063 }
1064 header >>= 1;
1065 } // end of loop inside of token group
1066
1067 } // end of loop inside of block
1068 }
1069
1070 // this block contains uncompressed data
1071 else {
1072 while (cl_index < blk_end && cl_index < comp->comp_len) {
1073 /* This seems to happen only with corrupt data -- such as
1074 * when an unallocated file is being processed... */
1075 if (comp->uncomp_idx >= comp->buf_size_b) {
1076 tsk_error_reset();
1077 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1078 tsk_error_set_errstr
1079 ("ntfs_uncompress_compunit: Trying to write past end of uncompression buffer (1) -- corrupt data?)");
1080 return 1;
1081 }
1082
1083 // Place data in uncompression_buffer
1084 comp->uncomp_buf[comp->uncomp_idx++] =
1085 comp->comp_buf[cl_index++];
1086 }
1087 }
1088 } // end of loop inside of compression unit
1089
1090 return 0;
1091 }
1092
1093
1094
1095 /**
1096 * Process a compression unit and return the decompressed data in a buffer in comp.
1097 *
1098 * @param ntfs File system
1099 * @param comp Compression state info (output will be stored in here)
1100 * @param comp_unit List of addresses that store compressed data
1101 * @param comp_unit_size Number of addresses in comp_unit
1102 * @returns 1 on error and 0 on success
1103 */
1104 static uint8_t
ntfs_proc_compunit(NTFS_INFO * ntfs,NTFS_COMP_INFO * comp,TSK_DADDR_T * comp_unit,uint32_t comp_unit_size)1105 ntfs_proc_compunit(NTFS_INFO * ntfs, NTFS_COMP_INFO * comp,
1106 TSK_DADDR_T * comp_unit, uint32_t comp_unit_size)
1107 {
1108 TSK_FS_INFO *fs = (TSK_FS_INFO *) ntfs;
1109 int sparse;
1110 uint64_t a;
1111
1112 /* With compressed attributes, there are three scenarios.
1113 * 1: The compression unit is not compressed,
1114 * 2: The compression unit is sparse
1115 * 3: The compression unit is compressed
1116 */
1117
1118 /* Check if the entire compression unit is sparse */
1119 sparse = 1;
1120 for (a = 0; a < comp_unit_size && sparse == 1; a++) {
1121 if (comp_unit[a]) {
1122 sparse = 0;
1123 break;
1124 }
1125 }
1126
1127 /* Entire comp unit is sparse... */
1128 if (sparse) {
1129 if (tsk_verbose)
1130 tsk_fprintf(stderr,
1131 "ntfs_proc_compunit: Unit is fully sparse\n");
1132
1133 memset(comp->uncomp_buf, 0, comp->buf_size_b);
1134 comp->uncomp_idx = comp->buf_size_b;
1135 }
1136
1137 /* Check if the end of the unit is sparse, which means the
1138 * unit is compressed */
1139 else if (comp_unit[comp_unit_size - 1] == 0) {
1140
1141 if (tsk_verbose)
1142 tsk_fprintf(stderr,
1143 "ntfs_proc_compunit: Unit is compressed\n");
1144
1145 // load up the compressed buffer so we can decompress it
1146 ntfs_uncompress_reset(comp);
1147 for (a = 0; a < comp_unit_size; a++) {
1148 ssize_t cnt;
1149
1150 if (comp_unit[a] == 0)
1151 break;
1152
1153 /* To get the uncompressed size, we must uncompress the
1154 * data -- even if addresses are only needed */
1155 cnt =
1156 tsk_fs_read_block(fs, comp_unit[a],
1157 &comp->comp_buf[comp->comp_len], fs->block_size);
1158 if (cnt != fs->block_size) {
1159 if (cnt >= 0) {
1160 tsk_error_reset();
1161 tsk_error_set_errno(TSK_ERR_FS_READ);
1162 }
1163 tsk_error_set_errstr2
1164 ("ntfs_proc_compunit: Error reading block at %"
1165 PRIuDADDR, comp_unit[a]);
1166 return 1;
1167 }
1168 comp->comp_len += fs->block_size;
1169 }
1170
1171 if (ntfs_uncompress_compunit(comp)) {
1172 return 1;
1173 }
1174 }
1175
1176 /* Uncompressed data */
1177 else {
1178 if (tsk_verbose)
1179 tsk_fprintf(stderr,
1180 "ntfs_proc_compunit: Unit is not compressed\n");
1181
1182 comp->uncomp_idx = 0;
1183 for (a = 0; a < comp_unit_size; a++) {
1184 ssize_t cnt;
1185
1186 cnt =
1187 tsk_fs_read_block(fs, comp_unit[a],
1188 &comp->uncomp_buf[comp->uncomp_idx], fs->block_size);
1189 if (cnt != fs->block_size) {
1190 if (cnt >= 0) {
1191 tsk_error_reset();
1192 tsk_error_set_errno(TSK_ERR_FS_READ);
1193 }
1194 tsk_error_set_errstr2
1195 ("ntfs_proc_compunit: Error reading block at %"
1196 PRIuDADDR, comp_unit[a]);
1197 return 1;
1198 }
1199 comp->uncomp_idx += fs->block_size;
1200 }
1201 }
1202 return 0;
1203 }
1204
1205
1206
1207 /**
1208 * Currently ignores the SPARSE flag
1209 */
1210 static uint8_t
ntfs_attr_walk_special(const TSK_FS_ATTR * fs_attr,int flags,TSK_FS_FILE_WALK_CB a_action,void * ptr)1211 ntfs_attr_walk_special(const TSK_FS_ATTR * fs_attr,
1212 int flags, TSK_FS_FILE_WALK_CB a_action, void *ptr)
1213 {
1214 TSK_FS_INFO *fs;
1215 NTFS_INFO *ntfs;
1216
1217 // clean up any error messages that are lying around
1218 tsk_error_reset();
1219 if ((fs_attr == NULL) || (fs_attr->fs_file == NULL)
1220 || (fs_attr->fs_file->meta == NULL)
1221 || (fs_attr->fs_file->fs_info == NULL)) {
1222 tsk_error_set_errno(TSK_ERR_FS_ARG);
1223 tsk_error_set_errstr
1224 ("ntfs_attr_walk_special: Null arguments given\n");
1225 return 1;
1226 }
1227
1228 fs = fs_attr->fs_file->fs_info;
1229 ntfs = (NTFS_INFO *) fs;
1230
1231 /* Process the compressed buffer
1232 *
1233 * The compsize value equal to 0 can occur if we are processing an
1234 * isolated entry that is part of an attribute list. The first
1235 * sequence of the attribute has the compsize and the latter ones
1236 * do not. So, if one of the non-base MFT entries is processed by
1237 * itself, we have that case. I tried to assume it was 16, but it
1238 * caused decompression problems -- likely because this sequence
1239 * did not start on a compression unit boundary. So, now we just
1240 * dump the compressed data instead of giving an error.
1241 */
1242 if (fs_attr->flags & TSK_FS_ATTR_COMP) {
1243 TSK_DADDR_T addr;
1244 TSK_FS_ATTR_RUN *fs_attr_run;
1245 TSK_DADDR_T *comp_unit;
1246 uint32_t comp_unit_idx = 0;
1247 NTFS_COMP_INFO comp;
1248 TSK_OFF_T off = 0;
1249 int retval;
1250 uint8_t stop_loop = 0;
1251
1252 if (fs_attr->nrd.compsize <= 0) {
1253 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1254 tsk_error_set_errstr
1255 ("ntfs_attrwalk_special: Compressed attribute has compsize of 0 (%"
1256 PRIuINUM ")", fs_attr->fs_file->meta->addr);
1257 return 1;
1258 }
1259
1260 /* Allocate the buffers and state structure */
1261 if (ntfs_uncompress_setup(fs, &comp, fs_attr->nrd.compsize)) {
1262 return 1;
1263 }
1264
1265 comp_unit =
1266 (TSK_DADDR_T *) tsk_malloc(fs_attr->nrd.compsize *
1267 sizeof(TSK_DADDR_T));
1268 if (comp_unit == NULL) {
1269 ntfs_uncompress_done(&comp);
1270 return 1;
1271 }
1272 retval = TSK_WALK_CONT;
1273
1274 /* cycle through the number of runs we have */
1275 for (fs_attr_run = fs_attr->nrd.run; fs_attr_run;
1276 fs_attr_run = fs_attr_run->next) {
1277 size_t len_idx;
1278
1279 /* We may get a FILLER entry at the beginning of the run
1280 * if we are processing a non-base file record since
1281 * this $DATA attribute could not be the first sequence in the
1282 * attribute. Therefore, do not error if it starts at 0 */
1283 if (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {
1284 if (fs_attr_run->addr != 0) {
1285 tsk_error_reset();
1286
1287 if (fs_attr->fs_file->meta->
1288 flags & TSK_FS_META_FLAG_UNALLOC)
1289 tsk_error_set_errno(TSK_ERR_FS_RECOVER);
1290 else
1291 tsk_error_set_errno(TSK_ERR_FS_GENFS);
1292 tsk_error_set_errstr
1293 ("ntfs_attr_walk_special: Filler Entry exists in fs_attr_run %"
1294 PRIuDADDR "@%" PRIuDADDR " - type: %" PRIu32
1295 " id: %d Meta: %" PRIuINUM " Status: %s",
1296 fs_attr_run->len, fs_attr_run->addr, fs_attr->type,
1297 fs_attr->id, fs_attr->fs_file->meta->addr,
1298 (fs_attr->fs_file->meta->
1299 flags & TSK_FS_META_FLAG_ALLOC) ? "Allocated" :
1300 "Deleted");
1301 free(comp_unit);
1302 ntfs_uncompress_done(&comp);
1303 return 1;
1304 }
1305 else {
1306 if ((fs_attr_run->len > LLONG_MAX)
1307 || (LLONG_MAX / fs_attr_run->len < fs->block_size)) {
1308 if (fs_attr->fs_file->meta->
1309 flags & TSK_FS_META_FLAG_UNALLOC)
1310 tsk_error_set_errno(TSK_ERR_FS_RECOVER);
1311 else
1312 tsk_error_set_errno(TSK_ERR_FS_GENFS);
1313 tsk_error_set_errstr
1314 ("ntfs_attr_walk_special: Attribute run length is too large %"
1315 PRIuDADDR "@%" PRIuDADDR " - type: %" PRIu32
1316 " id: %d Meta: %" PRIuINUM " Status: %s",
1317 fs_attr_run->len, fs_attr_run->addr, fs_attr->type,
1318 fs_attr->id, fs_attr->fs_file->meta->addr,
1319 (fs_attr->fs_file->meta->
1320 flags & TSK_FS_META_FLAG_ALLOC) ? "Allocated" :
1321 "Deleted");
1322 free(comp_unit);
1323 ntfs_uncompress_done(&comp);
1324 return 1;
1325 }
1326 off += (fs_attr_run->len * fs->block_size);
1327 continue;
1328 }
1329 }
1330 addr = fs_attr_run->addr;
1331
1332 /* cycle through each cluster in the run */
1333 for (len_idx = 0; len_idx < fs_attr_run->len; len_idx++) {
1334
1335 if (addr > fs->last_block) {
1336 tsk_error_reset();
1337
1338 if (fs_attr->fs_file->meta->
1339 flags & TSK_FS_META_FLAG_UNALLOC)
1340 tsk_error_set_errno(TSK_ERR_FS_RECOVER);
1341 else
1342 tsk_error_set_errno(TSK_ERR_FS_BLK_NUM);
1343 tsk_error_set_errstr
1344 ("ntfs_attr_walk_special: Invalid address in run (too large): %"
1345 PRIuDADDR " Meta: %" PRIuINUM " Status: %s", addr,
1346 fs_attr->fs_file->meta->addr,
1347 (fs_attr->fs_file->meta->
1348 flags & TSK_FS_META_FLAG_ALLOC) ? "Allocated" :
1349 "Deleted");
1350
1351 free(comp_unit);
1352 ntfs_uncompress_done(&comp);
1353 return 1;
1354 }
1355
1356 // queue up the addresses until we get a full unit
1357 comp_unit[comp_unit_idx++] = addr;
1358
1359 // time to decompress (if queue is full or this is the last block)
1360 if ((comp_unit_idx == fs_attr->nrd.compsize)
1361 || ((len_idx == fs_attr_run->len - 1)
1362 && (fs_attr_run->next == NULL))) {
1363 size_t i;
1364
1365 // decompress the unit
1366 if (ntfs_proc_compunit(ntfs, &comp, comp_unit,
1367 comp_unit_idx)) {
1368 tsk_error_set_errstr2("%" PRIuINUM " - type: %"
1369 PRIu32 " id: %d Status: %s",
1370 fs_attr->fs_file->meta->addr, fs_attr->type,
1371 fs_attr->id,
1372 (fs_attr->fs_file->meta->
1373 flags & TSK_FS_META_FLAG_ALLOC) ?
1374 "Allocated" : "Deleted");
1375 free(comp_unit);
1376 ntfs_uncompress_done(&comp);
1377 return 1;
1378 }
1379
1380 // now call the callback with the uncompressed data
1381 for (i = 0; i < comp_unit_idx; i++) {
1382 int myflags;
1383 size_t read_len;
1384
1385 myflags =
1386 TSK_FS_BLOCK_FLAG_CONT |
1387 TSK_FS_BLOCK_FLAG_COMP;
1388 retval = is_clustalloc(ntfs, comp_unit[i]);
1389 if (retval == -1) {
1390 if (fs_attr->fs_file->meta->
1391 flags & TSK_FS_META_FLAG_UNALLOC)
1392 tsk_error_set_errno(TSK_ERR_FS_RECOVER);
1393 free(comp_unit);
1394 ntfs_uncompress_done(&comp);
1395 return 1;
1396 }
1397 else if (retval == 1) {
1398 myflags |= TSK_FS_BLOCK_FLAG_ALLOC;
1399 }
1400 else if (retval == 0) {
1401 myflags |= TSK_FS_BLOCK_FLAG_UNALLOC;
1402 }
1403
1404 if (fs_attr->size - off > fs->block_size)
1405 read_len = fs->block_size;
1406 else
1407 read_len = (size_t) (fs_attr->size - off);
1408
1409 if (i * fs->block_size + read_len >
1410 comp.uncomp_idx) {
1411 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1412 tsk_error_set_errstr
1413 ("ntfs_attrwalk_special: Trying to read past end of uncompressed buffer: %"
1414 PRIuSIZE " %" PRIuSIZE " Meta: %" PRIuINUM
1415 " Status: %s",
1416 i * fs->block_size + read_len,
1417 comp.uncomp_idx,
1418 fs_attr->fs_file->meta->addr,
1419 (fs_attr->fs_file->meta->
1420 flags & TSK_FS_META_FLAG_ALLOC) ?
1421 "Allocated" : "Deleted");
1422 free(comp_unit);
1423 ntfs_uncompress_done(&comp);
1424 return 1;
1425 }
1426
1427 // call the callback
1428 retval =
1429 a_action(fs_attr->fs_file, off, comp_unit[i],
1430 &comp.uncomp_buf[i * fs->block_size], read_len,
1431 myflags, ptr);
1432
1433 off += read_len;
1434
1435 if (off >= fs_attr->size) {
1436 stop_loop = 1;
1437 break;
1438 }
1439 if (retval != TSK_WALK_CONT) {
1440 stop_loop = 1;
1441 break;
1442 }
1443 }
1444 comp_unit_idx = 0;
1445 }
1446
1447 if (stop_loop)
1448 break;
1449
1450 /* If it is a sparse run, don't increment the addr so that
1451 * it remains 0 */
1452 if (((fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) ==
1453 0)
1454 && ((fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_FILLER)
1455 == 0))
1456 addr++;
1457 }
1458
1459 if (stop_loop)
1460 break;
1461 }
1462
1463 ntfs_uncompress_done(&comp);
1464 free(comp_unit);
1465
1466 if (retval == TSK_WALK_ERROR)
1467 return 1;
1468 else
1469 return 0;
1470 }
1471 else {
1472 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1473 tsk_error_set_errstr
1474 ("ntfs_attrwalk_special: called with non-special attribute: %x",
1475 fs_attr->flags);
1476 return 1;
1477 }
1478 }
1479
1480
1481 /** \internal
1482 *
1483 * @returns number of bytes read or -1 on error (incl if offset is past EOF)
1484 */
1485 static ssize_t
ntfs_file_read_special(const TSK_FS_ATTR * a_fs_attr,TSK_OFF_T a_offset,char * a_buf,size_t a_len)1486 ntfs_file_read_special(const TSK_FS_ATTR * a_fs_attr,
1487 TSK_OFF_T a_offset, char *a_buf, size_t a_len)
1488 {
1489 TSK_FS_INFO *fs = NULL;
1490 NTFS_INFO *ntfs = NULL;
1491
1492 if ((a_fs_attr == NULL) || (a_fs_attr->fs_file == NULL)
1493 || (a_fs_attr->fs_file->meta == NULL)
1494 || (a_fs_attr->fs_file->fs_info == NULL)) {
1495 tsk_error_set_errno(TSK_ERR_FS_ARG);
1496 tsk_error_set_errstr
1497 ("ntfs_file_read_special: NULL parameters passed");
1498 return -1;
1499 }
1500
1501 fs = a_fs_attr->fs_file->fs_info;
1502 ntfs = (NTFS_INFO *) fs;
1503
1504 if (a_fs_attr->flags & TSK_FS_ATTR_COMP) {
1505 TSK_FS_ATTR_RUN *data_run_cur;
1506 TSK_OFF_T cu_blkoffset; // block offset of starting compression unit to start reading from
1507 size_t byteoffset; // byte offset in compression unit of where we want to start reading from
1508 TSK_DADDR_T *comp_unit;
1509 uint32_t comp_unit_idx = 0;
1510 NTFS_COMP_INFO comp;
1511 size_t buf_idx = 0;
1512
1513 if (a_fs_attr->nrd.compsize <= 0) {
1514 tsk_error_set_errno(TSK_ERR_FS_FWALK);
1515 tsk_error_set_errstr
1516 ("ntfs_file_read_special: Compressed attribute has compsize of 0");
1517 return -1;
1518 }
1519
1520 if (a_offset >= a_fs_attr->size) {
1521 tsk_error_reset();
1522 tsk_error_set_errno(TSK_ERR_FS_READ_OFF);
1523 tsk_error_set_errstr("ntfs_file_read_special - %" PRIdOFF
1524 " Meta: %" PRIuINUM, a_offset,
1525 a_fs_attr->fs_file->meta->addr);
1526 return -1;
1527 }
1528
1529 // we return 0s for reads past the initsize
1530 if (a_offset >= a_fs_attr->nrd.initsize) {
1531 ssize_t len;
1532
1533 if (tsk_verbose)
1534 fprintf(stderr,
1535 "ntfs_file_read_special: Returning 0s for read past end of initsize (%"
1536 PRIuINUM ")\n", a_fs_attr->fs_file->meta->addr);
1537
1538 if (a_offset + (TSK_OFF_T)a_len > a_fs_attr->nrd.allocsize)
1539 len = (ssize_t) (a_fs_attr->nrd.allocsize - a_offset);
1540 else
1541 len = (ssize_t) a_len;
1542 memset(a_buf, 0, a_len);
1543 return len;
1544 }
1545
1546 /* Allocate the buffers and state structure */
1547 if (ntfs_uncompress_setup(fs, &comp, a_fs_attr->nrd.compsize)) {
1548 return -1;
1549 }
1550
1551 comp_unit =
1552 (TSK_DADDR_T *) tsk_malloc(a_fs_attr->nrd.compsize *
1553 sizeof(TSK_DADDR_T));
1554 if (comp_unit == NULL) {
1555 ntfs_uncompress_done(&comp);
1556 return -1;
1557 }
1558
1559 // figure out the needed offsets
1560 cu_blkoffset = a_offset / fs->block_size;
1561 if (cu_blkoffset) {
1562 cu_blkoffset /= a_fs_attr->nrd.compsize;
1563 cu_blkoffset *= a_fs_attr->nrd.compsize;
1564 }
1565
1566 byteoffset = (size_t) (a_offset - cu_blkoffset * fs->block_size);
1567
1568 // cycle through the run until we find where we can start to process the clusters
1569 for (data_run_cur = a_fs_attr->nrd.run;
1570 (data_run_cur) && (buf_idx < a_len);
1571 data_run_cur = data_run_cur->next) {
1572
1573 TSK_DADDR_T addr;
1574 size_t a;
1575
1576 // See if this run contains the starting offset they requested
1577 if (data_run_cur->offset + data_run_cur->len <
1578 (TSK_DADDR_T) cu_blkoffset)
1579 continue;
1580
1581
1582 // seek to the start of where we want to read (we may need to read several runs)
1583 if (data_run_cur->offset > (TSK_DADDR_T) cu_blkoffset)
1584 a = 0;
1585 else
1586 a = (size_t) (cu_blkoffset - data_run_cur->offset);
1587
1588 addr = data_run_cur->addr;
1589 // don't increment addr if it is 0 -- sparse
1590 if (addr)
1591 addr += a;
1592
1593 /* cycle through the relevant in the run */
1594 for (; a < data_run_cur->len && buf_idx < a_len; a++) {
1595
1596 // queue up the addresses until we get a full unit
1597 comp_unit[comp_unit_idx++] = addr;
1598
1599 // time to decompress (if queue is full or this is the last block)
1600 if ((comp_unit_idx == a_fs_attr->nrd.compsize)
1601 || ((a == data_run_cur->len - 1)
1602 && (data_run_cur->next == NULL))) {
1603 size_t cpylen;
1604
1605 // decompress the unit
1606 if (ntfs_proc_compunit(ntfs, &comp, comp_unit,
1607 comp_unit_idx)) {
1608 tsk_error_set_errstr2("%" PRIuINUM " - type: %"
1609 PRIu32 " id: %d Status: %s",
1610 a_fs_attr->fs_file->meta->addr,
1611 a_fs_attr->type, a_fs_attr->id,
1612 (a_fs_attr->fs_file->meta->
1613 flags & TSK_FS_META_FLAG_ALLOC) ?
1614 "Allocated" : "Deleted");
1615 free(comp_unit);
1616 ntfs_uncompress_done(&comp);
1617 return -1;
1618 }
1619
1620 // copy uncompressed data to the output buffer
1621 if (comp.uncomp_idx < byteoffset) {
1622
1623 // @@ ERROR
1624 free(comp_unit);
1625 ntfs_uncompress_done(&comp);
1626 return -1;
1627 }
1628 else if (comp.uncomp_idx - byteoffset <
1629 a_len - buf_idx) {
1630 cpylen = comp.uncomp_idx - byteoffset;
1631 }
1632 else {
1633 cpylen = a_len - buf_idx;
1634 }
1635 // Make sure not to return more bytes than are in the file
1636 if (cpylen > (a_fs_attr->size - (a_offset + buf_idx)))
1637 cpylen =
1638 (size_t) (a_fs_attr->size - (a_offset +
1639 buf_idx));
1640
1641 memcpy(&a_buf[buf_idx], &comp.uncomp_buf[byteoffset],
1642 cpylen);
1643
1644 // reset this in case we need to also read from the next run
1645 byteoffset = 0;
1646 buf_idx += cpylen;
1647 comp_unit_idx = 0;
1648 }
1649 /* If it is a sparse run, don't increment the addr so that
1650 * it remains 0 */
1651 if (((data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) ==
1652 0)
1653 && ((data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER)
1654 == 0))
1655 addr++;
1656 }
1657 }
1658
1659 free(comp_unit);
1660 ntfs_uncompress_done(&comp);
1661 return (ssize_t) buf_idx;
1662 }
1663 else {
1664 tsk_error_set_errno(TSK_ERR_FS_ARG);
1665 tsk_error_set_errstr
1666 ("ntfs_file_read_special: called with non-special attribute: %x",
1667 a_fs_attr->flags);
1668 return -1;
1669 }
1670 }
1671
1672
1673 /* needs to be predefined for proc_attrseq */
1674 static TSK_RETVAL_ENUM ntfs_proc_attrlist(NTFS_INFO *, TSK_FS_FILE *,
1675 const TSK_FS_ATTR *);
1676
1677
1678 /* This structure is used when processing attrlist attributes.
1679 * The Id part of the MFTNUM-TYPE-ID triple is unique only to a given
1680 * MFTNUM. With the case of attribute lists, a file may use multiple
1681 * MFT entires and therefore have multiple attributes with the same
1682 * type and id pair (if they are in different MFT entries). This map
1683 * is created by proc_attrlist when it assigns unique IDs to the
1684 * other entries. proc_attrseq uses this when it adds the attributes.
1685 */
1686 typedef struct {
1687 int num_used;
1688 TSK_INUM_T extMft[256];
1689 uint32_t type[256];
1690 uint32_t extId[256];
1691 uint8_t name[256][512];
1692 uint32_t newId[256];
1693 } NTFS_ATTRLIST_MAP;
1694
1695 /*
1696 * Process an NTFS attribute sequence and load the data into data
1697 * structures.
1698 * An attribute sequence is a linked list of the attributes in an MFT entry.
1699 * This is called by copy_inode and proc_attrlist.
1700 *
1701 * @param ntfs File system to analyze
1702 * @param fs_file Generic metadata structure to add the attribute info to
1703 * @param attrseq Start of the attribute sequence to analyze
1704 * @param len Length of the attribute sequence buffer
1705 * @param a_attrinum MFT entry address that the attribute sequence came from (diff from fs_file for attribute lists)
1706 * @param a_attr_map List that maps to new IDs that were assigned by processing
1707 * the attribute list attribute (if it exists) or NULL if there is no attrlist.
1708 * @returns Error code
1709 */
1710 static TSK_RETVAL_ENUM
ntfs_proc_attrseq(NTFS_INFO * ntfs,TSK_FS_FILE * fs_file,const ntfs_attr * a_attrseq,size_t len,TSK_INUM_T a_attrinum,const NTFS_ATTRLIST_MAP * a_attr_map)1711 ntfs_proc_attrseq(NTFS_INFO * ntfs,
1712 TSK_FS_FILE * fs_file, const ntfs_attr * a_attrseq, size_t len,
1713 TSK_INUM_T a_attrinum, const NTFS_ATTRLIST_MAP * a_attr_map)
1714 {
1715 const ntfs_attr *attr;
1716 const TSK_FS_ATTR *fs_attr_attrl = NULL;
1717 char name[NTFS_MAXNAMLEN_UTF8 + 1];
1718 TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
1719
1720 if (tsk_verbose)
1721 tsk_fprintf(stderr,
1722 "ntfs_proc_attrseq: Processing extended entry for primary entry %"
1723 PRIuINUM "\n", fs_file->meta->addr);
1724
1725 if (fs_file->meta->attr == NULL) {
1726 tsk_error_reset();
1727 tsk_error_set_errno(TSK_ERR_FS_ARG);
1728 tsk_error_set_errstr("Null attribute list in ntfs_proc_attrseq");
1729 return TSK_ERR;
1730 }
1731
1732 if (len > ntfs->mft_rsize_b) {
1733 tsk_error_reset();
1734 tsk_error_set_errno(TSK_ERR_FS_ARG);
1735 tsk_error_set_errstr("invalid length in ntfs_proc_attrseq");
1736 return TSK_ERR;
1737 }
1738
1739
1740 /* Cycle through the list of attributes
1741 * There are 16 bytes in the non-union part of
1742 * an ntfs_attr, so make sure there is at least room for that */
1743 for (attr = a_attrseq; ((uintptr_t) attr >= (uintptr_t) a_attrseq)
1744 && ((uintptr_t) attr + 16 <= ((uintptr_t) a_attrseq + len))
1745 && (tsk_getu32(fs->endian, attr->len) > 0
1746 && (tsk_getu32(fs->endian, attr->type) !=
1747 0xffffffff));
1748 attr =
1749 (ntfs_attr *) ((uintptr_t) attr + tsk_getu32(fs->endian,
1750 attr->len))) {
1751
1752 int retVal, i;
1753 uint32_t type;
1754 uint16_t id, id_new;
1755
1756 // sanity check on bounds of attribute. Prevents other
1757 // issues later on that use attr->len for bounds checks.
1758 if (((uintptr_t) attr + tsk_getu32(fs->endian,
1759 attr->len)) > (uintptr_t) (a_attrseq + len)) {
1760 break;
1761 }
1762
1763 /* Get the type of this attribute */
1764 type = tsk_getu32(fs->endian, attr->type);
1765 id = tsk_getu16(fs->endian, attr->id);
1766 id_new = id;
1767
1768 /* If the map was supplied, search through it to see if this
1769 * entry is in there. Use that ID instead so that we always have
1770 * unique IDs for each attribute -- even if it spans multiple MFT entries. */
1771 if (a_attr_map) {
1772 for (i = 0; i < a_attr_map->num_used; i++) {
1773 if ((a_attr_map->type[i] == type) &&
1774 (memcmp(a_attr_map->name[i],
1775 (void *) ((uintptr_t) attr +
1776 tsk_getu16(fs->endian, attr->name_off)),
1777 attr->nlen * 2) == 0)) {
1778 id_new = a_attr_map->newId[i];
1779 break;
1780 }
1781 }
1782 }
1783
1784 /* Copy the name and convert it to UTF8 */
1785 const uint16_t nameoff = tsk_getu16(fs->endian, attr->name_off);
1786 if (attr->nlen && nameoff + (uint32_t) attr->nlen * 2 < tsk_getu32(fs->endian, attr->len)) {
1787 int i;
1788 UTF8 *name8;
1789 UTF16 *name16;
1790
1791 name8 = (UTF8 *) name;
1792 name16 = (UTF16 *) ((uintptr_t) attr + nameoff);
1793
1794 retVal =
1795 tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
1796 (UTF16 *) ((uintptr_t) name16 +
1797 attr->nlen * 2),
1798 &name8,
1799 (UTF8 *) ((uintptr_t) name8 +
1800 sizeof(name)), TSKlenientConversion);
1801
1802 if (retVal != TSKconversionOK) {
1803 if (tsk_verbose)
1804 tsk_fprintf(stderr,
1805 "ntfs_proc_attrseq: Error converting NTFS attribute name to UTF8: %d %"
1806 PRIuINUM, retVal, fs_file->meta->addr);
1807 *name = '\0';
1808 }
1809
1810 /* Make sure it is NULL Terminated */
1811 else if ((uintptr_t) name8 >= (uintptr_t) name + sizeof(name))
1812 name[sizeof(name) - 1] = '\0';
1813 else
1814 *name8 = '\0';
1815
1816 /* Clean up name */
1817 i = 0;
1818 while (name[i] != '\0') {
1819 if (TSK_IS_CNTRL(name[i]))
1820 name[i] = '^';
1821 i++;
1822 }
1823 }
1824 else {
1825 name[0] = '\0';
1826 }
1827
1828 /* For resident attributes, we will copy the buffer into
1829 * a TSK_FS_ATTR buffer, which is stored in the TSK_FS_META
1830 * structure
1831 */
1832 if (attr->res == NTFS_MFT_RES) {
1833 TSK_FS_ATTR *fs_attr;
1834
1835 if (tsk_verbose)
1836 tsk_fprintf(stderr,
1837 "ntfs_proc_attrseq: Resident Attribute in Type: %"
1838 PRIu32 " Id: %" PRIu16 " IdNew: %" PRIu16
1839 " Name: %s\n", type, id, id_new, name);
1840
1841 /* Check that there is room for the data.
1842 * Resident data needs 24 bytes total */
1843 if (((uintptr_t)attr + 24) > ((uintptr_t)a_attrseq + len)) {
1844 tsk_error_reset();
1845 tsk_error_set_errno(TSK_ERR_FS_CORRUPT);
1846 tsk_error_set_errstr("ntfs_attr_walk: Resident attribute %"
1847 PRIuINUM "-%" PRIu32
1848 " starting offset and length too large",
1849 fs_file->meta->addr, type);
1850 return TSK_COR;
1851 }
1852
1853 /* Validate the offset lengths */
1854 if (((tsk_getu16(fs->endian,
1855 attr->c.r.soff) + (uintptr_t) attr) >
1856 ((uintptr_t) a_attrseq + len))
1857 || (((size_t)tsk_getu16(fs->endian,
1858 attr->c.r.soff) + tsk_getu32(fs->endian,
1859 attr->c.r.ssize) + (uintptr_t) attr) >
1860 ((uintptr_t) a_attrseq + len))) {
1861 tsk_error_reset();
1862 tsk_error_set_errno(TSK_ERR_FS_CORRUPT);
1863 tsk_error_set_errstr("ntfs_attr_walk: Resident attribute %"
1864 PRIuINUM "-%" PRIu32
1865 " starting offset and length too large",
1866 fs_file->meta->addr, type);
1867 return TSK_COR;
1868 }
1869
1870 // Get a free fs_attr structure
1871 if ((fs_attr =
1872 tsk_fs_attrlist_getnew(fs_file->meta->attr,
1873 TSK_FS_ATTR_RES)) == NULL) {
1874 tsk_error_errstr2_concat(" - proc_attrseq");
1875 return TSK_ERR;
1876 }
1877
1878 // set the details in the fs_attr structure
1879 if (tsk_fs_attr_set_str(fs_file, fs_attr, name, type,
1880 id_new, (void *) ((uintptr_t) attr +
1881 tsk_getu16(fs->endian,
1882 attr->c.r.soff)), tsk_getu32(fs->endian,
1883 attr->c.r.ssize))) {
1884 tsk_error_errstr2_concat("- proc_attrseq");
1885 return TSK_ERR;
1886 }
1887
1888 // set the meta size if we find the relevant attribute
1889 if (TSK_FS_IS_DIR_META(fs_file->meta->type)
1890 && (type == NTFS_ATYPE_IDXROOT)) {
1891 fs_file->meta->size =
1892 tsk_getu32(fs->endian, attr->c.r.ssize);
1893 }
1894 else if ((fs_file->meta->type == TSK_FS_META_TYPE_REG)
1895 && (type == NTFS_ATYPE_DATA) && (name[0] == '\0')) {
1896 fs_file->meta->size =
1897 tsk_getu32(fs->endian, attr->c.r.ssize);
1898 }
1899 }
1900
1901 /* For non-resident attributes, we will copy the runlist
1902 * to the generic form and then save it in the TSK_FS_META->attr
1903 * list
1904 */
1905 else {
1906 TSK_FS_ATTR *fs_attr = NULL;
1907 TSK_FS_ATTR_RUN *fs_attr_run = NULL;
1908 uint8_t data_flag = 0;
1909 uint32_t compsize = 0;
1910 TSK_RETVAL_ENUM retval;
1911
1912 if (tsk_verbose)
1913 tsk_fprintf(stderr,
1914 "ntfs_proc_attrseq: Non-Resident Attribute Type: %"
1915 PRIu32 " Id: %" PRIu16 " IdNew: %" PRIu16
1916 " Name: %s Start VCN: %" PRIu64 "\n", type, id,
1917 id_new, name, tsk_getu64(fs->endian,
1918 attr->c.nr.start_vcn));
1919
1920 /* Check that there is room for the data.
1921 * Non-resident data needs 64 bytes total */
1922 if (((uintptr_t)attr + 64) > ((uintptr_t)a_attrseq + len)) {
1923 tsk_error_reset();
1924 tsk_error_set_errno(TSK_ERR_FS_CORRUPT);
1925 tsk_error_set_errstr("ntfs_attr_walk: Non-Resident attribute %"
1926 PRIuINUM "-%" PRIu32
1927 " starting offset and length too large",
1928 fs_file->meta->addr, type);
1929 return TSK_COR;
1930 }
1931
1932 // sanity check
1933 if (tsk_getu16(fs->endian, attr->c.nr.run_off) > tsk_getu32(fs->endian, attr->len)) {
1934 if (tsk_verbose)
1935 tsk_fprintf(stderr, "ntfs_proc_attrseq: run offset too big\n");
1936 break;
1937 }
1938
1939 /* convert the run to generic form */
1940 retval = ntfs_make_data_run(ntfs,
1941 tsk_getu64(fs->endian, attr->c.nr.start_vcn),
1942 (ntfs_runlist *) ((uintptr_t)
1943 attr + tsk_getu16(fs->endian,
1944 attr->c.nr.run_off)), &fs_attr_run, NULL,
1945 a_attrinum);
1946 if (retval != TSK_OK) {
1947 tsk_error_errstr2_concat(" - proc_attrseq");
1948 return retval;
1949 }
1950
1951 /* Determine the flags based on compression and stuff */
1952 data_flag = 0;
1953 if (tsk_getu16(fs->endian, attr->flags) & NTFS_ATTR_FLAG_COMP) {
1954 data_flag |= TSK_FS_ATTR_COMP;
1955 fs_file->meta->flags |= TSK_FS_META_FLAG_COMP;
1956 }
1957
1958 if (tsk_getu16(fs->endian, attr->flags) & NTFS_ATTR_FLAG_ENC)
1959 data_flag |= TSK_FS_ATTR_ENC;
1960
1961 if (tsk_getu16(fs->endian, attr->flags) & NTFS_ATTR_FLAG_SPAR)
1962 data_flag |= TSK_FS_ATTR_SPARSE;
1963
1964 /* SPECIAL CASE
1965 * We are in non-res section, so we know this
1966 * isn't $STD_INFO and $FNAME
1967 *
1968 * When we are processing a non-base entry, we may
1969 * find an attribute with an id of 0 and it is an
1970 * extension of a previous run (i.e. non-zero start VCN)
1971 *
1972 * We will lookup if we already have such an attribute
1973 * and get its ID
1974 *
1975 * We could also check for a start_vcn if this does
1976 * not fix the problem.
1977 *
1978 * NOTE: This should not be needed now that TSK assigns
1979 * unique ID values to the extended attributes.
1980 */
1981 if (id_new == 0) {
1982 int cnt, i;
1983
1984 // cycle through the attributes
1985 cnt = tsk_fs_file_attr_getsize(fs_file);
1986 for (i = 0; i < cnt; i++) {
1987
1988 const TSK_FS_ATTR *fs_attr2 =
1989 tsk_fs_file_attr_get_idx(fs_file, i);
1990 if (!fs_attr2)
1991 continue;
1992
1993 /* We found an attribute with the same name and type */
1994 if (fs_attr2->type == type) {
1995 if (((name[0] == '\0') && (fs_attr2->name == NULL))
1996 || ((fs_attr2->name)
1997 && (strcmp(fs_attr2->name, name) == 0))) {
1998 id_new = fs_attr2->id;
1999 if (tsk_verbose)
2000 tsk_fprintf(stderr,
2001 "ntfs_proc_attrseq: Updating id from 0 to %"
2002 PRIu16 "\n", id_new);
2003 break;
2004 }
2005 }
2006 }
2007 }
2008
2009 /* the compression unit size is stored in the header
2010 * it is stored as the power of 2 (if it is not 0)
2011 */
2012 if (tsk_getu16(fs->endian, attr->c.nr.compusize) > 16) {
2013 /* 64k is the maximum compression unit size */
2014 tsk_error_reset();
2015 tsk_error_set_errno(TSK_ERR_FS_CORRUPT);
2016 tsk_error_set_errstr("ntfs_proc_attrseq: Compression unit size 2^%d too large",
2017 tsk_getu16(fs->endian, attr->c.nr.compusize));
2018 if (fs_attr_run)
2019 tsk_fs_attr_run_free(fs_attr_run);
2020 return TSK_COR;
2021 }
2022
2023 if (tsk_getu16(fs->endian, attr->c.nr.compusize) > 0) {
2024 compsize =
2025 1 << (tsk_getu16(fs->endian, attr->c.nr.compusize));
2026 }
2027 else {
2028 compsize = 0;
2029 /* if this is 0, be sure to cancel out the COMP flag.
2030 * This occurs when we process an extended attribute
2031 * that has compressed data -- the attributes in the
2032 * latter MFT entries do not have compsize set.
2033 */
2034 if (data_flag & TSK_FS_ATTR_COMP) {
2035 if (tsk_verbose)
2036 fprintf(stderr,
2037 "ntfs_proc_attrseq: Clearing compression setting for attribute %"
2038 PRIuINUM "-%d because compsize is 0\n",
2039 fs_file->meta->addr, type);
2040 data_flag &= ~TSK_FS_ATTR_COMP;
2041 }
2042 }
2043
2044 /* Add the run to the list */
2045 // see if this attribute has already been partially defined
2046 // @@@ This is bad design, we are casting away the const...
2047 fs_attr =
2048 (TSK_FS_ATTR *) tsk_fs_attrlist_get_id(fs_file->meta->attr,
2049 type, id_new);
2050 if (fs_attr == NULL) {
2051 uint64_t ssize; // size
2052 uint64_t alen; // allocated length
2053
2054 if ((fs_attr =
2055 tsk_fs_attrlist_getnew(fs_file->meta->attr,
2056 TSK_FS_ATTR_RES)) == NULL) {
2057 tsk_error_errstr2_concat(" - proc_attrseq: getnew");
2058 // JRB: Coverity found leak.
2059 if (fs_attr_run)
2060 tsk_fs_attr_run_free(fs_attr_run);
2061 fs_attr_run = NULL;
2062 return TSK_ERR;
2063 }
2064
2065 ssize = tsk_getu64(fs->endian, attr->c.nr.ssize);
2066 /* This can happen with extended attributes, so
2067 * we set it based on what we currently have.
2068 * fs_attr_run can be NULL for $BadClust file. */
2069 if ((ssize == 0) && (fs_attr_run)) {
2070 TSK_FS_ATTR_RUN *fs_attr_run_tmp;
2071
2072 ssize = fs_attr_run->offset * fs->block_size;
2073 fs_attr_run_tmp = fs_attr_run;
2074 while (fs_attr_run_tmp) {
2075 ssize += (fs_attr_run_tmp->len * fs->block_size);
2076 fs_attr_run_tmp = fs_attr_run_tmp->next;
2077 }
2078 }
2079
2080 // update the meta->size value if this is the default $Data attribute
2081 if ((fs_file->meta->type == TSK_FS_META_TYPE_REG)
2082 && (type == NTFS_ATYPE_DATA) && (name[0] == '\0')) {
2083 fs_file->meta->size = ssize;
2084 }
2085
2086 alen = tsk_getu64(fs->endian, attr->c.nr.alen);
2087 /* This can also happen with extended attributes.
2088 * set it to what we know about */
2089 if (alen == 0) {
2090 alen = ssize;
2091 }
2092
2093 if (tsk_fs_attr_set_run(fs_file, fs_attr,
2094 fs_attr_run, name,
2095 type, id_new, ssize,
2096 tsk_getu64(fs->endian, attr->c.nr.initsize),
2097 alen, data_flag, compsize)) {
2098 tsk_error_errstr2_concat("- proc_attrseq: set run");
2099
2100 // If the run wasn't saved to the attribute, free it now
2101 if (fs_attr_run && (fs_attr->nrd.run == NULL))
2102 tsk_fs_attr_run_free(fs_attr_run);
2103 return TSK_COR;
2104 }
2105 // set the special functions
2106 if (fs_file->meta->flags & TSK_FS_META_FLAG_COMP) {
2107 fs_attr->w = ntfs_attr_walk_special;
2108 fs_attr->r = ntfs_file_read_special;
2109 }
2110
2111 }
2112 else {
2113 if (tsk_fs_attr_add_run(fs, fs_attr, fs_attr_run)) {
2114 tsk_error_errstr2_concat(" - proc_attrseq: put run");
2115 return TSK_COR;
2116 }
2117 }
2118 }
2119
2120 /*
2121 * Special Cases, where we grab additional information
2122 * regardless if they are resident or not
2123 */
2124
2125 /* Standard Information (is always resident) */
2126 if (type == NTFS_ATYPE_SI) {
2127 ntfs_attr_si *si;
2128 if (attr->res != NTFS_MFT_RES) {
2129 tsk_error_reset();
2130 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
2131 tsk_error_set_errstr
2132 ("proc_attrseq: Standard Information Attribute is not resident!");
2133 return TSK_COR;
2134 }
2135 si = (ntfs_attr_si *) ((uintptr_t) attr +
2136 tsk_getu16(fs->endian, attr->c.r.soff));
2137 fs_file->meta->mtime =
2138 nt2unixtime(tsk_getu64(fs->endian, si->mtime));
2139 fs_file->meta->mtime_nano =
2140 nt2nano(tsk_getu64(fs->endian, si->mtime));
2141
2142 fs_file->meta->atime =
2143 nt2unixtime(tsk_getu64(fs->endian, si->atime));
2144 fs_file->meta->atime_nano =
2145 nt2nano(tsk_getu64(fs->endian, si->atime));
2146
2147 fs_file->meta->ctime =
2148 nt2unixtime(tsk_getu64(fs->endian, si->ctime));
2149 fs_file->meta->ctime_nano =
2150 nt2nano(tsk_getu64(fs->endian, si->ctime));
2151
2152 fs_file->meta->crtime =
2153 nt2unixtime(tsk_getu64(fs->endian, si->crtime));
2154 fs_file->meta->crtime_nano =
2155 nt2nano(tsk_getu64(fs->endian, si->crtime));
2156
2157 fs_file->meta->uid = tsk_getu32(fs->endian, si->own_id);
2158 fs_file->meta->mode |=
2159 (TSK_FS_META_MODE_IXUSR | TSK_FS_META_MODE_IXGRP |
2160 TSK_FS_META_MODE_IXOTH);
2161 if ((tsk_getu32(fs->endian, si->dos) & NTFS_SI_RO) == 0)
2162 fs_file->meta->mode |=
2163 (TSK_FS_META_MODE_IRUSR | TSK_FS_META_MODE_IRGRP |
2164 TSK_FS_META_MODE_IROTH);
2165 if ((tsk_getu32(fs->endian, si->dos) & NTFS_SI_HID) == 0)
2166 fs_file->meta->mode |=
2167 (TSK_FS_META_MODE_IWUSR | TSK_FS_META_MODE_IWGRP |
2168 TSK_FS_META_MODE_IWOTH);
2169 }
2170
2171 /* File Name (always resident) */
2172 else if (type == NTFS_ATYPE_FNAME) {
2173 ntfs_attr_fname *fname;
2174 TSK_FS_META_NAME_LIST *fs_name;
2175 UTF16 *name16;
2176 UTF8 *name8;
2177 if (attr->res != NTFS_MFT_RES) {
2178 tsk_error_reset();
2179 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
2180 tsk_error_set_errstr
2181 ("proc_attr_seq: File Name Attribute is not resident!");
2182 return TSK_COR;
2183 }
2184 fname =
2185 (ntfs_attr_fname *) ((uintptr_t) attr +
2186 tsk_getu16(fs->endian, attr->c.r.soff));
2187 if (fname->nspace == NTFS_FNAME_DOS) {
2188 continue;
2189 }
2190
2191 fs_file->meta->time2.ntfs.fn_mtime =
2192 nt2unixtime(tsk_getu64(fs->endian, fname->mtime));
2193 fs_file->meta->time2.ntfs.fn_mtime_nano =
2194 nt2nano(tsk_getu64(fs->endian, fname->mtime));
2195
2196 fs_file->meta->time2.ntfs.fn_atime =
2197 nt2unixtime(tsk_getu64(fs->endian, fname->atime));
2198 fs_file->meta->time2.ntfs.fn_atime_nano =
2199 nt2nano(tsk_getu64(fs->endian, fname->atime));
2200
2201 fs_file->meta->time2.ntfs.fn_ctime =
2202 nt2unixtime(tsk_getu64(fs->endian, fname->ctime));
2203 fs_file->meta->time2.ntfs.fn_ctime_nano =
2204 nt2nano(tsk_getu64(fs->endian, fname->ctime));
2205
2206 fs_file->meta->time2.ntfs.fn_crtime =
2207 nt2unixtime(tsk_getu64(fs->endian, fname->crtime));
2208 fs_file->meta->time2.ntfs.fn_crtime_nano =
2209 nt2nano(tsk_getu64(fs->endian, fname->crtime));
2210
2211 fs_file->meta->time2.ntfs.fn_id = id;
2212
2213
2214 /* Seek to the end of the fs_name structures in TSK_FS_META */
2215 if (fs_file->meta->name2) {
2216 for (fs_name = fs_file->meta->name2;
2217 (fs_name) && (fs_name->next != NULL);
2218 fs_name = fs_name->next) {
2219 }
2220
2221 /* add to the end of the existing list */
2222 fs_name->next = (TSK_FS_META_NAME_LIST *)
2223 tsk_malloc(sizeof(TSK_FS_META_NAME_LIST));
2224 if (fs_name->next == NULL) {
2225 return TSK_ERR;
2226 }
2227 fs_name = fs_name->next;
2228 fs_name->next = NULL;
2229 }
2230 else {
2231 /* First name, so we start a list */
2232 fs_file->meta->name2 = fs_name = (TSK_FS_META_NAME_LIST *)
2233 tsk_malloc(sizeof(TSK_FS_META_NAME_LIST));
2234 if (fs_name == NULL) {
2235 return TSK_ERR;
2236 }
2237 fs_name->next = NULL;
2238 }
2239
2240 name16 = (UTF16 *) & fname->name;
2241 name8 = (UTF8 *) fs_name->name;
2242 retVal =
2243 tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
2244 (UTF16 *) ((uintptr_t) name16 +
2245 fname->nlen * 2),
2246 &name8,
2247 (UTF8 *) ((uintptr_t) name8 +
2248 sizeof(fs_name->name)), TSKlenientConversion);
2249 if (retVal != TSKconversionOK) {
2250 if (tsk_verbose)
2251 tsk_fprintf(stderr,
2252 "proc_attr_seq: Error converting NTFS name in $FNAME to UTF8: %d",
2253 retVal);
2254 *name8 = '\0';
2255 }
2256 /* Make sure it is NULL Terminated */
2257 else if ((uintptr_t) name8 >=
2258 (uintptr_t) fs_name->name + sizeof(fs_name->name))
2259 fs_name->name[sizeof(fs_name->name) - 1] = '\0';
2260 else
2261 *name8 = '\0';
2262
2263 fs_name->par_inode = tsk_getu48(fs->endian, fname->par_ref);
2264 fs_name->par_seq = tsk_getu16(fs->endian, fname->par_seq);
2265 }
2266
2267 /* If this is an attribute list than we need to process
2268 * it to get the list of other entries to read. But, because
2269 * of the wierd scenario of the $MFT having an attribute list
2270 * and not knowing where the other MFT entires are yet, we wait
2271 * until the end of the attrseq to processes the list and then
2272 * we should have the $Data attribute loaded
2273 */
2274 else if (type == NTFS_ATYPE_ATTRLIST) {
2275 if (fs_attr_attrl) {
2276 tsk_error_reset();
2277 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
2278 tsk_error_set_errstr
2279 ("Multiple instances of attribute lists in the same MFT\n"
2280 "I didn't realize that could happen, contact the developers");
2281 return TSK_ERR;
2282 }
2283 fs_attr_attrl = tsk_fs_attrlist_get_id(fs_file->meta->attr,
2284 NTFS_ATYPE_ATTRLIST, id_new);
2285 if (fs_attr_attrl == NULL) {
2286 tsk_error_errstr2_concat
2287 ("- proc_attrseq: getting attribute list");
2288 return TSK_ERR;
2289 }
2290 }
2291 }
2292
2293
2294 /* Are we currently in the process of loading $MFT? */
2295 if (ntfs->loading_the_MFT == 1) {
2296
2297 /* If we don't even have a mini cached version, get it now
2298 * Even if we are not done because of attribute lists, then we
2299 * should at least have the head of the list
2300 */
2301 if (!ntfs->mft_data) {
2302 int cnt, i;
2303
2304 // cycle through the attributes
2305 cnt = tsk_fs_file_attr_getsize(fs_file);
2306 for (i = 0; i < cnt; i++) {
2307 const TSK_FS_ATTR *fs_attr =
2308 tsk_fs_file_attr_get_idx(fs_file, i);
2309 if (!fs_attr)
2310 continue;
2311
2312 // get the default attribute
2313 if ((fs_attr->type == NTFS_ATYPE_DATA) &&
2314 (fs_attr->name == NULL)) {
2315 ntfs->mft_data = fs_attr;
2316 break;
2317 }
2318 }
2319
2320 // @@@ Is this needed here -- maybe it should be only in _open
2321 if (!ntfs->mft_data) {
2322 tsk_error_reset();
2323 tsk_error_set_errno(TSK_ERR_FS_GENFS);
2324 tsk_error_set_errstr
2325 ("$Data not found while loading the MFT");
2326 return TSK_ERR;
2327 }
2328 }
2329
2330 /* Update the inode count based on the current size
2331 * IF $MFT has an attribute list, this value will increase each
2332 * time
2333 */
2334 fs->inum_count = ntfs->mft_data->size / ntfs->mft_rsize_b;
2335 fs->last_inum = fs->inum_count - 1;
2336 }
2337
2338 /* If there was an attribute list, process it now, we wait because
2339 * the list can contain MFT entries that are described in $Data
2340 * of this MFT entry. For example, part of the $DATA attribute
2341 * could follow the ATTRLIST entry, so we read it first and then
2342 * process the attribute list
2343 */
2344 if (fs_attr_attrl) {
2345 TSK_RETVAL_ENUM retval;
2346 if ((retval = ntfs_proc_attrlist(ntfs, fs_file, fs_attr_attrl)) != TSK_OK) {
2347 return retval;
2348 }
2349 }
2350
2351 fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
2352 return TSK_OK;
2353 }
2354
2355
2356
2357 /******** Attribute List Action and Function ***********/
2358
2359
2360
2361 /*
2362 * Attribute lists are used when all of the attribute headers can not
2363 * fit into one MFT entry. This contains an entry for every attribute
2364 * and where they are located. We process this to get the locations
2365 * and then call proc_attrseq on each of those, which adds the data
2366 * to the fs_file structure.
2367 *
2368 * @param ntfs File system being analyzed
2369 * @param fs_file Main file that will have attributes added to it.
2370 * @param fs_attr_attrlist Attrlist attribute that needs to be parsed.
2371 *
2372 * @returns status of error, corrupt, or OK
2373 */
2374 static TSK_RETVAL_ENUM
ntfs_proc_attrlist(NTFS_INFO * ntfs,TSK_FS_FILE * fs_file,const TSK_FS_ATTR * fs_attr_attrlist)2375 ntfs_proc_attrlist(NTFS_INFO * ntfs,
2376 TSK_FS_FILE * fs_file, const TSK_FS_ATTR * fs_attr_attrlist)
2377 {
2378 ntfs_attrlist *list;
2379 char *buf;
2380 uintptr_t endaddr;
2381 TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
2382 ntfs_mft *mft;
2383 TSK_FS_LOAD_FILE load_file;
2384 TSK_INUM_T mftToDo[256];
2385 uint16_t mftToDoCnt = 0;
2386 NTFS_ATTRLIST_MAP *map;
2387 uint16_t nextid = 0;
2388 int a;
2389
2390 if (tsk_verbose)
2391 tsk_fprintf(stderr,
2392 "ntfs_proc_attrlist: Processing entry %"
2393 PRIuINUM "\n", fs_file->meta->addr);
2394
2395 if ((mft = (ntfs_mft *) tsk_malloc(ntfs->mft_rsize_b)) == NULL) {
2396 return TSK_ERR;
2397 }
2398
2399 if ((map =
2400 (NTFS_ATTRLIST_MAP *) tsk_malloc(sizeof(NTFS_ATTRLIST_MAP))) ==
2401 NULL) {
2402 free(mft);
2403 return TSK_ERR;
2404 }
2405
2406 /* Clear the contents of the todo buffer */
2407 memset(mftToDo, 0, sizeof(mftToDo));
2408
2409 /* Get a copy of the attribute list stream using the above action */
2410 load_file.left = load_file.total = (size_t) fs_attr_attrlist->size;
2411 load_file.base = load_file.cur = buf =
2412 tsk_malloc((size_t) fs_attr_attrlist->size);
2413 if (buf == NULL) {
2414 free(mft);
2415 free(map);
2416 return TSK_ERR;
2417 }
2418 endaddr = (uintptr_t) buf + (uintptr_t) fs_attr_attrlist->size;
2419 if (tsk_fs_attr_walk(fs_attr_attrlist, 0, tsk_fs_load_file_action,
2420 (void *) &load_file)) {
2421 tsk_error_errstr2_concat("- processing attrlist");
2422 free(mft);
2423 free(map);
2424 return TSK_ERR;
2425 }
2426
2427 /* this value should be zero, if not then we didn't read all of the
2428 * buffer
2429 */
2430 if (load_file.left > 0) {
2431 tsk_error_reset();
2432 tsk_error_set_errno(TSK_ERR_FS_FWALK);
2433 tsk_error_set_errstr2("processing attrlist of entry %" PRIuINUM,
2434 fs_file->meta->addr);
2435 free(mft);
2436 free(buf);
2437 free(map);
2438 return TSK_ERR;
2439 }
2440
2441 /* The TSK design requires that each attribute have its own ID.
2442 * Therefore, we need to identify all of the unique attributes
2443 * so that we can assign a unique ID to them.
2444 * In this process, we will also identify the unique MFT entries to
2445 * process. */
2446 nextid = fs_attr_attrlist->id; // we won't see this entry in the list
2447 for (list = (ntfs_attrlist *) buf;
2448 (list)
2449 // ntfs_attrlist contains the first byte of the name, which might actually be 0-length
2450 && (uintptr_t) list + sizeof(ntfs_attrlist) - 1 <= endaddr
2451 && tsk_getu16(fs->endian, list->len) > 0
2452 && (uintptr_t) list + tsk_getu16(fs->endian, list->len) <= endaddr
2453 && (uintptr_t) list + sizeof(ntfs_attrlist) - 1 + 2 * list->nlen <= endaddr;
2454 list =
2455 (ntfs_attrlist *) ((uintptr_t) list + tsk_getu16(fs->endian,
2456 list->len))) {
2457 uint8_t found;
2458 int i;
2459
2460 TSK_INUM_T mftnum = tsk_getu48(fs->endian, list->file_ref);
2461 uint32_t type = tsk_getu32(fs->endian, list->type);
2462 uint16_t id = tsk_getu16(fs->endian, list->id);
2463
2464 if (tsk_verbose)
2465 tsk_fprintf(stderr,
2466 "ntfs_proc_attrlist: mft: %" PRIuINUM
2467 " type %" PRIu32 " id %" PRIu16
2468 " VCN: %" PRIu64 "\n", mftnum, type,
2469 id, tsk_getu64(fs->endian, list->start_vcn));
2470
2471
2472 // keep track of the biggest ID that we saw.
2473 if (id > nextid)
2474 nextid = id;
2475
2476 /* First identify the unique attributes.
2477 * we can have duplicate entries at different VCNs. Ignore those. */
2478 found = 0;
2479 for (i = 0; i < map->num_used; i++) {
2480 if ((map->type[i] == type)
2481 && (memcmp(map->name[i], &list->name,
2482 list->nlen * 2) == 0)) {
2483 found = 1;
2484 break;
2485 }
2486 }
2487
2488 // add it to the list
2489 if (found == 0) {
2490 map->extMft[map->num_used] = mftnum;
2491 map->type[map->num_used] = type;
2492 map->extId[map->num_used] = id;
2493 memcpy(map->name[map->num_used], &list->name, list->nlen * 2);
2494 if (map->num_used < 255)
2495 map->num_used++;
2496 }
2497
2498 /* also check the todo list -- skip the base entry
2499 * the goal here is to get a unique list of MFT entries
2500 * to later process. */
2501 if (mftnum != fs_file->meta->addr) {
2502 found = 0;
2503 for (i = 0; i < mftToDoCnt; i++) {
2504 if (mftToDo[i] == mftnum) {
2505 found = 1;
2506 break;
2507 }
2508 }
2509 if ((found == 0) && (mftToDoCnt < 256)) {
2510 mftToDo[mftToDoCnt++] = mftnum;
2511 }
2512 }
2513 }
2514
2515 // update the map and assign unique IDs
2516 for (a = 0; a < map->num_used; a++) {
2517 // skip the base entry attributes -- they have unique attribute IDs
2518 if (map->extMft[a] == fs_file->meta->addr)
2519 continue;
2520 map->newId[a] = ++nextid;
2521 }
2522
2523
2524 /* Process the ToDo list & and call ntfs_proc_attr */
2525 for (a = 0; a < mftToDoCnt; a++) {
2526 TSK_RETVAL_ENUM retval;
2527
2528 /* Sanity check. */
2529 if (mftToDo[a] < ntfs->fs_info.first_inum ||
2530 mftToDo[a] > ntfs->fs_info.last_inum ||
2531 // MFT 0 is for $MFT. We had one system that we got a reference to it from parsing an allocated attribute list
2532 mftToDo[a] == 0) {
2533
2534 if (tsk_verbose) {
2535 /* this case can easily occur if the attribute list was non-resident and the cluster has been reallocated */
2536
2537 tsk_fprintf(stderr,
2538 "Invalid MFT file reference (%"
2539 PRIuINUM
2540 ") in the unallocated attribute list of MFT %"
2541 PRIuINUM "", mftToDo[a], fs_file->meta->addr);
2542 }
2543 continue;
2544 }
2545
2546 if ((retval =
2547 ntfs_dinode_lookup(ntfs, (char *) mft,
2548 mftToDo[a])) != TSK_OK) {
2549 // if the entry is corrupt, then continue
2550 if (retval == TSK_COR) {
2551 if (tsk_verbose)
2552 tsk_error_print(stderr);
2553 tsk_error_reset();
2554 continue;
2555 }
2556
2557 free(mft);
2558 free(map);
2559 free(buf);
2560 tsk_error_errstr2_concat(" - proc_attrlist");
2561 return TSK_ERR;
2562 }
2563
2564 /* verify that this entry refers to the original one */
2565 if (tsk_getu48(fs->endian, mft->base_ref) != fs_file->meta->addr) {
2566
2567 /* Before we raise alarms, check if the original was
2568 * unallocated. If so, then the list entry could
2569 * have been reallocated, so we will just ignore it
2570 */
2571 if (((tsk_getu16(fs->endian,
2572 mft->flags) & NTFS_MFT_INUSE) == 0)
2573 || (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) {
2574 continue;
2575 }
2576 else {
2577 tsk_error_reset();
2578 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
2579 tsk_error_set_errstr("ntfs_proc_attrlist: MFT %" PRIuINUM
2580 " is not an attribute list for %"
2581 PRIuINUM
2582 " (base file ref = %" PRIuINUM ")",
2583 mftToDo[a],
2584 fs_file->meta->addr,
2585 tsk_getu48(fs->endian, mft->base_ref));
2586 free(mft);
2587 free(map);
2588 free(buf);
2589 return TSK_COR;
2590 }
2591 }
2592
2593 // bounds check
2594 if (tsk_getu16(fs->endian, mft->attr_off) > ntfs->mft_rsize_b) {
2595 if (tsk_verbose)
2596 tsk_fprintf(stderr, "ntfs_proc_attrlist: corrupt MFT entry attribute offsets\n");
2597 continue;
2598 }
2599
2600 /* Process the attribute seq for this MFT entry and add them
2601 * to the TSK_FS_META structure
2602 */
2603 if ((retval =
2604 ntfs_proc_attrseq(ntfs, fs_file, (ntfs_attr *) ((uintptr_t)
2605 mft + tsk_getu16(fs->endian, mft->attr_off)),
2606 ntfs->mft_rsize_b - tsk_getu16(fs->endian,
2607 mft->attr_off), mftToDo[a], map)) != TSK_OK) {
2608
2609 if (retval == TSK_COR) {
2610 if (tsk_verbose)
2611 tsk_error_print(stderr);
2612 tsk_error_reset();
2613 continue;
2614 }
2615 tsk_error_errstr2_concat("- proc_attrlist");
2616 free(mft);
2617 free(map);
2618 free(buf);
2619 return TSK_ERR;
2620 }
2621 }
2622
2623 free(mft);
2624 free(map);
2625 free(buf);
2626 return TSK_OK;
2627 }
2628
2629
2630
2631 /**
2632 * Copy the MFT entry saved in a_buf to the generic structure.
2633 *
2634 * @param ntfs File system structure that contains entry to copy
2635 * @param fs_file Structure to copy processed data to.
2636 * @param a_buf MFT structure to copy from. Must be of size NTFS_INFO.mft_rsize_b
2637 * @param a_mnum MFT entry address
2638 *
2639 * @returns error code
2640 */
2641 static TSK_RETVAL_ENUM
ntfs_dinode_copy(NTFS_INFO * ntfs,TSK_FS_FILE * a_fs_file,char * a_buf,TSK_INUM_T a_mnum)2642 ntfs_dinode_copy(NTFS_INFO * ntfs, TSK_FS_FILE * a_fs_file, char *a_buf,
2643 TSK_INUM_T a_mnum)
2644 {
2645 ntfs_attr *attr;
2646 TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
2647 TSK_RETVAL_ENUM retval;
2648 ntfs_mft *mft = (ntfs_mft *) a_buf;
2649
2650 if ((a_fs_file == NULL) || (a_fs_file->meta == NULL)) {
2651 tsk_error_reset();
2652 tsk_error_set_errno(TSK_ERR_FS_ARG);
2653 tsk_error_set_errstr("ntfs_dinode_copy: NULL fs_file given");
2654 return TSK_ERR;
2655 }
2656
2657 /* if the attributes list has been used previously, then make sure the
2658 * flags are cleared
2659 */
2660 if (a_fs_file->meta->attr) {
2661 tsk_fs_attrlist_markunused(a_fs_file->meta->attr);
2662 }
2663 else {
2664 a_fs_file->meta->attr = tsk_fs_attrlist_alloc();
2665 if (a_fs_file->meta->attr == NULL)
2666 return TSK_ERR;
2667 }
2668 a_fs_file->meta->attr_state = TSK_FS_META_ATTR_EMPTY;
2669
2670 /* If there are any name structures allocated, then free 'em */
2671 if (a_fs_file->meta->name2) {
2672 TSK_FS_META_NAME_LIST *fs_name1, *fs_name2;
2673 fs_name1 = a_fs_file->meta->name2;
2674
2675 while (fs_name1) {
2676 fs_name2 = fs_name1->next;
2677 free(fs_name1);
2678 fs_name1 = fs_name2;
2679 }
2680 a_fs_file->meta->name2 = NULL;
2681 }
2682
2683 /* Set the a_fs_file->meta values from mft */
2684 a_fs_file->meta->nlink = tsk_getu16(fs->endian, mft->link);
2685 a_fs_file->meta->seq = tsk_getu16(fs->endian, mft->seq);
2686 a_fs_file->meta->addr = a_mnum;
2687
2688 /* Set the mode for file or directory */
2689 if (tsk_getu16(fs->endian, mft->flags) & NTFS_MFT_DIR)
2690 a_fs_file->meta->type = TSK_FS_META_TYPE_DIR;
2691 else
2692 a_fs_file->meta->type = TSK_FS_META_TYPE_REG;
2693 a_fs_file->meta->mode = 0; // will be set by proc_attrseq
2694
2695 /* the following will be changed once we find the correct attribute,
2696 * but initialize them now just in case
2697 */
2698 a_fs_file->meta->uid = 0;
2699 a_fs_file->meta->gid = 0;
2700 a_fs_file->meta->size = 0;
2701 a_fs_file->meta->mtime = 0;
2702 a_fs_file->meta->mtime_nano = 0;
2703 a_fs_file->meta->atime = 0;
2704 a_fs_file->meta->atime_nano = 0;
2705 a_fs_file->meta->ctime = 0;
2706 a_fs_file->meta->ctime_nano = 0;
2707 a_fs_file->meta->crtime = 0;
2708 a_fs_file->meta->crtime_nano = 0;
2709 a_fs_file->meta->time2.ntfs.fn_mtime = 0;
2710 a_fs_file->meta->time2.ntfs.fn_mtime_nano = 0;
2711 a_fs_file->meta->time2.ntfs.fn_atime = 0;
2712 a_fs_file->meta->time2.ntfs.fn_atime_nano = 0;
2713 a_fs_file->meta->time2.ntfs.fn_ctime = 0;
2714 a_fs_file->meta->time2.ntfs.fn_ctime_nano = 0;
2715 a_fs_file->meta->time2.ntfs.fn_crtime = 0;
2716 a_fs_file->meta->time2.ntfs.fn_crtime_nano = 0;
2717 a_fs_file->meta->time2.ntfs.fn_id = 0;
2718
2719 /* add the flags */
2720 a_fs_file->meta->flags =
2721 ((tsk_getu16(fs->endian, mft->flags) &
2722 NTFS_MFT_INUSE) ? TSK_FS_META_FLAG_ALLOC :
2723 TSK_FS_META_FLAG_UNALLOC);
2724
2725
2726 /* Process the attribute sequence to fill in the fs_meta->attr
2727 * list and the other info such as size and times
2728 */
2729 if (tsk_getu16(fs->endian, mft->attr_off) > ntfs->mft_rsize_b) {
2730 tsk_error_reset();
2731 tsk_error_set_errno(TSK_ERR_FS_ARG);
2732 tsk_error_set_errstr("ntfs_dinode_copy: corrupt MFT entry attribute offsets");
2733 return TSK_ERR;
2734 }
2735
2736 attr =
2737 (ntfs_attr *) ((uintptr_t) mft + tsk_getu16(fs->endian,
2738 mft->attr_off));
2739 if ((retval = ntfs_proc_attrseq(ntfs, a_fs_file, attr,
2740 ntfs->mft_rsize_b - tsk_getu16(fs->endian,
2741 mft->attr_off), a_fs_file->meta->addr,
2742 NULL)) != TSK_OK) {
2743 return retval;
2744 }
2745
2746 /* The entry has been 'used' if it has attributes */
2747
2748 if ((a_fs_file->meta->attr == NULL)
2749 || (a_fs_file->meta->attr->head == NULL)
2750 || ((a_fs_file->meta->attr->head->flags & TSK_FS_ATTR_INUSE) == 0))
2751 a_fs_file->meta->flags |= TSK_FS_META_FLAG_UNUSED;
2752 else
2753 a_fs_file->meta->flags |= TSK_FS_META_FLAG_USED;
2754
2755 return TSK_OK;
2756 }
2757
2758
2759
2760 /** \internal
2761 * Load the attributes. In NTFS, the attributes are already loaded
2762 * so return error values based on current state.
2763 * @param a_fs_file File to load attributes for.
2764 * @returns 1 on error
2765 */
2766 static uint8_t
ntfs_load_attrs(TSK_FS_FILE * a_fs_file)2767 ntfs_load_attrs(TSK_FS_FILE * a_fs_file)
2768 {
2769 if ((a_fs_file == NULL) || (a_fs_file->meta == NULL)) {
2770 tsk_error_set_errno(TSK_ERR_FS_ARG);
2771 tsk_error_set_errstr("ntfs_load_attrs: called with NULL pointers");
2772 return 1;
2773 }
2774
2775 /* Verify the file has attributes */
2776 if (a_fs_file->meta->attr == NULL) {
2777 if (a_fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)
2778 tsk_error_set_errno(TSK_ERR_FS_RECOVER);
2779 else
2780 tsk_error_set_errno(TSK_ERR_FS_ARG);
2781 tsk_error_set_errstr("ntfs_load_attrs: attributes are NULL");
2782 return 1;
2783 }
2784 return 0;
2785 }
2786
2787 /**
2788 * Read an MFT entry and save it in the generic TSK_FS_META format.
2789 *
2790 * @param fs File system to read from.
2791 * @param mftnum Address of mft entry to read
2792 * @returns 1 on error
2793 */
2794 static uint8_t
ntfs_inode_lookup(TSK_FS_INFO * fs,TSK_FS_FILE * a_fs_file,TSK_INUM_T mftnum)2795 ntfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,
2796 TSK_INUM_T mftnum)
2797 {
2798 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
2799 char *mft;
2800 uint8_t allocedMeta = 0;
2801
2802 // clean up any error messages that are lying around
2803 tsk_error_reset();
2804
2805 if (a_fs_file == NULL) {
2806 tsk_error_set_errno(TSK_ERR_FS_ARG);
2807 tsk_error_set_errstr("ntfs_inode_lookup: fs_file is NULL");
2808 return 1;
2809 }
2810
2811 if (a_fs_file->meta == NULL) {
2812 a_fs_file->meta = tsk_fs_meta_alloc(NTFS_FILE_CONTENT_LEN);
2813 if (a_fs_file->meta == NULL)
2814 return 1;
2815 allocedMeta = 1;
2816 }
2817 else {
2818 tsk_fs_meta_reset(a_fs_file->meta);
2819 }
2820
2821 // see if they are looking for the special "orphans" directory
2822 if (mftnum == TSK_FS_ORPHANDIR_INUM(fs)) {
2823 if (tsk_fs_dir_make_orphan_dir_meta(fs, a_fs_file->meta))
2824 return 1;
2825 else
2826 return 0;
2827 }
2828
2829 if ((mft = (char *) tsk_malloc(ntfs->mft_rsize_b)) == NULL) {
2830 return 1;
2831 }
2832
2833 /* Lookup inode and store it in the ntfs structure */
2834 if (ntfs_dinode_lookup(ntfs, mft, mftnum) != TSK_OK) {
2835 free(mft);
2836 return 1;
2837 }
2838
2839 /* Copy the structure in ntfs to generic a_fs_file->meta */
2840 if (ntfs_dinode_copy(ntfs, a_fs_file, mft, mftnum) != TSK_OK) {
2841 free(mft);
2842 return 1;
2843 }
2844
2845 /* Check if the metadata is the same sequence as the name - if it was already set.
2846 * Note that this is not as efficient and elegant as desired, but works for now.
2847 * Better design would be to pass sequence into dinode_lookup and have a more
2848 * obvious way to pass the desired sequence in. fs_dir_walk_lcl sets the name
2849 * before calling this, which motivated this quick fix. */
2850 if ((a_fs_file->name != NULL) && (a_fs_file->name->meta_addr == mftnum)) {
2851
2852 /* NTFS Updates the sequence when an entry is deleted and not when
2853 * it is allocated. So, if we have a deleted MFT entry, then use
2854 * its previous sequence number to compare with the name so that we
2855 * still match them up (until the entry is allocated again). */
2856 uint16_t seqToCmp = a_fs_file->meta->seq;
2857 if (a_fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) {
2858 if (a_fs_file->meta->seq > 0)
2859 seqToCmp--;
2860 }
2861
2862 if (a_fs_file->name->meta_seq != seqToCmp) {
2863 if (allocedMeta) {
2864 tsk_fs_meta_close(a_fs_file->meta);
2865 a_fs_file->meta = NULL;
2866 }
2867 else {
2868 tsk_fs_meta_reset(a_fs_file->meta);
2869 }
2870 }
2871 }
2872
2873 free(mft);
2874 return 0;
2875 }
2876
2877
2878
2879
2880 /**********************************************************************
2881 *
2882 * Load special MFT structures into the NTFS_INFO structure
2883 *
2884 **********************************************************************/
2885
2886 /* The attrdef structure defines the types of attributes and gives a
2887 * name value to the type number.
2888 *
2889 * We currently do not use this during the analysis (Because it has not
2890 * historically changed, but we do display it in fsstat
2891 *
2892 * Return 1 on error and 0 on success
2893 */
2894 static uint8_t
ntfs_load_attrdef(NTFS_INFO * ntfs)2895 ntfs_load_attrdef(NTFS_INFO * ntfs)
2896 {
2897 TSK_FS_FILE *fs_file;
2898 const TSK_FS_ATTR *fs_attr;
2899 TSK_FS_INFO *fs = &ntfs->fs_info;
2900 TSK_FS_LOAD_FILE load_file;
2901
2902 /* if already loaded, return now */
2903 if (ntfs->attrdef)
2904 return 1;
2905
2906 if ((fs_file = tsk_fs_file_open_meta(fs, NULL, NTFS_MFT_ATTR)) == NULL)
2907 return 1;
2908
2909 fs_attr = tsk_fs_attrlist_get(fs_file->meta->attr, NTFS_ATYPE_DATA);
2910 if (!fs_attr) {
2911 //("Data attribute not found in $Attr");
2912 tsk_fs_file_close(fs_file);
2913 return 1;
2914 }
2915
2916 // @@@ We need to do a sanity check on the size of fs_attr->size
2917
2918 /* Get a copy of the attribute list stream using the above action */
2919 load_file.left = load_file.total = (size_t) fs_attr->size;
2920 load_file.base = load_file.cur = tsk_malloc((size_t) fs_attr->size);
2921 if (load_file.cur == NULL) {
2922 tsk_fs_file_close(fs_file);
2923 return 1;
2924 }
2925 ntfs->attrdef = (ntfs_attrdef *) load_file.base;
2926
2927 if (tsk_fs_attr_walk(fs_attr,
2928 0, tsk_fs_load_file_action, (void *) &load_file)) {
2929 tsk_error_errstr2_concat(" - load_attrdef");
2930 tsk_fs_file_close(fs_file);
2931 free(ntfs->attrdef);
2932 ntfs->attrdef = NULL;
2933 return 1;
2934 }
2935 else if (load_file.left > 0) {
2936 tsk_error_reset();
2937 tsk_error_set_errno(TSK_ERR_FS_FWALK);
2938 tsk_error_set_errstr
2939 ("load_attrdef: space still left after walking $Attr data");
2940 tsk_fs_file_close(fs_file);
2941 free(ntfs->attrdef);
2942 ntfs->attrdef = NULL;
2943 return 1;
2944 }
2945
2946 ntfs->attrdef_len = (size_t) fs_attr->size;
2947 tsk_fs_file_close(fs_file);
2948 return 0;
2949 }
2950
2951
2952 /*
2953 * return the name of the attribute type. If the attribute has not
2954 * been loaded yet, it will be.
2955 *
2956 * Return 1 on error and 0 on success
2957 */
2958 uint8_t
ntfs_attrname_lookup(TSK_FS_INFO * fs,uint16_t type,char * name,int len)2959 ntfs_attrname_lookup(TSK_FS_INFO * fs, uint16_t type, char *name, int len)
2960 {
2961 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
2962 ntfs_attrdef *attrdef;
2963 if (!ntfs->attrdef) {
2964 if (ntfs_load_attrdef(ntfs))
2965 return 1;
2966 }
2967
2968 attrdef = ntfs->attrdef;
2969 while (
2970 (((uintptr_t) attrdef - (uintptr_t) ntfs->attrdef +
2971 sizeof(ntfs_attrdef)) < ntfs->attrdef_len) &&
2972 (tsk_getu32(fs->endian, attrdef->type))) {
2973 if (tsk_getu32(fs->endian, attrdef->type) == type) {
2974
2975 UTF16 *name16 = (UTF16 *) attrdef->label;
2976 UTF8 *name8 = (UTF8 *) name;
2977 int retVal;
2978 retVal =
2979 tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
2980 (UTF16 *) ((uintptr_t) name16 +
2981 sizeof(attrdef->label)),
2982 &name8,
2983 (UTF8 *) ((uintptr_t) name8 + len), TSKlenientConversion);
2984 if (retVal != TSKconversionOK) {
2985 if (tsk_verbose)
2986 tsk_fprintf(stderr,
2987 "attrname_lookup: Error converting NTFS attribute def label to UTF8: %d",
2988 retVal);
2989 break;
2990 }
2991
2992 /* Make sure it is NULL Terminated */
2993 else if ((uintptr_t) name8 >= (uintptr_t) name + len)
2994 name[len - 1] = '\0';
2995 else
2996 *name8 = '\0';
2997 return 0;
2998 }
2999 attrdef++;
3000 }
3001 /* If we didn't find it, then call it '?' */
3002 snprintf(name, len, "?");
3003 return 0;
3004 }
3005
3006
3007 /* Load the block bitmap $Data run and allocate a buffer for a cache
3008 *
3009 * return 1 on error and 0 on success
3010 * */
3011 static uint8_t
ntfs_load_bmap(NTFS_INFO * ntfs)3012 ntfs_load_bmap(NTFS_INFO * ntfs)
3013 {
3014 ssize_t cnt = 0;
3015 ntfs_attr *attr = NULL;
3016 ntfs_attr *data_attr = NULL;
3017 TSK_FS_INFO *fs = NULL;
3018 ntfs_mft *mft = NULL;
3019
3020 if (ntfs == NULL) {
3021 goto on_error;
3022 }
3023 fs = &ntfs->fs_info;
3024
3025 if ((mft = (ntfs_mft *) tsk_malloc(ntfs->mft_rsize_b)) == NULL) {
3026 goto on_error;
3027 }
3028
3029 /* Get data on the bitmap */
3030 if (ntfs_dinode_lookup(ntfs, (char *) mft, NTFS_MFT_BMAP) != TSK_OK) {
3031 goto on_error;
3032 }
3033
3034 attr = (ntfs_attr *) ((uintptr_t) mft +
3035 tsk_getu16(fs->endian, mft->attr_off));
3036 data_attr = NULL;
3037
3038 /* cycle through them */
3039 while ((uintptr_t) attr + sizeof (ntfs_attr) <=
3040 ((uintptr_t) mft + (uintptr_t) ntfs->mft_rsize_b)) {
3041
3042 if ((tsk_getu32(fs->endian, attr->len) == 0) ||
3043 (tsk_getu32(fs->endian, attr->type) == 0xffffffff)) {
3044 break;
3045 }
3046
3047 if (tsk_getu32(fs->endian, attr->type) == NTFS_ATYPE_DATA) {
3048 data_attr = attr;
3049 break;
3050 }
3051
3052 attr =
3053 (ntfs_attr *) ((uintptr_t) attr + tsk_getu32(fs->endian,
3054 attr->len));
3055 }
3056
3057 /* did we get it? */
3058 if (data_attr == NULL) {
3059 tsk_error_reset();
3060 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
3061 tsk_error_set_errstr("Error Finding Bitmap Data Attribute");
3062 goto on_error;
3063 }
3064
3065 /* convert to generic form */
3066 if ((ntfs_make_data_run(ntfs,
3067 tsk_getu64(fs->endian, data_attr->c.nr.start_vcn),
3068 (ntfs_runlist
3069 *) ((uintptr_t) data_attr + tsk_getu16(fs->endian,
3070 data_attr->c.nr.run_off)), &(ntfs->bmap),
3071 NULL, NTFS_MFT_BMAP)) != TSK_OK) {
3072 goto on_error;
3073 }
3074 ntfs->bmap_buf = (char *) tsk_malloc(fs->block_size);
3075 if (ntfs->bmap_buf == NULL) {
3076 goto on_error;
3077 }
3078
3079 /* Load the first cluster so that we have something there */
3080 ntfs->bmap_buf_off = 0;
3081
3082 // Check ntfs->bmap before it is accessed.
3083 if (ntfs->bmap == NULL) {
3084 goto on_error;
3085 }
3086 if (ntfs->bmap->addr > fs->last_block) {
3087 tsk_error_reset();
3088 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3089 tsk_error_set_errstr
3090 ("ntfs_load_bmap: Bitmap too large for image size: %" PRIuDADDR
3091 "", ntfs->bmap->addr);
3092 goto on_error;
3093 }
3094 cnt =
3095 tsk_fs_read_block(fs,
3096 ntfs->bmap->addr, ntfs->bmap_buf, fs->block_size);
3097 if (cnt != fs->block_size) {
3098 if (cnt >= 0) {
3099 tsk_error_reset();
3100 tsk_error_set_errno(TSK_ERR_FS_READ);
3101 }
3102 tsk_error_set_errstr2("ntfs_load_bmap: Error reading block at %"
3103 PRIuDADDR, ntfs->bmap->addr);
3104 goto on_error;
3105 }
3106
3107 free (mft);
3108 return 0;
3109
3110 on_error:
3111 if (mft != NULL) {
3112 free (mft);
3113 }
3114 return 1;
3115 }
3116
3117
3118 /*
3119 * Load the VOLUME MFT entry and the VINFO attribute so that we
3120 * can identify the volume version of this.
3121 *
3122 * Return 1 on error and 0 on success
3123 */
3124 static uint8_t
ntfs_load_ver(NTFS_INFO * ntfs)3125 ntfs_load_ver(NTFS_INFO * ntfs)
3126 {
3127 TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
3128 TSK_FS_FILE *fs_file;
3129 const TSK_FS_ATTR *fs_attr;
3130
3131 if ((fs_file = tsk_fs_file_open_meta(fs, NULL, NTFS_MFT_VOL)) == NULL) {
3132 return 1;
3133 }
3134
3135 /* cache the data attribute */
3136 fs_attr = tsk_fs_attrlist_get(fs_file->meta->attr, NTFS_ATYPE_VINFO);
3137 if (!fs_attr) {
3138 tsk_error_reset();
3139 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
3140 tsk_error_set_errstr("Volume Info attribute not found in $Volume");
3141 tsk_fs_file_close(fs_file);
3142 return 1;
3143 }
3144
3145 if ((fs_attr->flags & TSK_FS_ATTR_RES)
3146 && (fs_attr->size)) {
3147 ntfs_attr_vinfo *vinfo = (ntfs_attr_vinfo *) fs_attr->rd.buf;
3148
3149 if ((vinfo->maj_ver == 1)
3150 && (vinfo->min_ver == 2)) {
3151 ntfs->ver = NTFS_VINFO_NT;
3152 }
3153 else if ((vinfo->maj_ver == 3)
3154 && (vinfo->min_ver == 0)) {
3155 ntfs->ver = NTFS_VINFO_2K;
3156 }
3157 else if ((vinfo->maj_ver == 3)
3158 && (vinfo->min_ver == 1)) {
3159 ntfs->ver = NTFS_VINFO_XP;
3160 }
3161 else {
3162 tsk_error_reset();
3163 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3164 tsk_error_set_errstr("unknown version: %d.%d\n",
3165 vinfo->maj_ver, vinfo->min_ver);
3166 tsk_fs_file_close(fs_file);
3167 return 1;
3168 }
3169 }
3170 else {
3171 tsk_error_reset();
3172 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3173 tsk_error_set_errstr
3174 ("load_version: VINFO is a non-resident attribute");
3175 return 1;
3176 }
3177
3178 tsk_fs_file_close(fs_file);
3179 return 0;
3180 }
3181
3182
3183 #if TSK_USE_SID
3184 /** \internal
3185 * Prints the value of sds into the a_sidstr string in ASCII form. This will allocate a new buffer for the
3186 * string, so a_sidstr should not point to a buffer. Output is in format of:
3187 * S-R-I-S-S... with 'R' being revision, 'I' being the identifier authority, and 'S' being subauthority values.
3188 *
3189 * @param a_fs File system
3190 * @param a_sds SDS
3191 * @param a_sidstr [out] Pointer that will be assigned to the buffer allocated by this function to store the string.
3192 * @returns 1 on error, 0 on success
3193 */
3194 static uint8_t
ntfs_sds_to_str(TSK_FS_INFO * a_fs,const ntfs_attr_sds * a_sds,char ** a_sidstr)3195 ntfs_sds_to_str(TSK_FS_INFO * a_fs, const ntfs_attr_sds * a_sds,
3196 char **a_sidstr)
3197 {
3198 ntfs_sid *sid = NULL;
3199
3200 uint32_t owner_offset;
3201 *a_sidstr = NULL;
3202
3203 if ((a_fs == NULL) || (a_sds == NULL) || (a_sidstr == NULL)) {
3204 tsk_error_reset();
3205 tsk_error_set_errno(TSK_ERR_FS_ARG);
3206 tsk_error_set_errstr("Invalid argument");
3207 return 1;
3208 }
3209
3210 owner_offset =
3211 tsk_getu32(a_fs->endian, a_sds->self_rel_sec_desc.owner);
3212
3213 if (((uintptr_t) & a_sds->self_rel_sec_desc + owner_offset) >
3214 ((uintptr_t) a_sds + tsk_getu32(a_fs->endian, a_sds->ent_size))) {
3215 tsk_error_reset();
3216 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
3217 tsk_error_set_errstr
3218 ("ntfs_sds_to_str: owner offset larger than a_sds length");
3219 return 1;
3220 }
3221
3222 sid =
3223 (ntfs_sid *) ((uint8_t *) & a_sds->self_rel_sec_desc +
3224 owner_offset);
3225
3226 //tsk_fprintf(stderr, "Revision: %i\n", sid->revision);
3227
3228 // This check helps not process invalid data, which was noticed while testing
3229 // a failing harddrive
3230 if (sid->revision == 1) {
3231 uint64_t authority = 0;
3232 int i, len;
3233 char *sid_str_offset = NULL;
3234 char *sid_str = NULL;
3235 unsigned int sid_str_len;
3236
3237 //tsk_fprintf(stderr, "Sub-Authority Count: %i\n", sid->sub_auth_count);
3238 authority = 0;
3239 for (i = 0; i < 6; i++)
3240 authority += (uint64_t) sid->ident_auth[i] << ((5 - i) * 8);
3241
3242 //tsk_fprintf(stderr, "NT Authority: %" PRIu64 "\n", authority);
3243
3244 // "S-1-AUTH-SUBAUTH-SUBAUTH..."
3245 sid_str_len = 4 + 13 + (1 + 10) * sid->sub_auth_count + 1;
3246
3247 // Allocate the buffer for the string representation of the SID.
3248 if ((sid_str = (char *) tsk_malloc(sid_str_len)) == NULL) {
3249 return 1;
3250 }
3251
3252 len = sprintf(sid_str, "S-1-%" PRIu64, authority);
3253 sid_str_offset = sid_str + len;
3254
3255 for (i = 0; i < sid->sub_auth_count; i++) {
3256 len = sprintf(sid_str_offset, "-%" PRIu32, sid->sub_auth[i]);
3257 sid_str_offset += len;
3258 }
3259 *a_sidstr = sid_str;
3260 //tsk_fprintf(stderr, "SID: %s\n", sid_str);
3261 }
3262 else {
3263 tsk_error_reset();
3264 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3265 tsk_error_set_errstr("ntfs_sds_to_str: Invalid SID revision (%d)",
3266 sid->revision);
3267 return 1; // Invalid revision number in the SID.
3268 }
3269
3270 return 0;
3271 }
3272
3273
3274
3275
3276 /** \internal
3277 * Maps a security id value from a file to its SDS structure
3278 *
3279 * Note: This routine assumes &ntfs->sid_lock is locked by the caller.
3280 *
3281 * @param fs File system
3282 * @param secid Security Id to find SDS for.
3283 * @returns NULL on error
3284 */
3285 static const ntfs_attr_sds *
ntfs_get_sds(TSK_FS_INFO * fs,uint32_t secid)3286 ntfs_get_sds(TSK_FS_INFO * fs, uint32_t secid)
3287 {
3288 uint32_t i = 0;
3289 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
3290 ntfs_attr_sii *sii = NULL;
3291 ntfs_attr_sds *sds = NULL;
3292 uint32_t sii_secid = 0;
3293 uint32_t sds_secid = 0;
3294 uint32_t sii_sechash = 0;
3295 uint32_t sds_sechash = 0;
3296 uint64_t sds_file_off = 0;
3297 //uint32_t sds_ent_size = 0;
3298 uint64_t sii_sds_file_off = 0;
3299 uint32_t sii_sds_ent_size = 0;
3300
3301
3302 if ((fs == NULL) || (secid == 0)) {
3303 tsk_error_reset();
3304 tsk_error_set_errno(TSK_ERR_FS_ARG);
3305 tsk_error_set_errstr("Invalid argument");
3306 return NULL;
3307 }
3308
3309
3310 // Loop through all the SII entries looking for the security id matching that found in the file.
3311 // This lookup is obviously O(n^2) for all n files. However, since so many files have the exact
3312 // same security identifier, it is not really that bad. In reality, 100,000 files may only map to
3313 // 10,000 security identifiers. Since SII entries are 0x28 bytes each and security identifiers
3314 // increase incrementally, we could go directly to the entry in question ((secid * 0x28) + 256).
3315 // SII entries started at 256 on Vista; however, I did not look at the starting secid for other
3316 // versions of NTFS.
3317 for (i = 0; i < ntfs->sii_data.used; i++) {
3318 if (tsk_getu32(fs->endian,
3319 ((ntfs_attr_sii *) (ntfs->sii_data.buffer))[i].
3320 key_sec_id) == secid) {
3321 sii = &((ntfs_attr_sii *) (ntfs->sii_data.buffer))[i];
3322 break;
3323 }
3324 }
3325
3326 if (sii == NULL) {
3327 tsk_error_reset();
3328 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3329 tsk_error_set_errstr("ntfs_get_sds: SII entry not found (%" PRIu32
3330 ")", secid);
3331 return NULL;
3332 }
3333
3334 sii_secid = tsk_getu32(fs->endian, sii->key_sec_id);
3335 sii_sechash = tsk_getu32(fs->endian, sii->data_hash_sec_desc);
3336 sii_sds_file_off = tsk_getu64(fs->endian, sii->sec_desc_off);
3337 sii_sds_ent_size = tsk_getu32(fs->endian, sii->sec_desc_size);
3338
3339 // Check that we do not go out of bounds.
3340 if ((uint32_t) sii_sds_file_off > ntfs->sds_data.size) {
3341 tsk_error_reset();
3342 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3343 tsk_error_set_errstr("ntfs_get_sds: SII offset too large (%" PRIu64
3344 ")", sii_sds_file_off);
3345 return NULL;
3346 }
3347 else if (!sii_sds_ent_size) {
3348 tsk_error_reset();
3349 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3350 tsk_error_set_errstr("ntfs_get_sds: SII entry size is invalid (%"
3351 PRIu32 ")", sii_sds_ent_size);
3352 return NULL;
3353 }
3354
3355 sds =
3356 (ntfs_attr_sds *) ((uint8_t *) ntfs->sds_data.buffer +
3357 sii_sds_file_off);
3358 sds_secid = tsk_getu32(fs->endian, sds->sec_id);
3359 sds_sechash = tsk_getu32(fs->endian, sds->hash_sec_desc);
3360 sds_file_off = tsk_getu64(fs->endian, sds->file_off);
3361 //sds_ent_size = tsk_getu32(fs->endian, sds->ent_size);
3362
3363 // Sanity check to make sure the $SII entry points to
3364 // the correct $SDS entry.
3365 if ((sds_secid == sii_secid) &&
3366 (sds_sechash == sii_sechash) && (sds_file_off == sii_sds_file_off)
3367 //&& (sds_ent_size == sii_sds_ent_size)
3368 ) {
3369 return sds;
3370 }
3371 else {
3372 if (tsk_verbose)
3373 tsk_fprintf(stderr,
3374 "ntfs_get_sds: entry found was for wrong Security ID (%"
3375 PRIu32 " vs %" PRIu32 ")\n", sds_secid, sii_secid);
3376
3377 // if (sii_secid != 0) {
3378
3379 // There is obviously a mismatch between the information in the SII entry and that in the SDS entry.
3380 // After looking at these mismatches, it appears there is not a pattern. Perhaps some entries have been reused.
3381
3382 //printf("\nsecid %d hash %x offset %I64x size %x\n", sii_secid, sii_sechash, sii_sds_file_off, sii_sds_ent_size);
3383 //printf("secid %d hash %x offset %I64x size %x\n", sds_secid, sds_sechash, sds_file_off, sds_ent_size);
3384 // }
3385 }
3386
3387 tsk_error_reset();
3388 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3389 tsk_error_set_errstr("ntfs_get_sds: Got to end w/out data");
3390 return NULL;
3391 }
3392 #endif
3393
3394 /** \internal
3395 * NTFS-specific function (pointed to in FS_INFO) that maps a security ID
3396 * to an ASCII printable string.
3397 * Read the contents of the STANDARD_INFORMATION attribute of a file
3398 * to get the security id. Once we have the security id, we will
3399 * search $Secure:$SII to find a matching security id. That $SII entry
3400 * will contain the offset within the $SDS stream for the $SDS entry,
3401 * which contains the owner SID
3402 *
3403 * @param a_fs_file File to get security info on
3404 * @param sid_str [out] location where string representation of security info will be stored.
3405 Caller must free the string.
3406 * @returns 1 on error
3407 */
3408 static uint8_t
ntfs_file_get_sidstr(TSK_FS_FILE * a_fs_file,char ** sid_str)3409 ntfs_file_get_sidstr(TSK_FS_FILE * a_fs_file, char **sid_str)
3410 {
3411 #if TSK_USE_SID
3412 const TSK_FS_ATTR *fs_data;
3413 ntfs_attr_si *si;
3414 const ntfs_attr_sds *sds;
3415 NTFS_INFO *ntfs = (NTFS_INFO *) a_fs_file->fs_info;
3416
3417 *sid_str = NULL;
3418
3419 if (!a_fs_file->meta->attr) {
3420 tsk_error_reset();
3421 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3422 tsk_error_set_errstr
3423 ("ntfs_file_get_sidstr: file argument has no meta data");
3424 return 1;
3425 }
3426
3427 // Read STANDARD_INFORMATION attribute for the security id of the file.
3428 fs_data = tsk_fs_attrlist_get(a_fs_file->meta->attr,
3429 TSK_FS_ATTR_TYPE_NTFS_SI);
3430 if (!fs_data) {
3431 tsk_error_set_errstr2("- ntfs_file_get_sidstr:SI attribute");
3432 return 1;
3433 }
3434
3435 si = (ntfs_attr_si *) fs_data->rd.buf;
3436 if (!si) {
3437 tsk_error_reset();
3438 tsk_error_set_errno(TSK_ERR_FS_GENFS);
3439 tsk_error_set_errstr("ntfs_file_get_sidstr: SI buf is NULL");
3440 return 1;
3441 }
3442
3443 tsk_take_lock(&ntfs->sid_lock);
3444 // sds points inside ntfs->sds_data, which we've just locked
3445 sds =
3446 ntfs_get_sds(a_fs_file->fs_info,
3447 tsk_getu32(a_fs_file->fs_info->endian, si->sec_id));
3448 if (!sds) {
3449 tsk_release_lock(&ntfs->sid_lock);
3450 tsk_error_set_errstr2("- ntfs_file_get_sidstr:SI attribute");
3451 return 1;
3452 }
3453 if (ntfs_sds_to_str(a_fs_file->fs_info, sds, sid_str)) {
3454 tsk_release_lock(&ntfs->sid_lock);
3455 tsk_error_set_errstr2("- ntfs_file_get_sidstr:SI attribute");
3456 return 1;
3457 }
3458 tsk_release_lock(&ntfs->sid_lock);
3459 return 0;
3460 #else
3461 *sid_str = NULL;
3462 tsk_error_reset();
3463 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
3464 tsk_error_set_errstr("Unsupported function");
3465 return 1;
3466 #endif
3467 }
3468
3469
3470 #if TSK_USE_SID
3471 /** \internal
3472 * Process all the $SII entries into a single array by removing all the Attribute Headers.
3473 * Note: This routine assumes &ntfs->sid_lock is locked by the caller.
3474 * @param fs File system structure to store results into
3475 * @param sii_buffer Buffer of raw $SII entries to parse
3476 */
3477 static void
ntfs_proc_sii(TSK_FS_INFO * fs,NTFS_SXX_BUFFER * sii_buffer)3478 ntfs_proc_sii(TSK_FS_INFO * fs, NTFS_SXX_BUFFER * sii_buffer)
3479 {
3480 unsigned int sii_buffer_offset = 0;
3481 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
3482 ntfs_attr_sii *sii;
3483
3484 if ((fs == NULL) || (sii_buffer == NULL)
3485 || (ntfs->sii_data.buffer == NULL))
3486 return;
3487
3488 /* Loop by cluster size */
3489 for (sii_buffer_offset = 0; sii_buffer_offset < sii_buffer->size;
3490 sii_buffer_offset += ntfs->idx_rsize_b) {
3491
3492 uintptr_t idx_buffer_end = 0;
3493
3494 ntfs_idxrec *idxrec =
3495 (ntfs_idxrec *) & sii_buffer->buffer[sii_buffer_offset];
3496
3497 // stop processing if we hit corrupt data
3498 if (tsk_getu32(fs->endian, idxrec->list.begin_off) > ntfs->idx_rsize_b) {
3499 if (tsk_verbose)
3500 tsk_fprintf(stderr, "ntfs_proc_sii: corrupt offset\n");
3501 break;
3502 }
3503 else if (tsk_getu32(fs->endian, idxrec->list.bufend_off) > ntfs->idx_rsize_b) {
3504 if (tsk_verbose)
3505 tsk_fprintf(stderr, "ntfs_proc_sii: corrupt offset\n");
3506 break;
3507 }
3508 else if (tsk_getu32(fs->endian, idxrec->list.begin_off) > tsk_getu32(fs->endian, idxrec->list.bufend_off)) {
3509 if (tsk_verbose)
3510 tsk_fprintf(stderr, "ntfs_proc_sii: corrupt offset\n");
3511 break;
3512 }
3513
3514 // get pointer to first record
3515 sii =
3516 (ntfs_attr_sii *) ((uintptr_t) & idxrec->list +
3517 tsk_getu32(fs->endian, idxrec->list.begin_off));
3518
3519 // where last record ends
3520 idx_buffer_end = (uintptr_t) & idxrec->list +
3521 tsk_getu32(fs->endian, idxrec->list.bufend_off);
3522
3523
3524 // copy records into NTFS_INFO
3525 while ((uintptr_t)sii + sizeof(ntfs_attr_sii) <= idx_buffer_end) {
3526 /*
3527 if ((tsk_getu16(fs->endian,sii->size) == 0x14) &&
3528 (tsk_getu16(fs->endian,sii->data_off) == 0x14) &&
3529 (tsk_getu16(fs->endian,sii->ent_size) == 0x28)
3530 )
3531 {
3532 */
3533 /* make sure we don't go over bounds of ntfs->sii_data.buffer */
3534 if ((ntfs->sii_data.used + 1) * sizeof(ntfs_attr_sii) > ntfs->sii_data.size) {
3535 if (tsk_verbose)
3536 tsk_fprintf(stderr, "ntfs_proc_sii: data buffer too small\n");
3537 return; // reached end of ntfs->sii_data.buffer
3538 }
3539
3540 memcpy(ntfs->sii_data.buffer +
3541 (ntfs->sii_data.used * sizeof(ntfs_attr_sii)), sii,
3542 sizeof(ntfs_attr_sii));
3543 ntfs->sii_data.used++;
3544
3545 /*
3546 printf("Security id %d is at offset 0x%I64x for 0x%x bytes\n", tsk_getu32(fs->endian,sii->key_sec_id),
3547 tsk_getu64(fs->endian,sii->sec_desc_off),
3548 tsk_getu32(fs->endian,sii->sec_desc_size));
3549 }
3550 else
3551 {
3552 printf("\n\tOffset to data %x Size of data %x Size of Index entry %x\n", tsk_getu16(fs->endian,sii->data_off),
3553 tsk_getu16(fs->endian,sii->size),
3554 tsk_getu16(fs->endian,sii->ent_size));
3555 printf("\tSecurity id %d is at offset 0x%I64x for 0x%x bytes\n\n", tsk_getu32(fs->endian,sii->key_sec_id),
3556 tsk_getu64(fs->endian,sii->sec_desc_off),
3557 tsk_getu32(fs->endian,sii->sec_desc_size));
3558 }
3559 */
3560 sii++;
3561 }
3562 }
3563 }
3564
3565
3566 /*
3567 * Load the $Secure attributes so that we can identify the user.
3568 *
3569 * Note: This routine is called only from ntfs_open and therefore does
3570 * not need to lock ntfs->sid_lock.
3571 *
3572 * @returns 1 on error (which occurs only if malloc or other system error).
3573 */
3574 static uint8_t
ntfs_load_secure(NTFS_INFO * ntfs)3575 ntfs_load_secure(NTFS_INFO * ntfs)
3576 {
3577 TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info;
3578 TSK_FS_META *fs_meta = NULL;
3579 const TSK_FS_ATTR *fs_attr_sds = NULL;
3580 const TSK_FS_ATTR *fs_attr_sii = NULL;
3581 NTFS_SXX_BUFFER sii_buffer;
3582 TSK_FS_FILE *secure = NULL;
3583 ssize_t cnt;
3584
3585 ntfs->sii_data.buffer = NULL;
3586 ntfs->sii_data.size = 0;
3587 ntfs->sii_data.used = 0;
3588 ntfs->sds_data.buffer = NULL;
3589 ntfs->sds_data.size = 0;
3590 ntfs->sds_data.used = 0;
3591
3592
3593 // Open $Secure. The $SDS stream contains all the security descriptors
3594 // and is indexed by $SII and $SDH.
3595 secure = tsk_fs_file_open_meta(fs, NULL, NTFS_MFT_SECURE);
3596 if (!secure) {
3597 if (tsk_verbose)
3598 tsk_fprintf(stderr,
3599 "ntfs_load_secure: error opening $Secure file: %s\n",
3600 tsk_error_get_errstr());
3601 tsk_error_reset();
3602 return 0;
3603 }
3604
3605 // Make sure the TSK_FS_META is not NULL. We need it to get the
3606 // $SII and $SDH attributes.
3607 fs_meta = secure->meta;
3608 if (!fs_meta) {
3609 if (tsk_verbose)
3610 tsk_fprintf(stderr,
3611 "ntfs_load_secure: $Secure file has no attributes\n");
3612 tsk_error_reset();
3613 tsk_fs_file_close(secure);
3614 return 0;
3615 }
3616
3617 // Get the $SII attribute.
3618 fs_attr_sii =
3619 tsk_fs_attrlist_get_name_type(fs_meta->attr, NTFS_ATYPE_IDXALLOC,
3620 "$SII\0");
3621 if (!fs_attr_sii) {
3622 if (tsk_verbose)
3623 tsk_fprintf(stderr,
3624 "ntfs_load_secure: error getting $Secure:$SII IDX_ALLOC attribute\n");
3625 tsk_error_reset();
3626 tsk_fs_file_close(secure);
3627 return 0;
3628
3629 }
3630
3631 // Get the $SDS attribute.
3632 fs_attr_sds = tsk_fs_attrlist_get(fs_meta->attr, NTFS_ATYPE_DATA);
3633 if (!fs_attr_sds) {
3634 if (tsk_verbose)
3635 tsk_fprintf(stderr,
3636 "ntfs_load_secure: error getting $Secure:$SDS $Data attribute\n");
3637 tsk_error_reset();
3638 tsk_fs_file_close(secure);
3639 return 0;
3640 }
3641
3642 /* First we read in $SII to a local buffer adn then process it into NTFS_INFO */
3643
3644 // Allocate local space for the entire $SII stream.
3645 sii_buffer.size = (size_t) roundup(fs_attr_sii->size, fs->block_size);
3646 sii_buffer.used = 0;
3647
3648 // arbitrary check because we had problems before with alloc too much memory
3649 if (sii_buffer.size > 64000000) {
3650 if (tsk_verbose)
3651 tsk_fprintf(stderr,
3652 "ntfs_load_secure: sii_buffer.size is too large: %z\n",
3653 sii_buffer.size);
3654 return 0;
3655 }
3656 if ((sii_buffer.buffer = tsk_malloc(sii_buffer.size)) == NULL) {
3657 return 1;
3658 }
3659
3660 // Read in the raw $SII stream.
3661 cnt =
3662 tsk_fs_attr_read(fs_attr_sii, 0, sii_buffer.buffer,
3663 sii_buffer.size, TSK_FS_FILE_READ_FLAG_NONE);
3664 if (cnt != (ssize_t)sii_buffer.size) {
3665 if (tsk_verbose)
3666 tsk_fprintf(stderr,
3667 "ntfs_load_secure: error reading $Secure:$SII attribute: %s\n",
3668 tsk_error_get_errstr());
3669 tsk_error_reset();
3670
3671 free(sii_buffer.buffer);
3672 tsk_fs_file_close(secure);
3673 return 0;
3674 }
3675
3676 // allocate the structure for the processed version of the data
3677 ntfs->sii_data.used = 0; // use this to count the number of $SII entries
3678 if ((ntfs->sii_data.buffer =
3679 (char *) tsk_malloc(sii_buffer.size)) == NULL) {
3680 free(sii_buffer.buffer);
3681 tsk_fs_file_close(secure);
3682 return 1;
3683 }
3684 ntfs->sii_data.size = sii_buffer.size;
3685
3686 // parse sii_buffer into ntfs->sii_data.
3687 ntfs_proc_sii(fs, &sii_buffer);
3688 free(sii_buffer.buffer);
3689
3690
3691 /* Now we copy $SDS into NTFS_INFO. We do not do any processing in this step. */
3692
3693 // Allocate space for the entire $SDS stream with all the security
3694 // descriptors. We should be able to use the $SII offset to index
3695 // into the $SDS stream.
3696 ntfs->sds_data.size = (size_t) fs_attr_sds->size;
3697 // arbitrary check because we had problems before with alloc too much memory
3698 if (ntfs->sds_data.size > 64000000) {
3699 if (tsk_verbose)
3700 tsk_fprintf(stderr,
3701 "ntfs_load_secure: ntfs->sds_data.size is too large: %z\n",
3702 ntfs->sds_data.size);
3703 free(ntfs->sii_data.buffer);
3704 ntfs->sii_data.buffer = NULL;
3705 ntfs->sii_data.used = 0;
3706 ntfs->sii_data.size = 0;
3707 tsk_fs_file_close(secure);
3708
3709 return 0;
3710 }
3711 ntfs->sds_data.used = 0;
3712 if ((ntfs->sds_data.buffer =
3713 (char *) tsk_malloc(ntfs->sds_data.size)) == NULL) {
3714 free(ntfs->sii_data.buffer);
3715 ntfs->sii_data.buffer = NULL;
3716 ntfs->sii_data.used = 0;
3717 ntfs->sii_data.size = 0;
3718 tsk_fs_file_close(secure);
3719 return 1;
3720 }
3721
3722 // Read in the raw $SDS ($DATA) stream.
3723 cnt =
3724 tsk_fs_attr_read(fs_attr_sds, 0,
3725 ntfs->sds_data.buffer, ntfs->sds_data.size,
3726 TSK_FS_FILE_READ_FLAG_NONE);
3727 if (cnt != (ssize_t)ntfs->sds_data.size) {
3728 if (tsk_verbose)
3729 tsk_fprintf(stderr,
3730 "ntfs_load_secure: error reading $Secure:$SDS attribute: %s\n",
3731 tsk_error_get_errstr());
3732 tsk_error_reset();
3733
3734 free(ntfs->sii_data.buffer);
3735 ntfs->sii_data.buffer = NULL;
3736 ntfs->sii_data.used = 0;
3737 ntfs->sii_data.size = 0;
3738 free(ntfs->sds_data.buffer);
3739 ntfs->sds_data.buffer = NULL;
3740 ntfs->sds_data.used = 0;
3741 ntfs->sds_data.size = 0;
3742 tsk_fs_file_close(secure);
3743 return 0;
3744 }
3745
3746 tsk_fs_file_close(secure);
3747 return 0;
3748 }
3749
3750 #endif
3751
3752 /**********************************************************************
3753 *
3754 * Exported Walk Functions
3755 *
3756 **********************************************************************/
3757
3758
3759 static TSK_FS_BLOCK_FLAG_ENUM
ntfs_block_getflags(TSK_FS_INFO * a_fs,TSK_DADDR_T a_addr)3760 ntfs_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr)
3761 {
3762 NTFS_INFO *ntfs = (NTFS_INFO *) a_fs;
3763 int retval;
3764 int flags = 0;
3765
3766 /* identify if the cluster is allocated or not */
3767 retval = is_clustalloc(ntfs, a_addr);
3768 if (retval == 1)
3769 flags = TSK_FS_BLOCK_FLAG_ALLOC;
3770 else if (retval == 0)
3771 flags = TSK_FS_BLOCK_FLAG_UNALLOC;
3772
3773 return flags;
3774 }
3775
3776
3777
3778 /*
3779 * flags: TSK_FS_BLOCK_FLAG_ALLOC and FS_FLAG_UNALLOC
3780 *
3781 * @@@ We should probably consider some data META, but it is tough with
3782 * the NTFS design ...
3783 */
3784 static uint8_t
ntfs_block_walk(TSK_FS_INFO * fs,TSK_DADDR_T a_start_blk,TSK_DADDR_T a_end_blk,TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags,TSK_FS_BLOCK_WALK_CB a_action,void * a_ptr)3785 ntfs_block_walk(TSK_FS_INFO * fs,
3786 TSK_DADDR_T a_start_blk, TSK_DADDR_T a_end_blk,
3787 TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags, TSK_FS_BLOCK_WALK_CB a_action,
3788 void *a_ptr)
3789 {
3790 char *myname = "ntfs_block_walk";
3791 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
3792 TSK_DADDR_T addr;
3793 TSK_FS_BLOCK *fs_block;
3794
3795 // clean up any error messages that are lying around
3796 tsk_error_reset();
3797
3798 /*
3799 * Sanity checks.
3800 */
3801 if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) {
3802 tsk_error_reset();
3803 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
3804 tsk_error_set_errstr("%s: start block: %" PRIuDADDR "", myname,
3805 a_start_blk);
3806 return 1;
3807 }
3808 else if (a_end_blk < fs->first_block || a_end_blk > fs->last_block) {
3809 tsk_error_reset();
3810 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
3811 tsk_error_set_errstr("%s: last block: %" PRIuDADDR "", myname,
3812 a_end_blk);
3813 return 1;
3814 }
3815
3816 /* Sanity check on a_flags -- make sure at least one ALLOC is set */
3817 if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) &&
3818 ((a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) {
3819 a_flags |=
3820 (TSK_FS_BLOCK_WALK_FLAG_ALLOC |
3821 TSK_FS_BLOCK_WALK_FLAG_UNALLOC);
3822 }
3823 if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_META) == 0) &&
3824 ((a_flags & TSK_FS_BLOCK_WALK_FLAG_CONT) == 0)) {
3825 a_flags |=
3826 (TSK_FS_BLOCK_WALK_FLAG_CONT | TSK_FS_BLOCK_WALK_FLAG_META);
3827 }
3828
3829
3830 if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) {
3831 return 1;
3832 }
3833
3834 /* Cycle through the blocks */
3835 for (addr = a_start_blk; addr <= a_end_blk; addr++) {
3836 int retval;
3837 int myflags;
3838
3839 /* identify if the cluster is allocated or not */
3840 retval = is_clustalloc(ntfs, addr);
3841 if (retval == -1) {
3842 tsk_fs_block_free(fs_block);
3843 return 1;
3844 }
3845
3846 else if (retval == 1) {
3847 myflags = TSK_FS_BLOCK_FLAG_ALLOC;
3848 }
3849 else {
3850 myflags = TSK_FS_BLOCK_FLAG_UNALLOC;
3851 }
3852
3853 // test if we should call the callback with this one
3854 if ((myflags & TSK_FS_BLOCK_FLAG_ALLOC)
3855 && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC)))
3856 continue;
3857 else if ((myflags & TSK_FS_BLOCK_FLAG_UNALLOC)
3858 && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC)))
3859 continue;
3860
3861 if (a_flags & TSK_FS_BLOCK_WALK_FLAG_AONLY)
3862 myflags |= TSK_FS_BLOCK_FLAG_AONLY;
3863
3864 if (tsk_fs_block_get_flag(fs, fs_block, addr,
3865 (TSK_FS_BLOCK_FLAG_ENUM) myflags) == NULL) {
3866 tsk_error_set_errstr2
3867 ("ntfs_block_walk: Error reading block at %" PRIuDADDR,
3868 addr);
3869 tsk_fs_block_free(fs_block);
3870 return 1;
3871 }
3872
3873 retval = a_action(fs_block, a_ptr);
3874 if (retval == TSK_WALK_STOP) {
3875 break;
3876 }
3877 else if (retval == TSK_WALK_ERROR) {
3878 tsk_fs_block_free(fs_block);
3879 return 1;
3880 }
3881 }
3882
3883 tsk_fs_block_free(fs_block);
3884 return 0;
3885 }
3886
3887
3888
3889 /*
3890 * inode_walk
3891 *
3892 * Flags: TSK_FS_META_FLAG_ALLOC, TSK_FS_META_FLAG_UNALLOC,
3893 * TSK_FS_META_FLAG_USED, TSK_FS_META_FLAG_UNUSED, TSK_FS_META_FLAG_ORPHAN
3894 *
3895 * Note that with ORPHAN, entries will be found that can also be
3896 * found by searching based on parent directories (if parent directory is
3897 * known)
3898 */
3899 static uint8_t
ntfs_inode_walk(TSK_FS_INFO * fs,TSK_INUM_T start_inum,TSK_INUM_T end_inum,TSK_FS_META_FLAG_ENUM flags,TSK_FS_META_WALK_CB a_action,void * ptr)3900 ntfs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum,
3901 TSK_INUM_T end_inum, TSK_FS_META_FLAG_ENUM flags,
3902 TSK_FS_META_WALK_CB a_action, void *ptr)
3903 {
3904 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
3905 unsigned int myflags;
3906 TSK_INUM_T mftnum;
3907 TSK_FS_FILE *fs_file;
3908 TSK_INUM_T end_inum_tmp;
3909 ntfs_mft *mft;
3910 /*
3911 * Sanity checks.
3912 */
3913 if (start_inum < fs->first_inum) {
3914 tsk_error_reset();
3915 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
3916 tsk_error_set_errstr
3917 ("inode_walk: Starting inode number is too small (%" PRIuINUM
3918 ")", start_inum);
3919 return 1;
3920 }
3921 if (start_inum > fs->last_inum) {
3922 tsk_error_reset();
3923 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
3924 tsk_error_set_errstr
3925 ("inode_walk: Starting inode number is too large (%" PRIuINUM
3926 ")", start_inum);
3927 return 1;
3928 }
3929 if (end_inum < fs->first_inum) {
3930 tsk_error_reset();
3931 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
3932 tsk_error_set_errstr
3933 ("inode_walk: Ending inode number is too small (%" PRIuINUM
3934 ")", end_inum);
3935 return 1;
3936 }
3937 if (end_inum > fs->last_inum) {
3938 tsk_error_reset();
3939 tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
3940 tsk_error_set_errstr("Ending inode number is too large (%" PRIuINUM
3941 ")", end_inum);
3942 return 1;
3943 }
3944
3945
3946 /* If ORPHAN is wanted, then make sure that the flags are correct */
3947 if (flags & TSK_FS_META_FLAG_ORPHAN) {
3948 flags |= TSK_FS_META_FLAG_UNALLOC;
3949 flags &= ~TSK_FS_META_FLAG_ALLOC;
3950 flags |= TSK_FS_META_FLAG_USED;
3951 flags &= ~TSK_FS_META_FLAG_UNUSED;
3952 }
3953
3954 else {
3955 if (((flags & TSK_FS_META_FLAG_ALLOC) == 0) &&
3956 ((flags & TSK_FS_META_FLAG_UNALLOC) == 0)) {
3957 flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC);
3958 }
3959
3960 /* If neither of the USED or UNUSED flags are set, then set them
3961 * both
3962 */
3963 if (((flags & TSK_FS_META_FLAG_USED) == 0) &&
3964 ((flags & TSK_FS_META_FLAG_UNUSED) == 0)) {
3965 flags |= (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_UNUSED);
3966 }
3967 }
3968
3969
3970 /* If we are looking for orphan files and have not yet filled
3971 * in the list of unalloc inodes that are pointed to, then fill
3972 * in the list
3973 * */
3974 if ((flags & TSK_FS_META_FLAG_ORPHAN)) {
3975 if (tsk_fs_dir_load_inum_named(fs) != TSK_OK) {
3976 tsk_error_errstr2_concat
3977 ("- ntfs_inode_walk: identifying inodes allocated by file names");
3978 return 1;
3979 }
3980 }
3981
3982 if ((fs_file = tsk_fs_file_alloc(fs)) == NULL)
3983 return 1;
3984
3985 if ((fs_file->meta = tsk_fs_meta_alloc(NTFS_FILE_CONTENT_LEN)) == NULL) {
3986 // JRB: Coverity CID: 348
3987 if (fs_file)
3988 tsk_fs_file_close(fs_file);
3989 return 1;
3990 }
3991
3992 if ((mft = (ntfs_mft *) tsk_malloc(ntfs->mft_rsize_b)) == NULL) {
3993 tsk_fs_file_close(fs_file);
3994 return 1;
3995 }
3996 // we need to handle fs->last_inum specially because it is for the
3997 // virtual ORPHANS directory. Handle it outside of the loop.
3998 if (end_inum == TSK_FS_ORPHANDIR_INUM(fs))
3999 end_inum_tmp = end_inum - 1;
4000 else
4001 end_inum_tmp = end_inum;
4002
4003
4004 for (mftnum = start_inum; mftnum <= end_inum_tmp; mftnum++) {
4005 int retval;
4006 TSK_RETVAL_ENUM retval2;
4007
4008 /* read MFT entry in to NTFS_INFO */
4009 if ((retval2 =
4010 ntfs_dinode_lookup(ntfs, (char *) mft,
4011 mftnum)) != TSK_OK) {
4012 // if the entry is corrupt, then skip to the next one
4013 if (retval2 == TSK_COR) {
4014 if (tsk_verbose)
4015 tsk_error_print(stderr);
4016 tsk_error_reset();
4017 continue;
4018 }
4019 tsk_fs_file_close(fs_file);
4020 free(mft);
4021 return 1;
4022 }
4023
4024 /* we only want to look at base file records
4025 * (extended are because the base could not fit into one)
4026 */
4027 if (tsk_getu48(fs->endian, mft->base_ref) != NTFS_MFT_BASE)
4028 continue;
4029
4030 /* NOTE: We could add a sanity check here with the MFT bitmap
4031 * to validate of the INUSE flag and bitmap are in agreement
4032 */
4033 /* check flags */
4034 myflags =
4035 ((tsk_getu16(fs->endian, mft->flags) &
4036 NTFS_MFT_INUSE) ? TSK_FS_META_FLAG_ALLOC :
4037 TSK_FS_META_FLAG_UNALLOC);
4038
4039 /* If we want only orphans, then check if this
4040 * inode is in the seen list
4041 * */
4042 if ((myflags & TSK_FS_META_FLAG_UNALLOC) &&
4043 (flags & TSK_FS_META_FLAG_ORPHAN) &&
4044 (tsk_fs_dir_find_inum_named(fs, mftnum))) {
4045 continue;
4046 }
4047
4048 /* copy into generic format */
4049 if ((retval =
4050 ntfs_dinode_copy(ntfs, fs_file, (char *) mft,
4051 mftnum)) != TSK_OK) {
4052 // continue on if there were only corruption problems
4053 if (retval == TSK_COR) {
4054 if (tsk_verbose)
4055 tsk_error_print(stderr);
4056 tsk_error_reset();
4057 continue;
4058 }
4059 tsk_fs_file_close(fs_file);
4060 free(mft);
4061 return 1;
4062 }
4063
4064 myflags |=
4065 (fs_file->meta->flags & (TSK_FS_META_FLAG_USED |
4066 TSK_FS_META_FLAG_UNUSED));
4067 if ((flags & myflags) != myflags)
4068 continue;
4069
4070 /* call action */
4071 retval = a_action(fs_file, ptr);
4072 if (retval == TSK_WALK_STOP) {
4073 tsk_fs_file_close(fs_file);
4074 free(mft);
4075 return 0;
4076 }
4077 else if (retval == TSK_WALK_ERROR) {
4078 tsk_fs_file_close(fs_file);
4079 free(mft);
4080 return 1;
4081 }
4082 }
4083
4084 // handle the virtual orphans folder if they asked for it
4085 if ((end_inum == TSK_FS_ORPHANDIR_INUM(fs))
4086 && (flags & TSK_FS_META_FLAG_ALLOC)
4087 && (flags & TSK_FS_META_FLAG_USED)) {
4088 int retval;
4089
4090 if (tsk_fs_dir_make_orphan_dir_meta(fs, fs_file->meta)) {
4091 tsk_fs_file_close(fs_file);
4092 free(mft);
4093 return 1;
4094 }
4095 /* call action */
4096 retval = a_action(fs_file, ptr);
4097 if (retval == TSK_WALK_STOP) {
4098 tsk_fs_file_close(fs_file);
4099 free(mft);
4100 return 0;
4101 }
4102 else if (retval == TSK_WALK_ERROR) {
4103 tsk_fs_file_close(fs_file);
4104 free(mft);
4105 return 1;
4106 }
4107 }
4108
4109 tsk_fs_file_close(fs_file);
4110 free(mft);
4111 return 0;
4112 }
4113
4114
4115
4116 static uint8_t
ntfs_fscheck(TSK_FS_INFO * fs,FILE * hFile)4117 ntfs_fscheck(TSK_FS_INFO * fs, FILE * hFile)
4118 {
4119 tsk_error_reset();
4120 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
4121 tsk_error_set_errstr("fscheck not implemented for NTFS yet");
4122 return 1;
4123 }
4124
4125
4126 /**
4127 * Print details about the file system to a file handle.
4128 *
4129 * @param fs File system to print details on
4130 * @param hFile File handle to print text to
4131 *
4132 * @returns 1 on error and 0 on success
4133 */
4134 static uint8_t
ntfs_fsstat(TSK_FS_INFO * fs,FILE * hFile)4135 ntfs_fsstat(TSK_FS_INFO * fs, FILE * hFile)
4136 {
4137 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
4138 TSK_FS_FILE *fs_file;
4139 const TSK_FS_ATTR *fs_attr;
4140 char asc[512];
4141 ntfs_attrdef *attrdeftmp;
4142
4143 tsk_fprintf(hFile, "FILE SYSTEM INFORMATION\n");
4144 tsk_fprintf(hFile, "--------------------------------------------\n");
4145 tsk_fprintf(hFile, "File System Type: NTFS\n");
4146 tsk_fprintf(hFile,
4147 "Volume Serial Number: %.16" PRIX64
4148 "\n", tsk_getu64(fs->endian, ntfs->fs->serial));
4149 tsk_fprintf(hFile, "OEM Name: %c%c%c%c%c%c%c%c\n",
4150 ntfs->fs->oemname[0],
4151 ntfs->fs->oemname[1],
4152 ntfs->fs->oemname[2],
4153 ntfs->fs->oemname[3],
4154 ntfs->fs->oemname[4],
4155 ntfs->fs->oemname[5], ntfs->fs->oemname[6], ntfs->fs->oemname[7]);
4156 /*
4157 * Volume
4158 */
4159 if ((fs_file = tsk_fs_file_open_meta(fs, NULL, NTFS_MFT_VOL)) == NULL) {
4160 tsk_error_reset();
4161 tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
4162 tsk_error_errstr2_concat
4163 (" - fsstat: Error finding Volume MFT Entry");
4164 return 1;
4165 }
4166
4167 fs_attr = tsk_fs_attrlist_get(fs_file->meta->attr, NTFS_ATYPE_VNAME);
4168 if (!fs_attr) {
4169 tsk_error_reset();
4170 tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
4171 tsk_error_set_errstr("Volume Name attribute not found in $Volume");
4172 return 1;
4173 }
4174
4175 if ((fs_attr->flags & TSK_FS_ATTR_RES)
4176 && (fs_attr->size)) {
4177
4178 UTF16 *name16 = (UTF16 *) fs_attr->rd.buf;
4179 UTF8 *name8 = (UTF8 *) asc;
4180 int retVal;
4181 retVal =
4182 tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
4183 (UTF16 *) ((uintptr_t) name16 +
4184 (int) fs_attr->size), &name8,
4185 (UTF8 *) ((uintptr_t) name8 + sizeof(asc)),
4186 TSKlenientConversion);
4187 if (retVal != TSKconversionOK) {
4188 if (tsk_verbose)
4189 tsk_fprintf(stderr,
4190 "fsstat: Error converting NTFS Volume label to UTF8: %d",
4191 retVal);
4192 *name8 = '\0';
4193 }
4194
4195 /* Make sure it is NULL Terminated */
4196 else if ((uintptr_t) name8 >= (uintptr_t) asc + sizeof(asc))
4197 asc[sizeof(asc) - 1] = '\0';
4198 else
4199 *name8 = '\0';
4200 tsk_fprintf(hFile, "Volume Name: %s\n", asc);
4201 }
4202
4203 tsk_fs_file_close(fs_file);
4204 fs_file = NULL;
4205 fs_attr = NULL;
4206 if (ntfs->ver == NTFS_VINFO_NT)
4207 tsk_fprintf(hFile, "Version: Windows NT\n");
4208 else if (ntfs->ver == NTFS_VINFO_2K)
4209 tsk_fprintf(hFile, "Version: Windows 2000\n");
4210 else if (ntfs->ver == NTFS_VINFO_XP)
4211 tsk_fprintf(hFile, "Version: Windows XP\n");
4212 tsk_fprintf(hFile, "\nMETADATA INFORMATION\n");
4213 tsk_fprintf(hFile, "--------------------------------------------\n");
4214 tsk_fprintf(hFile,
4215 "First Cluster of MFT: %" PRIu64 "\n",
4216 tsk_getu64(fs->endian, ntfs->fs->mft_clust));
4217 tsk_fprintf(hFile,
4218 "First Cluster of MFT Mirror: %"
4219 PRIu64 "\n", tsk_getu64(fs->endian, ntfs->fs->mftm_clust));
4220 tsk_fprintf(hFile,
4221 "Size of MFT Entries: %" PRIu16 " bytes\n", ntfs->mft_rsize_b);
4222 tsk_fprintf(hFile,
4223 "Size of Index Records: %" PRIu16 " bytes\n", ntfs->idx_rsize_b);
4224 tsk_fprintf(hFile,
4225 "Range: %" PRIuINUM " - %" PRIuINUM
4226 "\n", fs->first_inum, fs->last_inum);
4227 tsk_fprintf(hFile, "Root Directory: %" PRIuINUM "\n", fs->root_inum);
4228 tsk_fprintf(hFile, "\nCONTENT INFORMATION\n");
4229 tsk_fprintf(hFile, "--------------------------------------------\n");
4230 tsk_fprintf(hFile, "Sector Size: %" PRIu16 "\n", ntfs->ssize_b);
4231 tsk_fprintf(hFile, "Cluster Size: %" PRIu16 "\n", ntfs->csize_b);
4232 tsk_fprintf(hFile,
4233 "Total Cluster Range: %" PRIuDADDR
4234 " - %" PRIuDADDR "\n", fs->first_block, fs->last_block);
4235
4236 if (fs->last_block != fs->last_block_act)
4237 tsk_fprintf(hFile,
4238 "Total Range in Image: %" PRIuDADDR " - %" PRIuDADDR "\n",
4239 fs->first_block, fs->last_block_act);
4240
4241 tsk_fprintf(hFile,
4242 "Total Sector Range: 0 - %" PRIu64
4243 "\n", tsk_getu64(fs->endian, ntfs->fs->vol_size_s) - 1);
4244 /*
4245 * Attrdef Info
4246 */
4247 tsk_fprintf(hFile, "\n$AttrDef Attribute Values:\n");
4248 if (!ntfs->attrdef) {
4249 if (ntfs_load_attrdef(ntfs)) {
4250 tsk_fprintf(hFile, "Error loading attribute definitions\n");
4251 goto attrdef_egress;
4252 }
4253 }
4254
4255 attrdeftmp = ntfs->attrdef;
4256 while ((((uintptr_t) attrdeftmp - (uintptr_t) ntfs->attrdef +
4257 sizeof(ntfs_attrdef)) < ntfs->attrdef_len) &&
4258 (tsk_getu32(fs->endian, attrdeftmp->type))) {
4259 UTF16 *name16 = (UTF16 *) attrdeftmp->label;
4260 UTF8 *name8 = (UTF8 *) asc;
4261 int retVal;
4262 retVal =
4263 tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
4264 (UTF16 *) ((uintptr_t) name16 +
4265 sizeof(attrdeftmp->label)),
4266 &name8,
4267 (UTF8 *) ((uintptr_t) name8 + sizeof(asc)),
4268 TSKlenientConversion);
4269 if (retVal != TSKconversionOK) {
4270 if (tsk_verbose)
4271 tsk_fprintf(stderr,
4272 "fsstat: Error converting NTFS attribute def label to UTF8: %d",
4273 retVal);
4274 *name8 = '\0';
4275 }
4276
4277 /* Make sure it is NULL Terminated */
4278 else if ((uintptr_t) name8 >= (uintptr_t) asc + sizeof(asc))
4279 asc[sizeof(asc) - 1] = '\0';
4280 else
4281 *name8 = '\0';
4282 tsk_fprintf(hFile, "%s (%" PRIu32 ") ",
4283 asc, tsk_getu32(fs->endian, attrdeftmp->type));
4284 if ((tsk_getu64(fs->endian, attrdeftmp->minsize) == 0) &&
4285 (tsk_getu64(fs->endian,
4286 attrdeftmp->maxsize) == 0xffffffffffffffffULL)) {
4287
4288 tsk_fprintf(hFile, "Size: No Limit");
4289 }
4290 else {
4291 tsk_fprintf(hFile, "Size: %" PRIu64 "-%" PRIu64,
4292 tsk_getu64(fs->endian, attrdeftmp->minsize),
4293 tsk_getu64(fs->endian, attrdeftmp->maxsize));
4294 }
4295
4296 tsk_fprintf(hFile, " Flags: %s%s%s\n",
4297 (tsk_getu32(fs->endian, attrdeftmp->flags) &
4298 NTFS_ATTRDEF_FLAGS_RES ? "Resident" :
4299 ""), (tsk_getu32(fs->endian,
4300 attrdeftmp->flags) &
4301 NTFS_ATTRDEF_FLAGS_NONRES ?
4302 "Non-resident" : ""),
4303 (tsk_getu32(fs->endian, attrdeftmp->flags) &
4304 NTFS_ATTRDEF_FLAGS_IDX ? ",Index" : ""));
4305 attrdeftmp++;
4306 }
4307
4308 attrdef_egress:
4309
4310 return 0;
4311 }
4312
4313
4314 /************************* istat *******************************/
4315
4316 #define NTFS_PRINT_WIDTH 8
4317 typedef struct {
4318 FILE *hFile;
4319 int idx;
4320 } NTFS_PRINT_ADDR;
4321 static TSK_WALK_RET_ENUM
print_addr_act(TSK_FS_FILE * fs_file,TSK_OFF_T a_off,TSK_DADDR_T addr,char * buf,size_t size,TSK_FS_BLOCK_FLAG_ENUM flags,void * ptr)4322 print_addr_act(TSK_FS_FILE * fs_file, TSK_OFF_T a_off, TSK_DADDR_T addr,
4323 char *buf, size_t size, TSK_FS_BLOCK_FLAG_ENUM flags, void *ptr)
4324 {
4325 NTFS_PRINT_ADDR *print = (NTFS_PRINT_ADDR *) ptr;
4326 tsk_fprintf(print->hFile, "%" PRIuDADDR " ", addr);
4327 if (++(print->idx) == NTFS_PRINT_WIDTH) {
4328 tsk_fprintf(print->hFile, "\n");
4329 print->idx = 0;
4330 }
4331
4332 return TSK_WALK_CONT;
4333 }
4334
4335 /**
4336 * Print details on a specific file to a file handle.
4337 *
4338 * @param fs File system file is located in
4339 * @param hFile File name to print text to
4340 * @param inum Address of file in file system
4341 * @param numblock The number of blocks in file to force print (can go beyond file size)
4342 * @param sec_skew Clock skew in seconds to also print times in
4343 *
4344 * @returns 1 on error and 0 on success
4345 */
4346 static uint8_t
ntfs_istat(TSK_FS_INFO * fs,TSK_FS_ISTAT_FLAG_ENUM istat_flags,FILE * hFile,TSK_INUM_T inum,TSK_DADDR_T numblock,int32_t sec_skew)4347 ntfs_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile,
4348 TSK_INUM_T inum, TSK_DADDR_T numblock, int32_t sec_skew)
4349 {
4350 TSK_FS_FILE *fs_file;
4351 const TSK_FS_ATTR *fs_attr;
4352 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
4353 ntfs_mft *mft;
4354 char timeBuf[128];
4355 int idx;
4356
4357 // clean up any error messages that are lying around
4358 tsk_error_reset();
4359
4360 if ((mft = (ntfs_mft *) tsk_malloc(ntfs->mft_rsize_b)) == NULL) {
4361 return 1;
4362 }
4363
4364 if (ntfs_dinode_lookup(ntfs, (char *) mft, inum)) {
4365 free(mft);
4366 return 1;
4367 }
4368
4369 if ((fs_file = tsk_fs_file_open_meta(fs, NULL, inum)) == NULL) {
4370 tsk_error_errstr2_concat(" - istat");
4371 free(mft);
4372 return 1;
4373 }
4374
4375 tsk_fprintf(hFile, "MFT Entry Header Values:\n");
4376 tsk_fprintf(hFile,
4377 "Entry: %" PRIuINUM
4378 " Sequence: %" PRIu32 "\n", inum, fs_file->meta->seq);
4379 if (tsk_getu48(fs->endian, mft->base_ref) != 0) {
4380 tsk_fprintf(hFile,
4381 "Base File Record: %" PRIu64 "\n",
4382 (uint64_t) tsk_getu48(fs->endian, mft->base_ref));
4383 }
4384
4385 tsk_fprintf(hFile,
4386 "$LogFile Sequence Number: %" PRIu64
4387 "\n", tsk_getu64(fs->endian, mft->lsn));
4388 tsk_fprintf(hFile, "%sAllocated %s\n",
4389 (fs_file->meta->flags & TSK_FS_META_FLAG_ALLOC) ? "" :
4390 "Not ",
4391 TSK_FS_IS_DIR_META(fs_file->meta->type) ? "Directory" : "File");
4392 tsk_fprintf(hFile, "Links: %u\n", fs_file->meta->nlink);
4393
4394 /* STANDARD_INFORMATION info */
4395 fs_attr = tsk_fs_attrlist_get(fs_file->meta->attr, NTFS_ATYPE_SI);
4396 if (fs_attr) {
4397 ntfs_attr_si *si = (ntfs_attr_si *) fs_attr->rd.buf;
4398 char *sid_str;
4399
4400 int a = 0;
4401 tsk_fprintf(hFile, "\n$STANDARD_INFORMATION Attribute Values:\n");
4402 tsk_fprintf(hFile, "Flags: ");
4403 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_RO)
4404 tsk_fprintf(hFile, "%sRead Only", a++ == 0 ? "" : ", ");
4405 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_HID)
4406 tsk_fprintf(hFile, "%sHidden", a++ == 0 ? "" : ", ");
4407 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_SYS)
4408 tsk_fprintf(hFile, "%sSystem", a++ == 0 ? "" : ", ");
4409 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_ARCH)
4410 tsk_fprintf(hFile, "%sArchive", a++ == 0 ? "" : ", ");
4411 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_DEV)
4412 tsk_fprintf(hFile, "%sDevice", a++ == 0 ? "" : ", ");
4413 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_NORM)
4414 tsk_fprintf(hFile, "%sNormal", a++ == 0 ? "" : ", ");
4415 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_TEMP)
4416 tsk_fprintf(hFile, "%sTemporary", a++ == 0 ? "" : ", ");
4417 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_SPAR)
4418 tsk_fprintf(hFile, "%sSparse", a++ == 0 ? "" : ", ");
4419 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_REP)
4420 tsk_fprintf(hFile, "%sReparse Point", a++ == 0 ? "" : ", ");
4421 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_COMP)
4422 tsk_fprintf(hFile, "%sCompressed", a++ == 0 ? "" : ", ");
4423 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_OFF)
4424 tsk_fprintf(hFile, "%sOffline", a++ == 0 ? "" : ", ");
4425 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_NOIDX)
4426 tsk_fprintf(hFile, "%sNot Content Indexed",
4427 a++ == 0 ? "" : ", ");
4428 if (tsk_getu32(fs->endian, si->dos) & NTFS_SI_ENC)
4429 tsk_fprintf(hFile, "%sEncrypted", a++ == 0 ? "" : ", ");
4430 tsk_fprintf(hFile, "\n");
4431 tsk_fprintf(hFile, "Owner ID: %" PRIu32 "\n",
4432 tsk_getu32(fs->endian, si->own_id));
4433
4434 #if TSK_USE_SID
4435 ntfs_file_get_sidstr(fs_file, &sid_str);
4436
4437 tsk_fprintf(hFile, "Security ID: %" PRIu32 " (%s)\n",
4438 tsk_getu32(fs->endian, si->sec_id), sid_str ? sid_str : "");
4439 free(sid_str);
4440 sid_str = NULL;
4441 #endif
4442
4443
4444 if (tsk_getu32(fs->endian, si->maxver) != 0) {
4445 tsk_fprintf(hFile,
4446 "Version %" PRIu32 " of %" PRIu32
4447 "\n", tsk_getu32(fs->endian, si->ver),
4448 tsk_getu32(fs->endian, si->maxver));
4449 }
4450
4451 if (tsk_getu64(fs->endian, si->quota) != 0) {
4452 tsk_fprintf(hFile, "Quota Charged: %" PRIu64 "\n",
4453 tsk_getu64(fs->endian, si->quota));
4454 }
4455
4456 if (tsk_getu64(fs->endian, si->usn) != 0) {
4457 tsk_fprintf(hFile,
4458 "Last User Journal Update Sequence Number: %"
4459 PRIu64 "\n", tsk_getu64(fs->endian, si->usn));
4460 }
4461
4462
4463 /* Times - take it from fs_file->meta instead of redoing the work */
4464
4465 if (sec_skew != 0) {
4466 tsk_fprintf(hFile, "\nAdjusted times:\n");
4467 if (fs_file->meta->mtime)
4468 fs_file->meta->mtime -= sec_skew;
4469 if (fs_file->meta->atime)
4470 fs_file->meta->atime -= sec_skew;
4471 if (fs_file->meta->ctime)
4472 fs_file->meta->ctime -= sec_skew;
4473 if (fs_file->meta->crtime)
4474 fs_file->meta->crtime -= sec_skew;
4475
4476 tsk_fprintf(hFile, "Created:\t%s\n",
4477 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->crtime), timeBuf));
4478 tsk_fprintf(hFile, "File Modified:\t%s\n",
4479 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->mtime), timeBuf));
4480 tsk_fprintf(hFile, "MFT Modified:\t%s\n",
4481 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->ctime), timeBuf));
4482 tsk_fprintf(hFile, "Accessed:\t%s\n",
4483 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->atime), timeBuf));
4484
4485 if (fs_file->meta->mtime)
4486 fs_file->meta->mtime += sec_skew;
4487 if (fs_file->meta->atime)
4488 fs_file->meta->atime += sec_skew;
4489 if (fs_file->meta->ctime)
4490 fs_file->meta->ctime += sec_skew;
4491 if (fs_file->meta->crtime)
4492 fs_file->meta->crtime += sec_skew;
4493
4494 tsk_fprintf(hFile, "\nOriginal times:\n");
4495 }
4496
4497 tsk_fprintf(hFile, "Created:\t%s\n",
4498 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->crtime), timeBuf));
4499 tsk_fprintf(hFile, "File Modified:\t%s\n",
4500 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->mtime), timeBuf));
4501 tsk_fprintf(hFile, "MFT Modified:\t%s\n",
4502 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->ctime), timeBuf));
4503 tsk_fprintf(hFile, "Accessed:\t%s\n",
4504 tsk_fs_time_to_str_subsecs(WITHNANO(fs_file->meta->atime), timeBuf));
4505 }
4506
4507 /* $FILE_NAME Information */
4508 for (idx = 0; idx < tsk_fs_attrlist_get_len(fs_file->meta->attr); idx++) {
4509 ntfs_attr_fname *fname;
4510 uint64_t flags;
4511 int a = 0;
4512 UTF16 *name16;
4513 UTF8 *name8;
4514 char name8buf[NTFS_MAXNAMLEN_UTF8 + 1];
4515 int retVal;
4516
4517 fs_attr = tsk_fs_attrlist_get_idx(fs_file->meta->attr, idx);
4518 if (fs_attr->type != NTFS_ATYPE_FNAME) {
4519 continue;
4520 }
4521 fname = (ntfs_attr_fname *) fs_attr->rd.buf;
4522
4523 tsk_fprintf(hFile, "\n$FILE_NAME Attribute Values:\n");
4524 flags = tsk_getu64(fs->endian, fname->flags);
4525 tsk_fprintf(hFile, "Flags: ");
4526 if (flags & NTFS_FNAME_FLAGS_DIR)
4527 tsk_fprintf(hFile, "%sDirectory", a++ == 0 ? "" : ", ");
4528 if (flags & NTFS_FNAME_FLAGS_DEV)
4529 tsk_fprintf(hFile, "%sDevice", a++ == 0 ? "" : ", ");
4530 if (flags & NTFS_FNAME_FLAGS_NORM)
4531 tsk_fprintf(hFile, "%sNormal", a++ == 0 ? "" : ", ");
4532 if (flags & NTFS_FNAME_FLAGS_RO)
4533 tsk_fprintf(hFile, "%sRead Only", a++ == 0 ? "" : ", ");
4534 if (flags & NTFS_FNAME_FLAGS_HID)
4535 tsk_fprintf(hFile, "%sHidden", a++ == 0 ? "" : ", ");
4536 if (flags & NTFS_FNAME_FLAGS_SYS)
4537 tsk_fprintf(hFile, "%sSystem", a++ == 0 ? "" : ", ");
4538 if (flags & NTFS_FNAME_FLAGS_ARCH)
4539 tsk_fprintf(hFile, "%sArchive", a++ == 0 ? "" : ", ");
4540 if (flags & NTFS_FNAME_FLAGS_TEMP)
4541 tsk_fprintf(hFile, "%sTemp", a++ == 0 ? "" : ", ");
4542 if (flags & NTFS_FNAME_FLAGS_SPAR)
4543 tsk_fprintf(hFile, "%sSparse", a++ == 0 ? "" : ", ");
4544 if (flags & NTFS_FNAME_FLAGS_REP)
4545 tsk_fprintf(hFile, "%sReparse Point", a++ == 0 ? "" : ", ");
4546 if (flags & NTFS_FNAME_FLAGS_COMP)
4547 tsk_fprintf(hFile, "%sCompressed", a++ == 0 ? "" : ", ");
4548 if (flags & NTFS_FNAME_FLAGS_ENC)
4549 tsk_fprintf(hFile, "%sEncrypted", a++ == 0 ? "" : ", ");
4550 if (flags & NTFS_FNAME_FLAGS_OFF)
4551 tsk_fprintf(hFile, "%sOffline", a++ == 0 ? "" : ", ");
4552 if (flags & NTFS_FNAME_FLAGS_NOIDX)
4553 tsk_fprintf(hFile, "%sNot Content Indexed",
4554 a++ == 0 ? "" : ", ");
4555 if (flags & NTFS_FNAME_FLAGS_IDXVIEW)
4556 tsk_fprintf(hFile, "%sIndex View", a++ == 0 ? "" : ", ");
4557 tsk_fprintf(hFile, "\n");
4558
4559
4560 name16 = (UTF16 *) & fname->name;
4561 name8 = (UTF8 *) name8buf;
4562
4563 retVal =
4564 tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16,
4565 (UTF16 *) ((uintptr_t) name16 +
4566 fname->nlen * 2),
4567 &name8,
4568 (UTF8 *) ((uintptr_t) name8 + NTFS_MAXNAMLEN_UTF8),
4569 TSKlenientConversion);
4570 if (retVal != TSKconversionOK) {
4571 if (tsk_verbose)
4572 tsk_fprintf(stderr,
4573 "ntfs_istat: Error converting NTFS name in $FNAME to UTF8: %d",
4574 retVal);
4575 *name8 = '\0';
4576 }
4577 /* Make sure it is NULL Terminated */
4578 else if ((uintptr_t) name8 >=
4579 (uintptr_t) name8buf + NTFS_MAXNAMLEN_UTF8)
4580 name8buf[NTFS_MAXNAMLEN_UTF8] = '\0';
4581 else
4582 *name8 = '\0';
4583
4584
4585 tsk_fprintf(hFile, "Name: %s\n", name8buf);
4586
4587 tsk_fprintf(hFile,
4588 "Parent MFT Entry: %" PRIu64
4589 " \tSequence: %" PRIu16 "\n",
4590 (uint64_t) tsk_getu48(fs->endian, fname->par_ref),
4591 tsk_getu16(fs->endian, fname->par_seq));
4592 tsk_fprintf(hFile,
4593 "Allocated Size: %" PRIu64
4594 " \tActual Size: %" PRIu64 "\n",
4595 tsk_getu64(fs->endian, fname->alloc_fsize),
4596 tsk_getu64(fs->endian, fname->real_fsize));
4597 /*
4598 * Times
4599 */
4600
4601 /* Times - take it from fs_file->meta instead of redoing the work */
4602
4603 if (sec_skew != 0) {
4604 tsk_fprintf(hFile, "\nAdjusted times:\n");
4605
4606 tsk_fprintf(hFile, "Created:\t%s\n",
4607 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->crtime)) - sec_skew, nt2nano(tsk_getu64(fs->endian, fname->crtime)), timeBuf));
4608 tsk_fprintf(hFile, "File Modified:\t%s\n",
4609 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->mtime)) - sec_skew, nt2nano(tsk_getu64(fs->endian, fname->mtime)), timeBuf));
4610 tsk_fprintf(hFile, "MFT Modified:\t%s\n",
4611 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->ctime)) - sec_skew, nt2nano(tsk_getu64(fs->endian, fname->ctime)), timeBuf));
4612 tsk_fprintf(hFile, "Accessed:\t%s\n",
4613 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->atime)) - sec_skew, nt2nano(tsk_getu64(fs->endian, fname->atime)), timeBuf));
4614
4615 tsk_fprintf(hFile, "\nOriginal times:\n");
4616 }
4617
4618 tsk_fprintf(hFile, "Created:\t%s\n",
4619 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->crtime)), nt2nano(tsk_getu64(fs->endian, fname->crtime)), timeBuf));
4620 tsk_fprintf(hFile, "File Modified:\t%s\n",
4621 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->mtime)), nt2nano(tsk_getu64(fs->endian, fname->mtime)), timeBuf));
4622 tsk_fprintf(hFile, "MFT Modified:\t%s\n",
4623 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->ctime)), nt2nano(tsk_getu64(fs->endian, fname->ctime)), timeBuf));
4624 tsk_fprintf(hFile, "Accessed:\t%s\n",
4625 tsk_fs_time_to_str_subsecs(nt2unixtime(tsk_getu64(fs->endian, fname->atime)), nt2nano(tsk_getu64(fs->endian, fname->atime)), timeBuf));
4626 }
4627
4628
4629 /* $OBJECT_ID Information */
4630 fs_attr = tsk_fs_attrlist_get(fs_file->meta->attr, NTFS_ATYPE_OBJID);
4631 if (fs_attr) {
4632 ntfs_attr_objid *objid = (ntfs_attr_objid *) fs_attr->rd.buf;
4633 uint64_t id1, id2;
4634 tsk_fprintf(hFile, "\n$OBJECT_ID Attribute Values:\n");
4635 id1 = tsk_getu64(fs->endian, objid->objid1);
4636 id2 = tsk_getu64(fs->endian, objid->objid2);
4637 tsk_fprintf(hFile,
4638 "Object Id: %.8" PRIx32 "-%.4" PRIx16
4639 "-%.4" PRIx16 "-%.4" PRIx16 "-%.4"
4640 PRIx16 "%.8" PRIx32 "\n",
4641 tsk_getu32(fs->endian, objid->objid1),
4642 tsk_getu16(fs->endian, objid->objid2),
4643 tsk_getu16(fs->endian, objid->objid3),
4644 tsk_getu16(TSK_BIG_ENDIAN, objid->objid4),
4645 tsk_getu16(TSK_BIG_ENDIAN, objid->objid5),
4646 tsk_getu32(TSK_BIG_ENDIAN, objid->objid6));
4647
4648 /* The rest of the fields do not always exist. Check the attr size */
4649 if (fs_attr->size > 16) {
4650 id1 = tsk_getu64(fs->endian, objid->orig_volid1);
4651 id2 = tsk_getu64(fs->endian, objid->orig_volid2);
4652 tsk_fprintf(hFile,
4653 "Birth Volume Id: %.8" PRIx32 "-%.4"
4654 PRIx16 "-%.4" PRIx16 "-%.4" PRIx16
4655 "-%.12" PRIx64 "\n",
4656 (uint32_t) (id2 >> 32) & 0xffffffff,
4657 (uint16_t) (id2 >> 16) & 0xffff,
4658 (uint16_t) (id2 & 0xffff),
4659 (uint16_t) (id1 >> 48) & 0xffff,
4660 (uint64_t) (id1 & (uint64_t)
4661 0x0000ffffffffffffULL));
4662 }
4663
4664 if (fs_attr->size > 32) {
4665 id1 = tsk_getu64(fs->endian, objid->orig_objid1);
4666 id2 = tsk_getu64(fs->endian, objid->orig_objid2);
4667 tsk_fprintf(hFile,
4668 "Birth Object Id: %.8" PRIx32 "-%.4"
4669 PRIx16 "-%.4" PRIx16 "-%.4" PRIx16
4670 "-%.12" PRIx64 "\n",
4671 (uint32_t) (id2 >> 32) & 0xffffffff,
4672 (uint16_t) (id2 >> 16) & 0xffff,
4673 (uint16_t) (id2 & 0xffff),
4674 (uint16_t) (id1 >> 48) & 0xffff,
4675 (uint64_t) (id1 & (uint64_t)
4676 0x0000ffffffffffffULL));
4677 }
4678
4679 if (fs_attr->size > 48) {
4680 id1 = tsk_getu64(fs->endian, objid->orig_domid1);
4681 id2 = tsk_getu64(fs->endian, objid->orig_domid2);
4682 tsk_fprintf(hFile,
4683 "Birth Domain Id: %.8" PRIx32 "-%.4"
4684 PRIx16 "-%.4" PRIx16 "-%.4" PRIx16
4685 "-%.12" PRIx64 "\n",
4686 (uint32_t) (id2 >> 32) & 0xffffffff,
4687 (uint16_t) (id2 >> 16) & 0xffff,
4688 (uint16_t) (id2 & 0xffff),
4689 (uint16_t) (id1 >> 48) & 0xffff,
4690 (uint64_t) (id1 & (uint64_t)
4691 0x0000ffffffffffffULL));
4692 }
4693 }
4694
4695 /* Attribute List Information */
4696 fs_attr =
4697 tsk_fs_attrlist_get(fs_file->meta->attr, NTFS_ATYPE_ATTRLIST);
4698 if (fs_attr) {
4699 char *buf;
4700 ntfs_attrlist *list;
4701 uintptr_t endaddr;
4702 TSK_FS_LOAD_FILE load_file;
4703
4704 tsk_fprintf(hFile, "\n$ATTRIBUTE_LIST Attribute Values:\n");
4705
4706 /* Get a copy of the attribute list stream */
4707 load_file.total = load_file.left = (size_t) fs_attr->size;
4708 load_file.cur = load_file.base = buf =
4709 tsk_malloc((size_t) fs_attr->size);
4710 if (buf == NULL) {
4711 free(mft);
4712 return 1;
4713 }
4714
4715 endaddr = (uintptr_t) buf + (uintptr_t) fs_attr->size;
4716 if (tsk_fs_attr_walk(fs_attr,
4717 0, tsk_fs_load_file_action, (void *) &load_file)) {
4718 tsk_fprintf(hFile, "error reading attribute list buffer\n");
4719 tsk_error_reset();
4720 goto egress;
4721 }
4722
4723 /* this value should be zero, if not then we didn't read all of the
4724 * buffer
4725 */
4726 if (load_file.left > 0) {
4727 tsk_fprintf(hFile, "error reading attribute list buffer\n");
4728 goto egress;
4729 }
4730
4731 /* Process the list & print the details */
4732 for (list = (ntfs_attrlist *) buf;
4733 (list) && ((uintptr_t) list < endaddr)
4734 && (tsk_getu16(fs->endian, list->len) > 0);
4735 list =
4736 (ntfs_attrlist *) ((uintptr_t) list + tsk_getu16(fs->endian,
4737 list->len))) {
4738 tsk_fprintf(hFile,
4739 "Type: %" PRIu32 "-%" PRIu16 " \tMFT Entry: %" PRIu64
4740 " \tVCN: %" PRIu64 "\n", tsk_getu32(fs->endian,
4741 list->type), tsk_getu16(fs->endian, list->id),
4742 (uint64_t) tsk_getu48(fs->endian, list->file_ref),
4743 tsk_getu64(fs->endian, list->start_vcn));
4744 }
4745 egress:
4746 free(buf);
4747 }
4748
4749 /* Print all of the attributes */
4750 tsk_fprintf(hFile, "\nAttributes: \n");
4751 if (fs_file->meta->attr) {
4752 int cnt, i;
4753
4754 // cycle through the attributes
4755 cnt = tsk_fs_file_attr_getsize(fs_file);
4756 for (i = 0; i < cnt; i++) {
4757 char type[512];
4758
4759 const TSK_FS_ATTR *fs_attr =
4760 tsk_fs_file_attr_get_idx(fs_file, i);
4761 if (!fs_attr)
4762 continue;
4763
4764 if (ntfs_attrname_lookup(fs, fs_attr->type, type, 512)) {
4765 tsk_fprintf(hFile, "error looking attribute name\n");
4766 break;
4767 }
4768
4769 /* print the layout if it is non-resident and not "special" */
4770 if (fs_attr->flags & TSK_FS_ATTR_NONRES) {
4771 NTFS_PRINT_ADDR print_addr;
4772
4773 tsk_fprintf(hFile,
4774 "Type: %s (%" PRIu32 "-%" PRIu16
4775 ") Name: %s Non-Resident%s%s%s size: %"
4776 PRIdOFF " init_size: %" PRIdOFF "\n", type,
4777 fs_attr->type, fs_attr->id,
4778 (fs_attr->name) ? fs_attr->name : "N/A",
4779 (fs_attr->flags & TSK_FS_ATTR_ENC) ? ", Encrypted" :
4780 "",
4781 (fs_attr->flags & TSK_FS_ATTR_COMP) ? ", Compressed" :
4782 "",
4783 (fs_attr->flags & TSK_FS_ATTR_SPARSE) ? ", Sparse" :
4784 "", fs_attr->size, fs_attr->nrd.initsize);
4785 if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
4786 if (tsk_fs_attr_print(fs_attr, hFile)) {
4787 tsk_fprintf(hFile, "\nError creating run lists\n");
4788 tsk_error_print(hFile);
4789 tsk_error_reset();
4790 }
4791 }
4792 else {
4793 print_addr.idx = 0;
4794 print_addr.hFile = hFile;
4795 if (tsk_fs_file_walk_type(fs_file, fs_attr->type,
4796 fs_attr->id,
4797 (TSK_FS_FILE_WALK_FLAG_AONLY |
4798 TSK_FS_FILE_WALK_FLAG_SLACK),
4799 print_addr_act, (void *)&print_addr)) {
4800 tsk_fprintf(hFile, "\nError walking file\n");
4801 tsk_error_print(hFile);
4802 tsk_error_reset();
4803 }
4804 if (print_addr.idx != 0)
4805 tsk_fprintf(hFile, "\n");
4806 }
4807
4808 }
4809 else {
4810 tsk_fprintf(hFile,
4811 "Type: %s (%" PRIu32 "-%" PRIu16
4812 ") Name: %s Resident%s%s%s size: %"
4813 PRIdOFF "\n", type, fs_attr->type,
4814 fs_attr->id,
4815 (fs_attr->name) ? fs_attr->name : "N/A",
4816 (fs_attr->flags & TSK_FS_ATTR_ENC) ? ", Encrypted"
4817 : "",
4818 (fs_attr->flags & TSK_FS_ATTR_COMP) ?
4819 ", Compressed" : "",
4820 (fs_attr->flags & TSK_FS_ATTR_SPARSE) ? ", Sparse" :
4821 "", fs_attr->size);
4822
4823 }
4824 }
4825 }
4826
4827 tsk_fs_file_close(fs_file);
4828 free(mft);
4829 return 0;
4830 }
4831
4832
4833
4834 /* JOURNAL CODE - MOVE TO NEW FILE AT SOME POINT */
4835
4836 static uint8_t
ntfs_jopen(TSK_FS_INFO * fs,TSK_INUM_T inum)4837 ntfs_jopen(TSK_FS_INFO * fs, TSK_INUM_T inum)
4838 {
4839 tsk_error_reset();
4840 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
4841 tsk_error_set_errstr("NTFS Journal is not yet supported\n");
4842 return 1;
4843 }
4844
4845 static uint8_t
ntfs_jentry_walk(TSK_FS_INFO * fs,int flags,TSK_FS_JENTRY_WALK_CB a_action,void * ptr)4846 ntfs_jentry_walk(TSK_FS_INFO * fs, int flags,
4847 TSK_FS_JENTRY_WALK_CB a_action, void *ptr)
4848 {
4849 tsk_error_reset();
4850 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
4851 tsk_error_set_errstr("NTFS Journal is not yet supported\n");
4852 return 1;
4853 }
4854
4855
4856 static uint8_t
ntfs_jblk_walk(TSK_FS_INFO * fs,TSK_DADDR_T start,TSK_DADDR_T end,int flags,TSK_FS_JBLK_WALK_CB a_action,void * ptr)4857 ntfs_jblk_walk(TSK_FS_INFO * fs, TSK_DADDR_T start,
4858 TSK_DADDR_T end, int flags, TSK_FS_JBLK_WALK_CB a_action, void *ptr)
4859 {
4860 tsk_error_reset();
4861 tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC);
4862 tsk_error_set_errstr("NTFS Journal is not yet supported\n");
4863 return 1;
4864 }
4865
4866
4867 static TSK_FS_ATTR_TYPE_ENUM
ntfs_get_default_attr_type(const TSK_FS_FILE * a_file)4868 ntfs_get_default_attr_type(const TSK_FS_FILE * a_file)
4869 {
4870 if ((a_file == NULL) || (a_file->meta == NULL))
4871 return TSK_FS_ATTR_TYPE_DEFAULT;
4872
4873 /* Use DATA for files and IDXROOT for dirs */
4874 if (TSK_FS_IS_DIR_META(a_file->meta->type))
4875 return TSK_FS_ATTR_TYPE_NTFS_IDXROOT;
4876 else
4877 return TSK_FS_ATTR_TYPE_NTFS_DATA;
4878
4879 }
4880
4881
4882 static void
ntfs_close(TSK_FS_INFO * fs)4883 ntfs_close(TSK_FS_INFO * fs)
4884 {
4885 NTFS_INFO *ntfs = (NTFS_INFO *) fs;
4886
4887 if (fs == NULL)
4888 return;
4889
4890 #if TSK_USE_SID
4891 free(ntfs->sii_data.buffer);
4892 ntfs->sii_data.buffer = NULL;
4893
4894 free(ntfs->sds_data.buffer);
4895 ntfs->sds_data.buffer = NULL;
4896
4897 #endif
4898
4899 fs->tag = 0;
4900 free(ntfs->fs);
4901 tsk_fs_attr_run_free(ntfs->bmap);
4902 free(ntfs->bmap_buf);
4903 tsk_fs_file_close(ntfs->mft_file);
4904
4905 if (ntfs->orphan_map)
4906 ntfs_orphan_map_free(ntfs);
4907
4908 tsk_deinit_lock(&ntfs->lock);
4909 tsk_deinit_lock(&ntfs->orphan_map_lock);
4910 #if TSK_USE_SID
4911 tsk_deinit_lock(&ntfs->sid_lock);
4912 #endif
4913
4914 tsk_fs_free(fs);
4915 }
4916
4917
4918 /**
4919 * Open part of a disk image as an NTFS file system.
4920 *
4921 * @param img_info Disk image to analyze
4922 * @param offset Byte offset where NTFS file system starts
4923 * @param ftype Specific type of NTFS file system
4924 * @param test NOT USED
4925 * @returns NULL on error or if data is not an NTFS file system
4926 */
4927 TSK_FS_INFO *
ntfs_open(TSK_IMG_INFO * img_info,TSK_OFF_T offset,TSK_FS_TYPE_ENUM ftype,uint8_t test)4928 ntfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
4929 TSK_FS_TYPE_ENUM ftype, uint8_t test)
4930 {
4931 char *myname = "ntfs_open";
4932 NTFS_INFO *ntfs = NULL;
4933 TSK_FS_INFO *fs = NULL;
4934 unsigned int len = 0;
4935 ssize_t cnt = 0;
4936
4937 // clean up any error messages that are lying around
4938 tsk_error_reset();
4939
4940 if (TSK_FS_TYPE_ISNTFS(ftype) == 0) {
4941 tsk_error_reset();
4942 tsk_error_set_errno(TSK_ERR_FS_ARG);
4943 tsk_error_set_errstr("Invalid FS type in ntfs_open");
4944 return NULL;
4945 }
4946
4947 if (img_info->sector_size == 0) {
4948 tsk_error_reset();
4949 tsk_error_set_errno(TSK_ERR_FS_ARG);
4950 tsk_error_set_errstr("ntfs_open: sector size is 0");
4951 return NULL;
4952 }
4953
4954 if ((ntfs = (NTFS_INFO *) tsk_fs_malloc(sizeof(*ntfs))) == NULL) {
4955 goto on_error;
4956 }
4957 fs = &(ntfs->fs_info);
4958
4959 fs->ftype = TSK_FS_TYPE_NTFS;
4960 fs->duname = "Cluster";
4961 fs->flags = TSK_FS_INFO_FLAG_HAVE_SEQ;
4962 fs->tag = TSK_FS_INFO_TAG;
4963
4964 fs->img_info = img_info;
4965 fs->offset = offset;
4966
4967 ntfs->loading_the_MFT = 0;
4968 ntfs->bmap = NULL;
4969 ntfs->bmap_buf = NULL;
4970
4971 /* Read the boot sector */
4972 len = roundup(sizeof(ntfs_sb), img_info->sector_size);
4973 ntfs->fs = (ntfs_sb *) tsk_malloc(len);
4974 if (ntfs->fs == NULL) {
4975 goto on_error;
4976 }
4977
4978 cnt = tsk_fs_read(fs, (TSK_OFF_T) 0, (char *) ntfs->fs, len);
4979 if (cnt != len) {
4980 if (cnt >= 0) {
4981 tsk_error_reset();
4982 tsk_error_set_errno(TSK_ERR_FS_READ);
4983 }
4984 tsk_error_set_errstr2("%s: Error reading boot sector.", myname);
4985 goto on_error;
4986 }
4987
4988 /* Check the magic value */
4989 if (tsk_fs_guessu16(fs, ntfs->fs->magic, NTFS_FS_MAGIC)) {
4990 tsk_error_reset();
4991 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
4992 tsk_error_set_errstr("Not a NTFS file system (magic)");
4993 if (tsk_verbose)
4994 fprintf(stderr, "ntfs_open: Incorrect NTFS magic\n");
4995 goto on_error;
4996 }
4997
4998
4999 /*
5000 * block calculations : although there are no blocks in ntfs,
5001 * we are using a cluster as a "block"
5002 */
5003
5004 ntfs->ssize_b = tsk_getu16(fs->endian, ntfs->fs->ssize);
5005 if ((ntfs->ssize_b == 0) || (ntfs->ssize_b % 512)) {
5006 tsk_error_reset();
5007 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
5008 tsk_error_set_errstr
5009 ("Not a NTFS file system (invalid sector size %d))",
5010 ntfs->ssize_b);
5011 if (tsk_verbose)
5012 fprintf(stderr, "ntfs_open: invalid sector size: %d\n",
5013 ntfs->ssize_b);
5014 goto on_error;
5015 }
5016
5017 if ((ntfs->fs->csize != 0x01) &&
5018 (ntfs->fs->csize != 0x02) &&
5019 (ntfs->fs->csize != 0x04) &&
5020 (ntfs->fs->csize != 0x08) &&
5021 (ntfs->fs->csize != 0x10) &&
5022 (ntfs->fs->csize != 0x20) && (ntfs->fs->csize != 0x40)
5023 && (ntfs->fs->csize != 0x80)) {
5024 tsk_error_reset();
5025 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
5026 tsk_error_set_errstr
5027 ("Not a NTFS file system (invalid cluster size %d)",
5028 ntfs->fs->csize);
5029 if (tsk_verbose)
5030 fprintf(stderr, "ntfs_open: invalid cluster size: %d\n",
5031 ntfs->fs->csize);
5032 goto on_error;
5033 }
5034
5035 ntfs->csize_b = ntfs->fs->csize * ntfs->ssize_b;
5036 fs->first_block = 0;
5037 /* This field is defined as 64-bits but according to the
5038 * NTFS drivers in Linux, old Windows versions used only 32-bits
5039 */
5040 fs->block_count =
5041 (TSK_DADDR_T) tsk_getu64(fs->endian,
5042 ntfs->fs->vol_size_s) / ntfs->fs->csize;
5043 if (fs->block_count == 0) {
5044 tsk_error_reset();
5045 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
5046 tsk_error_set_errstr("Not a NTFS file system (volume size is 0)");
5047 if (tsk_verbose)
5048 fprintf(stderr, "ntfs_open: invalid volume size: 0\n");
5049 goto on_error;
5050 }
5051
5052 fs->last_block = fs->last_block_act = fs->block_count - 1;
5053 fs->block_size = ntfs->csize_b;
5054 fs->dev_bsize = img_info->sector_size;
5055
5056 // determine the last block we have in this image
5057 if ((TSK_DADDR_T) ((img_info->size - offset) / fs->block_size) <
5058 fs->block_count)
5059 fs->last_block_act =
5060 (img_info->size - offset) / fs->block_size - 1;
5061
5062 ntfs->mft_rsize_b = 0;
5063 if (ntfs->fs->mft_rsize_c > 0) {
5064 ntfs->mft_rsize_b = ntfs->fs->mft_rsize_c * ntfs->csize_b;
5065 }
5066 else if (ntfs->fs->mft_rsize_c > -32) {
5067 /* if the mft_rsize_c is not > 0, then it is -log2(rsize_b) */
5068 ntfs->mft_rsize_b = 1 << -ntfs->fs->mft_rsize_c;
5069 }
5070
5071 if ((ntfs->mft_rsize_b == 0) || (ntfs->mft_rsize_b % 512)) {
5072 tsk_error_reset();
5073 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
5074 tsk_error_set_errstr
5075 ("Not a NTFS file system (invalid MFT entry size)");
5076 if (tsk_verbose)
5077 fprintf(stderr, "ntfs_open: invalid MFT entry size\n");
5078 goto on_error;
5079 }
5080
5081 ntfs->idx_rsize_b = 0;
5082 if (ntfs->fs->idx_rsize_c > 0) {
5083 ntfs->idx_rsize_b = ntfs->fs->idx_rsize_c * ntfs->csize_b;
5084 }
5085 else if (ntfs->fs->idx_rsize_c > -32) {
5086 /* if the idx_rsize_c is not > 0, then it is -log2(rsize_b) */
5087 ntfs->idx_rsize_b = 1 << -ntfs->fs->idx_rsize_c;
5088 }
5089
5090 if ((ntfs->idx_rsize_b == 0) || (ntfs->idx_rsize_b % 512)) {
5091 tsk_error_reset();
5092 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
5093 tsk_error_set_errstr
5094 ("Not a NTFS file system (invalid idx record size %d)",
5095 ntfs->idx_rsize_b);
5096 if (tsk_verbose)
5097 fprintf(stderr, "ntfs_open: invalid idx record size %d\n",
5098 ntfs->idx_rsize_b);
5099 goto on_error;
5100 }
5101
5102 ntfs->root_mft_addr =
5103 tsk_getu64(fs->endian, ntfs->fs->mft_clust) * ntfs->csize_b;
5104 if (tsk_getu64(fs->endian, ntfs->fs->mft_clust) > fs->last_block) {
5105 tsk_error_reset();
5106 tsk_error_set_errno(TSK_ERR_FS_MAGIC);
5107 tsk_error_set_errstr
5108 ("Not a NTFS file system (invalid starting MFT clust)");
5109 if (tsk_verbose)
5110 fprintf(stderr, "ntfs_open: invalid starting MFT cluster\n");
5111 goto on_error;
5112 }
5113
5114 /*
5115 * Set the function pointers (before we start calling internal functions)
5116 */
5117 fs->inode_walk = ntfs_inode_walk;
5118 fs->block_walk = ntfs_block_walk;
5119 fs->block_getflags = ntfs_block_getflags;
5120
5121 fs->get_default_attr_type = ntfs_get_default_attr_type;
5122 fs->load_attrs = ntfs_load_attrs;
5123
5124 fs->file_add_meta = ntfs_inode_lookup;
5125 fs->dir_open_meta = ntfs_dir_open_meta;
5126 fs->fsstat = ntfs_fsstat;
5127 fs->fscheck = ntfs_fscheck;
5128 fs->istat = ntfs_istat;
5129 fs->close = ntfs_close;
5130 fs->name_cmp = ntfs_name_cmp;
5131
5132 fs->fread_owner_sid = ntfs_file_get_sidstr;
5133 fs->jblk_walk = ntfs_jblk_walk;
5134 fs->jentry_walk = ntfs_jentry_walk;
5135 fs->jopen = ntfs_jopen;
5136 fs->journ_inum = 0;
5137
5138
5139
5140 // set up locks
5141 tsk_init_lock(&ntfs->lock);
5142 tsk_init_lock(&ntfs->orphan_map_lock);
5143 #if TSK_USE_SID
5144 tsk_init_lock(&ntfs->sid_lock);
5145 #endif
5146
5147 /*
5148 * inode
5149 */
5150
5151 fs->root_inum = NTFS_ROOTINO;
5152 fs->first_inum = NTFS_FIRSTINO;
5153 fs->last_inum = NTFS_LAST_DEFAULT_INO;
5154 ntfs->mft_data = NULL;
5155
5156 /* load the data run for the MFT table into ntfs->mft */
5157 ntfs->loading_the_MFT = 1;
5158 if ((ntfs->mft_file =
5159 tsk_fs_file_open_meta(fs, NULL, NTFS_MFT_MFT)) == NULL) {
5160 if (tsk_verbose)
5161 fprintf(stderr,
5162 "ntfs_open: Error opening $MFT (%s)\n", tsk_error_get());
5163 goto on_error;
5164 }
5165
5166 /* cache the data attribute
5167 *
5168 * This will likely be done already by proc_attrseq, but this
5169 * should be quick
5170 */
5171 ntfs->mft_data =
5172 tsk_fs_attrlist_get(ntfs->mft_file->meta->attr, NTFS_ATYPE_DATA);
5173 if (!ntfs->mft_data) {
5174 tsk_error_errstr2_concat(" - Data Attribute not found in $MFT");
5175 if (tsk_verbose)
5176 fprintf(stderr,
5177 "ntfs_open: Data attribute not found in $MFT (%s)\n",
5178 tsk_error_get());
5179 goto on_error;
5180 }
5181
5182 /* Get the inode count based on the table size */
5183 fs->inum_count = ntfs->mft_data->size / ntfs->mft_rsize_b + 1; // we are adding 1 in this calc to account for Orphans directory
5184 fs->last_inum = fs->inum_count - 1;
5185
5186 /* reset the flag that we are no longer loading $MFT */
5187 ntfs->loading_the_MFT = 0;
5188
5189 /* Volume ID */
5190 for (fs->fs_id_used = 0; fs->fs_id_used < 8; fs->fs_id_used++) {
5191 fs->fs_id[fs->fs_id_used] = ntfs->fs->serial[fs->fs_id_used];
5192 }
5193
5194 /* load the version of the file system */
5195 if (ntfs_load_ver(ntfs)) {
5196 if (tsk_verbose)
5197 fprintf(stderr,
5198 "ntfs_open: Error loading file system version ((%s)\n",
5199 tsk_error_get());
5200 goto on_error;
5201 }
5202
5203 /* load the data block bitmap data run into ntfs_info */
5204 if (ntfs_load_bmap(ntfs)) {
5205 if (tsk_verbose)
5206 fprintf(stderr, "ntfs_open: Error loading block bitmap (%s)\n",
5207 tsk_error_get());
5208 goto on_error;
5209 }
5210
5211 /* load the SID data into ntfs_info ($Secure - $SDS, $SDH, $SII */
5212
5213
5214 #if TSK_USE_SID
5215 if (ntfs_load_secure(ntfs)) {
5216 if (tsk_verbose)
5217 fprintf(stderr, "ntfs_open: Error loading Secure Info (%s)\n",
5218 tsk_error_get());
5219 goto on_error;
5220 }
5221 #endif
5222
5223 // initialize the caches
5224 ntfs->attrdef = NULL;
5225 ntfs->orphan_map = NULL;
5226
5227 // initialize the number of allocated files
5228 ntfs->alloc_file_count = 0;
5229
5230 if (tsk_verbose) {
5231 tsk_fprintf(stderr,
5232 "ssize: %" PRIu16
5233 " csize: %d serial: %" PRIx64 "\n",
5234 tsk_getu16(fs->endian, ntfs->fs->ssize),
5235 ntfs->fs->csize, tsk_getu64(fs->endian, ntfs->fs->serial));
5236 tsk_fprintf(stderr,
5237 "mft_rsize: %d idx_rsize: %d vol: %d mft: %"
5238 PRIu64 " mft_mir: %" PRIu64 "\n",
5239 ntfs->mft_rsize_b, ntfs->idx_rsize_b,
5240 (int) fs->block_count, tsk_getu64(fs->endian,
5241 ntfs->fs->mft_clust), tsk_getu64(fs->endian,
5242 ntfs->fs->mftm_clust));
5243 }
5244 return fs;
5245
5246 on_error:
5247 ntfs_close(fs);
5248 return NULL;
5249 }
5250