1 /*
2  * Brian Carrier [carrier <at> sleuthkit [dot] org]
3  * Copyright (c) 2006-2016 Brian Carrier, Basis Technology.  All rights reserved
4  * Copyright (c) 2005 Brian Carrier.  All rights reserved
5  *
6  * This software is distributed under the Common Public License 1.0
7  *
8  */
9 
10 
11 /** \file vhd.c
12  * Internal code for TSK to interface with libvhdi.
13  */
14 
15 #include "tsk_img_i.h"
16 
17 #if HAVE_LIBVHDI
18 #include "vhd.h"
19 
20 #define TSK_VHDI_ERROR_STRING_SIZE 512
21 
22 /**
23  * Get error string from libvhdi and make buffer empty if that didn't work.
24  * @returns 1 if error message was not set
25 */
26 static uint8_t
getError(libvhdi_error_t * vhdi_error,char error_string[TSK_VHDI_ERROR_STRING_SIZE])27 getError(libvhdi_error_t * vhdi_error,
28     char error_string[TSK_VHDI_ERROR_STRING_SIZE])
29 {
30     int retval;
31     error_string[0] = '\0';
32     retval = libvhdi_error_backtrace_sprint(vhdi_error,
33         error_string, TSK_VHDI_ERROR_STRING_SIZE);
34     if (retval)
35         return 1;
36     return 0;
37 }
38 
39 
40 static ssize_t
vhdi_image_read(TSK_IMG_INFO * img_info,TSK_OFF_T offset,char * buf,size_t len)41 vhdi_image_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf,
42     size_t len)
43 {
44     char error_string[TSK_VHDI_ERROR_STRING_SIZE];
45     libvhdi_error_t *vhdi_error = NULL;
46 
47     ssize_t cnt;
48     IMG_VHDI_INFO *vhdi_info = (IMG_VHDI_INFO *) img_info;
49 
50     if (tsk_verbose)
51         tsk_fprintf(stderr,
52             "vhdi_image_read: byte offset: %" PRIdOFF " len: %" PRIuSIZE
53             "\n", offset, len);
54 
55     if (offset > img_info->size) {
56         tsk_error_reset();
57         tsk_error_set_errno(TSK_ERR_IMG_READ_OFF);
58         tsk_error_set_errstr("vhdi_image_read - %" PRIdOFF, offset);
59         return -1;
60     }
61 
62     tsk_take_lock(&(vhdi_info->read_lock));
63 
64     cnt = libvhdi_file_read_buffer_at_offset(vhdi_info->handle,
65         buf, len, offset, &vhdi_error);
66     if (cnt < 0) {
67         char *errmsg = NULL;
68         tsk_error_reset();
69         tsk_error_set_errno(TSK_ERR_IMG_READ);
70         if (getError(vhdi_error, error_string))
71             errmsg = strerror(errno);
72         else
73             errmsg = error_string;
74 
75         tsk_error_set_errstr("vhdi_image_read - offset: %" PRIdOFF
76             " - len: %" PRIuSIZE " - %s", offset, len, errmsg);
77         tsk_release_lock(&(vhdi_info->read_lock));
78         return -1;
79     }
80 
81     tsk_release_lock(&(vhdi_info->read_lock));
82 
83     return cnt;
84 }
85 
86 static void
vhdi_image_imgstat(TSK_IMG_INFO * img_info,FILE * hFile)87 vhdi_image_imgstat(TSK_IMG_INFO * img_info, FILE * hFile)
88 {
89     tsk_fprintf(hFile, "IMAGE FILE INFORMATION\n");
90     tsk_fprintf(hFile, "--------------------------------------------\n");
91     tsk_fprintf(hFile, "Image Type:\t\tvhdi\n");
92     tsk_fprintf(hFile, "\nSize of data in bytes:\t%" PRIdOFF "\n",
93         img_info->size);
94     tsk_fprintf(hFile, "Sector size:\t%d\n", img_info->sector_size);
95 
96     return;
97 }
98 
99 
100 static void
vhdi_image_close(TSK_IMG_INFO * img_info)101     vhdi_image_close(TSK_IMG_INFO * img_info)
102 {
103     int i;
104     char error_string[TSK_VHDI_ERROR_STRING_SIZE];
105     libvhdi_error_t *vhdi_error = NULL;
106     char *errmsg = NULL;
107     IMG_VHDI_INFO *vhdi_info = (IMG_VHDI_INFO *) img_info;
108 
109     if( libvhdi_file_close(vhdi_info->handle, &vhdi_error ) != 0 )
110     {
111         tsk_error_reset();
112         tsk_error_set_errno(TSK_ERR_AUX_GENERIC);
113         if (getError(vhdi_error, error_string))
114             errmsg = strerror(errno);
115         else
116             errmsg = error_string;
117 
118         tsk_error_set_errstr("vhdi_image_close: unable to close handle - %s", errmsg);
119     }
120 
121     libvhdi_file_free(&(vhdi_info->handle), NULL);
122     if( libvhdi_file_free(&(vhdi_info->handle), &vhdi_error ) != 1 )
123     {
124         tsk_error_reset();
125         tsk_error_set_errno(TSK_ERR_AUX_GENERIC);
126         if (getError(vhdi_error, error_string))
127             errmsg = strerror(errno);
128         else
129             errmsg = error_string;
130 
131         tsk_error_set_errstr("vhdi_image_close: unable to free handle - %s", errmsg);
132     }
133 
134     for (i = 0; i < vhdi_info->img_info.num_img; i++) {
135         free(vhdi_info->img_info.images[i]);
136     }
137     free(vhdi_info->img_info.images);
138 
139     tsk_deinit_lock(&(vhdi_info->read_lock));
140     tsk_img_free(img_info);
141 }
142 
143 TSK_IMG_INFO *
vhdi_open(int a_num_img,const TSK_TCHAR * const a_images[],unsigned int a_ssize)144 vhdi_open(int a_num_img,
145     const TSK_TCHAR * const a_images[], unsigned int a_ssize)
146 {
147     char error_string[TSK_VHDI_ERROR_STRING_SIZE];
148     libvhdi_error_t *vhdi_error = NULL;
149     int i;
150 
151     IMG_VHDI_INFO *vhdi_info = NULL;
152     TSK_IMG_INFO *img_info = NULL;
153 
154     if (tsk_verbose) {
155         libvhdi_notify_set_verbose(1);
156         libvhdi_notify_set_stream(stderr, NULL);
157     }
158 
159     if ((vhdi_info =
160             (IMG_VHDI_INFO *) tsk_img_malloc(sizeof(IMG_VHDI_INFO))) ==
161         NULL) {
162         return NULL;
163     }
164     vhdi_info->handle = NULL;
165     img_info = (TSK_IMG_INFO *) vhdi_info;
166 
167     vhdi_info->img_info.num_img = a_num_img;
168     if ((vhdi_info->img_info.images =
169         (TSK_TCHAR **) tsk_malloc(a_num_img *
170         sizeof(TSK_TCHAR *))) == NULL) {
171             tsk_img_free(vhdi_info);
172             return NULL;
173     }
174     for (i = 0; i < a_num_img; i++) {
175         if ((vhdi_info->img_info.images[i] =
176             (TSK_TCHAR *) tsk_malloc((TSTRLEN(a_images[i]) +
177             1) * sizeof(TSK_TCHAR))) == NULL) {
178                 tsk_img_free(vhdi_info);
179                 return NULL;
180         }
181         TSTRNCPY(vhdi_info->img_info.images[i], a_images[i],
182             TSTRLEN(a_images[i]) + 1);
183     }
184 
185     if (libvhdi_file_initialize(&(vhdi_info->handle), &vhdi_error) != 1) {
186         tsk_error_reset();
187         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
188 
189         getError(vhdi_error, error_string);
190         tsk_error_set_errstr("vhdi_open file: %" PRIttocTSK
191             ": Error initializing handle (%s)", a_images[0], error_string);
192         libvhdi_error_free(&vhdi_error);
193 
194         tsk_img_free(vhdi_info);
195 
196         if (tsk_verbose != 0) {
197             tsk_fprintf(stderr, "Unable to create vhdi handle\n");
198         }
199         return (NULL);
200     }
201     // Check the file signature before we call the library open
202 #if defined( TSK_WIN32 )
203     if( libvhdi_check_file_signature_wide((const wchar_t *) vhdi_info->img_info.images[0], &vhdi_error ) != 1 )
204 #else
205     if( libvhdi_check_file_signature((const char *) vhdi_info->img_info.images[0], &vhdi_error) != 1)
206 #endif
207 	{
208         tsk_error_reset();
209         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
210 
211         getError(vhdi_error, error_string);
212         tsk_error_set_errstr("vhdi_open file: %" PRIttocTSK
213             ": Error checking file signature for image (%s)", a_images[0],
214             error_string);
215         libvhdi_error_free(&vhdi_error);
216 
217         tsk_img_free(vhdi_info);
218 
219         if (tsk_verbose != 0) {
220             tsk_fprintf(stderr, "Error checking file signature for vhd file\n");
221         }
222         return (NULL);
223     }
224 #if defined( TSK_WIN32 )
225     if (libvhdi_file_open_wide(vhdi_info->handle,
226             (const wchar_t *) vhdi_info->img_info.images[0],
227             LIBVHDI_OPEN_READ, &vhdi_error) != 1)
228 #else
229     if (libvhdi_file_open(vhdi_info->handle,
230             (const char *) vhdi_info->img_info.images[0],
231             LIBVHDI_OPEN_READ, &vhdi_error) != 1)
232 #endif
233     {
234         tsk_error_reset();
235         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
236 
237         getError(vhdi_error, error_string);
238         tsk_error_set_errstr("vhdi_open file: %" PRIttocTSK
239             ": Error opening (%s)", a_images[0], error_string);
240         libvhdi_error_free(&vhdi_error);
241 
242         tsk_img_free(vhdi_info);
243 
244         if (tsk_verbose != 0) {
245             tsk_fprintf(stderr, "Error opening vhdi file\n");
246         }
247         return (NULL);
248     }
249     if (libvhdi_file_get_media_size(vhdi_info->handle,
250             (size64_t *) & (img_info->size), &vhdi_error) != 1) {
251         tsk_error_reset();
252         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
253 
254         getError(vhdi_error, error_string);
255         tsk_error_set_errstr("vhdi_open file: %" PRIttocTSK
256             ": Error getting size of image (%s)", a_images[0],
257             error_string);
258         libvhdi_error_free(&vhdi_error);
259 
260         tsk_img_free(vhdi_info);
261 
262         if (tsk_verbose != 0) {
263             tsk_fprintf(stderr, "Error getting size of vhdi file\n");
264         }
265         return (NULL);
266     }
267 
268     if (a_ssize != 0) {
269         img_info->sector_size = a_ssize;
270     }
271     else {
272         img_info->sector_size = 512;
273     }
274     img_info->itype = TSK_IMG_TYPE_VHD_VHD;
275     img_info->read = &vhdi_image_read;
276     img_info->close = &vhdi_image_close;
277     img_info->imgstat = &vhdi_image_imgstat;
278 
279     // initialize the read lock
280     tsk_init_lock(&(vhdi_info->read_lock));
281 
282     return (img_info);
283 }
284 
285 #endif /* HAVE_LIBVHDI */
286