s4-net: Convert user subcommand to Python.
[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         struct libnet_context *libnet_ctx;
33         TALLOC_CTX *mem_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);
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, r.generic.out.error_string);
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, r.out.error_string);
131                 talloc_free(mem_ctx);
132                 return NULL;
133         }
134
135         talloc_free(mem_ctx);
136
137         Py_RETURN_NONE;
138 }
139
140 static const char py_net_export_keytab_doc[] = "export_keytab(keytab, name)\n\n"
141 "Export the DC keytab to a keytab file.";
142
143 static PyObject *py_net_time(py_net_Object *self, PyObject *args, PyObject *kwargs)
144 {
145         const char *kwnames[] = { "server_name", NULL };
146         union libnet_RemoteTOD r;
147         NTSTATUS status;
148         TALLOC_CTX *mem_ctx;
149         char timestr[64];
150         PyObject *ret;
151         struct tm *tm;
152
153         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s",
154                 discard_const_p(char *, kwnames), &r.generic.in.server_name))
155                 return NULL;
156
157         r.generic.level                 = LIBNET_REMOTE_TOD_GENERIC;
158
159         mem_ctx = talloc_new(NULL);
160         if (mem_ctx == NULL) {
161                 PyErr_NoMemory();
162                 return NULL;
163         }
164
165         status = libnet_RemoteTOD(self->libnet_ctx, mem_ctx, &r);
166         if (!NT_STATUS_IS_OK(status)) {
167                 PyErr_SetString(PyExc_RuntimeError, r.generic.out.error_string);
168                 talloc_free(mem_ctx);
169                 return NULL;
170         }
171
172         ZERO_STRUCT(timestr);
173         tm = localtime(&r.generic.out.time);
174         strftime(timestr, sizeof(timestr)-1, "%c %Z",tm);
175         
176         ret = PyString_FromString(timestr);
177
178         talloc_free(mem_ctx);
179
180         return ret;
181 }
182
183 static const char py_net_time_doc[] = "time(server_name) -> timestr\n"
184 "Retrieve the remote time on a server";
185
186 static PyObject *py_net_user_create(py_net_Object *self, PyObject *args, PyObject *kwargs)
187 {
188         const char *kwnames[] = { "username", NULL };
189         NTSTATUS status;
190         TALLOC_CTX *mem_ctx;
191         struct libnet_CreateUser r;
192
193         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames), 
194                                                                          &r.in.user_name))
195                 return NULL;
196
197         r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
198
199         mem_ctx = talloc_new(NULL);
200         if (mem_ctx == NULL) {
201                 PyErr_NoMemory();
202                 return NULL;
203         }
204
205         status = libnet_CreateUser(self->libnet_ctx, mem_ctx, &r);
206         if (!NT_STATUS_IS_OK(status)) {
207                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string);
208                 talloc_free(mem_ctx);
209                 return NULL;
210         }
211
212         talloc_free(mem_ctx);
213         
214         Py_RETURN_NONE;
215 }
216
217 static const char py_net_create_user_doc[] = "create_user(username)\n"
218 "Create a new user.";
219
220 static PyObject *py_net_user_delete(py_net_Object *self, PyObject *args, PyObject *kwargs)
221 {
222         const char *kwnames[] = { "username", NULL };
223         NTSTATUS status;
224         TALLOC_CTX *mem_ctx;
225         struct libnet_DeleteUser r;
226
227         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", discard_const_p(char *, kwnames), 
228                                                                          &r.in.user_name))
229                 return NULL;
230
231         r.in.domain_name = cli_credentials_get_domain(self->libnet_ctx->cred);
232
233         mem_ctx = talloc_new(NULL);
234         if (mem_ctx == NULL) {
235                 PyErr_NoMemory();
236                 return NULL;
237         }
238
239         status = libnet_DeleteUser(self->libnet_ctx, mem_ctx, &r);
240         if (!NT_STATUS_IS_OK(status)) {
241                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string);
242                 talloc_free(mem_ctx);
243                 return NULL;
244         }
245
246         talloc_free(mem_ctx);
247         
248         Py_RETURN_NONE;
249 }
250
251 static const char py_net_delete_user_doc[] = "delete_user(username)\n"
252 "Delete a user.";
253
254 static PyMethodDef net_obj_methods[] = {
255         {"join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc},
256         {"set_password", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc},
257         {"export_keytab", (PyCFunction)py_net_export_keytab, METH_VARARGS|METH_KEYWORDS, py_net_export_keytab_doc},
258         {"time", (PyCFunction)py_net_time, METH_VARARGS|METH_KEYWORDS, py_net_time_doc},
259         {"create_user", (PyCFunction)py_net_user_create, METH_VARARGS|METH_KEYWORDS, py_net_create_user_doc},
260         {"delete_user", (PyCFunction)py_net_user_delete, METH_VARARGS|METH_KEYWORDS, py_net_delete_user_doc},
261         { NULL }
262 };
263
264 static void py_net_dealloc(py_net_Object *self)
265 {
266         talloc_free(self->mem_ctx);
267 }
268
269 static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
270 {
271         PyObject *py_creds, *py_lp = Py_None;
272         const char *kwnames[] = { "creds", "lp", NULL };
273         py_net_Object *ret;
274         struct loadparm_context *lp;
275
276         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", 
277                         discard_const_p(char *, kwnames), &py_creds, &py_lp))
278                 return NULL;
279
280         ret = PyObject_New(py_net_Object, type);
281         if (ret == NULL) {
282                 return NULL;
283         }
284
285         /* FIXME: we really need to get a context from the caller or we may end
286          * up with 2 event contexts */
287         ret->ev = s4_event_context_init(NULL);
288         ret->mem_ctx = talloc_new(ret->ev);
289
290         lp = lp_from_py_object(ret->mem_ctx, py_lp);
291         if (lp == NULL) {
292                 Py_DECREF(ret);
293                 return NULL;
294         }
295
296         ret->libnet_ctx = libnet_context_init(ret->ev, lp);
297         if (ret->libnet_ctx == NULL) {
298                 PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
299                 Py_DECREF(ret);
300                 return NULL;
301         }
302
303         ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
304         if (ret->libnet_ctx->cred == NULL) {
305                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
306                 Py_DECREF(ret);
307                 return NULL;
308         }
309
310         return (PyObject *)ret;
311 }
312
313
314 PyTypeObject py_net_Type = {
315         PyObject_HEAD_INIT(NULL) 0,
316         .tp_name = "net.Net",
317         .tp_basicsize = sizeof(py_net_Object),
318         .tp_dealloc = (destructor)py_net_dealloc,
319         .tp_methods = net_obj_methods,
320         .tp_new = net_obj_new,
321 };
322
323 void initnet(void)
324 {
325         PyObject *m;
326
327         if (PyType_Ready(&py_net_Type) < 0)
328                 return;
329
330         m = Py_InitModule3("net", NULL, NULL);
331         if (m == NULL)
332                 return;
333
334         Py_INCREF(&py_net_Type);
335         PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
336 }