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