1 /*
2 ** The Sleuth Kit
3 **
4 ** Brian Carrier [carrier <at> sleuthkit [dot] org]
5 ** Copyright (c)2007 Brian Carrier.  All righs reserved.
6 **
7 **
8 ** This software is subject to the IBM Public License ver. 1.0,
9 ** which was displayed prior to download and is included in the readme.txt
10 ** file accompanying the Sleuth Kit files.  It may also be requested from:
11 ** Crucial Security Inc.
12 ** 14900 Conference Center Drive
13 ** Chantilly, VA 20151
14 **
15 ** Copyright (c) 2007-2011 Brian Carrier.  All rights reserved
16 **
17 ** Wyatt Banks [wbanks@crucialsecurity.com]
18 ** Copyright (c) 2005 Crucial Security Inc.  All rights reserved.
19 **
20 ** Brian Carrier [carrier <at> sleuthkit [dot] org]
21 ** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
22 **
23 ** Copyright (c) 1997,1998,1999, International Business Machines
24 ** Corporation and others. All Rights Reserved.
25 */
26 
27 /* TCT
28  * LICENSE
29  *      This software is distributed under the IBM Public License.
30  * AUTHOR(S)
31  *      Wietse Venema
32  *      IBM T.J. Watson Research
33  *      P.O. Box 704
34  *      Yorktown Heights, NY 10598, USA
35  --*/
36 
37 /*
38 ** You may distribute the Sleuth Kit, or other software that incorporates
39 ** part of all of the Sleuth Kit, in object code form under a license agreement,
40 ** provided that:
41 ** a) you comply with the terms and conditions of the IBM Public License
42 **    ver 1.0; and
43 ** b) the license agreement
44 **     i) effectively disclaims on behalf of all Contributors all warranties
45 **        and conditions, express and implied, including warranties or
46 **        conditions of title and non-infringement, and implied warranties
47 **        or conditions of merchantability and fitness for a particular
48 **        purpose.
49 **    ii) effectively excludes on behalf of all Contributors liability for
50 **        damages, including direct, indirect, special, incidental and
51 **        consequential damages such as lost profits.
52 **   iii) states that any provisions which differ from IBM Public License
53 **        ver. 1.0 are offered by that Contributor alone and not by any
54 **        other party; and
55 **    iv) states that the source code for the program is available from you,
56 **        and informs licensees how to obtain it in a reasonable manner on or
57 **        through a medium customarily used for software exchange.
58 **
59 ** When the Sleuth Kit or other software that incorporates part or all of
60 ** the Sleuth Kit is made available in source code form:
61 **     a) it must be made available under IBM Public License ver. 1.0; and
62 **     b) a copy of the IBM Public License ver. 1.0 must be included with
63 **        each copy of the program.
64 */
65 
66 /**
67  * \file iso9660_dent.c
68  * Contains the internal TSK ISO9660 file system code to handle the parsing of
69  * file names and directory structures.
70  */
71 
72 #include "tsk_fs_i.h"
73 #include "tsk_iso9660.h"
74 
75 
76 
77 /** \internal
78  * process the data from inside of a directory and load the corresponding
79  * file data into a TSK_FS_DIR structure.
80  *
81  * @param a_fs File system
82  * @param a_fs_dir Structure to store file names into
83  * @param buf Buffer that contains the directory content
84  * @param a_length Number of bytes in buffer
85  * @param a_addr The metadata address for the directory being processed
86  * @param a_dir_addr The block offset where this directory starts
87  * @returns TSK_ERR on error and TSK_OK otherwise
88  */
89 static uint8_t
iso9660_proc_dir(TSK_FS_INFO * a_fs,TSK_FS_DIR * a_fs_dir,char * buf,size_t a_length,TSK_INUM_T a_addr,TSK_OFF_T a_dir_addr)90 iso9660_proc_dir(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir, char *buf,
91     size_t a_length, TSK_INUM_T a_addr, TSK_OFF_T a_dir_addr)
92 {
93     ISO_INFO *iso = (ISO_INFO *) a_fs;
94     TSK_FS_NAME *fs_name;
95     size_t buf_idx;
96 
97     iso9660_dentry *dd;         /* directory descriptor */
98     iso9660_inode_node *in;
99     TSK_OFF_T dir_offs = a_dir_addr * a_fs->block_size;
100 
101     // had an issue once where dir was too small
102     // many later calculations assume we can fit at least one entry
103     if (a_length < sizeof(iso9660_dentry)) {
104         return TSK_OK;
105     }
106 
107     if ((fs_name = tsk_fs_name_alloc(ISO9660_MAXNAMLEN + 1, 0)) == NULL)
108         return TSK_ERR;
109 
110     buf_idx = 0;
111     dd = (iso9660_dentry *) & buf[buf_idx];
112 
113     /* handle "." entry */
114     fs_name->meta_addr = a_addr;
115     strcpy(fs_name->name, ".");
116     fs_name->type = TSK_FS_NAME_TYPE_DIR;
117     fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
118 
119     tsk_fs_dir_add(a_fs_dir, fs_name);
120 
121     buf_idx += dd->entry_len;
122     if (buf_idx > a_length - sizeof(iso9660_dentry)) {
123         free(buf);
124         tsk_fs_name_free(fs_name);
125         return TSK_OK;
126     }
127     dd = (iso9660_dentry *) & buf[buf_idx];
128 
129     /* handle ".." entry */
130     in = iso->in_list;
131     while (in
132         && (tsk_getu32(a_fs->endian, in->inode.dr.ext_loc_m) !=
133             tsk_getu32(a_fs->endian, dd->ext_loc_m)))
134         in = in->next;
135     if (in) {
136         fs_name->meta_addr = in->inum;
137         strcpy(fs_name->name, "..");
138 
139         fs_name->type = TSK_FS_NAME_TYPE_DIR;
140         fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
141 
142         tsk_fs_dir_add(a_fs_dir, fs_name);
143     }
144     buf_idx += dd->entry_len;
145 
146     // process the rest of the entries in the directory
147     while (buf_idx < a_length - sizeof(iso9660_dentry)) {
148         dd = (iso9660_dentry *) & buf[buf_idx];
149 
150         // process the entry (if it has a defined and valid length)
151         if ((dd->entry_len) && (buf_idx + dd->entry_len <= a_length)) {
152 
153             /* We need to find the data in the pre-processed list because that
154              * contains the meta data address that TSK assigned to this file.
155              * We find the entry by looking for one that was stored at the same
156              * byte offset that we now are.  We used to use the extent location, but
157              * we found an image
158              * that had a file with 0 bytes with the same starting block as another
159              * file. */
160             for (in = iso->in_list; in; in = in->next) {
161                 if (in->dentry_offset == dir_offs + (TSK_OFF_T)buf_idx)
162                     break;
163             }
164 
165             // we may have not found it because we are reading corrupt data...
166             if (!in) {
167                 buf_idx++;
168                 continue;
169             }
170 
171             // copy the data in fs_name for loading
172             fs_name->meta_addr = in->inum;
173             strncpy(fs_name->name, in->inode.fn, ISO9660_MAXNAMLEN);
174 
175             if (dd->flags & ISO9660_FLAG_DIR)
176                 fs_name->type = TSK_FS_NAME_TYPE_DIR;
177             else
178                 fs_name->type = TSK_FS_NAME_TYPE_REG;
179             fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
180 
181             tsk_fs_dir_add(a_fs_dir, fs_name);
182 
183             buf_idx += dd->entry_len;
184         }
185         /* If the length was not defined, we are probably in a hole in the
186          * directory.  The contents are  block aligned. So, we
187          * scan ahead until we get either a non-zero entry or the block boundary */
188         else {
189             buf_idx++;
190             for (; buf_idx < a_length - sizeof(iso9660_dentry); buf_idx++) {
191                 if (buf[buf_idx] != 0) {
192                     dd = (iso9660_dentry *) & buf[buf_idx];
193                     if ((dd->entry_len)
194                         && (buf_idx + dd->entry_len < a_length))
195                         break;
196                 }
197 
198                 if (buf_idx % a_fs->block_size == 0)
199                     break;
200             }
201         }
202     }
203 
204     free(buf);
205     tsk_fs_name_free(fs_name);
206 
207     return TSK_OK;
208 }
209 
210 
211 
212 /** \internal
213  * Process a directory and load up FS_DIR with the entries. If a pointer to
214  * an already allocated FS_DIR structure is given, it will be cleared.  If no existing
215  * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return
216  * value is error or corruption, then the FS_DIR structure could
217  * have entries (depending on when the error occurred).
218  *
219  * @param a_fs File system to analyze
220  * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated
221  * structure or a new structure.
222  * @param a_addr Address of directory to process.
223  * @returns error, corruption, ok etc.
224  */
225 TSK_RETVAL_ENUM
iso9660_dir_open_meta(TSK_FS_INFO * a_fs,TSK_FS_DIR ** a_fs_dir,TSK_INUM_T a_addr)226 iso9660_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
227     TSK_INUM_T a_addr)
228 {
229     TSK_RETVAL_ENUM retval;
230     TSK_FS_DIR *fs_dir;
231     ssize_t cnt;
232     char *buf;
233     size_t length;
234 
235     if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) {
236         tsk_error_reset();
237         tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
238         tsk_error_set_errstr
239             ("iso9660_dir_open_meta: Invalid inode value: %" PRIuINUM,
240             a_addr);
241         return TSK_ERR;
242     }
243     else if (a_fs_dir == NULL) {
244         tsk_error_reset();
245         tsk_error_set_errno(TSK_ERR_FS_ARG);
246         tsk_error_set_errstr
247             ("iso9660_dir_open_meta: NULL fs_attr argument given");
248         return TSK_ERR;
249     }
250 
251     if (tsk_verbose)
252         tsk_fprintf(stderr,
253             "iso9660_dir_open_meta: Processing directory %" PRIuINUM "\n",
254             a_addr);
255 
256     fs_dir = *a_fs_dir;
257     if (fs_dir) {
258         tsk_fs_dir_reset(fs_dir);
259         fs_dir->addr = a_addr;
260     }
261     else {
262         if ((*a_fs_dir = fs_dir =
263                 tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) {
264             return TSK_ERR;
265         }
266     }
267 
268     //  handle the orphan directory if its contents were requested
269     if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) {
270         return tsk_fs_dir_find_orphans(a_fs, fs_dir);
271     }
272 
273     fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr);
274     if (fs_dir->fs_file == NULL) {
275         tsk_error_reset();
276         tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
277         tsk_error_set_errstr("iso9660_dir_open_meta: %" PRIuINUM
278             " is not a valid inode", a_addr);
279         return TSK_COR;
280     }
281 
282     /* read directory extent into memory */
283     length = (size_t) fs_dir->fs_file->meta->size;
284     if ((buf = tsk_malloc(length)) == NULL)
285         return TSK_ERR;
286 
287     cnt = tsk_fs_file_read(fs_dir->fs_file, 0, buf, length, 0);
288     if (cnt != (ssize_t)length) {
289         if (cnt >= 0) {
290             tsk_error_reset();
291             tsk_error_set_errno(TSK_ERR_FS_READ);
292         }
293         tsk_error_set_errstr2("iso9660_dir_open_meta");
294         return TSK_ERR;
295     }
296 
297     // process the contents
298     retval = iso9660_proc_dir(a_fs, fs_dir, buf, length, a_addr,
299         fs_dir->fs_file->meta->attr->head->nrd.run->addr);
300 
301     // if we are listing the root directory, add the Orphan directory entry
302     if (a_addr == a_fs->root_inum) {
303         TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0);
304         if (fs_name == NULL)
305             return TSK_ERR;
306 
307         if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) {
308             tsk_fs_name_free(fs_name);
309             return TSK_ERR;
310         }
311 
312         if (tsk_fs_dir_add(fs_dir, fs_name)) {
313             tsk_fs_name_free(fs_name);
314             return TSK_ERR;
315         }
316         tsk_fs_name_free(fs_name);
317     }
318 
319     return retval;
320 }
321 
322 int
iso9660_name_cmp(TSK_FS_INFO * a_fs_info,const char * s1,const char * s2)323 iso9660_name_cmp(TSK_FS_INFO * a_fs_info, const char *s1, const char *s2)
324 {
325     return strcmp(s1, s2);
326 }
327