mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
pylibsmb: Add create_ex()
This is an extension of the create() function allowing smb2 create contexts to be passed back and forth and also returning the smb_create_returns. A new function seemed necessary for me because we need to return not just the fnum. So I chose a 3-tuple, see the test for an example how to use this. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
parent
68ba30215d
commit
cb0381ddc6
@ -140,6 +140,18 @@ class LibsmbTestCase(samba.tests.TestCase):
|
||||
except:
|
||||
pass
|
||||
|
||||
def test_libsmb_CreateContexts(self):
|
||||
(lp,creds) = self.prep_creds()
|
||||
c = libsmb.Conn(os.getenv("SERVER_IP"), "tmp", lp, creds)
|
||||
cc_in = [(libsmb.SMB2_CREATE_TAG_MXAC, b'')]
|
||||
fnum,cr,cc = c.create_ex("",CreateContexts=cc_in)
|
||||
self.assertEqual(
|
||||
cr['file_attributes'] & libsmb.FILE_ATTRIBUTE_DIRECTORY,
|
||||
libsmb.FILE_ATTRIBUTE_DIRECTORY)
|
||||
self.assertEqual(cc[0][0],libsmb.SMB2_CREATE_TAG_MXAC)
|
||||
self.assertEqual(len(cc[0][1]),8)
|
||||
c.close(fnum)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import unittest
|
||||
unittest.main()
|
||||
|
@ -837,6 +837,349 @@ static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
|
||||
return Py_BuildValue("I", (unsigned)fnum);
|
||||
}
|
||||
|
||||
static struct smb2_create_blobs *py_cli_get_create_contexts(
|
||||
TALLOC_CTX *mem_ctx, PyObject *list)
|
||||
{
|
||||
struct smb2_create_blobs *ctxs = NULL;
|
||||
Py_ssize_t i, len;
|
||||
int ret;
|
||||
|
||||
ret = PyList_Check(list);
|
||||
if (!ret) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
len = PyList_Size(list);
|
||||
if (len == 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ctxs = talloc_zero(mem_ctx, struct smb2_create_blobs);
|
||||
if (ctxs == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
NTSTATUS status;
|
||||
|
||||
PyObject *t = NULL;
|
||||
Py_ssize_t tlen;
|
||||
|
||||
PyObject *pname = NULL;
|
||||
char *name = NULL;
|
||||
|
||||
PyObject *pdata = NULL;
|
||||
DATA_BLOB data = { .data = NULL, };
|
||||
|
||||
t = PyList_GetItem(list, i);
|
||||
if (t == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = PyTuple_Check(t);
|
||||
if (!ret) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tlen = PyTuple_Size(t);
|
||||
if (tlen != 2) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pname = PyTuple_GetItem(t, 0);
|
||||
if (pname == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
ret = PyBytes_Check(pname);
|
||||
if (!ret) {
|
||||
goto fail;
|
||||
}
|
||||
name = PyBytes_AsString(pname);
|
||||
|
||||
pdata = PyTuple_GetItem(t, 1);
|
||||
if (pdata == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
ret = PyBytes_Check(pdata);
|
||||
if (!ret) {
|
||||
goto fail;
|
||||
}
|
||||
data = (DATA_BLOB) {
|
||||
.data = (uint8_t *)PyBytes_AsString(pdata),
|
||||
.length = PyBytes_Size(pdata),
|
||||
};
|
||||
status = smb2_create_blob_add(ctxs, ctxs, name, data);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return ctxs;
|
||||
|
||||
fail:
|
||||
TALLOC_FREE(ctxs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *py_cli_create_contexts(const struct smb2_create_blobs *blobs)
|
||||
{
|
||||
PyObject *py_blobs = NULL;
|
||||
PyObject *py_blob = NULL;
|
||||
PyObject *tmp = NULL;
|
||||
uint32_t i;
|
||||
|
||||
if (blobs == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
py_blobs = PyList_New(blobs->num_blobs);
|
||||
if (py_blobs == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i=0; i<blobs->num_blobs; i++) {
|
||||
struct smb2_create_blob *blob = &blobs->blobs[i];
|
||||
int ret;
|
||||
|
||||
py_blob = PyTuple_New(2);
|
||||
if (py_blob == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
tmp = PyBytes_FromString(blob->tag);
|
||||
if (tmp == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
ret = PyTuple_SetItem(py_blob, 0, tmp);
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tmp = PyBytes_FromStringAndSize(
|
||||
(char *)blob->data.data, blob->data.length);
|
||||
if (tmp == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
ret = PyTuple_SetItem(py_blob, 1, tmp);
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = PyList_SetItem(py_blobs, i, py_blob);
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return py_blobs;
|
||||
|
||||
nomem:
|
||||
PyErr_NoMemory();
|
||||
fail:
|
||||
Py_XDECREF(tmp);
|
||||
Py_XDECREF(py_blob);
|
||||
Py_XDECREF(py_blobs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool pydict_setnum(PyObject *dict, const char *key, uint64_t num)
|
||||
{
|
||||
PyObject *py_num = NULL;
|
||||
int ret;
|
||||
|
||||
py_num = PyLong_FromLong(num);
|
||||
if (py_num == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = PyDict_SetItemString(dict, key, py_num);
|
||||
Py_CLEAR(py_num);
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
static PyObject *py_cli_create_returns(const struct smb_create_returns *r)
|
||||
{
|
||||
PyObject *v = NULL;
|
||||
bool ok = true;
|
||||
|
||||
v = PyDict_New();
|
||||
if (v == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ok &= pydict_setnum(v, "oplock_level", r->oplock_level);
|
||||
ok &= pydict_setnum(v, "create_action", r->create_action);
|
||||
ok &= pydict_setnum(v, "creation_time", r->creation_time);
|
||||
ok &= pydict_setnum(v, "last_access_time", r->last_access_time);
|
||||
ok &= pydict_setnum(v, "last_write_time", r->last_write_time);
|
||||
ok &= pydict_setnum(v, "change_time", r->change_time);
|
||||
ok &= pydict_setnum(v, "allocation_size", r->allocation_size);
|
||||
ok &= pydict_setnum(v, "end_of_file", r->end_of_file);
|
||||
ok &= pydict_setnum(v, "file_attributes", r->file_attributes);
|
||||
|
||||
if (!ok) {
|
||||
Py_CLEAR(v);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static PyObject *py_cli_create_ex(
|
||||
struct py_cli_state *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *fname = NULL;
|
||||
unsigned CreateFlags = 0;
|
||||
unsigned DesiredAccess = FILE_GENERIC_READ;
|
||||
unsigned FileAttributes = 0;
|
||||
unsigned ShareAccess = 0;
|
||||
unsigned CreateDisposition = FILE_OPEN;
|
||||
unsigned CreateOptions = 0;
|
||||
unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
|
||||
unsigned SecurityFlags = 0;
|
||||
PyObject *py_create_contexts_in = NULL;
|
||||
PyObject *py_create_contexts_out = NULL;
|
||||
struct smb2_create_blobs *create_contexts_in = NULL;
|
||||
struct smb2_create_blobs create_contexts_out = { .num_blobs = 0 };
|
||||
struct smb_create_returns cr = { .create_action = 0, };
|
||||
PyObject *py_cr = NULL;
|
||||
uint16_t fnum;
|
||||
struct tevent_req *req;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
bool ok;
|
||||
PyObject *v = NULL;
|
||||
|
||||
static const char *kwlist[] = {
|
||||
"Name",
|
||||
"CreateFlags",
|
||||
"DesiredAccess",
|
||||
"FileAttributes",
|
||||
"ShareAccess",
|
||||
"CreateDisposition",
|
||||
"CreateOptions",
|
||||
"ImpersonationLevel",
|
||||
"SecurityFlags",
|
||||
"CreateContexts",
|
||||
NULL };
|
||||
|
||||
ret = ParseTupleAndKeywords(
|
||||
args,
|
||||
kwds,
|
||||
"s|IIIIIIIIO",
|
||||
kwlist,
|
||||
&fname,
|
||||
&CreateFlags,
|
||||
&DesiredAccess,
|
||||
&FileAttributes,
|
||||
&ShareAccess,
|
||||
&CreateDisposition,
|
||||
&CreateOptions,
|
||||
&ImpersonationLevel,
|
||||
&SecurityFlags,
|
||||
&py_create_contexts_in);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (py_create_contexts_in != NULL) {
|
||||
create_contexts_in = py_cli_get_create_contexts(
|
||||
NULL, py_create_contexts_in);
|
||||
if (create_contexts_in == NULL) {
|
||||
errno = EINVAL;
|
||||
PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
|
||||
req = cli_smb2_create_fnum_send(
|
||||
NULL,
|
||||
self->ev,
|
||||
self->cli,
|
||||
fname,
|
||||
CreateFlags,
|
||||
ImpersonationLevel,
|
||||
DesiredAccess,
|
||||
FileAttributes,
|
||||
ShareAccess,
|
||||
CreateDisposition,
|
||||
CreateOptions,
|
||||
create_contexts_in);
|
||||
} else {
|
||||
req = cli_ntcreate_send(
|
||||
NULL,
|
||||
self->ev,
|
||||
self->cli,
|
||||
fname,
|
||||
CreateFlags,
|
||||
DesiredAccess,
|
||||
FileAttributes,
|
||||
ShareAccess,
|
||||
CreateDisposition,
|
||||
CreateOptions,
|
||||
ImpersonationLevel,
|
||||
SecurityFlags);
|
||||
}
|
||||
|
||||
TALLOC_FREE(create_contexts_in);
|
||||
|
||||
ok = py_tevent_req_wait_exc(self, req);
|
||||
if (!ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
|
||||
status = cli_smb2_create_fnum_recv(
|
||||
req, &fnum, &cr, NULL, &create_contexts_out);
|
||||
} else {
|
||||
status = cli_ntcreate_recv(req, &fnum, &cr);
|
||||
}
|
||||
|
||||
TALLOC_FREE(req);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
py_create_contexts_out = py_cli_create_contexts(&create_contexts_out);
|
||||
TALLOC_FREE(create_contexts_out.blobs);
|
||||
if (py_create_contexts_out == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
py_cr = py_cli_create_returns(&cr);
|
||||
if (py_cr == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
v = PyTuple_New(3);
|
||||
if (v == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
ret = PyTuple_SetItem(v, 0, Py_BuildValue("I", (unsigned)fnum));
|
||||
if (ret == -1) {
|
||||
status = NT_STATUS_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
ret = PyTuple_SetItem(v, 1, py_cr);
|
||||
if (ret == -1) {
|
||||
status = NT_STATUS_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
ret = PyTuple_SetItem(v, 2, py_create_contexts_out);
|
||||
if (ret == -1) {
|
||||
status = NT_STATUS_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return v;
|
||||
nomem:
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
fail:
|
||||
Py_XDECREF(py_create_contexts_out);
|
||||
Py_XDECREF(py_cr);
|
||||
Py_XDECREF(v);
|
||||
PyErr_SetNTSTATUS(status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
|
||||
{
|
||||
struct tevent_req *req;
|
||||
@ -1921,6 +2264,10 @@ static PyMethodDef py_cli_state_methods[] = {
|
||||
{ "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
|
||||
METH_VARARGS|METH_KEYWORDS,
|
||||
"Open a file" },
|
||||
{ "create_ex",
|
||||
PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create_ex),
|
||||
METH_VARARGS|METH_KEYWORDS,
|
||||
"Open a file, SMB2 version returning create contexts" },
|
||||
{ "close", (PyCFunction)py_cli_close, METH_VARARGS,
|
||||
"Close a file handle" },
|
||||
{ "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
|
||||
|
Loading…
Reference in New Issue
Block a user