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 mac.c
12  * Contains the internal functions to process and load a Mac partition table.
13  */
14 #include "tsk_vs_i.h"
15 #include "tsk_mac.h"
16 
17 
18 /*
19  * Process the partition table at the sector address
20  *
21  * It is loaded into the internal sorted list
22  *
23  * Return 1 on error and 0 on success
24  */
25 static uint8_t
mac_load_table(TSK_VS_INFO * vs)26 mac_load_table(TSK_VS_INFO * vs)
27 {
28     char *part_buf;
29     mac_part *part;
30     char *table_str;
31     uint32_t idx, max_part;
32     TSK_DADDR_T taddr = vs->offset / vs->block_size + MAC_PART_SOFFSET;
33     TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector
34 
35     if (tsk_verbose)
36         tsk_fprintf(stderr, "mac_load_table: Sector: %" PRIuDADDR "\n",
37             taddr);
38 
39     /* The table can be variable length, so we loop on it
40      * The idx variable shows which round it is
41      * Each structure is a block size
42      */
43     if ((part_buf = tsk_malloc(vs->block_size)) == NULL)
44         return 1;
45     part = (mac_part *) part_buf;
46 
47     max_part = 1;               /* set it to 1 and it will be set in the first loop */
48     for (idx = 0; idx < max_part; idx++) {
49         uint32_t part_start;
50         uint32_t part_size;
51         uint32_t part_status;
52         char *str;
53         ssize_t cnt;
54         int flag = 0;
55 
56 
57         /* Read the entry */
58         cnt = tsk_vs_read_block
59             (vs, MAC_PART_SOFFSET + idx, part_buf, vs->block_size);
60 
61         /* If -1, then tsk_errno is already set */
62         if (cnt != vs->block_size) {
63             if (cnt >= 0) {
64                 tsk_error_reset();
65                 tsk_error_set_errno(TSK_ERR_VS_READ);
66             }
67             tsk_error_set_errstr2("MAC Partition entry %" PRIuDADDR,
68                 taddr + idx);
69             free(part_buf);
70             return 1;
71         }
72 
73 
74         /* Sanity Check */
75         if (idx == 0) {
76             /* Set the endian ordering the first time around */
77             if (tsk_vs_guessu16(vs, part->magic, MAC_MAGIC)) {
78                 tsk_error_reset();
79                 tsk_error_set_errno(TSK_ERR_VS_MAGIC);
80                 tsk_error_set_errstr("Mac partition table entry (Sector: %"
81                     PRIuDADDR ") %" PRIx16,
82                     (taddr + idx), tsk_getu16(vs->endian, part->magic));
83                 if (tsk_verbose)
84                     tsk_fprintf(stderr,
85                         "mac_load: Missing initial magic value\n");
86                 free(part_buf);
87                 return 1;
88             }
89 
90             /* Get the number of partitions */
91             max_part = tsk_getu32(vs->endian, part->pmap_size);
92         }
93         else if (tsk_getu16(vs->endian, part->magic) != MAC_MAGIC) {
94             tsk_error_reset();
95             tsk_error_set_errno(TSK_ERR_VS_MAGIC);
96             tsk_error_set_errstr("Mac partition table entry (Sector: %"
97                 PRIuDADDR ") %" PRIx16, (taddr + idx),
98                 tsk_getu16(vs->endian, part->magic));
99             if (tsk_verbose)
100                 tsk_fprintf(stderr,
101                     "mac_load: Missing magic value in entry %" PRIu32 "\n",
102                     idx);
103             free(part_buf);
104             return 1;
105         }
106 
107 
108         part_start = tsk_getu32(vs->endian, part->start_sec);
109         part_size = tsk_getu32(vs->endian, part->size_sec);
110         part_status = tsk_getu32(vs->endian, part->status);
111 
112         if (tsk_verbose)
113             tsk_fprintf(stderr,
114                 "mac_load: %" PRIu32 "  Starting Sector: %" PRIu32
115                 "  Size: %" PRIu32 " Type: %s Status: %"PRIu32"\n", idx, part_start,
116                 part_size, part->type, part_status);
117 
118         if (part_size == 0)
119             continue;
120 
121         if (part_status == 0)
122             flag = TSK_VS_PART_FLAG_UNALLOC;
123         else
124             flag = TSK_VS_PART_FLAG_ALLOC;
125 
126         // make sure the first couple are within the bounds of the image.
127         if ((idx < 2) && (part_start > max_addr)) {
128             tsk_error_reset();
129             tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
130             tsk_error_set_errstr
131                 ("mac_load_table: Starting sector too large for image");
132             if (tsk_verbose)
133                 tsk_fprintf(stderr,
134                     "mac_load: Starting sector too large for image (%"
135                     PRIu32 " vs %" PRIu32 ")\n", part_start, max_addr);
136             free(part_buf);
137             return 1;
138         }
139 
140 
141         if ((str = tsk_malloc(sizeof(part->name))) == NULL) {
142             free(part_buf);
143             return 1;
144         }
145 
146         strncpy(str, (char *) part->type, sizeof(part->name));
147 
148         if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
149                 (TSK_DADDR_T) part_size, (TSK_VS_PART_FLAG_ENUM)flag, str, -1,
150                 idx)) {
151             free(part_buf);
152             return 1;
153         }
154     }
155     free(part_buf);
156     part_buf = NULL;
157 
158     // Bail if we didn't find any valid entries
159     if (vs->part_count == 0) {
160         return 1;
161     }
162 
163     /* Add an entry for the table length */
164     if ((table_str = tsk_malloc(16)) == NULL) {
165         return 1;
166     }
167 
168     snprintf(table_str, 16, "Table");
169     if (NULL == tsk_vs_part_add(vs, taddr, max_part, TSK_VS_PART_FLAG_META,
170             table_str, -1, -1)) {
171         return 1;
172     }
173 
174     return 0;
175 }
176 
177 
178 static void
mac_close(TSK_VS_INFO * vs)179 mac_close(TSK_VS_INFO * vs)
180 {
181     vs->tag = 0;
182     tsk_vs_part_free(vs);
183     free(vs);
184 }
185 
186 /*
187  * Process img_info as a Mac disk.  Initialize TSK_VS_INFO or return
188  * NULL on error
189  * */
190 TSK_VS_INFO *
tsk_vs_mac_open(TSK_IMG_INFO * img_info,TSK_DADDR_T offset)191 tsk_vs_mac_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset)
192 {
193     TSK_VS_INFO *vs;
194 
195     // clean up any errors that are lying around
196     tsk_error_reset();
197 
198     if (img_info->sector_size == 0) {
199         tsk_error_reset();
200         tsk_error_set_errno(TSK_ERR_VS_ARG);
201         tsk_error_set_errstr("tsk_vs_mac_open: sector size is 0");
202         return NULL;
203     }
204 
205     vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs));
206     if (vs == NULL)
207         return NULL;
208 
209     vs->img_info = img_info;
210     vs->vstype = TSK_VS_TYPE_MAC;
211     vs->tag = TSK_VS_INFO_TAG;
212 
213     /* If an offset was given, then use that too */
214     vs->offset = offset;
215 
216     //vs->sect_offset = offset + MAC_PART_OFFSET;
217 
218     /* initialize settings */
219     vs->part_list = NULL;
220     vs->part_count = 0;
221     vs->endian = 0;
222     vs->block_size = img_info->sector_size;
223 
224     /* Assign functions */
225     vs->close = mac_close;
226 
227     /* Load the partitions into the sorted list */
228     if (mac_load_table(vs)) {
229 
230         // try some other sector sizes
231         uint8_t returnNull = 1;
232         if (vs->block_size == 512) {
233             if (tsk_verbose)
234                 tsk_fprintf(stderr,
235                     "mac_open: Trying 4096-byte sector size instead of 512-byte\n");
236             vs->block_size = 4096;
237             returnNull = mac_load_table(vs);
238         }
239         else if (vs->block_size == 4096) {
240             if (tsk_verbose)
241                 tsk_fprintf(stderr,
242                     "mac_open: Trying 512-byte sector size instead of 4096-byte\n");
243             vs->block_size = 512;
244             returnNull = mac_load_table(vs);
245         }
246 
247         if (returnNull) {
248             mac_close(vs);
249             return NULL;
250         }
251     }
252 
253     /* fill in the sorted list with the 'unknown' values */
254     if (tsk_vs_part_unused(vs)) {
255         mac_close(vs);
256         return NULL;
257     }
258 
259     return vs;
260 }
261