pytalloc: ensure talloc_ctx is directly after PyObject_HEAD
[nivanova/samba-autobuild/.git] / source4 / libnet / py_net.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2010
5    Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <Python.h>
22 #include "includes.h"
23 #include "libnet.h"
24 #include "auth/credentials/pycredentials.h"
25 #include "libcli/security/security.h"
26 #include "lib/events/events.h"
27 #include "param/param.h"
28 #include "param/pyparam.h"
29
30 typedef struct {
31         PyObject_HEAD
32         TALLOC_CTX *mem_ctx;
33         struct libnet_context *libnet_ctx;
34         struct tevent_context *ev;
35 } py_net_Object;
36
37 static PyObject *py_net_join(py_net_Object *self, PyObject *args, PyObject *kwargs)
38 {
39         struct libnet_Join r;
40         NTSTATUS status;
41         PyObject *result;
42         TALLOC_CTX *mem_ctx;
43         PyObject *py_creds;     
44         const char *kwnames[] = { "domain_name", "netbios_name", "join_type", "level", "credentials", NULL };
45
46         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssiiO:Join", discard_const_p(char *, kwnames), 
47                                          &r.in.domain_name, &r.in.netbios_name, 
48                                          &r.in.join_type, &r.in.level, &py_creds))
49                 return NULL;
50
51         mem_ctx = talloc_new(self->mem_ctx);
52
53         status = libnet_Join(self->libnet_ctx, mem_ctx, &r);
54         if (NT_STATUS_IS_ERR(status)) {
55                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
56                 talloc_free(mem_ctx);
57                 return NULL;
58         }
59
60         result = Py_BuildValue("sss", r.out.join_password,
61                                dom_sid_string(mem_ctx, r.out.domain_sid),
62                                r.out.domain_name);
63
64         talloc_free(mem_ctx);
65
66         return result;
67 }
68
69 static const char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \
70 "Join the domain with the specified name.";
71
72 static PyObject *py_net_set_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
73 {
74         union libnet_SetPassword r;
75         NTSTATUS status;
76         PyObject *py_creds;
77         TALLOC_CTX *mem_ctx;
78         struct tevent_context *ev;
79         const char *kwnames[] = { "account_name", "domain_name", "newpassword", "credentials", NULL };
80
81         r.generic.level = LIBNET_SET_PASSWORD_GENERIC;
82
83         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssO:set_password", discard_const_p(char *, kwnames),
84                                          &r.generic.in.account_name, &r.generic.in.domain_name,
85                                          &r.generic.in.newpassword, &py_creds)) {
86                 return NULL;
87         }
88
89         /* FIXME: we really need to get a context from the caller or we may end
90          * up with 2 event contexts */
91         ev = s4_event_context_init(NULL);
92         mem_ctx = talloc_new(ev);
93
94         status = libnet_SetPassword(self->libnet_ctx, mem_ctx, &r);
95         if (NT_STATUS_IS_ERR(status)) {
96                 PyErr_SetString(PyExc_RuntimeError,
97                                 r.generic.out.error_string?r.generic.out.error_string:nt_errstr(status));
98                 talloc_free(mem_ctx);
99                 return NULL;
100         }
101
102         talloc_free(mem_ctx);
103
104         Py_RETURN_NONE;
105 }
106
107 static const char py_net_set_password_doc[] = "set_password(account_name, domain_name, newpassword) -> True\n\n" \
108 "Set password for a user. You must supply credential with enough rights to do this.\n\n" \
109 "Sample usage is:\n" \
110 "net.set_password(account_name=<account_name>,\n" \
111 "                domain_name=domain_name,\n" \
112 "                newpassword=new_pass)\n";
113
114
115 static PyObject *py_net_export_keytab(py_net_Object *self, PyObject *args, PyObject *kwargs)
116 {
117         struct libnet_export_keytab r;
118         TALLOC_CTX *mem_ctx;
119         const char *kwnames[] = { "keytab", NULL };
120         NTSTATUS status;
121
122         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:export_keytab", discard_const_p(char *, kwnames),
123                                          &r.in.keytab_name)) {
124                 return NULL;
125         }
126
127         mem_ctx = talloc_new(self->mem_ctx);
128
129         status = libnet_export_keytab(self->libnet_ctx, mem_ctx, &r);
130         if (NT_STATUS_IS_ERR(status)) {
131                 PyErr_SetString(PyExc_RuntimeError,
132                                 r.out.error_string?r.out.error_string:nt_errstr(status));
133                 talloc_free(mem_ctx);
134                 return NULL;
135         }
136
137         talloc_free(mem_ctx);
138
139         Py_RETURN_NONE;
140 }
141
142 static const char py_net_export_keytab_doc[] = "export_keytab(keytab, name)\n\n"
143 "Export the DC keytab to a keytab file.";
144
145 static PyObject *py_net_time(py_net_Object *self, PyObject *args, PyObject *kwargs)
146 {
147         const char *kwnames[] = { "server_name", NULL };
148         union libnet_RemoteTOD r;
149         NTSTATUS status;
150         TALLOC_CTX *mem_ctx;
151         char timestr[64];
152         PyObject *ret;
153         struct tm *tm;
154
155         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s",
156                 discard_const_p(char *, kwnames), &r.generic.in.server_name))
157                 return NULL;
158
159         r.generic.level                 = LIBNET_REMOTE_TOD_GENERIC;
160
161         mem_ctx = talloc_new(NULL);
162         if (mem_ctx == NULL) {
163                 PyErr_NoMemory();
164                 return NULL;
165         }
166
167         status = libnet_RemoteTOD(self->libnet_ctx, mem_ctx, &r);
168         if (!NT_STATUS_IS_OK(status)) {
169                 PyErr_SetString(PyExc_RuntimeError,
170                                 r.generic.out.error_string?r.generic.out.error_string:nt_errstr(status));
171                 talloc_free(mem_ctx);
172                 return NULL;
173         }
174
175         ZERO_STRUCT(timestr);
176         tm = localtime(&r.generic.out.time);
177         strftime(timestr, sizeof(timestr)-1, "%c %Z",tm);
178         
179         ret = PyString_FromString(timestr);
180
181         talloc_free(mem_ctx);
182
183         return ret;
184 }
185
186 static const char py_net_time_doc[] = "time(server_name) -> timestr\n"
187 "Retrieve the remote time on a server";
188
189 static PyObject *py_net_user_create(py_net_Object *self, PyObject *args, PyObject *kwargs)
190 {
191         const char *kwnames[] = { "username", NULL };
192         NTSTATUS status;
193         TALLOC_CTX *mem_ctx;
194         struct libnet_CreateUser r;
195
196         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames), 
197                                                                          &r.in.user_name))
198                 return NULL;
199
200         r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
201
202         mem_ctx = talloc_new(NULL);
203         if (mem_ctx == NULL) {
204                 PyErr_NoMemory();
205                 return NULL;
206         }
207
208         status = libnet_CreateUser(self->libnet_ctx, mem_ctx, &r);
209         if (!NT_STATUS_IS_OK(status)) {
210                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
211                 talloc_free(mem_ctx);
212                 return NULL;
213         }
214
215         talloc_free(mem_ctx);
216         
217         Py_RETURN_NONE;
218 }
219
220 static const char py_net_create_user_doc[] = "create_user(username)\n"
221 "Create a new user.";
222
223 static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObject *kwargs)
224 {
225         const char *kwnames[] = { "username", NULL };
226         NTSTATUS status;
227         TALLOC_CTX *mem_ctx;
228         struct libnet_DeleteUser r;
229
230         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames), 
231                                                                          &r.in.user_name))
232                 return NULL;
233
234         r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
235
236         mem_ctx = talloc_new(NULL);
237         if (mem_ctx == NULL) {
238                 PyErr_NoMemory();
239                 return NULL;
240         }
241
242         status = libnet_DeleteUser(self->libnet_ctx, mem_ctx, &r);
243         if (!NT_STATUS_IS_OK(status)) {
244                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
245                 talloc_free(mem_ctx);
246                 return NULL;
247         }
248
249         talloc_free(mem_ctx);
250         
251         Py_RETURN_NONE;
252 }
253
254 static const char py_net_delete_user_doc[] = "delete_user(username)\n"
255 "Delete a user.";
256
257 static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
258 {
259         PyObject *mod_security, *dom_sid_Type;
260
261         mod_security = PyImport_ImportModule("samba.dcerpc.security");
262         if (mod_security == NULL)
263                 return NULL;
264
265         dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
266         if (dom_sid_Type == NULL)
267                 return NULL;
268
269         return py_talloc_reference((PyTypeObject *)dom_sid_Type, sid);
270 }
271
272 static PyObject *py_net_vampire(py_net_Object *self, PyObject *args, PyObject *kwargs)
273 {
274         const char *kwnames[] = { "domain", "target_dir", NULL };
275         NTSTATUS status;
276         TALLOC_CTX *mem_ctx;
277         PyObject *ret;
278         struct libnet_Vampire r;
279
280         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|s", discard_const_p(char *, kwnames),
281                                          &r.in.domain_name, &r.in.targetdir)) {
282                 return NULL;
283         }
284
285         r.in.netbios_name  = lp_netbios_name(self->libnet_ctx->lp_ctx);
286         r.out.error_string = NULL;
287
288         mem_ctx = talloc_new(NULL);
289         if (mem_ctx == NULL) {
290                 PyErr_NoMemory();
291                 return NULL;
292         }
293
294         status = libnet_Vampire(self->libnet_ctx, mem_ctx, &r);
295
296         if (!NT_STATUS_IS_OK(status)) {
297                 PyErr_SetString(PyExc_RuntimeError,
298                                 r.out.error_string ? r.out.error_string : nt_errstr(status));
299                 talloc_free(mem_ctx);
300                 return NULL;
301         }
302
303         ret = Py_BuildValue("(sO)", r.out.domain_name, py_dom_sid_FromSid(r.out.domain_sid));
304
305         talloc_free(mem_ctx);
306
307         return ret;
308 }
309
310 static const char py_net_vampire_doc[] = "vampire(domain, target_dir=None)\n"
311                                          "Vampire a domain.";
312
313 static PyMethodDef net_obj_methods[] = {
314         {"join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc},
315         {"set_password", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc},
316         {"export_keytab", (PyCFunction)py_net_export_keytab, METH_VARARGS|METH_KEYWORDS, py_net_export_keytab_doc},
317         {"time", (PyCFunction)py_net_time, METH_VARARGS|METH_KEYWORDS, py_net_time_doc},
318         {"create_user", (PyCFunction)py_net_user_create, METH_VARARGS|METH_KEYWORDS, py_net_create_user_doc},
319         {"delete_user", (PyCFunction)py_net_user_delete, METH_VARARGS|METH_KEYWORDS, py_net_delete_user_doc},
320         {"vampire", (PyCFunction)py_net_vampire, METH_VARARGS|METH_KEYWORDS, py_net_vampire_doc},
321         { NULL }
322 };
323
324 static void py_net_dealloc(py_net_Object *self)
325 {
326         talloc_free(self->mem_ctx);
327 }
328
329 static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
330 {
331         PyObject *py_creds, *py_lp = Py_None;
332         const char *kwnames[] = { "creds", "lp", NULL };
333         py_net_Object *ret;
334         struct loadparm_context *lp;
335
336         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", 
337                         discard_const_p(char *, kwnames), &py_creds, &py_lp))
338                 return NULL;
339
340         ret = PyObject_New(py_net_Object, type);
341         if (ret == NULL) {
342                 return NULL;
343         }
344
345         /* FIXME: we really need to get a context from the caller or we may end
346          * up with 2 event contexts */
347         ret->ev = s4_event_context_init(NULL);
348         ret->mem_ctx = talloc_new(ret->ev);
349
350         lp = lp_from_py_object(ret->mem_ctx, py_lp);
351         if (lp == NULL) {
352                 Py_DECREF(ret);
353                 return NULL;
354         }
355
356         ret->libnet_ctx = libnet_context_init(ret->ev, lp);
357         if (ret->libnet_ctx == NULL) {
358                 PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
359                 Py_DECREF(ret);
360                 return NULL;
361         }
362
363         ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
364         if (ret->libnet_ctx->cred == NULL) {
365                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
366                 Py_DECREF(ret);
367                 return NULL;
368         }
369
370         return (PyObject *)ret;
371 }
372
373
374 PyTypeObject py_net_Type = {
375         PyObject_HEAD_INIT(NULL) 0,
376         .tp_name = "net.Net",
377         .tp_basicsize = sizeof(py_net_Object),
378         .tp_dealloc = (destructor)py_net_dealloc,
379         .tp_methods = net_obj_methods,
380         .tp_new = net_obj_new,
381 };
382
383 void initnet(void)
384 {
385         PyObject *m;
386
387         if (PyType_Ready(&py_net_Type) < 0)
388                 return;
389
390         m = Py_InitModule3("net", NULL, NULL);
391         if (m == NULL)
392                 return;
393
394         Py_INCREF(&py_net_Type);
395         PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
396 }