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