From: Volker Lendecke Date: Thu, 21 Sep 2023 11:27:34 +0000 (-0700) Subject: libsmb: Add reparse_data_buffer_marshall() X-Git-Tag: tevent-0.16.0~522 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ddc1f56cf1a6e7b9f2e07b72fbe842c3de3122a4;p=thirdparty%2Fsamba.git libsmb: Add reparse_data_buffer_marshall() Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- diff --git a/libcli/smb/reparse.c b/libcli/smb/reparse.c index 1c4ad444bfc..77ef7fb715b 100644 --- a/libcli/smb/reparse.c +++ b/libcli/smb/reparse.c @@ -17,10 +17,12 @@ #include "replace.h" #include "libcli/smb/reparse.h" +#include "libcli/smb/reparse_symlink.h" #include "libcli/smb/smb_constants.h" #include "libcli/util/error.h" #include "lib/util/debug.h" #include "lib/util/bytearray.h" +#include "lib/util/talloc_stack.h" #include "lib/util/charset/charset.h" #include "smb_util.h" @@ -346,3 +348,187 @@ char *reparse_data_buffer_str(TALLOC_CTX *mem_ctx, } return s; } + +static ssize_t +reparse_data_buffer_marshall_syml(const struct symlink_reparse_struct *src, + uint8_t *buf, + size_t buflen) +{ + uint8_t sbuf[12]; + struct iovec iov[3]; + uint8_t *subst_utf16 = NULL; + uint8_t *print_utf16 = NULL; + size_t subst_len = 0; + size_t print_len = 0; + ssize_t ret = -1; + bool ok; + + if (src->substitute_name == NULL) { + return -1; + } + if (src->print_name == NULL) { + return -1; + } + + iov[0] = (struct iovec){ + .iov_base = sbuf, + .iov_len = sizeof(sbuf), + }; + + ok = convert_string_talloc(talloc_tos(), + CH_UNIX, + CH_UTF16, + src->substitute_name, + strlen(src->substitute_name), + &subst_utf16, + &subst_len); + if (!ok) { + goto fail; + } + if (subst_len > UINT16_MAX) { + goto fail; + } + iov[1] = (struct iovec){ + .iov_base = subst_utf16, + .iov_len = subst_len, + }; + + ok = convert_string_talloc(talloc_tos(), + CH_UNIX, + CH_UTF16, + src->print_name, + strlen(src->print_name), + &print_utf16, + &print_len); + if (!ok) { + goto fail; + } + if (print_len > UINT16_MAX) { + goto fail; + } + iov[2] = (struct iovec){ + .iov_base = print_utf16, + .iov_len = print_len, + }; + + PUSH_LE_U16(sbuf, 0, 0); /* SubstituteNameOffset */ + PUSH_LE_U16(sbuf, 2, subst_len); /* SubstituteNameLength */ + PUSH_LE_U16(sbuf, 4, subst_len); /* PrintNameOffset */ + PUSH_LE_U16(sbuf, 6, print_len); /* PrintNameLength */ + PUSH_LE_U32(sbuf, 8, src->flags); /* Flags */ + + ret = reparse_buffer_marshall(IO_REPARSE_TAG_SYMLINK, + src->unparsed_path_length, + iov, + ARRAY_SIZE(iov), + buf, + buflen); + +fail: + TALLOC_FREE(subst_utf16); + TALLOC_FREE(print_utf16); + return ret; +} + +static ssize_t +reparse_data_buffer_marshall_nfs(const struct nfs_reparse_data_buffer *src, + uint8_t *buf, + size_t buflen) +{ + uint8_t typebuf[8]; + uint8_t devbuf[8]; + struct iovec iov[2] = {}; + size_t iovlen; + uint8_t *lnk_utf16 = NULL; + size_t lnk_len = 0; + ssize_t ret; + + PUSH_LE_U64(typebuf, 0, src->type); + iov[0] = (struct iovec){ + .iov_base = typebuf, + .iov_len = sizeof(typebuf), + }; + iovlen = 1; + + switch (src->type) { + case NFS_SPECFILE_LNK: { + bool ok = convert_string_talloc(talloc_tos(), + CH_UNIX, + CH_UTF16, + src->data.lnk_target, + strlen(src->data.lnk_target), + &lnk_utf16, + &lnk_len); + if (!ok) { + return -1; + } + iov[1] = (struct iovec){ + .iov_base = lnk_utf16, + .iov_len = lnk_len, + }; + iovlen = 2; + break; + } + case NFS_SPECFILE_CHR: + FALL_THROUGH; + case NFS_SPECFILE_BLK: + PUSH_LE_U32(devbuf, 0, src->data.dev.major); + PUSH_LE_U32(devbuf, 4, src->data.dev.minor); + iov[1] = (struct iovec){ + .iov_base = devbuf, + .iov_len = sizeof(devbuf), + }; + iovlen = 2; + break; + default: + break; + /* Nothing to do for NFS_SPECFILE_FIFO and _SOCK */ + } + + ret = reparse_buffer_marshall(IO_REPARSE_TAG_NFS, + 0, + iov, + iovlen, + buf, + buflen); + TALLOC_FREE(lnk_utf16); + return ret; +} + +ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src, + uint8_t *buf, + size_t buflen) +{ + ssize_t ret = -1; + + switch (src->tag) { + case IO_REPARSE_TAG_SYMLINK: + + ret = reparse_data_buffer_marshall_syml(&src->parsed.lnk, + buf, + buflen); + break; + + case IO_REPARSE_TAG_NFS: + + ret = reparse_data_buffer_marshall_nfs(&src->parsed.nfs, + buf, + buflen); + break; + + default: { + struct iovec iov = { + .iov_base = src->parsed.raw.data, + .iov_len = src->parsed.raw.length, + }; + ret = reparse_buffer_marshall(src->tag, + src->parsed.raw.reserved, + &iov, + 1, + buf, + buflen); + } + } + + return ret; +} diff --git a/libcli/smb/reparse.h b/libcli/smb/reparse.h index aeeaf116eba..1e593272a66 100644 --- a/libcli/smb/reparse.h +++ b/libcli/smb/reparse.h @@ -70,4 +70,8 @@ NTSTATUS reparse_data_buffer_parse(TALLOC_CTX *mem_ctx, char *reparse_data_buffer_str(TALLOC_CTX *mem_ctx, const struct reparse_data_buffer *dst); +ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src, + uint8_t *buf, + size_t buflen); + #endif