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