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