1 /*
2    Unix SMB/CIFS implementation.
3    Python/Talloc glue
4    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <Python.h>
21 #include "replace.h"
22 #include <talloc.h>
23 #include "pytalloc.h"
24 #include <assert.h>
25 #include "pytalloc_private.h"
26 
27 static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type,
28 					 TALLOC_CTX *mem_ctx, void *ptr, bool steal);
29 
pytalloc_GetObjectType(void)30 _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
31 {
32 	static PyTypeObject *type = NULL;
33 	PyObject *mod;
34 
35 	mod = PyImport_ImportModule("talloc");
36 	if (mod == NULL) {
37 		return NULL;
38 	}
39 
40 	type = (PyTypeObject *)PyObject_GetAttrString(mod, "Object");
41 	Py_DECREF(mod);
42 
43 	return type;
44 }
45 
pytalloc_GetBaseObjectType(void)46 _PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
47 {
48 	static PyTypeObject *type = NULL;
49 	PyObject *mod;
50 
51 	mod = PyImport_ImportModule("talloc");
52 	if (mod == NULL) {
53 		return NULL;
54 	}
55 
56 	type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
57 	Py_DECREF(mod);
58 
59 	return type;
60 }
61 
pytalloc_GetGenericObjectType(void)62 static PyTypeObject *pytalloc_GetGenericObjectType(void)
63 {
64 	static PyTypeObject *type = NULL;
65 	PyObject *mod;
66 
67 	mod = PyImport_ImportModule("talloc");
68 	if (mod == NULL) {
69 		return NULL;
70 	}
71 
72 	type = (PyTypeObject *)PyObject_GetAttrString(mod, "GenericObject");
73 	Py_DECREF(mod);
74 
75 	return type;
76 }
77 
78 /**
79  * Import an existing talloc pointer into a Python object.
80  */
pytalloc_steal_ex(PyTypeObject * py_type,TALLOC_CTX * mem_ctx,void * ptr)81 _PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
82 				     void *ptr)
83 {
84 	return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, true);
85 }
86 
87 /**
88  * Import an existing talloc pointer into a Python object.
89  */
pytalloc_steal(PyTypeObject * py_type,void * ptr)90 _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
91 {
92 	return pytalloc_steal_or_reference(py_type, ptr, ptr, true);
93 }
94 
95 
96 /**
97  * Import an existing talloc pointer into a Python object, leaving the
98  * original parent, and creating a reference to the object in the python
99  * object.
100  *
101  * We remember the object we hold the reference to (a
102  * possibly-non-talloc pointer), the existing parent (typically the
103  * start of the array) and the new referenced parent.  That way we can
104  * cope with the fact that we will have multiple parents, one per time
105  * python sees the object.
106  */
pytalloc_reference_ex(PyTypeObject * py_type,TALLOC_CTX * mem_ctx,void * ptr)107 _PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
108 					 TALLOC_CTX *mem_ctx, void *ptr)
109 {
110 	return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, false);
111 }
112 
113 
114 /**
115  * Internal function that either steals or referecences the talloc
116  * pointer into a new talloc context.
117  */
pytalloc_steal_or_reference(PyTypeObject * py_type,TALLOC_CTX * mem_ctx,void * ptr,bool steal)118 static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type,
119 					 TALLOC_CTX *mem_ctx, void *ptr, bool steal)
120 {
121 	bool ok = false;
122 	TALLOC_CTX *talloc_ctx = NULL;
123 	bool is_baseobject = false;
124 	PyObject *obj = NULL;
125 	PyTypeObject *BaseObjectType = NULL, *ObjectType = NULL;
126 
127 	BaseObjectType = pytalloc_GetBaseObjectType();
128 	if (BaseObjectType == NULL) {
129 		goto err;
130 	}
131 	ObjectType = pytalloc_GetObjectType();
132 	if (ObjectType == NULL) {
133 		goto err;
134 	}
135 
136 	/* this should have been tested by caller */
137 	if (mem_ctx == NULL) {
138 		return PyErr_NoMemory();
139 	}
140 
141 	is_baseobject = PyType_IsSubtype(py_type, BaseObjectType);
142 	if (!is_baseobject) {
143 		if (!PyType_IsSubtype(py_type, ObjectType)) {
144 			PyErr_SetString(PyExc_TypeError,
145 				"Expected type based on talloc");
146 			return NULL;
147 		}
148 	}
149 
150 	obj = py_type->tp_alloc(py_type, 0);
151 	if (obj == NULL) {
152 		goto err;
153 	}
154 
155 	talloc_ctx = talloc_new(NULL);
156 	if (talloc_ctx == NULL) {
157 		PyErr_NoMemory();
158 		goto err;
159 	}
160 
161 	if (steal) {
162 		ok = (talloc_steal(talloc_ctx, mem_ctx) != NULL);
163 	} else {
164 		ok = (talloc_reference(talloc_ctx, mem_ctx) != NULL);
165 	}
166 	if (!ok) {
167 		goto err;
168 	}
169 	talloc_set_name_const(talloc_ctx, py_type->tp_name);
170 
171 	if (is_baseobject) {
172 		pytalloc_BaseObject *ret = (pytalloc_BaseObject*)obj;
173 		ret->talloc_ctx = talloc_ctx;
174 		ret->talloc_ptr_ctx = mem_ctx;
175 		ret->ptr = ptr;
176 	} else {
177 		pytalloc_Object *ret = (pytalloc_Object*)obj;
178 		ret->talloc_ctx = talloc_ctx;
179 		ret->ptr = ptr;
180 	}
181 	return obj;
182 
183 err:
184 	TALLOC_FREE(talloc_ctx);
185 	Py_XDECREF(obj);
186 	return NULL;
187 }
188 
189 /*
190  * Wrap a generic talloc pointer into a talloc.GenericObject,
191  * this is a subclass of talloc.BaseObject.
192  */
pytalloc_GenericObject_steal_ex(TALLOC_CTX * mem_ctx,void * ptr)193 _PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr)
194 {
195 	PyTypeObject *tp = pytalloc_GetGenericObjectType();
196 	return pytalloc_steal_ex(tp, mem_ctx, ptr);
197 }
198 
199 /*
200  * Wrap a generic talloc pointer into a talloc.GenericObject,
201  * this is a subclass of talloc.BaseObject.
202  */
pytalloc_GenericObject_reference_ex(TALLOC_CTX * mem_ctx,void * ptr)203 _PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr)
204 {
205 	PyTypeObject *tp = pytalloc_GetGenericObjectType();
206 	return pytalloc_reference_ex(tp, mem_ctx, ptr);
207 }
208 
pytalloc_Check(PyObject * obj)209 _PUBLIC_ int pytalloc_Check(PyObject *obj)
210 {
211 	PyTypeObject *tp = pytalloc_GetObjectType();
212 
213 	return PyObject_TypeCheck(obj, tp);
214 }
215 
pytalloc_BaseObject_check(PyObject * obj)216 _PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
217 {
218 	PyTypeObject *tp = pytalloc_GetBaseObjectType();
219 
220 	return PyObject_TypeCheck(obj, tp);
221 }
222 
pytalloc_BaseObject_size(void)223 _PUBLIC_ size_t pytalloc_BaseObject_size(void)
224 {
225 	return sizeof(pytalloc_BaseObject);
226 }
227 
_pytalloc_get_checked_type(PyObject * py_obj,const char * type_name,bool check_only,const char * function)228 static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name,
229 					bool check_only, const char *function)
230 {
231 	TALLOC_CTX *mem_ctx;
232 	void *ptr = NULL;
233 	void *type_obj;
234 
235 	mem_ctx = _pytalloc_get_mem_ctx(py_obj);
236 	ptr = _pytalloc_get_ptr(py_obj);
237 
238 	if (mem_ctx != ptr || ptr == NULL) {
239 		if (check_only) {
240 			return NULL;
241 		}
242 
243 		PyErr_Format(PyExc_TypeError, "%s: expected %s, "
244 			     "but the pointer is no talloc pointer, "
245 			     "pytalloc_get_ptr() would get the raw pointer.",
246 			     function, type_name);
247 		return NULL;
248 	}
249 
250 	type_obj = talloc_check_name(ptr, type_name);
251 	if (type_obj == NULL) {
252 		const char *name = NULL;
253 
254 		if (check_only) {
255 			return NULL;
256 		}
257 
258 		name = talloc_get_name(ptr);
259 		PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s",
260 			     function, type_name, name);
261 		return NULL;
262 	}
263 
264 	return ptr;
265 }
266 
_pytalloc_check_type(PyObject * py_obj,const char * type_name)267 _PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name)
268 {
269 	void *ptr = NULL;
270 
271 	ptr = _pytalloc_get_checked_type(py_obj, type_name,
272 					 true, /* check_only */
273 					 "pytalloc_check_type");
274 	if (ptr == NULL) {
275 		return 0;
276 	}
277 
278 	return 1;
279 }
280 
_pytalloc_get_type(PyObject * py_obj,const char * type_name)281 _PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
282 {
283 	return _pytalloc_get_checked_type(py_obj, type_name,
284 					  false, /* not check_only */
285 					  "pytalloc_get_type");
286 }
287 
_pytalloc_get_ptr(PyObject * py_obj)288 _PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
289 {
290 	if (pytalloc_BaseObject_check(py_obj)) {
291 		return ((pytalloc_BaseObject *)py_obj)->ptr;
292 	}
293 	if (pytalloc_Check(py_obj)) {
294 		return ((pytalloc_Object *)py_obj)->ptr;
295 	}
296 	return NULL;
297 }
298 
_pytalloc_get_mem_ctx(PyObject * py_obj)299 _PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
300 {
301 	if (pytalloc_BaseObject_check(py_obj)) {
302 		return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
303 	}
304 	if (pytalloc_Check(py_obj)) {
305 		return ((pytalloc_Object *)py_obj)->talloc_ctx;
306 	}
307 	return NULL;
308 }
309 
pytalloc_BaseObject_PyType_Ready(PyTypeObject * type)310 _PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type)
311 {
312 	PyTypeObject *talloc_type = pytalloc_GetBaseObjectType();
313 	if (talloc_type == NULL) {
314 		return -1;
315 	}
316 
317 	type->tp_base = talloc_type;
318 	type->tp_basicsize = pytalloc_BaseObject_size();
319 
320 	return PyType_Ready(type);
321 }
322 
_pytalloc_get_name(PyObject * obj)323 _PUBLIC_ const char *_pytalloc_get_name(PyObject *obj)
324 {
325 	void *ptr = pytalloc_get_ptr(obj);
326 	if (ptr == NULL) {
327 		return "non-talloc object";
328 	}
329 	return talloc_get_name(ptr);
330 }
331