1 /*
2  * The Sleuth Kit
3  *
4  * Brian Carrier [carrier <at> sleuthkit [dot] org]
5  * Copyright (c) 2006-2011 Brian Carrier.  All Rights reserved
6  *
7  * This software is distributed under the Common Public License 1.0
8  */
9 
10 #include "tsk_base_i.h"
11 #include "tsk_base.h"
12 
13 /**
14  * \file tsk_error.c
15  * Contains the error handling code and variables.
16  */
17 
18 
19 /* Global variables that fit here as well as anywhere */
20 char *progname = "unknown";
21 int tsk_verbose = 0;
22 
23 
24 /* Error messages */
25 static const char *tsk_err_aux_str[TSK_ERR_IMG_MAX] = {
26     "Insufficient memory",
27     "TSK Error"
28 };
29 
30 /* imagetools specific error strings */
31 static const char *tsk_err_img_str[TSK_ERR_IMG_MAX] = {
32     "Missing image file names", // 0
33     "Invalid image offset",
34     "Cannot determine image type",
35     "Unsupported image type",
36     "Error opening image file",
37     "Error stat(ing) image file",       // 5
38     "Error seeking in image file",
39     "Error reading image file",
40     "Read offset too large for image file",
41     "Invalid API argument",
42     "Invalid magic value",      // 10
43     "Error writing data",
44     "Error converting file name",
45     "Incorrect or missing password"
46 };
47 
48 
49 static const char *tsk_err_mm_str[TSK_ERR_VS_MAX] = {
50     "Cannot determine partition type",  // 0
51     "Unsupported partition type",
52     "Error reading image file",
53     "Invalid magic value",
54     "Invalid walk range",
55     "Invalid buffer size",      // 5
56     "Invalid sector address",
57     "Invalid API argument",
58 };
59 
60 static const char *tsk_err_fs_str[TSK_ERR_FS_MAX] = {
61     "Cannot determine file system type",        // 0
62     "Unsupported file system type",
63     "Function/Feature not supported",
64     "Invalid walk range",
65     "Error reading image file",
66     "Invalid file offset",      // 5
67     "Invalid API argument",
68     "Invalid block address",
69     "Invalid metadata address",
70     "Error in metadata structure",
71     "Invalid magic value",      // 10
72     "Error extracting file from image",
73     "Error writing data",
74     "Error converting Unicode",
75     "Error recovering deleted file",
76     "General file system error",        // 15
77     "File system is corrupt",
78     "Attribute not found in file",
79 };
80 
81 static const char *tsk_err_hdb_str[TSK_ERR_HDB_MAX] = {
82     "Cannot determine hash database type",      // 0
83     "Unsupported hash database type",
84     "Error reading hash database file",
85     "Error reading hash database index",
86     "Invalid argument",
87     "Error writing data",       // 5
88     "Error creating file",
89     "Error deleting file",
90     "Missing file",
91     "Error creating process",
92     "Error opening file",       // 10
93     "Corrupt hash database"
94 };
95 
96 static const char *tsk_err_auto_str[TSK_ERR_AUTO_MAX] = {
97     "Database Error",
98     "Corrupt file data",
99     "Error converting Unicode",
100     "Image not opened yet"
101 };
102 
103 
104 #ifdef TSK_MULTITHREAD_LIB
105 
106 #ifdef TSK_WIN32
107 TSK_ERROR_INFO *
tsk_error_get_info()108 tsk_error_get_info()
109 {
110     return (TSK_ERROR_INFO *)
111         tsk_error_win32_get_per_thread_(sizeof(TSK_ERROR_INFO));
112 }
113 
114     // non-windows
115 #else
116 static pthread_key_t pt_tls_key;
117 static pthread_once_t pt_tls_key_once = PTHREAD_ONCE_INIT;
118 
119 static void
free_error_info(void * per_thread_error_info)120 free_error_info(void *per_thread_error_info)
121 {
122     if (per_thread_error_info != 0) {
123         free(per_thread_error_info);
124         pthread_setspecific(pt_tls_key, 0);
125     }
126 }
127 
128 static void
make_pt_tls_key()129 make_pt_tls_key()
130 {
131     (void) pthread_key_create(&pt_tls_key, free_error_info);
132 }
133 
134 TSK_ERROR_INFO *
tsk_error_get_info()135 tsk_error_get_info()
136 {
137     TSK_ERROR_INFO *ptr = NULL;
138     (void) pthread_once(&pt_tls_key_once, make_pt_tls_key);
139     if ((ptr = (TSK_ERROR_INFO *) pthread_getspecific(pt_tls_key)) == 0) {
140         // Under high memory pressure malloc will return NULL.
141         ptr = (TSK_ERROR_INFO *) malloc(sizeof(TSK_ERROR_INFO));
142 
143         if( ptr != NULL ) {
144             ptr->t_errno = 0;
145             ptr->errstr[0] = 0;
146             ptr->errstr2[0] = 0;
147         }
148         (void) pthread_setspecific(pt_tls_key, ptr);
149     }
150     return ptr;
151 }
152 #endif
153 
154 // single-threaded
155 #else
156 
157 static TSK_ERROR_INFO error_info = { 0, {0}, {0} };
158 
159 TSK_ERROR_INFO *
tsk_error_get_info()160 tsk_error_get_info()
161 {
162     return &error_info;
163 }
164 
165 #endif
166 
167 /**
168  * \ingroup baselib
169  * Return the string with the current error message.  The string does not end with a
170  * newline.
171  *
172  * @returns String with error message or NULL if there is no error
173  */
174 const char *
tsk_error_get()175 tsk_error_get()
176 {
177     size_t pidx = 0;
178     TSK_ERROR_INFO *error_info = tsk_error_get_info();
179     int t_errno = error_info->t_errno;
180     char *errstr_print = error_info->errstr_print;
181 
182     if (t_errno == 0) {
183         return NULL;
184     }
185 
186     memset(errstr_print, 0, TSK_ERROR_STRING_MAX_LENGTH);
187     if (t_errno & TSK_ERR_AUX) {
188         if ((TSK_ERR_MASK & t_errno) < TSK_ERR_AUX_MAX)
189             snprintf(&errstr_print[pidx],
190                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s",
191                 tsk_err_aux_str[t_errno & TSK_ERR_MASK]);
192         else
193             snprintf(&errstr_print[pidx],
194                 TSK_ERROR_STRING_MAX_LENGTH - pidx,
195                 "auxtools error: %" PRIu32, TSK_ERR_MASK & t_errno);
196     }
197     else if (t_errno & TSK_ERR_IMG) {
198         if ((TSK_ERR_MASK & t_errno) < TSK_ERR_IMG_MAX)
199             snprintf(&errstr_print[pidx],
200                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s",
201                 tsk_err_img_str[t_errno & TSK_ERR_MASK]);
202         else
203             snprintf(&errstr_print[pidx],
204                 TSK_ERROR_STRING_MAX_LENGTH - pidx,
205                 "imgtools error: %" PRIu32, TSK_ERR_MASK & t_errno);
206     }
207     else if (t_errno & TSK_ERR_VS) {
208         if ((TSK_ERR_MASK & t_errno) < TSK_ERR_VS_MAX)
209             snprintf(&errstr_print[pidx],
210                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s",
211                 tsk_err_mm_str[t_errno & TSK_ERR_MASK]);
212         else
213             snprintf(&errstr_print[pidx],
214                 TSK_ERROR_STRING_MAX_LENGTH - pidx,
215                 "mmtools error: %" PRIu32, TSK_ERR_MASK & t_errno);
216     }
217     else if (t_errno & TSK_ERR_FS) {
218         if ((TSK_ERR_MASK & t_errno) < TSK_ERR_FS_MAX)
219             snprintf(&errstr_print[pidx],
220                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s",
221                 tsk_err_fs_str[t_errno & TSK_ERR_MASK]);
222         else
223             snprintf(&errstr_print[pidx],
224                 TSK_ERROR_STRING_MAX_LENGTH - pidx,
225                 "fstools error: %" PRIu32, TSK_ERR_MASK & t_errno);
226     }
227     else if (t_errno & TSK_ERR_HDB) {
228         if ((TSK_ERR_MASK & t_errno) < TSK_ERR_HDB_MAX)
229             snprintf(&errstr_print[pidx],
230                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s",
231                 tsk_err_hdb_str[t_errno & TSK_ERR_MASK]);
232         else
233             snprintf(&errstr_print[pidx],
234                 TSK_ERROR_STRING_MAX_LENGTH - pidx,
235                 "hashtools error: %" PRIu32, TSK_ERR_MASK & t_errno);
236     }
237     else if (t_errno & TSK_ERR_AUTO) {
238         if ((TSK_ERR_MASK & t_errno) < TSK_ERR_AUTO_MAX)
239             snprintf(&errstr_print[pidx],
240                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "%s",
241                 tsk_err_auto_str[t_errno & TSK_ERR_MASK]);
242         else
243             snprintf(&errstr_print[pidx],
244                 TSK_ERROR_STRING_MAX_LENGTH - pidx, "auto error: %" PRIu32,
245                 TSK_ERR_MASK & t_errno);
246     }
247     else {
248         snprintf(&errstr_print[pidx], TSK_ERROR_STRING_MAX_LENGTH - pidx,
249             "Unknown Error: %" PRIu32, t_errno);
250     }
251     pidx = strlen(errstr_print);
252 
253     /* Print the unique string, if it exists */
254     if (error_info->errstr[0] != '\0') {
255         snprintf(&errstr_print[pidx], TSK_ERROR_STRING_MAX_LENGTH - pidx,
256             " (%s)", error_info->errstr);
257         pidx = strlen(errstr_print);
258     }
259 
260     if (error_info->errstr2[0] != '\0') {
261         snprintf(&errstr_print[pidx], TSK_ERROR_STRING_MAX_LENGTH - pidx,
262             " (%s)", error_info->errstr2);
263         pidx = strlen(errstr_print);
264     }
265     return (char *) error_info->errstr_print;
266 }
267 
268 /**
269  * \ingroup baselib
270  * Return the current error number.
271  * @returns the current error number.
272  */
273 uint32_t
tsk_error_get_errno()274 tsk_error_get_errno()
275 {
276     return tsk_error_get_info()->t_errno;
277 }
278 
279 /**
280  * \ingroup baselib
281  * Set the current TSK error number.
282  * @param t_errno the error number.
283  */
284 void
tsk_error_set_errno(uint32_t t_errno)285 tsk_error_set_errno(uint32_t t_errno)
286 {
287     tsk_error_get_info()->t_errno = t_errno;
288 }
289 
290 /**
291  * \ingroup baselib
292  * Retrieve the current, basic error string.
293  * Additional information is in errstr2.
294  * Use tsk_error_get() to get a fully formatted string.
295  * @returns the string. This is only valid until the next call to a tsk function.
296  */
297 char *
tsk_error_get_errstr()298 tsk_error_get_errstr()
299 {
300     return tsk_error_get_info()->errstr;
301 }
302 
303 /**
304  * \ingroup baselib
305  * Set the error string #1. This should contain the basic message.
306  * @param format the printf-style format string
307  */
308 void
tsk_error_set_errstr(const char * format,...)309 tsk_error_set_errstr(const char *format, ...)
310 {
311     va_list args;
312     va_start(args, format);
313     vsnprintf(tsk_error_get_info()->errstr, TSK_ERROR_STRING_MAX_LENGTH,
314         format, args);
315     va_end(args);
316 }
317 
318 /**
319  * \ingroup baselib
320  * Set the error string
321  * @param format the printf-style format string
322  * @param args the printf-style args
323  */
324 void
tsk_error_vset_errstr(const char * format,va_list args)325 tsk_error_vset_errstr(const char *format, va_list args)
326 {
327     vsnprintf(tsk_error_get_info()->errstr, TSK_ERROR_STRING_MAX_LENGTH,
328         format, args);
329 }
330 
331 /**
332  * \ingroup baselib
333  * Retrieve the current error string #2.
334  * This has additional information than string #1.
335  * @returns the string. This is only valid until the next call to a tsk function.
336  */
337 char *
tsk_error_get_errstr2()338 tsk_error_get_errstr2()
339 {
340     return tsk_error_get_info()->errstr2;
341 }
342 
343 /**
344  * \ingroup baselib
345  * Set the error string #2. This is called by methods who encounter the error,
346  * but did not set errno.
347  * @param format the printf-style format string
348  */
349 void
tsk_error_set_errstr2(const char * format,...)350 tsk_error_set_errstr2(const char *format, ...)
351 {
352     va_list args;
353     va_start(args, format);
354     vsnprintf(tsk_error_get_info()->errstr2, TSK_ERROR_STRING_MAX_LENGTH,
355         format, args);
356     va_end(args);
357 }
358 
359 /**
360  * \ingroup baselib
361  * Set the error string
362  * @param format the printf-style format string
363  * @param args the printf-style format args
364  */
365 void
tsk_error_vset_errstr2(const char * format,va_list args)366 tsk_error_vset_errstr2(const char *format, va_list args)
367 {
368     vsnprintf(tsk_error_get_info()->errstr2, TSK_ERROR_STRING_MAX_LENGTH,
369         format, args);
370 }
371 
372 /**
373  * \ingroup baselib
374  * Concatenate a message onto the end of the errstr2.
375  * @param format
376  */
377 void
tsk_error_errstr2_concat(const char * format,...)378 tsk_error_errstr2_concat(const char *format, ...)
379 {
380     char *errstr2 = tsk_error_get_info()->errstr2;
381     int current_length = (int) (strlen(errstr2) + 1);   // +1 for a space
382     if (current_length > 0) {
383         va_list args;
384         int remaining = TSK_ERROR_STRING_MAX_LENGTH - current_length;
385         errstr2[current_length - 1] = ' ';
386         va_start(args, format);
387         vsnprintf(&errstr2[current_length], remaining, format, args);
388         va_end(args);
389     }
390 }
391 
392 /**
393  * \ingroup baselib
394  * Print the current fully formed error message to a file.
395  *
396  * @param hFile File to print message to
397  */
398 void
tsk_error_print(FILE * hFile)399 tsk_error_print(FILE * hFile)
400 {
401     const char *str;
402     if (tsk_error_get_errno() == 0)
403         return;
404 
405     str = tsk_error_get();
406     if (str != NULL) {
407         tsk_fprintf(hFile, "%s\n", str);
408     }
409     else {
410         tsk_fprintf(hFile,
411             "Error creating Sleuth Kit error string (Errno: %d)\n",
412             tsk_error_get_errno());
413     }
414 }
415 
416 /**
417  * \ingroup baselib
418  * Clear the error number and error message.
419  */
420 void
tsk_error_reset()421 tsk_error_reset()
422 {
423     TSK_ERROR_INFO *info = tsk_error_get_info();
424 
425     if( info != NULL ) {
426        info->t_errno = 0;
427        info->errstr[0] = 0;
428        info->errstr2[0] = 0;
429        info->errstr_print[0] = 0;
430     }
431 }
432