diff -Nru samba-4.19.4+dfsg/VERSION samba-4.19.5+dfsg/VERSION --- samba-4.19.4+dfsg/VERSION 2024-01-08 14:34:28.197466000 +0000 +++ samba-4.19.5+dfsg/VERSION 2024-02-19 10:42:54.150189400 +0000 @@ -27,7 +27,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=19 -SAMBA_VERSION_RELEASE=4 +SAMBA_VERSION_RELEASE=5 ######################################################## # If a official release has a serious bug # diff -Nru samba-4.19.4+dfsg/WHATSNEW.txt samba-4.19.5+dfsg/WHATSNEW.txt --- samba-4.19.4+dfsg/WHATSNEW.txt 2024-01-08 14:34:28.197466000 +0000 +++ samba-4.19.5+dfsg/WHATSNEW.txt 2024-02-19 10:42:54.150189400 +0000 @@ -1,4 +1,67 @@ ============================== + Release Notes for Samba 4.19.5 + February 19, 2024 + ============================== + + +This is the latest stable release of the Samba 4.19 release series. + + +Changes since 4.19.4 +-------------------- + +o Ralph Boehme + * BUG 13688: Windows 2016 fails to restore previous version of a file from a + shadow_copy2 snapshot. + * BUG 15549: Symlinks on AIX are broken in 4.19 (and a few version before + that). + +o Bjoern Jacke + * BUG 12421: Fake directory create times has no effect. + +o Björn Jacke + * BUG 15550: ctime mixed up with mtime by smbd. + +o David Mulder + * BUG 15548: samba-gpupdate --rsop fails if machine is not in a site. + +o Gabriel Nagy + * BUG 15557: gpupdate: The root cert import when NDES is not available is + broken. + +o Andreas Schneider + * BUG 15552: samba-gpupdate should print a useful message if cepces-submit + can't be found. + * BUG 15558: samba-gpupdate logging doesn't work. + +o Jones Syue + * BUG 15555: smbpasswd reset permissions only if not 0600. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical:matrix.org matrix room, or +#samba-technical IRC channel on irc.libera.chat. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the Samba 4.1 and newer product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + ============================== Release Notes for Samba 4.19.4 January 08, 2024 ============================== @@ -78,8 +141,7 @@ ====================================================================== -Release notes for older releases follow: ----------------------------------------- +---------------------------------------------------------------------- ============================== Release Notes for Samba 4.19.3 November 27, 2023 diff -Nru samba-4.19.4+dfsg/debian/changelog samba-4.19.5+dfsg/debian/changelog --- samba-4.19.4+dfsg/debian/changelog 2024-02-03 13:14:42.000000000 +0000 +++ samba-4.19.5+dfsg/debian/changelog 2024-02-25 17:45:54.000000000 +0000 @@ -1,3 +1,52 @@ +samba (2:4.19.5+dfsg-1ubuntu1) noble; urgency=medium + + * Merge with Debian unstable (LP: #2054592). Remaining changes: + - debian/control: Ubuntu i386 binary compatibility: + + enable the liburing vfs module, except on i386 where liburing is + not available + - d/t/control, d/t/util,d/t/samba-ad-dc-provisioning-internal-dns: + samba AD DC provisioning and domain join tests with internal DNS + (LP #1977746, LP #2011745) + - d/control: adjust breaks/replaces for file move that Debian did in + 4.16.6+dfsg-5, and Ubuntu only did in 4.17.7+dfsg-1ubuntu1, to avoid + file conflict in a dist-upgrade from earlier Ubuntu releases, like + Kinetic (LP #2024663) + - d/control: python3-samba has a runtime dep on python3-markdown + - glusterfs is no longer in main, create new binary package in + universe to ship the samba glusterfs vfs modules and manpages + (LP #2045063): + + d/control: new samba-vfs-modules-glusterfs package + + d/rules: glusterfs vfs modules and manpages are now in the + samba-vfs-modules-extra package + + d/samba-vfs-modules-extra.install: add glusterfs vfs modules and + manpage + - d/t/util: handle breakage introduced by lxd-installer. If on + Ubuntu, assume lxd comes from a snap and install it if needed + - d/t/util: ignore cloud-init's warning exit status, which is + happening because of LP #2048129 (also see LP #2048522) + + -- Andreas Hasenack Sun, 25 Feb 2024 14:45:54 -0300 + +samba (2:4.19.5+dfsg-1) unstable; urgency=medium + + * new upstream stable/bugfix release (4.19.5) + * reformat previous changelog entry to fit in 80cols + * d/winbind.postrm: stop recursively removing plain files + * d/winbind.postrm: winbindd_cache.tdb is in /var/lib now, + not in /var/cache + * d/control: RulesRequiresRoot:no + * d/*.symbols: use #PACKAGE# placeholders where appropriate + (or add comments where it is not) + * +silence-can-not-convert-group-sid.diff - + make another log message less annoying + * -python-fix-invalid-escape-sequences.patch (applied upstream) + * d/control: replace pkg-config=>pkgconf in Build-Depends, remove + pkg-config from Depends of libldb-dev and python3-ldb-dev + * d/samba-libs.symbols, d/control: make libsmbldapN a virtual package + provided by samba-libs too, like libndrN + + -- Michael Tokarev Mon, 19 Feb 2024 15:21:14 +0300 + samba (2:4.19.4+dfsg-3ubuntu1) noble; urgency=medium * Merge with Debian unstable (LP: #2051717). Remaining changes: @@ -31,10 +80,10 @@ samba (2:4.19.4+dfsg-3) unstable; urgency=medium * samba,winbind: remove logrotate scripts - samba does its own log rotation (max log size (=5000 by default) and renaming - to .old). The two clashes with each other in an interesting way. - * d/samba-libs.symbols, d/control: make libndrN a virtual package to ensure rdeps - pick the right dependency + samba does its own log rotation (max log size (=5000 by default) and + renaming to .old). The two clashes with each other in an interesting way. + * d/samba-libs.symbols, d/control: make libndrN a virtual package + to ensure rdeps pick the right dependency -- Michael Tokarev Tue, 30 Jan 2024 12:12:42 +0300 diff -Nru samba-4.19.4+dfsg/debian/control samba-4.19.5+dfsg/debian/control --- samba-4.19.4+dfsg/debian/control 2024-02-03 13:14:42.000000000 +0000 +++ samba-4.19.5+dfsg/debian/control 2024-02-25 17:45:54.000000000 +0000 @@ -28,7 +28,7 @@ libtdb-dev (>= 1.4.9~), python3-tdb (>= 1.4.9~), # system libraries: - pkg-config, + pkgconf, libacl1-dev, libarchive-dev, libavahi-client-dev, @@ -76,7 +76,7 @@ # python3-iso8601 , # python3-pyasn1 , # tdb-tools , -Rules-Requires-Root: binary-targets +Rules-Requires-Root: no Vcs-Browser: https://salsa.debian.org/samba-team/samba Vcs-Git: https://salsa.debian.org/samba-team/samba.git @@ -131,7 +131,7 @@ Multi-Arch: same Architecture: any Section: libs -Provides: libndr3 (= ${binary:Version}) +Provides: libndr3 (= ${binary:Version}), libsmbldap2 (= ${binary:Version}) Depends: ${misc:Depends}, ${shlibs:Depends}, # since libldb ABI is incorrectly versioned resulting in breakage like #1021371, # just require libldb version of the same build @@ -609,7 +609,6 @@ libtalloc-dev, libtevent-dev, libtdb-dev, - pkg-config, ${misc:Depends} Description: LDAP-like embedded database - development files ldb is a LDAP-like embedded database built on top of TDB. @@ -639,7 +638,6 @@ Architecture: any Depends: libc6-dev, libldb-dev, - pkg-config, python3-ldb (= ${binary:Version}), ${misc:Depends} Description: LDB Python 3 bindings - development files diff -Nru samba-4.19.4+dfsg/debian/libsmbclient.symbols samba-4.19.5+dfsg/debian/libsmbclient.symbols --- samba-4.19.4+dfsg/debian/libsmbclient.symbols 2023-12-12 17:37:55.000000000 +0000 +++ samba-4.19.5+dfsg/debian/libsmbclient.symbols 2024-02-25 17:43:52.000000000 +0000 @@ -1,4 +1,4 @@ -libsmbclient.so.0 libsmbclient #MINVER# +libsmbclient.so.0 #PACKAGE# #MINVER# * Build-Depends-Package: libsmbclient-dev SMBCLIENT_0.1.0@SMBCLIENT_0.1.0 2:4.0.3+dfsg1 SMBCLIENT_0.2.0@SMBCLIENT_0.2.0 2:4.0.3+dfsg1 diff -Nru samba-4.19.4+dfsg/debian/libwbclient0.symbols samba-4.19.5+dfsg/debian/libwbclient0.symbols --- samba-4.19.4+dfsg/debian/libwbclient0.symbols 2024-01-05 13:28:31.000000000 +0000 +++ samba-4.19.5+dfsg/debian/libwbclient0.symbols 2024-02-25 17:43:52.000000000 +0000 @@ -1,4 +1,4 @@ -libwbclient.so.0 libwbclient0 #MINVER# +libwbclient.so.0 #PACKAGE# #MINVER# * Build-Depends-Package: libwbclient-dev WBCLIENT_0.9@WBCLIENT_0.9 2:4.0.3+dfsg1 WBCLIENT_0.10@WBCLIENT_0.10 2:4.0.3+dfsg1 diff -Nru samba-4.19.4+dfsg/debian/patches/python-fix-invalid-escape-sequences.patch samba-4.19.5+dfsg/debian/patches/python-fix-invalid-escape-sequences.patch --- samba-4.19.4+dfsg/debian/patches/python-fix-invalid-escape-sequences.patch 2024-01-30 16:37:18.000000000 +0000 +++ samba-4.19.5+dfsg/debian/patches/python-fix-invalid-escape-sequences.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,296 +0,0 @@ -Origin: upstream, https://gitlab.com/samba-team/samba/-/commit/b068592dd0dccce634cb17b66f0659ba60523908 -From: Joseph Sutton -Date: Fri, 25 Aug 2023 13:56:21 +1200 -Subject: python: Fix invalid escape sequences -Comment: mjt: remove 1 hunk from python/samba/tests/gpo.py not present in 4.19 -Bug-Debian: https://bugs.debian.org/1057668 - -Signed-off-by: Joseph Sutton -Reviewed-by: Andrew Bartlett ---- - python/samba/gp/gp_cert_auto_enroll_ext.py | 6 +- - python/samba/graph.py | 2 +- - python/samba/tests/gpo.py | 66 +++++++++++----------- - python/samba/tests/samba_tool/gpo.py | 2 +- - 4 files changed, 38 insertions(+), 38 deletions(-) - -diff --git a/python/samba/gp/gp_cert_auto_enroll_ext.py b/python/samba/gp/gp_cert_auto_enroll_ext.py -index d626aca0cf2..14fef311348 100644 ---- a/python/samba/gp/gp_cert_auto_enroll_ext.py -+++ b/python/samba/gp/gp_cert_auto_enroll_ext.py -@@ -335,7 +335,7 @@ def cert_enroll(ca, ldb, trust_dir, private_dir, auth='Kerberos'): - - class gp_cert_auto_enroll_ext(gp_pol_ext, gp_applier): - def __str__(self): -- return 'Cryptography\AutoEnrollment' -+ return r'Cryptography\AutoEnrollment' - - def unapply(self, guid, attribute, value): - ca_cn = base64.b64decode(attribute) -@@ -387,7 +387,7 @@ class gp_cert_auto_enroll_ext(gp_pol_ext, gp_applier): - - for gpo in changed_gpo_list: - if gpo.file_sys_path: -- section = 'Software\Policies\Microsoft\Cryptography\AutoEnrollment' -+ section = r'Software\Policies\Microsoft\Cryptography\AutoEnrollment' - pol_file = 'MACHINE/Registry.pol' - path = os.path.join(gpo.file_sys_path, pol_file) - pol_conf = self.parse(path) -@@ -507,7 +507,7 @@ class gp_cert_auto_enroll_ext(gp_pol_ext, gp_applier): - def rsop(self, gpo): - output = {} - pol_file = 'MACHINE/Registry.pol' -- section = 'Software\Policies\Microsoft\Cryptography\AutoEnrollment' -+ section = r'Software\Policies\Microsoft\Cryptography\AutoEnrollment' - if gpo.file_sys_path: - path = os.path.join(gpo.file_sys_path, pol_file) - pol_conf = self.parse(path) -diff --git a/python/samba/graph.py b/python/samba/graph.py -index 537dc661fb3..4c4a07f47ae 100644 ---- a/python/samba/graph.py -+++ b/python/samba/graph.py -@@ -192,7 +192,7 @@ def compile_graph_key(key_items, nodes_above=None, elisions=None, - short = short[1:] - long = long[1:] - elision_str += ('\nelision%d[shape=plaintext; style=solid; ' -- 'label="\“%s” means “%s”\\r"]\n' -+ 'label="\\“%s” means “%s”\\r"]\n' - % ((i, short, long))) - - above_lines = [] -diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py -index 2b6217b702f..d59cb06b565 100644 ---- a/python/samba/tests/gpo.py -+++ b/python/samba/tests/gpo.py -@@ -123,7 +123,7 @@ dspath = 'CN=Policies,CN=System,' + base_dn - gpt_data = '[General]\nVersion=%d' - - gnome_test_reg_pol = \ --b""" -+br""" - - - -@@ -260,7 +260,7 @@ b""" - """ - - auto_enroll_reg_pol = \ --b""" -+br""" - - - -@@ -304,7 +304,7 @@ b""" - """ - - advanced_enroll_reg_pol = \ --b""" -+br""" - - - -@@ -338,122 +338,122 @@ b""" - 0 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 - URL - LDAP: - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 - PolicyID - %s - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 - FriendlyName - Example - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 - Flags - 16 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 - AuthFlags - 2 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 - Cost - 2147483645 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe -+ Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe - URL - https://example2.com/ADPolicyProvider_CEP_Certificate/service.svc/CEP - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe -+ Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe - PolicyID - %s - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe -+ Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe - FriendlyName - Example2 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe -+ Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe - Flags - 16 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe -+ Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe - AuthFlags - 8 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe -+ Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe - Cost - 10 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 - URL - https://example0.com/ADPolicyProvider_CEP_Kerberos/service.svc/CEP - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 - PolicyID - %s - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 - FriendlyName - Example0 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 - Flags - 16 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 - AuthFlags - 2 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 -+ Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 - Cost - 1 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac -+ Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac - URL - https://example1.com/ADPolicyProvider_CEP_Kerberos/service.svc/CEP - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac -+ Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac - PolicyID - %s - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac -+ Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac - FriendlyName - Example1 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac -+ Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac - Flags - 16 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac -+ Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac - AuthFlags - 2 - - -- Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac -+ Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac - Cost - 1 - -@@ -2116,7 +2116,7 @@ firefox_json_expected = \ - """ - - chromium_reg_pol = \ --b""" -+br""" - - - -@@ -3012,12 +3012,12 @@ b""" - - Software\Policies\Google\Chrome - RestrictSigninToPattern -- .*@example\\.com -+ .*@example\.com - - - Software\Policies\Google\Chrome - RoamingProfileLocation -- ${roaming_app_data}\\chrome-profile -+ ${roaming_app_data}\chrome-profile - - - Software\Policies\Google\Chrome -@@ -3267,7 +3267,7 @@ b""" - - Software\Policies\Google\Chrome\AlternativeBrowserParameters - 5 -- %HOME%\\browser_profile -+ %HOME%\browser_profile - - - Software\Policies\Google\Chrome\AudioCaptureAllowedUrls -@@ -4973,7 +4973,7 @@ b""" - """ - - firewalld_reg_pol = \ --b""" -+br""" - - - -diff --git a/python/samba/tests/samba_tool/gpo.py b/python/samba/tests/samba_tool/gpo.py -index 70e7e8acdf0..f5adccb88a1 100644 ---- a/python/samba/tests/samba_tool/gpo.py -+++ b/python/samba/tests/samba_tool/gpo.py -@@ -1804,7 +1804,7 @@ class GpoCmdTestCase(SambaToolCmdTest): - 'The test cse was not enabled') - self.assertIn('UserPolicy : False', out, - 'The test cse should not have User policy enabled') -- cse_ext = re.findall('^UniqueGUID\s+:\s+(.*)', out) -+ cse_ext = re.findall(r'^UniqueGUID\s+:\s+(.*)', out) - self.assertEquals(len(cse_ext), 1, - 'The test cse GUID was not found') - cse_ext = cse_ext[0] --- -2.39.2 - diff -Nru samba-4.19.4+dfsg/debian/patches/series samba-4.19.5+dfsg/debian/patches/series --- samba-4.19.4+dfsg/debian/patches/series 2024-01-30 16:37:18.000000000 +0000 +++ samba-4.19.5+dfsg/debian/patches/series 2024-02-25 17:43:52.000000000 +0000 @@ -22,4 +22,4 @@ meaningful-error-if-no-samba-ad-provision.patch meaningful-error-if-no-python3-markdown.patch ctdb-use-run-instead-of-var-run.patch -python-fix-invalid-escape-sequences.patch +silence-can-not-convert-group-sid.diff diff -Nru samba-4.19.4+dfsg/debian/patches/silence-can-not-convert-group-sid.diff samba-4.19.5+dfsg/debian/patches/silence-can-not-convert-group-sid.diff --- samba-4.19.4+dfsg/debian/patches/silence-can-not-convert-group-sid.diff 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.19.5+dfsg/debian/patches/silence-can-not-convert-group-sid.diff 2024-02-25 17:43:52.000000000 +0000 @@ -0,0 +1,26 @@ +From: Michael Tokarev +Date: Wed, 14 Feb 2024 15:26:29 +0300 +Subject: silence "Can not convert group sid" warnings in the log +Forwarded: yes + +/var/log/samba/log.winbind is full of messages like: + +[2024/02/09 06:25:04.788182, 1, pid=74620] source3/winbindd/winbindd_getgroups.c:259(winbindd_getgroups_recv) + Could not convert sid S-0-0: NT_STATUS_NONE_MAPPED + +On a busy server these are logged several 1000s times per minute, +making any other messages basically invisible. + +Signed-off-by: Michael Tokarev + +diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c +index c2603cc7026..f252e14bf95 100644 +--- a/source3/winbindd/winbindd_getgroups.c ++++ b/source3/winbindd/winbindd_getgroups.c +@@ -257,5 +257,5 @@ NTSTATUS winbindd_getgroups_recv(struct tevent_req *req, + if (tevent_req_is_nterror(req, &status)) { + struct dom_sid_buf buf; +- D_WARNING("Could not convert sid %s: %s\n", ++ D_DEBUG("Could not convert sid %s: %s\n", + dom_sid_str_buf(&state->sid, &buf), + nt_errstr(status)); diff -Nru samba-4.19.4+dfsg/debian/python3-ldb.symbols.in samba-4.19.5+dfsg/debian/python3-ldb.symbols.in --- samba-4.19.4+dfsg/debian/python3-ldb.symbols.in 2024-01-30 16:37:18.000000000 +0000 +++ samba-4.19.5+dfsg/debian/python3-ldb.symbols.in 2024-02-25 17:43:52.000000000 +0000 @@ -1,4 +1,4 @@ -#libpyldb-util${DEB_PY3_EXTENSION_SUFFIX}.2 python3-ldb #MINVER# +#libpyldb-util${DEB_PY3_EXTENSION_SUFFIX}.2 #PACKAGE# #MINVER# # PYLDB_UTIL${DEB_PY3_EXTENSION_UPCASE}_2.5.0@PYLDB_UTIL${DEB_PY3_EXTENSION_UPCASE}_2.5.0 2:2.5.0 PYLDB_UTIL_1.1.2@PYLDB_UTIL_1.1.2 2:2.2.0 PYLDB_UTIL_1.1.3@PYLDB_UTIL_1.1.3 2:2.0.7 diff -Nru samba-4.19.4+dfsg/debian/rules samba-4.19.5+dfsg/debian/rules --- samba-4.19.4+dfsg/debian/rules 2024-01-30 17:12:45.000000000 +0000 +++ samba-4.19.5+dfsg/debian/rules 2024-02-25 17:43:52.000000000 +0000 @@ -336,7 +336,7 @@ { \ suff=$$(${DEB_HOST_MULTIARCH}-python3-config --extension-suffix | tr _ -); \ SUFF=$$(echo "$${suff%.so}" | tr a-z- A-Z_); \ - echo "libpyldb-util$${suff}.2 python3-ldb #MINVER#"; \ + echo "libpyldb-util$${suff}.2 #PACKAGE# #MINVER#"; \ echo "* Build-Depends-Package: python3-ldb-dev" ; \ echo " PYLDB_UTIL$${SUFF}_${LDB_VERSION}@PYLDB_UTIL$${SUFF}_${LDB_VERSION} ${LDB_EPOCH}${LDB_VERSION}"; \ cat debian/python3-ldb.symbols.in; \ diff -Nru samba-4.19.4+dfsg/debian/samba-libs.symbols samba-4.19.5+dfsg/debian/samba-libs.symbols --- samba-4.19.4+dfsg/debian/samba-libs.symbols 2024-01-30 17:12:45.000000000 +0000 +++ samba-4.19.5+dfsg/debian/samba-libs.symbols 2024-02-25 17:43:52.000000000 +0000 @@ -1,3 +1,4 @@ +# libndrN is a virtual package provided by samba-libs libndr.so.3 libndr3 #MINVER# * Build-Depends-Package: samba-dev GUID_all_zero@NDR_0.0.1 2:4.17.2 @@ -294,7 +295,8 @@ ndr_transfer_syntax_ndr@NDR_0.0.1 2:4.17.2 ndr_zero_memory@NDR_0.2.0 2:4.17.2 -libsmbldap.so.2 #PACKAGE# #MINVER# +# libsmbldapN is a virtual package provided by samba-libs +libsmbldap.so.2 libsmbldap2 #MINVER# * Build-Depends-Package: samba-dev SMBLDAP_0@SMBLDAP_0 2:4.16.6 SMBLDAP_1@SMBLDAP_1 2:4.16.6 diff -Nru samba-4.19.4+dfsg/debian/winbind.postrm samba-4.19.5+dfsg/debian/winbind.postrm --- samba-4.19.4+dfsg/debian/winbind.postrm 2023-09-11 17:28:56.000000000 +0000 +++ samba-4.19.5+dfsg/debian/winbind.postrm 2024-02-25 17:43:52.000000000 +0000 @@ -2,11 +2,13 @@ set -e if [ "$1" = purge ]; then - winbindd_privileged_socket_directory='/var/lib/samba/winbindd_privileged' - rm -rf /var/cache/samba/netsamlogon_cache.tdb /var/cache/samba/winbindd_cache.tdb - rm -rf "$winbindd_privileged_socket_directory" - rm -rf /var/log/samba/log.winbind* /var/log/samba/log.wb* - rm -rf /run/samba/winbindd.pid + rm -rf /var/lib/samba/winbindd_privileged/ + rm -f \ + /var/cache/samba/netsamlogon_cache.tdb \ + /var/lib/samba/winbindd_cache.tdb \ + /var/log/samba/log.winbind* \ + /var/log/samba/log.wb* \ + /run/samba/winbindd.pid fi #DEBHELPER# diff -Nru samba-4.19.4+dfsg/lib/util/time.c samba-4.19.5+dfsg/lib/util/time.c --- samba-4.19.4+dfsg/lib/util/time.c 2023-07-18 08:14:54.530091300 +0000 +++ samba-4.19.5+dfsg/lib/util/time.c 2024-02-19 10:42:54.158189300 +0000 @@ -1450,7 +1450,7 @@ { struct timespec ret; - ret.tv_sec = pst->st_mtime; + ret.tv_sec = pst->st_ctime; ret.tv_nsec = get_ctimensec(pst); return ret; } diff -Nru samba-4.19.4+dfsg/python/samba/gp/gp_cert_auto_enroll_ext.py samba-4.19.5+dfsg/python/samba/gp/gp_cert_auto_enroll_ext.py --- samba-4.19.4+dfsg/python/samba/gp/gp_cert_auto_enroll_ext.py 2023-07-18 08:14:54.618091800 +0000 +++ samba-4.19.5+dfsg/python/samba/gp/gp_cert_auto_enroll_ext.py 2024-02-19 10:42:54.162189500 +0000 @@ -45,10 +45,12 @@ -----BEGIN CERTIFICATE----- %s -----END CERTIFICATE-----""" -global_trust_dir = '/etc/pki/trust/anchors' endpoint_re = '(https|HTTPS)://(?P[a-zA-Z0-9.-]+)/ADPolicyProvider' + \ '_CEP_(?P[a-zA-Z]+)/service.svc/CEP' +global_trust_dirs = ['/etc/pki/trust/anchors', # SUSE + '/etc/pki/ca-trust/source/anchors', # RHEL/Fedora + '/usr/local/share/ca-certificates'] # Debian/Ubuntu def octet_string_to_objectGUID(data): """Convert an octet string to an objectGUID.""" @@ -156,7 +158,7 @@ for es in res: data = { 'name': get_string(es['cn'][0]), 'hostname': get_string(es['dNSHostName'][0]), - 'cACertificate': get_string(es['cACertificate'][0]) + 'cACertificate': get_string(base64.b64encode(es['cACertificate'][0])) } result.append(data) return result @@ -174,8 +176,7 @@ return {'msPKI-Minimal-Key-Size': ['2048']} def format_root_cert(cert): - cert = base64.b64encode(cert.encode()) - return cert_wrap % re.sub(b"(.{64})", b"\\1\n", cert, 0, re.DOTALL) + return cert_wrap % re.sub(b"(.{64})", b"\\1\n", cert.encode(), 0, re.DOTALL) def find_cepces_submit(): certmonger_dirs = [os.environ.get("PATH"), '/usr/lib/certmonger', @@ -184,17 +185,19 @@ def get_supported_templates(server): cepces_submit = find_cepces_submit() - if os.path.exists(cepces_submit): - env = os.environ - env['CERTMONGER_OPERATION'] = 'GET-SUPPORTED-TEMPLATES' - p = Popen([cepces_submit, '--server=%s' % server, '--auth=Kerberos'], - env=env, stdout=PIPE, stderr=PIPE) - out, err = p.communicate() - if p.returncode != 0: - data = { 'Error': err.decode() } - log.error('Failed to fetch the list of supported templates.', data) - return out.strip().split() - return [] + if not cepces_submit or not os.path.exists(cepces_submit): + log.error('Failed to find cepces-submit') + return [] + + env = os.environ + env['CERTMONGER_OPERATION'] = 'GET-SUPPORTED-TEMPLATES' + p = Popen([cepces_submit, '--server=%s' % server, '--auth=Kerberos'], + env=env, stdout=PIPE, stderr=PIPE) + out, err = p.communicate() + if p.returncode != 0: + data = {'Error': err.decode()} + log.error('Failed to fetch the list of supported templates.', data) + return out.strip().split() def getca(ca, url, trust_dir): @@ -214,10 +217,11 @@ ' installed or not configured.') if 'cACertificate' in ca: log.warn('Installing the server certificate only.') + der_certificate = base64.b64decode(ca['cACertificate']) try: - cert = load_der_x509_certificate(ca['cACertificate']) + cert = load_der_x509_certificate(der_certificate) except TypeError: - cert = load_der_x509_certificate(ca['cACertificate'], + cert = load_der_x509_certificate(der_certificate, default_backend()) cert_data = cert.public_bytes(Encoding.PEM) with open(root_cert, 'wb') as w: @@ -239,7 +243,8 @@ certs = load_der_pkcs7_certificates(r.content) for i in range(0, len(certs)): cert = certs[i].public_bytes(Encoding.PEM) - dest = '%s.%d' % (root_cert, i) + filename, extension = root_cert.rsplit('.', 1) + dest = '%s.%d.%s' % (filename, i, extension) with open(dest, 'wb') as w: w.write(cert) root_certs.append(dest) @@ -249,12 +254,29 @@ return root_certs +def find_global_trust_dir(): + """Return the global trust dir using known paths from various Linux distros.""" + for trust_dir in global_trust_dirs: + if os.path.isdir(trust_dir): + return trust_dir + return global_trust_dirs[0] + +def update_ca_command(): + """Return the command to update the CA trust store.""" + return which('update-ca-certificates') or which('update-ca-trust') + +def changed(new_data, old_data): + """Return True if any key present in both dicts has changed.""" + return any((new_data[k] != old_data[k] if k in old_data else False) \ + for k in new_data.keys()) + def cert_enroll(ca, ldb, trust_dir, private_dir, auth='Kerberos'): """Install the root certificate chain.""" data = dict({'files': [], 'templates': []}, **ca) url = 'http://%s/CertSrv/mscep/mscep.dll/pkiclient.exe?' % ca['hostname'] root_certs = getca(ca, url, trust_dir) data['files'].extend(root_certs) + global_trust_dir = find_global_trust_dir() for src in root_certs: # Symlink the certs to global trust dir dst = os.path.join(global_trust_dir, os.path.basename(src)) @@ -273,7 +295,7 @@ # already exists. Ignore the FileExistsError. Preserve the # existing symlink in the unapply data. data['files'].append(dst) - update = which('update-ca-certificates') + update = update_ca_command() if update is not None: Popen([update]).wait() # Setup Certificate Auto Enrollment @@ -316,7 +338,7 @@ class gp_cert_auto_enroll_ext(gp_pol_ext, gp_applier): def __str__(self): - return 'Cryptography\AutoEnrollment' + return r'Cryptography\AutoEnrollment' def unapply(self, guid, attribute, value): ca_cn = base64.b64decode(attribute) @@ -337,12 +359,13 @@ # If the policy has changed, unapply, then apply new policy old_val = self.cache_get_attribute_value(guid, attribute) old_data = json.loads(old_val) if old_val is not None else {} - if all([(ca[k] == old_data[k] if k in old_data else False) \ - for k in ca.keys()]) or \ - self.cache_get_apply_state() == GPOSTATE.ENFORCE: + templates = ['%s.%s' % (ca['name'], t.decode()) for t in get_supported_templates(ca['hostname'])] \ + if old_val is not None else [] + new_data = { 'templates': templates, **ca } + if changed(new_data, old_data) or self.cache_get_apply_state() == GPOSTATE.ENFORCE: self.unapply(guid, attribute, old_val) - # If policy is already applied, skip application - if old_val is not None and \ + # If policy is already applied and unchanged, skip application + if old_val is not None and not changed(new_data, old_data) and \ self.cache_get_apply_state() != GPOSTATE.ENFORCE: return @@ -368,7 +391,7 @@ for gpo in changed_gpo_list: if gpo.file_sys_path: - section = 'Software\Policies\Microsoft\Cryptography\AutoEnrollment' + section = r'Software\Policies\Microsoft\Cryptography\AutoEnrollment' pol_file = 'MACHINE/Registry.pol' path = os.path.join(gpo.file_sys_path, pol_file) pol_conf = self.parse(path) @@ -396,7 +419,7 @@ # remove any existing policy ca_attrs = \ self.cache_get_all_attribute_values(gpo.name) - self.clean(gpo.name, remove=ca_attrs) + self.clean(gpo.name, remove=list(ca_attrs.keys())) def __read_cep_data(self, guid, ldb, end_point_information, trust_dir, private_dir): @@ -488,7 +511,7 @@ def rsop(self, gpo): output = {} pol_file = 'MACHINE/Registry.pol' - section = 'Software\Policies\Microsoft\Cryptography\AutoEnrollment' + section = r'Software\Policies\Microsoft\Cryptography\AutoEnrollment' if gpo.file_sys_path: path = os.path.join(gpo.file_sys_path, pol_file) pol_conf = self.parse(path) diff -Nru samba-4.19.4+dfsg/python/samba/gp/gpclass.py samba-4.19.5+dfsg/python/samba/gp/gpclass.py --- samba-4.19.4+dfsg/python/samba/gp/gpclass.py 2023-07-18 08:14:54.618091800 +0000 +++ samba-4.19.5+dfsg/python/samba/gp/gpclass.py 2024-02-19 10:42:54.162189500 +0000 @@ -866,19 +866,25 @@ # (S)ite if gpo_list_machine: - site_dn = site_dn_for_machine(samdb, dc_hostname, lp, creds, username) - try: - log.debug("get_gpo_list: query SITE: [%s] for GPOs" % site_dn) - gp_link = get_gpo_link(samdb, site_dn) - except ldb.LdbError as e: - (enum, estr) = e.args - log.debug(estr) - else: - add_gplink_to_gpo_list(samdb, gpo_list, forced_gpo_list, - site_dn, gp_link, - gpo.GP_LINK_SITE, - add_only_forced_gpos, token) + site_dn = site_dn_for_machine(samdb, dc_hostname, lp, creds, username) + + try: + log.debug("get_gpo_list: query SITE: [%s] for GPOs" % site_dn) + gp_link = get_gpo_link(samdb, site_dn) + except ldb.LdbError as e: + (enum, estr) = e.args + log.debug(estr) + else: + add_gplink_to_gpo_list(samdb, gpo_list, forced_gpo_list, + site_dn, gp_link, + gpo.GP_LINK_SITE, + add_only_forced_gpos, token) + except ldb.LdbError: + # [MS-GPOL] 3.2.5.1.4 Site Search: If the method returns + # ERROR_NO_SITENAME, the remainder of this message MUST be skipped + # and the protocol sequence MUST continue at GPO Search + pass # (L)ocal gpo_list.insert(0, gpo.GROUP_POLICY_OBJECT("Local Policy", diff -Nru samba-4.19.4+dfsg/python/samba/gp/util/logging.py samba-4.19.5+dfsg/python/samba/gp/util/logging.py --- samba-4.19.4+dfsg/python/samba/gp/util/logging.py 2023-07-18 08:14:54.618091800 +0000 +++ samba-4.19.5+dfsg/python/samba/gp/util/logging.py 2024-02-19 10:42:54.162189500 +0000 @@ -24,9 +24,10 @@ import random import sys -logger = logging.getLogger() +logger = logging.getLogger("gp") + + def logger_init(name, log_level): - logger = logging.getLogger(name) logger.addHandler(logging.StreamHandler(sys.stdout)) logger.setLevel(logging.CRITICAL) if log_level == 1: diff -Nru samba-4.19.4+dfsg/python/samba/graph.py samba-4.19.5+dfsg/python/samba/graph.py --- samba-4.19.4+dfsg/python/samba/graph.py 2023-07-18 08:14:54.622092000 +0000 +++ samba-4.19.5+dfsg/python/samba/graph.py 2024-02-19 10:42:54.166189400 +0000 @@ -192,7 +192,7 @@ short = short[1:] long = long[1:] elision_str += ('\nelision%d[shape=plaintext; style=solid; ' - 'label="\“%s” means “%s”\\r"]\n' + 'label="\\“%s” means “%s”\\r"]\n' % ((i, short, long))) above_lines = [] diff -Nru samba-4.19.4+dfsg/python/samba/tests/bin/cepces-submit samba-4.19.5+dfsg/python/samba/tests/bin/cepces-submit --- samba-4.19.4+dfsg/python/samba/tests/bin/cepces-submit 2023-07-18 08:14:54.638092000 +0000 +++ samba-4.19.5+dfsg/python/samba/tests/bin/cepces-submit 2024-02-19 10:42:54.166189400 +0000 @@ -14,4 +14,5 @@ assert opts.auth == 'Kerberos' if 'CERTMONGER_OPERATION' in os.environ and \ os.environ['CERTMONGER_OPERATION'] == 'GET-SUPPORTED-TEMPLATES': - print('Machine') # Report a Machine template + templates = os.environ.get('CEPCES_SUBMIT_SUPPORTED_TEMPLATES', 'Machine').split(',') + print('\n'.join(templates)) # Report the requested templates diff -Nru samba-4.19.4+dfsg/python/samba/tests/gpo.py samba-4.19.5+dfsg/python/samba/tests/gpo.py --- samba-4.19.4+dfsg/python/samba/tests/gpo.py 2023-11-27 12:09:10.596012800 +0000 +++ samba-4.19.5+dfsg/python/samba/tests/gpo.py 2024-02-19 10:42:54.174189600 +0000 @@ -102,17 +102,21 @@ # Dummy requests structure for Certificate Auto Enrollment class dummy_requests(object): - @staticmethod - def get(url=None, params=None): + class exceptions(object): + ConnectionError = Exception + + def __init__(self, want_exception=False): + self.want_exception = want_exception + + def get(self, url=None, params=None): + if self.want_exception: + raise self.exceptions.ConnectionError + dummy = requests.Response() dummy._content = dummy_certificate() dummy.headers = {'Content-Type': 'application/x-x509-ca-cert'} return dummy - class exceptions(object): - ConnectionError = Exception -cae.requests = dummy_requests - realm = os.environ.get('REALM') policies = realm + '/POLICIES' realm = realm.lower() @@ -123,7 +127,7 @@ gpt_data = '[General]\nVersion=%d' gnome_test_reg_pol = \ -b""" +br""" @@ -260,7 +264,7 @@ """ auto_enroll_reg_pol = \ -b""" +br""" @@ -281,8 +285,30 @@ """ +auto_enroll_unchecked_reg_pol = \ +br""" + + + + Software\Policies\Microsoft\Cryptography\AutoEnrollment + AEPolicy + 0 + + + Software\Policies\Microsoft\Cryptography\AutoEnrollment + OfflineExpirationPercent + 10 + + + Software\Policies\Microsoft\Cryptography\AutoEnrollment + OfflineExpirationStoreNames + MY + + +""" + advanced_enroll_reg_pol = \ -b""" +br""" @@ -316,122 +342,122 @@ 0 - Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 + Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 URL LDAP: - Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 + Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 PolicyID %s - Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 + Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 FriendlyName Example - Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 + Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 Flags 16 - Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 + Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 AuthFlags 2 - Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 + Software\Policies\Microsoft\Cryptography\PolicyServers\37c9dc30f207f27f61a2f7c3aed598a6e2920b54 Cost 2147483645 - Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe + Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe URL https://example2.com/ADPolicyProvider_CEP_Certificate/service.svc/CEP - Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe + Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe PolicyID %s - Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe + Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe FriendlyName Example2 - Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe + Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe Flags 16 - Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe + Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe AuthFlags 8 - Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe + Software\Policies\Microsoft\Cryptography\PolicyServers\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe Cost 10 - Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 + Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 URL https://example0.com/ADPolicyProvider_CEP_Kerberos/service.svc/CEP - Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 + Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 PolicyID %s - Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 + Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 FriendlyName Example0 - Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 + Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 Flags 16 - Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 + Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 AuthFlags 2 - Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9 + Software\Policies\Microsoft\Cryptography\PolicyServers\20d46e856e9b9746c0b1265c328f126a7b3283a9 Cost 1 - Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac + Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac URL https://example1.com/ADPolicyProvider_CEP_Kerberos/service.svc/CEP - Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac + Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac PolicyID %s - Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac + Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac FriendlyName Example1 - Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac + Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac Flags 16 - Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac + Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac AuthFlags 2 - Software\Policies\Microsoft\Cryptography\PolicyServers\\855b5246433a48402ac4f5c3427566df26ccc9ac + Software\Policies\Microsoft\Cryptography\PolicyServers\855b5246433a48402ac4f5c3427566df26ccc9ac Cost 1 @@ -2094,7 +2120,7 @@ """ chromium_reg_pol = \ -b""" +br""" @@ -2990,12 +3016,12 @@ Software\Policies\Google\Chrome RestrictSigninToPattern - .*@example\\.com + .*@example\.com Software\Policies\Google\Chrome RoamingProfileLocation - ${roaming_app_data}\\chrome-profile + ${roaming_app_data}\chrome-profile Software\Policies\Google\Chrome @@ -3245,7 +3271,7 @@ Software\Policies\Google\Chrome\AlternativeBrowserParameters 5 - %HOME%\\browser_profile + %HOME%\browser_profile Software\Policies\Google\Chrome\AudioCaptureAllowedUrls @@ -4951,7 +4977,7 @@ """ firewalld_reg_pol = \ -b""" +br""" @@ -6742,6 +6768,114 @@ # Unstage the Registry.pol file unstage_file(reg_pol) + def test_gp_cert_auto_enroll_ext_without_ndes(self): + local_path = self.lp.cache_path('gpo_cache') + guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' + reg_pol = os.path.join(local_path, policies, guid, + 'MACHINE/REGISTRY.POL') + cache_dir = self.lp.get('cache directory') + store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb')) + + machine_creds = Credentials() + machine_creds.guess(self.lp) + machine_creds.set_machine_account() + + # Initialize the group policy extension + cae.requests = dummy_requests(want_exception=True) + ext = cae.gp_cert_auto_enroll_ext(self.lp, machine_creds, + machine_creds.get_username(), store) + + gpos = get_gpo_list(self.server, machine_creds, self.lp, + machine_creds.get_username()) + + # Stage the Registry.pol file with test data + parser = GPPolParser() + parser.load_xml(etree.fromstring(auto_enroll_reg_pol.strip())) + ret = stage_file(reg_pol, ndr_pack(parser.pol_file)) + self.assertTrue(ret, 'Could not create the target %s' % reg_pol) + + # Write the dummy CA entry, Enrollment Services, and Templates Entries + admin_creds = Credentials() + admin_creds.set_username(os.environ.get('DC_USERNAME')) + admin_creds.set_password(os.environ.get('DC_PASSWORD')) + admin_creds.set_realm(os.environ.get('REALM')) + hostname = get_dc_hostname(machine_creds, self.lp) + url = 'ldap://%s' % hostname + ldb = Ldb(url=url, session_info=system_session(), + lp=self.lp, credentials=admin_creds) + # Write the dummy CA + confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn + ca_cn = '%s-CA' % hostname.replace('.', '-') + certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn) + ldb.add({'dn': certa_dn, + 'objectClass': 'certificationAuthority', + 'authorityRevocationList': ['XXX'], + 'cACertificate': dummy_certificate(), + 'certificateRevocationList': ['XXX'], + }) + # Write the dummy pKIEnrollmentService + enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn) + ldb.add({'dn': enroll_dn, + 'objectClass': 'pKIEnrollmentService', + 'cACertificate': dummy_certificate(), + 'certificateTemplates': ['Machine'], + 'dNSHostName': hostname, + }) + # Write the dummy pKICertificateTemplate + template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn + ldb.add({'dn': template_dn, + 'objectClass': 'pKICertificateTemplate', + }) + + with TemporaryDirectory() as dname: + try: + ext.process_group_policy([], gpos, dname, dname) + except Exception as e: + self.fail(str(e)) + + ca_crt = os.path.join(dname, '%s.crt' % ca_cn) + self.assertTrue(os.path.exists(ca_crt), + 'Root CA certificate was not requested') + machine_crt = os.path.join(dname, '%s.Machine.crt' % ca_cn) + self.assertTrue(os.path.exists(machine_crt), + 'Machine certificate was not requested') + machine_key = os.path.join(dname, '%s.Machine.key' % ca_cn) + self.assertTrue(os.path.exists(machine_key), + 'Machine key was not generated') + + # Verify RSOP does not fail + ext.rsop([g for g in gpos if g.name == guid][0]) + + # Check that a call to gpupdate --rsop also succeeds + ret = rsop(self.lp) + self.assertEqual(ret, 0, 'gpupdate --rsop failed!') + + # Remove policy + gp_db = store.get_gplog(machine_creds.get_username()) + del_gpos = get_deleted_gpos_list(gp_db, []) + ext.process_group_policy(del_gpos, [], dname) + self.assertFalse(os.path.exists(ca_crt), + 'Root CA certificate was not removed') + self.assertFalse(os.path.exists(machine_crt), + 'Machine certificate was not removed') + self.assertFalse(os.path.exists(machine_key), + 'Machine key was not removed') + out, _ = Popen(['getcert', 'list-cas'], stdout=PIPE).communicate() + self.assertNotIn(get_bytes(ca_cn), out, 'CA was not removed') + out, _ = Popen(['getcert', 'list'], stdout=PIPE).communicate() + self.assertNotIn(b'Machine', out, + 'Machine certificate not removed') + self.assertNotIn(b'Workstation', out, + 'Workstation certificate not removed') + + # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate + ldb.delete(certa_dn) + ldb.delete(enroll_dn) + ldb.delete(template_dn) + + # Unstage the Registry.pol file + unstage_file(reg_pol) + def test_gp_cert_auto_enroll_ext(self): local_path = self.lp.cache_path('gpo_cache') guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' @@ -6755,6 +6889,7 @@ machine_creds.set_machine_account() # Initialize the group policy extension + cae.requests = dummy_requests() ext = cae.gp_cert_auto_enroll_ext(self.lp, machine_creds, machine_creds.get_username(), store) @@ -6783,14 +6918,14 @@ ldb.add({'dn': certa_dn, 'objectClass': 'certificationAuthority', 'authorityRevocationList': ['XXX'], - 'cACertificate': 'XXX', + 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I', 'certificateRevocationList': ['XXX'], }) # Write the dummy pKIEnrollmentService enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn) ldb.add({'dn': enroll_dn, 'objectClass': 'pKIEnrollmentService', - 'cACertificate': 'XXXX', + 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I', 'certificateTemplates': ['Machine'], 'dNSHostName': hostname, }) @@ -6812,6 +6947,23 @@ self.assertTrue(os.path.exists(machine_crt), 'Machine key was not generated') + # Subsequent apply should react to new certificate templates + os.environ['CEPCES_SUBMIT_SUPPORTED_TEMPLATES'] = 'Machine,Workstation' + self.addCleanup(os.environ.pop, 'CEPCES_SUBMIT_SUPPORTED_TEMPLATES') + ext.process_group_policy([], gpos, dname, dname) + self.assertTrue(os.path.exists(ca_crt), + 'Root CA certificate was not requested') + self.assertTrue(os.path.exists(machine_crt), + 'Machine certificate was not requested') + self.assertTrue(os.path.exists(machine_crt), + 'Machine key was not generated') + workstation_crt = os.path.join(dname, '%s.Workstation.crt' % ca_cn) + self.assertTrue(os.path.exists(workstation_crt), + 'Workstation certificate was not requested') + workstation_key = os.path.join(dname, '%s.Workstation.key' % ca_cn) + self.assertTrue(os.path.exists(workstation_crt), + 'Workstation key was not generated') + # Verify RSOP does not fail ext.rsop([g for g in gpos if g.name == guid][0]) @@ -6819,6 +6971,38 @@ ret = rsop(self.lp) self.assertEqual(ret, 0, 'gpupdate --rsop failed!') + # Remove policy by staging pol file with auto-enroll unchecked + parser.load_xml(etree.fromstring(auto_enroll_unchecked_reg_pol.strip())) + ret = stage_file(reg_pol, ndr_pack(parser.pol_file)) + self.assertTrue(ret, 'Could not create the target %s' % reg_pol) + ext.process_group_policy([], gpos, dname, dname) + self.assertFalse(os.path.exists(ca_crt), + 'Root CA certificate was not removed') + self.assertFalse(os.path.exists(machine_crt), + 'Machine certificate was not removed') + self.assertFalse(os.path.exists(machine_crt), + 'Machine key was not removed') + self.assertFalse(os.path.exists(workstation_crt), + 'Workstation certificate was not removed') + self.assertFalse(os.path.exists(workstation_crt), + 'Workstation key was not removed') + + # Reapply policy by staging the enabled pol file + parser.load_xml(etree.fromstring(auto_enroll_reg_pol.strip())) + ret = stage_file(reg_pol, ndr_pack(parser.pol_file)) + self.assertTrue(ret, 'Could not create the target %s' % reg_pol) + ext.process_group_policy([], gpos, dname, dname) + self.assertTrue(os.path.exists(ca_crt), + 'Root CA certificate was not requested') + self.assertTrue(os.path.exists(machine_crt), + 'Machine certificate was not requested') + self.assertTrue(os.path.exists(machine_crt), + 'Machine key was not generated') + self.assertTrue(os.path.exists(workstation_crt), + 'Workstation certificate was not requested') + self.assertTrue(os.path.exists(workstation_crt), + 'Workstation key was not generated') + # Remove policy gp_db = store.get_gplog(machine_creds.get_username()) del_gpos = get_deleted_gpos_list(gp_db, []) @@ -6829,11 +7013,17 @@ 'Machine certificate was not removed') self.assertFalse(os.path.exists(machine_crt), 'Machine key was not removed') + self.assertFalse(os.path.exists(workstation_crt), + 'Workstation certificate was not removed') + self.assertFalse(os.path.exists(workstation_crt), + 'Workstation key was not removed') out, _ = Popen(['getcert', 'list-cas'], stdout=PIPE).communicate() self.assertNotIn(get_bytes(ca_cn), out, 'CA was not removed') out, _ = Popen(['getcert', 'list'], stdout=PIPE).communicate() self.assertNotIn(b'Machine', out, 'Machine certificate not removed') + self.assertNotIn(b'Workstation', out, + 'Workstation certificate not removed') # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate ldb.delete(certa_dn) @@ -7164,6 +7354,7 @@ machine_creds.set_machine_account() # Initialize the group policy extension + cae.requests = dummy_requests() ext = cae.gp_cert_auto_enroll_ext(self.lp, machine_creds, machine_creds.get_username(), store) @@ -7201,14 +7392,14 @@ ldb.add({'dn': certa_dn, 'objectClass': 'certificationAuthority', 'authorityRevocationList': ['XXX'], - 'cACertificate': 'XXX', + 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I', 'certificateRevocationList': ['XXX'], }) # Write the dummy pKIEnrollmentService enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn) ldb.add({'dn': enroll_dn, 'objectClass': 'pKIEnrollmentService', - 'cACertificate': 'XXXX', + 'cACertificate': b'0\x82\x03u0\x82\x02]\xa0\x03\x02\x01\x02\x02\x10I', 'certificateTemplates': ['Machine'], 'dNSHostName': hostname, }) @@ -7233,6 +7424,25 @@ self.assertTrue(os.path.exists(machine_crt), 'Machine key was not generated') + # Subsequent apply should react to new certificate templates + os.environ['CEPCES_SUBMIT_SUPPORTED_TEMPLATES'] = 'Machine,Workstation' + self.addCleanup(os.environ.pop, 'CEPCES_SUBMIT_SUPPORTED_TEMPLATES') + ext.process_group_policy([], gpos, dname, dname) + for ca in ca_list: + self.assertTrue(os.path.exists(ca_crt), + 'Root CA certificate was not requested') + self.assertTrue(os.path.exists(machine_crt), + 'Machine certificate was not requested') + self.assertTrue(os.path.exists(machine_crt), + 'Machine key was not generated') + + workstation_crt = os.path.join(dname, '%s.Workstation.crt' % ca) + self.assertTrue(os.path.exists(workstation_crt), + 'Workstation certificate was not requested') + workstation_key = os.path.join(dname, '%s.Workstation.key' % ca) + self.assertTrue(os.path.exists(workstation_crt), + 'Workstation key was not generated') + # Verify RSOP does not fail ext.rsop([g for g in gpos if g.name == guid][0]) @@ -7250,12 +7460,18 @@ 'Machine certificate was not removed') self.assertFalse(os.path.exists(machine_crt), 'Machine key was not removed') + self.assertFalse(os.path.exists(workstation_crt), + 'Workstation certificate was not removed') + self.assertFalse(os.path.exists(workstation_crt), + 'Workstation key was not removed') out, _ = Popen(['getcert', 'list-cas'], stdout=PIPE).communicate() for ca in ca_list: self.assertNotIn(get_bytes(ca), out, 'CA was not removed') out, _ = Popen(['getcert', 'list'], stdout=PIPE).communicate() self.assertNotIn(b'Machine', out, 'Machine certificate not removed') + self.assertNotIn(b'Workstation', out, + 'Workstation certificate not removed') # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate ldb.delete(certa_dn) diff -Nru samba-4.19.4+dfsg/python/samba/tests/samba_tool/gpo.py samba-4.19.5+dfsg/python/samba/tests/samba_tool/gpo.py --- samba-4.19.4+dfsg/python/samba/tests/samba_tool/gpo.py 2023-07-18 08:14:54.674092300 +0000 +++ samba-4.19.5+dfsg/python/samba/tests/samba_tool/gpo.py 2024-02-19 10:42:54.178189500 +0000 @@ -1806,7 +1806,7 @@ 'The test cse was not enabled') self.assertIn('UserPolicy : False', out, 'The test cse should not have User policy enabled') - cse_ext = re.findall('^UniqueGUID\s+:\s+(.*)', out) + cse_ext = re.findall(r'^UniqueGUID\s+:\s+(.*)', out) self.assertEquals(len(cse_ext), 1, 'The test cse GUID was not found') cse_ext = cse_ext[0] diff -Nru samba-4.19.4+dfsg/script/autobuild.py samba-4.19.5+dfsg/script/autobuild.py --- samba-4.19.4+dfsg/script/autobuild.py 2023-07-18 08:14:54.678092200 +0000 +++ samba-4.19.5+dfsg/script/autobuild.py 2024-02-19 10:42:54.178189500 +0000 @@ -296,7 +296,7 @@ "samba-no-opath-build": { "git-clone-required": True, "sequence": [ - ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1' ./configure.developer --without-ad-dc " + samba_configure_params), + ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1 -DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS=1 -DDISABLE_PROC_FDS=1' ./configure.developer --without-ad-dc " + samba_configure_params), ("make", "make -j"), ("check-clean-tree", CLEAN_SOURCE_TREE_CMD), ("chmod-R-a-w", "chmod -R a-w ."), diff -Nru samba-4.19.4+dfsg/selftest/skip.opath-required samba-4.19.5+dfsg/selftest/skip.opath-required --- samba-4.19.4+dfsg/selftest/skip.opath-required 2023-07-18 08:14:54.698092500 +0000 +++ samba-4.19.5+dfsg/selftest/skip.opath-required 2024-02-19 10:42:54.178189500 +0000 @@ -14,3 +14,7 @@ # available this works fine. So for now restrict testing posix # extensions to environments where we have O_PATH around ^samba.tests.smb1posix + +# These don't work without /proc/fd support +^samba3.blackbox.shadow_copy_torture.*\(fileserver\) +^samba3.blackbox.virus_scanner.*\(fileserver:local\) diff -Nru samba-4.19.4+dfsg/selftest/target/Samba3.pm samba-4.19.5+dfsg/selftest/target/Samba3.pm --- samba-4.19.4+dfsg/selftest/target/Samba3.pm 2024-01-08 14:34:28.221465800 +0000 +++ samba-4.19.5+dfsg/selftest/target/Samba3.pm 2024-02-19 10:42:54.182189700 +0000 @@ -3437,9 +3437,7 @@ [shadow_write] path = $shadow_tstdir comment = previous versions snapshots under mount point - vfs objects = shadow_copy2 streams_xattr error_inject - aio write size = 0 - error_inject:pwrite = EBADF + vfs objects = shadow_copy2 streams_xattr shadow:mountpoint = $shadow_tstdir shadow:fixinodes = yes smbd async dosmode = yes diff -Nru samba-4.19.4+dfsg/source3/include/proto.h samba-4.19.5+dfsg/source3/include/proto.h --- samba-4.19.4+dfsg/source3/include/proto.h 2024-01-08 14:34:28.225465800 +0000 +++ samba-4.19.5+dfsg/source3/include/proto.h 2024-02-19 10:42:54.182189700 +0000 @@ -719,6 +719,12 @@ const SMB_STRUCT_STAT *psbuf, NTTIME twrp, uint32_t flags); +NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx, + const char *connectpath, + const char *dir, + const char *target, + size_t unparsed, + char **_relative); NTSTATUS filename_convert_dirfsp( TALLOC_CTX *ctx, connection_struct *conn, diff -Nru samba-4.19.4+dfsg/source3/include/smb_macros.h samba-4.19.5+dfsg/source3/include/smb_macros.h --- samba-4.19.4+dfsg/source3/include/smb_macros.h 2023-07-18 08:14:54.710092500 +0000 +++ samba-4.19.5+dfsg/source3/include/smb_macros.h 2024-02-19 10:42:54.182189700 +0000 @@ -74,11 +74,6 @@ (fsp_get_io_fd(fsp) != -1) && \ (((fsp)->fsp_flags.can_read))) -#define CHECK_WRITE(fsp) \ - ((fsp)->fsp_flags.can_write && \ - (!(fsp)->fsp_flags.is_pathref) && \ - (fsp_get_io_fd(fsp) != -1)) - #define ERROR_WAS_LOCK_DENIED(status) (NT_STATUS_EQUAL((status), NT_STATUS_LOCK_NOT_GRANTED) || \ NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT) ) diff -Nru samba-4.19.4+dfsg/source3/lib/system.c samba-4.19.5+dfsg/source3/lib/system.c --- samba-4.19.4+dfsg/source3/lib/system.c 2023-11-27 12:09:10.604012700 +0000 +++ samba-4.19.5+dfsg/source3/lib/system.c 2024-02-19 10:42:54.182189700 +0000 @@ -186,6 +186,7 @@ if (S_ISDIR(pst->st_mode) && fake_dir_create_times) { dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */ dst->st_ex_btime.tv_nsec = 0; + return; } dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME; diff -Nru samba-4.19.4+dfsg/source3/modules/offload_token.c samba-4.19.5+dfsg/source3/modules/offload_token.c --- samba-4.19.4+dfsg/source3/modules/offload_token.c 2023-07-18 08:14:54.854093300 +0000 +++ samba-4.19.5+dfsg/source3/modules/offload_token.c 2024-02-19 10:42:54.182189700 +0000 @@ -259,6 +259,8 @@ files_struct *src_fsp, files_struct *dst_fsp) { + NTSTATUS status; + if (src_fsp->vuid != dst_fsp->vuid) { DBG_INFO("copy chunk handles not in the same session.\n"); return NT_STATUS_ACCESS_DENIED; @@ -317,10 +319,11 @@ * * A non writable dst handle also doesn't make sense for other fsctls. */ - if (!CHECK_WRITE(dst_fsp)) { + status = check_any_access_fsp(dst_fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { DBG_INFO("dest handle not writable (%s).\n", smb_fname_str_dbg(dst_fsp->fsp_name)); - return NT_STATUS_ACCESS_DENIED; + return status; } /* * - The Open.GrantedAccess of the destination file does not include diff -Nru samba-4.19.4+dfsg/source3/modules/vfs_acl_common.c samba-4.19.5+dfsg/source3/modules/vfs_acl_common.c --- samba-4.19.4+dfsg/source3/modules/vfs_acl_common.c 2023-07-18 08:14:54.854093300 +0000 +++ samba-4.19.5+dfsg/source3/modules/vfs_acl_common.c 2024-02-19 10:42:54.182189700 +0000 @@ -738,10 +738,13 @@ /* We got access denied here. If we're already root, or we didn't need to do a chown, or the fsp isn't open with WRITE_OWNER access, just return. */ - if (get_current_uid(handle->conn) == 0 || !chown_needed || - !(fsp->access_mask & SEC_STD_WRITE_OWNER)) { + if (get_current_uid(handle->conn) == 0 || !chown_needed) { return NT_STATUS_ACCESS_DENIED; } + status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* * Only allow take-ownership, not give-ownership. That's the way Windows diff -Nru samba-4.19.4+dfsg/source3/modules/vfs_default.c samba-4.19.5+dfsg/source3/modules/vfs_default.c --- samba-4.19.4+dfsg/source3/modules/vfs_default.c 2023-07-18 08:14:54.858093300 +0000 +++ samba-4.19.5+dfsg/source3/modules/vfs_default.c 2024-02-19 10:42:54.186189700 +0000 @@ -52,6 +52,9 @@ bool bval; handle->conn->have_proc_fds = sys_have_proc_fds(); +#ifdef DISABLE_PROC_FDS + handle->conn->have_proc_fds = false; +#endif /* * assume the kernel will support openat2(), @@ -70,6 +73,9 @@ handle->conn->open_how_resolve |= VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS; } +#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS + handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS; +#endif return 0; /* Return >= 0 for success */ } diff -Nru samba-4.19.4+dfsg/source3/modules/vfs_nfs4acl_xattr.c samba-4.19.5+dfsg/source3/modules/vfs_nfs4acl_xattr.c --- samba-4.19.4+dfsg/source3/modules/vfs_nfs4acl_xattr.c 2023-07-18 08:14:54.866093400 +0000 +++ samba-4.19.5+dfsg/source3/modules/vfs_nfs4acl_xattr.c 2024-02-19 10:42:54.186189700 +0000 @@ -368,11 +368,14 @@ } if (get_current_uid(handle->conn) == 0 || - chown_needed == false || - !(fsp->access_mask & SEC_STD_WRITE_OWNER)) + chown_needed == false) { return NT_STATUS_ACCESS_DENIED; } + status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* * Only allow take-ownership, not give-ownership. That's the way Windows diff -Nru samba-4.19.4+dfsg/source3/modules/vfs_shadow_copy2.c samba-4.19.5+dfsg/source3/modules/vfs_shadow_copy2.c --- samba-4.19.4+dfsg/source3/modules/vfs_shadow_copy2.c 2023-07-18 08:14:54.866093400 +0000 +++ samba-4.19.5+dfsg/source3/modules/vfs_shadow_copy2.c 2024-02-19 10:42:54.186189700 +0000 @@ -1556,7 +1556,6 @@ struct smb_filename *smb_fname = NULL; time_t timestamp = 0; char *stripped = NULL; - bool is_converted = false; int saved_errno = 0; int ret; bool ok; @@ -1573,26 +1572,15 @@ return -1; } - ok = shadow_copy2_strip_snapshot_converted(talloc_tos(), - handle, - smb_fname, - ×tamp, - &stripped, - &is_converted); + ok = shadow_copy2_strip_snapshot(talloc_tos(), + handle, + smb_fname, + ×tamp, + &stripped); if (!ok) { return -1; } if (timestamp == 0) { - if (is_converted) { - /* - * Just pave over the user requested mode and use - * O_RDONLY. Later attempts by the client to write on - * the handle will fail in the pwrite() syscall with - * EINVAL which we carefully map to EROFS. In sum, this - * matches Windows behaviour. - */ - how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT); - } return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname_in, @@ -1613,14 +1601,6 @@ } TALLOC_FREE(stripped); - /* - * Just pave over the user requested mode and use O_RDONLY. Later - * attempts by the client to write on the handle will fail in the - * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum, - * this matches Windows behaviour. - */ - how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT); - ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, diff -Nru samba-4.19.4+dfsg/source3/passdb/pdb_smbpasswd.c samba-4.19.5+dfsg/source3/passdb/pdb_smbpasswd.c --- samba-4.19.4+dfsg/source3/passdb/pdb_smbpasswd.c 2023-07-28 12:14:20.892020200 +0000 +++ samba-4.19.5+dfsg/source3/passdb/pdb_smbpasswd.c 2024-02-19 10:42:54.186189700 +0000 @@ -192,6 +192,7 @@ const char *open_mode = NULL; int race_loop = 0; int lock_type = F_RDLCK; + struct stat st; if (!*pfile) { DEBUG(0, ("startsmbfilepwent: No SMB password file set\n")); @@ -324,19 +325,38 @@ /* Set a buffer to do more efficient reads */ setvbuf(fp, (char *)NULL, _IOFBF, 1024); - /* Make sure it is only rw by the owner */ -#ifdef HAVE_FCHMOD - if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) { -#else - if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) { -#endif - DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \ -Error was %s\n.", pfile, strerror(errno) )); + /* Ensure we have a valid stat. */ + if (fstat(fileno(fp), &st) != 0) { + DBG_ERR("Unable to fstat file %s. Error was %s\n", + pfile, + strerror(errno)); pw_file_unlock(fileno(fp), lock_depth); fclose(fp); return NULL; } + /* If file has invalid permissions != 0600, then [f]chmod(). */ + if ((st.st_mode & 0777) != (S_IRUSR|S_IWUSR)) { + DBG_WARNING("file %s has invalid permissions 0%o should " + "be 0600.\n", + pfile, + (unsigned int)st.st_mode & 0777); + /* Make sure it is only rw by the owner */ +#ifdef HAVE_FCHMOD + if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) { +#else + if (chmod(pfile, S_IRUSR|S_IWUSR) == -1) { +#endif + DBG_ERR("Failed to set 0600 permissions on password file %s. " + "Error was %s\n.", + pfile, + strerror(errno)); + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + return NULL; + } + } + /* We have a lock on the file. */ return fp; } diff -Nru samba-4.19.4+dfsg/source3/printing/printspoolss.c samba-4.19.5+dfsg/source3/printing/printspoolss.c --- samba-4.19.4+dfsg/source3/printing/printspoolss.c 2023-07-18 08:14:54.890093600 +0000 +++ samba-4.19.5+dfsg/source3/printing/printspoolss.c 2024-02-19 10:42:54.186189700 +0000 @@ -244,6 +244,7 @@ fsp->sent_oplock_break = NO_BREAK_SENT; fsp->fsp_flags.is_directory = false; fsp->fsp_flags.delete_on_close = false; + fsp->fsp_flags.is_fsa = true; fsp->print_file = pf; diff -Nru samba-4.19.4+dfsg/source3/smbd/dir.c samba-4.19.5+dfsg/source3/smbd/dir.c --- samba-4.19.4+dfsg/source3/smbd/dir.c 2023-07-18 08:14:54.938094000 +0000 +++ samba-4.19.5+dfsg/source3/smbd/dir.c 2024-02-19 10:42:54.186189700 +0000 @@ -218,11 +218,12 @@ return NT_STATUS_INVALID_PARAMETER; } - if (!(fsp->access_mask & SEC_DIR_LIST)) { + status = check_any_access_fsp(fsp, SEC_DIR_LIST); + if (!NT_STATUS_IS_OK(status)) { DBG_INFO("dptr_create: directory %s " "not open for LIST access\n", fsp_str_dbg(fsp)); - return NT_STATUS_ACCESS_DENIED; + return status; } status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd); if (!NT_STATUS_IS_OK(status)) { diff -Nru samba-4.19.4+dfsg/source3/smbd/dosmode.c samba-4.19.5+dfsg/source3/smbd/dosmode.c --- samba-4.19.4+dfsg/source3/smbd/dosmode.c 2023-07-28 12:14:20.908020300 +0000 +++ samba-4.19.5+dfsg/source3/smbd/dosmode.c 2024-02-19 10:42:54.190189600 +0000 @@ -1068,15 +1068,17 @@ * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the * following access flags are granted. */ - if ((fsp->access_mask & (FILE_WRITE_DATA - | FILE_WRITE_ATTRIBUTES - | SEC_FILE_APPEND_DATA)) == 0) { - DEBUG(9,("file_set_sparse: fname[%s] set[%u] " - "access_mask[0x%08X] - access denied\n", - smb_fname_str_dbg(fsp->fsp_name), - sparse, - fsp->access_mask)); - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, + FILE_WRITE_DATA + | FILE_WRITE_ATTRIBUTES + | SEC_FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("fname[%s] set[%u] " + "access_mask[0x%08X] - access denied\n", + smb_fname_str_dbg(fsp->fsp_name), + sparse, + fsp->access_mask); + return status; } if (fsp->fsp_flags.is_directory) { diff -Nru samba-4.19.4+dfsg/source3/smbd/file_access.c samba-4.19.5+dfsg/source3/smbd/file_access.c --- samba-4.19.4+dfsg/source3/smbd/file_access.c 2023-07-18 08:14:54.938094000 +0000 +++ samba-4.19.5+dfsg/source3/smbd/file_access.c 2024-02-19 10:42:54.190189600 +0000 @@ -191,6 +191,7 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode) { + NTSTATUS status; /* * Only allow delete on close for writable files. */ @@ -219,11 +220,12 @@ * intent. */ - if (!(fsp->access_mask & DELETE_ACCESS)) { - DEBUG(10,("can_set_delete_on_close: file %s delete on " + status = check_any_access_fsp(fsp, DELETE_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("file %s delete on " "close flag set but delete access denied.\n", - fsp_str_dbg(fsp))); - return NT_STATUS_ACCESS_DENIED; + fsp_str_dbg(fsp)); + return status; } /* Don't allow delete on close for non-empty directories. */ diff -Nru samba-4.19.4+dfsg/source3/smbd/filename.c samba-4.19.5+dfsg/source3/smbd/filename.c --- samba-4.19.4+dfsg/source3/smbd/filename.c 2024-01-08 14:34:28.237465900 +0000 +++ samba-4.19.5+dfsg/source3/smbd/filename.c 2024-02-19 10:42:54.190189600 +0000 @@ -942,44 +942,46 @@ return ret; } -static NTSTATUS safe_symlink_target_path( - TALLOC_CTX *mem_ctx, - const char *connectpath, - const char *name_in, - const char *substitute, - size_t unparsed, - char **_name_out) +NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx, + const char *connectpath, + const char *dir, + const char *target, + size_t unparsed, + char **_relative) { - char *target = NULL; char *abs_target = NULL; char *abs_target_canon = NULL; const char *relative = NULL; - char *name_out = NULL; - NTSTATUS status = NT_STATUS_NO_MEMORY; bool in_share; + NTSTATUS status = NT_STATUS_NO_MEMORY; - target = symlink_target_path(mem_ctx, name_in, substitute, unparsed); - if (target == NULL) { - goto fail; - } - - DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n", - name_in, - substitute, - unparsed, - target); + DBG_DEBUG("connectpath [%s] target [%s] unparsed [%zu]\n", + connectpath, target, unparsed); if (target[0] == '/') { - abs_target = target; + abs_target = talloc_strdup(mem_ctx, target); + } else if (dir == NULL) { + abs_target = talloc_asprintf(mem_ctx, + "%s/%s", + connectpath, + target); + } else if (dir[0] == '/') { + abs_target = talloc_asprintf(mem_ctx, + "%s/%s", + dir, + target); } else { - abs_target = talloc_asprintf( - target, "%s/%s", connectpath, target); - if (abs_target == NULL) { - goto fail; - } + abs_target = talloc_asprintf(mem_ctx, + "%s/%s/%s", + connectpath, + dir, + target); + } + if (abs_target == NULL) { + goto fail; } - abs_target_canon = canonicalize_absolute_path(target, abs_target); + abs_target_canon = canonicalize_absolute_path(abs_target, abs_target); if (abs_target_canon == NULL) { goto fail; } @@ -994,15 +996,14 @@ goto fail; } - name_out = talloc_strdup(mem_ctx, relative); - if (name_out == NULL) { + *_relative = talloc_strdup(mem_ctx, relative); + if (*_relative == NULL) { goto fail; } status = NT_STATUS_OK; - *_name_out = name_out; fail: - TALLOC_FREE(target); + TALLOC_FREE(abs_target); return status; } @@ -1438,6 +1439,7 @@ size_t unparsed = 0; NTSTATUS status; char *target = NULL; + char *safe_target = NULL; size_t symlink_redirects = 0; next: @@ -1476,17 +1478,22 @@ * resolve all symlinks locally. */ - status = safe_symlink_target_path( - mem_ctx, - conn->connectpath, - name_in, - substitute, - unparsed, - &target); + target = symlink_target_path(mem_ctx, name_in, substitute, unparsed); + if (target == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = safe_symlink_target_path(mem_ctx, + conn->connectpath, + NULL, + target, + unparsed, + &safe_target); + TALLOC_FREE(target); if (!NT_STATUS_IS_OK(status)) { return status; } - name_in = target; + name_in = safe_target; symlink_redirects += 1; diff -Nru samba-4.19.4+dfsg/source3/smbd/files.c samba-4.19.5+dfsg/source3/smbd/files.c --- samba-4.19.4+dfsg/source3/smbd/files.c 2024-01-08 14:34:28.241466000 +0000 +++ samba-4.19.5+dfsg/source3/smbd/files.c 2024-02-19 10:42:54.190189600 +0000 @@ -2148,6 +2148,9 @@ to->fsp_flags.can_write = CAN_WRITE(from->conn) && ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0); + if (from->fsp_name->twrp != 0) { + to->fsp_flags.can_write = false; + } to->fsp_flags.modified = from->fsp_flags.modified; to->fsp_flags.is_directory = from->fsp_flags.is_directory; to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind; diff -Nru samba-4.19.4+dfsg/source3/smbd/notify.c samba-4.19.5+dfsg/source3/smbd/notify.c --- samba-4.19.4+dfsg/source3/smbd/notify.c 2023-07-28 12:14:20.912020200 +0000 +++ samba-4.19.5+dfsg/source3/smbd/notify.c 2024-02-19 10:42:54.190189600 +0000 @@ -295,8 +295,9 @@ * Setting a changenotify needs READ/LIST access * on the directory handle. */ - if (!(fsp->access_mask & SEC_DIR_LIST)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_DIR_LIST); + if (!NT_STATUS_IS_OK(status)) { + return status; } if (fsp->notify != NULL) { diff -Nru samba-4.19.4+dfsg/source3/smbd/open.c samba-4.19.5+dfsg/source3/smbd/open.c --- samba-4.19.4+dfsg/source3/smbd/open.c 2023-11-27 12:09:10.616012800 +0000 +++ samba-4.19.5+dfsg/source3/smbd/open.c 2024-02-19 10:42:54.194189800 +0000 @@ -571,7 +571,6 @@ static NTSTATUS symlink_target_below_conn( TALLOC_CTX *mem_ctx, const char *connection_path, - size_t connection_path_len, struct files_struct *fsp, struct files_struct *dirfsp, struct smb_filename *symlink_name, @@ -579,9 +578,7 @@ { char *target = NULL; char *absolute = NULL; - const char *relative = NULL; NTSTATUS status; - bool ok; if (fsp_get_pathref_fd(fsp) != -1) { /* @@ -594,69 +591,28 @@ talloc_tos(), dirfsp, symlink_name, &target); } + status = safe_symlink_target_path(talloc_tos(), + connection_path, + dirfsp->fsp_name->base_name, + target, + 0, + &absolute); if (!NT_STATUS_IS_OK(status)) { - DBG_DEBUG("readlink_talloc failed: %s\n", nt_errstr(status)); + DBG_DEBUG("safe_symlink_target_path() failed: %s\n", + nt_errstr(status)); return status; } - if (target[0] != '/') { - char *tmp = talloc_asprintf( - talloc_tos(), - "%s/%s/%s", - connection_path, - dirfsp->fsp_name->base_name, - target); - - TALLOC_FREE(target); - - if (tmp == NULL) { - return NT_STATUS_NO_MEMORY; - } - target = tmp; - } - - DBG_DEBUG("redirecting to %s\n", target); - - absolute = canonicalize_absolute_path(talloc_tos(), target); - TALLOC_FREE(target); - - if (absolute == NULL) { - return NT_STATUS_NO_MEMORY; - } - - /* - * We're doing the "below connection_path" here because it's - * cheap. It might be that we get a symlink out of the share, - * pointing to yet another symlink getting us back into the - * share. If we need that, we would have to remove the check - * here. - */ - ok = subdir_of( - connection_path, - connection_path_len, - absolute, - &relative); - if (!ok) { - DBG_NOTICE("Bad access attempt: %s is a symlink " - "outside the share path\n" - "conn_rootdir =%s\n" - "resolved_name=%s\n", - symlink_name->base_name, - connection_path, - absolute); - TALLOC_FREE(absolute); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - - if (relative[0] == '\0') { + if (absolute[0] == '\0') { /* * special case symlink to share root: "." is our * share root filename */ - absolute[0] = '.'; - absolute[1] = '\0'; - } else { - memmove(absolute, relative, strlen(relative)+1); + TALLOC_FREE(absolute); + absolute = talloc_strdup(talloc_tos(), "."); + if (absolute == NULL) { + return NT_STATUS_NO_MEMORY; + } } *_target = absolute; @@ -834,7 +790,6 @@ status = symlink_target_below_conn( talloc_tos(), connpath, - connpath_len, fsp, discard_const_p(files_struct, dirfsp), smb_fname_rel, @@ -1678,6 +1633,9 @@ fsp->fsp_flags.can_write = CAN_WRITE(conn) && ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0); + if (fsp->fsp_name->twrp != 0) { + fsp->fsp_flags.can_write = false; + } fsp->print_file = NULL; fsp->fsp_flags.modified = false; fsp->sent_oplock_break = NO_BREAK_SENT; @@ -3669,7 +3627,8 @@ } static int calculate_open_access_flags(uint32_t access_mask, - uint32_t private_flags) + uint32_t private_flags, + NTTIME twrp) { bool need_write, need_read; @@ -3678,6 +3637,15 @@ * mean the same thing under DOS and Unix. */ + if (twrp != 0) { + /* + * Pave over the user requested mode and force O_RDONLY for the + * file handle. Windows allows opening a VSS file with O_RDWR, + * even though actual writes on the handle will fail. + */ + return O_RDONLY; + } + need_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)); if (!need_write) { return O_RDONLY; @@ -3808,6 +3776,7 @@ bool posix_open = False; bool new_file_created = False; bool first_open_attempt = true; + bool is_twrp = (smb_fname_atname->twrp != 0); NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; @@ -3965,6 +3934,9 @@ smb_fname_str_dbg(smb_fname) )); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + if (is_twrp) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } break; case FILE_CREATE: @@ -3980,11 +3952,24 @@ } return NT_STATUS_OBJECT_NAME_COLLISION; } + if (is_twrp) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } break; case FILE_SUPERSEDE: case FILE_OVERWRITE_IF: + if (is_twrp) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + break; case FILE_OPEN_IF: + if (is_twrp) { + if (!file_existed) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + create_disposition = FILE_OPEN; + } break; default: return NT_STATUS_INVALID_PARAMETER; @@ -4057,7 +4042,9 @@ * mean the same thing under DOS and Unix. */ - flags = calculate_open_access_flags(access_mask, private_flags); + flags = calculate_open_access_flags(access_mask, + private_flags, + smb_fname->twrp); /* * Currently we only look at FILE_WRITE_THROUGH for create options. @@ -4785,6 +4772,10 @@ return status; } + if (smb_fname_atname->twrp != 0) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + status = mkdir_internal(conn, parent_dir_fname, smb_fname_atname, @@ -4813,6 +4804,9 @@ status = NT_STATUS_OK; info = FILE_WAS_OPENED; } else { + if (smb_fname_atname->twrp != 0) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } status = mkdir_internal(conn, parent_dir_fname, smb_fname_atname, @@ -4921,8 +4915,8 @@ if (access_mask & need_fd_access) { status = reopen_from_fsp( - fsp->conn->cwd_fsp, - fsp->fsp_name, + parent_dir_fname->fsp, + smb_fname_atname, fsp, O_RDONLY | O_DIRECTORY, 0, diff -Nru samba-4.19.4+dfsg/source3/smbd/proto.h samba-4.19.5+dfsg/source3/smbd/proto.h --- samba-4.19.4+dfsg/source3/smbd/proto.h 2023-07-28 12:14:20.912020200 +0000 +++ samba-4.19.5+dfsg/source3/smbd/proto.h 2024-02-19 10:42:54.194189800 +0000 @@ -1108,8 +1108,8 @@ files_struct *fsp, struct smb_filename *smb_fname); NTSTATUS refuse_symlink_fsp(const struct files_struct *fsp); -NTSTATUS check_access_fsp(struct files_struct *fsp, - uint32_t access_mask); +NTSTATUS check_any_access_fsp(struct files_struct *fsp, + uint32_t access_requested); uint64_t smb_roundup(connection_struct *conn, uint64_t val); bool samba_private_attr_name(const char *unix_ea_name); NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx, diff -Nru samba-4.19.4+dfsg/source3/smbd/smb1_reply.c samba-4.19.5+dfsg/source3/smbd/smb1_reply.c --- samba-4.19.4+dfsg/source3/smbd/smb1_reply.c 2023-08-18 11:18:20.433133800 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb1_reply.c 2024-02-19 10:42:54.194189800 +0000 @@ -3926,8 +3926,9 @@ return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); error_to_writebrawerr(req); END_PROFILE(SMBwritebraw); return; @@ -4157,8 +4158,9 @@ return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBwriteunlock); return; } @@ -4292,8 +4294,9 @@ return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBwrite); return; } @@ -4571,8 +4574,9 @@ goto out; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); goto out; } @@ -5283,6 +5287,7 @@ struct timespec mtime; files_struct *fsp; struct lock_struct lock; + NTSTATUS status; START_PROFILE(SMBwriteclose); @@ -5298,8 +5303,9 @@ END_PROFILE(SMBwriteclose); return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBwriteclose); return; } @@ -6086,6 +6092,7 @@ int numtowrite; const char *data; files_struct *fsp; + NTSTATUS status; START_PROFILE(SMBsplwr); @@ -6108,8 +6115,9 @@ return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBsplwr); return; } @@ -6957,8 +6965,9 @@ goto out; } - if (!(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); goto out; } diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_flush.c samba-4.19.5+dfsg/source3/smbd/smb2_flush.c --- samba-4.19.4+dfsg/source3/smbd/smb2_flush.c 2023-07-18 08:14:54.954094000 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_flush.c 2024-02-19 10:42:54.194189800 +0000 @@ -128,6 +128,7 @@ struct smb_request *smbreq; bool is_compound = false; bool is_last_in_compound = false; + NTSTATUS status; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_flush_state); @@ -150,7 +151,8 @@ return tevent_req_post(req, ev); } - if (!CHECK_WRITE(fsp)) { + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { bool allow_dir_flush = false; uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY; @@ -166,7 +168,8 @@ * they can be flushed. */ - if ((fsp->access_mask & flush_access) != 0) { + status = check_any_access_fsp(fsp, flush_access); + if (NT_STATUS_IS_OK(status)) { allow_dir_flush = true; } diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_getinfo.c samba-4.19.5+dfsg/source3/smbd/smb2_getinfo.c --- samba-4.19.4+dfsg/source3/smbd/smb2_getinfo.c 2023-07-18 08:14:54.954094000 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_getinfo.c 2024-02-19 10:42:54.194189800 +0000 @@ -315,15 +315,15 @@ case FSCC_FILE_ALL_INFORMATION: case FSCC_FILE_NETWORK_OPEN_INFORMATION: case FSCC_FILE_ATTRIBUTE_TAG_INFORMATION: - if (!(fsp->access_mask & SEC_FILE_READ_ATTRIBUTE)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, SEC_FILE_READ_ATTRIBUTE); + if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } break; case FSCC_FILE_FULL_EA_INFORMATION: - if (!(fsp->access_mask & SEC_FILE_READ_EA)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, SEC_FILE_READ_EA); + if (tevent_req_nterror(req, status)) { return tevent_req_post(req, ev); } break; diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_ioctl_filesys.c samba-4.19.5+dfsg/source3/smbd/smb2_ioctl_filesys.c --- samba-4.19.4+dfsg/source3/smbd/smb2_ioctl_filesys.c 2023-07-18 08:14:54.954094000 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_ioctl_filesys.c 2024-02-19 10:42:54.194189800 +0000 @@ -378,7 +378,7 @@ } /* WRITE_DATA permission is required, WRITE_ATTRIBUTES is not */ - status = check_access_fsp(fsp, FILE_WRITE_DATA); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -426,7 +426,7 @@ } /* WRITE_DATA permission is required */ - status = check_access_fsp(fsp, FILE_WRITE_DATA); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -616,7 +616,7 @@ } /* READ_DATA permission is required */ - status = check_access_fsp(fsp, FILE_READ_DATA); + status = check_any_access_fsp(fsp, FILE_READ_DATA); if (!NT_STATUS_IS_OK(status)) { return status; } diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_nttrans.c samba-4.19.5+dfsg/source3/smbd/smb2_nttrans.c --- samba-4.19.4+dfsg/source3/smbd/smb2_nttrans.c 2023-07-28 12:14:20.916020400 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_nttrans.c 2024-02-19 10:42:54.194189800 +0000 @@ -114,20 +114,23 @@ /* Ensure we have the rights to do this. */ if (security_info_sent & SECINFO_OWNER) { - if (!(fsp->access_mask & SEC_STD_WRITE_OWNER)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); + if (!NT_STATUS_IS_OK(status)) { + return status; } } if (security_info_sent & SECINFO_GROUP) { - if (!(fsp->access_mask & SEC_STD_WRITE_OWNER)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); + if (!NT_STATUS_IS_OK(status)) { + return status; } } if (security_info_sent & SECINFO_DACL) { - if (!(fsp->access_mask & SEC_STD_WRITE_DAC)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_STD_WRITE_DAC); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Convert all the generic bits. */ if (psd->dacl) { @@ -136,15 +139,17 @@ } if (security_info_sent & SECINFO_SACL) { - if (!(fsp->access_mask & SEC_FLAG_SYSTEM_SECURITY)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_FLAG_SYSTEM_SECURITY); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* * Setting a SACL also requires WRITE_DAC. * See the smbtorture3 SMB2-SACL test. */ - if (!(fsp->access_mask & SEC_STD_WRITE_DAC)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_STD_WRITE_DAC); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Convert all the generic bits. */ if (psd->sacl) { @@ -407,16 +412,20 @@ * Get the permissions to return. */ - if ((security_info_wanted & SECINFO_SACL) && - !(fsp->access_mask & SEC_FLAG_SYSTEM_SECURITY)) { - DEBUG(10, ("Access to SACL denied.\n")); - return NT_STATUS_ACCESS_DENIED; + if (security_info_wanted & SECINFO_SACL) { + status = check_any_access_fsp(fsp, SEC_FLAG_SYSTEM_SECURITY); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("Access to SACL denied.\n"); + return status; + } } - if ((security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|SECINFO_GROUP)) && - !(fsp->access_mask & SEC_STD_READ_CONTROL)) { - DEBUG(10, ("Access to DACL, OWNER, or GROUP denied.\n")); - return NT_STATUS_ACCESS_DENIED; + if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|SECINFO_GROUP)) { + status = check_any_access_fsp(fsp, SEC_STD_READ_CONTROL); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("Access to DACL, OWNER, or GROUP denied.\n"); + return status; + } } status = refuse_symlink_fsp(fsp); diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_reply.c samba-4.19.5+dfsg/source3/smbd/smb2_reply.c --- samba-4.19.4+dfsg/source3/smbd/smb2_reply.c 2023-08-18 11:18:20.433133800 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_reply.c 2024-02-19 10:42:54.198189700 +0000 @@ -1140,6 +1140,13 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, uint16_t dirtype) { + NTSTATUS status; + + if (fsp->fsp_name->twrp != 0) { + /* Get the error right, this is what Windows returns. */ + return NT_STATUS_NOT_SAME_DEVICE; + } + if (!CAN_WRITE(conn)) { return NT_STATUS_MEDIA_WRITE_PROTECTED; } @@ -1178,11 +1185,11 @@ return NT_STATUS_OK; } - if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) { - return NT_STATUS_OK; + status = check_any_access_fsp(fsp, DELETE_ACCESS | FILE_WRITE_ATTRIBUTES); + if (!NT_STATUS_IS_OK(status)) { + return status; } - - return NT_STATUS_ACCESS_DENIED; + return NT_STATUS_OK; } /**************************************************************************** diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_trans2.c samba-4.19.5+dfsg/source3/smbd/smb2_trans2.c --- samba-4.19.4+dfsg/source3/smbd/smb2_trans2.c 2023-07-28 12:14:20.920020300 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_trans2.c 2024-02-19 10:42:54.198189700 +0000 @@ -72,18 +72,61 @@ return NT_STATUS_OK; } -NTSTATUS check_access_fsp(struct files_struct *fsp, - uint32_t access_mask) -{ - if (!fsp->fsp_flags.is_fsa) { - return smbd_check_access_rights_fsp(fsp->conn->cwd_fsp, - fsp, - false, - access_mask); +/** + * Check that one or more of the rights in access mask are + * allowed. Iow, access_requested can contain more then one right and + * it is sufficient having only one of those granted to pass. + **/ +NTSTATUS check_any_access_fsp(struct files_struct *fsp, + uint32_t access_requested) +{ + const uint32_t ro_access = SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE; + uint32_t ro_access_granted = 0; + uint32_t access_granted = 0; + NTSTATUS status; + + if (fsp->fsp_flags.is_fsa) { + access_granted = fsp->access_mask; + } else { + uint32_t mask = 1; + + while (mask != 0) { + if (!(mask & access_requested)) { + mask <<= 1; + continue; + } + + status = smbd_check_access_rights_fsp( + fsp->conn->cwd_fsp, + fsp, + false, + mask); + if (NT_STATUS_IS_OK(status)) { + access_granted |= mask; + if (fsp->fsp_name->twrp == 0) { + /* + * We can only optimize + * the non-snapshot case + */ + break; + } + } + mask <<= 1; + } } - if (!(fsp->access_mask & access_mask)) { + if ((access_granted & access_requested) == 0) { return NT_STATUS_ACCESS_DENIED; } + + if (fsp->fsp_name->twrp == 0) { + return NT_STATUS_OK; + } + + ro_access_granted = access_granted & ro_access; + if ((ro_access_granted & access_requested) == 0) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + return NT_STATUS_OK; } @@ -677,7 +720,7 @@ return status; } - status = check_access_fsp(fsp, FILE_WRITE_EA); + status = check_any_access_fsp(fsp, FILE_WRITE_EA); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -3763,6 +3806,11 @@ goto out; } + if (smb_fname_old->twrp != 0) { + status = NT_STATUS_NOT_SAME_DEVICE; + goto out; + } + status = parent_pathref(talloc_tos(), conn->cwd_fsp, smb_fname_old, @@ -4021,8 +4069,9 @@ fsp_get_io_fd(fsp) != -1) { /* Handle based call. */ - if (!(fsp->access_mask & FILE_WRITE_DATA)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, FILE_WRITE_DATA); + if (!NT_STATUS_IS_OK(status)) { + return status; } if (vfs_set_filelen(fsp, size) == -1) { @@ -4803,7 +4852,7 @@ return NT_STATUS_INVALID_HANDLE; } - status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); + status = check_any_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -4874,7 +4923,7 @@ DEBUG(10,("smb_set_info_standard: file %s\n", smb_fname_str_dbg(smb_fname))); - status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); + status = check_any_access_fsp(fsp, FILE_WRITE_ATTRIBUTES); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -4932,8 +4981,9 @@ fsp_get_io_fd(fsp) != -1) { /* Open file handle. */ - if (!(fsp->access_mask & FILE_WRITE_DATA)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, FILE_WRITE_DATA); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* Only change if needed. */ diff -Nru samba-4.19.4+dfsg/source3/smbd/smb2_write.c samba-4.19.5+dfsg/source3/smbd/smb2_write.c --- samba-4.19.4+dfsg/source3/smbd/smb2_write.c 2023-10-16 14:15:01.053622500 +0000 +++ samba-4.19.5+dfsg/source3/smbd/smb2_write.c 2024-02-19 10:42:54.198189700 +0000 @@ -24,6 +24,7 @@ #include "../libcli/smb/smb_common.h" #include "../lib/util/tevent_ntstatus.h" #include "rpc_server/srv_pipe_hnd.h" +#include "libcli/security/security.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_SMB2 @@ -339,8 +340,9 @@ return req; } - if (!CHECK_WRITE(fsp)) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); return tevent_req_post(req, ev); } diff -Nru samba-4.19.4+dfsg/source4/libcli/raw/rawsetfileinfo.c samba-4.19.5+dfsg/source4/libcli/raw/rawsetfileinfo.c --- samba-4.19.4+dfsg/source4/libcli/raw/rawsetfileinfo.c 2023-07-18 08:14:55.182095300 +0000 +++ samba-4.19.5+dfsg/source4/libcli/raw/rawsetfileinfo.c 2024-02-19 10:42:54.198189700 +0000 @@ -119,6 +119,20 @@ parms->full_ea_information.in.eas.eas, 4); return true; + case RAW_SFILEINFO_LINK_INFORMATION: + NEED_BLOB(20); + memset(blob->data, 0, blob->length); + + PUSH_LE_U8(blob->data, 0, parms->link_information.in.overwrite); + PUSH_LE_U64(blob->data, 8, parms->link_information.in.root_fid); + + len = smbcli_blob_append_string( + NULL, mem_ctx, blob, + parms->link_information.in.new_name, + STR_UNICODE | STR_TERMINATE); + PUSH_LE_U32(blob->data, 16, len - 2); + return true; + /* Unhandled levels */ case RAW_SFILEINFO_PIPE_INFORMATION: case RAW_SFILEINFO_VALID_DATA_INFORMATION: diff -Nru samba-4.19.4+dfsg/source4/torture/smb2/create.c samba-4.19.5+dfsg/source4/torture/smb2/create.c --- samba-4.19.4+dfsg/source4/torture/smb2/create.c 2023-07-18 08:14:56.542103800 +0000 +++ samba-4.19.5+dfsg/source4/torture/smb2/create.c 2024-02-19 10:42:54.198189700 +0000 @@ -1753,6 +1753,18 @@ uint64_t nttime; const char *file = NULL; const char *snapshot = NULL; + uint32_t expected_access; + union smb_fileinfo getinfo; + union smb_setfileinfo setinfo; + struct security_descriptor *sd = NULL, *sd_orig = NULL; + const char *owner_sid = NULL; + struct create_disps_tests { + const char *file; + uint32_t create_disposition; + uint32_t create_options; + NTSTATUS expected_status; + }; + struct create_disps_tests *cd_test = NULL; file = torture_setting_string(tctx, "twrp_file", NULL); if (file == NULL) { @@ -1794,11 +1806,102 @@ "smb2_create\n"); smb2_util_close(tree, io.out.file.handle); - ret = io.out.maximal_access & (SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA); - torture_assert_goto(tctx, ret, ret, done, "Bad access\n"); + expected_access = SEC_RIGHTS_FILE_ALL & + ~(SEC_FILE_EXECUTE | SEC_DIR_DELETE_CHILD); + + torture_assert_int_equal_goto(tctx, + io.out.maximal_access & expected_access, + expected_access, + ret, done, "Bad access\n"); + + { + /* + * Test create dispositions + */ + struct create_disps_tests cd_tests[] = { + { + .file = file, + .create_disposition = NTCREATEX_DISP_OPEN, + .expected_status = NT_STATUS_OK, + }, + { + .file = file, + .create_disposition = NTCREATEX_DISP_OPEN_IF, + .expected_status = NT_STATUS_OK, + }, + { + .file = file, + .create_disposition = NTCREATEX_DISP_OVERWRITE, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = file, + .create_disposition = NTCREATEX_DISP_OVERWRITE_IF, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = file, + .create_disposition = NTCREATEX_DISP_SUPERSEDE, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = "newfile", + .create_disposition = NTCREATEX_DISP_OPEN_IF, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = "newfile", + .create_disposition = NTCREATEX_DISP_OVERWRITE_IF, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = "newfile", + .create_disposition = NTCREATEX_DISP_CREATE, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = "newfile", + .create_disposition = NTCREATEX_DISP_SUPERSEDE, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = "newdir", + .create_disposition = NTCREATEX_DISP_OPEN_IF, + .create_options = NTCREATEX_OPTIONS_DIRECTORY, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = "newdir", + .create_disposition = NTCREATEX_DISP_CREATE, + .create_options = NTCREATEX_OPTIONS_DIRECTORY, + .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED, + }, + { + .file = NULL, + }, + }; + + for (cd_test = &cd_tests[0]; cd_test->file != NULL; cd_test++) { + io = (struct smb2_create) { + .in.fname = cd_test->file, + .in.create_disposition = cd_test->create_disposition, + .in.create_options = cd_test->create_options, + + .in.desired_access = SEC_FILE_READ_DATA, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.timewarp = nttime, + }; + + status = smb2_create(tree, tctx, &io); + torture_assert_ntstatus_equal_goto( + tctx, status, cd_test->expected_status, ret, done, + "Bad status\n"); + } + } io = (struct smb2_create) { - .in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, + .in.desired_access = expected_access, .in.file_attributes = FILE_ATTRIBUTE_NORMAL, .in.create_disposition = NTCREATEX_DISP_OPEN, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, @@ -1816,9 +1919,145 @@ NT_STATUS_MEDIA_WRITE_PROTECTED, ret, done, "smb2_create\n"); + /* + * Verify access mask + */ + + ZERO_STRUCT(getinfo); + getinfo.generic.level = RAW_FILEINFO_ACCESS_INFORMATION; + getinfo.generic.in.file.handle = h1; + + status = smb2_getinfo_file(tree, tree, &getinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file\n"); + + torture_assert_int_equal_goto( + tctx, + getinfo.access_information.out.access_flags, + expected_access, + ret, done, + "Bad access mask\n"); + + /* + * Check we can't set various things + */ + + ZERO_STRUCT(getinfo); + getinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + getinfo.query_secdesc.in.file.handle = h1; + getinfo.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER; + + status = smb2_getinfo_file(tree, tctx, &getinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file\n"); + + sd_orig = getinfo.query_secdesc.out.sd; + owner_sid = dom_sid_string(tctx, sd_orig->owner_sid); + + sd = security_descriptor_dacl_create(tctx, + 0, NULL, NULL, + owner_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_FILE_WRITE_DATA, + 0, + NULL); + + /* Try to set ACL */ + + ZERO_STRUCT(setinfo); + setinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; + setinfo.set_secdesc.in.file.handle = h1; + setinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL; + setinfo.set_secdesc.in.sd = sd; + + status = smb2_setinfo_file(tree, &setinfo); + torture_assert_ntstatus_equal_goto( + tctx, + status, + NT_STATUS_MEDIA_WRITE_PROTECTED, + ret, done, + "smb2_setinfo_file\n"); + + /* Try to delete */ + + ZERO_STRUCT(setinfo); + setinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION; + setinfo.disposition_info.in.delete_on_close = 1; + setinfo.generic.in.file.handle = h1; + + status = smb2_setinfo_file(tree, &setinfo); + torture_assert_ntstatus_equal_goto( + tctx, + status, + NT_STATUS_MEDIA_WRITE_PROTECTED, + ret, done, + "smb2_setinfo_file\n"); + + ZERO_STRUCT(setinfo); + setinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN; + setinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; + setinfo.generic.in.file.handle = h1; + + status = smb2_setinfo_file(tree, &setinfo); + torture_assert_ntstatus_equal_goto( + tctx, + status, + NT_STATUS_MEDIA_WRITE_PROTECTED, + ret, done, + "smb2_setinfo_file\n"); + + /* Try to truncate */ + + ZERO_STRUCT(setinfo); + setinfo.generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION; + setinfo.generic.in.file.handle = h1; + setinfo.end_of_file_info.in.size = 0x100000; + + status = smb2_setinfo_file(tree, &setinfo); + torture_assert_ntstatus_equal_goto( + tctx, + status, + NT_STATUS_MEDIA_WRITE_PROTECTED, + ret, done, + "smb2_setinfo_file\n"); + + /* Try to set a hardlink */ + + ZERO_STRUCT(setinfo); + setinfo.generic.level = RAW_SFILEINFO_LINK_INFORMATION; + setinfo.generic.in.file.handle = h1; + setinfo.link_information.in.new_name = "hardlink"; + + status = smb2_setinfo_file(tree, &setinfo); + torture_assert_ntstatus_equal_goto( + tctx, + status, + NT_STATUS_NOT_SAME_DEVICE, + ret, done, + "smb2_setinfo_file\n"); + + /* Try to rename */ + + ZERO_STRUCT(setinfo); + setinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + setinfo.rename_information.in.file.handle = h1; + setinfo.rename_information.in.new_name = "renamed"; + + status = smb2_setinfo_file(tree, &setinfo); + torture_assert_ntstatus_equal_goto( + tctx, + status, + NT_STATUS_NOT_SAME_DEVICE, + ret, done, + "smb2_setinfo_file\n"); + smb2_util_close(tree, h1); + ZERO_STRUCT(h1); done: + if (!smb2_util_handle_empty(h1)) { + smb2_util_close(tree, h1); + } return ret; }