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