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