s4-libnet: added join type constants to python interface
[kai/samba.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         const char *kwnames[] = { "domain_name", "netbios_name", "join_type", "level", NULL };
44
45         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssii:Join", discard_const_p(char *, kwnames), 
46                                          &r.in.domain_name, &r.in.netbios_name, 
47                                          &r.in.join_type, &r.in.level))
48                 return NULL;
49
50         mem_ctx = talloc_new(self->mem_ctx);
51
52         status = libnet_Join(self->libnet_ctx, mem_ctx, &r);
53         if (NT_STATUS_IS_ERR(status)) {
54                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
55                 talloc_free(mem_ctx);
56                 return NULL;
57         }
58
59         result = Py_BuildValue("sss", r.out.join_password,
60                                dom_sid_string(mem_ctx, r.out.domain_sid),
61                                r.out.domain_name);
62
63         talloc_free(mem_ctx);
64
65         return result;
66 }
67
68 static const char py_net_join_doc[] = "join(domain_name, netbios_name, join_type, level) -> (join_password, domain_sid, domain_name)\n\n" \
69 "Join the domain with the specified name.";
70
71 static PyObject *py_net_set_password(py_net_Object *self, PyObject *args, PyObject *kwargs)
72 {
73         union libnet_SetPassword r;
74         NTSTATUS status;
75         PyObject *py_creds;
76         TALLOC_CTX *mem_ctx;
77         struct tevent_context *ev;
78         const char *kwnames[] = { "account_name", "domain_name", "newpassword", "credentials", NULL };
79
80         r.generic.level = LIBNET_SET_PASSWORD_GENERIC;
81
82         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssO:set_password", discard_const_p(char *, kwnames),
83                                          &r.generic.in.account_name, &r.generic.in.domain_name,
84                                          &r.generic.in.newpassword, &py_creds)) {
85                 return NULL;
86         }
87
88         /* FIXME: we really need to get a context from the caller or we may end
89          * up with 2 event contexts */
90         ev = s4_event_context_init(NULL);
91         mem_ctx = talloc_new(ev);
92
93         status = libnet_SetPassword(self->libnet_ctx, mem_ctx, &r);
94         if (NT_STATUS_IS_ERR(status)) {
95                 PyErr_SetString(PyExc_RuntimeError,
96                                 r.generic.out.error_string?r.generic.out.error_string:nt_errstr(status));
97                 talloc_free(mem_ctx);
98                 return NULL;
99         }
100
101         talloc_free(mem_ctx);
102
103         Py_RETURN_NONE;
104 }
105
106 static const char py_net_set_password_doc[] = "set_password(account_name, domain_name, newpassword) -> True\n\n" \
107 "Set password for a user. You must supply credential with enough rights to do this.\n\n" \
108 "Sample usage is:\n" \
109 "net.set_password(account_name=<account_name>,\n" \
110 "                domain_name=domain_name,\n" \
111 "                newpassword=new_pass)\n";
112
113
114 static PyObject *py_net_export_keytab(py_net_Object *self, PyObject *args, PyObject *kwargs)
115 {
116         struct libnet_export_keytab r;
117         TALLOC_CTX *mem_ctx;
118         const char *kwnames[] = { "keytab", NULL };
119         NTSTATUS status;
120
121         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:export_keytab", discard_const_p(char *, kwnames),
122                                          &r.in.keytab_name)) {
123                 return NULL;
124         }
125
126         mem_ctx = talloc_new(self->mem_ctx);
127
128         status = libnet_export_keytab(self->libnet_ctx, mem_ctx, &r);
129         if (NT_STATUS_IS_ERR(status)) {
130                 PyErr_SetString(PyExc_RuntimeError,
131                                 r.out.error_string?r.out.error_string:nt_errstr(status));
132                 talloc_free(mem_ctx);
133                 return NULL;
134         }
135
136         talloc_free(mem_ctx);
137
138         Py_RETURN_NONE;
139 }
140
141 static const char py_net_export_keytab_doc[] = "export_keytab(keytab, name)\n\n"
142 "Export the DC keytab to a keytab file.";
143
144 static PyObject *py_net_time(py_net_Object *self, PyObject *args, PyObject *kwargs)
145 {
146         const char *kwnames[] = { "server_name", NULL };
147         union libnet_RemoteTOD r;
148         NTSTATUS status;
149         TALLOC_CTX *mem_ctx;
150         char timestr[64];
151         PyObject *ret;
152         struct tm *tm;
153
154         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s",
155                 discard_const_p(char *, kwnames), &r.generic.in.server_name))
156                 return NULL;
157
158         r.generic.level                 = LIBNET_REMOTE_TOD_GENERIC;
159
160         mem_ctx = talloc_new(NULL);
161         if (mem_ctx == NULL) {
162                 PyErr_NoMemory();
163                 return NULL;
164         }
165
166         status = libnet_RemoteTOD(self->libnet_ctx, mem_ctx, &r);
167         if (!NT_STATUS_IS_OK(status)) {
168                 PyErr_SetString(PyExc_RuntimeError,
169                                 r.generic.out.error_string?r.generic.out.error_string:nt_errstr(status));
170                 talloc_free(mem_ctx);
171                 return NULL;
172         }
173
174         ZERO_STRUCT(timestr);
175         tm = localtime(&r.generic.out.time);
176         strftime(timestr, sizeof(timestr)-1, "%c %Z",tm);
177         
178         ret = PyString_FromString(timestr);
179
180         talloc_free(mem_ctx);
181
182         return ret;
183 }
184
185 static const char py_net_time_doc[] = "time(server_name) -> timestr\n"
186 "Retrieve the remote time on a server";
187
188 static PyObject *py_net_user_create(py_net_Object *self, PyObject *args, PyObject *kwargs)
189 {
190         const char *kwnames[] = { "username", NULL };
191         NTSTATUS status;
192         TALLOC_CTX *mem_ctx;
193         struct libnet_CreateUser r;
194
195         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames), 
196                                                                          &r.in.user_name))
197                 return NULL;
198
199         r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
200
201         mem_ctx = talloc_new(NULL);
202         if (mem_ctx == NULL) {
203                 PyErr_NoMemory();
204                 return NULL;
205         }
206
207         status = libnet_CreateUser(self->libnet_ctx, mem_ctx, &r);
208         if (!NT_STATUS_IS_OK(status)) {
209                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
210                 talloc_free(mem_ctx);
211                 return NULL;
212         }
213
214         talloc_free(mem_ctx);
215         
216         Py_RETURN_NONE;
217 }
218
219 static const char py_net_create_user_doc[] = "create_user(username)\n"
220 "Create a new user.";
221
222 static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObject *kwargs)
223 {
224         const char *kwnames[] = { "username", NULL };
225         NTSTATUS status;
226         TALLOC_CTX *mem_ctx;
227         struct libnet_DeleteUser r;
228
229         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames), 
230                                                                          &r.in.user_name))
231                 return NULL;
232
233         r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
234
235         mem_ctx = talloc_new(NULL);
236         if (mem_ctx == NULL) {
237                 PyErr_NoMemory();
238                 return NULL;
239         }
240
241         status = libnet_DeleteUser(self->libnet_ctx, mem_ctx, &r);
242         if (!NT_STATUS_IS_OK(status)) {
243                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string?r.out.error_string:nt_errstr(status));
244                 talloc_free(mem_ctx);
245                 return NULL;
246         }
247
248         talloc_free(mem_ctx);
249         
250         Py_RETURN_NONE;
251 }
252
253 static const char py_net_delete_user_doc[] = "delete_user(username)\n"
254 "Delete a user.";
255
256 static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
257 {
258         PyObject *mod_security, *dom_sid_Type;
259
260         mod_security = PyImport_ImportModule("samba.dcerpc.security");
261         if (mod_security == NULL)
262                 return NULL;
263
264         dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
265         if (dom_sid_Type == NULL)
266                 return NULL;
267
268         return py_talloc_reference((PyTypeObject *)dom_sid_Type, sid);
269 }
270
271 static PyObject *py_net_vampire(py_net_Object *self, PyObject *args, PyObject *kwargs)
272 {
273         const char *kwnames[] = { "domain", "target_dir", NULL };
274         NTSTATUS status;
275         TALLOC_CTX *mem_ctx;
276         PyObject *ret;
277         struct libnet_Vampire r;
278
279         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z", discard_const_p(char *, kwnames),
280                                          &r.in.domain_name, &r.in.targetdir)) {
281                 return NULL;
282         }
283
284         r.in.netbios_name  = lpcfg_netbios_name(self->libnet_ctx->lp_ctx);
285         r.out.error_string = NULL;
286
287         mem_ctx = talloc_new(NULL);
288         if (mem_ctx == NULL) {
289                 PyErr_NoMemory();
290                 return NULL;
291         }
292
293         status = libnet_Vampire(self->libnet_ctx, mem_ctx, &r);
294
295         if (!NT_STATUS_IS_OK(status)) {
296                 PyErr_SetString(PyExc_RuntimeError,
297                                 r.out.error_string ? r.out.error_string : nt_errstr(status));
298                 talloc_free(mem_ctx);
299                 return NULL;
300         }
301
302         ret = Py_BuildValue("(sO)", r.out.domain_name, py_dom_sid_FromSid(r.out.domain_sid));
303
304         talloc_free(mem_ctx);
305
306         return ret;
307 }
308
309 static const char py_net_vampire_doc[] = "vampire(domain, target_dir=None)\n"
310                                          "Vampire a domain.";
311
312 static PyMethodDef net_obj_methods[] = {
313         {"join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc},
314         {"set_password", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc},
315         {"export_keytab", (PyCFunction)py_net_export_keytab, METH_VARARGS|METH_KEYWORDS, py_net_export_keytab_doc},
316         {"time", (PyCFunction)py_net_time, METH_VARARGS|METH_KEYWORDS, py_net_time_doc},
317         {"create_user", (PyCFunction)py_net_user_create, METH_VARARGS|METH_KEYWORDS, py_net_create_user_doc},
318         {"delete_user", (PyCFunction)py_net_user_delete, METH_VARARGS|METH_KEYWORDS, py_net_delete_user_doc},
319         {"vampire", (PyCFunction)py_net_vampire, METH_VARARGS|METH_KEYWORDS, py_net_vampire_doc},
320         { NULL }
321 };
322
323 static void py_net_dealloc(py_net_Object *self)
324 {
325         talloc_free(self->mem_ctx);
326 }
327
328 static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
329 {
330         PyObject *py_creds, *py_lp = Py_None;
331         const char *kwnames[] = { "creds", "lp", NULL };
332         py_net_Object *ret;
333         struct loadparm_context *lp;
334
335         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", 
336                         discard_const_p(char *, kwnames), &py_creds, &py_lp))
337                 return NULL;
338
339         ret = PyObject_New(py_net_Object, type);
340         if (ret == NULL) {
341                 return NULL;
342         }
343
344         /* FIXME: we really need to get a context from the caller or we may end
345          * up with 2 event contexts */
346         ret->ev = s4_event_context_init(NULL);
347         ret->mem_ctx = talloc_new(ret->ev);
348
349         lp = lpcfg_from_py_object(ret->mem_ctx, py_lp);
350         if (lp == NULL) {
351                 Py_DECREF(ret);
352                 return NULL;
353         }
354
355         ret->libnet_ctx = libnet_context_init(ret->ev, lp);
356         if (ret->libnet_ctx == NULL) {
357                 PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
358                 Py_DECREF(ret);
359                 return NULL;
360         }
361
362         ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
363         if (ret->libnet_ctx->cred == NULL) {
364                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
365                 Py_DECREF(ret);
366                 return NULL;
367         }
368
369         return (PyObject *)ret;
370 }
371
372
373 PyTypeObject py_net_Type = {
374         PyObject_HEAD_INIT(NULL) 0,
375         .tp_name = "net.Net",
376         .tp_basicsize = sizeof(py_net_Object),
377         .tp_dealloc = (destructor)py_net_dealloc,
378         .tp_methods = net_obj_methods,
379         .tp_new = net_obj_new,
380 };
381
382 void initnet(void)
383 {
384         PyObject *m;
385
386         if (PyType_Ready(&py_net_Type) < 0)
387                 return;
388
389         m = Py_InitModule3("net", NULL, NULL);
390         if (m == NULL)
391                 return;
392
393         Py_INCREF(&py_net_Type);
394         PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
395         PyModule_AddObject(m, "LIBNET_JOINDOMAIN_AUTOMATIC", PyInt_FromLong(LIBNET_JOINDOMAIN_AUTOMATIC));
396         PyModule_AddObject(m, "LIBNET_JOINDOMAIN_SPECIFIED", PyInt_FromLong(LIBNET_JOINDOMAIN_SPECIFIED));
397         PyModule_AddObject(m, "LIBNET_JOIN_AUTOMATIC", PyInt_FromLong(LIBNET_JOIN_AUTOMATIC));
398         PyModule_AddObject(m, "LIBNET_JOIN_SPECIFIED", PyInt_FromLong(LIBNET_JOIN_SPECIFIED));
399 }