s4-pyrpc: added py_return_ndr_struct()
[gd/samba-autobuild/.git] / source4 / librpc / rpc / pyrpc_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Python interface to DCE/RPC library - utility functions.
5
6    Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
7    Copyright (C) 2010 Andrew Tridgell <tridge@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <Python.h>
24 #include "includes.h"
25 #include "librpc/rpc/pyrpc_util.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/pyrpc.h"
28 #include "param/pyparam.h"
29 #include "auth/credentials/pycredentials.h"
30 #include "lib/events/events.h"
31
32 #ifndef Py_TYPE /* Py_TYPE is only available on Python > 2.6 */
33 #define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
34 #endif
35
36 bool py_check_dcerpc_type(PyObject *obj, const char *module, const char *typename)
37 {
38         PyObject *mod;
39         PyTypeObject *type;
40         bool ret;
41
42         mod = PyImport_ImportModule(module);
43
44         if (mod == NULL) {
45                 PyErr_Format(PyExc_RuntimeError, "Unable to import %s to check type %s",
46                         module, typename);
47                 return NULL;
48         }
49
50         type = (PyTypeObject *)PyObject_GetAttrString(mod, typename);
51         Py_DECREF(mod);
52         if (type == NULL) {
53                 PyErr_Format(PyExc_RuntimeError, "Unable to find type %s in module %s",
54                         module, typename);
55                 return NULL;
56         }
57
58         ret = PyObject_TypeCheck(obj, type);
59         Py_DECREF(type);
60
61         if (!ret)
62                 PyErr_Format(PyExc_TypeError, "Expected type %s.%s, got %s",
63                         module, typename, Py_TYPE(obj)->tp_name);
64
65         return ret;
66 }
67
68 PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, PyObject *kwargs, const struct ndr_interface_table *table)
69 {
70         dcerpc_InterfaceObject *ret;
71         const char *binding_string;
72         struct cli_credentials *credentials;
73         struct loadparm_context *lp_ctx = NULL;
74         PyObject *py_lp_ctx = Py_None, *py_credentials = Py_None, *py_basis = Py_None;
75         TALLOC_CTX *mem_ctx = NULL;
76         struct tevent_context *event_ctx;
77         NTSTATUS status;
78
79         const char *kwnames[] = {
80                 "binding", "lp_ctx", "credentials", "basis_connection", NULL
81         };
82
83         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO:samr", discard_const_p(char *, kwnames), &binding_string, &py_lp_ctx, &py_credentials, &py_basis)) {
84                 return NULL;
85         }
86
87         mem_ctx = talloc_new(NULL);
88         if (mem_ctx == NULL) {
89                 PyErr_NoMemory();
90                 return NULL;
91         }
92
93         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
94         if (lp_ctx == NULL) {
95                 PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
96                 talloc_free(mem_ctx);
97                 return NULL;
98         }
99
100         status = dcerpc_init(lp_ctx);
101         if (!NT_STATUS_IS_OK(status)) {
102                 PyErr_SetNTSTATUS(status);
103                 talloc_free(mem_ctx);
104                 return NULL;
105         }
106         credentials = cli_credentials_from_py_object(py_credentials);
107         if (credentials == NULL) {
108                 PyErr_SetString(PyExc_TypeError, "Expected credentials");
109                 talloc_free(mem_ctx);
110                 return NULL;
111         }
112         ret = PyObject_New(dcerpc_InterfaceObject, type);
113         ret->mem_ctx = mem_ctx;
114
115         event_ctx = s4_event_context_init(ret->mem_ctx);
116
117         if (py_basis != Py_None) {
118                 struct dcerpc_pipe *base_pipe;
119                 PyObject *py_base;
120                 PyTypeObject *ClientConnection_Type;
121
122                 py_base = PyImport_ImportModule("samba.dcerpc.base");
123                 if (py_base == NULL) {
124                         talloc_free(mem_ctx);
125                         return NULL;
126                 }
127
128                 ClientConnection_Type = (PyTypeObject *)PyObject_GetAttrString(py_base, "ClientConnection");
129                 if (ClientConnection_Type == NULL) {
130                         PyErr_SetNone(PyExc_TypeError);
131                         talloc_free(mem_ctx);
132                         return NULL;
133                 }
134
135                 if (!PyObject_TypeCheck(py_basis, ClientConnection_Type)) {
136                         PyErr_SetString(PyExc_TypeError, "basis_connection must be a DCE/RPC connection");
137                         talloc_free(mem_ctx);
138                         return NULL;
139                 }
140
141                 base_pipe = talloc_reference(mem_ctx, ((dcerpc_InterfaceObject *)py_basis)->pipe);
142
143                 status = dcerpc_secondary_context(base_pipe, &ret->pipe, table);
144
145                 ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe);
146         } else {
147                 status = dcerpc_pipe_connect(event_ctx, &ret->pipe, binding_string,
148                              table, credentials, event_ctx, lp_ctx);
149         }
150         if (NT_STATUS_IS_ERR(status)) {
151                 PyErr_SetNTSTATUS(status);
152                 talloc_free(mem_ctx);
153                 return NULL;
154         }
155
156         ret->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
157         ret->binding_handle = ret->pipe->binding_handle;
158         return (PyObject *)ret;
159 }
160
161 static PyObject *py_dcerpc_run_function(dcerpc_InterfaceObject *iface,
162                                         const struct PyNdrRpcMethodDef *md,
163                                         PyObject *args, PyObject *kwargs)
164 {
165         TALLOC_CTX *mem_ctx;
166         NTSTATUS status;
167         void *r;
168         PyObject *result = Py_None;
169
170         if (md->pack_in_data == NULL || md->unpack_out_data == NULL) {
171                 PyErr_SetString(PyExc_NotImplementedError, "No marshalling code available yet");
172                 return NULL;
173         }
174
175         mem_ctx = talloc_new(NULL);
176         if (mem_ctx == NULL) {
177                 PyErr_NoMemory();
178                 return NULL;
179         }
180
181         r = talloc_zero_size(mem_ctx, md->table->calls[md->opnum].struct_size);
182         if (r == NULL) {
183                 PyErr_NoMemory();
184                 return NULL;
185         }
186
187         if (!md->pack_in_data(args, kwargs, r)) {
188                 talloc_free(mem_ctx);
189                 return NULL;
190         }
191
192         status = md->call(iface->binding_handle, mem_ctx, r);
193         if (!NT_STATUS_IS_OK(status)) {
194                 PyErr_SetDCERPCStatus(iface->pipe, status);
195                 talloc_free(mem_ctx);
196                 return NULL;
197         }
198
199         result = md->unpack_out_data(r);
200
201         talloc_free(mem_ctx);
202         return result;
203 }
204
205 static PyObject *py_dcerpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs)
206 {       
207         dcerpc_InterfaceObject *iface = (dcerpc_InterfaceObject *)self;
208         const struct PyNdrRpcMethodDef *md = (const struct PyNdrRpcMethodDef *)wrapped;
209
210         return py_dcerpc_run_function(iface, md, args, kwargs);
211 }
212
213 bool PyInterface_AddNdrRpcMethods(PyTypeObject *ifacetype, const struct PyNdrRpcMethodDef *mds)
214 {
215         int i;
216         for (i = 0; mds[i].name; i++) {
217                 PyObject *ret;
218                 struct wrapperbase *wb = (struct wrapperbase *)calloc(sizeof(struct wrapperbase), 1);
219
220                 wb->name = discard_const_p(char, mds[i].name);
221                 wb->flags = PyWrapperFlag_KEYWORDS;
222                 wb->wrapper = (wrapperfunc)py_dcerpc_call_wrapper;
223                 wb->doc = discard_const_p(char, mds[i].doc);
224
225                 ret = PyDescr_NewWrapper(ifacetype, wb, discard_const_p(void, &mds[i]));
226
227                 PyDict_SetItemString(ifacetype->tp_dict, mds[i].name, 
228                                      (PyObject *)ret);
229         }
230
231         return true;
232 }
233
234 void PyErr_SetDCERPCStatus(struct dcerpc_pipe *p, NTSTATUS status)
235 {
236         if (p && NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
237                 status = dcerpc_fault_to_nt_status(p->last_fault_code);
238         }
239         PyErr_SetNTSTATUS(status);
240 }
241
242
243 /*
244   take a NDR structure that has a type in a python module and return
245   it as a python object
246
247   r is the NDR structure pointer (a C structure)
248
249   r_ctx is the context that is a parent of r. It will be referenced by
250   the resulting python object
251  */
252 PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
253                                TALLOC_CTX *r_ctx, void *r)
254 {
255         PyTypeObject *py_type;
256         PyObject *module;
257
258         if (r == NULL) {
259                 Py_RETURN_NONE;
260         }
261
262         module = PyImport_ImportModule(module_name);
263         if (module == NULL) {
264                 return NULL;
265         }
266
267         py_type = (PyTypeObject *)PyObject_GetAttrString(module, type_name);
268         if (py_type == NULL) {
269                 return NULL;
270         }
271
272         return py_talloc_reference_ex(py_type, r_ctx, r);
273 }