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