pynet: Create a net class.
[kamenim/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
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 "creds = samba.credentials.Credentials()\n" \
110 "creds.set_username('admin_user')\n" \
111 "creds.set_domain('domain_name')\n" \
112 "creds.set_password('pass')\n\n" \
113 "net.set_password(account_name=<account_name>,\n" \
114 "                domain_name=creds.get_domain(),\n" \
115 "                newpassword=new_pass,\n" \
116 "                credentials=creds)\n";
117
118
119 static PyObject *py_net_export_keytab(py_net_Object *self, PyObject *args, PyObject *kwargs)
120 {
121         struct libnet_export_keytab r;
122         TALLOC_CTX *mem_ctx;
123         const char *kwnames[] = { "keytab", "creds", NULL };
124         PyObject *py_creds;
125         NTSTATUS status;
126
127         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO:export_keytab", discard_const_p(char *, kwnames),
128                                          &r.in.keytab_name, &py_creds)) {
129                 return NULL;
130         }
131
132         mem_ctx = talloc_new(self->mem_ctx);
133
134         status = libnet_export_keytab(self->libnet_ctx, mem_ctx, &r);
135         if (NT_STATUS_IS_ERR(status)) {
136                 PyErr_SetString(PyExc_RuntimeError, r.out.error_string);
137                 talloc_free(mem_ctx);
138                 return NULL;
139         }
140
141         talloc_free(mem_ctx);
142
143         Py_RETURN_NONE;
144 }
145
146 static const char py_net_export_keytab_doc[] = "export_keytab(keytab, name)\n\n"
147 "Export the DC keytab to a keytab file.";
148
149 static PyMethodDef net_obj_methods[] = {
150         {"join", (PyCFunction)py_net_join, METH_VARARGS|METH_KEYWORDS, py_net_join_doc},
151         {"set_password", (PyCFunction)py_net_set_password, METH_VARARGS|METH_KEYWORDS, py_net_set_password_doc},
152         {"export_keytab", (PyCFunction)py_net_export_keytab, METH_VARARGS|METH_KEYWORDS, py_net_export_keytab_doc},
153         { NULL }
154 };
155
156 static void py_net_dealloc(py_net_Object *self)
157 {
158         talloc_free(self->mem_ctx);
159 }
160
161 static PyObject *net_obj_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
162 {
163         PyObject *py_creds, *py_lp = Py_None;
164         const char *kwnames[] = { "creds", "lp", NULL };
165         py_net_Object *ret;
166         struct loadparm_context *lp;
167
168         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", 
169                         discard_const_p(char *, kwnames), &py_creds, &py_lp))
170                 return NULL;
171
172         ret = PyObject_New(py_net_Object, type);
173         if (ret == NULL) {
174                 return NULL;
175         }
176
177         /* FIXME: we really need to get a context from the caller or we may end
178          * up with 2 event contexts */
179         ret->ev = s4_event_context_init(NULL);
180         ret->mem_ctx = talloc_new(ret->ev);
181
182         lp = lp_from_py_object(ret->mem_ctx, py_lp);
183         if (lp == NULL) {
184                 Py_DECREF(ret);
185                 return NULL;
186         }
187
188         ret->libnet_ctx = libnet_context_init(ret->ev, lp);
189         if (ret->libnet_ctx == NULL) {
190                 PyErr_SetString(PyExc_RuntimeError, "Unable to initialize net");
191                 Py_DECREF(ret);
192                 return NULL;
193         }
194
195         ret->libnet_ctx->cred = cli_credentials_from_py_object(py_creds);
196         if (ret->libnet_ctx->cred == NULL) {
197                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
198                 Py_DECREF(ret);
199                 return NULL;
200         }
201
202         return (PyObject *)ret;
203 }
204
205
206 PyTypeObject py_net_Type = {
207         PyObject_HEAD_INIT(NULL) 0,
208         .tp_name = "net.Net",
209         .tp_basicsize = sizeof(py_net_Object),
210         .tp_dealloc = (destructor)py_net_dealloc,
211         .tp_methods = net_obj_methods,
212         .tp_new = net_obj_new,
213 };
214
215 void initnet(void)
216 {
217         PyObject *m;
218         m = Py_InitModule3("net", NULL, NULL);
219         if (m == NULL)
220                 return;
221
222         Py_INCREF(&py_net_Type);
223         PyModule_AddObject(m, "Net", (PyObject *)&py_net_Type);
224 }