libsmb: Convert cli_list_recv() to single-recv
[samba.git] / source3 / libsmb / pylibsmb.c
index 452c30e949051a2172a55a70a500a7b20e56c259..a1d48fe863e62b77b483332169b18f2b0e200550 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * Unix SMB/CIFS implementation.
- * Samba-internal work in progress Python binding for libsmbclient
+ *
+ * SMB client Python bindings used internally by Samba (for things like
+ * samba-tool). These Python bindings may change without warning, and so
+ * should not be used outside of the Samba codebase.
  *
  * Copyright (C) Volker Lendecke 2012
  *
@@ -21,6 +24,7 @@
 #include <Python.h>
 #include "includes.h"
 #include "python/py3compat.h"
+#include "python/modules.h"
 #include "libcli/smb/smbXcli_base.h"
 #include "libsmb/libsmb.h"
 #include "libcli/security/security.h"
 #include "auth/credentials/pycredentials.h"
 #include "trans2.h"
 #include "libsmb/clirap.h"
+#include "librpc/rpc/pyrpc_util.h"
 
 #define LIST_ATTRIBUTE_MASK \
        (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
 
+#define SECINFO_DEFAULT_FLAGS \
+       (SECINFO_OWNER | SECINFO_GROUP | \
+        SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL | \
+        SECINFO_SACL | SECINFO_PROTECTED_SACL | SECINFO_UNPROTECTED_SACL)
+
 static PyTypeObject *get_pytype(const char *module, const char *type)
 {
        PyObject *mod;
@@ -430,18 +440,18 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
        PyObject *py_lp = Py_None;
        PyObject *py_multi_threaded = Py_False;
        bool multi_threaded = false;
-       PyObject *py_sign = Py_False;
-       bool sign = false;
-       int signing_state = SMB_SIGNING_DEFAULT;
        PyObject *py_force_smb1 = Py_False;
        bool force_smb1 = false;
+       PyObject *py_ipc = Py_False;
+       bool use_ipc = false;
        struct tevent_req *req;
        bool ret;
        int flags = 0;
 
        static const char *kwlist[] = {
-               "host", "share", "lp", "credentials",
-               "multi_threaded", "sign", "force_smb1",
+               "host", "share", "lp", "creds",
+               "multi_threaded", "force_smb1",
+               "ipc",
                NULL
        };
 
@@ -456,8 +466,8 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
                &host, &share, &py_lp,
                py_type_Credentials, &creds,
                &py_multi_threaded,
-               &py_sign,
-               &py_force_smb1);
+               &py_force_smb1,
+               &py_ipc);
 
        Py_DECREF(py_type_Credentials);
 
@@ -466,13 +476,8 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
        }
 
        multi_threaded = PyObject_IsTrue(py_multi_threaded);
-       sign = PyObject_IsTrue(py_sign);
        force_smb1 = PyObject_IsTrue(py_force_smb1);
 
-       if (sign) {
-               signing_state = SMB_SIGNING_REQUIRED;
-       }
-
        if (force_smb1) {
                /*
                 * As most of the cli_*_send() function
@@ -483,6 +488,11 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
                flags = CLI_FULL_CONNECTION_FORCE_SMB1;
        }
 
+       use_ipc = PyObject_IsTrue(py_ipc);
+       if (use_ipc) {
+               flags |= CLI_FULL_CONNECTION_IPC;
+       }
+
        if (multi_threaded) {
 #ifdef HAVE_PTHREAD
                ret = py_cli_state_setup_mt_ev(self);
@@ -515,7 +525,7 @@ static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
 
        req = cli_full_connection_creds_send(
                NULL, self->ev, "myname", host, NULL, 0, share, "?????",
-               cli_creds, flags, signing_state);
+               cli_creds, flags);
        if (!py_tevent_req_wait_exc(self, req)) {
                return -1;
        }
@@ -672,7 +682,7 @@ static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
 
        omsecs = cli_set_timeout(self->cli, nmsecs);
 
-       return PyInt_FromLong(omsecs);
+       return PyLong_FromLong(omsecs);
 }
 
 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
@@ -777,8 +787,7 @@ static size_t push_data(uint8_t *buf, size_t n, void *priv)
 /*
  * Writes a file with the contents specified
  */
-static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args,
-                                PyObject *kwargs)
+static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
 {
        uint16_t fnum;
        const char *filename = NULL;
@@ -847,7 +856,7 @@ static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
                "fnum", "buffer", "offset", "mode", NULL };
 
        if (!ParseTupleAndKeywords(
-                   args, kwds, "I" PYARG_BYTES_LEN "K|I", kwlist,
+                   args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
                    &fnum, &buf, &buflen, &offset, &mode)) {
                return NULL;
        }
@@ -874,35 +883,22 @@ static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
                                off_t *size)
 {
        NTSTATUS status;
+       struct tevent_req *req = NULL;
 
-       if (self->is_smb1) {
-               uint8_t *rdata = NULL;
-               struct tevent_req *req = NULL;
-
-               req = cli_qfileinfo_send(NULL, self->ev, self->cli, fnum,
-                                        SMB_QUERY_FILE_ALL_INFO, 68,
-                                        CLI_BUFFER_SIZE);
-               if (!py_tevent_req_wait_exc(self, req)) {
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-               status = cli_qfileinfo_recv(req, NULL, NULL, &rdata, NULL);
-               if (NT_STATUS_IS_OK(status)) {
-                       *size = IVAL2_TO_SMB_BIG_UINT(rdata, 48);
-               }
-               TALLOC_FREE(req);
-               TALLOC_FREE(rdata);
-       } else {
-               status = cli_qfileinfo_basic(self->cli, fnum, NULL, size,
-                                            NULL, NULL, NULL, NULL, NULL);
+       req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return NT_STATUS_INTERNAL_ERROR;
        }
+       status = cli_qfileinfo_basic_recv(
+               req, NULL, size, NULL, NULL, NULL, NULL, NULL);
+       TALLOC_FREE(req);
        return status;
 }
 
 /*
  * Loads the specified file's contents and returns it
  */
-static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args,
-                                PyObject *kwargs)
+static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
 {
        NTSTATUS status;
        const char *filename = NULL;
@@ -919,7 +915,8 @@ static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args,
 
        /* get a read file handle */
        req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
-                               FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+                               FILE_READ_DATA | FILE_READ_ATTRIBUTES,
+                               FILE_ATTRIBUTE_NORMAL,
                                FILE_SHARE_READ, FILE_OPEN, 0,
                                SMB2_IMPERSONATION_IMPERSONATION, 0);
        if (!py_tevent_req_wait_exc(self, req)) {
@@ -1002,7 +999,7 @@ static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
                "fnum", "offset", "size", NULL };
 
        if (!ParseTupleAndKeywords(
-                   args, kwds, "IKI", kwlist, &fnum, &offset,
+                   args, kwds, "iKI", kwlist, &fnum, &offset,
                    &size)) {
                return NULL;
        }
@@ -1109,35 +1106,39 @@ static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
 /*
  * Helper to add directory listing entries to an overall Python list
  */
-static NTSTATUS list_helper(const char *mntpoint, struct file_info *finfo,
+static NTSTATUS list_helper(struct file_info *finfo,
                            const char *mask, void *state)
 {
        PyObject *result = (PyObject *)state;
        PyObject *file = NULL;
+       PyObject *size = NULL;
        int ret;
 
        /* suppress '.' and '..' in the results we return */
        if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
                return NT_STATUS_OK;
        }
-
+       size = PyLong_FromUnsignedLongLong(finfo->size);
        /*
         * Build a dictionary representing the file info.
         * Note: Windows does not always return short_name (so it may be None)
         */
        file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l}",
                             "name", finfo->name,
-                            "attrib", (int)finfo->mode,
+                            "attrib", (int)finfo->attr,
                             "short_name", finfo->short_name,
-                            "size", PyLong_FromUnsignedLongLong(finfo->size),
+                            "size", size,
                             "mtime",
                             convert_timespec_to_time_t(finfo->mtime_ts));
 
+       Py_CLEAR(size);
+
        if (file == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
        ret = PyList_Append(result, file);
+       Py_CLEAR(file);
        if (ret == -1) {
                return NT_STATUS_INTERNAL_ERROR;
        }
@@ -1145,19 +1146,38 @@ static NTSTATUS list_helper(const char *mntpoint, struct file_info *finfo,
        return NT_STATUS_OK;
 }
 
+struct do_listing_state {
+       const char *mask;
+       NTSTATUS (*callback_fn)(
+               struct file_info *finfo,
+               const char *mask,
+               void *private_data);
+       void *private_data;
+       NTSTATUS status;
+};
+
+static void do_listing_cb(struct tevent_req *subreq)
+{
+       struct do_listing_state *state = tevent_req_callback_data_void(subreq);
+       struct file_info *finfo = NULL;
+
+       state->status = cli_list_recv(subreq, NULL, &finfo);
+       if (!NT_STATUS_IS_OK(state->status)) {
+               return;
+       }
+       state->callback_fn(finfo, state->mask, state->private_data);
+       TALLOC_FREE(finfo);
+}
+
 static NTSTATUS do_listing(struct py_cli_state *self,
                           const char *base_dir, const char *user_mask,
                           uint16_t attribute,
-                          NTSTATUS (*callback_fn)(const char *,
-                                                  struct file_info *,
+                          NTSTATUS (*callback_fn)(struct file_info *,
                                                   const char *, void *),
                           void *priv)
 {
        char *mask = NULL;
        unsigned int info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
-       struct file_info *finfos = NULL;
-       size_t i;
-       size_t num_finfos = 0;
        NTSTATUS status;
 
        if (user_mask == NULL) {
@@ -1172,36 +1192,37 @@ static NTSTATUS do_listing(struct py_cli_state *self,
        dos_format(mask);
 
        if (self->is_smb1) {
+               struct do_listing_state state = {
+                       .mask = mask,
+                       .callback_fn = callback_fn,
+                       .private_data = priv,
+               };
                struct tevent_req *req = NULL;
 
                req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
                                    info_level);
+               if (req == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+               tevent_req_set_callback(req, do_listing_cb, &state);
+
                if (!py_tevent_req_wait_exc(self, req)) {
                        return NT_STATUS_INTERNAL_ERROR;
                }
-               status = cli_list_recv(req, NULL, &finfos, &num_finfos);
                TALLOC_FREE(req);
+
+               status = state.status;
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
+                       status = NT_STATUS_OK;
+               }
        } else {
                status = cli_list(self->cli, mask, attribute, callback_fn,
                                  priv);
        }
-       TALLOC_FREE(mask);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
 
-       /* invoke the callback for the async results (SMBv1 connections) */
-       for (i = 0; i < num_finfos; i++) {
-               status = callback_fn(base_dir, &finfos[i], user_mask,
-                                    priv);
-               if (!NT_STATUS_IS_OK(status)) {
-                       TALLOC_FREE(finfos);
-                       return status;
-               }
-       }
-
-       TALLOC_FREE(finfos);
+done:
+       TALLOC_FREE(mask);
        return status;
 }
 
@@ -1213,10 +1234,10 @@ static PyObject *py_cli_list(struct py_cli_state *self,
        char *user_mask = NULL;
        unsigned int attribute = LIST_ATTRIBUTE_MASK;
        NTSTATUS status;
-       PyObject *result;
+       PyObject *result = NULL;
        const char *kwlist[] = { "directory", "mask", "attribs", NULL };
 
-       if (!ParseTupleAndKeywords(args, kwds, "z|sH:list", kwlist,
+       if (!ParseTupleAndKeywords(args, kwds, "z|sI:list", kwlist,
                                   &base_dir, &user_mask, &attribute)) {
                return NULL;
        }
@@ -1238,78 +1259,44 @@ static PyObject *py_cli_list(struct py_cli_state *self,
        return result;
 }
 
-/*
- * Deletes a file
- */
-static NTSTATUS unlink_file(struct py_cli_state *self, const char *filename)
-{
-       NTSTATUS status;
-       uint16_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
-
-       if (self->is_smb1) {
-               struct tevent_req *req = NULL;
-
-               req = cli_unlink_send(NULL, self->ev, self->cli, filename,
-                                     attrs);
-               if (!py_tevent_req_wait_exc(self, req)) {
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-               status = cli_unlink_recv(req);
-               TALLOC_FREE(req);
-       } else {
-               status = cli_unlink(self->cli, filename, attrs);
-       }
-
-       return status;
-}
-
 static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
 {
        NTSTATUS status;
        const char *filename = NULL;
+       struct tevent_req *req = NULL;
+       const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
 
        if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
                return NULL;
        }
 
-       status = unlink_file(self, filename);
+       req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return NULL;
+       }
+       status = cli_unlink_recv(req);
+       TALLOC_FREE(req);
        PyErr_NTSTATUS_NOT_OK_RAISE(status);
 
        Py_RETURN_NONE;
 }
 
-/*
- * Delete an empty directory
- */
-static NTSTATUS remove_dir(struct py_cli_state *self, const char *dirname)
-{
-       NTSTATUS status;
-
-       if (self->is_smb1) {
-               struct tevent_req *req = NULL;
-
-               req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
-               if (!py_tevent_req_wait_exc(self, req)) {
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-               status = cli_rmdir_recv(req);
-               TALLOC_FREE(req);
-       } else {
-               status = cli_rmdir(self->cli, dirname);
-       }
-       return status;
-}
-
 static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
 {
        NTSTATUS status;
-       const char *dirname;
+       struct tevent_req *req = NULL;
+       const char *dirname = NULL;
 
        if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
                return NULL;
        }
 
-       status = remove_dir(self, dirname);
+       req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return NULL;
+       }
+       status = cli_rmdir_recv(req);
+       TALLOC_FREE(req);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        Py_RETURN_NONE;
@@ -1321,24 +1308,19 @@ static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
 static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
 {
        NTSTATUS status;
-       const char *dirname;
+       const char *dirname = NULL;
+       struct tevent_req *req = NULL;
 
        if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
                return NULL;
        }
 
-       if (self->is_smb1) {
-               struct tevent_req *req = NULL;
-
-               req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
-               if (!py_tevent_req_wait_exc(self, req)) {
-                       return NULL;
-               }
-               status = cli_mkdir_recv(req);
-               TALLOC_FREE(req);
-       } else {
-               status = cli_mkdir(self->cli, dirname);
+       req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return NULL;
        }
+       status = cli_mkdir_recv(req);
+       TALLOC_FREE(req);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        Py_RETURN_NONE;
@@ -1350,26 +1332,21 @@ static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
 static bool check_dir_path(struct py_cli_state *self, const char *path)
 {
        NTSTATUS status;
+       struct tevent_req *req = NULL;
 
-       if (self->is_smb1) {
-               struct tevent_req *req = NULL;
-
-               req = cli_chkpath_send(NULL, self->ev, self->cli, path);
-               if (!py_tevent_req_wait_exc(self, req)) {
-                       return false;
-               }
-               status = cli_chkpath_recv(req);
-               TALLOC_FREE(req);
-       } else {
-               status = cli_chkpath(self->cli, path);
+       req = cli_chkpath_send(NULL, self->ev, self->cli, path);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return false;
        }
+       status = cli_chkpath_recv(req);
+       TALLOC_FREE(req);
 
        return NT_STATUS_IS_OK(status);
 }
 
 static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
 {
-       const char *path;
+       const char *path = NULL;
        bool dir_exists;
 
        if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
@@ -1380,93 +1357,58 @@ static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
        return PyBool_FromLong(dir_exists);
 }
 
-struct deltree_state {
-       struct py_cli_state *self;
-       const char *full_dirpath;
-};
-
-static NTSTATUS delete_dir_tree(struct py_cli_state *self,
-                               const char *dirpath);
-
-/*
- * Deletes a single item in the directory tree. This could be either a file
- * or a directory. This function gets invoked as a callback for every item in
- * the given directory's listings.
- */
-static NTSTATUS delete_tree_callback(const char *mntpoint,
-                                    struct file_info *finfo,
-                                    const char *mask, void *priv)
+static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
 {
-       char *filepath = NULL;
-       struct deltree_state *state = priv;
+       int fnum;
+       unsigned sinfo;
+       struct tevent_req *req = NULL;
+       struct security_descriptor *sd = NULL;
        NTSTATUS status;
 
-       /* skip '.' or '..' directory listings */
-       if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
-               return NT_STATUS_OK;
-       }
-
-       /* get the absolute filepath */
-       filepath = talloc_asprintf(NULL, "%s\\%s", state->full_dirpath,
-                                  finfo->name);
-       if (filepath == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
+               return NULL;
        }
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
-
-               /* recursively delete the sub-directory and its contents */
-               status = delete_dir_tree(state->self, filepath);
-       } else {
-               status = unlink_file(state->self, filepath);
+       req = cli_query_security_descriptor_send(
+               NULL, self->ev, self->cli, fnum, sinfo);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return false;
        }
+       status = cli_query_security_descriptor_recv(req, NULL, &sd);
+       PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
-       TALLOC_FREE(filepath);
-       return status;
+       return py_return_ndr_struct(
+               "samba.dcerpc.security", "descriptor", sd, sd);
 }
 
-/*
- * Removes a directory and all its contents
- */
-static NTSTATUS delete_dir_tree(struct py_cli_state *self,
-                               const char *filepath)
+static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
 {
+       PyObject *py_sd = NULL;
+       struct tevent_req *req = NULL;
+       struct security_descriptor *sd = NULL;
+       uint16_t fnum;
+       unsigned int sinfo;
        NTSTATUS status;
-       const char *mask = "*";
-       struct deltree_state state = { 0 };
 
-       /* go through the directory's contents, deleting each item */
-       state.self = self;
-       state.full_dirpath = filepath;
-       status = do_listing(self, filepath, mask, LIST_ATTRIBUTE_MASK,
-                           delete_tree_callback, &state);
-
-       /* remove the directory itself */
-       if (NT_STATUS_IS_OK(status)) {
-               status = remove_dir(self, filepath);
+       if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
+               return NULL;
        }
-       return status;
-}
 
-static PyObject *py_smb_deltree(struct py_cli_state *self, PyObject *args)
-{
-       NTSTATUS status;
-       const char *filepath = NULL;
-       bool dir_exists;
-
-       if (!PyArg_ParseTuple(args, "s:deltree", &filepath)) {
+       sd = pytalloc_get_type(py_sd, struct security_descriptor);
+       if (!sd) {
+               PyErr_Format(PyExc_TypeError,
+                       "Expected dcerpc.security.descriptor as argument, got %s",
+                       pytalloc_get_name(py_sd));
                return NULL;
        }
 
-       /* check whether we're removing a directory or a file */
-       dir_exists = check_dir_path(self, filepath);
-
-       if (dir_exists) {
-               status = delete_dir_tree(self, filepath);
-       } else {
-               status = unlink_file(self, filepath);
+       req = cli_set_security_descriptor_send(
+               NULL, self->ev, self->cli, fnum, sinfo, sd);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               return false;
        }
 
+       status = cli_set_security_descriptor_recv(req);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        Py_RETURN_NONE;
@@ -1475,21 +1417,27 @@ static PyObject *py_smb_deltree(struct py_cli_state *self, PyObject *args)
 static PyMethodDef py_cli_state_methods[] = {
        { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
          "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
-       { "create", (PyCFunction)py_cli_create, METH_VARARGS|METH_KEYWORDS,
+       { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
+               METH_VARARGS|METH_KEYWORDS,
          "Open a file" },
        { "close", (PyCFunction)py_cli_close, METH_VARARGS,
          "Close a file handle" },
-       { "write", (PyCFunction)py_cli_write, METH_VARARGS|METH_KEYWORDS,
+       { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
+               METH_VARARGS|METH_KEYWORDS,
          "Write to a file handle" },
-       { "read", (PyCFunction)py_cli_read, METH_VARARGS|METH_KEYWORDS,
+       { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
+               METH_VARARGS|METH_KEYWORDS,
          "Read from a file handle" },
-       { "truncate", (PyCFunction)py_cli_ftruncate,
+       { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
+                       py_cli_ftruncate),
          METH_VARARGS|METH_KEYWORDS,
          "Truncate a file" },
-       { "delete_on_close", (PyCFunction)py_cli_delete_on_close,
+       { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
+                                        py_cli_delete_on_close),
          METH_VARARGS|METH_KEYWORDS,
          "Set/Reset the delete on close flag" },
-       { "list", (PyCFunction)py_cli_list, METH_VARARGS|METH_KEYWORDS,
+       { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
+               METH_VARARGS|METH_KEYWORDS,
          "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
          "directory contents as a dictionary\n"
          "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
@@ -1518,18 +1466,21 @@ static PyMethodDef py_cli_state_methods[] = {
        { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
          "loadfile(path) -> file contents as a " PY_DESC_PY3_BYTES
          "\n\n\t\tRead contents of a file." },
-       { "deltree", (PyCFunction)py_smb_deltree, METH_VARARGS,
-         "deltree(path) -> None\n\n"
-         "\t\tDelete a directory and all its contents." },
+       { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
+         "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
+         "\t\tGet security descriptor for opened file." },
+       { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
+         "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
+         "\t\tSet security descriptor for opened file." },
        { NULL, NULL, 0, NULL }
 };
 
 static PyTypeObject py_cli_state_type = {
        PyVarObject_HEAD_INIT(NULL, 0)
-       .tp_name = "libsmb_samba_internal.Conn",
+       .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
        .tp_basicsize = sizeof(struct py_cli_state),
        .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-       .tp_doc = "libsmb connection",
+       .tp_doc = "libsmb cwrapper connection",
        .tp_new = py_cli_state_new,
        .tp_init = (initproc)py_cli_state_init,
        .tp_dealloc = (destructor)py_cli_state_dealloc,
@@ -1537,20 +1488,20 @@ static PyTypeObject py_cli_state_type = {
 };
 
 static PyMethodDef py_libsmb_methods[] = {
-       { NULL },
+       {0},
 };
 
-void initlibsmb_samba_internal(void);
+void initlibsmb_samba_cwrapper(void);
 
 static struct PyModuleDef moduledef = {
     PyModuleDef_HEAD_INIT,
-    .m_name = "libsmb_samba_internal",
+    .m_name = "libsmb_samba_cwrapper",
     .m_doc = "libsmb wrapper",
     .m_size = -1,
     .m_methods = py_libsmb_methods,
 };
 
-MODULE_INIT_FUNC(libsmb_samba_internal)
+MODULE_INIT_FUNC(libsmb_samba_cwrapper)
 {
        PyObject *m = NULL;
 
@@ -1564,6 +1515,30 @@ MODULE_INIT_FUNC(libsmb_samba_internal)
                return NULL;
        }
        Py_INCREF(&py_cli_state_type);
-       PyModule_AddObject(m, "Conn", (PyObject *)&py_cli_state_type);
+       PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
+
+#define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
+
+       ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
+       ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
+       ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
+       ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
+       ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
+       ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
+       ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
+       ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
+       ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
+       ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
+       ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
+       ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
+       ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
+       ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
+       ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
+       ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
+
+       ADD_FLAGS(FILE_SHARE_READ);
+       ADD_FLAGS(FILE_SHARE_WRITE);
+       ADD_FLAGS(FILE_SHARE_DELETE);
+
        return m;
 }