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 /** \file vmdk.c
11  * Internal code for TSK to interface with libvmdk.
12  */
13 
14 #include "tsk_img_i.h"
15 
16 #if HAVE_LIBVMDK
17 #include "vmdk.h"
18 
19 #define TSK_VMDK_ERROR_STRING_SIZE 512
20 
21 
22 /**
23  * Get error string from libvmdk and make buffer empty if that didn't work.
24  * @returns 1 if error message was not set
25 */
26 static uint8_t
27 getError(libvmdk_error_t * vmdk_error,
28     char error_string[TSK_VMDK_ERROR_STRING_SIZE])
29 {
30     int retval;
31     error_string[0] = '\0';
32     retval = libvmdk_error_backtrace_sprint(vmdk_error,
33         error_string, TSK_VMDK_ERROR_STRING_SIZE);
34     if (retval)
35         return 1;
36     return 0;
37 }
38 
39 
40 static ssize_t
41 vmdk_image_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf,
42     size_t len)
43 {
44     char error_string[TSK_VMDK_ERROR_STRING_SIZE];
45     libvmdk_error_t *vmdk_error = NULL;
46 
47     ssize_t cnt;
48     IMG_VMDK_INFO *vmdk_info = (IMG_VMDK_INFO *) img_info;
49 
50     if (tsk_verbose)
51         tsk_fprintf(stderr,
52             "vmdk_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("vmdk_image_read - %" PRIdOFF, offset);
59         return -1;
60     }
61 
62     tsk_take_lock(&(vmdk_info->read_lock));
63 
64     cnt = libvmdk_handle_read_buffer_at_offset(vmdk_info->handle,
65         buf, len, offset, &vmdk_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(vmdk_error, error_string))
71             errmsg = strerror(errno);
72         else
73             errmsg = error_string;
74 
75         tsk_error_set_errstr("vmdk_image_read - offset: %" PRIdOFF
76             " - len: %" PRIuSIZE " - %s", offset, len, errmsg);
77         tsk_release_lock(&(vmdk_info->read_lock));
78         return -1;
79     }
80 
81     tsk_release_lock(&(vmdk_info->read_lock));
82 
83     return cnt;
84 }
85 
86 static void
87 vmdk_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\tvmdk\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
101     vmdk_image_close(TSK_IMG_INFO * img_info)
102 {
103     int i;
104     char error_string[TSK_VMDK_ERROR_STRING_SIZE];
105     libvmdk_error_t *vmdk_error = NULL;
106     char *errmsg = NULL;
107     IMG_VMDK_INFO *vmdk_info = (IMG_VMDK_INFO *) img_info;
108 
109     if( libvmdk_handle_close(vmdk_info->handle, &vmdk_error ) != 0 )
110     {
111         tsk_error_reset();
112         tsk_error_set_errno(TSK_ERR_AUX_GENERIC);
113         if (getError(vmdk_error, error_string))
114             errmsg = strerror(errno);
115         else
116             errmsg = error_string;
117 
118         tsk_error_set_errstr("vmdk_image_close: unable to close handle - %s", errmsg);
119     }
120 
121     libvmdk_handle_free(&(vmdk_info->handle), NULL);
122     if( libvmdk_handle_free(&(vmdk_info->handle), &vmdk_error ) != 1 )
123     {
124         tsk_error_reset();
125         tsk_error_set_errno(TSK_ERR_AUX_GENERIC);
126         if (getError(vmdk_error, error_string))
127             errmsg = strerror(errno);
128         else
129             errmsg = error_string;
130 
131         tsk_error_set_errstr("vmdk_image_close: unable to free handle - %s", errmsg);
132     }
133 
134     for (i = 0; i < vmdk_info->img_info.num_img; i++) {
135         free(vmdk_info->img_info.images[i]);
136     }
137     free(vmdk_info->img_info.images);
138 
139     tsk_deinit_lock(&(vmdk_info->read_lock));
140     tsk_img_free(img_info);
141 }
142 
143 TSK_IMG_INFO *
144 vmdk_open(int a_num_img,
145     const TSK_TCHAR * const a_images[], unsigned int a_ssize)
146 {
147     char error_string[TSK_VMDK_ERROR_STRING_SIZE];
148     libvmdk_error_t *vmdk_error = NULL;
149     int i;
150 
151     IMG_VMDK_INFO *vmdk_info = NULL;
152     TSK_IMG_INFO *img_info = NULL;
153 
154     if (tsk_verbose) {
155         libvmdk_notify_set_verbose(1);
156         libvmdk_notify_set_stream(stderr, NULL);
157     }
158 
159     if ((vmdk_info =
160             (IMG_VMDK_INFO *) tsk_img_malloc(sizeof(IMG_VMDK_INFO))) ==
161         NULL) {
162         return NULL;
163     }
164     vmdk_info->handle = NULL;
165     img_info = (TSK_IMG_INFO *) vmdk_info;
166 
167     vmdk_info->img_info.num_img = a_num_img;
168     if ((vmdk_info->img_info.images =
169         (TSK_TCHAR **) tsk_malloc(a_num_img *
170         sizeof(TSK_TCHAR *))) == NULL) {
171             tsk_img_free(vmdk_info);
172             return NULL;
173     }
174     for (i = 0; i < a_num_img; i++) {
175         if ((vmdk_info->img_info.images[i] =
176             (TSK_TCHAR *) tsk_malloc((TSTRLEN(a_images[i]) +
177             1) * sizeof(TSK_TCHAR))) == NULL) {
178                 tsk_img_free(vmdk_info);
179                 return NULL;
180         }
181         TSTRNCPY(vmdk_info->img_info.images[i], a_images[i],
182             TSTRLEN(a_images[i]) + 1);
183     }
184 
185     if (libvmdk_handle_initialize(&(vmdk_info->handle), &vmdk_error) != 1) {
186         tsk_error_reset();
187         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
188 
189         getError(vmdk_error, error_string);
190         tsk_error_set_errstr("vmdk_open file: %" PRIttocTSK
191             ": Error initializing handle (%s)", a_images[0], error_string);
192         libvmdk_error_free(&vmdk_error);
193 
194         tsk_img_free(vmdk_info);
195 
196         if (tsk_verbose != 0) {
197             tsk_fprintf(stderr, "Unable to create vmdk handle\n");
198         }
199         return (NULL);
200     }
201 #if defined( TSK_WIN32 )
202     if (libvmdk_handle_open_wide(vmdk_info->handle,
203             (const wchar_t *) vmdk_info->img_info.images[0],
204             LIBVMDK_OPEN_READ, &vmdk_error) != 1)
205 #else
206     if (libvmdk_handle_open(vmdk_info->handle,
207             (const char *) vmdk_info->img_info.images[0],
208             LIBVMDK_OPEN_READ, &vmdk_error) != 1)
209 #endif
210     {
211         tsk_error_reset();
212         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
213 
214         getError(vmdk_error, error_string);
215         tsk_error_set_errstr("vmdk_open file: %" PRIttocTSK
216             ": Error opening (%s)", a_images[0], error_string);
217         libvmdk_error_free(&vmdk_error);
218 
219         tsk_img_free(vmdk_info);
220 
221         if (tsk_verbose != 0) {
222             tsk_fprintf(stderr, "Error opening vmdk file\n");
223         }
224         return (NULL);
225     }
226     if( libvmdk_handle_open_extent_data_files(vmdk_info->handle, &vmdk_error ) != 1 )
227 	{
228         tsk_error_reset();
229         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
230 
231         getError(vmdk_error, error_string);
232         tsk_error_set_errstr("vmdk_open file: %" PRIttocTSK
233             ": Error opening extent data files for image (%s)", a_images[0],
234             error_string);
235         libvmdk_error_free(&vmdk_error);
236 
237         tsk_img_free(vmdk_info);
238 
239         if (tsk_verbose != 0) {
240             tsk_fprintf(stderr, "Error opening vmdk extent data files\n");
241         }
242         return (NULL);
243     }
244     if (libvmdk_handle_get_media_size(vmdk_info->handle,
245             (size64_t *) & (img_info->size), &vmdk_error) != 1) {
246         tsk_error_reset();
247         tsk_error_set_errno(TSK_ERR_IMG_OPEN);
248 
249         getError(vmdk_error, error_string);
250         tsk_error_set_errstr("vmdk_open file: %" PRIttocTSK
251             ": Error getting size of image (%s)", a_images[0],
252             error_string);
253         libvmdk_error_free(&vmdk_error);
254 
255         tsk_img_free(vmdk_info);
256 
257         if (tsk_verbose != 0) {
258             tsk_fprintf(stderr, "Error getting size of vmdk file\n");
259         }
260         return (NULL);
261     }
262 
263     if (a_ssize != 0) {
264         img_info->sector_size = a_ssize;
265     }
266     else {
267         img_info->sector_size = 512;
268     }
269     img_info->itype = TSK_IMG_TYPE_VMDK_VMDK;
270     img_info->read = &vmdk_image_read;
271     img_info->close = &vmdk_image_close;
272     img_info->imgstat = &vmdk_image_imgstat;
273 
274     // initialize the read lock
275     tsk_init_lock(&(vmdk_info->read_lock));
276 
277     return (img_info);
278 }
279 
280 #endif /* HAVE_LIBVMDK */
281