libcli: Make symlink_reparse_buffer_parse() more flexible
authorVolker Lendecke <vl@samba.org>
Thu, 6 Jul 2023 14:19:06 +0000 (16:19 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 10 Aug 2023 13:40:31 +0000 (13:40 +0000)
Allow the destination struct to be preallocated

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
libcli/smb/py_reparse_symlink.c
libcli/smb/reparse_symlink.c
libcli/smb/reparse_symlink.h
libcli/smb/smb2cli_create.c
source3/libsmb/clisymlink.c

index 57dc6032f99bca8a95cdba456b11e7a5392248fc..b998b2e27a151acf0214cabfd8a890244274bbae 100644 (file)
@@ -104,8 +104,11 @@ static PyObject *py_reparse_symlink_get(PyObject *module, PyObject *args)
 {
        char *buf = NULL;
        Py_ssize_t buflen;
-       struct symlink_reparse_struct *syml = NULL;
+       struct symlink_reparse_struct syml = {
+               .flags = 0,
+       };
        PyObject *result = NULL;
+       int ret;
        bool ok;
 
        ok = PyArg_ParseTuple(args, PYARG_BYTES_LEN ":get", &buf, &buflen);
@@ -113,19 +116,21 @@ static PyObject *py_reparse_symlink_get(PyObject *module, PyObject *args)
                return NULL;
        }
 
-       syml = symlink_reparse_buffer_parse(NULL, (uint8_t *)buf, buflen);
-       if (syml == NULL) {
-               PyErr_NoMemory();
+       ret = symlink_reparse_buffer_parse(NULL, &syml, (uint8_t *)buf, buflen);
+       if (ret != 0) {
+               errno = ret;
+               PyErr_SetFromErrno(PyExc_RuntimeError);
                return NULL;
        }
 
-       result = Py_BuildValue(
-               "ssII",
-               syml->substitute_name,
-               syml->print_name,
-               (unsigned)syml->unparsed_path_length,
-               (unsigned)syml->flags);
-       TALLOC_FREE(syml);
+       result = Py_BuildValue("ssII",
+                              syml.substitute_name,
+                              syml.print_name,
+                              (unsigned)syml.unparsed_path_length,
+                              (unsigned)syml.flags);
+
+       TALLOC_FREE(syml.print_name);
+       TALLOC_FREE(syml.substitute_name);
        return result;
 }
 
index 51570b563e44609c142aefb4828d19ea3e7c081e..2871974cbdc750cd26d51701d782f894f629acce 100644 (file)
@@ -166,10 +166,11 @@ fail:
        return ret;
 }
 
-struct symlink_reparse_struct *symlink_reparse_buffer_parse(
-       TALLOC_CTX *mem_ctx, const uint8_t *src, size_t srclen)
+int symlink_reparse_buffer_parse(TALLOC_CTX *mem_ctx,
+                                struct symlink_reparse_struct *dst,
+                                const uint8_t *src,
+                                size_t srclen)
 {
-       struct symlink_reparse_struct *result = NULL;
        uint16_t reparse_data_length;
        uint16_t substitute_name_offset, substitute_name_length;
        uint16_t print_name_offset, print_name_length;
@@ -177,13 +178,13 @@ struct symlink_reparse_struct *symlink_reparse_buffer_parse(
 
        if (srclen < 20) {
                DBG_DEBUG("srclen = %zu, expected >= 20\n", srclen);
-               goto fail;
+               return EINVAL;
        }
        if (IVAL(src, 0) != IO_REPARSE_TAG_SYMLINK) {
                DBG_DEBUG("Got ReparseTag %8.8x, expected %8.8x\n",
                          IVAL(src, 0),
                          IO_REPARSE_TAG_SYMLINK);
-               goto fail;
+               return EINVAL;
        }
 
        reparse_data_length     = SVAL(src, 4);
@@ -195,14 +196,14 @@ struct symlink_reparse_struct *symlink_reparse_buffer_parse(
        if (reparse_data_length < 12) {
                DBG_DEBUG("reparse_data_length = %"PRIu16", expected >= 12\n",
                          reparse_data_length);
-               goto fail;
+               return EINVAL;
        }
        if (smb_buffer_oob(srclen - 8, reparse_data_length, 0)) {
                DBG_DEBUG("reparse_data_length (%"PRIu16") too large for "
                           "src_len (%zu)\n",
                          reparse_data_length,
                          srclen);
-               goto fail;
+               return EINVAL;
        }
        if (smb_buffer_oob(reparse_data_length - 12, substitute_name_offset,
                           substitute_name_length)) {
@@ -211,7 +212,7 @@ struct symlink_reparse_struct *symlink_reparse_buffer_parse(
                          substitute_name_offset,
                          substitute_name_length,
                          reparse_data_length - 12);
-               goto fail;
+               return EINVAL;
        }
        if (smb_buffer_oob(reparse_data_length - 12, print_name_offset,
                           print_name_length)) {
@@ -220,47 +221,41 @@ struct symlink_reparse_struct *symlink_reparse_buffer_parse(
                          print_name_offset,
                          print_name_length,
                          reparse_data_length - 12);
-               goto fail;
+               return EINVAL;
        }
 
-       result = talloc_zero(mem_ctx, struct symlink_reparse_struct);
-       if (result == NULL) {
-               DBG_DEBUG("talloc failed\n");
-               goto fail;
-       }
+       *dst = (struct symlink_reparse_struct) {
+               .unparsed_path_length = PULL_LE_U16(src, 6),
+               .flags = PULL_LE_U32(src, 16),
+       };
 
-       ok = convert_string_talloc(
-               result,
-               CH_UTF16,
-               CH_UNIX,
-               src + 20 + substitute_name_offset,
-               substitute_name_length,
-               &result->substitute_name,
-               NULL);
+       ok = convert_string_talloc(mem_ctx,
+                                  CH_UTF16,
+                                  CH_UNIX,
+                                  src + 20 + substitute_name_offset,
+                                  substitute_name_length,
+                                  &dst->substitute_name,
+                                  NULL);
        if (!ok) {
+               int ret = errno;
                DBG_DEBUG("convert_string_talloc for substitute_name "
                          "failed\n");
-               goto fail;
+               return ret;
        }
 
-       ok = convert_string_talloc(
-               result,
-               CH_UTF16,
-               CH_UNIX,
-               src + 20 + print_name_offset,
-               print_name_length,
-               &result->print_name,
-               NULL);
+       ok = convert_string_talloc(mem_ctx,
+                                  CH_UTF16,
+                                  CH_UNIX,
+                                  src + 20 + print_name_offset,
+                                  print_name_length,
+                                  &dst->print_name,
+                                  NULL);
        if (!ok) {
+               int ret = errno;
                DBG_DEBUG("convert_string_talloc for print_name failed\n");
-               goto fail;
+               TALLOC_FREE(dst->substitute_name);
+               return ret;
        }
 
-       result->unparsed_path_length = SVAL(src, 6);
-       result->flags = IVAL(src, 16);
-
-       return result;
-fail:
-       TALLOC_FREE(result);
-       return NULL;
+       return 0;
 }
index 2f57a592eec57379627d912798fdd9a16bc585a7..0718f34395dce8254b5e8d246f3025f7668de413 100644 (file)
@@ -50,7 +50,9 @@ bool symlink_reparse_buffer_marshall(
        TALLOC_CTX *mem_ctx,
        uint8_t **pdst,
        size_t *pdstlen);
-struct symlink_reparse_struct *symlink_reparse_buffer_parse(
-       TALLOC_CTX *mem_ctx, const uint8_t *src, size_t srclen);
+int symlink_reparse_buffer_parse(TALLOC_CTX *mem_ctx,
+                                struct symlink_reparse_struct *dst,
+                                const uint8_t *src,
+                                size_t srclen);
 
 #endif
index dbad297a3f076f4523901018beb4019ddf2fa4d3..1197eec28aeffc36aafde2514d78cad5bca57c4a 100644 (file)
@@ -198,6 +198,7 @@ static NTSTATUS smb2cli_parse_symlink_error_response(
 {
        struct symlink_reparse_struct *symlink = NULL;
        uint32_t symlink_length, error_tag;
+       int ret;
 
        if (buflen < 8) {
                DBG_DEBUG("buffer too short: %zu bytes\n", buflen);
@@ -219,10 +220,15 @@ static NTSTATUS smb2cli_parse_symlink_error_response(
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
-       symlink = symlink_reparse_buffer_parse(
-               mem_ctx, buf+8, buflen-8);
+       symlink = talloc(mem_ctx, struct symlink_reparse_struct);
        if (symlink == NULL) {
-               DBG_DEBUG("symlink_reparse_buffer_parse failed\n");
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ret = symlink_reparse_buffer_parse(
+               symlink, symlink, buf+8, buflen-8);
+       if (ret != 0) {
+               DBG_DEBUG("symlink_reparse_buffer_parse failed: %s\n", strerror(ret));
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
index 12d644eb68dbfd67ef45d519829758aa29b4bfd5..1155526f96d5fdf457968e0de5d3f665f466d7b9 100644 (file)
@@ -368,8 +368,9 @@ NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 {
        struct cli_readlink_state *state = tevent_req_data(
                req, struct cli_readlink_state);
-       struct symlink_reparse_struct *symlink = NULL;
+       struct symlink_reparse_struct symlink = { .flags = 0, };
        NTSTATUS status;
+       int ret;
 
        if (tevent_req_is_nterror(req, &status)) {
                return status;
@@ -392,26 +393,27 @@ NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                return NT_STATUS_OK;
        }
 
-       symlink = symlink_reparse_buffer_parse(
-               talloc_tos(), state->data, state->num_data);
-       if (symlink == NULL) {
+       ret = symlink_reparse_buffer_parse(
+               talloc_tos(), &symlink, state->data, state->num_data);
+       if (ret != 0) {
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
        if (psubstitute_name != NULL) {
                *psubstitute_name = talloc_move(
-                       mem_ctx, &symlink->substitute_name);
+                       mem_ctx, &symlink.substitute_name);
        }
 
        if (pprint_name != NULL) {
-               *pprint_name = talloc_move(mem_ctx, &symlink->print_name);
+               *pprint_name = talloc_move(mem_ctx, &symlink.print_name);
        }
 
        if (pflags != NULL) {
-               *pflags = symlink->flags;
+               *pflags = symlink.flags;
        }
 
-       TALLOC_FREE(symlink);
+       TALLOC_FREE(symlink.print_name);
+       TALLOC_FREE(symlink.substitute_name);
 
        return NT_STATUS_OK;
 }