s3-rpc_cli: make dcerpc_lsa_lookup_sids_generic() public.
[kai/samba.git] / source3 / libsmb / pylibsmb.c
index 00fe2d9726d2117ec163e89f16b51c07d83751cb..900d05212c54516110717c86dd807f51f72cb311 100644 (file)
@@ -25,6 +25,7 @@
 #include "system/select.h"
 #include "source4/libcli/util/pyerrors.h"
 #include "auth/credentials/pycredentials.h"
+#include "trans2.h"
 
 static PyTypeObject *get_pytype(const char *module, const char *type)
 {
@@ -49,13 +50,40 @@ static PyTypeObject *get_pytype(const char *module, const char *type)
        return result;
 }
 
+/*
+ * We're using "const char **" for keywords,
+ * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
+ * inevitable warnings to just one place.
+ */
+static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
+                                const char *format, const char **keywords,
+                                ...)
+{
+       va_list a;
+       int ret;
+       va_start(a, keywords);
+       ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
+                                           (char **)keywords, a);
+       va_end(a);
+       return ret;
+}
+
 struct py_cli_thread;
 
+struct py_cli_oplock_break {
+       uint16_t fnum;
+       uint8_t level;
+};
+
 struct py_cli_state {
        PyObject_HEAD
        struct cli_state *cli;
        struct tevent_context *ev;
        struct py_cli_thread *thread_state;
+
+       struct tevent_req *oplock_waiter;
+       struct py_cli_oplock_break *oplock_breaks;
+       struct py_tevent_cond *oplock_cond;
 };
 
 #if HAVE_PTHREAD
@@ -280,10 +308,8 @@ static int py_tevent_req_wait(struct tevent_context *ev,
        return py_tevent_cond_wait(&cond);
 }
 
-static void py_tevent_signalme(struct tevent_req *req)
+static void py_tevent_cond_signal(struct py_tevent_cond *cond)
 {
-       struct py_tevent_cond *cond = (struct py_tevent_cond *)
-               tevent_req_callback_data_void(req);
        int ret;
 
        ret = pthread_mutex_lock(&cond->mutex);
@@ -297,6 +323,14 @@ static void py_tevent_signalme(struct tevent_req *req)
        assert(ret == 0);
 }
 
+static void py_tevent_signalme(struct tevent_req *req)
+{
+       struct py_tevent_cond *cond = (struct py_tevent_cond *)
+               tevent_req_callback_data_void(req);
+
+       py_tevent_cond_signal(cond);
+}
+
 #else
 
 static bool py_cli_state_setup_ev(struct py_cli_state *self)
@@ -352,9 +386,14 @@ static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
        self->cli = NULL;
        self->ev = NULL;
        self->thread_state = NULL;
+       self->oplock_waiter = NULL;
+       self->oplock_cond = NULL;
+       self->oplock_breaks = NULL;
        return (PyObject *)self;
 }
 
+static void py_cli_got_oplock_break(struct tevent_req *req);
+
 static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
                             PyObject *kwds)
 {
@@ -374,8 +413,8 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
                return -1;
        }
 
-       ret = PyArg_ParseTupleAndKeywords(
-               args, kwds, "ss|O!", (char **)kwlist,
+       ret = ParseTupleAndKeywords(
+               args, kwds, "ss|O!", kwlist,
                &host, &share, py_type_Credentials, &creds);
 
        Py_DECREF(py_type_Credentials);
@@ -404,12 +443,114 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
                PyErr_SetNTSTATUS(status);
                return -1;
        }
+
+       self->oplock_waiter = cli_smb_oplock_break_waiter_send(
+               self->ev, self->ev, self->cli);
+       if (self->oplock_waiter == NULL) {
+               PyErr_NoMemory();
+               return -1;
+       }
+       tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
+                               self);
        return 0;
 }
 
+static void py_cli_got_oplock_break(struct tevent_req *req)
+{
+       struct py_cli_state *self = (struct py_cli_state *)
+               tevent_req_callback_data_void(req);
+       struct py_cli_oplock_break b;
+       struct py_cli_oplock_break *tmp;
+       size_t num_breaks;
+       NTSTATUS status;
+
+       status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
+       TALLOC_FREE(req);
+       self->oplock_waiter = NULL;
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return;
+       }
+
+       num_breaks = talloc_array_length(self->oplock_breaks);
+       tmp = talloc_realloc(self->ev, self->oplock_breaks,
+                            struct py_cli_oplock_break, num_breaks+1);
+       if (tmp == NULL) {
+               return;
+       }
+       self->oplock_breaks = tmp;
+       self->oplock_breaks[num_breaks] = b;
+
+       if (self->oplock_cond != NULL) {
+               py_tevent_cond_signal(self->oplock_cond);
+       }
+
+       self->oplock_waiter = cli_smb_oplock_break_waiter_send(
+               self->ev, self->ev, self->cli);
+       if (self->oplock_waiter == NULL) {
+               return;
+       }
+       tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
+                               self);
+}
+
+static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
+                                        PyObject *args)
+{
+       size_t num_oplock_breaks;
+
+       if (!PyArg_ParseTuple(args, "")) {
+               return NULL;
+       }
+
+       if (self->oplock_cond != NULL) {
+               errno = EBUSY;
+               PyErr_SetFromErrno(PyExc_RuntimeError);
+               return NULL;
+       }
+
+       num_oplock_breaks = talloc_array_length(self->oplock_breaks);
+
+       if (num_oplock_breaks == 0) {
+               struct py_tevent_cond cond;
+               int ret;
+
+               self->oplock_cond = &cond;
+               ret = py_tevent_cond_wait(&cond);
+               self->oplock_cond = NULL;
+
+               if (ret != 0) {
+                       errno = ret;
+                       PyErr_SetFromErrno(PyExc_RuntimeError);
+                       return NULL;
+               }
+       }
+
+       num_oplock_breaks = talloc_array_length(self->oplock_breaks);
+       if (num_oplock_breaks > 0) {
+               PyObject *result;
+
+               result = Py_BuildValue(
+                       "{s:i,s:i}",
+                       "fnum", self->oplock_breaks[0].fnum,
+                       "level", self->oplock_breaks[0].level);
+
+               memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
+                       sizeof(self->oplock_breaks[0]) *
+                       (num_oplock_breaks - 1));
+               self->oplock_breaks = talloc_realloc(
+                       NULL, self->oplock_breaks, struct py_cli_oplock_break,
+                       num_oplock_breaks - 1);
+
+               return result;
+       }
+       Py_RETURN_NONE;
+}
+
 static void py_cli_state_dealloc(struct py_cli_state *self)
 {
        TALLOC_FREE(self->thread_state);
+       TALLOC_FREE(self->oplock_waiter);
        TALLOC_FREE(self->ev);
 
        if (self->cli != NULL) {
@@ -439,8 +580,8 @@ static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
                "ShareAccess", "CreateDisposition", "CreateOptions",
                "SecurityFlags", NULL };
 
-       if (!PyArg_ParseTupleAndKeywords(
-                   args, kwds, "s|IIIIIII", (char **)kwlist,
+       if (!ParseTupleAndKeywords(
+                   args, kwds, "s|IIIIIII", kwlist,
                    &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
                    &ShareAccess, &CreateDisposition, &CreateOptions,
                    &SecurityFlags)) {
@@ -485,8 +626,7 @@ static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
                PyErr_SetNTSTATUS(status);
                return NULL;
        }
-       Py_INCREF(Py_None);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
@@ -504,8 +644,8 @@ static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
        static const char *kwlist[] = {
                "fnum", "buffer", "offset", "mode", NULL };
 
-       if (!PyArg_ParseTupleAndKeywords(
-                   args, kwds, "Is#K|I", (char **)kwlist,
+       if (!ParseTupleAndKeywords(
+                   args, kwds, "Is#K|I", kwlist,
                    &fnum, &buf, &buflen, &offset, &mode)) {
                return NULL;
        }
@@ -540,8 +680,8 @@ static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
        static const char *kwlist[] = {
                "fnum", "offset", "size", NULL };
 
-       if (!PyArg_ParseTupleAndKeywords(
-                   args, kwds, "IKI", (char **)kwlist, &fnum, &offset,
+       if (!ParseTupleAndKeywords(
+                   args, kwds, "IKI", kwlist, &fnum, &offset,
                    &size)) {
                return NULL;
        }
@@ -574,8 +714,8 @@ static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
        static const char *kwlist[] = {
                "fnum", "size", NULL };
 
-       if (!PyArg_ParseTupleAndKeywords(
-                   args, kwds, "IK", (char **)kwlist, &fnum, &size)) {
+       if (!ParseTupleAndKeywords(
+                   args, kwds, "IK", kwlist, &fnum, &size)) {
                return NULL;
        }
 
@@ -590,8 +730,7 @@ static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
                PyErr_SetNTSTATUS(status);
                return NULL;
        }
-       Py_INCREF(Py_None);
-       return Py_None;
+       Py_RETURN_NONE;
 }
 
 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
@@ -605,8 +744,8 @@ static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
        static const char *kwlist[] = {
                "fnum", "flag", NULL };
 
-       if (!PyArg_ParseTupleAndKeywords(
-                   args, kwds, "II", (char **)kwlist, &fnum, &flag)) {
+       if (!ParseTupleAndKeywords(
+                   args, kwds, "II", kwlist, &fnum, &flag)) {
                return NULL;
        }
 
@@ -622,8 +761,75 @@ static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
                PyErr_SetNTSTATUS(status);
                return NULL;
        }
-       Py_INCREF(Py_None);
-       return Py_None;
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_cli_list(struct py_cli_state *self,
+                            PyObject *args,
+                            PyObject *kwds)
+{
+       char *mask;
+       unsigned attribute =
+               FILE_ATTRIBUTE_DIRECTORY |
+               FILE_ATTRIBUTE_SYSTEM |
+               FILE_ATTRIBUTE_HIDDEN;
+       unsigned info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
+       struct tevent_req *req;
+       NTSTATUS status;
+       struct file_info *finfos;
+       size_t i, num_finfos;
+       PyObject *result;
+
+       const char *kwlist[] = {
+               "mask", "attribute", "info_level", NULL
+       };
+
+       if (!ParseTupleAndKeywords(
+                   args, kwds, "s|II", kwlist,
+                   &mask, &attribute, &info_level)) {
+               return NULL;
+       }
+
+       req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
+                           info_level);
+       if (!py_tevent_req_wait_exc(self->ev, req)) {
+               return NULL;
+       }
+       status = cli_list_recv(req, NULL, &finfos, &num_finfos);
+       TALLOC_FREE(req);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               return NULL;
+       }
+
+       result = Py_BuildValue("[]");
+       if (result == NULL) {
+               return NULL;
+       }
+
+       for (i=0; i<num_finfos; i++) {
+               struct file_info *finfo = &finfos[i];
+               PyObject *file;
+               int ret;
+
+               file = Py_BuildValue(
+                       "{s:s,s:i}",
+                       "name", finfo->name,
+                       "mode", (int)finfo->mode);
+               if (file == NULL) {
+                       Py_XDECREF(result);
+                       return NULL;
+               }
+
+               ret = PyList_Append(result, file);
+               if (ret == -1) {
+                       Py_XDECREF(result);
+                       return NULL;
+               }
+       }
+
+       return result;
 }
 
 static PyMethodDef py_cli_state_methods[] = {
@@ -641,6 +847,11 @@ static PyMethodDef py_cli_state_methods[] = {
        { "delete_on_close", (PyCFunction)py_cli_delete_on_close,
          METH_VARARGS|METH_KEYWORDS,
          "Set/Reset the delete on close flag" },
+       { "readdir", (PyCFunction)py_cli_list,
+         METH_VARARGS|METH_KEYWORDS,
+         "List a directory" },
+       { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
+         METH_VARARGS, "Wait for an oplock break" },
        { NULL, NULL, 0, NULL }
 };