rpc_server lsa: pass remote connection data
[samba.git] / source4 / libcli / pysmb.c
index 14b05f7994820aeee1fa64b5509c5b4f40dc6e2e..5bb3807ab76af1b1563d6a6f08b399b7c346392e 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include <Python.h>
+#include "python/py3compat.h"
 #include <tevent.h>
 #include <pytalloc.h>
 #include "includes.h"
 #include "libcli/security/security_descriptor.h"
 #include "librpc/rpc/pyrpc_util.h"
 
-#ifndef Py_RETURN_NONE
-#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-#endif
-
-staticforward PyTypeObject PySMB;
+static PyTypeObject PySMB;
 
 void initsmb(void);
 
@@ -63,12 +60,13 @@ static void dos_format(char *s)
  * Connect to SMB share using smb_full_connection
  */
 static NTSTATUS do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spdata,
-                       const char *hostname, const char *service, struct smbcli_tree **tree)
+                              const char *hostname, const char *service,
+                              struct smbcli_options *options,
+                              struct smbcli_session_options *session_options,
+                              struct smbcli_tree **tree)
 {
        struct smbcli_state *smb_state;
        NTSTATUS status;
-       struct smbcli_options options;
-       struct smbcli_session_options session_options;
 
        *tree = NULL;
 
@@ -76,9 +74,6 @@ static NTSTATUS do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spd
 
        smb_state = smbcli_state_init(mem_ctx);
 
-       lpcfg_smbcli_options(spdata->lp_ctx, &options);
-       lpcfg_smbcli_session_options(spdata->lp_ctx, &session_options);
-
        status = smbcli_full_connection(mem_ctx, &smb_state, hostname, 
                                        lpcfg_smb_ports(spdata->lp_ctx),
                                        service, 
@@ -87,8 +82,8 @@ static NTSTATUS do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spd
                                        spdata->creds,
                                        lpcfg_resolve_context(spdata->lp_ctx),
                                        spdata->ev_ctx,
-                                       &options,
-                                       &session_options,
+                                       options,
+                                       session_options,
                                        lpcfg_gensec_settings(mem_ctx, spdata->lp_ctx));
 
        if (NT_STATUS_IS_OK(status)) {
@@ -102,7 +97,7 @@ static NTSTATUS do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spd
 /*
  * Read SMB file and return the contents of the file as python string
  */
-static PyObject * py_smb_loadfile(pytalloc_Object *self, PyObject *args)
+static PyObject * py_smb_loadfile(PyObject *self, PyObject *args)
 {
        struct smb_composite_loadfile io;
        const char *filename;
@@ -117,33 +112,34 @@ static PyObject * py_smb_loadfile(pytalloc_Object *self, PyObject *args)
 
        io.in.fname = filename;
 
-       spdata = self->ptr;
-       status = smb_composite_loadfile(spdata->tree, self->talloc_ctx, &io);
+       spdata = pytalloc_get_ptr(self);
+       status = smb_composite_loadfile(spdata->tree, pytalloc_get_mem_ctx(self), &io);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
-       return Py_BuildValue("s#", io.out.data, io.out.size);
+       return Py_BuildValue(PYARG_BYTES_LEN, io.out.data, io.out.size);
 }
 
 /*
  * Create a SMB file with given string as the contents
  */
-static PyObject * py_smb_savefile(pytalloc_Object *self, PyObject *args)
+static PyObject * py_smb_savefile(PyObject *self, PyObject *args)
 {
        struct smb_composite_savefile io;
        const char *filename;
-       char *data;
+       char *data = NULL;
+       Py_ssize_t size = 0;
        NTSTATUS status;
        struct smb_private_data *spdata;
 
-       if (!PyArg_ParseTuple(args, "ss:savefile", &filename, &data)) {
+       if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename, &data, &size )) {
                return NULL;
        }
 
        io.in.fname = filename;
        io.in.data = (unsigned char *)data;
-       io.in.size = strlen(data);
+       io.in.size = size;
 
-       spdata = self->ptr;
+       spdata = pytalloc_get_ptr(self);
        status = smb_composite_savefile(spdata->tree, &io);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
@@ -163,11 +159,11 @@ static void py_smb_list_callback(struct clilist_file_info *f, const char *mask,
 
                dict = PyDict_New();
                if(dict) {
-                       PyDict_SetItemString(dict, "name", PyString_FromString(f->name));
+                       PyDict_SetItemString(dict, "name", PyStr_FromString(f->name));
                        
                        /* Windows does not always return short_name */
                        if (f->short_name) {
-                               PyDict_SetItemString(dict, "short_name", PyString_FromString(f->short_name));
+                               PyDict_SetItemString(dict, "short_name", PyStr_FromString(f->short_name));
                        } else {
                                PyDict_SetItemString(dict, "short_name", Py_None);
                        }
@@ -184,7 +180,7 @@ static void py_smb_list_callback(struct clilist_file_info *f, const char *mask,
 /*
  * List the directory contents for specified directory (Ignore '.' and '..' dirs)
  */
-static PyObject *py_smb_list(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_smb_list(PyObject *self, PyObject *args, PyObject *kwargs)
 {
        struct smb_private_data *spdata;
        PyObject *py_dirlist;
@@ -202,13 +198,13 @@ static PyObject *py_smb_list(pytalloc_Object *self, PyObject *args, PyObject *kw
        }
 
        if (user_mask == NULL) {
-               mask = talloc_asprintf(self->talloc_ctx, "%s\\*", base_dir);
+               mask = talloc_asprintf(pytalloc_get_mem_ctx(self), "%s\\*", base_dir);
        } else {
-               mask = talloc_asprintf(self->talloc_ctx, "%s\\%s", base_dir, user_mask);
+               mask = talloc_asprintf(pytalloc_get_mem_ctx(self), "%s\\%s", base_dir, user_mask);
        }
        dos_format(mask);
 
-       spdata = self->ptr;
+       spdata = pytalloc_get_ptr(self);
 
        if((py_dirlist = PyList_New(0)) == NULL) {
                PyErr_NoMemory();
@@ -225,7 +221,7 @@ static PyObject *py_smb_list(pytalloc_Object *self, PyObject *args, PyObject *kw
 /*
  * Create a directory
  */
-static PyObject *py_smb_mkdir(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_mkdir(PyObject *self, PyObject *args)
 {
        NTSTATUS status;
        const char *dirname;
@@ -235,7 +231,7 @@ static PyObject *py_smb_mkdir(pytalloc_Object *self, PyObject *args)
                return NULL;
        }
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
        status = smbcli_mkdir(spdata->tree, dirname);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
@@ -245,7 +241,7 @@ static PyObject *py_smb_mkdir(pytalloc_Object *self, PyObject *args)
 /*
  * Remove a directory
  */
-static PyObject *py_smb_rmdir(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_rmdir(PyObject *self, PyObject *args)
 {
        NTSTATUS status;
        const char *dirname;
@@ -255,17 +251,39 @@ static PyObject *py_smb_rmdir(pytalloc_Object *self, PyObject *args)
                return NULL;
        }
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
        status = smbcli_rmdir(spdata->tree, dirname);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        Py_RETURN_NONE;
 }
 
+/*
+ * Remove a directory and all its contents
+ */
+static PyObject *py_smb_deltree(PyObject *self, PyObject *args)
+{
+       int status;
+       const char *dirname;
+       struct smb_private_data *spdata;
+
+       if (!PyArg_ParseTuple(args, "s:deltree", &dirname)) {
+               return NULL;
+       }
+
+       spdata = pytalloc_get_ptr(self);
+       status = smbcli_deltree(spdata->tree, dirname);
+       if (status <= 0) {
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
 /*
  * Check existence of a path
  */
-static PyObject *py_smb_chkpath(pytalloc_Object *self, PyObject *args)
+static PyObject *py_smb_chkpath(PyObject *self, PyObject *args)
 {
        NTSTATUS status;
        const char *path;
@@ -275,7 +293,7 @@ static PyObject *py_smb_chkpath(pytalloc_Object *self, PyObject *args)
                return NULL;
        }
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
        status = smbcli_chkpath(spdata->tree, path);
 
        if (NT_STATUS_IS_OK(status)) {
@@ -288,28 +306,29 @@ static PyObject *py_smb_chkpath(pytalloc_Object *self, PyObject *args)
 /*
  * Read ACL on a given file/directory as a security descriptor object
  */
-static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_smb_getacl(PyObject *self, PyObject *args, PyObject *kwargs)
 {
        NTSTATUS status;
        union smb_open io;
        union smb_fileinfo fio;
        struct smb_private_data *spdata;
        const char *filename;
-       int sinfo = 0;
+       uint32_t sinfo = 0;
+       int access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        int fnum;
 
-       if (!PyArg_ParseTuple(args, "s|i:get_acl", &filename, &sinfo)) {
+       if (!PyArg_ParseTuple(args, "s|Ii:get_acl", &filename, &sinfo, &access_mask)) {
                return NULL;
        }
 
        ZERO_STRUCT(io);
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
 
        io.generic.level = RAW_OPEN_NTCREATEX;
        io.ntcreatex.in.root_fid.fnum = 0;
        io.ntcreatex.in.flags = 0;
-       io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       io.ntcreatex.in.access_mask = access_mask;
        io.ntcreatex.in.create_options = 0;
        io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | 
@@ -320,7 +339,7 @@ static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = filename;
        
-       status = smb_raw_open(spdata->tree, self->talloc_ctx, &io);
+       status = smb_raw_open(spdata->tree, pytalloc_get_mem_ctx(self), &io);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        fnum = io.ntcreatex.out.file.fnum;
@@ -341,19 +360,19 @@ static PyObject *py_smb_getacl(pytalloc_Object *self, PyObject *args, PyObject *
                                                SECINFO_PROTECTED_SACL |
                                                SECINFO_UNPROTECTED_SACL;
 
-       status = smb_raw_query_secdesc(spdata->tree, self->talloc_ctx, &fio);
+       status = smb_raw_query_secdesc(spdata->tree, pytalloc_get_mem_ctx(self), &fio);
        smbcli_close(spdata->tree, fnum);
 
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        return py_return_ndr_struct("samba.dcerpc.security", "descriptor",
-                               self->talloc_ctx, fio.query_secdesc.out.sd);
+                               pytalloc_get_mem_ctx(self), fio.query_secdesc.out.sd);
 }
 
 /*
  * Set ACL on file/directory using given security descriptor object
  */
-static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_smb_setacl(PyObject *self, PyObject *args, PyObject *kwargs)
 {
        NTSTATUS status;
        union smb_open io;
@@ -369,7 +388,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
                return NULL;
        }
 
-       spdata = self->ptr;
+       spdata = pytalloc_get_ptr(self);
 
        sd = pytalloc_get_type(py_sd, struct security_descriptor);
        if (!sd) {
@@ -381,7 +400,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
 
        ZERO_STRUCT(io);
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
 
        io.generic.level = RAW_OPEN_NTCREATEX;
        io.ntcreatex.in.root_fid.fnum = 0;
@@ -397,7 +416,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = filename;
        
-       status = smb_raw_open(spdata->tree, self->talloc_ctx, &io);
+       status = smb_raw_open(spdata->tree, pytalloc_get_mem_ctx(self), &io);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
 
        fnum = io.ntcreatex.out.file.fnum;
@@ -431,7 +450,7 @@ static PyObject *py_smb_setacl(pytalloc_Object *self, PyObject *args, PyObject *
 /*
  * Open the file with the parameters passed in and return an object if OK
  */
-static PyObject *py_open_file(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_open_file(PyObject *self, PyObject *args, PyObject *kwargs)
 {
        NTSTATUS status;
        union smb_open io;
@@ -456,7 +475,7 @@ static PyObject *py_open_file(pytalloc_Object *self, PyObject *args, PyObject *k
 
        ZERO_STRUCT(io);
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
 
        mem_ctx = talloc_new(NULL);
 
@@ -486,7 +505,7 @@ static PyObject *py_open_file(pytalloc_Object *self, PyObject *args, PyObject *k
 /*
  * Close the file based on the fnum passed in
  */
-static PyObject *py_close_file(pytalloc_Object *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_close_file(PyObject *self, PyObject *args, PyObject *kwargs)
 {
        struct smb_private_data *spdata;
        int fnum;
@@ -495,7 +514,7 @@ static PyObject *py_close_file(pytalloc_Object *self, PyObject *args, PyObject *
                return NULL;
        }
 
-       spdata = self->ptr;     
+       spdata = pytalloc_get_ptr(self);
 
        /*
         * Should check the status ...
@@ -506,27 +525,36 @@ static PyObject *py_close_file(pytalloc_Object *self, PyObject *args, PyObject *
 }
 
 static PyMethodDef py_smb_methods[] = {
-       { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
-               "loadfile(path) -> file contents as a string\n\n \
-               Read contents of a file." },
-       { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
-               "savefile(path, str) -> None\n\n \
-               Write string str to file." },
+       { "loadfile", py_smb_loadfile, METH_VARARGS,
+               "loadfile(path) -> file contents as a "
+               PY_DESC_PY3_BYTES
+               "\n\n Read contents of a file." },
+       { "savefile", py_smb_savefile, METH_VARARGS,
+               "savefile(path, str) -> None\n\n Write "
+               PY_DESC_PY3_BYTES
+               " str to file." },
        { "list", (PyCFunction)py_smb_list, METH_VARARGS|METH_KEYWORDS,
-               "list(path) -> directory contents as a dictionary\n\n \
+               "list(path, access_mask='*', attribs=DEFAULT_ATTRS) -> \
+directory contents as a dictionary\n \
+               DEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | \
+FILE_ATTRIBUTE_DIRECTORY | \
+FILE_ATTRIBUTE_ARCHIVE\n\n \
                List contents of a directory. The keys are, \n \
                \tname: Long name of the directory item\n \
                \tshort_name: Short name of the directory item\n \
                \tsize: File size in bytes\n \
                \tattrib: Attributes\n \
                \tmtime: Modification time\n" },
-       { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
+       { "mkdir", py_smb_mkdir, METH_VARARGS,
                "mkdir(path) -> None\n\n \
                Create a directory." },
-       { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
+       { "rmdir", py_smb_rmdir, METH_VARARGS,
                "rmdir(path) -> None\n\n \
                Delete a directory." },
-       { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
+       { "deltree", py_smb_deltree, METH_VARARGS,
+               "deltree(path) -> None\n\n \
+               Delete a directory and all its contents." },
+       { "chkpath", py_smb_chkpath, METH_VARARGS,
                "chkpath(path) -> True or False\n\n \
                Return true if path exists, false otherwise." },
        { "get_acl", (PyCFunction)py_smb_getacl, METH_VARARGS,
@@ -548,64 +576,82 @@ static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs
 {
        PyObject *py_creds = Py_None;
        PyObject *py_lp = Py_None;
-       const char *kwnames[] = { "hostname", "service", "creds", "lp", NULL };
+       const char *kwnames[] = { "hostname", "service", "creds", "lp",
+                                 "ntlmv2_auth", "use_spnego", NULL };
        const char *hostname = NULL;
        const char *service = NULL;
-       pytalloc_Object *smb;
+       PyObject *smb;
        struct smb_private_data *spdata;
        NTSTATUS status;
+       TALLOC_CTX *frame = NULL;
+       struct smbcli_options options;
+       struct smbcli_session_options session_options;
+       uint8_t ntlmv2_auth = 0xFF;
+       uint8_t use_spnego = 0xFF;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OO",
-                                       discard_const_p(char *, kwnames),
-                                       &hostname, &service, &py_creds, &py_lp)) {
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OObb",
+                                        discard_const_p(char *, kwnames),
+                                        &hostname, &service, &py_creds, &py_lp,
+                                        &ntlmv2_auth, &use_spnego)) {
                return NULL;
        }
 
-       smb = (pytalloc_Object *)type->tp_alloc(type, 0);
-       if (smb == NULL) {
-               PyErr_NoMemory();
-               return NULL;
-       }
-       smb->talloc_ctx = talloc_new(NULL);
-       if (smb->talloc_ctx == NULL) {
-               PyErr_NoMemory();
-               return NULL;
-       }
+       frame = talloc_stackframe();
 
-       spdata = talloc_zero(smb->talloc_ctx, struct smb_private_data);
+       spdata = talloc_zero(frame, struct smb_private_data);
        if (spdata == NULL) {
                PyErr_NoMemory();
-               Py_DECREF(smb);
+               TALLOC_FREE(frame);
                return NULL;
        }
 
-       spdata->lp_ctx = lpcfg_from_py_object(smb->talloc_ctx, py_lp);
+       spdata->lp_ctx = lpcfg_from_py_object(spdata, py_lp);
        if (spdata->lp_ctx == NULL) {
-               Py_DECREF(smb);
+               PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
+               TALLOC_FREE(frame);
+               return NULL;
+       }
+
+       spdata->creds = cli_credentials_from_py_object(py_creds);
+       if (spdata->creds == NULL) {
+               PyErr_SetString(PyExc_TypeError, "Expected credentials");
+               TALLOC_FREE(frame);
                return NULL;
        }
-       spdata->creds = PyCredentials_AsCliCredentials(py_creds);
-       spdata->ev_ctx = s4_event_context_init(smb->talloc_ctx);
+       spdata->ev_ctx = s4_event_context_init(spdata);
        if (spdata->ev_ctx == NULL) {
                PyErr_NoMemory();
-               Py_DECREF(smb);
+               TALLOC_FREE(frame);
                return NULL;
        }
 
-       status = do_smb_connect(smb->talloc_ctx, spdata, hostname, service, &spdata->tree);
+       lpcfg_smbcli_options(spdata->lp_ctx, &options);
+       lpcfg_smbcli_session_options(spdata->lp_ctx, &session_options);
+
+       if (ntlmv2_auth != 0xFF) {
+               session_options.ntlmv2_auth = ntlmv2_auth;
+       }
+       if (use_spnego != 0xFF) {
+               options.use_spnego = use_spnego;
+       }
+
+       status = do_smb_connect(spdata, spdata, hostname, service,
+                               &options,
+                               &session_options,
+                               &spdata->tree);
        PyErr_NTSTATUS_IS_ERR_RAISE(status);
        if (spdata->tree == NULL) {
-               Py_DECREF(smb);
+               TALLOC_FREE(frame);
                return NULL;
        }
 
-       smb->ptr = spdata;
-       return (PyObject *)smb;
+       smb = pytalloc_steal(type, spdata);
+       TALLOC_FREE(frame);
+       return smb;
 }
 
 static PyTypeObject PySMB = {
        .tp_name = "smb.SMB",
-       .tp_basicsize = sizeof(pytalloc_Object),
        .tp_new = py_smb_new,
        .tp_flags = Py_TPFLAGS_DEFAULT,
        .tp_methods = py_smb_methods,
@@ -613,23 +659,27 @@ static PyTypeObject PySMB = {
 
 };
 
-void initsmb(void)
-{
-       PyObject *m;
-       PyTypeObject *talloc_type = pytalloc_GetObjectType();
-       if (talloc_type == NULL) {
-               return;
-       }
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "smb",
+    .m_doc = "SMB File I/O support",
+    .m_size = -1,
+    .m_methods = NULL,
+};
 
-       PySMB.tp_base = talloc_type;
+void initsmb(void);
+
+MODULE_INIT_FUNC(smb)
+{
+       PyObject *m = NULL;
 
-       if (PyType_Ready(&PySMB) < 0) {
-               return;
+       if (pytalloc_BaseObject_PyType_Ready(&PySMB) < 0) {
+               return m;
        }
 
-       m = Py_InitModule3("smb", NULL, "SMB File I/O support");
+       m = PyModule_Create(&moduledef);
        if (m == NULL) {
-           return;
+           return m;
        }
 
        Py_INCREF(&PySMB);
@@ -653,4 +703,5 @@ void initsmb(void)
        ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
        ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
        ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
+       return m;
 }