diff options
-rw-r--r-- | python/samba/tests/reparsepoints.py | 167 | ||||
-rw-r--r-- | selftest/skip | 1 | ||||
-rwxr-xr-x | source3/selftest/tests.py | 1 |
3 files changed, 169 insertions, 0 deletions
diff --git a/python/samba/tests/reparsepoints.py b/python/samba/tests/reparsepoints.py new file mode 100644 index 00000000000..07abdb03975 --- /dev/null +++ b/python/samba/tests/reparsepoints.py @@ -0,0 +1,167 @@ +# Unix SMB/CIFS implementation. +# Copyright Volker Lendecke <vl@samba.org> 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/>. +# + +from samba.samba3 import libsmb_samba_internal as libsmb +from samba import (ntstatus,NTSTATUSError) +from samba.dcerpc import security as sec +from samba import reparse_symlink +import samba.tests.libsmb + +class ReparsePoints(samba.tests.libsmb.LibsmbTests): + + def connection(self): + share = samba.tests.env_get_var_value("SHARENAME") + smb1 = samba.tests.env_get_var_value("SMB1", allow_missing=True) + conn = libsmb.Conn( + self.server_ip, + share, + self.lp, + self.creds, + force_smb1=smb1) + return conn + + def clean_file(self, conn, filename): + try: + conn.unlink(filename) + except NTSTATUSError as e: + err = e.args[0] + ok = (err == ntstatus.NT_STATUS_OBJECT_NAME_NOT_FOUND) + ok |= (err == ntstatus.NT_STATUS_OBJECT_PATH_NOT_FOUND) + if not ok: + raise + + def test_error_not_a_reparse_point(self): + conn = self.connection() + filename = 'reparse' + self.clean_file(conn, filename) + + fd = conn.create( + filename, + DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE, + CreateDisposition=libsmb.FILE_CREATE) + + with self.assertRaises(NTSTATUSError) as e: + conn.fsctl(fd, libsmb.FSCTL_GET_REPARSE_POINT, b'', 1024) + self.assertEqual(e.args[0], ntstatus.NT_STATUS_NOT_A_REPARSE_POINT) + + conn.close(fd) + + self.clean_file(conn, filename) + + def test_create_reparse(self): + conn = self.connection() + filename = 'reparse' + self.clean_file(conn, filename) + + fd = conn.create( + filename, + DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE, + CreateDisposition=libsmb.FILE_CREATE) + b = reparse_symlink.put(0x80000025, 0, b'asdfasdfasdfasdfasdfasdf') + conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0) + b = reparse_symlink.put(0x80000026, 0, b'asdfasdfasdfasdfasdfasdf') + conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0) + + # Show that directories can carry reparse points + + def test_create_reparse_directory(self): + conn = self.connection() + dirname = "reparse_dir" + + self.clean_file(conn, dirname) + + fd = conn.create( + dirname, + DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE| + sec.SEC_STD_DELETE, + CreateDisposition=libsmb.FILE_CREATE, + CreateOptions=libsmb.FILE_DIRECTORY_FILE) + b = reparse_symlink.put(0x80000025, 0, b'asdfasdfasdfasdfasdfasdf') + conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0) + conn.delete_on_close(fd, 1) + + # Only empty directories can carry reparse points + + def test_create_reparse_nonempty_directory(self): + conn = self.connection() + dirname = "reparse_dir" + filename = f'{dirname}\\file.txt' + + self.clean_file(conn, filename) + self.clean_file(conn, dirname) + + dir_fd = conn.create( + dirname, + DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE| + sec.SEC_STD_DELETE, + CreateDisposition=libsmb.FILE_CREATE, + CreateOptions=libsmb.FILE_DIRECTORY_FILE) + fd = conn.create( + filename, + DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE| + sec.SEC_STD_DELETE, + CreateDisposition=libsmb.FILE_CREATE) + + b = reparse_symlink.put(0x80000025, 0, b'asdf') + try: + conn.fsctl(dir_fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0) + except NTSTATUSError as e: + err = e.args[0] + ok = (err == ntstatus.NT_STATUS_DIRECTORY_NOT_EMPTY) + if not ok: + raise + + conn.delete_on_close(fd, 1) + conn.close(fd) + conn.delete_on_close(dir_fd, 1) + conn.close(dir_fd) + + # Show that reparse point opens respect share modes + + def test_reparse_share_modes(self): + conn = self.connection() + filename = 'reparse' + self.clean_file(conn, filename) + + fd = conn.create( + filename, + DesiredAccess=sec.SEC_FILE_WRITE_ATTRIBUTE, + CreateDisposition=libsmb.FILE_CREATE) + b = reparse_symlink.put(0x80000025, 0, b'asdfasdfasdfasdfasdfasdf') + conn.fsctl(fd, libsmb.FSCTL_SET_REPARSE_POINT, b, 0) + conn.close(fd); + + fd1 = conn.create( + filename, + DesiredAccess=sec.SEC_FILE_READ_DATA|sec.SEC_STD_DELETE, + CreateDisposition=libsmb.FILE_OPEN, + CreateOptions=libsmb.FILE_OPEN_REPARSE_POINT) + + with self.assertRaises(NTSTATUSError) as e: + fd2 = conn.create( + filename, + DesiredAccess=sec.SEC_FILE_READ_DATA, + CreateDisposition=libsmb.FILE_OPEN, + CreateOptions=libsmb.FILE_OPEN_REPARSE_POINT) + self.assertEqual(e.args[0], ntstatus.NT_STATUS_SHARING_VIOLATION) + + conn.delete_on_close(fd1, 1); + conn.close(fd1) + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/selftest/skip b/selftest/skip index d5cc786f8a5..321a09e988b 100644 --- a/selftest/skip +++ b/selftest/skip @@ -148,3 +148,4 @@ bench # don't run benchmarks in our selftest ^samba4.smb2.mangle.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test ^samba4.smb2.tcon.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test ^samba4.smb2.mkdir.*\(ad_dc_ntvfs\)$ # Ignore ad_dc_ntvfs since this is a new test +^samba.tests.reparsepoints.* diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index f6cc6e0c639..dceed0e0072 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -1687,3 +1687,4 @@ for t in CLUSTERED_LOCAL_TESTS: "-N 1000 -o 2000"]) planpythontestsuite("fileserver", "samba.tests.smb3unix") +planpythontestsuite("fileserver", "samba.tests.reparsepoints") |