[Pkg-samba-maint] [Git][samba-team/samba][upstream_4.19] 26 commits: VERSION: Bump version up to Samba 4.19.9...
Michael Tokarev (@mjt)
gitlab at salsa.debian.org
Fri Oct 18 16:01:06 BST 2024
Michael Tokarev pushed to branch upstream_4.19 at Debian Samba Team / samba
Commits:
9d57d32b by Jule Anger at 2024-08-15T13:56:30+02:00
VERSION: Bump version up to Samba 4.19.9...
and re-enable GIT_SNAPSHOT.
Signed-off-by: Jule Anger <janger at samba.org>
- - - - -
3db88bd0 by Stefan Metzmacher at 2024-08-20T12:03:11+00:00
s4:torture/smb2: let smb2.session.expire2* also check compound requests
This shows that all compound related requests should get
NT_STATUS_NETWORK_SESSION_EXPIRED.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15696
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
(cherry picked from commit f6009aa73b9234df1e6ab689de322487ad1394ed)
- - - - -
2d944eb0 by Stefan Metzmacher at 2024-08-20T13:02:43+00:00
s3:smb2_server: return NT_STATUS_NETWORK_SESSION_EXPIRED for compound requests
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15696
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Autobuild-User(master): Jeremy Allison <jra at samba.org>
Autobuild-Date(master): Tue Aug 13 22:29:28 UTC 2024 on atb-devel-224
(cherry picked from commit 4df1bfd07012dd3d2d2921281e6d6e309303b88d)
Autobuild-User(v4-19-test): Jule Anger <janger at samba.org>
Autobuild-Date(v4-19-test): Tue Aug 20 13:02:43 UTC 2024 on atb-devel-224
- - - - -
a92076d8 by Shachar Sharon at 2024-08-26T10:25:30+00:00
s3:smbd: fix NULL dereference in case of readlink failure
When VFS readlinkat hook returns with error the following sequence
yields NULL-pointer dereference (SIGSEGV):
symlink_target_below_conn (source3/smbd/open.c)
char *target = NULL;
...
readlink_talloc (source3/smbd/files.c)
SMB_VFS_READLINKAT
smb_vfs_call_readlinkat (source3/smbd/vfs.c)
handle->fns->readlinkat_fn --> returns error
status = safe_symlink_target_path(.., target /* NULL */ ..)
safe_symlink_target_path (source3/smbd/filename.c)
if (target[0] == '/') { /* NULL pointer dereference */
A failure in VFS module's readlinkat hook may happen due to run-time
error (e.g., network failure which cases libcephfs to disconnect from
MDS).
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15700
Signed-off-by: Shachar Sharon <ssharon at redhat.com>
Reviewed-by: John Mulligan <jmulligan at redhat.com>
Reviewed-by: Volker Lendecke <vl at samba.org>
Autobuild-User(master): Volker Lendecke <vl at samba.org>
Autobuild-Date(master): Fri Aug 23 09:27:06 UTC 2024 on atb-devel-224
(cherry picked from commit 168966a053045476a84044aa73f66722eb702fe0)
Autobuild-User(v4-19-test): Jule Anger <janger at samba.org>
Autobuild-Date(v4-19-test): Mon Aug 26 10:25:30 UTC 2024 on atb-devel-224
- - - - -
3455944c by David Disseldorp at 2024-09-02T08:56:12+00:00
s4:torture/smb2: test FSCTL_QUERY_ALLOCATED_RANGES truncation
FSCTL_QUERY_ALLOCATED_RANGES responses with more than one range should
be truncated to account for a ioctl.smb2.in.max_output_response limit.
Add a test for this.
Flag the new test knownfail; fix in subsequent commit.
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Noel Power <npower at samba.org>
(cherry picked from commit 5cf57f1f539021f1490285516d8cfb2a2ab483e0)
- - - - -
1602d847 by David Disseldorp at 2024-09-02T10:02:09+00:00
smb2_ioctl: fix truncated FSCTL_QUERY_ALLOCATED_RANGES responses
As per MS-FSA 2.1.5.10.22 FSCTL_QUERY_ALLOCATED_RANGES, if response
range entries exceed in_max_output, then we should respond with
STATUS_BUFFER_OVERFLOW and a truncated output buffer.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=15699
Reported-by: David Howells <dhowells at redhat.com>
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Noel Power <npower at samba.org>
Autobuild-User(master): David Disseldorp <ddiss at samba.org>
Autobuild-Date(master): Wed Aug 28 08:54:11 UTC 2024 on atb-devel-224
(cherry picked from commit 5e278a52646a48e3671270e5b57ec5b852f9fb4b)
Autobuild-User(v4-19-test): Jule Anger <janger at samba.org>
Autobuild-Date(v4-19-test): Mon Sep 2 10:02:09 UTC 2024 on atb-devel-224
- - - - -
796d0269 by Ralph Boehme at 2024-10-02T14:34:13+00:00
s3/lib: add next helper variable in server_id_watch_*
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit d76edcd48437715c7541b5b1e6a56245c25f460b)
- - - - -
b365e106 by Ralph Boehme at 2024-10-02T14:34:13+00:00
s3/lib: add option "serverid watch:debug = yes" to print kernel stack of hanging process
We only do if sys_have_proc_fds() returns true, so it's most likely
linux...
Enabled by default with log level 10...
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit 5c57e840527432c4b1a7ec94894939022a9e9622)
- - - - -
b5388c25 by Ralph Boehme at 2024-10-02T14:34:13+00:00
s3/lib: add option "serverid watch:debug script"
This takes just PID and NODE:PID on a cluster.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit 7add7dbf1aee13b4d9ab70d1a5312c8ff30d9e00)
- - - - -
71568683 by Ralph Boehme at 2024-10-02T14:34:13+00:00
smbd: log share_mode_watch_recv() errors as errors
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit b45e78871aadca6ae33475bee890736838f44219)
- - - - -
2c8dfff7 by Ralph Boehme at 2024-10-02T14:34:13+00:00
smbd: add option "smbd lease break:debug hung procs"
By enabling this a process sending a lease break message to another process
holding a lease will start watching that process and if that process didn't
process the lease break within 10 seconds (cf server_id_watch_waited()), we log
a kernel stack backtrace of that process.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit d8613d7ee23c4e990285a387eb9ac2eeefff9749)
- - - - -
38242b55 by Ralph Boehme at 2024-10-02T14:34:13+00:00
smbd: move trace_state variable behind tv variable
Next commit adds timestamp variables to trace_state that want to be initialized
with the current time, so moving behind tv we can then just reuse tv for that.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit 679e12aee2f0c283a6f9b9c6008c549a6ca9633e)
- - - - -
3e6d740b by Ralph Boehme at 2024-10-02T14:34:13+00:00
smbd: add option "smbd:debug events" for tevent handling duration threshold warnings
Can be used to enable printing an error message if tevent event handlers ran
longer then three seconds. Also logs a message with a loglevel of 3 if there
were no events at hall.
Enabled by default with 'log level = 10' or
'smbd profiling level = on'...
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit 90d776cb18395ed804f0ab4fd13ef571fc0ad827)
- - - - -
b0fb5a1d by Stefan Metzmacher at 2024-10-02T14:34:13+00:00
vfs_error_inject: add 'error_inject:durable_reconnect = st_ex_nlink'
This allows to simulate durable reconnect failures because the stat
information of the file changed.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit 692ed832dfff61ad1c9b646b5c8d6f85f25efb99)
- - - - -
5f3f8835 by Stefan Metzmacher at 2024-10-02T14:34:13+00:00
s4:torture/smb2: add smb2.durable-v2-regressions.durable_v2_reconnect_bug15624
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit ef4ef04e7f83b1029446ff8b5fc5fdf4ab33edbd)
- - - - -
153f9027 by Stefan Metzmacher at 2024-10-02T14:34:13+00:00
s3:tests: let test_durable_handle_reconnect.sh run smb2.durable-v2-regressions.durable_v2_reconnect_bug15624
This demonstrates the dead lock after a durable reconnect failed
because the stat info changed, the file can't be accessed anymore
as we leak the incomplete share mode entry in a still running
process.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit 14875448ca06a3a28800343a3a326f1a66bccec0)
- - - - -
92d7e6c6 by Ralph Boehme at 2024-10-02T14:34:13+00:00
smbd: consolidate DH reconnect failure code
No change in behaviour, except that we now
also call fd_close() if vfs_default_durable_cookie()
failed.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
(cherry picked from commit a91457f97c98fcec1ed062514c364271af1df669)
- - - - -
335ce71c by Ralph Boehme at 2024-10-02T14:34:13+00:00
smbd: remove just created sharemode entry in the error codepaths
Without this we leave stale sharemode entries around that can lead to all sorts
of havoc.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15624
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Guenther Deschner <gd at samba.org>
Autobuild-User(master): Günther Deschner <gd at samba.org>
Autobuild-Date(master): Thu Sep 19 19:36:19 UTC 2024 on atb-devel-224
(cherry picked from commit 2ff3b9bc0d254a63a913ff9084de3d794fee27d0)
- - - - -
13cfe36b by Stefan Metzmacher at 2024-10-02T15:37:43+00:00
s4:lib/messaging: fix interaction between imessaging_reinit and irpc_destructor
This was missing in commit 0d096931196524a2d1bf59470bc629dc9231131e.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15280
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
Autobuild-Date(master): Wed Sep 18 19:45:56 UTC 2024 on atb-devel-224
(cherry picked from commit a14320461e3abb56f5dacc90ca73bc1143270394)
Autobuild-User(v4-19-test): Jule Anger <janger at samba.org>
Autobuild-Date(v4-19-test): Wed Oct 2 15:37:43 UTC 2024 on atb-devel-224
- - - - -
9a617692 by Douglas Bagnall at 2024-10-07T14:18:15+00:00
ldb_kv_index: dn_list load sub transaction can re-use keys
We don't want to modify the original list, but we can reuse the keys
if we treat them as immutable and don't free them. That makes it a lot
quicker if there are many keys (i.e. where an index is useful) and may
sub-transactions. In particular, it avoids O(n²) talloc_memdups.
A removed comment that says "We have to free the top level index
memory otherwise we would leak", and this will be addressed in the
next commit.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15590
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
(cherry picked from commit 5f0198d69843c864f2b98a7c0c6305ad789a68a0)
- - - - -
9b338939 by Douglas Bagnall at 2024-10-07T14:18:15+00:00
ldb:kv_index: realloc away old dn list
We can't just free it, because has the GUID index list as a child, and
these are shared by the new dn list (from the subtransaction we are
committing). But if the dn list is long and the main transaction is
long-lived, we can save a lot of memory by turning this dn list into
an almost empty node in the talloc tree. This returns us to roughly
the situation we had prior to the last commit.
For example, with the repro.sh script on bug 15590 in indexes mode
with 10000 rules, The last 3 commits use this much memory at the end
of an unusually large transaction:
full talloc report on 'struct ldb_context' (total 4012222 bytes in 90058 blocks)
full talloc report on 'struct ldb_context' (total 2405482219 bytes in 90058 blocks)
full talloc report on 'struct ldb_context' (total 4282195 bytes in 90058 blocks)
That is, the last commit increased usage 500 fold, and this commit
brings it back to normal.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15590
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
(cherry picked from commit 1bf9ede94f0a6b41fb18e880e59a8e390f8c21d3)
- - - - -
5a15cbb1 by Douglas Bagnall at 2024-10-07T15:22:36+00:00
ldb:kv_index: help static analysers to not worry (CID 1615192)
The point of this realloc is that we are not using this array, but
keeping it around to remain a node the talloc tree. We'd prefer to
reduce it to nothing.
Coverity rightly spotted that it was reallocing an array of `struct
ldb_val` to an array of `struct ldb_val *`, which has a different size
and all. But it doesn't matter in this case, because we will never use
it.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15590
Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Reviewed-by: Jennifer Sutton <josutton at catalyst.net.nz>
(cherry picked from commit e2a74963fb89f5409c236a0fbe4cd070e1a75a43)
Autobuild-User(v4-19-test): Jule Anger <janger at samba.org>
Autobuild-Date(v4-19-test): Mon Oct 7 15:22:36 UTC 2024 on atb-devel-224
- - - - -
8d4a277d by Jule Anger at 2024-10-17T13:49:59+02:00
BUG 15590 ldb: Release LDB 2.8.2
* BUG 15590: libldb: performance issue with indexes.
Signed-off-by: Jule Anger <janger at samba.org>
- - - - -
4059e001 by Jule Anger at 2024-10-17T13:57:47+02:00
WHATSNEW: Add release notes for Samba 4.19.9.
Signed-off-by: Jule Anger <janger at samba.org>
- - - - -
7eabe40b by Jule Anger at 2024-10-17T13:58:18+02:00
VERSION: Disable GIT_SNAPSHOT for the 4.19.9 release.
Signed-off-by: Jule Anger <janger at samba.org>
- - - - -
c0e8acf6 by Michael Tokarev at 2024-10-18T17:54:44+03:00
New upstream version 4.19.9+dfsg
- - - - -
22 changed files:
- VERSION
- WHATSNEW.txt
- + lib/ldb/ABI/ldb-2.8.2.sigs
- + lib/ldb/ABI/pyldb-util-2.8.2.sigs
- lib/ldb/ldb_key_value/ldb_kv_index.c
- lib/ldb/wscript
- selftest/skip
- source3/lib/server_id_watch.c
- source3/modules/vfs_error_inject.c
- source3/script/tests/test_durable_handle_reconnect.sh
- source3/smbd/durable.c
- source3/smbd/open.c
- source3/smbd/smb2_ioctl.c
- source3/smbd/smb2_ioctl_filesys.c
- source3/smbd/smb2_process.c
- source3/smbd/smb2_server.c
- source4/lib/messaging/messaging.c
- source4/libcli/smb2/ioctl.c
- source4/torture/smb2/durable_v2_open.c
- source4/torture/smb2/ioctl.c
- source4/torture/smb2/session.c
- source4/torture/smb2/smb2.c
Changes:
=====================================
VERSION
=====================================
@@ -27,7 +27,7 @@ SAMBA_COPYRIGHT_STRING="Copyright Andrew Tridgell and the Samba Team 1992-2023"
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=19
-SAMBA_VERSION_RELEASE=8
+SAMBA_VERSION_RELEASE=9
########################################################
# If a official release has a serious bug #
=====================================
WHATSNEW.txt
=====================================
@@ -1,3 +1,59 @@
+ ==============================
+ Release Notes for Samba 4.19.9
+ October 17, 2024
+ ==============================
+
+
+This is the latest stable release of the Samba 4.19 release series.
+
+
+Changes since 4.19.8
+--------------------
+
+o Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+ * BUG 15590: libldb: performance issue with indexes (ldb 2.8.2 is already
+ released).
+
+o Ralph Boehme <slow at samba.org>
+ * BUG 15624: DH reconnect error handling can lead to stale sharemode entries.
+
+o David Disseldorp <ddiss at samba.org>
+ * BUG 15699: Incorrect FSCTL_QUERY_ALLOCATED_RANGES response when truncated.
+
+o Stefan Metzmacher <metze at samba.org>
+ * BUG 15280: irpc_destructor may crash during shutdown.
+ * BUG 15624: DH reconnect error handling can lead to stale sharemode entries.
+ * BUG 15696: Compound SMB2 requests don't return
+ NT_STATUS_NETWORK_SESSION_EXPIRED for all requests, confuses
+ MacOSX clients.
+
+o Shachar Sharon <ssharon at redhat.com>
+ * BUG 15700: Crash when readlinkat fails.
+
+
+#######################################
+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.8
August 15, 2024
@@ -97,8 +153,7 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
==============================
Release Notes for Samba 4.19.7
June 10, 2024
=====================================
lib/ldb/ABI/ldb-2.8.2.sigs
=====================================
@@ -0,0 +1,305 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_attrs_in_place: int (struct ldb_message *, const char * const *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_match_scope: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *, enum ldb_scope)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_distinguished_name: int (struct ldb_message *)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_string_flags: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_append_fmt: int (struct ldb_message *, int, const char *, const char *, ...)
+ldb_msg_append_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *, int)
+ldb_msg_append_steal_string: int (struct ldb_message *, const char *, char *, int)
+ldb_msg_append_steal_value: int (struct ldb_message *, const char *, struct ldb_val *, int)
+ldb_msg_append_string: int (struct ldb_message *, const char *, const char *, int)
+ldb_msg_append_value: int (struct ldb_message *, const char *, const struct ldb_val *, int)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_add_value: int (TALLOC_CTX *, struct ldb_message_element *, const struct ldb_val *)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_element_is_inaccessible: bool (const struct ldb_message_element *)
+ldb_msg_element_mark_inaccessible: void (struct ldb_message_element *)
+ldb_msg_elements_take_ownership: int (struct ldb_message *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_remove_inaccessible: void (struct ldb_message *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_shrink_to_fit: void (struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_get_attr: const char *(const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_register_redact_callback: int (struct ldb_context *, ldb_redact_fn, struct ldb_module *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_as_bool: int (const struct ldb_val *, bool *)
+ldb_val_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_val *)
+ldb_val_as_int64: int (const struct ldb_val *, int64_t *)
+ldb_val_as_uint64: int (const struct ldb_val *, uint64_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
=====================================
lib/ldb/ABI/pyldb-util-2.8.2.sigs
=====================================
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
=====================================
lib/ldb/ldb_key_value/ldb_kv_index.c
=====================================
@@ -446,34 +446,39 @@ static int ldb_kv_dn_list_load(struct ldb_module *module,
* There is an active index sub transaction, and the record was
* found in the primary index transaction cache. A copy of the
* record needs be taken to prevent the original entry being
- * altered, until the index sub transaction is committed.
+ * altered, until the index sub transaction is committed, but we
+ * don't copy the actual values, just the array of struct ldb_val
+ * that points to the values (which are offsets into a GUID array).
+ *
+ * As a reminder, our primary cache is an in-memory tdb that
+ * maps attributes to struct dn_list objects, which point to
+ * the actual index, which is an array of struct ldb_val, the
+ * contents of which are {.data = <binary GUID>, .length =
+ * 16}. The array is sorted by GUID data, and these GUIDs are
+ * used to look up index entries in the main database. There
+ * are more layers of indirection than necessary, but what
+ * makes the index useful is we can use a binary search to
+ * find if the array contains a GUID.
+ *
+ * What we do in a sub-transaction is make a copy of the struct
+ * dn_list and the array of struct ldb_val, but *not* of the
+ * .data that they point to. This copy is put into a new
+ * in-memory tdb which masks the primary cache for the duration
+ * of the sub-transaction.
+ *
+ * In an add operation in a sub-transaction, the new ldb_val
+ * is a child of the sub-transaction dn_list, which will
+ * become the main dn_list if the transaction succeeds.
+ *
+ * These acrobatics do not affect read-only operations.
*/
-
- {
- struct ldb_val *dns = NULL;
- size_t x = 0;
-
- dns = talloc_array(
- list,
- struct ldb_val,
- list2->count);
- if (dns == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- for (x = 0; x < list2->count; x++) {
- dns[x].length = list2->dn[x].length;
- dns[x].data = talloc_memdup(
- dns,
- list2->dn[x].data,
- list2->dn[x].length);
- if (dns[x].data == NULL) {
- TALLOC_FREE(dns);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- }
- list->dn = dns;
- list->count = list2->count;
+ list->dn = talloc_memdup(list,
+ list2->dn,
+ talloc_get_size(list2->dn));
+ if (list->dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
+ list->count = list2->count;
return LDB_SUCCESS;
/*
@@ -3852,9 +3857,7 @@ int ldb_kv_reindex(struct ldb_module *module)
* Copy the contents of the nested transaction index cache record to the
* transaction index cache.
*
- * During this 'commit' of the subtransaction to the main transaction
- * (cache), care must be taken to free any existing index at the top
- * level because otherwise we would leak memory.
+ * This is a 'commit' of the subtransaction to the main transaction cache.
*/
static int ldb_kv_sub_transaction_traverse(
struct tdb_context *tdb,
@@ -3883,8 +3886,7 @@ static int ldb_kv_sub_transaction_traverse(
/*
* Do we already have an entry in the primary transaction cache
- * If so free it's dn_list and replace it with the dn_list from
- * the secondary cache
+ * If so replace dn_list with the one from the subtransaction.
*
* The TDB and so the fetched rec contains NO DATA, just a
* pointer to data held in memory.
@@ -3897,21 +3899,41 @@ static int ldb_kv_sub_transaction_traverse(
abort();
}
/*
- * We had this key at the top level. However we made a copy
- * at the sub-transaction level so that we could possibly
- * roll back. We have to free the top level index memory
- * otherwise we would leak
+ * We had this key at the top level, and made a copy
+ * of the dn list for this sub-transaction level that
+ * borrowed the top level GUID data. We can't free the
+ * original dn list just yet.
+ *
+ * In this diagram, ... is the C pointer structure
+ * and --- is the talloc structure (::: is both).
+ *
+ * index_in_top_level ::: dn orig ..............
+ * | | :
+ * | `--GUID array :
+ * | |----- val1 data
+ * ldb_kv `----- val2 data
+ * | :
+ * index_in_subtransaction :: dn copy ..........:
+ * | :
+ * `------------ new val3 data
+ *
+ * So we don't free the index_in_top_level dn list yet,
+ * because we are (probably) borrowing most of its
+ * children. But we can save memory by discarding the
+ * values and keeping it as an almost empty talloc
+ * node.
*/
- if (index_in_top_level->count > 0) {
- TALLOC_FREE(index_in_top_level->dn);
- }
+ talloc_realloc(index_in_top_level,
+ index_in_top_level->dn, struct ldb_val, 1);
index_in_top_level->dn
= talloc_steal(index_in_top_level,
index_in_subtransaction->dn);
index_in_top_level->count = index_in_subtransaction->count;
return 0;
}
-
+ /*
+ * We found no top level index in the cache, so we put one in.
+ */
index_in_top_level = talloc(ldb_kv->idxptr, struct dn_list);
if (index_in_top_level == NULL) {
ldb_kv->idxptr->error = LDB_ERR_OPERATIONS_ERROR;
=====================================
lib/ldb/wscript
=====================================
@@ -2,7 +2,7 @@
APPNAME = 'ldb'
# For Samba 4.19.x !
-VERSION = '2.8.1'
+VERSION = '2.8.2'
import sys, os
=====================================
selftest/skip
=====================================
@@ -149,3 +149,4 @@ bench # don't run benchmarks in our selftest
^samba.tests.reparsepoints.*
^samba.tests.smb2symlink.*
^samba3.blackbox.open-eintr.*
+smb2.durable-v2-regressions # Only used in blackbox tests
=====================================
source3/lib/server_id_watch.c
=====================================
@@ -17,16 +17,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "replace.h"
-#include <tevent.h>
-#include <talloc.h>
+#include "includes.h"
#include "serverid.h"
#include "server_id_watch.h"
+#include "lib/util/server_id.h"
#include "lib/util/tevent_unix.h"
struct server_id_watch_state {
struct tevent_context *ev;
struct server_id pid;
+ struct timeval start;
+ struct timeval warn;
+ bool debug;
};
static void server_id_watch_waited(struct tevent_req *subreq);
@@ -37,6 +39,7 @@ struct tevent_req *server_id_watch_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req, *subreq;
struct server_id_watch_state *state;
+ struct timeval next;
req = tevent_req_create(mem_ctx, &state, struct server_id_watch_state);
if (req == NULL) {
@@ -44,14 +47,21 @@ struct tevent_req *server_id_watch_send(TALLOC_CTX *mem_ctx,
}
state->ev = ev;
state->pid = pid;
+ state->start = tevent_timeval_current();
+ state->warn = tevent_timeval_add(&state->start, 10, 0);
+
+ state->debug = lp_parm_bool(GLOBAL_SECTION_SNUM,
+ "serverid watch",
+ "debug",
+ CHECK_DEBUGLVL(DBGLVL_DEBUG));
if (!serverid_exists(&state->pid)) {
tevent_req_done(req);
return tevent_req_post(req, ev);
}
- subreq = tevent_wakeup_send(
- state, ev, tevent_timeval_current_ofs(0, 500000));
+ next = tevent_timeval_add(&state->start, 0, 500000);
+ subreq = tevent_wakeup_send(state, ev, next);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -66,6 +76,8 @@ static void server_id_watch_waited(struct tevent_req *subreq)
subreq, struct tevent_req);
struct server_id_watch_state *state = tevent_req_data(
req, struct server_id_watch_state);
+ struct timeval now;
+ struct timeval next;
bool ok;
ok = tevent_wakeup_recv(subreq);
@@ -80,8 +92,110 @@ static void server_id_watch_waited(struct tevent_req *subreq)
return;
}
- subreq = tevent_wakeup_send(
- state, state->ev, tevent_timeval_current_ofs(0, 500000));
+ now = tevent_timeval_current();
+
+ if (!state->debug) {
+ goto next;
+ }
+
+ if (timeval_compare(&state->warn, &now) == -1) {
+ double duration = timeval_elapsed2(&state->start, &now);
+ const char *cmd = NULL;
+ char proc_path[64] = { 0, };
+ char *kstack = NULL;
+ struct server_id_buf buf;
+ const char *pid = server_id_str_buf(state->pid, &buf);
+ int ret;
+
+ state->warn = tevent_timeval_add(&now, 10, 0);
+
+ cmd = lp_parm_const_string(GLOBAL_SECTION_SNUM,
+ "serverid watch",
+ "debug script",
+ NULL);
+ if (cmd != NULL) {
+ char *cmdstr = NULL;
+ char *output = NULL;
+ int fd;
+
+ /*
+ * Note in a cluster setup pid will be
+ * a NOTE:PID like '1:3978365'
+ *
+ * Without clustering it is just '3978365'
+ */
+ cmdstr = talloc_asprintf(state, "%s %s", cmd, pid);
+ if (cmdstr == NULL) {
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "talloc_asprintf failed\n",
+ pid, duration);
+ goto next;
+ }
+
+ become_root();
+ ret = smbrun(cmdstr, &fd, NULL);
+ unbecome_root();
+ if (ret != 0) {
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "smbrun('%s') failed\n",
+ pid, duration, cmdstr);
+ TALLOC_FREE(cmdstr);
+ goto next;
+ }
+
+ output = fd_load(fd, NULL, 0, state);
+ close(fd);
+ if (output == NULL) {
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "fd_load() of smbrun('%s') failed\n",
+ pid, duration, cmdstr);
+ TALLOC_FREE(cmdstr);
+ goto next;
+ }
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "%s returned:\n%s",
+ pid, duration, cmdstr, output);
+ TALLOC_FREE(cmdstr);
+ TALLOC_FREE(output);
+ goto next;
+ }
+
+ if (!procid_is_local(&state->pid) || !sys_have_proc_fds()) {
+ DBG_ERR("Process %s hanging for %f seconds?\n",
+ pid, duration);
+ goto next;
+ }
+
+ ret = snprintf(proc_path,
+ ARRAY_SIZE(proc_path),
+ "/proc/%" PRIu64 "/stack",
+ state->pid.pid);
+ if (ret < 0) {
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "snprintf failed\n",
+ pid, duration);
+ goto next;
+ }
+
+ become_root();
+ kstack = file_load(proc_path, NULL, 0, state);
+ unbecome_root();
+ if (kstack == NULL) {
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "file_load [%s] failed\n",
+ pid, duration, proc_path);
+ goto next;
+ }
+
+ DBG_ERR("Process %s hanging for %f seconds?\n"
+ "%s:\n%s",
+ pid, duration, proc_path, kstack);
+ TALLOC_FREE(kstack);
+ }
+
+next:
+ next = tevent_timeval_add(&now, 0, 500000);
+ subreq = tevent_wakeup_send(state, state->ev, next);
if (tevent_req_nomem(subreq, req)) {
return;
}
=====================================
source3/modules/vfs_error_inject.c
=====================================
@@ -19,6 +19,7 @@
#include "includes.h"
#include "smbd/smbd.h"
+#include "librpc/gen_ndr/ndr_open_files.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
@@ -204,11 +205,86 @@ static int vfs_error_inject_unlinkat(struct vfs_handle_struct *handle,
return -1;
}
+static NTSTATUS vfs_error_inject_durable_reconnect(struct vfs_handle_struct *handle,
+ struct smb_request *smb1req,
+ struct smbXsrv_open *op,
+ const DATA_BLOB old_cookie,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct **fsp,
+ DATA_BLOB *new_cookie)
+{
+ const char *vfs_func = "durable_reconnect";
+ const char *err_str = NULL;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct vfs_default_durable_cookie cookie;
+ DATA_BLOB modified_cookie = data_blob_null;
+
+ err_str = lp_parm_const_string(SNUM(handle->conn),
+ "error_inject",
+ vfs_func,
+ NULL);
+ if (err_str == NULL) {
+ return SMB_VFS_NEXT_DURABLE_RECONNECT(handle,
+ smb1req,
+ op,
+ old_cookie,
+ mem_ctx,
+ fsp,
+ new_cookie);
+ }
+
+ ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
+ (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ return status;
+ }
+
+ if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (strequal(err_str, "st_ex_nlink")) {
+ cookie.stat_info.st_ex_nlink += 1;
+ } else {
+ DBG_ERR("Unknown error inject %s requested "
+ "for vfs function %s\n", err_str, vfs_func);
+ return SMB_VFS_NEXT_DURABLE_RECONNECT(handle,
+ smb1req,
+ op,
+ old_cookie,
+ mem_ctx,
+ fsp,
+ new_cookie);
+ }
+
+ ndr_err = ndr_push_struct_blob(&modified_cookie, talloc_tos(), &cookie,
+ (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ return status;
+ }
+
+ return SMB_VFS_NEXT_DURABLE_RECONNECT(handle,
+ smb1req,
+ op,
+ modified_cookie,
+ mem_ctx,
+ fsp,
+ new_cookie);
+}
+
static struct vfs_fn_pointers vfs_error_inject_fns = {
.chdir_fn = vfs_error_inject_chdir,
.pwrite_fn = vfs_error_inject_pwrite,
.openat_fn = vfs_error_inject_openat,
.unlinkat_fn = vfs_error_inject_unlinkat,
+ .durable_reconnect_fn = vfs_error_inject_durable_reconnect,
};
static_decl_vfs;
=====================================
source3/script/tests/test_durable_handle_reconnect.sh
=====================================
@@ -33,4 +33,22 @@ testit "durable_v2_delay.durable_v2_reconnect_delay_msec" $VALGRIND \
rm $delay_inject_conf
+error_inject_conf=$(dirname $SMB_CONF_PATH)/error_inject.conf
+
+cat > $error_inject_conf << _EOF
+ kernel share modes = no
+ kernel oplocks = no
+ posix locking = no
+ error_inject:durable_reconnect = st_ex_nlink
+_EOF
+
+testit "durable-v2-regressions.durable_v2_reconnect_bug15624" \
+ $VALGRIND $BINDIR/smbtorture //$SERVER_IP/error_inject \
+ -U$USERNAME%$PASSWORD \
+ --option=torture:bug15624=yes \
+ smb2.durable-v2-regressions.durable_v2_reconnect_bug15624 ||
+ failed=$(expr $failed + 1)
+
+rm $error_inject_conf
+
testok $0 $failed
=====================================
source3/smbd/durable.c
=====================================
@@ -538,6 +538,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
enum ndr_err_code ndr_err;
struct vfs_default_durable_cookie cookie;
DATA_BLOB new_cookie_blob = data_blob_null;
+ bool have_share_mode_entry = false;
*result = NULL;
*new_cookie = data_blob_null;
@@ -624,22 +625,22 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
if (!ok) {
DBG_WARNING("share_mode_forall_entries failed\n");
- TALLOC_FREE(lck);
- return NT_STATUS_INTERNAL_DB_ERROR;
+ status = NT_STATUS_INTERNAL_DB_ERROR;
+ goto fail;
}
if (e.pid.pid == 0) {
DBG_WARNING("Did not find a unique valid share mode entry\n");
- TALLOC_FREE(lck);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
if (!server_id_is_disconnected(&e.pid)) {
DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
"reconnect for handle that was not marked "
"disconnected (e.g. smbd or cluster node died)\n"));
- TALLOC_FREE(lck);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
if (e.share_file_id != op->global->open_persistent_id) {
@@ -648,8 +649,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
"(e.g. another client had opened the file)\n",
e.share_file_id,
op->global->open_persistent_id);
- TALLOC_FREE(lck);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
@@ -658,8 +659,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
"share[%s] is not writeable anymore\n",
lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
- TALLOC_FREE(lck);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
/*
@@ -670,8 +671,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
"new fsp: %s\n", nt_errstr(status)));
- TALLOC_FREE(lck);
- return status;
+ goto fail;
}
fh_set_private_options(fsp->fh, e.private_options);
@@ -714,9 +714,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
*/
if (!GUID_equal(fsp_client_guid(fsp),
&e.client_guid)) {
- TALLOC_FREE(lck);
- file_free(smb1req, fsp);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
status = leases_db_get(
@@ -730,9 +729,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
&lease_version, /* lease_version */
&epoch); /* epoch */
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(lck);
- file_free(smb1req, fsp);
- return status;
+ goto fail;
}
fsp->lease = find_fsp_lease(
@@ -742,9 +739,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
lease_version,
epoch);
if (fsp->lease == NULL) {
- TALLOC_FREE(lck);
- file_free(smb1req, fsp);
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
}
@@ -760,12 +756,10 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
status = fsp_set_smb_fname(fsp, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(lck);
- file_free(smb1req, fsp);
DEBUG(0, ("vfs_default_durable_reconnect: "
"fsp_set_smb_fname failed: %s\n",
nt_errstr(status)));
- return status;
+ goto fail;
}
op->compat = fsp;
@@ -780,12 +774,10 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
fh_get_gen_id(fsp->fh));
if (!ok) {
DBG_DEBUG("Could not set new share_mode_entry values\n");
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return NT_STATUS_INTERNAL_ERROR;
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
}
+ have_share_mode_entry = true;
ok = brl_reconnect_disconnected(fsp);
if (!ok) {
@@ -793,11 +785,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
DEBUG(1, ("vfs_default_durable_reconnect: "
"failed to reopen brlocks: %s\n",
nt_errstr(status)));
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return status;
+ goto fail;
}
/*
@@ -813,13 +801,9 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(lck);
DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
"file: %s\n", nt_errstr(status)));
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return status;
+ goto fail;
}
/*
@@ -833,48 +817,22 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
if (ret == -1) {
- NTSTATUS close_status;
status = map_nt_error_from_unix_common(errno);
DEBUG(1, ("Unable to fstat stream: %s => %s\n",
smb_fname_str_dbg(smb_fname),
nt_errstr(status)));
- close_status = fd_close(fsp);
- if (!NT_STATUS_IS_OK(close_status)) {
- DBG_ERR("fd_close failed (%s) - leaking file "
- "descriptor\n", nt_errstr(close_status));
- }
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return status;
+ goto fail;
}
if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
- NTSTATUS close_status = fd_close(fsp);
- if (!NT_STATUS_IS_OK(close_status)) {
- DBG_ERR("fd_close failed (%s) - leaking file "
- "descriptor\n", nt_errstr(close_status));
- }
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
if (!file_id_equal(&cookie.id, &file_id)) {
- NTSTATUS close_status = fd_close(fsp);
- if (!NT_STATUS_IS_OK(close_status)) {
- DBG_ERR("fd_close failed (%s) - leaking file "
- "descriptor\n", nt_errstr(close_status));
- }
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
(void)fdos_mode(fsp);
@@ -883,42 +841,21 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
&fsp->fsp_name->st,
fsp_str_dbg(fsp));
if (!ok) {
- NTSTATUS close_status = fd_close(fsp);
- if (!NT_STATUS_IS_OK(close_status)) {
- DBG_ERR("fd_close failed (%s) - leaking file "
- "descriptor\n", nt_errstr(close_status));
- }
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
}
status = set_file_oplock(fsp);
if (!NT_STATUS_IS_OK(status)) {
- NTSTATUS close_status = fd_close(fsp);
- if (!NT_STATUS_IS_OK(close_status)) {
- DBG_ERR("fd_close failed (%s) - leaking file "
- "descriptor\n", nt_errstr(close_status));
- }
- TALLOC_FREE(lck);
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return status;
+ goto fail;
}
status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(lck);
DEBUG(1, ("vfs_default_durable_reconnect: "
"vfs_default_durable_cookie - %s\n",
nt_errstr(status)));
- op->compat = NULL;
- fsp->op = NULL;
- file_free(smb1req, fsp);
- return status;
+ goto fail;
}
smb1req->chain_fsp = fsp;
@@ -935,4 +872,27 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
*new_cookie = new_cookie_blob;
return NT_STATUS_OK;
+
+fail:
+ if (fsp != NULL && have_share_mode_entry) {
+ /*
+ * Something is screwed up, delete the sharemode entry.
+ */
+ del_share_mode(lck, fsp);
+ }
+ if (fsp != NULL && fsp_get_pathref_fd(fsp) != -1) {
+ NTSTATUS close_status;
+ close_status = fd_close(fsp);
+ if (!NT_STATUS_IS_OK(close_status)) {
+ DBG_ERR("fd_close failed (%s), leaking fd\n",
+ nt_errstr(close_status));
+ }
+ }
+ TALLOC_FREE(lck);
+ if (fsp != NULL) {
+ op->compat = NULL;
+ fsp->op = NULL;
+ file_free(smb1req, fsp);
+ }
+ return status;
}
=====================================
source3/smbd/open.c
=====================================
@@ -38,6 +38,7 @@
#include "serverid.h"
#include "messages.h"
#include "source3/lib/dbwrap/dbwrap_watch.h"
+#include "source3/lib/server_id_watch.h"
#include "locking/leases_db.h"
#include "librpc/gen_ndr/ndr_leases_db.h"
#include "lib/util/time_basic.h"
@@ -591,6 +592,10 @@ static NTSTATUS symlink_target_below_conn(
talloc_tos(), dirfsp, symlink_name, &target);
}
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
status = safe_symlink_target_path(talloc_tos(),
connection_path,
dirfsp->fsp_name->base_name,
@@ -2475,6 +2480,10 @@ static int map_lease_type_to_oplock(uint32_t lease_type)
return result;
}
+struct blocker_debug_state {
+ size_t num_blockers;
+};
+
struct delay_for_oplock_state {
struct files_struct *fsp;
const struct smb2_lease *lease;
@@ -2486,8 +2495,22 @@ struct delay_for_oplock_state {
bool have_other_lease;
uint32_t total_lease_types;
bool delay;
+ struct blocker_debug_state *blocker_debug_state;
};
+static int blocker_debug_state_destructor(struct blocker_debug_state *state)
+{
+ if (state->num_blockers == 0) {
+ return 0;
+ }
+
+ DBG_DEBUG("blocker_debug_state [%p] num_blockers [%zu]\n",
+ state, state->num_blockers);
+ return 0;
+}
+
+static void delay_for_oplock_fn_watch_done(struct tevent_req *subreq);
+
static bool delay_for_oplock_fn(
struct share_mode_entry *e,
bool *modified,
@@ -2500,6 +2523,8 @@ static bool delay_for_oplock_fn(
uint32_t e_lease_type = SMB2_LEASE_NONE;
uint32_t break_to;
bool lease_is_breaking = false;
+ struct tevent_req *subreq = NULL;
+ struct server_id_buf idbuf = {};
if (e_is_lease) {
NTSTATUS status;
@@ -2639,9 +2664,56 @@ static bool delay_for_oplock_fn(
state->delay = true;
}
+ if (!state->delay) {
+ return false;
+ }
+
+ if (state->blocker_debug_state == NULL) {
+ return false;
+ }
+
+ subreq = server_id_watch_send(state->blocker_debug_state,
+ fsp->conn->sconn->ev_ctx,
+ e->pid);
+ if (subreq == NULL) {
+ DBG_ERR("server_id_watch_send(%s) returned NULL\n",
+ server_id_str_buf(e->pid, &idbuf));
+ return false;
+ }
+
+ tevent_req_set_callback(subreq,
+ delay_for_oplock_fn_watch_done,
+ state->blocker_debug_state);
+
+ state->blocker_debug_state->num_blockers++;
+
+ DBG_DEBUG("Starting to watch pid [%s] state [%p] num_blockers [%zu]\n",
+ server_id_str_buf(e->pid, &idbuf),
+ state->blocker_debug_state,
+ state->blocker_debug_state->num_blockers);
+
return false;
};
+static void delay_for_oplock_fn_watch_done(struct tevent_req *subreq)
+{
+ struct blocker_debug_state *blocker_debug_state = tevent_req_callback_data(
+ subreq, struct blocker_debug_state);
+ struct server_id pid = {};
+ struct server_id_buf idbuf = {};
+ int ret;
+
+ ret = server_id_watch_recv(subreq, &pid);
+ if (ret != 0) {
+ DBG_ERR("server_id_watch_recv failed %s\n", strerror(ret));
+ return;
+ }
+
+ DBG_DEBUG("state [%p] server_id_watch_recv() returned pid [%s] exited\n",
+ blocker_debug_state,
+ server_id_str_buf(pid, &idbuf));
+}
+
static NTSTATUS delay_for_oplock(files_struct *fsp,
int oplock_request,
const struct smb2_lease *lease,
@@ -2650,7 +2722,8 @@ static NTSTATUS delay_for_oplock(files_struct *fsp,
uint32_t create_disposition,
bool first_open_attempt,
int *poplock_type,
- uint32_t *pgranted)
+ uint32_t *pgranted,
+ struct blocker_debug_state **blocker_debug_state)
{
struct delay_for_oplock_state state = {
.fsp = fsp,
@@ -2696,6 +2769,22 @@ static NTSTATUS delay_for_oplock(files_struct *fsp,
goto grant;
}
+ if (lp_parm_bool(GLOBAL_SECTION_SNUM,
+ "smbd lease break",
+ "debug hung procs",
+ false))
+ {
+ state.blocker_debug_state = talloc_zero(fsp,
+ struct blocker_debug_state);
+ if (state.blocker_debug_state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_steal(talloc_tos(), state.blocker_debug_state);
+
+ talloc_set_destructor(state.blocker_debug_state,
+ blocker_debug_state_destructor);
+ }
+
state.delay_mask = have_sharing_violation ?
SMB2_LEASE_HANDLE : SMB2_LEASE_WRITE;
@@ -2717,6 +2806,7 @@ static NTSTATUS delay_for_oplock(files_struct *fsp,
}
if (state.delay) {
+ *blocker_debug_state = state.blocker_debug_state;
return NT_STATUS_RETRY;
}
@@ -2830,7 +2920,8 @@ static NTSTATUS handle_share_mode_lease(
const struct smb2_lease *lease,
bool first_open_attempt,
int *poplock_type,
- uint32_t *pgranted)
+ uint32_t *pgranted,
+ struct blocker_debug_state **blocker_debug_state)
{
bool sharing_violation = false;
NTSTATUS status;
@@ -2871,7 +2962,8 @@ static NTSTATUS handle_share_mode_lease(
create_disposition,
first_open_attempt,
poplock_type,
- pgranted);
+ pgranted,
+ blocker_debug_state);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -2906,7 +2998,8 @@ static void defer_open_done(struct tevent_req *req);
static void defer_open(struct share_mode_lock *lck,
struct timeval timeout,
struct smb_request *req,
- struct file_id id)
+ struct file_id id,
+ struct blocker_debug_state **blocker_debug_state)
{
struct deferred_open_record *open_rec = NULL;
struct timeval abs_timeout;
@@ -2950,6 +3043,8 @@ static void defer_open(struct share_mode_lock *lck,
}
tevent_req_set_callback(watch_req, defer_open_done, watch_state);
+ talloc_move(watch_req, blocker_debug_state);
+
ok = tevent_req_set_endtime(watch_req, req->sconn->ev_ctx, abs_timeout);
if (!ok) {
exit_server("tevent_req_set_endtime failed");
@@ -2972,8 +3067,9 @@ static void defer_open_done(struct tevent_req *req)
status = share_mode_watch_recv(req, NULL, NULL);
TALLOC_FREE(req);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(5, ("dbwrap_watched_watch_recv returned %s\n",
- nt_errstr(status)));
+ DBG_ERR("share_mode_watch_recv() returned %s, "
+ "rescheduling mid %" PRIu64 "\n",
+ nt_errstr(status), state->mid);
/*
* Even if it failed, retry anyway. TODO: We need a way to
* tell a re-scheduled open about that error.
@@ -3231,7 +3327,8 @@ static bool open_match_attributes(connection_struct *conn,
static void schedule_defer_open(struct share_mode_lock *lck,
struct file_id id,
- struct smb_request *req)
+ struct smb_request *req,
+ struct blocker_debug_state **blocker_debug_state)
{
/* This is a relative time, added to the absolute
request_time value to get the absolute timeout time.
@@ -3255,7 +3352,7 @@ static void schedule_defer_open(struct share_mode_lock *lck,
return;
}
- defer_open(lck, timeout, req, id);
+ defer_open(lck, timeout, req, id, blocker_debug_state);
}
/****************************************************************************
@@ -3317,6 +3414,7 @@ static NTSTATUS check_and_store_share_mode(
int oplock_type = NO_OPLOCK;
uint32_t granted_lease = 0;
const struct smb2_lease_key *lease_key = NULL;
+ struct blocker_debug_state *blocker_debug_state = NULL;
bool delete_on_close;
bool ok;
@@ -3339,9 +3437,10 @@ static NTSTATUS check_and_store_share_mode(
lease,
first_open_attempt,
&oplock_type,
- &granted_lease);
+ &granted_lease,
+ &blocker_debug_state);
if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
- schedule_defer_open(lck, fsp->file_id, req);
+ schedule_defer_open(lck, fsp->file_id, req, &blocker_debug_state);
return NT_STATUS_SHARING_VIOLATION;
}
if (!NT_STATUS_IS_OK(status)) {
=====================================
source3/smbd/smb2_ioctl.c
=====================================
@@ -268,7 +268,8 @@ static bool smbd_smb2_ioctl_is_failure(uint32_t ctl_code, NTSTATUS status,
if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)
&& ((ctl_code == FSCTL_PIPE_TRANSCEIVE)
|| (ctl_code == FSCTL_PIPE_PEEK)
- || (ctl_code == FSCTL_DFS_GET_REFERRALS))) {
+ || (ctl_code == FSCTL_DFS_GET_REFERRALS)
+ || (ctl_code == FSCTL_QUERY_ALLOCATED_RANGES))) {
return false;
}
@@ -344,6 +345,7 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq)
* in:
* - fsctl_dfs_get_refers()
* - smbd_smb2_ioctl_pipe_read_done()
+ * - fsctl_qar()
*/
status = NT_STATUS_BUFFER_TOO_SMALL;
}
=====================================
source3/smbd/smb2_ioctl_filesys.c
=====================================
@@ -3,7 +3,7 @@
Core SMB2 server
Copyright (C) Stefan Metzmacher 2009
- Copyright (C) David Disseldorp 2013-2015
+ Copyright (C) David Disseldorp 2013-2024
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
@@ -538,6 +538,7 @@ static NTSTATUS fsctl_qar_seek_fill(TALLOC_CTX *mem_ctx,
struct files_struct *fsp,
off_t curr_off,
off_t max_off,
+ size_t in_max_output,
DATA_BLOB *qar_array_blob)
{
NTSTATUS status = NT_STATUS_NOT_SUPPORTED;
@@ -578,6 +579,17 @@ static NTSTATUS fsctl_qar_seek_fill(TALLOC_CTX *mem_ctx,
return NT_STATUS_INTERNAL_ERROR;
}
+ if (qar_array_blob->length + sizeof(qar_buf) > in_max_output) {
+ /*
+ * Earlier check ensures space for one range or more.
+ * Subsequent overflow results in a truncated response.
+ */
+ DBG_NOTICE("truncated QAR output: need > %zu, max %zu\n",
+ qar_array_blob->length + sizeof(qar_buf),
+ in_max_output);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
qar_buf.file_off = data_off;
/* + 1 to convert maximum offset to length */
qar_buf.len = MIN(hole_off, max_off + 1) - data_off;
@@ -652,6 +664,13 @@ static NTSTATUS fsctl_qar(TALLOC_CTX *mem_ctx,
return NT_STATUS_INVALID_PARAMETER;
}
+ /* must have enough space for at least one range */
+ if (in_max_output < sizeof(struct file_alloced_range_buf)) {
+ DEBUG(2, ("QAR max %lu insufficient for one range\n",
+ (unsigned long)in_max_output));
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
/*
* Maximum offset is either the last valid offset _before_ EOF, or the
* last byte offset within the requested range. -1 converts length to
@@ -687,31 +706,24 @@ static NTSTATUS fsctl_qar(TALLOC_CTX *mem_ctx,
status = fsctl_qar_buf_push(mem_ctx, &qar_buf, &qar_array_blob);
} else {
status = fsctl_qar_seek_fill(mem_ctx, fsp, qar_req.buf.file_off,
- max_off, &qar_array_blob);
- }
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ max_off, in_max_output,
+ &qar_array_blob);
}
- /* marshall response buffer. */
- qar_rsp.far_buf_array = qar_array_blob;
+ if (NT_STATUS_IS_OK(status)
+ || NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* marshall response. STATUS_BUFFER_OVERFLOW=truncated */
+ qar_rsp.far_buf_array = qar_array_blob;
- ndr_ret = ndr_push_struct_blob(out_output, mem_ctx, &qar_rsp,
- (ndr_push_flags_fn_t)ndr_push_fsctl_query_alloced_ranges_rsp);
- if (ndr_ret != NDR_ERR_SUCCESS) {
- DEBUG(0, ("failed to marshall QAR rsp\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (out_output->length > in_max_output) {
- DEBUG(2, ("QAR output len %lu exceeds max %lu\n",
- (unsigned long)out_output->length,
- (unsigned long)in_max_output));
- data_blob_free(out_output);
- return NT_STATUS_BUFFER_TOO_SMALL;
+ ndr_ret = ndr_push_struct_blob(out_output, mem_ctx, &qar_rsp,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_query_alloced_ranges_rsp);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ DEBUG(0, ("failed to marshall QAR rsp\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
}
- return NT_STATUS_OK;
+ return status;
}
static void smb2_ioctl_filesys_dup_extents_done(struct tevent_req *subreq);
=====================================
source3/smbd/smb2_process.c
=====================================
@@ -1692,8 +1692,36 @@ struct smbd_tevent_trace_state {
struct tevent_context *ev;
TALLOC_CTX *frame;
SMBPROFILE_BASIC_ASYNC_STATE(profile_idle);
+ struct timeval before_wait_tv;
+ struct timeval after_wait_tv;
};
+static inline void smbd_tevent_trace_callback_before_wait(
+ struct smbd_tevent_trace_state *state)
+{
+ struct timeval now = timeval_current();
+ struct timeval diff;
+
+ diff = tevent_timeval_until(&state->after_wait_tv, &now);
+ if (diff.tv_sec > 3) {
+ DBG_ERR("Handling event took %ld seconds!\n", (long)diff.tv_sec);
+ }
+ state->before_wait_tv = now;
+}
+
+static inline void smbd_tevent_trace_callback_after_wait(
+ struct smbd_tevent_trace_state *state)
+{
+ struct timeval now = timeval_current();
+ struct timeval diff;
+
+ diff = tevent_timeval_until(&state->before_wait_tv, &now);
+ if (diff.tv_sec > 30) {
+ DBG_NOTICE("No event for %ld seconds!\n", (long)diff.tv_sec);
+ }
+ state->after_wait_tv = now;
+}
+
static inline void smbd_tevent_trace_callback_before_loop_once(
struct smbd_tevent_trace_state *state)
{
@@ -1729,6 +1757,30 @@ static void smbd_tevent_trace_callback(enum tevent_trace_point point,
errno = 0;
}
+static void smbd_tevent_trace_callback_debug(enum tevent_trace_point point,
+ void *private_data)
+{
+ struct smbd_tevent_trace_state *state =
+ (struct smbd_tevent_trace_state *)private_data;
+
+ switch (point) {
+ case TEVENT_TRACE_BEFORE_WAIT:
+ smbd_tevent_trace_callback_before_wait(state);
+ break;
+ case TEVENT_TRACE_AFTER_WAIT:
+ smbd_tevent_trace_callback_after_wait(state);
+ break;
+ case TEVENT_TRACE_BEFORE_LOOP_ONCE:
+ smbd_tevent_trace_callback_before_loop_once(state);
+ break;
+ case TEVENT_TRACE_AFTER_LOOP_ONCE:
+ smbd_tevent_trace_callback_after_loop_once(state);
+ break;
+ }
+
+ errno = 0;
+}
+
static void smbd_tevent_trace_callback_profile(enum tevent_trace_point point,
void *private_data)
{
@@ -1737,6 +1789,7 @@ static void smbd_tevent_trace_callback_profile(enum tevent_trace_point point,
switch (point) {
case TEVENT_TRACE_BEFORE_WAIT:
+ smbd_tevent_trace_callback_before_wait(state);
if (!smbprofile_dump_pending()) {
/*
* If there's no dump pending
@@ -1749,6 +1802,7 @@ static void smbd_tevent_trace_callback_profile(enum tevent_trace_point point,
SMBPROFILE_BASIC_ASYNC_START(idle, profile_p, state->profile_idle);
break;
case TEVENT_TRACE_AFTER_WAIT:
+ smbd_tevent_trace_callback_after_wait(state);
SMBPROFILE_BASIC_ASYNC_END(state->profile_idle);
if (!smbprofile_dump_pending()) {
/*
@@ -1783,10 +1837,6 @@ void smbd_process(struct tevent_context *ev_ctx,
int sock_fd,
bool interactive)
{
- struct smbd_tevent_trace_state trace_state = {
- .ev = ev_ctx,
- .frame = talloc_stackframe(),
- };
const struct loadparm_substitution *lp_sub =
loadparm_s3_global_substitution();
struct smbXsrv_client *client = NULL;
@@ -1797,6 +1847,16 @@ void smbd_process(struct tevent_context *ev_ctx,
int ret;
NTSTATUS status;
struct timeval tv = timeval_current();
+ struct smbd_tevent_trace_state trace_state = {
+ .ev = ev_ctx,
+ .frame = talloc_stackframe(),
+ .before_wait_tv = tv,
+ .after_wait_tv = tv,
+ };
+ bool debug = lp_parm_bool(GLOBAL_SECTION_SNUM,
+ "smbd",
+ "debug events",
+ CHECK_DEBUGLVL(DBGLVL_DEBUG));
NTTIME now = timeval_to_nttime(&tv);
char *chroot_dir = NULL;
int rc;
@@ -2041,6 +2101,10 @@ void smbd_process(struct tevent_context *ev_ctx,
tevent_set_trace_callback(ev_ctx,
smbd_tevent_trace_callback_profile,
&trace_state);
+ } else if (debug) {
+ tevent_set_trace_callback(ev_ctx,
+ smbd_tevent_trace_callback_debug,
+ &trace_state);
} else {
tevent_set_trace_callback(ev_ctx,
smbd_tevent_trace_callback,
=====================================
source3/smbd/smb2_server.c
=====================================
@@ -3051,6 +3051,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
bool signing_required = false;
bool encryption_desired = false;
bool encryption_required = false;
+ bool session_expired = false;
inhdr = SMBD_SMB2_IN_HDR_PTR(req);
@@ -3099,6 +3100,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
signing_required = x->global->signing_flags & SMBXSRV_SIGNING_REQUIRED;
encryption_desired = x->global->encryption_flags & SMBXSRV_ENCRYPTION_DESIRED;
encryption_required = x->global->encryption_flags & SMBXSRV_ENCRYPTION_REQUIRED;
+ session_expired =
+ NT_STATUS_EQUAL(session_status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED);
}
req->async_internal = false;
@@ -3171,7 +3175,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
* This check is mostly for giving the correct error code
* for compounded requests.
*/
- if (!NT_STATUS_IS_OK(session_status)) {
+ if (!session_expired && !NT_STATUS_IS_OK(session_status)) {
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
}
} else {
@@ -3257,6 +3261,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
}
if (!NT_STATUS_IS_OK(session_status)) {
+ if (session_expired && opcode == SMB2_OP_CREATE) {
+ req->compound_create_err = session_status;
+ }
return smbd_smb2_request_error(req, session_status);
}
}
@@ -3308,11 +3315,18 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
skipped_signing:
if (flags & SMB2_HDR_FLAG_CHAINED) {
+ if (!NT_STATUS_IS_OK(req->compound_create_err)) {
+ return smbd_smb2_request_error(req,
+ req->compound_create_err);
+ }
req->compound_related = true;
}
if (call->need_session) {
if (!NT_STATUS_IS_OK(session_status)) {
+ if (session_expired && opcode == SMB2_OP_CREATE) {
+ req->compound_create_err = session_status;
+ }
return smbd_smb2_request_error(req, session_status);
}
}
=====================================
source4/lib/messaging/messaging.c
=====================================
@@ -443,6 +443,15 @@ void imessaging_dgm_unref_ev(struct tevent_context *ev)
static NTSTATUS imessaging_reinit(struct imessaging_context *msg)
{
int ret = -1;
+ struct irpc_request *irpc = NULL;
+ struct irpc_request *next = NULL;
+
+ for (irpc = msg->requests; irpc != NULL; irpc = next) {
+ next = irpc->next;
+
+ DLIST_REMOVE(msg->requests, irpc);
+ irpc->callid = -1;
+ }
TALLOC_FREE(msg->msg_dgm_ref);
=====================================
source4/libcli/smb2/ioctl.c
=====================================
@@ -86,7 +86,8 @@ static bool smb2_ioctl_is_failure(uint32_t ctl_code, NTSTATUS status,
if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)
&& ((ctl_code == FSCTL_PIPE_TRANSCEIVE)
|| (ctl_code == FSCTL_PIPE_PEEK)
- || (ctl_code == FSCTL_DFS_GET_REFERRALS))) {
+ || (ctl_code == FSCTL_DFS_GET_REFERRALS)
+ || (ctl_code == FSCTL_QUERY_ALLOCATED_RANGES))) {
return false;
}
=====================================
source4/torture/smb2/durable_v2_open.c
=====================================
@@ -2355,6 +2355,112 @@ done:
return ret;
}
+/**
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+static bool test_durable_v2_reconnect_bug15624(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ struct smbcli_options options;
+ uint64_t previous_session_id;
+ uint8_t b = 0;
+ bool ret = true;
+ bool ok;
+
+ if (!torture_setting_bool(tctx, "bug15624", false)) {
+ torture_comment(tctx,
+ "share requires:\n"
+ "'vfs objects = error_inject'\n"
+ "'error_inject:durable_reconnect=st_ex_nlink'\n"
+ "test requires:\n"
+ "'--option=torture:bug15624=yes'\n");
+ torture_skip(tctx, "'--option=torture:bug15624=yes' missing");
+ }
+
+ options = tree->session->transport->options;
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname,
+ sizeof(fname),
+ "durable_v2_reconnect_bug15624_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = 0;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+
+ status = smb2_util_write(tree, *h, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+ h = NULL;
+
+ ok = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree);
+ torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = &_h;
+ io.in.create_guid = create_guid;
+
+ /*
+ * This assumes 'error_inject:durable_reconnect = st_ex_nlink'
+ * will cause the durable reconnect to fail...
+ * in order to have a regression test for the dead lock.
+ */
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * With the regression this will fail with
+ * a timeout...
+ */
+ status = smb2_util_unlink(tree2, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ TALLOC_FREE(tree);
+
+ smb2_util_unlink(tree2, fname);
+
+ TALLOC_FREE(tree2);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
struct torture_suite *torture_smb2_durable_v2_delay_init(TALLOC_CTX *ctx)
{
struct torture_suite *suite =
@@ -2369,3 +2475,15 @@ struct torture_suite *torture_smb2_durable_v2_delay_init(TALLOC_CTX *ctx)
return suite;
}
+
+struct torture_suite *torture_smb2_durable_v2_regressions_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "durable-v2-regressions");
+
+ torture_suite_add_2smb2_test(suite,
+ "durable_v2_reconnect_bug15624",
+ test_durable_v2_reconnect_bug15624);
+
+ return suite;
+}
=====================================
source4/torture/smb2/ioctl.c
=====================================
@@ -3,7 +3,7 @@
test suite for SMB2 ioctl operations
- Copyright (C) David Disseldorp 2011-2016
+ Copyright (C) David Disseldorp 2011-2024
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
@@ -3838,6 +3838,151 @@ static bool test_ioctl_sparse_qar_malformed(struct torture_context *torture,
return true;
}
+static bool test_ioctl_sparse_qar_truncated(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_ioctl ioctl;
+ struct file_alloced_range_buf far_buf;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ struct file_alloced_range_buf far_rsp;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /*
+ * Write 0 and 1M offsets as (hopefully) two separate extents.
+ * XXX this test assumes that these ranges will be recorded as separate
+ * FSCTL_QUERY_ALLOCATED_RANGES extents, which isn't strictly required:
+ * the spec basically says the FS can do what it wants as long as
+ * non-zeroed data ranges aren't reported as sparse holes.
+ */
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ 1024, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 1024 * 1024, /* off */
+ 1024, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* qar max output enough to carry one range, should be truncated */
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
+ ioctl.smb2.in.max_output_response = sizeof(struct file_alloced_range_buf);
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ far_buf.file_off = 0;
+ far_buf.len = 2048 * 1024;
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &far_buf,
+ (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ STATUS_BUFFER_OVERFLOW, "qar truncated");
+ torture_assert_u64_equal(torture,
+ ioctl.smb2.out.out.length, sizeof(far_buf),
+ "qar outlen");
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &far_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "pull far range");
+ torture_assert_u64_equal(torture, far_rsp.file_off, 0, "far offset");
+ /* length depends on allocation behaviour of FS, so allow range */
+ torture_assert(torture, far_rsp.len >= 1024, "far len");
+
+ /* qar max output for just under 2 ranges, should be truncated */
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
+ ioctl.smb2.in.max_output_response = 31;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ far_buf.file_off = 0;
+ far_buf.len = 2048 * 1024;
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &far_buf,
+ (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ STATUS_BUFFER_OVERFLOW, "qar truncated");
+ torture_assert_u64_equal(torture,
+ ioctl.smb2.out.out.length, sizeof(far_buf),
+ "qar outlen");
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &far_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "pull far range");
+ torture_assert_u64_equal(torture, far_rsp.file_off, 0, "far offset");
+ torture_assert(torture, far_rsp.len >= 1024, "far len");
+
+ /* qar max output for 2 ranges, should pass */
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
+ ioctl.smb2.in.max_output_response = 32;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ far_buf.file_off = 0;
+ far_buf.len = 2048 * 1024;
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &far_buf,
+ (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "qar non-truncated");
+ torture_assert_u64_equal(torture,
+ ioctl.smb2.out.out.length,
+ 2 * sizeof(far_buf), "qar outlen");
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &far_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "pull far range");
+ torture_assert_u64_equal(torture, far_rsp.file_off, 0, "far offset");
+ torture_assert(torture, far_rsp.len >= 1024, "far len");
+ /* move to next buffer */
+ ioctl.smb2.out.out.data += sizeof(far_buf);
+ ioctl.smb2.out.out.length -= sizeof(far_buf);
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &far_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "pull far range");
+ torture_assert_u64_equal(torture, far_rsp.file_off, 1024 * 1024,
+ "far offset");
+ torture_assert(torture, far_rsp.len >= 1024, "far len");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
bool test_ioctl_alternate_data_stream(struct torture_context *tctx)
{
bool ret = false;
@@ -7548,6 +7693,8 @@ struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
test_ioctl_sparse_qar);
torture_suite_add_1smb2_test(suite, "sparse_qar_malformed",
test_ioctl_sparse_qar_malformed);
+ torture_suite_add_1smb2_test(suite, "sparse_qar_truncated",
+ test_ioctl_sparse_qar_truncated);
torture_suite_add_1smb2_test(suite, "sparse_punch",
test_ioctl_sparse_punch);
torture_suite_add_1smb2_test(suite, "sparse_hole_dealloc",
=====================================
source4/torture/smb2/session.c
=====================================
@@ -1317,6 +1317,7 @@ static bool test_session_expire2i(struct torture_context *tctx,
char fname[256];
struct smb2_handle dh;
struct smb2_handle dh2;
+ struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
struct smb2_handle _h1;
struct smb2_handle *h1 = NULL;
struct smb2_create io1;
@@ -1330,7 +1331,10 @@ static bool test_session_expire2i(struct torture_context *tctx,
struct smb2_ioctl ctl;
struct smb2_break oack;
struct smb2_lease_break_ack lack;
+ struct smb2_create cio;
struct smb2_find fnd;
+ struct smb2_close cl;
+ struct smb2_request *reqs[3] = { NULL, };
union smb_search_data *d = NULL;
unsigned int count;
struct smb2_request *req = NULL;
@@ -1562,6 +1566,58 @@ static bool test_session_expire2i(struct torture_context *tctx,
ret, done, "smb2_find_level "
"returned unexpected status");
+ /* Now do a compound open + query directory + close handle. */
+ smb2_transport_compound_start(tree->session->transport, 3);
+ torture_comment(tctx, "Compound: Open+QueryDirectory+Close => EXPIRED\n");
+
+ ZERO_STRUCT(cio);
+ cio.in.oplock_level = 0;
+ cio.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
+ cio.in.file_attributes = 0;
+ cio.in.create_disposition = NTCREATEX_DISP_OPEN;
+ cio.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
+ cio.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
+ cio.in.fname = "";
+
+ reqs[0] = smb2_create_send(tree, &cio);
+ torture_assert_not_null_goto(tctx, reqs[0], ret, done,
+ "smb2_create_send failed\n");
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(fnd);
+ fnd.in.file.handle = relhandle;
+ fnd.in.pattern = "*";
+ fnd.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ fnd.in.max_response_size= 0x100;
+ fnd.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ reqs[1] = smb2_find_send(tree, &fnd);
+ torture_assert_not_null_goto(tctx, reqs[1], ret, done,
+ "smb2_find_send failed\n");
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = relhandle;
+ reqs[2] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, reqs[2], ret, done,
+ "smb2_close_send failed\n");
+
+ status = smb2_create_recv(reqs[0], tree, &cio);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_create "
+ "returned unexpected status");
+ status = smb2_find_recv(reqs[1], tree, &fnd);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_find "
+ "returned unexpected status");
+ status = smb2_close_recv(reqs[2], &cl);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_close "
+ "returned unexpected status");
+
torture_comment(tctx, "1st notify => CANCEL\n");
smb2_cancel(req);
=====================================
source4/torture/smb2/smb2.c
=====================================
@@ -170,6 +170,8 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
torture_smb2_durable_v2_open_init(suite));
torture_suite_add_suite(suite,
torture_smb2_durable_v2_delay_init(suite));
+ torture_suite_add_suite(suite,
+ torture_smb2_durable_v2_regressions_init(suite));
torture_suite_add_suite(suite, torture_smb2_dir_init(suite));
torture_suite_add_suite(suite, torture_smb2_lease_init(suite));
torture_suite_add_suite(suite, torture_smb2_compound_init(suite));
View it on GitLab: https://salsa.debian.org/samba-team/samba/-/compare/8b3f193e9f26c9cc65c2846dc79f2cc7c0d4248b...c0e8acf65b1afa2527b4989a8f198dcb1a04bd35
--
View it on GitLab: https://salsa.debian.org/samba-team/samba/-/compare/8b3f193e9f26c9cc65c2846dc79f2cc7c0d4248b...c0e8acf65b1afa2527b4989a8f198dcb1a04bd35
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-samba-maint/attachments/20241018/06892459/attachment-0001.htm>
More information about the Pkg-samba-maint
mailing list