Use public pytalloc header file.
[idra/samba.git] / source4 / auth / gensec / pygensec.c
index 21acff81362af0edfb9d68ba6d20df8a4d57c5c0..d7cbea6f574d9850b453bc230480899480937182 100644 (file)
 #include "includes.h"
 #include "param/pyparam.h"
 #include "auth/gensec/gensec.h"
+#include "auth/credentials/pycredentials.h"
 #include "libcli/util/pyerrors.h"
 #include "scripting/python/modules.h"
-#include "pytalloc.h"
+#include <pytalloc.h>
 #include <tevent.h>
+#include "librpc/rpc/pyrpc_util.h"
 
 static PyObject *py_get_name_by_authtype(PyObject *self, PyObject *args)
 {
@@ -34,7 +36,7 @@ static PyObject *py_get_name_by_authtype(PyObject *self, PyObject *args)
        if (!PyArg_ParseTuple(args, "i", &type))
                return NULL;
 
-       security = (struct gensec_security *)py_talloc_get_ptr(self);
+       security = pytalloc_get_type(self, struct gensec_security);
 
        name = gensec_get_name_by_authtype(security, type);
        if (name == NULL)
@@ -67,26 +69,26 @@ static struct gensec_settings *settings_from_object(TALLOC_CTX *mem_ctx, PyObjec
                PyErr_SetString(PyExc_ValueError, "settings.lp_ctx not found");
                return NULL;
        }
-       
+
        s->target_hostname = PyString_AsString(py_hostname);
-       s->lp_ctx = lp_from_py_object(py_lp_ctx);
-       s->iconv_convenience = py_iconv_convenience(s);
+       s->lp_ctx = lpcfg_from_py_object(s, py_lp_ctx);
        return s;
 }
 
 static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
        NTSTATUS status;
-       py_talloc_Object *self;
+       pytalloc_Object *self;
        struct gensec_settings *settings;
        const char *kwnames[] = { "settings", NULL };
        PyObject *py_settings;
        struct tevent_context *ev;
+       struct gensec_security *gensec;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", discard_const_p(char *, kwnames), &py_settings))
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", discard_const_p(char *, kwnames), &py_settings))
                return NULL;
 
-       self = (py_talloc_Object*)type->tp_alloc(type, 0);
+       self = (pytalloc_Object*)type->tp_alloc(type, 0);
        if (self == NULL) {
                PyErr_NoMemory();
                return NULL;
@@ -97,12 +99,100 @@ static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyOb
                return NULL;
        }
 
-       settings = settings_from_object(self->talloc_ctx, py_settings);
-       if (settings == NULL) {
+       if (py_settings != Py_None) {
+               settings = settings_from_object(self->talloc_ctx, py_settings);
+               if (settings == NULL) {
+                       PyObject_DEL(self);
+                       return NULL;
+               }
+       } else {
+               settings = talloc_zero(self->talloc_ctx, struct gensec_settings);
+               if (settings == NULL) {
+                       PyObject_DEL(self);
+                       return NULL;
+               }
+
+               settings->lp_ctx = loadparm_init_global(true);
+               if (settings->lp_ctx == NULL) {
+                       PyErr_NoMemory();
+                       PyObject_DEL(self);
+                       return NULL;
+               }
+       }
+
+       ev = tevent_context_init(self->talloc_ctx);
+       if (ev == NULL) {
+               PyErr_NoMemory();
+               PyObject_Del(self);
+               return NULL;
+       }
+
+       status = gensec_init();
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
                PyObject_DEL(self);
                return NULL;
        }
-       
+
+       status = gensec_client_start(self->talloc_ctx, &gensec, ev, settings);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               PyObject_DEL(self);
+               return NULL;
+       }
+
+       self->ptr = gensec;
+
+       return (PyObject *)self;
+}
+
+static PyObject *py_gensec_start_server(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+       NTSTATUS status;
+       pytalloc_Object *self;
+       struct gensec_settings *settings = NULL;
+       const char *kwnames[] = { "settings", "auth_context", NULL };
+       PyObject *py_settings = Py_None;
+       PyObject *py_auth_context = Py_None;
+       struct tevent_context *ev;
+       struct gensec_security *gensec;
+       struct auth4_context *auth_context = NULL;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", discard_const_p(char *, kwnames), &py_settings, &py_auth_context))
+               return NULL;
+
+       self = (pytalloc_Object*)type->tp_alloc(type, 0);
+       if (self == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
+       self->talloc_ctx = talloc_new(NULL);
+       if (self->talloc_ctx == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
+
+       if (py_settings != Py_None) {
+               settings = settings_from_object(self->talloc_ctx, py_settings);
+               if (settings == NULL) {
+                       PyObject_DEL(self);
+                       return NULL;
+               }
+       } else {
+               settings = talloc_zero(self->talloc_ctx, struct gensec_settings);
+               if (settings == NULL) {
+                       PyObject_DEL(self);
+                       return NULL;
+               }
+
+               settings->lp_ctx = loadparm_init_global(true);
+               if (settings->lp_ctx == NULL) {
+                       PyErr_NoMemory();
+                       PyObject_DEL(self);
+                       return NULL;
+               }
+       }
+
        ev = tevent_context_init(self->talloc_ctx);
        if (ev == NULL) {
                PyErr_NoMemory();
@@ -110,66 +200,323 @@ static PyObject *py_gensec_start_client(PyTypeObject *type, PyObject *args, PyOb
                return NULL;
        }
 
-       status = gensec_init(settings->lp_ctx);
+       if (py_auth_context != Py_None) {
+               auth_context = pytalloc_get_type(py_auth_context, struct auth4_context);
+               if (!auth_context) {
+                       PyErr_Format(PyExc_TypeError,
+                                    "Expected auth.AuthContext for auth_context argument, got %s",
+                                    talloc_get_name(pytalloc_get_ptr(py_auth_context)));
+                       return NULL;
+               }
+       }
+
+       status = gensec_init();
        if (!NT_STATUS_IS_OK(status)) {
                PyErr_SetNTSTATUS(status);
                PyObject_DEL(self);
                return NULL;
        }
 
-       status = gensec_client_start(self->talloc_ctx, 
-               (struct gensec_security **)&self->ptr, ev, settings);
+       status = gensec_server_start(self->talloc_ctx, ev, settings, auth_context, &gensec);
        if (!NT_STATUS_IS_OK(status)) {
                PyErr_SetNTSTATUS(status);
                PyObject_DEL(self);
                return NULL;
        }
+
+       self->ptr = gensec;
+
        return (PyObject *)self;
 }
 
+static PyObject *py_gensec_set_credentials(PyObject *self, PyObject *args)
+{
+       PyObject *py_creds = Py_None;
+       struct cli_credentials *creds;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       NTSTATUS status;
+
+       if (!PyArg_ParseTuple(args, "O", &py_creds))
+               return NULL;
+
+       creds = PyCredentials_AsCliCredentials(py_creds);
+       if (!creds) {
+               PyErr_Format(PyExc_TypeError,
+                            "Expected samba.credentaials for credentials argument got  %s",
+                            talloc_get_name(pytalloc_get_ptr(py_creds)));
+       }
+
+       status = gensec_set_credentials(security, creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
 static PyObject *py_gensec_session_info(PyObject *self)
 {
+       TALLOC_CTX *mem_ctx;
        NTSTATUS status;
-       struct gensec_security *security = (struct gensec_security *)py_talloc_get_ptr(self);
+       PyObject *py_session_info;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
        struct auth_session_info *info;
        if (security->ops == NULL) {
-               PyErr_SetString(PyExc_ValueError, "gensec not fully initialised - ask Andrew");
+               PyErr_SetString(PyExc_RuntimeError, "no mechanism selected");
                return NULL;
        }
-       status = gensec_session_info(security, &info);
+       mem_ctx = talloc_new(NULL);
+
+       status = gensec_session_info(security, mem_ctx, &info);
        if (NT_STATUS_IS_ERR(status)) {
                PyErr_SetNTSTATUS(status);
                return NULL;
        }
 
-       /* FIXME */
+       py_session_info = py_return_ndr_struct("samba.dcerpc.auth", "session_info",
+                                                info, info);
+       talloc_free(mem_ctx);
+       return py_session_info;
+}
+
+static PyObject *py_gensec_start_mech_by_name(PyObject *self, PyObject *args)
+{
+       char *name;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       NTSTATUS status;
+
+       if (!PyArg_ParseTuple(args, "s", &name))
+               return NULL;
+
+       status = gensec_start_mech_by_name(security, name);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               return NULL;
+       }
+
        Py_RETURN_NONE;
 }
 
+static PyObject *py_gensec_start_mech_by_sasl_name(PyObject *self, PyObject *args)
+{
+       char *sasl_name;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       NTSTATUS status;
+
+       if (!PyArg_ParseTuple(args, "s", &sasl_name))
+               return NULL;
+
+       status = gensec_start_mech_by_sasl_name(security, sasl_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_gensec_start_mech_by_authtype(PyObject *self, PyObject *args)
+{
+       int authtype, level;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       NTSTATUS status;
+       if (!PyArg_ParseTuple(args, "ii", &authtype, &level))
+               return NULL;
+
+       status = gensec_start_mech_by_authtype(security, authtype, level);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_gensec_want_feature(PyObject *self, PyObject *args)
+{
+       int feature;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       /* This is i (and declared as an int above) by design, as they are handled as an integer in python */
+       if (!PyArg_ParseTuple(args, "i", &feature))
+               return NULL;
+
+       gensec_want_feature(security, feature);
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_gensec_have_feature(PyObject *self, PyObject *args)
+{
+       int feature;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       /* This is i (and declared as an int above) by design, as they are handled as an integer in python */
+       if (!PyArg_ParseTuple(args, "i", &feature))
+               return NULL;
+
+       if (gensec_have_feature(security, feature)) {
+               return Py_True;
+       } 
+       return Py_False;
+}
+
+static PyObject *py_gensec_update(PyObject *self, PyObject *args)
+{
+       NTSTATUS status;
+       TALLOC_CTX *mem_ctx;
+       DATA_BLOB in, out;
+       PyObject *ret, *py_in;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+       PyObject *finished_processing;
+
+       if (!PyArg_ParseTuple(args, "O", &py_in))
+               return NULL;
+
+       mem_ctx = talloc_new(NULL);
+
+       if (!PyString_Check(py_in)) {
+               PyErr_Format(PyExc_TypeError, "expected a string");
+               return NULL;
+       }
+
+       in.data = (uint8_t *)PyString_AsString(py_in);
+       in.length = PyString_Size(py_in);
+
+       status = gensec_update(security, mem_ctx, in, &out);
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)
+           && !NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               talloc_free(mem_ctx);
+               return NULL;
+       }
+       ret = PyString_FromStringAndSize((const char *)out.data, out.length);
+       talloc_free(mem_ctx);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               finished_processing = Py_False;
+       } else {
+               finished_processing = Py_True;
+       }
+
+       return PyTuple_Pack(2, finished_processing, ret);
+}
+
+static PyObject *py_gensec_wrap(PyObject *self, PyObject *args)
+{
+       NTSTATUS status;
+
+       TALLOC_CTX *mem_ctx;
+       DATA_BLOB in, out;
+       PyObject *ret, *py_in;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+
+       if (!PyArg_ParseTuple(args, "O", &py_in))
+               return NULL;
+
+       mem_ctx = talloc_new(NULL);
+
+       if (!PyString_Check(py_in)) {
+               PyErr_Format(PyExc_TypeError, "expected a string");
+               return NULL;
+       }
+       in.data = (uint8_t *)PyString_AsString(py_in);
+       in.length = PyString_Size(py_in);
+
+       status = gensec_wrap(security, mem_ctx, &in, &out);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               talloc_free(mem_ctx);
+               return NULL;
+       }
+
+       ret = PyString_FromStringAndSize((const char *)out.data, out.length);
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+static PyObject *py_gensec_unwrap(PyObject *self, PyObject *args)
+{
+       NTSTATUS status;
+
+       TALLOC_CTX *mem_ctx;
+       DATA_BLOB in, out;
+       PyObject *ret, *py_in;
+       struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+
+       if (!PyArg_ParseTuple(args, "O", &py_in))
+               return NULL;
+
+       mem_ctx = talloc_new(NULL);
+
+       if (!PyString_Check(py_in)) {
+               PyErr_Format(PyExc_TypeError, "expected a string");
+               return NULL;
+       }
+
+       in.data = (uint8_t *)PyString_AsString(py_in);
+       in.length = PyString_Size(py_in);
+
+       status = gensec_unwrap(security, mem_ctx, &in, &out);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               talloc_free(mem_ctx);
+               return NULL;
+       }
+
+       ret = PyString_FromStringAndSize((const char *)out.data, out.length);
+       talloc_free(mem_ctx);
+       return ret;
+}
+
 static PyMethodDef py_gensec_security_methods[] = {
        { "start_client", (PyCFunction)py_gensec_start_client, METH_VARARGS|METH_KEYWORDS|METH_CLASS, 
                "S.start_client(settings) -> gensec" },
-/*     { "start_server", (PyCFunction)py_gensec_start_server, METH_VARARGS|METH_KEYWORDS|METH_CLASS, 
-               "S.start_server(auth_ctx, settings) -> gensec" },*/
+       { "start_server", (PyCFunction)py_gensec_start_server, METH_VARARGS|METH_KEYWORDS|METH_CLASS,
+               "S.start_server(auth_ctx, settings) -> gensec" },
+       { "set_credentials", (PyCFunction)py_gensec_set_credentials, METH_VARARGS, 
+               "S.start_client(credentials)" },
        { "session_info", (PyCFunction)py_gensec_session_info, METH_NOARGS,
-               "S.session_info() -> info" },
+               "S.session_info() -> info" },
+       { "start_mech_by_name", (PyCFunction)py_gensec_start_mech_by_name, METH_VARARGS,
+        "S.start_mech_by_name(name)" },
+       { "start_mech_by_sasl_name", (PyCFunction)py_gensec_start_mech_by_sasl_name, METH_VARARGS,
+        "S.start_mech_by_sasl_name(name)" },
+       { "start_mech_by_authtype", (PyCFunction)py_gensec_start_mech_by_authtype, METH_VARARGS, "S.start_mech_by_authtype(authtype, level)" },
        { "get_name_by_authtype", (PyCFunction)py_get_name_by_authtype, METH_VARARGS,
                "S.get_name_by_authtype(authtype) -> name\nLookup an auth type." },
+       { "want_feature", (PyCFunction)py_gensec_want_feature, METH_VARARGS,
+         "S.want_feature(feature)\n Request that GENSEC negotiate a particular feature." },
+       { "have_feature", (PyCFunction)py_gensec_have_feature, METH_VARARGS,
+         "S.have_feature()\n Return True if GENSEC negotiated a particular feature." },
+       { "update",  (PyCFunction)py_gensec_update, METH_VARARGS,
+               "S.update(blob_in) -> (finished, blob_out)\nPerform one step in a GENSEC dance.  Repeat with new packets until finished is true or exception." },
+       { "wrap",  (PyCFunction)py_gensec_wrap, METH_VARARGS,
+               "S.wrap(blob_in) -> blob_out\nPackage one clear packet into a wrapped GENSEC packet." },
+       { "unwrap",  (PyCFunction)py_gensec_unwrap, METH_VARARGS,
+               "S.unwrap(blob_in) -> blob_out\nPerform one wrapped GENSEC packet into a clear packet." },
+
        { NULL }
 };
 
 static PyTypeObject Py_Security = {
-       .tp_name = "Security",
+       .tp_name = "gensec.Security",
        .tp_flags = Py_TPFLAGS_DEFAULT,
        .tp_methods = py_gensec_security_methods,
-       .tp_basicsize = sizeof(py_talloc_Object),
-       .tp_dealloc = py_talloc_dealloc,
+       .tp_basicsize = sizeof(pytalloc_Object),
 };
 
+void initgensec(void);
 void initgensec(void)
 {
        PyObject *m;
 
+       Py_Security.tp_base = pytalloc_GetObjectType();
+       if (Py_Security.tp_base == NULL)
+               return;
+
        if (PyType_Ready(&Py_Security) < 0)
                return;