/src/sleuthkit/tsk/fs/iso9660_dent.cpp
Line | Count | Source (jump to first uncovered line) |
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 TSK_RETVAL_ENUM |
90 | | iso9660_proc_dir(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir, const char *buf, |
91 | | size_t a_length, TSK_INUM_T a_addr, TSK_OFF_T a_dir_addr) |
92 | 154k | { |
93 | 154k | ISO_INFO *iso = (ISO_INFO *) a_fs; |
94 | 154k | TSK_FS_NAME *fs_name; |
95 | 154k | size_t buf_idx; |
96 | | |
97 | 154k | iso9660_dentry *dd; /* directory descriptor */ |
98 | 154k | iso9660_inode_node *in; |
99 | 154k | 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 | 154k | if (a_length < sizeof(iso9660_dentry)) { |
104 | 3.31k | return TSK_OK; |
105 | 3.31k | } |
106 | | |
107 | 150k | if ((fs_name = tsk_fs_name_alloc(ISO9660_MAXNAMLEN + 1, 0)) == NULL) |
108 | 0 | return TSK_ERR; |
109 | | |
110 | 150k | buf_idx = 0; |
111 | 150k | dd = (iso9660_dentry *) & buf[buf_idx]; |
112 | | |
113 | | /* handle "." entry */ |
114 | 150k | fs_name->meta_addr = a_addr; |
115 | 150k | strcpy(fs_name->name, "."); |
116 | 150k | fs_name->type = TSK_FS_NAME_TYPE_DIR; |
117 | 150k | fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; |
118 | | |
119 | 150k | tsk_fs_dir_add(a_fs_dir, fs_name); |
120 | | |
121 | 150k | buf_idx += dd->entry_len; |
122 | 150k | if (buf_idx > a_length - sizeof(iso9660_dentry)) { |
123 | 3.21k | tsk_fs_name_free(fs_name); |
124 | 3.21k | return TSK_OK; |
125 | 3.21k | } |
126 | 147k | dd = (iso9660_dentry *) & buf[buf_idx]; |
127 | | |
128 | | /* handle ".." entry */ |
129 | 147k | in = iso->in_list; |
130 | 2.19M | while (in |
131 | 2.19M | && (tsk_getu32(a_fs->endian, in->inode.dr.ext_loc_m) != |
132 | 2.08M | tsk_getu32(a_fs->endian, dd->ext_loc_m))) |
133 | 2.05M | in = in->next; |
134 | 147k | if (in) { |
135 | 29.6k | fs_name->meta_addr = in->inum; |
136 | 29.6k | strcpy(fs_name->name, ".."); |
137 | | |
138 | 29.6k | fs_name->type = TSK_FS_NAME_TYPE_DIR; |
139 | 29.6k | fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; |
140 | | |
141 | 29.6k | tsk_fs_dir_add(a_fs_dir, fs_name); |
142 | 29.6k | } |
143 | 147k | buf_idx += dd->entry_len; |
144 | | |
145 | | // process the rest of the entries in the directory |
146 | 968M | while (buf_idx < a_length - sizeof(iso9660_dentry)) { |
147 | 968M | dd = (iso9660_dentry *) & buf[buf_idx]; |
148 | | |
149 | | // process the entry (if it has a defined and valid length) |
150 | 968M | if ((dd->entry_len) && (buf_idx + dd->entry_len <= a_length)) { |
151 | | |
152 | | /* We need to find the data in the pre-processed list because that |
153 | | * contains the meta data address that TSK assigned to this file. |
154 | | * We find the entry by looking for one that was stored at the same |
155 | | * byte offset that we now are. We used to use the extent location, but |
156 | | * we found an image |
157 | | * that had a file with 0 bytes with the same starting block as another |
158 | | * file. */ |
159 | 24.4G | for (in = iso->in_list; in; in = in->next) { |
160 | 23.9G | if (in->dentry_offset == dir_offs + (TSK_OFF_T)buf_idx) |
161 | 840k | break; |
162 | 23.9G | } |
163 | | |
164 | | // we may have not found it because we are reading corrupt data... |
165 | 542M | if (!in) { |
166 | 541M | buf_idx++; |
167 | 541M | continue; |
168 | 541M | } |
169 | | |
170 | | // copy the data in fs_name for loading |
171 | 840k | fs_name->meta_addr = in->inum; |
172 | 840k | strncpy(fs_name->name, in->inode.fn, ISO9660_MAXNAMLEN + 1); |
173 | | |
174 | 840k | if (dd->flags & ISO9660_FLAG_DIR) |
175 | 544k | fs_name->type = TSK_FS_NAME_TYPE_DIR; |
176 | 295k | else |
177 | 295k | fs_name->type = TSK_FS_NAME_TYPE_REG; |
178 | 840k | fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; |
179 | | |
180 | 840k | tsk_fs_dir_add(a_fs_dir, fs_name); |
181 | | |
182 | 840k | buf_idx += dd->entry_len; |
183 | 840k | } |
184 | | /* If the length was not defined, we are probably in a hole in the |
185 | | * directory. The contents are block aligned. So, we |
186 | | * scan ahead until we get either a non-zero entry or the block boundary */ |
187 | 426M | else { |
188 | 426M | buf_idx++; |
189 | 1.05G | for (; buf_idx < a_length - sizeof(iso9660_dentry); buf_idx++) { |
190 | 1.05G | if (buf[buf_idx] != 0) { |
191 | 29.4M | dd = (iso9660_dentry *) & buf[buf_idx]; |
192 | 29.4M | if ((dd->entry_len) |
193 | 29.4M | && (buf_idx + dd->entry_len < a_length)) |
194 | 27.3M | break; |
195 | 29.4M | } |
196 | | |
197 | 1.03G | if (buf_idx % a_fs->block_size == 0) |
198 | 398M | break; |
199 | 1.03G | } |
200 | 426M | } |
201 | 968M | } |
202 | | |
203 | 147k | tsk_fs_name_free(fs_name); |
204 | | |
205 | 147k | return TSK_OK; |
206 | 150k | } |
207 | | |
208 | | |
209 | | |
210 | | /** \internal |
211 | | * Process a directory and load up FS_DIR with the entries. If a pointer to |
212 | | * an already allocated FS_DIR structure is given, it will be cleared. If no existing |
213 | | * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return |
214 | | * value is error or corruption, then the FS_DIR structure could |
215 | | * have entries (depending on when the error occurred). |
216 | | * |
217 | | * @param a_fs File system to analyze |
218 | | * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated |
219 | | * structure or a new structure. |
220 | | * @param a_addr Address of directory to process. |
221 | | * @param recursion_depth Recursion depth to limit the number of self-calls |
222 | | * @returns error, corruption, ok etc. |
223 | | */ |
224 | | TSK_RETVAL_ENUM |
225 | | iso9660_dir_open_meta( |
226 | | TSK_FS_INFO * a_fs, |
227 | | TSK_FS_DIR ** a_fs_dir, |
228 | | TSK_INUM_T a_addr, |
229 | | [[maybe_unused]] int recursion_depth) |
230 | 247k | { |
231 | 247k | TSK_RETVAL_ENUM retval; |
232 | 247k | TSK_FS_DIR *fs_dir; |
233 | 247k | ssize_t cnt; |
234 | 247k | char *buf; |
235 | 247k | size_t length; |
236 | | |
237 | 247k | if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) { |
238 | 0 | tsk_error_reset(); |
239 | 0 | tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); |
240 | 0 | tsk_error_set_errstr |
241 | 0 | ("iso9660_dir_open_meta: Invalid inode value: %" PRIuINUM, |
242 | 0 | a_addr); |
243 | 0 | return TSK_ERR; |
244 | 0 | } |
245 | 247k | else if (a_fs_dir == NULL) { |
246 | 0 | tsk_error_reset(); |
247 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
248 | 0 | tsk_error_set_errstr |
249 | 0 | ("iso9660_dir_open_meta: NULL fs_attr argument given"); |
250 | 0 | return TSK_ERR; |
251 | 0 | } |
252 | | |
253 | 247k | if (tsk_verbose) |
254 | 0 | tsk_fprintf(stderr, |
255 | 0 | "iso9660_dir_open_meta: Processing directory %" PRIuINUM "\n", |
256 | 0 | a_addr); |
257 | | |
258 | 247k | fs_dir = *a_fs_dir; |
259 | 247k | if (fs_dir) { |
260 | 0 | tsk_fs_dir_reset(fs_dir); |
261 | 0 | fs_dir->addr = a_addr; |
262 | 0 | } |
263 | 247k | else { |
264 | 247k | if ((*a_fs_dir = fs_dir = |
265 | 247k | tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) { |
266 | 0 | return TSK_ERR; |
267 | 0 | } |
268 | 247k | } |
269 | | |
270 | | // handle the orphan directory if its contents were requested |
271 | 247k | if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { |
272 | 3.92k | return tsk_fs_dir_find_orphans(a_fs, fs_dir); |
273 | 3.92k | } |
274 | | |
275 | 243k | fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr); |
276 | 243k | if (fs_dir->fs_file == NULL) { |
277 | 8 | tsk_error_reset(); |
278 | 8 | tsk_error_set_errno(TSK_ERR_FS_INODE_NUM); |
279 | 8 | tsk_error_set_errstr("iso9660_dir_open_meta: %" PRIuINUM |
280 | 8 | " is not a valid inode", a_addr); |
281 | 8 | return TSK_COR; |
282 | 8 | } |
283 | | |
284 | | /* read directory extent into memory */ |
285 | 243k | length = (size_t) fs_dir->fs_file->meta->size; |
286 | 243k | if ((buf = (char*) tsk_malloc(length)) == NULL) |
287 | 0 | return TSK_ERR; |
288 | | |
289 | 243k | cnt = tsk_fs_file_read(fs_dir->fs_file, 0, buf, length, TSK_FS_FILE_READ_FLAG_NONE); |
290 | 243k | if (cnt != (ssize_t)length) { |
291 | 89.3k | if (cnt >= 0) { |
292 | 47.7k | tsk_error_reset(); |
293 | 47.7k | tsk_error_set_errno(TSK_ERR_FS_READ); |
294 | 47.7k | } |
295 | 89.3k | tsk_error_set_errstr2("iso9660_dir_open_meta"); |
296 | 89.3k | free(buf); |
297 | 89.3k | return TSK_ERR; |
298 | 89.3k | } |
299 | | |
300 | | // process the contents |
301 | 154k | retval = iso9660_proc_dir(a_fs, fs_dir, buf, length, a_addr, |
302 | 154k | fs_dir->fs_file->meta->attr->head->nrd.run->addr); |
303 | | |
304 | | // if we are listing the root directory, add the Orphan directory entry |
305 | 154k | if (a_addr == a_fs->root_inum) { |
306 | 18.1k | TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0); |
307 | 18.1k | if (fs_name == NULL) { |
308 | 0 | free(buf); |
309 | 0 | return TSK_ERR; |
310 | 0 | } |
311 | | |
312 | 18.1k | if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) { |
313 | 0 | tsk_fs_name_free(fs_name); |
314 | 0 | free(buf); |
315 | 0 | return TSK_ERR; |
316 | 0 | } |
317 | | |
318 | 18.1k | if (tsk_fs_dir_add(fs_dir, fs_name)) { |
319 | 0 | tsk_fs_name_free(fs_name); |
320 | 0 | free(buf); |
321 | 0 | return TSK_ERR; |
322 | 0 | } |
323 | 18.1k | tsk_fs_name_free(fs_name); |
324 | 18.1k | } |
325 | | |
326 | 154k | free(buf); |
327 | 154k | return retval; |
328 | 154k | } |
329 | | |
330 | | int |
331 | | iso9660_name_cmp( |
332 | | [[maybe_unused]] TSK_FS_INFO * a_fs_info, |
333 | | const char *s1, |
334 | | const char *s2) |
335 | 0 | { |
336 | 0 | return strcmp(s1, s2); |
337 | 0 | } |