The branch, v4-23-stable has been updated
via 7a8bcd84200 VERSION: Disable GIT_SNAPSHOT for the 4.23.0rc3 release.
via 2e5edf70589 WHATSNEW: Add release notes for Samba 4.23.0rc3.
via 1fe870aa4c8 WHATSNEW: unify format
via cd46d6f2bd8 WHATSNEW: add Initial version of smb_prometheus_endpoint
via 601e0e2c744 WHATSNEW: add Modern write time update logic
via 1757f22046d WHATSNEW: add SMB3 Unix Extensions
via fb9a042dab9 WHATSNEW: add support for SMB3 over QUIC
via 20c3ccc7be7 s4:lib/tls: add additional dns hostnames as
GNUTLS_SAN_DNSNAME for self-signed certificates
via ef469b45168 s4:lib/tls: set GNUTLS_SAN_DNSNAME for self-signed
certificates
via fbb1a8bfd8a s4:lib/tls: let tstream_tls_params_server_lpcfg() use
lpcfg_dns_hostname() internally
via 3710cb26ae3 auth:creds: Update the documentation for set_principal
and set_realm
via 1505f130450 auth:creds: Make sure to uppercase the realm of a
principal
via e9b5835127f auth:creds: Validate realm names in set_realm and
set_principal
via 2629f19dbe5 s3:utils: Keep password secret in ntlm_auth
get_password()
via ae5124ac5f5 auth:creds: Keep password secret in
cmdline_get_userpassword()
via 16b4aa95658 auth:creds: Keep the password secret
via 8f98180ed71 auth:creds: Allow to reset the principal by passing
NULL to set_principal
via e6158a6bf6d auth:creds: Also uppercase realm set via a callback
via 3985c45ad97 auth:creds: Allow to reset the realm by passing NULL
via 2788551866a smbd: return correct reparse tag DFS when listing
directories
via 607d7ad27c4 CI: add Python test
samba.tests.dcerpc.dfs.DfsTests.test_dfs_reparse_tag
via 24ba677d127 python/tests: also populate self.server in calls
LibsmbTests setup()
via d0fa3266ad8 pylibsmb: add SMB2_FIND_ID_BOTH_DIRECTORY_INFO
via d22c428c1da vfs_xattr_tdb: fix dangling symlink detection
via 8619973d978 s3/rpc_server/dfs: fix creating a DFS link
via 6dc245c4669 VERSION: Bump version up to Samba 4.23.0rc3...
from 4936cd33142 VERSION: Disable GIT_SNAPSHOT for the 4.23.0rc2 release.
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-23-stable
- Log -----------------------------------------------------------------
-----------------------------------------------------------------------
Summary of changes:
VERSION | 2 +-
WHATSNEW.txt | 91 ++++++++++++++++-----
auth/credentials/credentials.c | 140 ++++++++++++++++++++++++++++-----
auth/credentials/credentials_cmdline.c | 1 +
python/samba/tests/credentials.py | 4 +-
python/samba/tests/dcerpc/dfs.py | 48 +++++++++++
python/samba/tests/libsmb.py | 1 +
source3/libsmb/pylibsmb.c | 1 +
source3/modules/vfs_xattr_tdb.c | 13 ++-
source3/rpc_server/dfs/srv_dfs_nt.c | 4 +-
source3/smbd/dir.c | 2 +
source3/smbd/server.c | 8 --
source3/utils/ntlm_auth.c | 1 +
source4/ldap_server/ldap_server.c | 10 ---
source4/ldap_server/ldap_server.h | 1 -
source4/lib/tls/tls.h | 3 +-
source4/lib/tls/tls_tstream.c | 6 +-
source4/lib/tls/tlscert.c | 16 ++++
source4/selftest/tests.py | 1 +
19 files changed, 279 insertions(+), 74 deletions(-)
create mode 100644 python/samba/tests/dcerpc/dfs.py
Changeset truncated at 500 lines:
diff --git a/VERSION b/VERSION
index b91b719c4b5..35ac38d9d15 100644
--- a/VERSION
+++ b/VERSION
@@ -89,7 +89,7 @@ SAMBA_VERSION_PRE_RELEASE=
# e.g. SAMBA_VERSION_RC_RELEASE=1 #
# -> "3.0.0rc1" #
########################################################
-SAMBA_VERSION_RC_RELEASE=2
+SAMBA_VERSION_RC_RELEASE=3
########################################################
# To mark SVN snapshots this should be set to 'yes' #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 051fa2084de..7367f771995 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,7 +1,7 @@
Release Announcements
=====================
-This is the second release candidate release of Samba 4.23. This is *not*
+This is the third release candidate release of Samba 4.23. This is *not*
intended for production environments and is designed for testing
purposes only. Please report any defects via the Samba bug reporting
system at https://bugzilla.samba.org/.
@@ -18,23 +18,60 @@ NEW FEATURES/CHANGES
Enable SMB3 Unix Extensions by default
--------------------------------------
-todo
+Starting with Samba 4.23, the SMB3 UNIX Extensions are enabled by
+default. These extensions provide first-class support for POSIX semantics
+over SMB3, allowing UNIX and Linux clients to access file services with
+features such as proper POSIX permissions, symlink handling, hardlinks,
+and special file types.
+
+Enabling this feature by default improves interoperability for UNIX/Linux
+clients without requiring additional configuration. Windows clients that
+do not support the extensions will continue to function normally, by
+using standard SMB3 behavior.
Add support for SMB3 over QUIC
------------------------------
-todo
+The new "client smb transports" and "server smb transport"
+allow a more flexible configuration for the used tcp
+sockets.
+
+It also got the ability specify "quic" as possible transport.
+If quic should be used in addition to the defaults something
+like "server smb transports = +quic" can be used.
+
+For the client quic only works with name based uncs,
+ip address based uncs are not supported.
+
+Note for the server 'quic' requires the quic.ko kernel module
+for Linux from https://github.com/lxin/quic (tested with Linux 6.14).
+Future Linux versions may support it natively, here's the
+branch that will hopefully accepted upstream soon:
+https://github.com/lxin/net-next/commits/quic/
+
+For the client side there's a fallback to the userspace ngtcp2
+library if the quic kernel module is not available.
+
+Check the smb.conf manpage for additional hints
+about the "client smb transports" and "server smb transport"
+options and interactions with tls related options.
Modern write time update logic
------------------------------
-todo
+Samba 4.23 changes file timestamp handling to match modern Windows servers.
+Earlier releases used delayed write time updates, where last_write_time was
+only refreshed after a short idle period. Now Samba applies immediate
+timestamp updates consistent with modern Windows 10/Server 2016 or newer.
Initial version of smb_prometheus_endpoint
------------------------------------------
-todo
+Samba 4.23 introduces the smb_prometheus_endpoint utility, which exports
+Samba server metrics in Prometheus-compatible format. This enables seamless
+integration of Samba performance and status monitoring into existing
+Prometheus and Grafana environments. For usage and configuration details,
+refer to the new smb_prometheus_endpoint man page.
samba-tool domain backup --no-secrets avoids confidential attributes
--------------------------------------------------------------------
-
The --no-secrets option creates a back-up without secret attributes
(e.g. passwords), suitable for use in a lab domain. Until now it could
still contain confidential attributes, including BitLocker recovery
@@ -45,20 +82,19 @@ schema to have confidential attributes and are no use
without them.
CTDB changes
------------
-
-* CTDB now supports loading tunables from
- /etc/ctdb/tunables.d/*.tunables, in addition to the standard
- /etc/ctdb/tunables.conf. See the ctdb-tunables(7) manual page for
- more details. Note that the above locations are examples - the
- actual location of these files will depend on compile time
- configuration.
-
- It isn't expected that many users will require a directory of tunables
- files, since most users do not need to change tunables from their
- default values. However, this allows vendors to ship their required
- tunables settings (for example, in one or more files marked "do not
- edit") while still allowing local administrators to add their own
- tunables settings (in one or more separate files).
+CTDB now supports loading tunables from
+/etc/ctdb/tunables.d/*.tunables, in addition to the standard
+/etc/ctdb/tunables.conf. See the ctdb-tunables(7) manual page for
+more details. Note that the above locations are examples - the
+actual location of these files will depend on compile time
+configuration.
+
+It isn't expected that many users will require a directory of tunables
+files, since most users do not need to change tunables from their
+default values. However, this allows vendors to ship their required
+tunables settings (for example, in one or more files marked "do not
+edit") while still allowing local administrators to add their own
+tunables settings (in one or more separate files).
Per-share profiling stats
-------------------------
@@ -89,6 +125,21 @@ smb.conf changes
server smb transports New tcp, nbt
winbind varlink service New no
+
+CHANGES SINCE 4.23.0rc2
+=======================
+
+o Ralph Boehme <[email protected]>
+ * BUG 15843: macOS Finder client DFS broken on 4.22.0.
+
+o Stefan Metzmacher <[email protected]>
+ * BUG 15899: Self-signed certificates don't have X509v3 Subject Alternative
+ Name for DNS.
+
+o Andreas Schneider <[email protected]>
+ * BUG 15893: Improve handling of principals and realms in client tools.
+
+
CHANGES SINCE 4.23.0rc1
=======================
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index c31470a81d2..dab1c047c13 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -33,6 +33,18 @@
#include "system/filesys.h"
#include "system/passwd.h"
+static bool str_is_ascii(const char *s) {
+ if (s != NULL) {
+ for (; s[0] != '\0'; s++) {
+ if (!isascii(s[0])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
/**
* Create a new credentials structure
* @param mem_ctx TALLOC_CTX parent for credentials structure
@@ -367,9 +379,31 @@ _PUBLIC_ char
*cli_credentials_get_principal_and_obtained(struct cli_credentials
if (cred->principal_obtained == CRED_CALLBACK &&
!cred->callback_running) {
+ const char *princ = NULL;
+
cred->callback_running = true;
- cred->principal = cred->principal_cb(cred);
+ princ = cred->principal_cb(cred);
cred->callback_running = false;
+
+ cred->principal = NULL;
+ if (princ != NULL) {
+ char *p = NULL;
+
+ cred->principal = talloc_strdup(cred, princ);
+ if (cred->principal == NULL) {
+ return NULL;
+ }
+
+ p = strchr(cred->principal, '@');
+ if (p != NULL) {
+ p += 1;
+
+ for (; p[0] != '\0'; p++) {
+ *p = toupper(p[0]);
+ }
+ }
+ }
+
if (cred->principal_obtained == CRED_CALLBACK) {
cred->principal_obtained = CRED_CALLBACK_RESULT;
cli_credentials_invalidate_ccache(cred,
cred->principal_obtained);
@@ -427,17 +461,52 @@ _PUBLIC_ char *cli_credentials_get_principal(struct
cli_credentials *cred, TALLO
return cli_credentials_get_principal_and_obtained(cred, mem_ctx,
&obtained);
}
+/**
+ * @brief Set the principal for the credentials context.
+ *
+ * The realm of the principal will be checked if it is ASCII only and upper
+ * cased if it isn't yet.
+ *
+ * @param cred The credential context.
+ *
+ * @param val The principal to set or NULL to reset.
+ *
+ * @param obtained This way the described principal was specified.
+ *
+ * @return true on success, false if the realm is not ASCII or the allocation
+ * failed.
+ */
_PUBLIC_ bool cli_credentials_set_principal(struct cli_credentials *cred,
- const char *val,
- enum credentials_obtained obtained)
+ const char *val,
+ enum credentials_obtained obtained)
{
if (obtained >= cred->principal_obtained) {
- cred->principal = talloc_strdup(cred, val);
- if (cred->principal == NULL) {
- return false;
+ /* If `val = NULL` is passed, principal is reset */
+ cred->principal = NULL;
+ if (val != NULL) {
+ char *p = strchr(val, '@');
+ if (p != NULL) {
+ /* For realm names, only ASCII is allowed */
+ if (!str_is_ascii(p + 1)) {
+ return false;
+ }
+ }
+
+ cred->principal = talloc_strdup(cred, val);
+ if (cred->principal == NULL) {
+ return false;
+ }
+
+ p = strchr(cred->principal, '@');
+ if (p != NULL) {
+ p += 1;
+
+ for (; p[0] != '\0'; p++) {
+ *p = toupper(p[0]);
+ }
+ }
}
cred->principal_obtained = obtained;
-
cli_credentials_invalidate_ccache(cred,
cred->principal_obtained);
return true;
}
@@ -623,6 +692,7 @@ _PUBLIC_ bool cli_credentials_set_password(struct
cli_credentials *cred,
if (cred->password == NULL) {
return false;
}
+ talloc_keep_secret(discard_const(cred->password));
/* Don't print the actual password in talloc memory dumps */
talloc_set_name_const(cred->password,
@@ -912,9 +982,20 @@ _PUBLIC_ const char *cli_credentials_get_realm(struct
cli_credentials *cred)
if (cred->realm_obtained == CRED_CALLBACK &&
!cred->callback_running) {
+ const char *realm = NULL;
+
cred->callback_running = true;
- cred->realm = cred->realm_cb(cred);
+ realm = cred->realm_cb(cred);
cred->callback_running = false;
+
+ cred->realm = NULL;
+ if (realm != NULL) {
+ cred->realm = strupper_talloc(cred, realm);
+ if (cred->realm == NULL) {
+ return NULL;
+ }
+ }
+
if (cred->realm_obtained == CRED_CALLBACK) {
cred->realm_obtained = CRED_CALLBACK_RESULT;
cli_credentials_invalidate_ccache(cred,
cred->realm_obtained);
@@ -925,15 +1006,37 @@ _PUBLIC_ const char *cli_credentials_get_realm(struct
cli_credentials *cred)
}
/**
- * Set the realm for this credentials context, and force it to
- * uppercase for the sanity of our local kerberos libraries
+ * @brief Set the realm for this credentials context.
+ *
+ * The realm be checked if it is ASCII only and upper cased if it isn't yet.
+ *
+ * @param cred The credential context.
+ *
+ * @param val The realm to set or NULL to reset.
+ *
+ * @param obtained This way the described realm was specified.
+ *
+ * @return true on success, false if the realm is not ASCII or the allocation
+ * failed.
*/
_PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred,
- const char *val,
- enum credentials_obtained obtained)
+ const char *val,
+ enum credentials_obtained obtained)
{
if (obtained >= cred->realm_obtained) {
- cred->realm = strupper_talloc(cred, val);
+ /* If `val = NULL` is passed, realm is reset */
+ cred->realm = NULL;
+ if (val != NULL) {
+ /* For realm names, only ASCII is allowed */
+ if (!str_is_ascii(val)) {
+ return false;
+ }
+
+ cred->realm = strupper_talloc(cred, val);
+ if (cred->realm == NULL) {
+ return false;
+ }
+ }
cred->realm_obtained = obtained;
cli_credentials_invalidate_ccache(cred, cred->realm_obtained);
return true;
@@ -1030,8 +1133,6 @@ _PUBLIC_ void cli_credentials_parse_string(struct
cli_credentials *credentials,
}
if ((p = strchr_m(uname,'@'))) {
- char *x = NULL;
-
/*
* We also need to set username and domain
* in order to undo the effect of
@@ -1040,11 +1141,6 @@ _PUBLIC_ void cli_credentials_parse_string(struct
cli_credentials *credentials,
cli_credentials_set_username(credentials, uname, obtained);
cli_credentials_set_domain(credentials, "", obtained);
- /* Make sure the realm is uppercase */
- for (x = p + 1; x[0] != '\0'; x++) {
- *x = toupper_m(*x);
- }
-
cli_credentials_set_principal(credentials, uname, obtained);
*p = 0;
cli_credentials_set_realm(credentials, p+1, obtained);
@@ -1535,7 +1631,9 @@ _PUBLIC_ void
cli_credentials_get_ntlm_username_domain(struct cli_credentials *c
const char **username,
const char **domain)
{
- if (cred->principal_obtained >= cred->username_obtained) {
+ if (!cli_credentials_is_anonymous(cred) &&
+ cred->principal_obtained >= cred->username_obtained)
+ {
*domain = talloc_strdup(mem_ctx, "");
*username = cli_credentials_get_principal(cred, mem_ctx);
} else {
diff --git a/auth/credentials/credentials_cmdline.c
b/auth/credentials/credentials_cmdline.c
index c8c7c183c22..e9cdc80d52a 100644
--- a/auth/credentials/credentials_cmdline.c
+++ b/auth/credentials/credentials_cmdline.c
@@ -46,6 +46,7 @@ static const char *cmdline_get_userpassword(struct
cli_credentials *creds)
goto fail;
}
talloc_set_name_const(ret, __location__);
+ talloc_keep_secret(ret);
fail:
ZERO_STRUCT(pwd);
TALLOC_FREE(frame);
diff --git a/python/samba/tests/credentials.py
b/python/samba/tests/credentials.py
index bc132681c48..1835d9b7b59 100644
--- a/python/samba/tests/credentials.py
+++ b/python/samba/tests/credentials.py
@@ -361,7 +361,7 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.get_username(), "env_user")
self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
self.assertEqual(creds.get_realm(), realm.upper())
- self.assertEqual(creds.get_principal(), "[email protected]")
+ self.assertEqual(creds.get_principal(), "[email protected]")
creds.parse_string("domain\\user")
self.assertEqual(creds.get_username(), "user")
self.assertEqual(creds.get_domain(), "DOMAIN")
@@ -385,7 +385,7 @@ class CredentialsTests(samba.tests.TestCaseInTempDir):
self.assertEqual(creds.get_username(), "env_user")
self.assertEqual(creds.get_domain(), lp.get("workgroup").upper())
self.assertEqual(creds.get_realm(), realm.upper())
- self.assertEqual(creds.get_principal(), "[email protected]")
+ self.assertEqual(creds.get_principal(), "[email protected]")
creds.parse_string("domain\\user")
self.assertEqual(creds.get_username(), "user")
self.assertEqual(creds.get_domain(), "DOMAIN")
diff --git a/python/samba/tests/dcerpc/dfs.py b/python/samba/tests/dcerpc/dfs.py
new file mode 100644
index 00000000000..0fcce324e55
--- /dev/null
+++ b/python/samba/tests/dcerpc/dfs.py
@@ -0,0 +1,48 @@
+#
+# Unix SMB/CIFS implementation.
+# Copyright Ralph Boehme <[email protected]> 2025
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Tests for samba.dcerpc.dfs"""
+
+import os
+import logging
+import samba
+from samba.dcerpc import dfs
+from samba.tests import RpcInterfaceTestCase
+from samba.logger import get_samba_logger
+from samba.credentials import Credentials
+from samba.samba3 import libsmb_samba_internal as libsmb
+import samba.tests.libsmb
+from samba.samba3 import param as s3param
+
+logger = get_samba_logger(name=__name__)
+
+class DfsTests(samba.tests.libsmb.LibsmbTests):
+ def setUp(self):
+ super().setUp()
+ self.dfs = dfs.netdfs('ncacn_np:%s[/pipe/netdfs]' % self.server,
self.lp, self.creds)
+ self.c = libsmb.Conn(self.server_ip, "msdfs-share", self.lp,
self.creds)
+
+ def tearDown(self):
+ super().tearDown()
+
+ def test_dfs_reparse_tag(self):
+ self.dfs.Add('\\\\%s\\msdfs-share\\dfslink' % self.server,
self.server, 'tmp', 'comment', 0)
+ l = self.c.list('', info_level=libsmb.SMB2_FIND_ID_BOTH_DIRECTORY_INFO)
+ files = {i['name']: i for i in l}
+ self.assertEqual(files['dfslink']['reparse_tag'],
libsmb.IO_REPARSE_TAG_DFS)
+ self.dfs.Remove('\\\\%s\\msdfs-share\\dfslink' % self.server,
self.server, 'tmp')
diff --git a/python/samba/tests/libsmb.py b/python/samba/tests/libsmb.py
index 3ac1b68a59b..e3683901df2 100644
--- a/python/samba/tests/libsmb.py
+++ b/python/samba/tests/libsmb.py
@@ -43,6 +43,7 @@ class LibsmbTests(samba.tests.TestCase):
server_conf_dir = os.path.dirname(server_conf)
self.global_inject = os.path.join(server_conf_dir,
"global_inject.conf")
+ self.server = samba.tests.env_get_var_value("SERVER")
self.server_ip = samba.tests.env_get_var_value("SERVER_IP")
def clean_file(self, conn, filename):
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c
index 67872d8e3b1..cba910d173d 100644
--- a/source3/libsmb/pylibsmb.c
+++ b/source3/libsmb/pylibsmb.c
@@ -3740,6 +3740,7 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
ADD_STRING(SMB2_CREATE_TAG_POSIX);
+ ADD_FLAGS(SMB2_FIND_ID_BOTH_DIRECTORY_INFO);
ADD_FLAGS(SMB2_FIND_POSIX_INFORMATION);
ADD_FLAGS(FILE_SUPERSEDE);
ADD_FLAGS(FILE_OPEN);
diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c
index 447d868924d..19331d0de4f 100644
--- a/source3/modules/vfs_xattr_tdb.c
+++ b/source3/modules/vfs_xattr_tdb.c
@@ -604,13 +604,12 @@ static int xattr_tdb_unlinkat(vfs_handle_struct *handle,
} else {
ret = SMB_VFS_NEXT_STAT(handle, full_fname);
if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
- if (VALID_STAT(smb_fname->st) &&
- S_ISLNK(smb_fname->st.st_ex_mode)) {
- /*
- * Original name was a link - Could be
- * trying to remove a dangling symlink.
- */
- ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
+ /*
+ * Could be trying to remove a dangling symlink.
+ */
+ ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
+ if (ret == 0 && !S_ISLNK(full_fname->st.st_ex_mode)) {
--
Samba Shared Repository