The branch, master has been updated via 09f8d4ac81a tests: Start testing smb2 symlink error returns via 2e3e27f7e31 tests: Add nosymlinks_smb1allow share via 45091febd2a tests: Start testing reparsepoints via c58c826e43c pylibsmb: Add protocol() via c33f3a38686 pylibsmb: Add CreateDisposition values via 5907dff30ad pylibsmb: Add FSCTL codes via 7f63e98b95b libcli: Add python wappers to reparse_symlink.c via e7516fa9884 libsmb: Factor out reparse_buffer_marshall from symlink_reparse_buffer_marshall() via d79566c782f pylibsmb: Add fsctl() via 99730a59d5a pylibsmb: Add create options via 68a4be1edf7 pylibsmb: Add smb1_symlink() via 7d133943678 pylibsmb: Add smb1_readlink() via 98a627b93f4 pylibsmb: Add smb1_posix() to request smb1 posix extensions via 37784b86a06 pylibsmb: Pass symlink error to create_ex exception via 18d6334ca41 libsmb: Pass symlink error up through cli_smb2_create_fnum_recv() via 0c419b8a204 libsmb: Return symlink error struct from smb2cli_create_recv() via 218baae2d36 libsmb: Parse the smb2 symlink error response in smb2cli_create() via 3fbd4b27cb3 libsmb: Keep name_utf16 around in smb2cli_create() via f2c0f118fcc smbd: Pass unparsed_path_length to symlink_reparse_buffer_marshall() via 9e07a818124 smbd: Pass error_context_count through smbd_smb2_request_error_ex() via c14b8dc0aaf smbd: Factor out safe_symlink_target_path() via f71bdfbacbc tests: Fix an incorrect comment via b7fd2cf5bae libsmb: Add "DOMAIN" to authentication creds via c3d65f10c58 libsmb: Fix cli_fsctl() via fdb7e91df04 libsmb: Fix cli_smb2_fsctl_recv() via b4c45decd41 libsmb: Fix removing a rogue reparse point via 71789c7f6b2 pylibsmb: Add template code via b7d4b8eaac7 lib: Whitespace fixes via cb6d9e7b811 idl: Fix whitespace via 0789dd6959a libcli: Make "attr_strs" static via 9dddb9a2fc2 lib: Make lib/util/iov_buf.h self-contained via 9735498f60f pam_winbind: Fix a memleak from 59b5abbe8ce gp: Test PAM Access with DENY_ALL
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 09f8d4ac81a4b846ae472411cfaa9d8ee14c94c2 Author: Volker Lendecke <v...@samba.org> Date: Thu Oct 27 12:59:53 2022 +0200 tests: Start testing smb2 symlink error returns This still all fails, but if you run them against Windows they work. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue Nov 22 19:25:34 UTC 2022 on sn-devel-184 commit 2e3e27f7e313cee7a646f57e49e2b192282f40d4 Author: Volker Lendecke <v...@samba.org> Date: Thu Oct 27 12:48:59 2022 +0200 tests: Add nosymlinks_smb1allow share The next commits will create symlinks via posix extensions to test the smb2 symlink error return. Creating posix symlinks is not allowed with follow symlinks = no, but it's currently our only way to create symlinks over SMB. This could go away once we can create symlinks via reparse points. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 45091febd2aaeb9b030c8c14a4f44fe6e7f297bf Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 10 18:31:11 2022 +0100 tests: Start testing reparsepoints This still all fails, but if you run them against Windows they work. How to run: PYTHONPATH=bin/python \ LOCAL_PATH=/tmp \ SMB1_SHARE=share \ SMB2_SHARE=share \ SHARENAME=share \ SERVER_IP=<server-ip> \ DOMAIN=<your-domain> \ USERNAME=Administrator \ PASSWORD=<your-password> \ SMB_CONF_PATH=/usr/local/samba/etc/smb.conf \ SERVERCONFFILE="$SMB_CONF_PATH" \ python3 -m samba.subunit.run samba.tests.reparsepoints Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit c58c826e43c3b847b0cea3c8b6344274196506ca Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 3 16:42:12 2022 +0100 pylibsmb: Add protocol() Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit c33f3a386869cdeca59b02a51ba5781dd58c813c Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 3 16:39:44 2022 +0100 pylibsmb: Add CreateDisposition values Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 5907dff30adb9600235e757044fc75f3e5734dd6 Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 3 16:18:37 2022 +0100 pylibsmb: Add FSCTL codes Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 7f63e98b95b8a9b6c02762618ee0f4be30cafa79 Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 3 12:26:34 2022 +0100 libcli: Add python wappers to reparse_symlink.c Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit e7516fa9884dfa114703c1d532fa39dddd9bef47 Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 10 13:46:25 2022 +0100 libsmb: Factor out reparse_buffer_marshall from symlink_reparse_buffer_marshall() Make it easier to play with reparse points Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit d79566c782f308d470a6075593c3e8fb6b7bcad0 Author: Volker Lendecke <v...@samba.org> Date: Tue Nov 1 16:14:06 2022 +0100 pylibsmb: Add fsctl() Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 99730a59d5a35d5f91dee5343fd69a345a374d51 Author: Volker Lendecke <v...@samba.org> Date: Tue Sep 20 17:58:04 2022 +0200 pylibsmb: Add create options Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 68a4be1edf77aef3589c8ab1bfcc291fc8e3a70c Author: Volker Lendecke <v...@samba.org> Date: Tue Oct 18 16:55:53 2022 +0200 pylibsmb: Add smb1_symlink() Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 7d1339436786881514a006b33071a9cfe862e379 Author: Volker Lendecke <v...@samba.org> Date: Tue Oct 18 16:41:30 2022 +0200 pylibsmb: Add smb1_readlink() Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 98a627b93f475d2da9882db1abeb44f6ecad38cf Author: Volker Lendecke <v...@samba.org> Date: Sun Oct 16 19:41:58 2022 +0200 pylibsmb: Add smb1_posix() to request smb1 posix extensions Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 37784b86a06e92380a7935670afb0beda0e691df Author: Volker Lendecke <v...@samba.org> Date: Tue Sep 20 17:28:27 2022 +0200 pylibsmb: Pass symlink error to create_ex exception Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 18d6334ca4154649c66cb946834dc1b2588902df Author: Volker Lendecke <v...@samba.org> Date: Tue Sep 20 14:31:31 2022 +0200 libsmb: Pass symlink error up through cli_smb2_create_fnum_recv() Not passing through the sync wrapper yet. Not needed right now, and it's simple to add if required. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 0c419b8a204bd21e8991356ac88188c98bcfbb79 Author: Volker Lendecke <v...@samba.org> Date: Mon Oct 25 15:23:43 2021 +0200 libsmb: Return symlink error struct from smb2cli_create_recv() Looks larger than it is, this just adds a parameter and while there adapts long lines to README.Coding Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 218baae2d364dff581bb88ccd2a773e617ec8be8 Author: Volker Lendecke <v...@samba.org> Date: Wed Oct 26 13:58:56 2022 +0200 libsmb: Parse the smb2 symlink error response in smb2cli_create() Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 3fbd4b27cb32f2f93793b8c6c44eb5d37034fcf8 Author: Volker Lendecke <v...@samba.org> Date: Thu Oct 20 10:10:43 2022 +0200 libsmb: Keep name_utf16 around in smb2cli_create() This is needed to pass up the "unparsed" part of the smb2 symlink error response in unix charset form. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit f2c0f118fcccc19072639a7bccad673cc86dc5a6 Author: Volker Lendecke <v...@samba.org> Date: Fri Oct 14 17:12:26 2022 +0200 smbd: Pass unparsed_path_length to symlink_reparse_buffer_marshall() [MS-FSCC] 2.1.2.4 Symbolic Link Reparse Data Buffer lists this field as reserved, but [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response is the exact same format with the reserved field as UnparsedPathLength. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 9e07a8181247385a169e02adc184a03590d35573 Author: Volker Lendecke <v...@samba.org> Date: Fri Oct 14 16:23:30 2022 +0200 smbd: Pass error_context_count through smbd_smb2_request_error_ex() See [MS-SMB2] 2.2.2: This field MUST be set to 0 for SMB dialects other than 3.1.1. For the SMB dialect 3.1.1, if this field is nonzero, the ErrorData field MUST be formatted as a variable-length array of SMB2 ERROR Context structures containing ErrorContextCount entries. Not used right now yet, but once we start to return STOPPED_ON_SYMLINK properly this is required. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit c14b8dc0aaf2d095498072367d2ddfc247a283fe Author: Volker Lendecke <v...@samba.org> Date: Tue Oct 25 10:26:26 2022 +0200 smbd: Factor out safe_symlink_target_path() Small refactoring to make filename_convert_dirfsp() itself a bit shorter using a subroutine. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit f71bdfbacbcc4753f1cf5a254194b93f9b29d775 Author: Volker Lendecke <v...@samba.org> Date: Wed Nov 9 12:35:59 2022 +0100 tests: Fix an incorrect comment Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit b7fd2cf5bae6735c4b15d058159d7278ee091baa Author: Volker Lendecke <v...@samba.org> Date: Wed Nov 9 11:25:51 2022 +0100 libsmb: Add "DOMAIN" to authentication creds If you want to create symlinks on Windows using reparse points, you need to authenticate as local administrator, just "administrator" is not enough. So this is required to run some tests against Windows. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit c3d65f10c5863749b3b3ead5f178bbd1deb6f287 Author: Volker Lendecke <v...@samba.org> Date: Wed Nov 9 12:56:11 2022 +0100 libsmb: Fix cli_fsctl() Untested code is broken code. Found while testing symlinks over SMB1. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit fdb7e91df048b94a8755e5976b5c34401545c89c Author: Volker Lendecke <v...@samba.org> Date: Tue Nov 1 16:12:33 2022 +0100 libsmb: Fix cli_smb2_fsctl_recv() Untested code is broken code... data_blob_talloc() returns a NULL blob for NULL/0 input. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit b4c45decd410c6012b21eebb786bf252665570ad Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 10 17:40:22 2022 +0100 libsmb: Fix removing a rogue reparse point If you set a reparse point for which Windows server does not have a handler, it returns NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED when you later open it without FILE_OPEN_REPARSE_POINT. See the discussion thread starting with https://lists.samba.org/archive/cifs-protocol/2022-November/003888.html Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 71789c7f6b2d98219ae712ed810df86ebe4eda6a Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 3 12:37:58 2022 +0100 pylibsmb: Add template code I've looked this up in my samples too often :-) Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit b7d4b8eaac71e7af334d313d215139ed9bcaa7f8 Author: Volker Lendecke <v...@samba.org> Date: Wed Nov 9 10:15:31 2022 +0100 lib: Whitespace fixes Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit cb6d9e7b8118829b2996363050960837222396b8 Author: Volker Lendecke <v...@samba.org> Date: Wed Nov 2 13:24:22 2022 +0100 idl: Fix whitespace Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 0789dd6959a6f8fdc76ea6d706d494ab491add5b Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 10 11:22:13 2022 +0100 libcli: Make "attr_strs" static This saves 70 bytes of .text, we don't need this on the stack. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 9dddb9a2fc2943e835298976ad45ee4aff73330d Author: Volker Lendecke <v...@samba.org> Date: Thu Nov 10 13:42:01 2022 +0100 lib: Make lib/util/iov_buf.h self-contained We need "struct iovec", which comes in via sys/uio.h, incuded by system/filesys.h Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 9735498f60f83fd231ce20845db9288f4d343fe6 Author: Volker Lendecke <v...@samba.org> Date: Fri Nov 4 11:23:52 2022 +0100 pam_winbind: Fix a memleak Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: examples/fuse/clifuse.c | 26 +- lib/util/iov_buf.h | 1 + lib/util/ms_fnmatch.c | 22 +- libcli/smb/py_reparse_symlink.c | 165 +++++++ libcli/smb/reparse_symlink.c | 102 +++- libcli/smb/reparse_symlink.h | 18 +- libcli/smb/smb2cli_create.c | 270 ++++++++++- libcli/smb/smbXcli_base.h | 8 +- libcli/smb/smb_constants.h | 5 + libcli/smb/tstream_smbXcli_np.c | 12 +- libcli/smb/util.c | 2 +- libcli/smb/wscript | 6 + librpc/idl/mgmt.idl | 4 +- nsswitch/pam_winbind.c | 5 +- python/samba/tests/__init__.py | 2 +- python/samba/tests/libsmb.py | 1 + python/samba/tests/reparsepoints.py | 167 +++++++ python/samba/tests/smb2symlink.py | 166 +++++++ selftest/skip | 2 + selftest/target/Samba3.pm | 3 + source3/libsmb/cli_smb2_fnum.c | 64 ++- source3/libsmb/cli_smb2_fnum.h | 4 +- source3/libsmb/clifile.c | 5 +- source3/libsmb/clisymlink.c | 2 +- source3/libsmb/pylibsmb.c | 378 ++++++++++++++- source3/selftest/tests.py | 2 + source3/smbd/filename.c | 114 +++-- source3/smbd/globals.h | 3 +- source3/smbd/smb2_getinfo.c | 1 + source3/smbd/smb2_server.c | 2 + source3/torture/test_smb2.c | 910 ++++++++++++++++++++++-------------- 31 files changed, 1981 insertions(+), 491 deletions(-) create mode 100644 libcli/smb/py_reparse_symlink.c create mode 100644 python/samba/tests/reparsepoints.py create mode 100644 python/samba/tests/smb2symlink.py Changeset truncated at 500 lines: diff --git a/examples/fuse/clifuse.c b/examples/fuse/clifuse.c index f75a9f5a2d7..2d9edad5f47 100644 --- a/examples/fuse/clifuse.c +++ b/examples/fuse/clifuse.c @@ -178,7 +178,7 @@ static void cli_ll_create_done(struct tevent_req *req) uint16_t fnum; NTSTATUS status; - status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL); + status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL, NULL); TALLOC_FREE(req); if (!NT_STATUS_IS_OK(status)) { fuse_reply_err(state->freq, map_errno_from_nt_status(status)); @@ -267,8 +267,14 @@ static void cli_get_unixattr_opened(struct tevent_req *subreq) struct cli_state *cli = state->cli; NTSTATUS status; - status = smb2cli_create_recv(subreq, &state->fid_persistent, - &state->fid_volatile, NULL, NULL, NULL); + status = smb2cli_create_recv( + subreq, + &state->fid_persistent, + &state->fid_volatile, + NULL, + NULL, + NULL, + NULL); TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { DBG_DEBUG("smb2cli_create_recv returned %s\n", @@ -869,7 +875,7 @@ static void cli_ll_open_done(struct tevent_req *req) uint16_t fnum; NTSTATUS status; - status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL); + status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL, NULL); TALLOC_FREE(req); if (!NT_STATUS_IS_OK(status)) { fuse_reply_err(state->freq, map_errno_from_nt_status(status)); @@ -1174,10 +1180,14 @@ static void cli_ll_opendir_done(struct tevent_req *req) req, struct ll_opendir_state); NTSTATUS status; - status = smb2cli_create_recv(req, - &state->dir_state->fid_persistent, - &state->dir_state->fid_volatile, - NULL, NULL, NULL); + status = smb2cli_create_recv( + req, + &state->dir_state->fid_persistent, + &state->dir_state->fid_volatile, + NULL, + NULL, + NULL, + NULL); TALLOC_FREE(req); DEBUG(10, ("%s: smbcli_create_recv returned %s\n", __func__, diff --git a/lib/util/iov_buf.h b/lib/util/iov_buf.h index 79b81b84779..07e08e1650b 100644 --- a/lib/util/iov_buf.h +++ b/lib/util/iov_buf.h @@ -22,6 +22,7 @@ #include "replace.h" #include <talloc.h> +#include "system/filesys.h" ssize_t iov_buflen(const struct iovec *iov, int iovlen); ssize_t iov_buf(const struct iovec *iov, int iovcnt, diff --git a/lib/util/ms_fnmatch.c b/lib/util/ms_fnmatch.c index e43d4e0a3be..90aab13ec90 100644 --- a/lib/util/ms_fnmatch.c +++ b/lib/util/ms_fnmatch.c @@ -1,4 +1,4 @@ -/* +/* Unix SMB/CIFS implementation. filename matching routine Copyright (C) Andrew Tridgell 1992-2004 @@ -7,21 +7,21 @@ 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/>. + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* This module was originally based on fnmatch.c copyright by the Free Software Foundation. It bears little (if any) resemblence to that code now -*/ +*/ /** * @file @@ -59,7 +59,7 @@ struct max_n { an optimisation only. The ldot pointer is NULL if the string does not contain a '.', otherwise it points at the last dot in 'n'. */ -static int ms_fnmatch_core(const char *p, const char *n, +static int ms_fnmatch_core(const char *p, const char *n, struct max_n *max_n, const char *ldot, bool is_case_sensitive) { @@ -168,11 +168,11 @@ static int ms_fnmatch_core(const char *p, const char *n, break; } } - + if (! *n) { return 0; } - + return -1; } @@ -205,12 +205,12 @@ int ms_fnmatch_protocol(const char *pattern, const char *string, int protocol, for (i=0;p[i];i++) { if (p[i] == '?') { p[i] = '>'; - } else if (p[i] == '.' && - (p[i+1] == '?' || + } else if (p[i] == '.' && + (p[i+1] == '?' || p[i+1] == '*' || p[i+1] == 0)) { p[i] = '"'; - } else if (p[i] == '*' && + } else if (p[i] == '*' && p[i+1] == '.') { p[i] = '<'; } diff --git a/libcli/smb/py_reparse_symlink.c b/libcli/smb/py_reparse_symlink.c new file mode 100644 index 00000000000..57dc6032f99 --- /dev/null +++ b/libcli/smb/py_reparse_symlink.c @@ -0,0 +1,165 @@ +/* + * 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 <Python.h> +#include "replace.h" +#include "python/modules.h" +#include "python/py3compat.h" +#include "reparse_symlink.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; + struct iovec iov; + uint8_t *buf = NULL; + ssize_t buflen; + PyObject *result = NULL; + bool ok; + + ok = PyArg_ParseTuple( + args, + "Kk"PYARG_BYTES_LEN":put", + &tag, + &reserved, + &reparse, + &reparse_len); + if (!ok) { + return NULL; + } + iov = (struct iovec) { + .iov_base = reparse, .iov_len = reparse_len, + }; + + buflen = reparse_buffer_marshall(tag, reserved, &iov, 1, 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_buffer_marshall(tag, reserved, &iov, 1, buf, buflen); + + result = PyBytes_FromStringAndSize((char *)buf, buflen); + TALLOC_FREE(buf); + return result; +} + +static PyObject *py_reparse_symlink_put(PyObject *module, PyObject *args) +{ + char *substitute = NULL; + char *printname = NULL; + int unparsed = 0; + int flags = 0; + uint8_t *buf = NULL; + size_t buflen; + PyObject *result = NULL; + bool ok; + + ok = PyArg_ParseTuple( + args, + "ssii:symlink_put", + &substitute, + &printname, + &unparsed, + &flags); + if (!ok) { + return NULL; + } + + ok = symlink_reparse_buffer_marshall( + substitute, printname, unparsed, flags, NULL, &buf, &buflen); + if (!ok) { + PyErr_NoMemory(); + return false; + } + + result = PyBytes_FromStringAndSize((char *)buf, buflen); + TALLOC_FREE(buf); + return result; +} + +static PyObject *py_reparse_symlink_get(PyObject *module, PyObject *args) +{ + char *buf = NULL; + Py_ssize_t buflen; + struct symlink_reparse_struct *syml = NULL; + PyObject *result = NULL; + bool ok; + + ok = PyArg_ParseTuple(args, PYARG_BYTES_LEN ":get", &buf, &buflen); + if (!ok) { + return NULL; + } + + syml = symlink_reparse_buffer_parse(NULL, (uint8_t *)buf, buflen); + if (syml == NULL) { + PyErr_NoMemory(); + return NULL; + } + + result = Py_BuildValue( + "ssII", + syml->substitute_name, + syml->print_name, + (unsigned)syml->unparsed_path_length, + (unsigned)syml->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; +} diff --git a/libcli/smb/reparse_symlink.c b/libcli/smb/reparse_symlink.c index 04f26dc1162..51570b563e4 100644 --- a/libcli/smb/reparse_symlink.c +++ b/libcli/smb/reparse_symlink.c @@ -28,12 +28,52 @@ #include "libcli/smb/smb_util.h" #include "lib/util/debug.h" +ssize_t reparse_buffer_marshall( + uint32_t reparse_tag, + uint16_t reserved, + const struct iovec *iov, + int iovlen, + uint8_t *buf, + size_t buflen) +{ + ssize_t reparse_data_length = iov_buflen(iov, iovlen); + size_t needed; + + if (reparse_data_length == -1) { + return -1; + } + if (reparse_data_length > UINT16_MAX) { + return -1; + } + + needed = reparse_data_length + 8; + if (needed < reparse_data_length) { + return -1; + } + + if (buflen >= needed) { + PUSH_LE_U32(buf, 0, reparse_tag); + PUSH_LE_U16(buf, 4, reparse_data_length); + PUSH_LE_U16(buf, 6, reserved); + iov_buf(iov, iovlen, buf+8, buflen-8); + } + + return needed; +} + bool symlink_reparse_buffer_marshall( - const char *substitute, const char *printname, uint32_t flags, - TALLOC_CTX *mem_ctx, uint8_t **pdst, size_t *pdstlen) + const char *substitute, + const char *printname, + uint16_t unparsed_path_length, + uint32_t flags, + TALLOC_CTX *mem_ctx, + uint8_t **pdst, + size_t *pdstlen) { + uint8_t sbuf[12]; + struct iovec iov[3]; uint8_t *dst = NULL; - size_t dst_len; + ssize_t dst_len; uint8_t *subst_utf16 = NULL; uint8_t *print_utf16 = NULL; size_t subst_len = 0; @@ -48,6 +88,8 @@ bool symlink_reparse_buffer_marshall( printname = substitute; } + iov[0] = (struct iovec) { .iov_base = sbuf, .iov_len = sizeof(sbuf), }; + ok = convert_string_talloc( mem_ctx, CH_UNIX, @@ -59,6 +101,12 @@ bool symlink_reparse_buffer_marshall( 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( mem_ctx, @@ -71,36 +119,42 @@ bool symlink_reparse_buffer_marshall( if (!ok) { goto fail; } - - dst_len = subst_len + 20; - if (dst_len < 20) { + if (print_len > UINT16_MAX) { goto fail; } - dst_len += print_len; - if (dst_len < print_len) { + 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, flags); /* Flags */ + + dst_len = reparse_buffer_marshall( + IO_REPARSE_TAG_SYMLINK, + unparsed_path_length, + iov, + ARRAY_SIZE(iov), + NULL, + 0); + if (dst_len == -1) { goto fail; } + dst = talloc_array(mem_ctx, uint8_t, dst_len); if (dst == NULL) { goto fail; } - SIVAL(dst, 0, IO_REPARSE_TAG_SYMLINK); /* ReparseTag */ - SSVAL(dst, 4, 12 + subst_len + print_len); /* ReparseDataLength */ - SSVAL(dst, 6, 0); /* Reserved */ - SSVAL(dst, 8, 0); /* SubstituteNameOffset */ - SSVAL(dst, 10, subst_len); /* SubstituteNameLength */ - SSVAL(dst, 12, subst_len); /* PrintNameOffset */ - SSVAL(dst, 14, print_len); /* PrintNameLength */ - SIVAL(dst, 16, flags); /* Flags */ - - if ((subst_utf16 != NULL) && (subst_len != 0)) { - memcpy(dst + 20, subst_utf16, subst_len); - } - - if ((print_utf16 != NULL) && (print_len != 0)) { - memcpy(dst + 20 + subst_len, print_utf16, print_len); - } + reparse_buffer_marshall( + IO_REPARSE_TAG_SYMLINK, + unparsed_path_length, + iov, + ARRAY_SIZE(iov), + dst, + dst_len); *pdst = dst; *pdstlen = dst_len; diff --git a/libcli/smb/reparse_symlink.h b/libcli/smb/reparse_symlink.h index b561fa9fc98..2f57a592eec 100644 --- a/libcli/smb/reparse_symlink.h +++ b/libcli/smb/reparse_symlink.h @@ -25,6 +25,7 @@ #include "replace.h" #include <talloc.h> +#include "lib/util/iov_buf.h" struct symlink_reparse_struct { uint16_t unparsed_path_length; /* reserved for the reparse point */ @@ -33,9 +34,22 @@ struct symlink_reparse_struct { uint32_t flags; }; +ssize_t reparse_buffer_marshall( + uint32_t reparse_tag, + uint16_t reserved, + const struct iovec *iov, + int iovlen, + uint8_t *buf, + size_t buflen); + bool symlink_reparse_buffer_marshall( - const char *substitute, const char *printname, uint32_t flags, - TALLOC_CTX *mem_ctx, uint8_t **pdst, size_t *pdstlen); + const char *substitute, + const char *printname, + uint16_t unparsed_path_length, + uint32_t flags, + 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); diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c -- Samba Shared Repository