auth: Move auth_session_info into IDL
[samba.git] / source4 / auth / pyauth.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2011
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <Python.h>
21 #include "includes.h"
22 #include "libcli/util/pyerrors.h"
23 #include "param/param.h"
24 #include "pyauth.h"
25 #include "pyldb.h"
26 #include "auth/system_session_proto.h"
27 #include "auth/auth.h"
28 #include "param/pyparam.h"
29 #include "libcli/security/security.h"
30 #include "auth/credentials/pycredentials.h"
31 #include <tevent.h>
32 #include "librpc/rpc/pyrpc_util.h"
33
34 void initauth(void);
35
36 staticforward PyTypeObject PyAuthContext;
37
38 /* There's no Py_ssize_t in 2.4, apparently */
39 #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 5
40 typedef int Py_ssize_t;
41 typedef inquiry lenfunc;
42 typedef intargfunc ssizeargfunc;
43 #endif
44
45 #ifndef Py_RETURN_NONE
46 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
47 #endif
48
49 static PyObject *PyAuthSession_FromSession(struct auth_session_info *session)
50 {
51         return py_return_ndr_struct("samba.dcerpc.auth", "session_info", session, session);
52 }
53
54 static PyObject *py_system_session(PyObject *module, PyObject *args)
55 {
56         PyObject *py_lp_ctx = Py_None;
57         struct loadparm_context *lp_ctx = NULL;
58         struct auth_session_info *session;
59         TALLOC_CTX *mem_ctx;
60         if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx))
61                 return NULL;
62
63         mem_ctx = talloc_new(NULL);
64         if (mem_ctx == NULL) {
65                 PyErr_NoMemory();
66                 return NULL;
67         }
68
69         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
70         if (lp_ctx == NULL) {
71                 talloc_free(mem_ctx);
72                 return NULL;
73         }
74
75         session = system_session(lp_ctx);
76
77         talloc_free(mem_ctx);
78
79         return PyAuthSession_FromSession(session);
80 }
81
82
83 static PyObject *py_admin_session(PyObject *module, PyObject *args)
84 {
85         PyObject *py_lp_ctx;
86         PyObject *py_sid;
87         struct loadparm_context *lp_ctx = NULL;
88         struct auth_session_info *session;
89         struct dom_sid *domain_sid = NULL;
90         TALLOC_CTX *mem_ctx;
91
92         if (!PyArg_ParseTuple(args, "OO", &py_lp_ctx, &py_sid))
93                 return NULL;
94
95         mem_ctx = talloc_new(NULL);
96         if (mem_ctx == NULL) {
97                 PyErr_NoMemory();
98                 return NULL;
99         }
100
101         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
102         if (lp_ctx == NULL) {
103                 talloc_free(mem_ctx);
104                 return NULL;
105         }
106
107         domain_sid = dom_sid_parse_talloc(mem_ctx, PyString_AsString(py_sid));
108         if (domain_sid == NULL) {
109                 PyErr_Format(PyExc_RuntimeError, "Unable to parse sid %s", 
110                                          PyString_AsString(py_sid));
111                 talloc_free(mem_ctx);
112                 return NULL;
113         }
114         session = admin_session(NULL, lp_ctx, domain_sid);
115         talloc_free(mem_ctx);
116
117         return PyAuthSession_FromSession(session);
118 }
119
120 static PyObject *py_user_session(PyObject *module, PyObject *args, PyObject *kwargs)
121 {
122         NTSTATUS nt_status;
123         struct auth_session_info *session;
124         TALLOC_CTX *mem_ctx;
125         const char * const kwnames[] = { "ldb", "lp_ctx", "principal", "dn", "session_info_flags", NULL };
126         struct ldb_context *ldb_ctx;
127         PyObject *py_ldb = Py_None;
128         PyObject *py_dn = Py_None;
129         PyObject *py_lp_ctx = Py_None;
130         struct loadparm_context *lp_ctx = NULL;
131         struct ldb_dn *user_dn;
132         char *principal = NULL;
133         int session_info_flags = 0; /* This is an int, because that's
134                                  * what we need for the python
135                                  * PyArg_ParseTupleAndKeywords */
136
137         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OzOi",
138                                          discard_const_p(char *, kwnames),
139                                          &py_ldb, &py_lp_ctx, &principal, &py_dn, &session_info_flags)) {
140                 return NULL;
141         }
142
143         mem_ctx = talloc_new(NULL);
144         if (mem_ctx == NULL) {
145                 PyErr_NoMemory();
146                 return NULL;
147         }
148
149         ldb_ctx = PyLdb_AsLdbContext(py_ldb);
150
151         if (py_dn == Py_None) {
152                 user_dn = NULL;
153         } else {
154                 if (!PyObject_AsDn(ldb_ctx, py_dn, ldb_ctx, &user_dn)) {
155                         talloc_free(mem_ctx);
156                         return NULL;
157                 }
158         }
159
160         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
161         if (lp_ctx == NULL) {
162                 talloc_free(mem_ctx);
163                 return NULL;
164         }
165
166         nt_status = authsam_get_session_info_principal(mem_ctx, lp_ctx, ldb_ctx, principal, user_dn,
167                                                        session_info_flags, &session);
168         if (!NT_STATUS_IS_OK(nt_status)) {
169                 talloc_free(mem_ctx);
170                 PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
171         }
172
173         talloc_steal(NULL, session);
174         talloc_free(mem_ctx);
175
176         return PyAuthSession_FromSession(session);
177 }
178
179
180 static const char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list, 
181                                         const char *paramname)
182 {
183         const char **ret;
184         Py_ssize_t i;
185         if (!PyList_Check(list)) {
186                 PyErr_Format(PyExc_TypeError, "%s is not a list", paramname);
187                 return NULL;
188         }
189         ret = talloc_array(NULL, const char *, PyList_Size(list)+1);
190         if (ret == NULL) {
191                 PyErr_NoMemory();
192                 return NULL;
193         }
194
195         for (i = 0; i < PyList_Size(list); i++) {
196                 PyObject *item = PyList_GetItem(list, i);
197                 if (!PyString_Check(item)) {
198                         PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
199                         return NULL;
200                 }
201                 ret[i] = talloc_strndup(ret, PyString_AsString(item),
202                                         PyString_Size(item));
203         }
204         ret[i] = NULL;
205         return ret;
206 }
207
208 static PyObject *PyAuthContext_FromContext(struct auth_context *auth_context)
209 {
210         return py_talloc_reference(&PyAuthContext, auth_context);
211 }
212
213 static PyObject *py_auth_context_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
214 {
215         PyObject *py_lp_ctx = Py_None;
216         PyObject *py_ldb = Py_None;
217         PyObject *py_messaging_ctx = Py_None;
218         PyObject *py_auth_context = Py_None;
219         PyObject *py_methods = Py_None;
220         TALLOC_CTX *mem_ctx;
221         struct auth_context *auth_context;
222         struct messaging_context *messaging_context = NULL;
223         struct loadparm_context *lp_ctx;
224         struct tevent_context *ev;
225         struct ldb_context *ldb;
226         NTSTATUS nt_status;
227         const char **methods;
228
229         const char * const kwnames[] = { "lp_ctx", "messaging_ctx", "ldb", "methods", NULL };
230
231         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOO",
232                                          discard_const_p(char *, kwnames),
233                                          &py_lp_ctx, &py_messaging_ctx, &py_ldb, &py_methods))
234                 return NULL;
235
236         mem_ctx = talloc_new(NULL);
237         if (mem_ctx == NULL) {
238                 PyErr_NoMemory();
239                 return NULL;
240         }
241
242         if (py_ldb != Py_None) {
243                 ldb = PyLdb_AsLdbContext(py_ldb);
244         }
245
246         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
247
248         ev = tevent_context_init(mem_ctx);
249         if (ev == NULL) {
250                 PyErr_NoMemory();
251                 return NULL;
252         }
253
254         if (py_messaging_ctx != Py_None) {
255                 messaging_context = py_talloc_get_type(py_messaging_ctx, struct messaging_context);
256         }
257
258         if (py_methods == Py_None && py_ldb == Py_None) {
259                 nt_status = auth_context_create(mem_ctx, ev, messaging_context, lp_ctx, &auth_context);
260         } else {
261                 if (py_methods != Py_None) {
262                         methods = PyList_AsStringList(mem_ctx, py_methods, "methods");
263                         if (methods == NULL) {
264                                 talloc_free(mem_ctx);
265                                 return NULL;
266                         }
267                 } else {
268                         methods = auth_methods_from_lp(mem_ctx, lp_ctx);
269                 }
270                 nt_status = auth_context_create_methods(mem_ctx, methods, ev, 
271                                                         messaging_context, lp_ctx, 
272                                                         ldb, &auth_context);
273         }
274
275         if (!NT_STATUS_IS_OK(nt_status)) {
276                 talloc_free(mem_ctx);
277                 PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
278         }
279
280         if (!talloc_reference(auth_context, lp_ctx)) {
281                 talloc_free(mem_ctx);
282                 PyErr_NoMemory();
283                 return NULL;
284         }
285
286         if (!talloc_reference(auth_context, ev)) {
287                 talloc_free(mem_ctx);
288                 PyErr_NoMemory();
289                 return NULL;
290         }
291
292         py_auth_context = PyAuthContext_FromContext(auth_context);
293
294         talloc_free(mem_ctx);
295
296         return py_auth_context;
297 }
298
299 static PyTypeObject PyAuthContext = {
300         .tp_name = "AuthContext",
301         .tp_basicsize = sizeof(py_talloc_Object),
302         .tp_flags = Py_TPFLAGS_DEFAULT,
303         .tp_new = py_auth_context_new,
304         .tp_basicsize = sizeof(py_talloc_Object),
305 };
306
307 static PyMethodDef py_auth_methods[] = {
308         { "system_session", (PyCFunction)py_system_session, METH_VARARGS, NULL },
309         { "admin_session", (PyCFunction)py_admin_session, METH_VARARGS, NULL },
310         { "user_session", (PyCFunction)py_user_session, METH_VARARGS|METH_KEYWORDS, NULL },
311         { NULL },
312 };
313
314 void initauth(void)
315 {
316         PyObject *m;
317
318         PyAuthContext.tp_base = PyTalloc_GetObjectType();
319         if (PyAuthContext.tp_base == NULL)
320                 return;
321
322         if (PyType_Ready(&PyAuthContext) < 0)
323                 return;
324
325         m = Py_InitModule3("auth", py_auth_methods,
326                                            "Authentication and authorization support.");
327         if (m == NULL)
328                 return;
329
330         Py_INCREF(&PyAuthContext);
331         PyModule_AddObject(m, "AuthContext", (PyObject *)&PyAuthContext);
332
333 #define ADD_FLAG(val)  PyModule_AddObject(m, #val, PyInt_FromLong(val))
334         ADD_FLAG(AUTH_SESSION_INFO_DEFAULT_GROUPS);
335         ADD_FLAG(AUTH_SESSION_INFO_AUTHENTICATED);
336         ADD_FLAG(AUTH_SESSION_INFO_SIMPLE_PRIVILEGES);
337
338 }