a088f9c4db6b9f16aa5d6fb52bd056f15e501604
[idra/samba.git] / source4 / auth / gensec / pygensec.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <Python.h>
20 #include "includes.h"
21 #include "param/pyparam.h"
22 #include "auth/gensec/gensec.h"
23 #include "auth/credentials/pycredentials.h"
24 #include "libcli/util/pyerrors.h"
25 #include "scripting/python/modules.h"
26 #include "lib/talloc/pytalloc.h"
27 #include <tevent.h>
28 #include "librpc/rpc/pyrpc_util.h"
29
30 static PyObject *py_get_name_by_authtype(PyObject *self, PyObject *args)
31 {
32         int type;
33         const char *name;
34         struct gensec_security *security;
35
36         if (!PyArg_ParseTuple(args, "i", &type))
37                 return NULL;
38
39         security = pytalloc_get_type(self, struct gensec_security);
40
41         name = gensec_get_name_by_authtype(security, type);
42         if (name == NULL)
43                 Py_RETURN_NONE;
44
45         return PyString_FromString(name);
46 }
47
48 static struct gensec_settings *settings_from_object(TALLOC_CTX *mem_ctx, PyObject *object)
49 {
50         struct gensec_settings *s;
51         PyObject *py_hostname, *py_lp_ctx;
52
53         if (!PyDict_Check(object)) {
54                 PyErr_SetString(PyExc_ValueError, "settings should be a dictionary");
55                 return NULL;
56         }
57
58         s = talloc_zero(mem_ctx, struct gensec_settings);
59         if (!s) return NULL;
60
61         py_hostname = PyDict_GetItemString(object, "target_hostname");
62         if (!py_hostname) {
63                 PyErr_SetString(PyExc_ValueError, "settings.target_hostname not found");
64                 return NULL;
65         }
66
67         py_lp_ctx = PyDict_GetItemString(object, "lp_ctx");
68         if (!py_lp_ctx) {
69                 PyErr_SetString(PyExc_ValueError, "settings.lp_ctx not found");
70                 return NULL;
71         }
72
73         s->target_hostname = PyString_AsString(py_hostname);
74         s->lp_ctx = lpcfg_from_py_object(s, py_lp_ctx);
75         return s;
76 }
77
78 static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyObject *kwargs)
79 {
80         NTSTATUS status;
81         pytalloc_Object *self;
82         struct gensec_settings *settings;
83         const char *kwnames[] = { "settings", NULL };
84         PyObject *py_settings;
85         struct tevent_context *ev;
86         struct gensec_security *gensec;
87
88         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", discard_const_p(char *, kwnames), &py_settings))
89                 return NULL;
90
91         self = (pytalloc_Object*)type->tp_alloc(type, 0);
92         if (self == NULL) {
93                 PyErr_NoMemory();
94                 return NULL;
95         }
96         self->talloc_ctx = talloc_new(NULL);
97         if (self->talloc_ctx == NULL) {
98                 PyErr_NoMemory();
99                 return NULL;
100         }
101
102         if (py_settings != Py_None) {
103                 settings = settings_from_object(self->talloc_ctx, py_settings);
104                 if (settings == NULL) {
105                         PyObject_DEL(self);
106                         return NULL;
107                 }
108         } else {
109                 settings = talloc_zero(self->talloc_ctx, struct gensec_settings);
110                 if (settings == NULL) {
111                         PyObject_DEL(self);
112                         return NULL;
113                 }
114
115                 settings->lp_ctx = loadparm_init_global(true);
116                 if (settings->lp_ctx == NULL) {
117                         PyErr_NoMemory();
118                         PyObject_DEL(self);
119                         return NULL;
120                 }
121         }
122
123         ev = tevent_context_init(self->talloc_ctx);
124         if (ev == NULL) {
125                 PyErr_NoMemory();
126                 PyObject_Del(self);
127                 return NULL;
128         }
129
130         status = gensec_init();
131         if (!NT_STATUS_IS_OK(status)) {
132                 PyErr_SetNTSTATUS(status);
133                 PyObject_DEL(self);
134                 return NULL;
135         }
136
137         status = gensec_client_start(self->talloc_ctx, &gensec, ev, settings);
138         if (!NT_STATUS_IS_OK(status)) {
139                 PyErr_SetNTSTATUS(status);
140                 PyObject_DEL(self);
141                 return NULL;
142         }
143
144         self->ptr = gensec;
145
146         return (PyObject *)self;
147 }
148
149 static PyObject *py_gensec_start_server(PyTypeObject *type, PyObject *args, PyObject *kwargs)
150 {
151         NTSTATUS status;
152         pytalloc_Object *self;
153         struct gensec_settings *settings = NULL;
154         const char *kwnames[] = { "settings", "auth_context", NULL };
155         PyObject *py_settings = Py_None;
156         PyObject *py_auth_context = Py_None;
157         struct tevent_context *ev;
158         struct gensec_security *gensec;
159         struct auth4_context *auth_context = NULL;
160
161         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", discard_const_p(char *, kwnames), &py_settings, &py_auth_context))
162                 return NULL;
163
164         self = (pytalloc_Object*)type->tp_alloc(type, 0);
165         if (self == NULL) {
166                 PyErr_NoMemory();
167                 return NULL;
168         }
169         self->talloc_ctx = talloc_new(NULL);
170         if (self->talloc_ctx == NULL) {
171                 PyErr_NoMemory();
172                 return NULL;
173         }
174
175         if (py_settings != Py_None) {
176                 settings = settings_from_object(self->talloc_ctx, py_settings);
177                 if (settings == NULL) {
178                         PyObject_DEL(self);
179                         return NULL;
180                 }
181         } else {
182                 settings = talloc_zero(self->talloc_ctx, struct gensec_settings);
183                 if (settings == NULL) {
184                         PyObject_DEL(self);
185                         return NULL;
186                 }
187
188                 settings->lp_ctx = loadparm_init_global(true);
189                 if (settings->lp_ctx == NULL) {
190                         PyErr_NoMemory();
191                         PyObject_DEL(self);
192                         return NULL;
193                 }
194         }
195
196         ev = tevent_context_init(self->talloc_ctx);
197         if (ev == NULL) {
198                 PyErr_NoMemory();
199                 PyObject_Del(self);
200                 return NULL;
201         }
202
203         if (py_auth_context != Py_None) {
204                 auth_context = pytalloc_get_type(py_auth_context, struct auth4_context);
205                 if (!auth_context) {
206                         PyErr_Format(PyExc_TypeError,
207                                      "Expected auth.AuthContext for auth_context argument, got %s",
208                                      talloc_get_name(pytalloc_get_ptr(py_auth_context)));
209                         return NULL;
210                 }
211         }
212
213         status = gensec_init();
214         if (!NT_STATUS_IS_OK(status)) {
215                 PyErr_SetNTSTATUS(status);
216                 PyObject_DEL(self);
217                 return NULL;
218         }
219
220         status = gensec_server_start(self->talloc_ctx, ev, settings, auth_context, &gensec);
221         if (!NT_STATUS_IS_OK(status)) {
222                 PyErr_SetNTSTATUS(status);
223                 PyObject_DEL(self);
224                 return NULL;
225         }
226
227         self->ptr = gensec;
228
229         return (PyObject *)self;
230 }
231
232 static PyObject *py_gensec_set_credentials(PyObject *self, PyObject *args)
233 {
234         PyObject *py_creds = Py_None;
235         struct cli_credentials *creds;
236         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
237         NTSTATUS status;
238
239         if (!PyArg_ParseTuple(args, "O", &py_creds))
240                 return NULL;
241
242         creds = PyCredentials_AsCliCredentials(py_creds);
243         if (!creds) {
244                 PyErr_Format(PyExc_TypeError,
245                              "Expected samba.credentaials for credentials argument got  %s",
246                              talloc_get_name(pytalloc_get_ptr(py_creds)));
247         }
248
249         status = gensec_set_credentials(security, creds);
250         if (!NT_STATUS_IS_OK(status)) {
251                 PyErr_SetNTSTATUS(status);
252                 return NULL;
253         }
254
255         Py_RETURN_NONE;
256 }
257
258 static PyObject *py_gensec_session_info(PyObject *self)
259 {
260         TALLOC_CTX *mem_ctx;
261         NTSTATUS status;
262         PyObject *py_session_info;
263         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
264         struct auth_session_info *info;
265         if (security->ops == NULL) {
266                 PyErr_SetString(PyExc_RuntimeError, "no mechanism selected");
267                 return NULL;
268         }
269         mem_ctx = talloc_new(NULL);
270
271         status = gensec_session_info(security, mem_ctx, &info);
272         if (NT_STATUS_IS_ERR(status)) {
273                 PyErr_SetNTSTATUS(status);
274                 return NULL;
275         }
276
277         py_session_info = py_return_ndr_struct("samba.dcerpc.auth", "session_info",
278                                                  info, info);
279         talloc_free(mem_ctx);
280         return py_session_info;
281 }
282
283 static PyObject *py_gensec_start_mech_by_name(PyObject *self, PyObject *args)
284 {
285         char *name;
286         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
287         NTSTATUS status;
288
289         if (!PyArg_ParseTuple(args, "s", &name))
290                 return NULL;
291
292         status = gensec_start_mech_by_name(security, name);
293         if (!NT_STATUS_IS_OK(status)) {
294                 PyErr_SetNTSTATUS(status);
295                 return NULL;
296         }
297
298         Py_RETURN_NONE;
299 }
300
301 static PyObject *py_gensec_start_mech_by_sasl_name(PyObject *self, PyObject *args)
302 {
303         char *sasl_name;
304         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
305         NTSTATUS status;
306
307         if (!PyArg_ParseTuple(args, "s", &sasl_name))
308                 return NULL;
309
310         status = gensec_start_mech_by_sasl_name(security, sasl_name);
311         if (!NT_STATUS_IS_OK(status)) {
312                 PyErr_SetNTSTATUS(status);
313                 return NULL;
314         }
315
316         Py_RETURN_NONE;
317 }
318
319 static PyObject *py_gensec_start_mech_by_authtype(PyObject *self, PyObject *args)
320 {
321         int authtype, level;
322         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
323         NTSTATUS status;
324         if (!PyArg_ParseTuple(args, "ii", &authtype, &level))
325                 return NULL;
326
327         status = gensec_start_mech_by_authtype(security, authtype, level);
328         if (!NT_STATUS_IS_OK(status)) {
329                 PyErr_SetNTSTATUS(status);
330                 return NULL;
331         }
332
333         Py_RETURN_NONE;
334 }
335
336 static PyObject *py_gensec_want_feature(PyObject *self, PyObject *args)
337 {
338         int feature;
339         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
340         /* This is i (and declared as an int above) by design, as they are handled as an integer in python */
341         if (!PyArg_ParseTuple(args, "i", &feature))
342                 return NULL;
343
344         gensec_want_feature(security, feature);
345
346         Py_RETURN_NONE;
347 }
348
349 static PyObject *py_gensec_have_feature(PyObject *self, PyObject *args)
350 {
351         int feature;
352         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
353         /* This is i (and declared as an int above) by design, as they are handled as an integer in python */
354         if (!PyArg_ParseTuple(args, "i", &feature))
355                 return NULL;
356
357         if (gensec_have_feature(security, feature)) {
358                 return Py_True;
359         } 
360         return Py_False;
361 }
362
363 static PyObject *py_gensec_update(PyObject *self, PyObject *args)
364 {
365         NTSTATUS status;
366         TALLOC_CTX *mem_ctx;
367         DATA_BLOB in, out;
368         PyObject *ret, *py_in;
369         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
370         PyObject *finished_processing;
371
372         if (!PyArg_ParseTuple(args, "O", &py_in))
373                 return NULL;
374
375         mem_ctx = talloc_new(NULL);
376
377         if (!PyString_Check(py_in)) {
378                 PyErr_Format(PyExc_TypeError, "expected a string");
379                 return NULL;
380         }
381
382         in.data = (uint8_t *)PyString_AsString(py_in);
383         in.length = PyString_Size(py_in);
384
385         status = gensec_update(security, mem_ctx, in, &out);
386
387         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)
388             && !NT_STATUS_IS_OK(status)) {
389                 PyErr_SetNTSTATUS(status);
390                 talloc_free(mem_ctx);
391                 return NULL;
392         }
393         ret = PyString_FromStringAndSize((const char *)out.data, out.length);
394         talloc_free(mem_ctx);
395
396         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
397                 finished_processing = Py_False;
398         } else {
399                 finished_processing = Py_True;
400         }
401
402         return PyTuple_Pack(2, finished_processing, ret);
403 }
404
405 static PyObject *py_gensec_wrap(PyObject *self, PyObject *args)
406 {
407         NTSTATUS status;
408
409         TALLOC_CTX *mem_ctx;
410         DATA_BLOB in, out;
411         PyObject *ret, *py_in;
412         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
413
414         if (!PyArg_ParseTuple(args, "O", &py_in))
415                 return NULL;
416
417         mem_ctx = talloc_new(NULL);
418
419         if (!PyString_Check(py_in)) {
420                 PyErr_Format(PyExc_TypeError, "expected a string");
421                 return NULL;
422         }
423         in.data = (uint8_t *)PyString_AsString(py_in);
424         in.length = PyString_Size(py_in);
425
426         status = gensec_wrap(security, mem_ctx, &in, &out);
427
428         if (!NT_STATUS_IS_OK(status)) {
429                 PyErr_SetNTSTATUS(status);
430                 talloc_free(mem_ctx);
431                 return NULL;
432         }
433
434         ret = PyString_FromStringAndSize((const char *)out.data, out.length);
435         talloc_free(mem_ctx);
436         return ret;
437 }
438
439 static PyObject *py_gensec_unwrap(PyObject *self, PyObject *args)
440 {
441         NTSTATUS status;
442
443         TALLOC_CTX *mem_ctx;
444         DATA_BLOB in, out;
445         PyObject *ret, *py_in;
446         struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
447
448         if (!PyArg_ParseTuple(args, "O", &py_in))
449                 return NULL;
450
451         mem_ctx = talloc_new(NULL);
452
453         if (!PyString_Check(py_in)) {
454                 PyErr_Format(PyExc_TypeError, "expected a string");
455                 return NULL;
456         }
457
458         in.data = (uint8_t *)PyString_AsString(py_in);
459         in.length = PyString_Size(py_in);
460
461         status = gensec_unwrap(security, mem_ctx, &in, &out);
462
463         if (!NT_STATUS_IS_OK(status)) {
464                 PyErr_SetNTSTATUS(status);
465                 talloc_free(mem_ctx);
466                 return NULL;
467         }
468
469         ret = PyString_FromStringAndSize((const char *)out.data, out.length);
470         talloc_free(mem_ctx);
471         return ret;
472 }
473
474 static PyMethodDef py_gensec_security_methods[] = {
475         { "start_client", (PyCFunction)py_gensec_start_client, METH_VARARGS|METH_KEYWORDS|METH_CLASS, 
476                 "S.start_client(settings) -> gensec" },
477         { "start_server", (PyCFunction)py_gensec_start_server, METH_VARARGS|METH_KEYWORDS|METH_CLASS,
478                 "S.start_server(auth_ctx, settings) -> gensec" },
479         { "set_credentials", (PyCFunction)py_gensec_set_credentials, METH_VARARGS, 
480                 "S.start_client(credentials)" },
481         { "session_info", (PyCFunction)py_gensec_session_info, METH_NOARGS,
482                 "S.session_info() -> info" },
483         { "start_mech_by_name", (PyCFunction)py_gensec_start_mech_by_name, METH_VARARGS,
484         "S.start_mech_by_name(name)" },
485         { "start_mech_by_sasl_name", (PyCFunction)py_gensec_start_mech_by_sasl_name, METH_VARARGS,
486         "S.start_mech_by_sasl_name(name)" },
487         { "start_mech_by_authtype", (PyCFunction)py_gensec_start_mech_by_authtype, METH_VARARGS, "S.start_mech_by_authtype(authtype, level)" },
488         { "get_name_by_authtype", (PyCFunction)py_get_name_by_authtype, METH_VARARGS,
489                 "S.get_name_by_authtype(authtype) -> name\nLookup an auth type." },
490         { "want_feature", (PyCFunction)py_gensec_want_feature, METH_VARARGS,
491           "S.want_feature(feature)\n Request that GENSEC negotiate a particular feature." },
492         { "have_feature", (PyCFunction)py_gensec_have_feature, METH_VARARGS,
493           "S.have_feature()\n Return True if GENSEC negotiated a particular feature." },
494         { "update",  (PyCFunction)py_gensec_update, METH_VARARGS,
495                 "S.update(blob_in) -> (finished, blob_out)\nPerform one step in a GENSEC dance.  Repeat with new packets until finished is true or exception." },
496         { "wrap",  (PyCFunction)py_gensec_wrap, METH_VARARGS,
497                 "S.wrap(blob_in) -> blob_out\nPackage one clear packet into a wrapped GENSEC packet." },
498         { "unwrap",  (PyCFunction)py_gensec_unwrap, METH_VARARGS,
499                 "S.unwrap(blob_in) -> blob_out\nPerform one wrapped GENSEC packet into a clear packet." },
500
501         { NULL }
502 };
503
504 static PyTypeObject Py_Security = {
505         .tp_name = "gensec.Security",
506         .tp_flags = Py_TPFLAGS_DEFAULT,
507         .tp_methods = py_gensec_security_methods,
508         .tp_basicsize = sizeof(pytalloc_Object),
509 };
510
511 void initgensec(void);
512 void initgensec(void)
513 {
514         PyObject *m;
515
516         Py_Security.tp_base = pytalloc_GetObjectType();
517         if (Py_Security.tp_base == NULL)
518                 return;
519
520         if (PyType_Ready(&Py_Security) < 0)
521                 return;
522
523         m = Py_InitModule3("gensec", NULL, "Generic Security Interface.");
524         if (m == NULL)
525                 return;
526
527         PyModule_AddObject(m, "FEATURE_SESSION_KEY",     PyInt_FromLong(GENSEC_FEATURE_SESSION_KEY));
528         PyModule_AddObject(m, "FEATURE_SIGN",            PyInt_FromLong(GENSEC_FEATURE_SIGN));
529         PyModule_AddObject(m, "FEATURE_SEAL",            PyInt_FromLong(GENSEC_FEATURE_SEAL));
530         PyModule_AddObject(m, "FEATURE_DCE_STYLE",       PyInt_FromLong(GENSEC_FEATURE_DCE_STYLE));
531         PyModule_AddObject(m, "FEATURE_ASYNC_REPLIES",   PyInt_FromLong(GENSEC_FEATURE_ASYNC_REPLIES));
532         PyModule_AddObject(m, "FEATURE_DATAGRAM_MODE",   PyInt_FromLong(GENSEC_FEATURE_DATAGRAM_MODE));
533         PyModule_AddObject(m, "FEATURE_SIGN_PKT_HEADER", PyInt_FromLong(GENSEC_FEATURE_SIGN_PKT_HEADER));
534         PyModule_AddObject(m, "FEATURE_NEW_SPNEGO",      PyInt_FromLong(GENSEC_FEATURE_NEW_SPNEGO));
535
536         Py_INCREF(&Py_Security);
537         PyModule_AddObject(m, "Security", (PyObject *)&Py_Security);
538 }