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  * This software is distributed under the Common Public License 1.0
9  */
10 
11 /** \file bsd.c
12  * Contains the internal functions required to process BSD disk labels.
13  */
14 #include "tsk_vs_i.h"
15 #include "tsk_bsd.h"
16 
17 
18 /*
19  * Return a buffer with a description of the partition type.  The buffer
20  * must be freed by the caller.
21  */
22 static char *
bsd_get_desc(uint8_t fstype)23 bsd_get_desc(uint8_t fstype)
24 {
25     char *str = tsk_malloc(64);
26     if (str == NULL)
27         return "";
28 
29     switch (fstype) {
30 
31     case 0:
32         strncpy(str, "Unused (0x00)", 64);
33         break;
34     case 1:
35         strncpy(str, "Swap (0x01)", 64);
36         break;
37     case 2:
38         strncpy(str, "Version 6 (0x02)", 64);
39         break;
40     case 3:
41         strncpy(str, "Version 7 (0x03)", 64);
42         break;
43     case 4:
44         strncpy(str, "System V (0x04)", 64);
45         break;
46     case 5:
47         strncpy(str, "4.1BSD (0x05)", 64);
48         break;
49     case 6:
50         strncpy(str, "Eighth Edition (0x06)", 64);
51         break;
52     case 7:
53         strncpy(str, "4.2BSD (0x07)", 64);
54         break;
55     case 8:
56         strncpy(str, "MSDOS (0x08)", 64);
57         break;
58     case 9:
59         strncpy(str, "4.4LFS (0x09)", 64);
60         break;
61     case 10:
62         strncpy(str, "Unknown (0x0A)", 64);
63         break;
64     case 11:
65         strncpy(str, "HPFS (0x0B)", 64);
66         break;
67     case 12:
68         strncpy(str, "ISO9660 (0x0C)", 64);
69         break;
70     case 13:
71         strncpy(str, "Boot (0x0D)", 64);
72         break;
73     case 14:
74         strncpy(str, "Vinum (0x0E)", 64);
75         break;
76     default:
77         snprintf(str, 64, "Unknown Type (0x%.2x)", fstype);
78         break;
79     }
80 
81     return str;
82 }
83 
84 /*
85  * Process the partition table at the sector address
86  *
87  * Return 1 on error and 0 if no error
88  */
89 static uint8_t
bsd_load_table(TSK_VS_INFO * a_vs)90 bsd_load_table(TSK_VS_INFO * a_vs)
91 {
92     char *sect_buf;
93     bsd_disklabel *dlabel;
94     uint32_t idx = 0;
95     ssize_t cnt;
96     char *table_str;
97     TSK_DADDR_T laddr = a_vs->offset / a_vs->block_size + BSD_PART_SOFFSET;     // used for printing only
98     TSK_DADDR_T max_addr = (a_vs->img_info->size - a_vs->offset) / a_vs->block_size;    // max sector
99 
100     if (tsk_verbose)
101         tsk_fprintf(stderr,
102             "bsd_load_table: Table Sector: %" PRIuDADDR "\n", laddr);
103 
104     if ((sect_buf = tsk_malloc(a_vs->block_size)) == NULL)
105         return 1;
106     dlabel = (bsd_disklabel *) sect_buf;
107 
108     /* read the block */
109     cnt = tsk_vs_read_block
110         (a_vs, BSD_PART_SOFFSET, sect_buf, a_vs->block_size);
111     if (cnt != a_vs->block_size) {
112         if (cnt >= 0) {
113             tsk_error_reset();
114             tsk_error_set_errno(TSK_ERR_VS_READ);
115         }
116         tsk_error_set_errstr2("BSD Disk Label in Sector: %" PRIuDADDR,
117             laddr);
118         free(sect_buf);
119         return 1;
120     }
121 
122     /* Check the magic  */
123     if (tsk_vs_guessu32(a_vs, dlabel->magic, BSD_MAGIC)) {
124         tsk_error_reset();
125         tsk_error_set_errno(TSK_ERR_VS_MAGIC);
126         tsk_error_set_errstr("BSD partition table (magic #1) (Sector: %"
127             PRIuDADDR ") %" PRIx32, laddr, tsk_getu32(a_vs->endian,
128                 dlabel->magic));
129         free(sect_buf);
130         return 1;
131     }
132 
133     /* Check the second magic value */
134     if (tsk_getu32(a_vs->endian, dlabel->magic2) != BSD_MAGIC) {
135         tsk_error_reset();
136         tsk_error_set_errno(TSK_ERR_VS_MAGIC);
137         tsk_error_set_errstr("BSD disk label (magic #2) (Sector: %"
138             PRIuDADDR ")  %" PRIx32, laddr, tsk_getu32(a_vs->endian,
139                 dlabel->magic2));
140         free(sect_buf);
141         return 1;
142     }
143 
144     /* Add an entry of 1 length for the table  to the internal structure */
145     if ((table_str = tsk_malloc(32)) == NULL) {
146         free(sect_buf);
147         return 1;
148     }
149 
150     snprintf(table_str, 32, "Partition Table");
151     if (NULL == tsk_vs_part_add(a_vs, BSD_PART_SOFFSET,
152             (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, -1, -1)) {
153         free(sect_buf);
154         return 1;
155     }
156 
157     /* Cycle through the partitions, there are either 8 or 16 */
158     for (idx = 0; idx < tsk_getu16(a_vs->endian, dlabel->num_parts); idx++) {
159 
160         uint32_t part_start;
161         uint32_t part_size;
162 
163         part_start = tsk_getu32(a_vs->endian, dlabel->part[idx].start_sec);
164         part_size = tsk_getu32(a_vs->endian, dlabel->part[idx].size_sec);
165 
166         if (tsk_verbose)
167             tsk_fprintf(stderr,
168                 "load_table: %" PRIu32 "  Starting Sector: %" PRIu32
169                 "  Size: %" PRIu32 "  Type: %d\n", idx, part_start,
170                 part_size, dlabel->part[idx].fstype);
171 
172         if (part_size == 0)
173             continue;
174 
175         // make sure the first couple are in the image bounds
176         if ((idx < 2) && (part_start > max_addr)) {
177             tsk_error_reset();
178             tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
179             tsk_error_set_errstr
180                 ("bsd_load_table: Starting sector too large for image");
181             free(sect_buf);
182             return 1;
183         }
184 
185 
186         /* Add the partition to the internal sorted list */
187         if (NULL == tsk_vs_part_add(a_vs, (TSK_DADDR_T) part_start,
188                 (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
189                 bsd_get_desc(dlabel->part[idx].fstype), -1, idx)) {
190             free(sect_buf);
191             return 1;
192         }
193     }
194 
195     free(sect_buf);
196     return 0;
197 }
198 
199 
200 static void
bsd_close(TSK_VS_INFO * a_vs)201 bsd_close(TSK_VS_INFO * a_vs)
202 {
203     a_vs->tag = 0;
204     tsk_vs_part_free(a_vs);
205     free(a_vs);
206 }
207 
208 /*
209  * analyze the image in img_info and process it as BSD
210  * Initialize the TSK_VS_INFO structure
211  *
212  * Return TSK_VS_INFO or NULL if not BSD or an error
213  */
214 TSK_VS_INFO *
tsk_vs_bsd_open(TSK_IMG_INFO * img_info,TSK_DADDR_T offset)215 tsk_vs_bsd_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset)
216 {
217     TSK_VS_INFO *vs;
218 
219     // clean up any errors that are lying around
220     tsk_error_reset();
221 
222     if (img_info->sector_size == 0) {
223         tsk_error_reset();
224         tsk_error_set_errno(TSK_ERR_VS_ARG);
225         tsk_error_set_errstr("tsk_vs_bsd_open: sector size is 0");
226         return NULL;
227     }
228 
229     vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs));
230     if (vs == NULL)
231         return NULL;
232 
233     vs->img_info = img_info;
234     vs->vstype = TSK_VS_TYPE_BSD;
235     vs->tag = TSK_VS_INFO_TAG;
236 
237     /* use the offset provided */
238     vs->offset = offset;
239 
240     /* initialize settings */
241     vs->part_list = NULL;
242     vs->part_count = 0;
243     vs->endian = 0;
244     vs->block_size = img_info->sector_size;
245 
246     /* Assign functions */
247     vs->close = bsd_close;
248 
249     /* Load the partitions into the sorted list */
250     if (bsd_load_table(vs)) {
251         bsd_close(vs);
252         return NULL;
253     }
254 
255     /* fill in the sorted list with the 'unknown' values */
256     if (tsk_vs_part_unused(vs)) {
257         bsd_close(vs);
258         return NULL;
259     }
260 
261     return vs;
262 }
263