/*
* 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
*
#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;
"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;
}
/* 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)) {
"fnum", "offset", "size", NULL };
if (!ParseTupleAndKeywords(
- args, kwds, "IKI", kwlist, &fnum, &offset,
+ args, kwds, "iKI", kwlist, &fnum, &offset,
&size)) {
return NULL;
}
{
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)
"name", finfo->name,
"attrib", (int)finfo->mode,
"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;
}
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;
}
static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
{
NTSTATUS status;
- const char *dirname;
+ const char *dirname = NULL;
if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
return NULL;
static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
{
NTSTATUS status;
- const char *dirname;
+ const char *dirname = NULL;
if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
return NULL;
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)) {
Py_RETURN_NONE;
}
+/*
+ * Read ACL on a given file/directory as a security descriptor object
+ */
+static PyObject *py_smb_getacl(struct py_cli_state *self, PyObject *args)
+{
+ NTSTATUS status;
+ const char *filename = NULL;
+ unsigned int sinfo = SECINFO_DEFAULT_FLAGS;
+ unsigned int access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ uint16_t fnum;
+ struct security_descriptor *sd = NULL;
+
+ /* there's no async version of cli_query_security_descriptor() */
+ if (self->thread_state != NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "get_acl() is not supported on "
+ "a multi_threaded connection");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "s|II:get_acl", &filename, &sinfo,
+ &access_mask)) {
+ return NULL;
+ }
+
+ /* get a file handle with the desired access */
+ status = cli_ntcreate(self->cli, filename, 0, access_mask, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0x0, 0x0, &fnum, NULL);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ /* query the security descriptor for this file */
+ status = cli_query_security_descriptor(self->cli, fnum, sinfo,
+ NULL, &sd);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ /* close the file handle and convert the SD to a python struct */
+ status = cli_close(self->cli, fnum);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ return py_return_ndr_struct("samba.dcerpc.security", "descriptor",
+ sd, sd);
+}
+
+/*
+ * Set ACL on file/directory using given security descriptor object
+ */
+static PyObject *py_smb_setacl(struct py_cli_state *self, PyObject *args)
+{
+ NTSTATUS status;
+ char *filename = NULL;
+ PyObject *py_sd = NULL;
+ struct security_descriptor *sd = NULL;
+ unsigned int sinfo = SECINFO_DEFAULT_FLAGS;
+ uint16_t fnum;
+
+ /* there's no async version of cli_set_security_descriptor() */
+ if (self->thread_state != NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "set_acl() is not supported on "
+ "a multi_threaded connection");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "sO|I:set_acl", &filename, &py_sd,
+ &sinfo)) {
+ return NULL;
+ }
+
+ sd = pytalloc_get_type(py_sd, struct security_descriptor);
+ if (!sd) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected dcerpc.security.descriptor as argument, got %s",
+ talloc_get_name(pytalloc_get_ptr(py_sd)));
+ return NULL;
+ }
+
+ status = cli_ntcreate(self->cli, filename, 0,
+ SEC_FLAG_MAXIMUM_ALLOWED, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0x0, 0x0, &fnum, NULL);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ status = cli_set_security_descriptor(self->cli, fnum, sinfo, sd);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ status = cli_close(self->cli, fnum);
+ PyErr_NTSTATUS_IS_ERR_RAISE(status);
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef py_cli_state_methods[] = {
{ "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
"settimeout(new_timeout_msecs) => return old_timeout_msecs" },
{ "deltree", (PyCFunction)py_smb_deltree, METH_VARARGS,
"deltree(path) -> None\n\n"
"\t\tDelete a directory and all its contents." },
+ { "get_acl", (PyCFunction)py_smb_getacl, METH_VARARGS,
+ "get_acl(path[, security_info=0]) -> security_descriptor object\n\n"
+ "\t\tGet security descriptor for file." },
+ { "set_acl", (PyCFunction)py_smb_setacl, METH_VARARGS,
+ "set_acl(path, security_descriptor[, security_info=0]) -> None\n\n"
+ "\t\tSet security descriptor for file." },
{ NULL, NULL, 0, NULL }
};
static PyTypeObject py_cli_state_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "libsmb.Conn",
+ .tp_name = "libsmb_samba_internal.Conn",
.tp_basicsize = sizeof(struct py_cli_state),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_doc = "libsmb connection",
{ NULL },
};
-void initlibsmb(void);
+void initlibsmb_samba_internal(void);
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
- .m_name = "libsmb",
+ .m_name = "libsmb_samba_internal",
.m_doc = "libsmb wrapper",
.m_size = -1,
.m_methods = py_libsmb_methods,
};
-MODULE_INIT_FUNC(libsmb)
+MODULE_INIT_FUNC(libsmb_samba_internal)
{
PyObject *m = NULL;
}
Py_INCREF(&py_cli_state_type);
PyModule_AddObject(m, "Conn", (PyObject *)&py_cli_state_type);
+
+#define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyInt_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);
+
return m;
}