1 /*
2 * The Sleuth Kit
3 *
4 * Brian Carrier [carrier <at> sleuthkit [dot] org]
5 * Copyright (c) 2006-2011 Brian Carrier, Basis Technology. All rights reserved
6 * Copyright (c) 2003-2005 Brian Carrier. All rights reserved
7 *
8 * SUN - Sun VTOC code
9 *
10 * This software is distributed under the Common Public License 1.0
11 */
12
13 /** \file sun.c
14 * Contains the internal SUN VTOC volume system processing code.
15 */
16 #include "tsk_vs_i.h"
17 #include "tsk_sun.h"
18
19
20 /*
21 * Return a buffer with a description of the partition type
22 */
23 static char *
24 sun_get_desc(uint16_t fstype)
25 {
26 char *str = tsk_malloc(64);
27 if (str == NULL)
28 return "";
29 switch (fstype) {
30
31 case 0:
32 strncpy(str, "Unassigned (0x00)", 64);
33 break;
34 case 1:
35 strncpy(str, "boot (0x01)", 64);
36 break;
37 case 2:
38 strncpy(str, "/ (0x02)", 64);
39 break;
40 case 3:
41 strncpy(str, "swap (0x03)", 64);
42 break;
tsk_vs_type_toid(const TSK_TCHAR * str)43 case 4:
44 strncpy(str, "/usr/ (0x04)", 64);
45 break;
46 case 5:
47 strncpy(str, "backup (0x05)", 64);
48 break;
49 case 6:
50 strncpy(str, "stand (0x06)", 64);
51 break;
52 case 7:
53 strncpy(str, "/var/ (0x07)", 64);
54 break;
55 case 8:
56 strncpy(str, "/home/ (0x08)", 64);
57 break;
58 case 9:
59 strncpy(str, "alt sector (0x09)", 64);
60 break;
61 case 10:
62 strncpy(str, "cachefs (0x0A)", 64);
63 break;
64 default:
65 snprintf(str, 64, "Unknown Type (0x%.4x)", fstype);
tsk_vs_type_toid_utf8(const char * str)66 break;
67 }
68
69 return str;
70 }
71
72
73 /*
74 * Load an Intel disk label, this is called by sun_load_table
75 */
76
77 static uint8_t
78 sun_load_table_i386(TSK_VS_INFO * vs, sun_dlabel_i386 * dlabel_x86)
79 {
80 uint32_t idx = 0;
81 uint16_t num_parts;
82 TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector
83
tsk_vs_type_print(FILE * hFile)84 if (tsk_verbose)
85 tsk_fprintf(stderr, "load_table_i386: Number of partitions: %d\n",
86 tsk_getu16(vs->endian, dlabel_x86->num_parts));
87
88 num_parts = tsk_getu16(vs->endian, dlabel_x86->num_parts);
89 if (num_parts > 16) {
90 num_parts = 16;
91 }
92
93 /* Cycle through the partitions, there are 16 for i386 */
94 for (idx = 0; idx < num_parts; idx++) {
95 TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
96
97 if (tsk_verbose)
tsk_vs_type_supported()98 tsk_fprintf(stderr,
99 "load_table_i386: %" PRIu32
100 " Starting Sector: %" PRIu32 " Size: %" PRIu32
101 " Type: %" PRIu16 "\n", idx, tsk_getu32(vs->endian,
102 dlabel_x86->part[idx].start_sec),
103 tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec),
104 tsk_getu16(vs->endian, dlabel_x86->part[idx].type));
105
106 if (tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec) == 0)
107 continue;
108
109 // make sure the first couple are in the image bounds
110 if ((idx < 2) && (tsk_getu32(vs->endian,
111 dlabel_x86->part[idx].start_sec) > max_addr)) {
112 tsk_error_reset();
113 tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
114 tsk_error_set_errstr
115 ("sun_load_i386: Starting sector too large for image");
116 return 1;
117 }
tsk_vs_type_toname(TSK_VS_TYPE_ENUM type)118
119 // set the entry that covers the entire disk image as DESC
120 if ((tsk_getu16(vs->endian, dlabel_x86->part[idx].type) == 5)
121 && (tsk_getu32(vs->endian,
122 dlabel_x86->part[idx].start_sec) == 0))
123 ptype = TSK_VS_PART_FLAG_META;
124
125 /* Add the partition to the internal sorted list */
126 if (NULL == tsk_vs_part_add(vs,
127 (TSK_DADDR_T) tsk_getu32(vs->endian,
128 dlabel_x86->part[idx].start_sec),
129 (TSK_DADDR_T) tsk_getu32(vs->endian,
130 dlabel_x86->part[idx].size_sec), ptype,
131 sun_get_desc(tsk_getu16(vs->endian,
132 dlabel_x86->part[idx].type)), -1, idx)) {
133 return 1;
134 }
135 }
136
137 return 0;
138 }
139
140
tsk_vs_type_todesc(TSK_VS_TYPE_ENUM type)141 /* load a sparc disk label, this is called from the general
142 * sun_load_table
143 */
144 static uint8_t
145 sun_load_table_sparc(TSK_VS_INFO * vs, sun_dlabel_sparc * dlabel_sp)
146 {
147 uint32_t idx = 0;
148 uint32_t cyl_conv;
149 uint16_t num_parts;
150 TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector
151
152 /* The value to convert cylinders to sectors */
153 cyl_conv = (uint32_t) tsk_getu16(vs->endian, dlabel_sp->sec_per_tr) *
154 tsk_getu16(vs->endian, dlabel_sp->num_head);
155
156 if (tsk_verbose)
157 tsk_fprintf(stderr, "load_table_sparc: Number of partitions: %d\n",
158 tsk_getu16(vs->endian, dlabel_sp->num_parts));
159
160 num_parts = tsk_getu16(vs->endian, dlabel_sp->num_parts);
161 if (num_parts > 8) {
162 num_parts = 8;
163 }
164
165 /* Cycle through the partitions, there are 8 for sparc */
166 for (idx = 0; idx < num_parts; idx++) {
167 TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
168 uint32_t part_start = cyl_conv * tsk_getu32(vs->endian,
169 dlabel_sp->part_layout[idx].start_cyl);
170
171 uint32_t part_size = tsk_getu32(vs->endian,
172 dlabel_sp->part_layout[idx].size_blk);
173
174 if (tsk_verbose)
175 tsk_fprintf(stderr,
176 "load_table_sparc: %" PRIu32
177 " Starting Sector: %" PRIu32 " Size: %" PRIu32
178 " Type: %" PRIu16 "\n", idx, part_start, part_size,
179 tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type));
180
181 if (part_size == 0)
182 continue;
183
184 // make sure the first couple are in the image bounds
185 if ((idx < 2) && (part_start > max_addr)) {
186 tsk_error_reset();
187 tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
188 tsk_error_set_errstr
189 ("sun_load_sparc: Starting sector too large for image");
190 return 1;
191 }
192
193 // set the entry that covers the entire disk image as DESC
194 if ((tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type) == 5)
195 && (part_start == 0))
196 ptype = TSK_VS_PART_FLAG_META;
197
198 /* Add the partition to the internal sorted list */
199 if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
200 (TSK_DADDR_T) part_size, ptype,
201 sun_get_desc(tsk_getu16(vs->endian,
202 dlabel_sp->part_meta[idx].type)), -1, idx))
203 return 1;
204
205 }
206
207 return 0;
208 }
209
210
211 /*
212 * Process the partition table at the sector address
213 *
214 * This method just finds out if it is sparc or Intel and then
215 * calls the appropriate method
216 *
217 * Return 0 on success and 1 on error
218 */
219 static uint8_t
220 sun_load_table(TSK_VS_INFO * vs)
221 {
222 sun_dlabel_sparc *dlabel_sp;
223 sun_dlabel_i386 *dlabel_x86;
224 char *buf;
225 ssize_t cnt;
226 TSK_DADDR_T taddr =
227 vs->offset / vs->block_size + SUN_SPARC_PART_SOFFSET;
228 int result = 0;
229
230
231 /* Sanity check in case label sizes change */
232 if ((sizeof(*dlabel_sp) > vs->block_size) ||
233 (sizeof(*dlabel_x86) > vs->block_size)) {
234 tsk_error_reset();
235 tsk_error_set_errno(TSK_ERR_VS_BUF);
236 tsk_error_set_errstr
237 ("sun_load_table: disk labels bigger than block size");
238 return 1;
239 }
240
241 if (tsk_verbose)
242 tsk_fprintf(stderr,
243 "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr);
244
245 if ((buf = tsk_malloc(vs->block_size)) == NULL) {
246 goto on_error;
247 }
248
249 /* Try the given offset */
250 cnt = tsk_vs_read_block
251 (vs, SUN_SPARC_PART_SOFFSET, buf, vs->block_size);
252
253 /* If -1 is returned, tsk_errno is already set */
254 if (cnt != vs->block_size) {
255 if (cnt >= 0) {
256 tsk_error_reset();
257 tsk_error_set_errno(TSK_ERR_VS_READ);
258 }
259 tsk_error_set_errstr2("SUN Disk Label in Sector: %" PRIuDADDR,
260 taddr);
261 goto on_error;
262 }
263
264
265 /* Check the magic value
266 * Both intel and sparc have the magic value in the same location
267 *
268 * We try both in case someone specifies the exact location of the
269 * intel disk label.
270 * */
271 dlabel_sp = (sun_dlabel_sparc *) buf;
272 dlabel_x86 = (sun_dlabel_i386 *) buf;
273 if (tsk_vs_guessu16(vs, dlabel_sp->magic, SUN_MAGIC) == 0) {
274 if (tsk_getu32(vs->endian, dlabel_sp->sanity) == SUN_SANITY) {
275 result = sun_load_table_sparc(vs, dlabel_sp);
276 // TODO: I assume based on the existing free that the previous function
277 // does not take ownership of buf.
278 free(buf);
279 return result;
280 }
281 else if (tsk_getu32(vs->endian, dlabel_x86->sanity) == SUN_SANITY) {
282 result = sun_load_table_i386(vs, dlabel_x86);
283 // TODO: I assume based on the existing free that the previous function
284 // does not take ownership of buf.
285 free(buf);
286 return result;
287 }
288 }
289
290
291 /* Now try the next sector, which is where the intel
292 * could be stored */
293
294 taddr = vs->offset / vs->block_size / SUN_I386_PART_SOFFSET;
295 if (tsk_verbose)
296 tsk_fprintf(stderr,
297 "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr + 1);
298
299 cnt = tsk_vs_read_block
300 (vs, SUN_I386_PART_SOFFSET, buf, vs->block_size);
301
302 if (cnt != vs->block_size) {
303 if (cnt >= 0) {
304 tsk_error_reset();
305 tsk_error_set_errno(TSK_ERR_VS_READ);
306 }
307 tsk_error_set_errstr2("SUN (Intel) Disk Label in Sector: %"
308 PRIuDADDR, taddr);
309 goto on_error;
310 }
311
312 dlabel_x86 = (sun_dlabel_i386 *) buf;
313 if (tsk_vs_guessu16(vs, dlabel_x86->magic, SUN_MAGIC)) {
314 tsk_error_reset();
315 tsk_error_set_errno(TSK_ERR_VS_MAGIC);
316 tsk_error_set_errstr("SUN (intel) partition table (Sector: %"
317 PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
318 dlabel_sp->magic));
319 goto on_error;
320 }
321
322 if (tsk_getu32(vs->endian, dlabel_x86->sanity) != SUN_SANITY) {
323 tsk_error_reset();
324 tsk_error_set_errno(TSK_ERR_VS_MAGIC);
325 tsk_error_set_errstr("SUN (intel) sanity value (Sector: %"
326 PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
327 dlabel_sp->magic));
328 goto on_error;
329 }
330
331 result = sun_load_table_i386(vs, dlabel_x86);
332 // TODO: I assume based on the existing free that the previous function
333 // does not take ownership of buf.
334 free(buf);
335 return result;
336
337 on_error:
338 free(buf);
339 return 1;
340 }
341
342
343 static void
344 sun_close(TSK_VS_INFO * vs)
345 {
346 vs->tag = 0;
347 tsk_vs_part_free(vs);
348 free(vs);
349 }
350
351 TSK_VS_INFO *
352 tsk_vs_sun_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset)
353 {
354 TSK_VS_INFO *vs;
355
356 // clean up any errors that are lying around
357 tsk_error_reset();
358
359 if (img_info->sector_size == 0) {
360 tsk_error_reset();
361 tsk_error_set_errno(TSK_ERR_VS_ARG);
362 tsk_error_set_errstr("tsk_vs_sun_open: sector size is 0");
363 return NULL;
364 }
365
366 vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs));
367 if (vs == NULL)
368 return NULL;
369
370 vs->img_info = img_info;
371 vs->vstype = TSK_VS_TYPE_SUN;
372 vs->tag = TSK_VS_INFO_TAG;
373
374 vs->offset = offset;
375
376 /* initialize settings */
377 vs->part_list = NULL;
378 vs->part_count = 0;
379 vs->endian = 0;
380 vs->block_size = img_info->sector_size;
381
382 /* Assign functions */
383 vs->close = sun_close;
384
385 /* Load the partitions into the sorted list */
386 if (sun_load_table(vs)) {
387 sun_close(vs);
388 return NULL;
389 }
390
391 /* fill in the sorted list with the 'unknown' values */
392 if (tsk_vs_part_unused(vs)) {
393 sun_close(vs);
394 return NULL;
395 }
396
397 return vs;
398 }
399