1 /*
2  * Python object wrapper of libfwnt_security_identifier_t
3  *
4  * Copyright (C) 2009-2021, 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 <types.h>
24 
25 #if defined( HAVE_STDLIB_H ) || defined( HAVE_WINAPI )
26 #include <stdlib.h>
27 #endif
28 
29 #include "pyfwnt_error.h"
30 #include "pyfwnt_libcerror.h"
31 #include "pyfwnt_libfwnt.h"
32 #include "pyfwnt_python.h"
33 #include "pyfwnt_security_identifier.h"
34 #include "pyfwnt_unused.h"
35 
36 PyMethodDef pyfwnt_security_identifier_object_methods[] = {
37 
38 	{ "copy_from_byte_stream",
39 	  (PyCFunction) pyfwnt_security_identifier_copy_from_byte_stream,
40 	  METH_VARARGS | METH_KEYWORDS,
41 	  "copy_from_byte_stream(byte_stream)\n"
42 	  "\n"
43 	  "Copies the security identifier from the byte stream." },
44 
45 	{ "get_string",
46 	  (PyCFunction) pyfwnt_security_identifier_get_string,
47 	  METH_NOARGS,
48 	  "get_string() -> Unicode string\n"
49 	  "\n"
50 	  "Retrieves the security identifier formatted as a string." },
51 
52 	/* Sentinel */
53 	{ NULL, NULL, 0, NULL }
54 };
55 
56 PyGetSetDef pyfwnt_security_identifier_object_get_set_definitions[] = {
57 
58 	{ "string",
59 	  (getter) pyfwnt_security_identifier_get_string,
60 	  (setter) 0,
61 	  "The string.",
62 	  NULL },
63 
64 	/* Sentinel */
65 	{ NULL, NULL, NULL, NULL, NULL }
66 };
67 
68 PyTypeObject pyfwnt_security_identifier_type_object = {
69 	PyVarObject_HEAD_INIT( NULL, 0 )
70 
71 	/* tp_name */
72 	"pyfwnt.security_identifier",
73 	/* tp_basicsize */
74 	sizeof( pyfwnt_security_identifier_t ),
75 	/* tp_itemsize */
76 	0,
77 	/* tp_dealloc */
78 	(destructor) pyfwnt_security_identifier_free,
79 	/* tp_print */
80 	0,
81 	/* tp_getattr */
82 	0,
83 	/* tp_setattr */
84 	0,
85 	/* tp_compare */
86 	0,
87 	/* tp_repr */
88 	0,
89 	/* tp_as_number */
90 	0,
91 	/* tp_as_sequence */
92 	0,
93 	/* tp_as_mapping */
94 	0,
95 	/* tp_hash */
96 	0,
97 	/* tp_call */
98 	0,
99 	/* tp_str */
100 	0,
101 	/* tp_getattro */
102 	0,
103 	/* tp_setattro */
104 	0,
105 	/* tp_as_buffer */
106 	0,
107 	/* tp_flags */
108 	Py_TPFLAGS_DEFAULT,
109 	/* tp_doc */
110 	"pyfwnt security identifier object (wraps libfwnt_security_identifier_t)",
111 	/* tp_traverse */
112 	0,
113 	/* tp_clear */
114 	0,
115 	/* tp_richcompare */
116 	0,
117 	/* tp_weaklistoffset */
118 	0,
119 	/* tp_iter */
120 	0,
121 	/* tp_iternext */
122 	0,
123 	/* tp_methods */
124 	pyfwnt_security_identifier_object_methods,
125 	/* tp_members */
126 	0,
127 	/* tp_getset */
128 	pyfwnt_security_identifier_object_get_set_definitions,
129 	/* tp_base */
130 	0,
131 	/* tp_dict */
132 	0,
133 	/* tp_descr_get */
134 	0,
135 	/* tp_descr_set */
136 	0,
137 	/* tp_dictoffset */
138 	0,
139 	/* tp_init */
140 	(initproc) pyfwnt_security_identifier_init,
141 	/* tp_alloc */
142 	0,
143 	/* tp_new */
144 	0,
145 	/* tp_free */
146 	0,
147 	/* tp_is_gc */
148 	0,
149 	/* tp_bases */
150 	NULL,
151 	/* tp_mro */
152 	NULL,
153 	/* tp_cache */
154 	NULL,
155 	/* tp_subclasses */
156 	NULL,
157 	/* tp_weaklist */
158 	NULL,
159 	/* tp_del */
160 	0
161 };
162 
163 /* Creates a new security identifier object
164  * Returns a Python object if successful or NULL on error
165  */
pyfwnt_security_identifier_new(libfwnt_security_identifier_t * security_identifier,PyObject * parent_object)166 PyObject *pyfwnt_security_identifier_new(
167            libfwnt_security_identifier_t *security_identifier,
168            PyObject *parent_object )
169 {
170 	pyfwnt_security_identifier_t *pyfwnt_security_identifier = NULL;
171 	static char *function                                    = "pyfwnt_security_identifier_new";
172 
173 	if( security_identifier == NULL )
174 	{
175 		PyErr_Format(
176 		 PyExc_ValueError,
177 		 "%s: invalid security identifier.",
178 		 function );
179 
180 		return( NULL );
181 	}
182 	/* PyObject_New does not invoke tp_init
183 	 */
184 	pyfwnt_security_identifier = PyObject_New(
185 	                              struct pyfwnt_security_identifier,
186 	                              &pyfwnt_security_identifier_type_object );
187 
188 	if( pyfwnt_security_identifier == NULL )
189 	{
190 		PyErr_Format(
191 		 PyExc_MemoryError,
192 		 "%s: unable to initialize security identifier.",
193 		 function );
194 
195 		goto on_error;
196 	}
197 	pyfwnt_security_identifier->security_identifier = security_identifier;
198 	pyfwnt_security_identifier->parent_object       = parent_object;
199 
200 	if( pyfwnt_security_identifier->parent_object != NULL )
201 	{
202 		Py_IncRef(
203 		 pyfwnt_security_identifier->parent_object );
204 	}
205 	return( (PyObject *) pyfwnt_security_identifier );
206 
207 on_error:
208 	if( pyfwnt_security_identifier != NULL )
209 	{
210 		Py_DecRef(
211 		 (PyObject *) pyfwnt_security_identifier );
212 	}
213 	return( NULL );
214 }
215 
216 /* Initializes a security identifier object
217  * Returns 0 if successful or -1 on error
218  */
pyfwnt_security_identifier_init(pyfwnt_security_identifier_t * pyfwnt_security_identifier)219 int pyfwnt_security_identifier_init(
220      pyfwnt_security_identifier_t *pyfwnt_security_identifier )
221 {
222 	libcerror_error_t *error = NULL;
223 	static char *function    = "pyfwnt_security_identifier_init";
224 
225 	if( pyfwnt_security_identifier == NULL )
226 	{
227 		PyErr_Format(
228 		 PyExc_ValueError,
229 		 "%s: invalid security identifier.",
230 		 function );
231 
232 		return( -1 );
233 	}
234 	/* Make sure libfwnt security identifier is set to NULL
235 	 */
236 	pyfwnt_security_identifier->security_identifier = NULL;
237 
238 	if( libfwnt_security_identifier_initialize(
239 	     &( pyfwnt_security_identifier->security_identifier ),
240 	     &error ) != 1 )
241 	{
242 		pyfwnt_error_raise(
243 		 error,
244 		 PyExc_MemoryError,
245 		 "%s: unable to initialize security identifier.",
246 		 function );
247 
248 		libcerror_error_free(
249 		 &error );
250 
251 		return( -1 );
252 	}
253 	return( 0 );
254 }
255 
256 /* Frees a security identifier object
257  */
pyfwnt_security_identifier_free(pyfwnt_security_identifier_t * pyfwnt_security_identifier)258 void pyfwnt_security_identifier_free(
259       pyfwnt_security_identifier_t *pyfwnt_security_identifier )
260 {
261 	struct _typeobject *ob_type = NULL;
262 	libcerror_error_t *error    = NULL;
263 	static char *function       = "pyfwnt_security_identifier_free";
264 	int result                  = 0;
265 
266 	if( pyfwnt_security_identifier == NULL )
267 	{
268 		PyErr_Format(
269 		 PyExc_ValueError,
270 		 "%s: invalid security identifier.",
271 		 function );
272 
273 		return;
274 	}
275 	ob_type = Py_TYPE(
276 	           pyfwnt_security_identifier );
277 
278 	if( ob_type == NULL )
279 	{
280 		PyErr_Format(
281 		 PyExc_ValueError,
282 		 "%s: missing ob_type.",
283 		 function );
284 
285 		return;
286 	}
287 	if( ob_type->tp_free == NULL )
288 	{
289 		PyErr_Format(
290 		 PyExc_ValueError,
291 		 "%s: invalid ob_type - missing tp_free.",
292 		 function );
293 
294 		return;
295 	}
296 	if( pyfwnt_security_identifier->security_identifier != NULL )
297 	{
298 		Py_BEGIN_ALLOW_THREADS
299 
300 		result = libfwnt_security_identifier_free(
301 		          &( pyfwnt_security_identifier->security_identifier ),
302 		          &error );
303 
304 		Py_END_ALLOW_THREADS
305 
306 		if( result != 1 )
307 		{
308 			pyfwnt_error_raise(
309 			 error,
310 			 PyExc_MemoryError,
311 			 "%s: unable to free libfwnt security identifier.",
312 			 function );
313 
314 			libcerror_error_free(
315 			 &error );
316 		}
317 	}
318 	if( pyfwnt_security_identifier->parent_object != NULL )
319 	{
320 		Py_DecRef(
321 		 pyfwnt_security_identifier->parent_object );
322 	}
323 	ob_type->tp_free(
324 	 (PyObject*) pyfwnt_security_identifier );
325 }
326 
327 /* Copies the security identifier from a byte stream
328  * Returns a Python object if successful or NULL on error
329  */
pyfwnt_security_identifier_copy_from_byte_stream(pyfwnt_security_identifier_t * pyfwnt_security_identifier,PyObject * arguments,PyObject * keywords)330 PyObject *pyfwnt_security_identifier_copy_from_byte_stream(
331            pyfwnt_security_identifier_t *pyfwnt_security_identifier,
332            PyObject *arguments,
333            PyObject *keywords )
334 {
335 	PyObject *bytes_object      = NULL;
336 	libcerror_error_t *error    = NULL;
337 	const char *byte_stream     = NULL;
338 	static char *function       = "pyfwnt_security_identifier_copy_from_byte_stream";
339 	static char *keyword_list[] = { "byte_stream", NULL };
340 	Py_ssize_t byte_stream_size = 0;
341 	int result                  = 0;
342 
343 	if( pyfwnt_security_identifier == NULL )
344 	{
345 		PyErr_Format(
346 		 PyExc_TypeError,
347 		 "%s: invalid security identifier.",
348 		 function );
349 
350 		return( NULL );
351 	}
352 	if( PyArg_ParseTupleAndKeywords(
353 	     arguments,
354 	     keywords,
355 	     "O",
356 	     keyword_list,
357 	     &bytes_object ) == 0 )
358 	{
359 		return( NULL );
360 	}
361 	PyErr_Clear();
362 
363 #if PY_MAJOR_VERSION >= 3
364 	result = PyObject_IsInstance(
365 	          bytes_object,
366 	          (PyObject *) &PyBytes_Type );
367 #else
368 	result = PyObject_IsInstance(
369 	          bytes_object,
370 	          (PyObject *) &PyString_Type );
371 #endif
372 	if( result == -1 )
373 	{
374 		pyfwnt_error_fetch_and_raise(
375 		 PyExc_RuntimeError,
376 		 "%s: unable to determine if object is of type bytes.",
377 		 function );
378 
379 		return( NULL );
380 	}
381 	else if( result == 0 )
382 	{
383 		PyErr_Format(
384 		 PyExc_TypeError,
385 		 "%s: unsupported bytes object type",
386 		 function );
387 
388 		return( NULL );
389 	}
390 	PyErr_Clear();
391 
392 #if PY_MAJOR_VERSION >= 3
393 	byte_stream = PyBytes_AsString(
394 	               bytes_object );
395 
396 	byte_stream_size = PyBytes_Size(
397 	                    bytes_object );
398 #else
399 	byte_stream = PyString_AsString(
400 	               bytes_object );
401 
402 	byte_stream_size = PyString_Size(
403 	                    bytes_object );
404 #endif
405 	if( ( byte_stream_size < 0 )
406 	 || ( byte_stream_size > (Py_ssize_t) SSIZE_MAX ) )
407 	{
408 		PyErr_Format(
409 		 PyExc_ValueError,
410 		 "%s: invalid byte stream size value out of bounds.",
411 		 function );
412 
413 		return( NULL );
414 	}
415 	Py_BEGIN_ALLOW_THREADS
416 
417 	result = libfwnt_security_identifier_copy_from_byte_stream(
418 	          pyfwnt_security_identifier->security_identifier,
419 	          (uint8_t *) byte_stream,
420 	          (size_t) byte_stream_size,
421 	          LIBFWNT_ENDIAN_LITTLE,
422 	          &error );
423 
424 	Py_END_ALLOW_THREADS
425 
426 	if( result != 1 )
427 	{
428 		pyfwnt_error_raise(
429 		 error,
430 		 PyExc_IOError,
431 		 "%s: unable to copy security identifier from byte stream.",
432 		 function );
433 
434 		libcerror_error_free(
435 		 &error );
436 
437 		return( NULL );
438 	}
439 	Py_IncRef(
440 	 Py_None );
441 
442 	return( Py_None );
443 }
444 
445 /* Retrieves the string
446  * Returns a Python object if successful or NULL on error
447  */
pyfwnt_security_identifier_get_string(pyfwnt_security_identifier_t * pyfwnt_security_identifier,PyObject * arguments PYFWNT_ATTRIBUTE_UNUSED)448 PyObject *pyfwnt_security_identifier_get_string(
449            pyfwnt_security_identifier_t *pyfwnt_security_identifier,
450            PyObject *arguments PYFWNT_ATTRIBUTE_UNUSED )
451 {
452 	PyObject *string_object      = NULL;
453 	libcerror_error_t *error     = NULL;
454 	const char *errors           = NULL;
455 	static char *function        = "pyfwnt_security_identifier_get_string";
456 	char *utf8_string            = NULL;
457 	size_t string_size           = 0;
458 	uint32_t string_format_flags = 0;
459 	int result                   = 0;
460 
461 	PYFWNT_UNREFERENCED_PARAMETER( arguments )
462 
463 	if( pyfwnt_security_identifier == NULL )
464 	{
465 		PyErr_Format(
466 		 PyExc_ValueError,
467 		 "%s: invalid security identifier.",
468 		 function );
469 
470 		return( NULL );
471 	}
472 	Py_BEGIN_ALLOW_THREADS
473 
474 	result = libfwnt_security_identifier_get_string_size(
475 	          pyfwnt_security_identifier->security_identifier,
476 	          &string_size,
477 	          string_format_flags,
478 	          &error );
479 
480 	Py_END_ALLOW_THREADS
481 
482 	if( result == -1 )
483 	{
484 		pyfwnt_error_raise(
485 		 error,
486 		 PyExc_IOError,
487 		 "%s: unable to determine size of string as string.",
488 		 function );
489 
490 		libcerror_error_free(
491 		 &error );
492 
493 		goto on_error;
494 	}
495 	else if( ( result == 0 )
496 	      || ( string_size == 0 ) )
497 	{
498 		Py_IncRef(
499 		 Py_None );
500 
501 		return( Py_None );
502 	}
503 	utf8_string = (char *) PyMem_Malloc(
504 	                        sizeof( char ) * string_size );
505 
506 	if( utf8_string == NULL )
507 	{
508 		PyErr_Format(
509 		 PyExc_MemoryError,
510 		 "%s: unable to create UTF-8 string.",
511 		 function );
512 
513 		goto on_error;
514 	}
515 	Py_BEGIN_ALLOW_THREADS
516 
517 	result = libfwnt_security_identifier_copy_to_utf8_string(
518 	          pyfwnt_security_identifier->security_identifier,
519 	          (uint8_t *) utf8_string,
520 	          string_size,
521 	          string_format_flags,
522 	          &error );
523 
524 	Py_END_ALLOW_THREADS
525 
526 	if( result != 1 )
527 	{
528 		pyfwnt_error_raise(
529 		 error,
530 		 PyExc_IOError,
531 		 "%s: unable to retrieve string as UTF-8 string.",
532 		 function );
533 
534 		libcerror_error_free(
535 		 &error );
536 
537 		goto on_error;
538 	}
539 	/* Pass the string length to PyUnicode_DecodeUTF8 otherwise it makes
540 	 * the end of string character is part of the string.
541 	 */
542 	string_object = PyUnicode_DecodeUTF8(
543 	                 utf8_string,
544 	                 (Py_ssize_t) string_size - 1,
545 	                 errors );
546 
547 	if( string_object == NULL )
548 	{
549 		PyErr_Format(
550 		 PyExc_IOError,
551 		 "%s: unable to convert UTF-8 string into Unicode object.",
552 		 function );
553 
554 		goto on_error;
555 	}
556 	PyMem_Free(
557 	 utf8_string );
558 
559 	return( string_object );
560 
561 on_error:
562 	if( utf8_string != NULL )
563 	{
564 		PyMem_Free(
565 		 utf8_string );
566 	}
567 	return( NULL );
568 }
569 
570