1 /*
2  * System functions
3  *
4  * Copyright (C) 2008-2020, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <memory.h>
24 #include <narrow_string.h>
25 #include <system_string.h>
26 #include <types.h>
27 #include <wide_string.h>
28 
29 #if defined( HAVE_STDLIB_H ) || defined( WINAPI )
30 #include <stdlib.h>
31 #endif
32 
33 #if defined( HAVE_STRING_H ) || defined( WINAPI )
34 #include <string.h>
35 #endif
36 
37 #if defined( HAVE_STDARG_H ) || defined( WINAPI )
38 #include <stdarg.h>
39 #elif defined( HAVE_VARARGS_H )
40 #include <varargs.h>
41 #else
42 #error Missing headers stdarg.h and varargs.h
43 #endif
44 
45 #include "libcerror_definitions.h"
46 #include "libcerror_error.h"
47 #include "libcerror_system.h"
48 #include "libcerror_types.h"
49 
50 #if defined( WINAPI )
51 
52 /* The make language identifier macro for the WINAPI FormatMessage function
53  */
54 #if !defined( MAKELANGID )
55 #define MAKELANGID( primary_language_identifier, sub_language_identifier ) \
56 	( ( ( (WORD) ( sub_language_identifier ) ) << 10 ) | (WORD) ( primary_language_identifier ) )
57 #endif
58 
59 #if !defined( LANG_NEUTRAL )
60 #define LANG_NEUTRAL		0
61 #endif
62 
63 #if !defined( SUBLANG_DEFAULT )
64 #define SUBLANG_DEFAULT		1
65 #endif
66 
67 #endif /* defined( WINAPI ) */
68 
69 #if defined( WINAPI ) && ( WINVER <= 0x0500 )
70 
71 /* Cross Windows safe version of FormatMessageA
72  * Returns the number of printed characters without the end-of-string character or 0 on error
73  */
libcerror_FormatMessageA(DWORD flags,LPCVOID source,DWORD message_identifier,DWORD language_identifier,LPCSTR string,DWORD string_size,va_list * argument_list)74 DWORD libcerror_FormatMessageA(
75        DWORD flags,
76        LPCVOID source,
77        DWORD message_identifier,
78        DWORD language_identifier,
79        LPCSTR string,
80        DWORD string_size,
81        va_list *argument_list )
82 {
83 	FARPROC function       = NULL;
84 	HMODULE library_handle = NULL;
85 	DWORD print_count      = 0;
86 
87 	if( string == NULL )
88 	{
89 		return( 0 );
90 	}
91 	library_handle = LoadLibrary(
92 	                  _SYSTEM_STRING( "kernel32.dll" ) );
93 
94 	if( library_handle == NULL )
95 	{
96 		return( 0 );
97 	}
98 	function = GetProcAddress(
99 	            library_handle,
100 	            (LPCSTR) "FormatMessageA" );
101 
102 	if( function != NULL )
103 	{
104 		print_count = function(
105 		               flags,
106 		               source,
107 		               message_identifier,
108 		               language_identifier,
109 		               string,
110 		               string_size,
111 		               argument_list );
112 	}
113 	/* This call should be after using the function
114 	 * in most cases kernel32.dll will still be available after free
115 	 */
116 	if( FreeLibrary(
117 	     library_handle ) != TRUE )
118 	{
119 		print_count = 0;
120 	}
121 	return( print_count );
122 }
123 
124 /* Cross Windows safe version of FormatMessageW
125  * Returns the number of printed characters without the end-of-string character or 0 on error
126  */
libcerror_FormatMessageW(DWORD flags,LPCVOID source,DWORD message_identifier,DWORD language_identifier,LPWSTR string,DWORD string_size,va_list * argument_list)127 DWORD libcerror_FormatMessageW(
128        DWORD flags,
129        LPCVOID source,
130        DWORD message_identifier,
131        DWORD language_identifier,
132        LPWSTR string,
133        DWORD string_size,
134        va_list *argument_list )
135 {
136 	FARPROC function       = NULL;
137 	HMODULE library_handle = NULL;
138 	DWORD print_count      = 0;
139 
140 	if( string == NULL )
141 	{
142 		return( 0 );
143 	}
144 	library_handle = LoadLibrary(
145 	                  _SYSTEM_STRING( "kernel32.dll" ) );
146 
147 	if( library_handle == NULL )
148 	{
149 		return( 0 );
150 	}
151 	function = GetProcAddress(
152 	            library_handle,
153 	            (LPCSTR) "FormatMessageW" );
154 
155 	if( function != NULL )
156 	{
157 		print_count = function(
158 		               flags,
159 		               source,
160 		               message_identifier,
161 		               language_identifier,
162 		               string,
163 		               string_size,
164 		               argument_list );
165 	}
166 	/* This call should be after using the function
167 	 * in most cases kernel32.dll will still be available after free
168 	 */
169 	if( FreeLibrary(
170 	     library_handle ) != TRUE )
171 	{
172 		print_count = 0;
173 	}
174 	return( print_count );
175 }
176 
177 #endif /* defined( WINAPI ) && ( WINVER <= 0x0500 ) */
178 
179 #if defined( WINAPI )
180 
181 #if ( WINVER <= 0x0500 )
182 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
183 #define libcerror_system_FormatMessage libcerror_FormatMessageW
184 #else
185 #define libcerror_system_FormatMessage libcerror_FormatMessageA
186 #endif
187 
188 #else
189 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
190 #define libcerror_system_FormatMessage FormatMessageW
191 #else
192 #define libcerror_system_FormatMessage FormatMessageA
193 #endif
194 #endif /* ( WINVER <= 0x0500 ) */
195 
196 /* Retrieves a descriptive string of the error number
197  * This function uses the WINAPI functions for Windows XP or later
198  * Returns the string_length if successful or -1 on error
199  */
libcerror_system_copy_string_from_error_number(system_character_t * string,size_t string_size,uint32_t error_number)200 int libcerror_system_copy_string_from_error_number(
201      system_character_t *string,
202      size_t string_size,
203      uint32_t error_number )
204 {
205 	DWORD print_count = 0;
206 
207 	if( string == NULL )
208 	{
209 		return( -1 );
210 	}
211 	if( string_size > (size_t) INT_MAX )
212 	{
213 		return( -1 );
214 	}
215 	print_count = libcerror_system_FormatMessage(
216 	               FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
217 	               NULL,
218 	               (DWORD) error_number,
219 	               MAKELANGID(
220 	                LANG_NEUTRAL,
221 	                SUBLANG_DEFAULT ),
222 	               string,
223 	               (DWORD) string_size,
224 	               NULL );
225 
226 	if( print_count == 0 )
227 	{
228 		return( -1 );
229 	}
230 	return( (int) print_count );
231 }
232 
233 #elif defined( HAVE_STRERROR_R )
234 
235 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
236 #error Missing wide character strerror_r function
237 #endif
238 
239 /* Retrieves a descriptive string of the error number
240  * This function uses the POSIX strerror_r function or equivalent
241  * Returns the string_length if successful or -1 on error
242  */
libcerror_system_copy_string_from_error_number(system_character_t * string,size_t string_size,uint32_t error_number)243 int libcerror_system_copy_string_from_error_number(
244      system_character_t *string,
245      size_t string_size,
246      uint32_t error_number )
247 {
248 	size_t string_length = 0;
249 
250 	if( string == NULL )
251 	{
252 		return( -1 );
253 	}
254 	if( string_size > (size_t) INT_MAX )
255 	{
256 		return( -1 );
257 	}
258 #if defined( STRERROR_R_CHAR_P )
259 	if( strerror_r(
260 	     (int) error_number,
261 	     string,
262 	     string_size ) == NULL )
263 #else
264 	if( strerror_r(
265 	     (int) error_number,
266 	     string,
267 	     string_size ) != 0 )
268 #endif
269 	{
270 		return( -1 );
271 	}
272 	string[ string_size - 1 ] = (system_character_t) 0;
273 
274 	string_length = system_string_length(
275 	                 string );
276 
277 	return( (int) string_length );
278 }
279 
280 #elif defined( HAVE_STRERROR )
281 
282 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
283 #error Missing wide character strerror function
284 #endif
285 
286 /* Retrieves a descriptive string of the error number
287  * This function uses the POSIX strerror function or equivalent
288  * Returns the string_length if successful or -1 on error
289  */
libcerror_system_copy_string_from_error_number(system_character_t * string,size_t string_size,uint32_t error_number)290 int libcerror_system_copy_string_from_error_number(
291      system_character_t *string,
292      size_t string_size,
293      uint32_t error_number )
294 {
295 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
296 	const wchar_t *static_error_string = NULL;
297 #else
298 	const char *static_error_string    = NULL;
299 #endif
300 	size_t static_error_string_length  = 0;
301 
302 	if( string == NULL )
303 	{
304 		return( -1 );
305 	}
306 	if( string_size > (size_t) INT_MAX )
307 	{
308 		return( -1 );
309 	}
310 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
311 	static_error_string = _wcserror(
312 	                       (int) error_number );
313 #else
314 	static_error_string = strerror(
315 	                       (int) error_number );
316 #endif
317 
318 	if( static_error_string == NULL )
319 	{
320 		return( -1 );
321 	}
322 	static_error_string_length = system_string_length(
323 	                              static_error_string );
324 
325 	if( system_string_copy(
326 	     string,
327 	     static_error_string,
328 	     static_error_string_length ) == NULL )
329 	{
330 		return( -1 );
331 	}
332 	string[ static_error_string_length ] = 0;
333 
334 	return( (int) static_error_string_length );
335 }
336 
337 #else
338 #error Missing error to string system function
339 #endif
340 
341 #if defined( HAVE_STDARG_H ) || defined( WINAPI )
342 #define VARARGS( function, error, error_domain, error_code, system_error_code, type, argument ) \
343         function( error, error_domain, error_code, system_error_code, type argument, ... )
344 #define VASTART( argument_list, type, name ) \
345         va_start( argument_list, name )
346 #define VAEND( argument_list ) \
347         va_end( argument_list )
348 
349 #elif defined( HAVE_VARARGS_H )
350 #define VARARGS( function, error, error_domain, error_code, system_error_code, type, argument ) \
351         function( error, error_domain, error_code, system_error_code, va_alist ) va_dcl
352 #define VASTART( argument_list, type, name ) \
353         { type name; va_start( argument_list ); name = va_arg( argument_list, type )
354 #define VAEND( argument_list ) \
355         va_end( argument_list ); }
356 
357 #endif
358 
359 /* Sets an error and adds a system specific error string if possible
360  * Creates the error if necessary
361  * The error domain and code are set only the first time and the error message is appended for back tracing
362  */
VARARGS(libcerror_system_set_error,libcerror_error_t ** error,int error_domain,int error_code,uint32_t system_error_code,const char *,format_string)363 void VARARGS(
364       libcerror_system_set_error,
365       libcerror_error_t **error,
366       int error_domain,
367       int error_code,
368       uint32_t system_error_code,
369       const char *,
370       format_string )
371 {
372 	va_list argument_list;
373 
374 	libcerror_internal_error_t *internal_error = NULL;
375 	system_character_t *error_string           = NULL;
376 	system_character_t *system_format_string   = NULL;
377 	void *reallocation                         = NULL;
378 	size_t error_string_size                   = 0;
379 	size_t format_string_length                = 0;
380 	size_t message_size                        = 0;
381 	size_t next_message_size                   = LIBCERROR_MESSAGE_INCREMENT_SIZE;
382 	size_t string_index                        = 0;
383 	int message_index                          = 0;
384 	int print_count                            = 0;
385 
386 	if( error == NULL )
387 	{
388 		return;
389 	}
390 	if( format_string == NULL )
391 	{
392 		return;
393 	}
394 	format_string_length = narrow_string_length(
395 	                        format_string );
396 
397 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
398 	libcerror_error_get_system_format_string(
399 	 format_string,
400 	 format_string_length,
401 	 &system_format_string );
402 
403 	if( system_format_string == NULL )
404 	{
405 		return;
406 	}
407 #else
408 	system_format_string = (system_character_t *) format_string;
409 #endif
410 	if( *error == NULL )
411 	{
412 		if( libcerror_error_initialize(
413 		     error,
414 		     error_domain,
415 		     error_code ) != 1 )
416 		{
417 			goto on_error;
418 		}
419 	}
420 	internal_error = (libcerror_internal_error_t *) *error;
421 
422 	if( libcerror_error_resize(
423 	     internal_error ) != 1 )
424 	{
425 		goto on_error;
426 	}
427 	if( format_string_length > next_message_size )
428 	{
429 		next_message_size = ( ( format_string_length / LIBCERROR_MESSAGE_INCREMENT_SIZE ) + 1 )
430 		                  * LIBCERROR_MESSAGE_INCREMENT_SIZE;
431 	}
432 	do
433 	{
434 		if( next_message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
435 		{
436 			next_message_size = LIBCERROR_MESSAGE_MAXIMUM_SIZE;
437 		}
438 		reallocation = memory_reallocate(
439 		                error_string,
440 		                sizeof( system_character_t ) * next_message_size );
441 
442 		if( reallocation == NULL )
443 		{
444 			memory_free(
445 			 error_string );
446 
447 			goto on_error;
448 		}
449 		error_string = (system_character_t *) reallocation;
450 
451 		message_size = next_message_size;
452 
453 		/* argument_list cannot be reused in successive calls to vsnprintf
454 		 */
455 		VASTART(
456 		 argument_list,
457 		 const char *,
458 		 format_string );
459 
460 		print_count = system_string_vsnprintf(
461 		               error_string,
462 		               message_size,
463 		               system_format_string,
464 		               argument_list );
465 
466 		VAEND(
467 		 argument_list );
468 
469 		if( print_count <= -1 )
470 		{
471 			next_message_size += LIBCERROR_MESSAGE_INCREMENT_SIZE;
472 		}
473 		else if( ( (size_t) print_count >= message_size )
474 		      || ( error_string[ print_count ] != (system_character_t) 0 ) )
475 		{
476 			next_message_size = (size_t) ( print_count + 1 );
477 			print_count       = -1;
478 		}
479 		else
480 		{
481 			error_string_size = (size_t) print_count + 1;
482 		}
483 		if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
484 		{
485 			break;
486 		}
487 	}
488 	while( print_count <= -1 );
489 
490 	if( message_size >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
491 	{
492 		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
493 		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
494 		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
495 		error_string[ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
496 		error_string_size                                  = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
497 	}
498 	message_index = internal_error->number_of_messages - 1;
499 
500 	internal_error->messages[ message_index ] = error_string;
501 	internal_error->sizes[ message_index ]    = error_string_size;
502 
503 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
504 	memory_free(
505 	 system_format_string );
506 
507 	system_format_string = NULL;
508 #endif
509 
510 	message_size = internal_error->sizes[ message_index ];
511 
512 	if( message_size < LIBCERROR_MESSAGE_MAXIMUM_SIZE )
513 	{
514 /* TODO move to separate helper function */
515 		string_index = internal_error->sizes[ message_index ] - 1;
516 
517 		if( ( internal_error->messages[ message_index ] != NULL )
518 		 && ( ( internal_error->messages[ message_index ] )[ string_index - 1 ] == (system_character_t) '.' ) )
519 		{
520 			string_index -= 1;
521 		}
522 		reallocation = memory_reallocate(
523 		                internal_error->messages[ message_index ],
524 		                sizeof( system_character_t ) * ( message_size + 13 + 512 ) );
525 
526 		if( reallocation == NULL )
527 		{
528 			memory_free(
529 			 internal_error->messages[ message_index ] );
530 
531 			internal_error->messages[ message_index ] = NULL;
532 
533 			goto on_error;
534 		}
535 		internal_error->messages[ message_index ] = (system_character_t *) reallocation;
536 
537 		if( system_string_copy(
538 		     &( ( internal_error->messages[ message_index ] )[ string_index ] ),
539 		     _SYSTEM_STRING( " with error: " ),
540 		     13 ) == NULL )
541 		{
542 			memory_free(
543 			 internal_error->messages[ message_index ] );
544 
545 			internal_error->messages[ message_index ] = NULL;
546 
547 			goto on_error;
548 		}
549 		internal_error->sizes[ message_index ] += 13;
550 		string_index                           += 13;
551 
552 		print_count = libcerror_system_copy_string_from_error_number(
553 		               &( ( internal_error->messages[ message_index ] )[ string_index ] ),
554 		               512,
555 		               system_error_code );
556 
557 		if( print_count == -1 )
558 		{
559 			goto on_error;
560 		}
561 		internal_error->sizes[ message_index ] += print_count;
562 	}
563 	if( internal_error->sizes[ message_index ] >= LIBCERROR_MESSAGE_MAXIMUM_SIZE )
564 	{
565 		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 4 ] = (system_character_t) '.';
566 		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 3 ] = (system_character_t) '.';
567 		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 2 ] = (system_character_t) '.';
568 		internal_error->messages[ message_index ][ LIBCERROR_MESSAGE_MAXIMUM_SIZE - 1 ] = 0;
569 		internal_error->sizes[ message_index ]                                          = (size_t) LIBCERROR_MESSAGE_MAXIMUM_SIZE;
570 	}
571 	return;
572 
573 on_error:
574 #if defined( HAVE_WIDE_SYSTEM_CHARACTER )
575 	if( system_format_string != NULL )
576 	{
577 		memory_free(
578 		 system_format_string );
579 	}
580 #endif
581 	return;
582 }
583 
584 #undef VARARGS
585 #undef VASTART
586 #undef VAEND
587 
588