summaryrefslogtreecommitdiffstats
path: root/libcli/smb/py_reparse_symlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcli/smb/py_reparse_symlink.c')
-rw-r--r--libcli/smb/py_reparse_symlink.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/libcli/smb/py_reparse_symlink.c b/libcli/smb/py_reparse_symlink.c
new file mode 100644
index 0000000..5626e27
--- /dev/null
+++ b/libcli/smb/py_reparse_symlink.c
@@ -0,0 +1,198 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2022
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lib/replace/system/python.h"
+#include "replace.h"
+#include "python/modules.h"
+#include "python/py3compat.h"
+#include "libcli/util/pyerrors.h"
+#include "reparse.h"
+#include "lib/util/iov_buf.h"
+#include "smb_constants.h"
+
+static PyObject *py_reparse_put(PyObject *module, PyObject *args)
+{
+ char *reparse = NULL;
+ Py_ssize_t reparse_len;
+ unsigned long long tag = 0;
+ unsigned reserved = 0;
+ uint8_t *buf = NULL;
+ ssize_t buflen;
+ PyObject *result = NULL;
+ struct reparse_data_buffer reparse_buf = {};
+ bool ok;
+
+ ok = PyArg_ParseTuple(
+ args,
+ "Kk"PYARG_BYTES_LEN":put",
+ &tag,
+ &reserved,
+ &reparse,
+ &reparse_len);
+ if (!ok) {
+ return NULL;
+ }
+
+ reparse_buf.tag = tag;
+ reparse_buf.parsed.raw.data = (uint8_t *)reparse;
+ reparse_buf.parsed.raw.length = reparse_len;
+ reparse_buf.parsed.raw.reserved = reserved;
+
+ buflen = reparse_data_buffer_marshall(&reparse_buf, NULL, 0);
+ if (buflen == -1) {
+ errno = EINVAL;
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+ buf = talloc_array(NULL, uint8_t, buflen);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ reparse_data_buffer_marshall(&reparse_buf, buf, buflen);
+
+ result = PyBytes_FromStringAndSize((char *)buf, buflen);
+ TALLOC_FREE(buf);
+ return result;
+}
+
+static PyObject *py_reparse_symlink_put(PyObject *module, PyObject *args)
+{
+ int unparsed = 0;
+ int flags = 0;
+ struct reparse_data_buffer reparse = {
+ .tag = IO_REPARSE_TAG_SYMLINK,
+ };
+ struct symlink_reparse_struct *lnk = &reparse.parsed.lnk;
+ uint8_t stackbuf[1024];
+ uint8_t *buf = stackbuf;
+ ssize_t buflen = sizeof(stackbuf);
+ PyObject *result = NULL;
+ bool ok;
+
+ ok = PyArg_ParseTuple(args,
+ "ssii:symlink_put",
+ &lnk->substitute_name,
+ &lnk->print_name,
+ &unparsed,
+ &flags);
+ if (!ok) {
+ return NULL;
+ }
+ lnk->unparsed_path_length = unparsed;
+ lnk->flags = flags;
+
+ buflen = reparse_data_buffer_marshall(&reparse, buf, buflen);
+
+ if ((buflen > 0) && ((size_t)buflen > sizeof(stackbuf))) {
+ buf = malloc(buflen);
+ buflen = reparse_data_buffer_marshall(&reparse, buf, buflen);
+ }
+
+ if (buflen == -1) {
+ PyErr_NoMemory();
+ } else {
+ result = PyBytes_FromStringAndSize((char *)buf, buflen);
+ }
+
+ if (buf != stackbuf) {
+ free(buf);
+ }
+
+ return result;
+}
+
+static PyObject *py_reparse_symlink_get(PyObject *module, PyObject *args)
+{
+ char *buf = NULL;
+ Py_ssize_t buflen;
+ struct reparse_data_buffer *syml = NULL;
+ struct symlink_reparse_struct *lnk = NULL;
+ PyObject *result = NULL;
+ NTSTATUS status;
+ bool ok;
+
+ ok = PyArg_ParseTuple(args, PYARG_BYTES_LEN ":get", &buf, &buflen);
+ if (!ok) {
+ return NULL;
+ }
+
+ syml = talloc(NULL, struct reparse_data_buffer);
+ if (syml == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ status = reparse_data_buffer_parse(syml, syml, (uint8_t *)buf, buflen);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(syml);
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ if (syml->tag != IO_REPARSE_TAG_SYMLINK) {
+ TALLOC_FREE(syml);
+ PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return NULL;
+ }
+ lnk = &syml->parsed.lnk;
+
+ result = Py_BuildValue("ssII",
+ lnk->substitute_name,
+ lnk->print_name,
+ (unsigned)lnk->unparsed_path_length,
+ (unsigned)lnk->flags);
+
+ TALLOC_FREE(syml);
+ return result;
+}
+
+static PyMethodDef py_reparse_symlink_methods[] = {
+ { "put",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_put),
+ METH_VARARGS,
+ "Create a reparse point blob"},
+ { "symlink_put",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_symlink_put),
+ METH_VARARGS,
+ "Create a reparse symlink blob"},
+ { "symlink_get",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_symlink_get),
+ METH_VARARGS,
+ "Parse a reparse symlink blob"},
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "reparse_symlink",
+ .m_doc = "[un]marshall reparse symlink blobs",
+ .m_size = -1,
+ .m_methods = py_reparse_symlink_methods,
+};
+
+MODULE_INIT_FUNC(reparse_symlink)
+{
+ PyObject *m;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}