0736859092c990b5a1aeb14a598939fdb43622c5
[sfrench/samba-autobuild/.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 "python/py3compat.h"
22 #include "includes.h"
23 #include "libcli/util/pyerrors.h"
24 #include "param/param.h"
25 #include "pyauth.h"
26 #include "pyldb.h"
27 #include "auth/system_session_proto.h"
28 #include "auth/auth.h"
29 #include "auth/auth_util.h"
30 #include "param/pyparam.h"
31 #include "libcli/security/security.h"
32 #include "auth/credentials/pycredentials.h"
33 #include <tevent.h>
34 #include "librpc/rpc/pyrpc_util.h"
35 #include "lib/events/events.h"
36
37 static PyTypeObject PyAuthContext;
38
39 static PyObject *PyAuthSession_FromSession(struct auth_session_info *session)
40 {
41         return py_return_ndr_struct("samba.dcerpc.auth", "session_info", session, session);
42 }
43
44 static PyObject *py_copy_session_info(PyObject *module,
45                                       PyObject *args,
46                                       PyObject *kwargs)
47 {
48         PyObject *py_session = Py_None;
49         PyObject *result = Py_None;
50         struct auth_session_info *session = NULL;
51         struct auth_session_info *session_duplicate = NULL;
52         TALLOC_CTX *frame;
53         int ret = 1;
54
55         const char * const kwnames[] = { "session_info", NULL };
56
57         ret = PyArg_ParseTupleAndKeywords(args,
58                                           kwargs,
59                                           "O",
60                                           discard_const_p(char *, kwnames),
61                                           &py_session);
62         if (!ret) {
63                 return NULL;
64         }
65
66         ret = py_check_dcerpc_type(py_session,
67                                    "samba.dcerpc.auth",
68                                    "session_info");
69         if (!ret) {
70                 return NULL;
71         }
72         session = pytalloc_get_type(py_session,
73                                     struct auth_session_info);
74         if (!session) {
75                 PyErr_Format(PyExc_TypeError,
76                              "Expected auth_session_info for session_info "
77                              "argument got %s",
78                              talloc_get_name(pytalloc_get_ptr(py_session)));
79                 return NULL;
80         }
81
82         frame = talloc_stackframe();
83         if (frame == NULL) {
84                 return PyErr_NoMemory();
85         }
86
87         session_duplicate = copy_session_info(frame, session);
88         if (session_duplicate == NULL) {
89                 TALLOC_FREE(frame);
90                 return PyErr_NoMemory();
91         }
92
93         result = PyAuthSession_FromSession(session_duplicate);
94         TALLOC_FREE(frame);
95         return result;
96 }
97
98 static PyObject *py_system_session(PyObject *module, PyObject *args)
99 {
100         PyObject *py_lp_ctx = Py_None;
101         struct loadparm_context *lp_ctx = NULL;
102         struct auth_session_info *session;
103         TALLOC_CTX *mem_ctx;
104         if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx))
105                 return NULL;
106
107         mem_ctx = talloc_new(NULL);
108         if (mem_ctx == NULL) {
109                 PyErr_NoMemory();
110                 return NULL;
111         }
112
113         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
114         if (lp_ctx == NULL) {
115                 talloc_free(mem_ctx);
116                 return NULL;
117         }
118
119         session = system_session(lp_ctx);
120
121         talloc_free(mem_ctx);
122
123         return PyAuthSession_FromSession(session);
124 }
125
126
127 static PyObject *py_admin_session(PyObject *module, PyObject *args)
128 {
129         PyObject *py_lp_ctx;
130         const char *sid;
131         struct loadparm_context *lp_ctx = NULL;
132         struct auth_session_info *session;
133         struct dom_sid *domain_sid = NULL;
134         TALLOC_CTX *mem_ctx;
135
136         if (!PyArg_ParseTuple(args, "Os", &py_lp_ctx, &sid))
137                 return NULL;
138
139         mem_ctx = talloc_new(NULL);
140         if (mem_ctx == NULL) {
141                 PyErr_NoMemory();
142                 return NULL;
143         }
144
145         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
146         if (lp_ctx == NULL) {
147                 talloc_free(mem_ctx);
148                 return NULL;
149         }
150
151         domain_sid = dom_sid_parse_talloc(mem_ctx, sid);
152         if (domain_sid == NULL) {
153                 PyErr_Format(PyExc_RuntimeError, "Unable to parse sid %s", sid);
154                 talloc_free(mem_ctx);
155                 return NULL;
156         }
157         session = admin_session(NULL, lp_ctx, domain_sid);
158         talloc_free(mem_ctx);
159
160         return PyAuthSession_FromSession(session);
161 }
162
163 static PyObject *py_user_session(PyObject *module, PyObject *args, PyObject *kwargs)
164 {
165         NTSTATUS nt_status;
166         struct auth_session_info *session;
167         TALLOC_CTX *mem_ctx;
168         const char * const kwnames[] = { "ldb", "lp_ctx", "principal", "dn", "session_info_flags", NULL };
169         struct ldb_context *ldb_ctx;
170         PyObject *py_ldb = Py_None;
171         PyObject *py_dn = Py_None;
172         PyObject *py_lp_ctx = Py_None;
173         struct loadparm_context *lp_ctx = NULL;
174         struct ldb_dn *user_dn;
175         char *principal = NULL;
176         int session_info_flags = 0; /* This is an int, because that's
177                                  * what we need for the python
178                                  * PyArg_ParseTupleAndKeywords */
179
180         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OzOi",
181                                          discard_const_p(char *, kwnames),
182                                          &py_ldb, &py_lp_ctx, &principal, &py_dn, &session_info_flags)) {
183                 return NULL;
184         }
185
186         mem_ctx = talloc_new(NULL);
187         if (mem_ctx == NULL) {
188                 PyErr_NoMemory();
189                 return NULL;
190         }
191
192         ldb_ctx = pyldb_Ldb_AsLdbContext(py_ldb);
193         if (ldb_ctx == NULL) {
194                 talloc_free(mem_ctx);
195                 return NULL;
196         }
197
198         if (py_dn == Py_None) {
199                 user_dn = NULL;
200         } else {
201                 if (!pyldb_Object_AsDn(ldb_ctx, py_dn, ldb_ctx, &user_dn)) {
202                         talloc_free(mem_ctx);
203                         return NULL;
204                 }
205         }
206
207         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
208         if (lp_ctx == NULL) {
209                 talloc_free(mem_ctx);
210                 return NULL;
211         }
212
213         nt_status = authsam_get_session_info_principal(mem_ctx, lp_ctx, ldb_ctx, principal, user_dn,
214                                                        session_info_flags, &session);
215         if (!NT_STATUS_IS_OK(nt_status)) {
216                 talloc_free(mem_ctx);
217                 PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
218         }
219
220         talloc_steal(NULL, session);
221         talloc_free(mem_ctx);
222
223         return PyAuthSession_FromSession(session);
224 }
225
226 static PyObject *py_session_info_fill_unix(PyObject *module,
227                                            PyObject *args,
228                                            PyObject *kwargs)
229 {
230         NTSTATUS nt_status;
231         char *user_name = NULL;
232         struct loadparm_context *lp_ctx = NULL;
233         struct auth_session_info *session_info;
234         PyObject *py_lp_ctx = Py_None;
235         PyObject *py_session = Py_None;
236         TALLOC_CTX *frame;
237
238         const char * const kwnames[] = { "session_info",
239                                          "user_name",
240                                          "lp_ctx",
241                                          NULL };
242         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oz|O",
243                                          discard_const_p(char *, kwnames),
244                                          &py_session,
245                                          &user_name,
246                                          &py_lp_ctx)) {
247                 return NULL;
248         }
249
250         if (!py_check_dcerpc_type(py_session,
251                                   "samba.dcerpc.auth",
252                                   "session_info")) {
253                 return NULL;
254         }
255         session_info = pytalloc_get_type(py_session,
256                                          struct auth_session_info);
257         if (!session_info) {
258                 PyErr_Format(PyExc_TypeError,
259                              "Expected auth_session_info for session_info argument got %s",
260                              talloc_get_name(pytalloc_get_ptr(py_session)));
261                 return NULL;
262         }
263
264         frame = talloc_stackframe();
265         
266         lp_ctx = lpcfg_from_py_object(frame, py_lp_ctx);
267         if (lp_ctx == NULL) {
268                 TALLOC_FREE(frame);
269                 return NULL;
270         }
271
272         nt_status = auth_session_info_fill_unix(lp_ctx,
273                                                user_name,
274                                                session_info);
275         TALLOC_FREE(frame);
276         if (!NT_STATUS_IS_OK(nt_status)) {
277                 PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
278         }
279
280         Py_RETURN_NONE;
281 }
282
283
284 static const char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list, 
285                                         const char *paramname)
286 {
287         const char **ret;
288         Py_ssize_t i;
289         if (!PyList_Check(list)) {
290                 PyErr_Format(PyExc_TypeError, "%s is not a list", paramname);
291                 return NULL;
292         }
293         ret = talloc_array(NULL, const char *, PyList_Size(list)+1);
294         if (ret == NULL) {
295                 PyErr_NoMemory();
296                 return NULL;
297         }
298
299         for (i = 0; i < PyList_Size(list); i++) {
300                 const char *value;
301                 Py_ssize_t size;
302                 PyObject *item = PyList_GetItem(list, i);
303                 if (!(PyStr_Check(item) || PyUnicode_Check(item))) {
304                         PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
305                         return NULL;
306                 }
307                 value = PyStr_AsUTF8AndSize(item, &size);
308                 if (value == NULL) {
309                         talloc_free(ret);
310                         return NULL;
311                 }
312                 ret[i] = talloc_strndup(ret, value, size);
313         }
314         ret[i] = NULL;
315         return ret;
316 }
317
318 static PyObject *PyAuthContext_FromContext(struct auth4_context *auth_context)
319 {
320         return pytalloc_reference(&PyAuthContext, auth_context);
321 }
322
323 static PyObject *py_auth_context_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
324 {
325         PyObject *py_lp_ctx = Py_None;
326         PyObject *py_ldb = Py_None;
327         PyObject *py_auth_context = Py_None;
328         PyObject *py_methods = Py_None;
329         TALLOC_CTX *mem_ctx;
330         struct auth4_context *auth_context;
331         struct loadparm_context *lp_ctx;
332         struct tevent_context *ev;
333         struct ldb_context *ldb = NULL;
334         NTSTATUS nt_status;
335         const char **methods;
336
337         const char *const kwnames[] = {"lp_ctx", "ldb", "methods", NULL};
338
339         if (!PyArg_ParseTupleAndKeywords(args,
340                                          kwargs,
341                                          "|OOO",
342                                          discard_const_p(char *, kwnames),
343                                          &py_lp_ctx,
344                                          &py_ldb,
345                                          &py_methods))
346                 return NULL;
347
348         mem_ctx = talloc_new(NULL);
349         if (mem_ctx == NULL) {
350                 PyErr_NoMemory();
351                 return NULL;
352         }
353
354         if (py_ldb != Py_None) {
355                 ldb = pyldb_Ldb_AsLdbContext(py_ldb);
356                 if (ldb == NULL) {
357                         talloc_free(mem_ctx);
358                         return NULL;
359                 }
360         }
361
362         lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
363         if (lp_ctx == NULL) {
364                 PyErr_NoMemory();
365                 return NULL;
366         }
367
368         ev = s4_event_context_init(mem_ctx);
369         if (ev == NULL) {
370                 PyErr_NoMemory();
371                 return NULL;
372         }
373
374         if (py_methods == Py_None && py_ldb == Py_None) {
375                 nt_status = auth_context_create(
376                     mem_ctx, ev, NULL, lp_ctx, &auth_context);
377         } else {
378                 if (py_methods != Py_None) {
379                         methods = PyList_AsStringList(mem_ctx, py_methods, "methods");
380                         if (methods == NULL) {
381                                 talloc_free(mem_ctx);
382                                 return NULL;
383                         }
384                 } else {
385                         methods = auth_methods_from_lp(mem_ctx, lp_ctx);
386                 }
387                 nt_status = auth_context_create_methods(
388                     mem_ctx, methods, ev, NULL, lp_ctx, ldb, &auth_context);
389         }
390
391         if (!NT_STATUS_IS_OK(nt_status)) {
392                 talloc_free(mem_ctx);
393                 PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
394         }
395
396         if (!talloc_reference(auth_context, lp_ctx)) {
397                 talloc_free(mem_ctx);
398                 PyErr_NoMemory();
399                 return NULL;
400         }
401
402         if (!talloc_reference(auth_context, ev)) {
403                 talloc_free(mem_ctx);
404                 PyErr_NoMemory();
405                 return NULL;
406         }
407
408         py_auth_context = PyAuthContext_FromContext(auth_context);
409
410         talloc_free(mem_ctx);
411
412         return py_auth_context;
413 }
414
415 static PyTypeObject PyAuthContext = {
416         .tp_name = "AuthContext",
417         .tp_flags = Py_TPFLAGS_DEFAULT,
418         .tp_new = py_auth_context_new,
419 };
420
421 static PyMethodDef py_auth_methods[] = {
422         { "system_session", (PyCFunction)py_system_session, METH_VARARGS, NULL },
423         { "admin_session", (PyCFunction)py_admin_session, METH_VARARGS, NULL },
424         { "user_session", (PyCFunction)py_user_session, METH_VARARGS|METH_KEYWORDS, NULL },
425         { "session_info_fill_unix",
426           (PyCFunction)py_session_info_fill_unix,
427           METH_VARARGS|METH_KEYWORDS,
428           NULL },
429         { "copy_session_info",
430           (PyCFunction)py_copy_session_info,
431           METH_VARARGS|METH_KEYWORDS,
432           NULL },
433         { NULL },
434 };
435
436 static struct PyModuleDef moduledef = {
437         PyModuleDef_HEAD_INIT,
438         .m_name = "auth",
439         .m_doc = "Authentication and authorization support.",
440         .m_size = -1,
441         .m_methods = py_auth_methods,
442 };
443
444 MODULE_INIT_FUNC(auth)
445 {
446         PyObject *m;
447
448         if (pytalloc_BaseObject_PyType_Ready(&PyAuthContext) < 0)
449                 return NULL;
450
451         m = PyModule_Create(&moduledef);
452         if (m == NULL)
453                 return NULL;
454
455         Py_INCREF(&PyAuthContext);
456         PyModule_AddObject(m, "AuthContext", (PyObject *)&PyAuthContext);
457
458 #define ADD_FLAG(val)  PyModule_AddIntConstant(m, #val, val)
459         ADD_FLAG(AUTH_SESSION_INFO_DEFAULT_GROUPS);
460         ADD_FLAG(AUTH_SESSION_INFO_AUTHENTICATED);
461         ADD_FLAG(AUTH_SESSION_INFO_SIMPLE_PRIVILEGES);
462         ADD_FLAG(AUTH_SESSION_INFO_NTLM);
463
464         return m;
465 }