1 /*
2  * Brian Carrier [carrier <at> sleuthkit [dot] org]
3  * Copyright (c) 2006-2011 Brian Carrier, Basis Technology.  All rights reserved
4  *
5  * This software is distributed under the Common Public License 1.0
6  */
7 
8 /**
9  * \file aff.c
10  * Internal code to interface with afflib to read and open AFF image files
11  */
12 
13 #include "tsk_img_i.h"
14 
15 #if HAVE_LIBAFFLIB
16 
17 typedef int bool;
18 
19 #include "aff.h"
20 
21 /* Note: The routine -assumes- we are under a lock on &(img_info->cache_lock)) */
22 static ssize_t
aff_read(TSK_IMG_INFO * img_info,TSK_OFF_T offset,char * buf,size_t len)23 aff_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf, size_t len)
24 {
25     ssize_t cnt;
26     IMG_AFF_INFO *aff_info = (IMG_AFF_INFO *) img_info;
27 
28     if (tsk_verbose)
29         tsk_fprintf(stderr,
30             "aff_read: byte offset: %" PRIdOFF " len: %" PRId64
31             "\n", offset, len);
32 
33     if (offset > img_info->size) {
34         tsk_error_reset();
35         tsk_error_set_errno(TSK_ERR_IMG_READ_OFF);
36         tsk_error_set_errstr("aff_read - %" PRIdOFF, offset);
37         return -1;
38     }
39 
40     if (aff_info->seek_pos != offset) {
41         if (af_seek(aff_info->af_file, offset, SEEK_SET) != (uint64_t)offset) {
42             tsk_error_reset();
43             // @@@ ADD more specific error messages
44             tsk_error_set_errno(TSK_ERR_IMG_SEEK);
45             tsk_error_set_errstr("aff_read - %" PRIdOFF " - %s", offset,
46                 strerror(errno));
47             return -1;
48 
49         }
50         aff_info->seek_pos = offset;
51     }
52 
53     cnt = af_read(aff_info->af_file, (unsigned char *) buf, len);
54     if (cnt < 0) {
55         // @@@ Add more specific error message
56         tsk_error_reset();
57         tsk_error_set_errno(TSK_ERR_IMG_READ);
58         tsk_error_set_errstr("aff_read - offset: %" PRIdOFF " - len: %"
59             PRIuSIZE " - %s", offset, len, strerror(errno));
60         return -1;
61     }
62 
63     /* AFF will return 0 if the page does not exist -- fill the
64      * buffer with zeros in this case */
65     if (cnt == 0) {
66         // @@@ We could improve this if there is an AFF call
67         // to see if the data exists or not
68         if ((af_eof(aff_info->af_file) == 0) &&
69             (offset + (TSK_OFF_T)len < img_info->size)) {
70             memset(buf, 0, len);
71             cnt = len;
72         }
73     }
74 
75     aff_info->seek_pos += cnt;
76     return cnt;
77 }
78 
79 static void
aff_imgstat(TSK_IMG_INFO * img_info,FILE * hFile)80 aff_imgstat(TSK_IMG_INFO * img_info, FILE * hFile)
81 {
82     IMG_AFF_INFO *aff_info = (IMG_AFF_INFO *) img_info;
83     unsigned char buf[512];
84     size_t buf_len = 512;
85 
86 
87     tsk_fprintf(hFile, "IMAGE FILE INFORMATION\n");
88     tsk_fprintf(hFile, "--------------------------------------------\n");
89     tsk_fprintf(hFile, "Image Type: ");
90     switch (aff_info->type) {
91     case AF_IDENTIFY_AFF:
92         tsk_fprintf(hFile, "AFF\n");
93         break;
94     case AF_IDENTIFY_AFD:
95         tsk_fprintf(hFile, "AFD\n");
96         break;
97     case AF_IDENTIFY_AFM:
98         tsk_fprintf(hFile, "AFM\n");
99         break;
100     default:
101         tsk_fprintf(hFile, "AFFLIB (%d)\n", aff_info->type);
102         break;
103     }
104 
105     tsk_fprintf(hFile, "\nSize in bytes: %" PRIdOFF "\n", img_info->size);
106 
107     // we won't have the rest of the info for the non-AFF formats.
108     if (img_info->itype == TSK_IMG_TYPE_AFF_ANY)
109         return;
110 
111     tsk_fprintf(hFile, "\nMD5: ");
112     if (af_get_seg(aff_info->af_file, AF_MD5, NULL, buf, &buf_len) == 0) {
113         int i;
114         for (i = 0; i < 16; i++) {
115             tsk_fprintf(hFile, "%x", buf[i]);
116         }
117         tsk_fprintf(hFile, "\n");
118     }
119     else {
120         tsk_fprintf(hFile, "Segment not found\n");
121     }
122 
123     buf_len = 512;
124     tsk_fprintf(hFile, "SHA1: ");
125     if (af_get_seg(aff_info->af_file, AF_SHA1, NULL, buf, &buf_len) == 0) {
126         int i;
127         for (i = 0; i < 20; i++) {
128             tsk_fprintf(hFile, "%x", buf[i]);
129         }
130         tsk_fprintf(hFile, "\n");
131     }
132     else {
133         tsk_fprintf(hFile, "Segment not found\n");
134     }
135 
136     /* Creator segment */
137     buf_len = 512;
138     if (af_get_seg(aff_info->af_file, AF_CREATOR, NULL, buf,
139             &buf_len) == 0) {
140         buf[buf_len] = '\0';
141         tsk_fprintf(hFile, "Creator: %s\n", buf);
142     }
143 
144     buf_len = 512;
145     if (af_get_seg(aff_info->af_file, AF_CASE_NUM, NULL, buf,
146             &buf_len) == 0) {
147         buf[buf_len] = '\0';
148         tsk_fprintf(hFile, "Case Number: %s\n", buf);
149     }
150 
151     buf_len = 512;
152     if (af_get_seg(aff_info->af_file, AF_IMAGE_GID, NULL, buf,
153             &buf_len) == 0) {
154         unsigned int i;
155         tsk_fprintf(hFile, "Image GID: ");
156         for (i = 0; i < buf_len; i++) {
157             tsk_fprintf(hFile, "%X", buf[i]);
158         }
159         tsk_fprintf(hFile, "\n");
160     }
161 
162     buf_len = 512;
163     if (af_get_seg(aff_info->af_file, AF_ACQUISITION_DATE, NULL, buf,
164             &buf_len) == 0) {
165         buf[buf_len] = '\0';
166         tsk_fprintf(hFile, "Acquisition Date: %s\n", buf);
167     }
168 
169     buf_len = 512;
170     if (af_get_seg(aff_info->af_file, AF_ACQUISITION_NOTES, NULL, buf,
171             &buf_len) == 0) {
172         buf[buf_len] = '\0';
173         tsk_fprintf(hFile, "Acquisition Notes: %s\n", buf);
174     }
175 
176     buf_len = 512;
177     if (af_get_seg(aff_info->af_file, AF_ACQUISITION_DEVICE, NULL, buf,
178             &buf_len) == 0) {
179         buf[buf_len] = '\0';
180         tsk_fprintf(hFile, "Acquisition Device: %s\n", buf);
181     }
182 
183     buf_len = 512;
184     if (af_get_seg(aff_info->af_file, AF_AFFLIB_VERSION, NULL, buf,
185             &buf_len) == 0) {
186         buf[buf_len] = '\0';
187         tsk_fprintf(hFile, "AFFLib Version: %s\n", buf);
188     }
189 
190     buf_len = 512;
191     if (af_get_seg(aff_info->af_file, AF_DEVICE_MANUFACTURER, NULL, buf,
192             &buf_len) == 0) {
193         buf[buf_len] = '\0';
194         tsk_fprintf(hFile, "Device Manufacturer: %s\n", buf);
195     }
196 
197     buf_len = 512;
198     if (af_get_seg(aff_info->af_file, AF_DEVICE_MODEL, NULL, buf,
199             &buf_len) == 0) {
200         buf[buf_len] = '\0';
201         tsk_fprintf(hFile, "Device Model: %s\n", buf);
202     }
203 
204     buf_len = 512;
205     if (af_get_seg(aff_info->af_file, AF_DEVICE_SN, NULL, buf,
206             &buf_len) == 0) {
207         buf[buf_len] = '\0';
208         tsk_fprintf(hFile, "Device SN: %s\n", buf);
209     }
210 
211     return;
212 }
213 
214 static void
aff_close(TSK_IMG_INFO * img_info)215 aff_close(TSK_IMG_INFO * img_info)
216 {
217     int i;
218     IMG_AFF_INFO *aff_info = (IMG_AFF_INFO *) img_info;
219     af_close(aff_info->af_file);
220 	for (i = 0; i < img_info->num_img; i++) {
221 		if (img_info->images[i])
222 			free(img_info->images[i]);
223 	}
224 	free(img_info->images);
225     tsk_img_free(aff_info);
226 }
227 
228 
229 TSK_IMG_INFO *
aff_open(const TSK_TCHAR * const images[],unsigned int a_ssize)230 aff_open(const TSK_TCHAR * const images[], unsigned int a_ssize)
231 {
232     IMG_AFF_INFO *aff_info;
233     TSK_IMG_INFO *img_info;
234     int type;
235     char *image;
236 
237 #ifdef TSK_WIN32
238     // convert wchar_t* image path to char* to conform to
239     // the AFFLIB API
240     UTF16 *utf16 = (UTF16 *) images[0];
241     size_t ilen = wcslen(utf16);
242     size_t olen = ilen * 4 + 1;
243     UTF8 *utf8 = (UTF8 *) tsk_malloc(olen);
244 
245     image = (char *) utf8;
246     if (image == NULL)
247         return NULL;
248     TSKConversionResult retval =
249         tsk_UTF16toUTF8_lclorder((const UTF16 **) &utf16,
250         &utf16[ilen], &utf8,
251         &utf8[olen], TSKlenientConversion);
252     *utf8 = '\0';
253     if (retval != TSKconversionOK) {
254         tsk_error_reset();
255         tsk_error_set_errno(TSK_ERR_FS_UNICODE);
256         tsk_error_set_errstr("aff_open file: %" PRIttocTSK
257             ": Error converting path to UTF-8 %d\n", images[0], retval);
258         free(image);
259         return NULL;
260     }
261     utf8 = (UTF8 *) image;
262     while (*utf8) {
263         if (*utf8 > 127) {
264             tsk_error_reset();
265             tsk_error_set_errno(TSK_ERR_FS_UNICODE);
266             tsk_error_set_errstr("aff_open file: %" PRIttocTSK
267                 ": Non-Latin paths are not supported for AFF images\n",
268                 images[0]);
269             free(image);
270             return NULL;
271         }
272         utf8++;
273     }
274 #else
275     image = (char *) tsk_malloc(strlen(images[0]) + 1);
276     if (image == NULL)
277         return NULL;
278     strncpy(image, images[0], strlen(images[0]) + 1);
279 #endif
280 
281     if ((aff_info =
282             (IMG_AFF_INFO *) tsk_img_malloc(sizeof(IMG_AFF_INFO))) ==
283         NULL) {
284         free(image);
285         return NULL;
286     }
287 
288     img_info = (TSK_IMG_INFO *) aff_info;
289     img_info->read = aff_read;
290     img_info->close = aff_close;
291     img_info->imgstat = aff_imgstat;
292 
293     // Save the image path in TSK_IMG_INFO - this is mostly for consistency with the other
294     // image types and is not currently used
295     img_info->num_img = 1;
296     img_info->images =
297         (TSK_TCHAR **)tsk_malloc(sizeof(TSK_TCHAR *) * img_info->num_img);
298     if (img_info->images == NULL) {
299         free(image);
300         return NULL;
301     }
302     size_t len = TSTRLEN(images[0]);
303     img_info->images[0] =
304         (TSK_TCHAR *)tsk_malloc(sizeof(TSK_TCHAR) * (len + 1));
305     if (img_info->images[0] == NULL) {
306         free(img_info->images);
307         free(image);
308         return NULL;
309     }
310     TSTRNCPY(img_info->images[0], images[0], len + 1);
311 
312     img_info->sector_size = 512;
313     if (a_ssize)
314         img_info->sector_size = a_ssize;
315 
316     type = af_identify_file_type(image, 1);
317     if ((type == AF_IDENTIFY_ERR) || (type == AF_IDENTIFY_NOEXIST)) {
318         if (tsk_verbose) {
319             tsk_fprintf(stderr,
320                 "aff_open: Error determining type of file: %" PRIttocTSK
321                 "\n", images[0]);
322             perror("aff_open");
323         }
324         tsk_error_reset();
325         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
326         tsk_error_set_errstr("aff_open file: %" PRIttocTSK
327             ": Error checking type", images[0]);
328         tsk_img_free(aff_info);
329         free(image);
330         return NULL;
331     }
332     else if (type == AF_IDENTIFY_AFF) {
333         img_info->itype = TSK_IMG_TYPE_AFF_AFF;
334     }
335     else if (type == AF_IDENTIFY_AFD) {
336         img_info->itype = TSK_IMG_TYPE_AFF_AFD;
337     }
338     else if (type == AF_IDENTIFY_AFM) {
339         img_info->itype = TSK_IMG_TYPE_AFF_AFM;
340     }
341     else {
342         img_info->itype = TSK_IMG_TYPE_AFF_ANY;
343     }
344 
345     aff_info->af_file = af_open(image, O_RDONLY | O_BINARY, 0);
346     if (!aff_info->af_file) {
347         // @@@ Need to check here if the open failed because of an incorrect password.
348         tsk_error_reset();
349         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
350         tsk_error_set_errstr("aff_open file: %" PRIttocTSK
351             ": Error opening - %s", images[0], strerror(errno));
352         tsk_img_free(aff_info);
353         if (tsk_verbose) {
354             tsk_fprintf(stderr, "Error opening AFF/AFD/AFM file\n");
355             perror("aff_open");
356         }
357         free(image);
358         return NULL;
359     }
360     // verify that a password was given and we can read encrypted data.
361     if (af_cannot_decrypt(aff_info->af_file)) {
362         tsk_error_reset();
363         tsk_error_set_errno(TSK_ERR_IMG_PASSWD);
364         tsk_error_set_errstr("aff_open file: %" PRIttocTSK, images[0]);
365         tsk_img_free(aff_info);
366         if (tsk_verbose) {
367             tsk_fprintf(stderr,
368                 "Error opening AFF/AFD/AFM file (incorrect password)\n");
369         }
370         free(image);
371         return NULL;
372     }
373 
374     aff_info->type = type;
375 
376     img_info->size = af_imagesize(aff_info->af_file);
377 
378     af_seek(aff_info->af_file, 0, SEEK_SET);
379     aff_info->seek_pos = 0;
380     free(image);
381     return img_info;
382 }
383 #endif
384