The branch, master has been updated
via 0aee889f554 python:tarfile: notes about extraction_filter
via 7a5b22e4221 pytest: safe_tarfile: accept NotADirectoryError as bad
path rejection
via 8969e48023e s4:libsocket: better diagnostics for no interfaces
via fedbb4ecc70 s3:smbd: slightly improve no sockets panic message
via 82120ebf796 winbindd:migrate_secrets_tdb_to_ldb() handles no client
password
via 491bd6c9603 s4:smb_composite: session_setup_old() handles no
password
via 316144621b2 s4:smb_composite: session_setup_nt1() handles no
password
via 18928f524c4 utils/smbtree: do not crash with no password (-N)
via 649f78252bc auth: avoid strcmp(x, NULL)
via 6e5626f2f26 auth: fix docs for
cli_credentials_get_password_and_obtained()
via b6a80e68b7a domsid: be less alarmed by non-SID
via 15416d801a0 dsdb:password_hash.c: restrict crypt hash to proper
forms
via 812998b15ff python:build: do not allow sizeof(int) != 4
from 499656a0501 s4:lib/tls: add additional dns hostnames as
GNUTLS_SAN_DNSNAME for self-signed certificates
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 0aee889f5548e2cae596ab84e0d39780f9844735
Author: Douglas Bagnall <[email protected]>
Date: Fri Aug 22 16:23:16 2025 +1200
python:tarfile: notes about extraction_filter
a reminder to delete.
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
Autobuild-User(master): Douglas Bagnall <[email protected]>
Autobuild-Date(master): Tue Aug 26 23:43:08 UTC 2025 on atb-devel-224
commit 7a5b22e4221ea2a0960a26cf79339168f0899d0c
Author: Douglas Bagnall <[email protected]>
Date: Fri Aug 22 15:24:34 2025 +1200
pytest: safe_tarfile: accept NotADirectoryError as bad path rejection
After recent upstream Python fixes for various path escape and symlink
CVEs in tarfile, in particular this commit:
commit 3612d8f51741b11f36f8fb0494d79086bac9390a
Author: Łukasz Langa <[email protected]>
Date: Tue Jun 3 12:42:11 2025 +0200
gh-135034: Normalize link targets in tarfile, add
`os.path.realpath(strict='allow_missing')` (#135037)
Addresses CVEs 2024-12718, 2025-4138, 2025-4330, and 2025-4517.
Signed-off-by: Łukasz Langa <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
Co-authored-by: Petr Viktorin <[email protected]>
Co-authored-by: Seth Michael Larson <[email protected]>
Co-authored-by: Adam Turner <[email protected]>
Co-authored-by: Serhiy Storchaka <[email protected]>
our ../../ test that looks for a tarfile.OutsideDestinationError now
meets a NotADirectoryError in recent Python versions (this from 3.13,
Fedora 42):
UNEXPECTED(error):
samba.tests.safe_tarfile.samba.tests.safe_tarfile.SafeTarFileTestCase.test_dots(none)
REASON: Exception: Exception: Traceback (most recent call last):
File
"/tmp/samba-testbase/b1/samba-o3/bin/python/samba/tests/safe_tarfile.py", line
48, in test_dots
self.assertRaises(tarfile.OutsideDestinationError,
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stf.extractall,
^^^^^^^^^^^^^^^
tarname)
^^^^^^^^
File "/usr/lib64/python3.13/unittest/case.py", line 795, in assertRaises
return context.handle('assertRaises', args, kwargs)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/unittest/case.py", line 238, in handle
callable_obj(*args, **kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/tarfile.py", line 2343, in extractall
tarinfo, unfiltered = self._get_extract_tarinfo(
~~~~~~~~~~~~~~~~~~~~~~~~~^
member, filter_function, path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/tarfile.py", line 2432, in
_get_extract_tarinfo
self._handle_fatal_error(e)
~~~~~~~~~~~~~~~~~~~~~~~~^^^
File "/usr/lib64/python3.13/tarfile.py", line 2430, in
_get_extract_tarinfo
filtered = filter_function(unfiltered, path)
File "/usr/lib64/python3.13/tarfile.py", line 842, in tar_filter
new_attrs = _get_filtered_attrs(member, dest_path, False)
File "/usr/lib64/python3.13/tarfile.py", line 783, in _get_filtered_attrs
target_path = os.path.realpath(os.path.join(dest_path, name),
strict=os.path.ALLOW_MISSING)
File "<frozen posixpath>", line 457, in realpath
NotADirectoryError: [Errno 20] Not a directory:
'/tmp/samba-testbase/b1/samba-o3/bin/ab/tmp/tmpbn6e69ci/tar.tar'
In this commit, we say that a NotADirectoryError is OK.
When we started safe_tarfile we were acting in advance of upstream
Python, but now they are well ahead of us. If we trust their work in
recent versions and accept the error conditions they choose, we can
more easily get rid of our safe_tarfile when the time is right.
For the moment we still support as far back as Python 3.6 for some old
enterprise distros, and it is for those that we continue to maintain
safe_tarfile. In versions before 3.11 we will see
tarfile.ExtractError, and the test for that is unaffected by this
change.
Signed-off-by: Douglas Bagnall <[email protected]>
commit 8969e48023eaf073eb1d4e9122afe4ac98f414a7
Author: Douglas Bagnall <[email protected]>
Date: Fri Feb 7 13:37:37 2025 +1300
s4:libsocket: better diagnostics for no interfaces
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit fedbb4ecc708ecd9744989dbebbff2cbe88822ff
Author: Douglas Bagnall <[email protected]>
Date: Fri Feb 7 13:36:24 2025 +1300
s3:smbd: slightly improve no sockets panic message
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 82120ebf7967584c8f4d55e710d2e4b7b1c32126
Author: Douglas Bagnall <[email protected]>
Date: Wed Feb 5 16:50:28 2025 +1300
winbindd:migrate_secrets_tdb_to_ldb() handles no client password
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 491bd6c960328e0987351656b3fb73f301fd73d5
Author: Douglas Bagnall <[email protected]>
Date: Wed Feb 5 16:49:21 2025 +1300
s4:smb_composite: session_setup_old() handles no password
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 316144621b20d0de0384ae1c66c05dfbec3b68a2
Author: Douglas Bagnall <[email protected]>
Date: Wed Feb 5 16:49:01 2025 +1300
s4:smb_composite: session_setup_nt1() handles no password
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 18928f524c41f6584925fc0313f0e5405e9ceb3d
Author: Douglas Bagnall <[email protected]>
Date: Wed Feb 5 16:47:39 2025 +1300
utils/smbtree: do not crash with no password (-N)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15170
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 649f78252bcafc5e3ee77f0ed9c13028243e004c
Author: Douglas Bagnall <[email protected]>
Date: Wed Feb 5 16:45:06 2025 +1300
auth: avoid strcmp(x, NULL)
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 6e5626f2f268a2d237dccd711517a0bf2e076671
Author: Douglas Bagnall <[email protected]>
Date: Wed Feb 5 16:40:47 2025 +1300
auth: fix docs for cli_credentials_get_password_and_obtained()
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit b6a80e68b7a26eccaaf822d7877b6870196c086d
Author: Douglas Bagnall <[email protected]>
Date: Sat May 4 13:07:26 2024 +1200
domsid: be less alarmed by non-SID
This has been causing log noise when something is trying to parse an
identifier using a sequence of parsers, to see if it is a SID, a DN,
an account name, etc.
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 15416d801a0ade89f2754b59f46f4fb3dc188290
Author: Douglas Bagnall <[email protected]>
Date: Fri Jan 31 09:24:53 2025 +1300
dsdb:password_hash.c: restrict crypt hash to proper forms
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
commit 812998b15ff9130d8f7139e20ac61ac75e68eff0
Author: Douglas Bagnall <[email protected]>
Date: Thu May 29 12:58:48 2025 +1200
python:build: do not allow sizeof(int) != 4
A non-32 bit int will (if the compiler allows it) result in code
where we write into memory adjacent to a target uint32_t value in
many python bindings using the python arg-parsing API. The more
correct thing to do would be to always parse into an unsigned long
long and error if it is greater than UINT32_MAX, but we do this in
so many places that there is reason to believe we'll just keep
adding more.
Note, we already check in lib/replace/wscript that int is at least
32 bits; here we are effectively just checking that it is not more.
There was apparently a version of 64 bit Solaris in the 1990s that
had 64 bit ints.
Signed-off-by: Douglas Bagnall <[email protected]>
Reviewed-by: Jennifer Sutton <[email protected]>
-----------------------------------------------------------------------
Summary of changes:
auth/credentials/credentials.c | 2 +-
auth/credentials/credentials_secrets.c | 7 ++++++-
libcli/security/dom_sid.c | 3 ++-
python/samba/safe_tarfile.py | 17 ++++++++++++++++-
python/samba/tests/safe_tarfile.py | 3 ++-
python/wscript | 13 +++++++++++++
source3/smbd/server.c | 7 +++++--
source3/utils/smbtree.c | 9 +++++++--
source3/winbindd/winbindd_util.c | 11 +++++++++--
source4/dsdb/samdb/ldb_modules/password_hash.c | 24 ++++++++++++++++++++++++
source4/lib/socket/interface.c | 11 ++++++++---
source4/libcli/smb_composite/sesssetup.c | 7 +++++++
12 files changed, 100 insertions(+), 14 deletions(-)
Changeset truncated at 500 lines:
diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c
index dab1c047c13..a8e3e22002f 100644
--- a/auth/credentials/credentials.c
+++ b/auth/credentials/credentials.c
@@ -626,7 +626,7 @@ cli_credentials_get_password_obtained(struct
cli_credentials *cred)
*
* @param[in] obtained A pointer to store the obtained information.
*
- * return The user name or NULL if an error occurred.
+ * return The password if there is one.
*/
_PUBLIC_ const char *
cli_credentials_get_password_and_obtained(struct cli_credentials *cred,
diff --git a/auth/credentials/credentials_secrets.c
b/auth/credentials/credentials_secrets.c
index 5f4c6cd1ed1..a5cc389a57d 100644
--- a/auth/credentials/credentials_secrets.c
+++ b/auth/credentials/credentials_secrets.c
@@ -364,7 +364,12 @@ _PUBLIC_ NTSTATUS
cli_credentials_set_machine_account_db_ctx(struct cli_credenti
} else if (secrets_tdb_lct >
cli_credentials_get_password_last_changed_time(cred)) {
secrets_tdb_password_more_recent = true;
} else if (secrets_tdb_lct ==
cli_credentials_get_password_last_changed_time(cred)) {
- secrets_tdb_password_more_recent = strcmp(secrets_tdb_password,
cli_credentials_get_password(cred)) != 0;
+ const char *pwd = cli_credentials_get_password(cred);
+ if (pwd == NULL || (strcmp(secrets_tdb_password, pwd) != 0)) {
+ secrets_tdb_password_more_recent = true;
+ } else {
+ secrets_tdb_password_more_recent = false;
+ }
} else {
secrets_tdb_password_more_recent = false;
}
diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
index c898d87f64a..2cb755dcd42 100644
--- a/libcli/security/dom_sid.c
+++ b/libcli/security/dom_sid.c
@@ -163,7 +163,8 @@ bool dom_sid_parse_endp(const char *sidstr,struct dom_sid
*sidout,
*sidout = (struct dom_sid) {};
if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
- goto format_error;
+ DBG_INFO("'%s' is not a SID\n", sidstr);
+ return false;
}
/* Get the revision number. */
diff --git a/python/samba/safe_tarfile.py b/python/samba/safe_tarfile.py
index 1015fcf4a8c..88b32965c8a 100644
--- a/python/samba/safe_tarfile.py
+++ b/python/samba/safe_tarfile.py
@@ -28,9 +28,24 @@ class TarFile(UnsafeTarFile):
"""
try:
- # New in version 3.11.4 (also has been backported)
+ # In 3.8.18 (the last 3.8) and post 2023-08-22 versions of
+ # 3.9+ (including all of 3.12 and greater), Python's standard
+ # tarfile module uses the extraction_filter method for
+ # preventing path traversal. See:
+ #
#
https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extraction_filter
# https://peps.python.org/pep-0706/
+ #
+ # The default filter is 'fully_trusted', which allows
+ # extraction outside the directory, but in Python 3.14 the
+ # default is expected to change to the stricter 'data' filter.
+ # The 'data' filter preserves no permissions so we select the
+ # intermediate 'tar' filter here which prevents escape but
+ # preserves permissions.
+ #
+ # When we no longer support versions less than 3.8 or 3.9, we
+ # should remove this whole try...except and just have this
+ # next line as the whole class body:
extraction_filter = staticmethod(tarfile.tar_filter)
except AttributeError:
def extract(self, member, path="", set_attrs=True, *,
diff --git a/python/samba/tests/safe_tarfile.py
b/python/samba/tests/safe_tarfile.py
index 1f2cb03aeb4..6dc2a6e3355 100644
--- a/python/samba/tests/safe_tarfile.py
+++ b/python/samba/tests/safe_tarfile.py
@@ -45,7 +45,8 @@ class SafeTarFileTestCase(TestCaseInTempDir):
# If we have data_filter, we have a patched python to address
# CVE-2007-4559.
if hasattr(tarfile, "data_filter"):
- self.assertRaises(tarfile.OutsideDestinationError,
+ self.assertRaises((tarfile.OutsideDestinationError,
+ NotADirectoryError),
stf.extractall,
tarname)
else:
diff --git a/python/wscript b/python/wscript
index 7c17e390dc7..b5e509bbf1a 100644
--- a/python/wscript
+++ b/python/wscript
@@ -72,6 +72,19 @@ def configure(conf):
finally:
f.close()
+ # In many places we fill in a uint32_t with an unsigned int, using
+ # PyArg_ParseTuple("I"), which will overwrite memory if the size
+ # of the int is not 4. There are no systems on which Samba will
+ # compile where int is not 32 bit, but we are testing in case this
+ # changes.
+ if 'SIZEOF_INT' not in conf.env:
+ conf.CHECK_SIZEOF('int uint32_t')
+ sizeof_int = conf.env['SIZEOF_INT']
+ sizeof_uint32 = conf.env['SIZEOF_UINT32_T']
+ if sizeof_int != sizeof_uint32:
+ conf.fatal("Samba python bindings won't work with int bigger than
uint32_t "
+ f"(int: {sizeof_int}, uint32_t: {sizeof_uint32}).")
+
if conf.CONFIG_GET('ENABLE_SELFTEST'):
for module, package in selftest_pkgs.items():
find_third_party_module(conf, module, package)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index f31ea894600..b3b50c72fa4 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -2552,8 +2552,11 @@ quic_disabled:
smbd_init_addrchange(NULL, ev_ctx, msg_ctx, parent);
}
- if (!open_sockets_smbd(parent, ev_ctx, msg_ctx))
- exit_server("open_sockets_smbd() failed");
+ if (!open_sockets_smbd(parent, ev_ctx, msg_ctx)) {
+ DBG_ERR("smbd could not bind to a socket, which can be caused "
+ "by a bad 'interfaces' line in smb.conf\n");
+ exit_server("Could not bind to any sockets\n");
+ }
TALLOC_FREE(frame);
/* make sure we always have a valid stackframe */
diff --git a/source3/utils/smbtree.c b/source3/utils/smbtree.c
index 26363fd58ed..4e178113e1a 100644
--- a/source3/utils/smbtree.c
+++ b/source3/utils/smbtree.c
@@ -47,6 +47,7 @@ static void get_auth_data_with_context_fn(
{
struct cli_credentials *creds = samba_cmdline_get_creds();
size_t len;
+ const char *pwd = NULL;
len = strlcpy(domain, cli_credentials_get_domain(creds), domain_len);
if ((int)len >= domain_len) {
@@ -57,8 +58,12 @@ static void get_auth_data_with_context_fn(
if ((int)len >= user_len) {
return;
}
- len = strlcpy(
- password, cli_credentials_get_password(creds), password_len);
+ pwd = cli_credentials_get_password(creds);
+ if (pwd == NULL) {
+ pwd = "";
+ }
+
+ len = strlcpy(password, pwd, password_len);
if ((int)len >= password_len) {
/* pointless, but what can you do... */
return;
diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c
index 3c991425dd9..174ebcbdc3d 100644
--- a/source3/winbindd/winbindd_util.c
+++ b/source3/winbindd/winbindd_util.c
@@ -903,7 +903,8 @@ static void wb_imsg_new_trusted_domain(struct
imessaging_context *msg,
static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
{
bool ok;
- struct cli_credentials *creds;
+ struct cli_credentials *creds = NULL;
+ const char *password = NULL;
NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
NULL, domain, &creds);
if (!NT_STATUS_IS_OK(can_migrate)) {
@@ -919,7 +920,13 @@ static bool migrate_secrets_tdb_to_ldb(struct
winbindd_domain *domain)
* oldpass, because a new password is created at
* classicupgrade, so this is not a concern.
*/
- ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
+ password = cli_credentials_get_password(creds);
+ if (password == NULL) {
+ DBG_ERR("No password was provided for local AD domain join\n");
+ return false;
+ }
+
+ ok = secrets_store_machine_pw_sync(password,
NULL /* oldpass */,
cli_credentials_get_domain(creds),
cli_credentials_get_realm(creds),
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c
b/source4/dsdb/samdb/ldb_modules/password_hash.c
index ee4aae6d10a..b7a0c5066a7 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -1562,6 +1562,9 @@ static bool parse_scheme(const char *scheme, int
*algorithm, int *rounds) {
== 0) {
*algorithm = SHA_512_ALGORITHM_ID;
} else {
+ DBG_ERR("user password scheme '%s' is not SHA_256 or SHA_512 "
+ "('$5$' or '$6$')\n",
+ scheme);
return false;
}
@@ -1577,6 +1580,27 @@ static bool parse_scheme(const char *scheme, int
*algorithm, int *rounds) {
}
digits[i] = '\0';
*rounds = atoi(digits);
+ /*
+ * According to https://www.akkadia.org/drepper/SHA-crypt.txt
+ * SHA_256 and SHA_512 crypt rounds are restricted to the range
+ * [1000, 999_999_999]. (thus it is OK to use int and atoi).
+ *
+ * As specified crypt() itself will clamp to these values and
+ * continue, but that leads to confusing situations, like the
+ * salt not matching.
+ *
+ * Rather than let that happen, we complain and bail out. This
+ * is from smb.conf ("password hash userPassword schemes"),
+ * and we want to let the admin know it's wrong.
+ */
+ if (*rounds < 1000 || *rounds > 999999999) {
+ DBG_ERR("user password scheme '%s' specifies a non-standard "
+ "number of rounds (%d)\n",
+ scheme,
+ *rounds);
+ return false;
+ }
+
return true;
}
diff --git a/source4/lib/socket/interface.c b/source4/lib/socket/interface.c
index 65543c6a294..4899ef69b9f 100644
--- a/source4/lib/socket/interface.c
+++ b/source4/lib/socket/interface.c
@@ -331,8 +331,13 @@ void load_interface_list(TALLOC_CTX *mem_ctx, struct
loadparm_context *lp_ctx, s
ptr++;
}
- if (!*local_interfaces) {
- DEBUG(0,("WARNING: no network interfaces found\n"));
+ if (*local_interfaces == NULL) {
+ const char **first_ptr = lpcfg_interfaces(lp_ctx);
+ if (first_ptr != NULL && *first_ptr != NULL) {
+ DBG_ERR("None of the interfaces listed in smb.conf "
+ "'interfaces = ...' seem to exist\n");
+ }
+ DBG_ERR("WARNING: no network interfaces found\n");
}
talloc_free(ifaces);
}
@@ -356,7 +361,7 @@ int iface_list_count(struct interface *ifaces)
const char *iface_list_n_ip(struct interface *ifaces, int n)
{
struct interface *i;
-
+
for (i=ifaces;i && n;i=i->next)
n--;
diff --git a/source4/libcli/smb_composite/sesssetup.c
b/source4/libcli/smb_composite/sesssetup.c
index 553132c76bb..c1c4c3dc85a 100644
--- a/source4/libcli/smb_composite/sesssetup.c
+++ b/source4/libcli/smb_composite/sesssetup.c
@@ -377,6 +377,9 @@ static NTSTATUS session_setup_nt1(struct composite_context
*c,
NT_STATUS_NOT_OK_RETURN(nt_status);
} else if (session->options.plaintext_auth) {
const char *password =
cli_credentials_get_password(io->in.credentials);
+ if (password == NULL) {
+ password = "";
+ }
state->setup.nt1.in.password1 = data_blob_talloc(state,
password, strlen(password));
state->setup.nt1.in.password2 = data_blob(NULL, 0);
} else {
@@ -438,6 +441,10 @@ static NTSTATUS session_setup_old(struct composite_context
*c,
*/
DATA_BLOB session_key;
+ if (password == NULL) {
+ password = "";
+ }
+
state->setup.old.level = RAW_SESSSETUP_OLD;
state->setup.old.in.bufsize = session->transport->options.max_xmit;
state->setup.old.in.mpx_max = session->transport->options.max_mux;
--
Samba Shared Repository