[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Mon May 20 05:18:01 UTC 2019


The branch, master has been updated
       via  3b509129f5e torture: Address flapping samba4.rpc.altercontext test
       via  0559430ab6e ldap_server: Run ldapsrv_queue_reply() in the ldb callback, rather than waiting for the full result
       via  8dfad9fa2cc ldap_server: chunk the writev() calls at 25MB
       via  e8475f8ec5f ldap_server: Add explict repsonse size limit of 256MB
       via  00b9a97706e ldap_server: Use an array of struct iovec to avoid data_blob_append()
       via  fd74b631444 ldap_server: Run the ldap_encode() step in ldapsrv_queue_reply()
       via  11c20e03d7d ldap_server: Remove success_limit
       via  98226287491 selftest: Remove gensec.FEATURE_SEAL from samba4.ldap.notification
       via  46185daeb21 dsdb: lock metadata.tdb during lock_read in partitions module
       via  99867565a50 dsdb/partition: Remove teardown of data->metadata on partition_metadata_set_sequence_number() failure
       via  bc663a97983 dsdb/partition: Move in_transaction decrement to end of partition_del_trans()
       via  7567f29211f dsdb/partition: Ensure metadata.tdb is opened early in partition_reload_if_required()
       via  46677b8e1ef dsdb: Add random values to names in tests for large LDAP responses
      from  594676c8b8f s3: torture: Fix return values

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 3b509129f5edf47e3753dce3d0375e485eb251ac
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 15 16:07:16 2019 +1200

    torture: Address flapping samba4.rpc.altercontext test
    
    NT_STATUS_CONNECTION_DISCONNECTED and NT_STATUS_CONNECTION_RESET are
    equivilent for the purposes of this test, both come from the server
    shutting down the connection, the difference comes from two different
    unix error numbers that can come from this.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Mon May 20 05:17:42 UTC 2019 on sn-devel-184

commit 0559430ab6e5c48d6e853fda0d8b63f2e149015c
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Apr 3 17:11:01 2019 +1300

    ldap_server: Run ldapsrv_queue_reply() in the ldb callback, rather than waiting for the full result
    
    Based on earlier work by Garming Sam.
    
    This allows the server to stop working on a reply that will never
    be sent to the client as it is too large.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 8dfad9fa2cc5f9ae464a6df44c7ae0448cc4f3ab
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue May 14 12:08:03 2019 +1200

    ldap_server: chunk the writev() calls at 25MB
    
    This should limit the amount we send to GENSEC at a
    time where it may help avoid large realloc or memcpy calls.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit e8475f8ec5fc61409a98667b22e20364c0820cd6
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 8 14:03:50 2019 +1200

    ldap_server: Add explict repsonse size limit of 256MB
    
    This allows us to replace the implicit limit via data_blob_append()
    removed in the previous commit.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 00b9a97706e71e6834781df0a144f23af9526689
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Apr 4 17:25:30 2019 +1300

    ldap_server: Use an array of struct iovec to avoid data_blob_append()
    
    This avoids a the implicit 256MB limit on LDAP replies (allowing this
    to be increased in the future) and means we copy less memory around.
    
    However because we can only have 1024 entries in a struct iovec (on Linux)
    we will need to call tstream_writev_queue_send() multiple times.
    
    Calling it in chunks of 1024 seems a reasonable compromise, the
    gensec layer will chunk it out smaller if required.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit fd74b6314444ff8f1da8fcd8d540a2e88b7b872c
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Apr 4 16:52:17 2019 +1300

    ldap_server: Run the ldap_encode() step in ldapsrv_queue_reply()
    
    This avoids holding the memory for the response twice,
    by the time the result is queued it is only ASN.1 encoded.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 11c20e03d7de7099e6f0b8ad0169a82b0e270c80
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Apr 3 16:48:33 2019 +1300

    ldap_server: Remove success_limit
    
    This was always set to 0 so was poinless.  Any LDAP scope can return 0 entries,
    even a SCOPE_BASE if the filter does not match.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 98226287491d04945b36413425cc59b0fbd8355d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Apr 8 14:54:04 2019 +1200

    selftest: Remove gensec.FEATURE_SEAL from samba4.ldap.notification
    
    This made it much harder to watch under wireshark and is not required (no password setting).
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 46185daeb212267ebb0e4abe8bdad8c7cd7bfce2
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu May 16 10:44:42 2019 +1200

    dsdb: lock metadata.tdb during lock_read in partitions module
    
    metadata.tdb was being locked during transactions, but not during read, and
    we should ensure we take all our locks in order for consistency
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13950
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 99867565a5070c072abcf7abc69bba9849b4984a
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu May 16 16:15:39 2019 +1200

    dsdb/partition: Remove teardown of data->metadata on partition_metadata_set_sequence_number() failure
    
    This changes variables that are not the responsiblity of this function, the unlock
    implied by partition_del_trans() needs to be done carefully in the right spot.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit bc663a979837f84fbd6d5f3bed1444d170ce7abb
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu May 16 15:12:55 2019 +1200

    dsdb/partition: Move in_transaction decrement to end of partition_del_trans()
    
    It makes no sense for this to be mid-function.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 7567f29211f7da35a785bd8c8cee999b0b24a078
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu May 16 14:35:00 2019 +1200

    dsdb/partition: Ensure metadata.tdb is opened early in partition_reload_if_required()
    
    This allows metadata.tdb to be locked in the correct place in
    in the lock order, as partition_reload_if_required() implicitly
    calls partition_lock_read().
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 46677b8e1effe4a1eab4ac69fb0213bf72c7cf42
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon May 13 15:32:23 2019 +1200

    dsdb: Add random values to names in tests for large LDAP responses
    
    This test is run agianst multiple DCs in the same domain, so there can
    be a race with replication.  Therefore avoid using the same name twice
    by adding a random suffix.
    
    This is an improvement to a demonstrator for this bug in TDB:
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=13952
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 selftest/knownfail.d/large-dc                      |   6 -
 source4/dsdb/samdb/ldb_modules/partition.c         |  72 +++--
 source4/dsdb/samdb/ldb_modules/partition.h         |   1 +
 source4/dsdb/samdb/ldb_modules/partition_init.c    |  12 +-
 .../dsdb/samdb/ldb_modules/partition_metadata.c    |  69 ++++-
 source4/dsdb/tests/python/large_ldap.py            |   4 +-
 source4/dsdb/tests/python/notification.py          |   1 -
 source4/ldap_server/ldap_backend.c                 | 317 +++++++++++++++------
 source4/ldap_server/ldap_server.c                  |  92 ++++--
 source4/ldap_server/ldap_server.h                  |  16 +-
 source4/torture/rpc/alter_context.c                |   3 +-
 source4/torture/rpc/lsa.c                          |  18 +-
 12 files changed, 453 insertions(+), 158 deletions(-)
 delete mode 100644 selftest/knownfail.d/large-dc


Changeset truncated at 500 lines:

diff --git a/selftest/knownfail.d/large-dc b/selftest/knownfail.d/large-dc
deleted file mode 100644
index 9a9e53a193f..00000000000
--- a/selftest/knownfail.d/large-dc
+++ /dev/null
@@ -1,6 +0,0 @@
-# Current Samba drops the LDAP socket after 256MB of replies, rather
-# than giving an nice error message
-^samba4.ldap.large_ldap.gssapi.python\(vampire_dc\).__main__.LargeLDAPTest.test_unindexed_iterator_search
-^samba4.ldap.large_ldap.ntlmssp.python\(ad_dc_default\).__main__.LargeLDAPTest.test_unindexed_iterator_search
-^samba4.ldap.large_ldap.ldaps.python\(ad_dc_ntvfs\).__main__.LargeLDAPTest.test_unindexed_iterator_search
-^samba4.ldap.large_ldap.straight_ldap.python\(fl2008r2dc\).__main__.LargeLDAPTest.test_unindexed_iterator_search
diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c
index 49bdeb04fa5..c9d815b4fb0 100644
--- a/source4/dsdb/samdb/ldb_modules/partition.c
+++ b/source4/dsdb/samdb/ldb_modules/partition.c
@@ -1193,12 +1193,6 @@ int partition_del_trans(struct ldb_module *module)
 		}
 	}	
 
-	if (data->in_transaction == 0) {
-		DEBUG(0,("partition del transaction mismatch\n"));
-		return ldb_operr(ldb_module_get_ctx(module));
-	}
-	data->in_transaction--;
-
 	if (ldb_module_flags(ldb_module_get_ctx(module)) &
 	    LDB_FLG_ENABLE_TRACING) {
 		ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_del_trans() -> (metadata partition)");
@@ -1213,6 +1207,12 @@ int partition_del_trans(struct ldb_module *module)
 		final_ret = ret;
 	}
 
+	if (data->in_transaction == 0) {
+		DEBUG(0,("partition del transaction mismatch\n"));
+		return ldb_operr(ldb_module_get_ctx(module));
+	}
+	data->in_transaction--;
+
 	return final_ret;
 }
 
@@ -1435,7 +1435,7 @@ int partition_read_lock(struct ldb_module *module)
 
 	/*
 	 * This order must match that in prepare_commit(), start with
-	 * the metadata partition (sam.ldb) lock
+	 * the top level DB (sam.ldb) lock
 	 */
 	ret = ldb_next_read_lock(module);
 	if (ret != LDB_SUCCESS) {
@@ -1449,7 +1449,7 @@ int partition_read_lock(struct ldb_module *module)
 	}
 
 	/*
-	 * The metadata partition (sam.ldb) lock is not
+	 * The top level DB (sam.ldb) lock is not
 	 * enough to block another process in prepare_commit(),
 	 * because prepare_commit() is a no-op, if nothing
 	 * was changed in the specific backend.
@@ -1476,18 +1476,24 @@ int partition_read_lock(struct ldb_module *module)
 			      ldb_dn_get_linearized(
 				      data->partitions[i]->ctrl->dn));
 
-		/* Back it out, if it fails on one */
-		for (i--; i >= 0; i--) {
-			ret2 = ldb_next_read_unlock(data->partitions[i]->module);
-			if (ret2 != LDB_SUCCESS) {
-				ldb_debug(ldb,
-					  LDB_DEBUG_FATAL,
-					  "Failed to unlock db: %s / %s",
-					  ldb_errstring(ldb),
-					  ldb_strerror(ret2));
-			}
-		}
-		ret2 = ldb_next_read_unlock(module);
+		goto failed;
+	}
+
+	/*
+	 * Because in prepare_commit this must come last, to ensure
+	 * lock ordering we have to do this last here also
+	 */
+	ret = partition_metadata_read_lock(module);
+	if (ret != LDB_SUCCESS) {
+		goto failed;
+	}
+
+	return LDB_SUCCESS;
+
+failed:
+	/* Back it out, if it fails on one */
+	for (i--; i >= 0; i--) {
+		ret2 = ldb_next_read_unlock(data->partitions[i]->module);
 		if (ret2 != LDB_SUCCESS) {
 			ldb_debug(ldb,
 				  LDB_DEBUG_FATAL,
@@ -1495,10 +1501,16 @@ int partition_read_lock(struct ldb_module *module)
 				  ldb_errstring(ldb),
 				  ldb_strerror(ret2));
 		}
-		return ret;
 	}
-
-	return LDB_SUCCESS;
+	ret2 = ldb_next_read_unlock(module);
+	if (ret2 != LDB_SUCCESS) {
+		ldb_debug(ldb,
+			  LDB_DEBUG_FATAL,
+			  "Failed to unlock db: %s / %s",
+			  ldb_errstring(ldb),
+			  ldb_strerror(ret2));
+	}
+	return ret;
 }
 
 /* unlock all the backends */
@@ -1566,6 +1578,20 @@ int partition_read_unlock(struct ldb_module *module)
 		}
 	}
 
+	/*
+	 * Because in prepare_commit this must come last, to ensure
+	 * lock ordering we have to do this last here also
+	 */
+	ret = partition_metadata_read_unlock(module);
+
+	/*
+	 * Don't overwrite the original failure code
+	 * if there was one
+	 */
+	if (ret == LDB_SUCCESS) {
+		ret = ret2;
+	}
+
 	return ret;
 }
 
diff --git a/source4/dsdb/samdb/ldb_modules/partition.h b/source4/dsdb/samdb/ldb_modules/partition.h
index 1bf213f9767..5790838e318 100644
--- a/source4/dsdb/samdb/ldb_modules/partition.h
+++ b/source4/dsdb/samdb/ldb_modules/partition.h
@@ -43,6 +43,7 @@ struct partition_module {
 struct partition_metadata {
 	struct tdb_wrap *db;
 	int in_transaction;
+	int read_lock_count;
 };
 
 struct partition_private_data {
diff --git a/source4/dsdb/samdb/ldb_modules/partition_init.c b/source4/dsdb/samdb/ldb_modules/partition_init.c
index 9a8bb7e211d..7d076932665 100644
--- a/source4/dsdb/samdb/ldb_modules/partition_init.c
+++ b/source4/dsdb/samdb/ldb_modules/partition_init.c
@@ -409,6 +409,12 @@ int partition_reload_if_required(struct ldb_module *module,
 		return LDB_SUCCESS;
 	}
 
+	/* This loads metadata tdb. If it's missing, creates it */
+	ret = partition_metadata_init(module);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+
 	ret = partition_reload_metadata(module, data, mem_ctx, &msg, parent);
 	if (ret != LDB_SUCCESS) {
 		talloc_free(mem_ctx);
@@ -890,11 +896,5 @@ int partition_init(struct ldb_module *module)
 		return ldb_operr(ldb);
 	}
 
-	/* This loads metadata tdb. If it's missing, creates it */
-	ret = partition_metadata_init(module);
-	if (ret != LDB_SUCCESS) {
-		return ret;
-	}
-
 	return ldb_next_init(module);
 }
diff --git a/source4/dsdb/samdb/ldb_modules/partition_metadata.c b/source4/dsdb/samdb/ldb_modules/partition_metadata.c
index cf44c5d1218..349f79c2645 100644
--- a/source4/dsdb/samdb/ldb_modules/partition_metadata.c
+++ b/source4/dsdb/samdb/ldb_modules/partition_metadata.c
@@ -303,6 +303,10 @@ int partition_metadata_init(struct ldb_module *module)
 	data = talloc_get_type_abort(ldb_module_get_private(module),
 				     struct partition_private_data);
 
+	if (data->metadata != NULL && data->metadata->db != NULL) {
+		return LDB_SUCCESS;
+	}
+
 	data->metadata = talloc_zero(data, struct partition_metadata);
 	if (data->metadata == NULL) {
 		return ldb_module_oom(module);
@@ -402,8 +406,6 @@ int partition_metadata_sequence_number_increment(struct ldb_module *module, uint
 		 */
 		ret = partition_metadata_set_sequence_number(module);
 		if (ret != LDB_SUCCESS) {
-			TALLOC_FREE(data->metadata);
-			partition_del_trans(module);
 			return ret;
 		}
 
@@ -419,6 +421,69 @@ int partition_metadata_sequence_number_increment(struct ldb_module *module, uint
 	ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
 	return ret;
 }
+/*
+  lock the database for read - use by partition_lock_read
+*/
+int partition_metadata_read_lock(struct ldb_module *module)
+{
+	struct partition_private_data *data
+		= talloc_get_type_abort(ldb_module_get_private(module),
+					struct partition_private_data);
+	struct tdb_context *tdb = NULL;
+	int tdb_ret = 0;
+	int ret;
+
+	if (!data || !data->metadata || !data->metadata->db) {
+		return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+					"partition_metadata: metadata not initialized");
+	}
+	tdb = data->metadata->db->tdb;
+
+	if (tdb_transaction_active(tdb) == false &&
+	    data->metadata->read_lock_count == 0) {
+		tdb_ret = tdb_lockall_read(tdb);
+	}
+	if (tdb_ret == 0) {
+		data->metadata->read_lock_count++;
+		return LDB_SUCCESS;
+	} else {
+		/* Sadly we can't call ltdb_err_map(tdb_error(tdb)); */
+		ret = LDB_ERR_BUSY;
+	}
+	ldb_debug_set(ldb_module_get_ctx(module),
+		      LDB_DEBUG_FATAL,
+		      "Failure during partition_metadata_read_lock(): %s",
+		      tdb_errorstr(tdb));
+	return ret;
+}
+
+/*
+  unlock the database after a partition_metadata_lock_read()
+*/
+int partition_metadata_read_unlock(struct ldb_module *module)
+{
+	struct partition_private_data *data
+		= talloc_get_type_abort(ldb_module_get_private(module),
+					struct partition_private_data);
+	struct tdb_context *tdb = NULL;
+
+	data = talloc_get_type_abort(ldb_module_get_private(module),
+				     struct partition_private_data);
+	if (!data || !data->metadata || !data->metadata->db) {
+		return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+					"partition_metadata: metadata not initialized");
+	}
+	tdb = data->metadata->db->tdb;
+
+	if (!tdb_transaction_active(tdb) &&
+	    data->metadata->read_lock_count == 1) {
+		tdb_unlockall_read(tdb);
+		data->metadata->read_lock_count--;
+		return 0;
+	}
+	data->metadata->read_lock_count--;
+	return 0;
+}
 
 
 /*
diff --git a/source4/dsdb/tests/python/large_ldap.py b/source4/dsdb/tests/python/large_ldap.py
index 2fc56e70455..cce9d41862f 100644
--- a/source4/dsdb/tests/python/large_ldap.py
+++ b/source4/dsdb/tests/python/large_ldap.py
@@ -70,7 +70,7 @@ class ManyLDAPTest(samba.tests.TestCase):
         super(ManyLDAPTest, self).setUp()
         self.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp)
         self.base_dn = self.ldb.domain_dn()
-        self.OU_NAME_MANY="many_ou"
+        self.OU_NAME_MANY="many_ou" + format(random.randint(0, 99999), "05")
         self.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME_MANY + "," + str(self.base_dn))
 
         samba.tests.delete_force(self.ldb, self.ou_dn,
@@ -122,7 +122,7 @@ class LargeLDAPTest(samba.tests.TestCase):
         self.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp)
         self.base_dn = self.ldb.domain_dn()
         self.USER_NAME = "large_user" + format(random.randint(0, 99999), "05") + "-"
-        self.OU_NAME="large_user_ou"
+        self.OU_NAME="large_user_ou" + format(random.randint(0, 99999), "05")
         self.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME + "," + str(self.base_dn))
 
         samba.tests.delete_force(self.ldb, self.ou_dn,
diff --git a/source4/dsdb/tests/python/notification.py b/source4/dsdb/tests/python/notification.py
index 15107739086..9e5f7dc9d5d 100755
--- a/source4/dsdb/tests/python/notification.py
+++ b/source4/dsdb/tests/python/notification.py
@@ -61,7 +61,6 @@ url = args[0]
 
 lp = sambaopts.get_loadparm()
 creds = credopts.get_credentials(lp)
-creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
 
 
 class LDAPNotificationTest(samba.tests.TestCase):
diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index 9f72734f973..ef7fb15179d 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -32,6 +32,7 @@
 #include <ldb_module.h>
 #include "ldb_wrap.h"
 #include "lib/tsocket/tsocket.h"
+#include "libcli/ldap/ldap_proto.h"
 
 static int map_ldb_error(TALLOC_CTX *mem_ctx, int ldb_err,
 	const char *add_err_string, const char **errstring)
@@ -257,9 +258,73 @@ struct ldapsrv_reply *ldapsrv_init_reply(struct ldapsrv_call *call, uint8_t type
 	return reply;
 }
 
-void ldapsrv_queue_reply(struct ldapsrv_call *call, struct ldapsrv_reply *reply)
+/*
+ * Encode a reply to an LDAP client as ASN.1, free the original memory
+ */
+static NTSTATUS ldapsrv_encode(TALLOC_CTX *mem_ctx,
+			       struct ldapsrv_reply *reply)
+{
+	bool bret = ldap_encode(reply->msg,
+				samba_ldap_control_handlers(),
+				&reply->blob,
+				mem_ctx);
+	TALLOC_FREE(reply->msg);
+	if (!bret) {
+		DEBUG(0,("Failed to encode ldap reply of type %d: "
+			 "ldap_encode() failed\n",
+			 reply->msg->type));
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	talloc_set_name_const(reply->blob.data,
+			      "Outgoing, encoded single LDAP reply");
+
+	return NT_STATUS_OK;
+}
+
+/*
+ * Queue a reply (encoding it also), even if it would exceed the
+ * limit.  This allows the error packet with LDAP_SIZE_LIMIT_EXCEEDED
+ * to be sent
+ */
+static NTSTATUS ldapsrv_queue_reply_forced(struct ldapsrv_call *call,
+					   struct ldapsrv_reply *reply)
 {
+	NTSTATUS status = ldapsrv_encode(call, reply);
+
+	if (NT_STATUS_IS_OK(status)) {
+		DLIST_ADD_END(call->replies, reply);
+	}
+	return status;
+}
+
+/*
+ * Queue a reply (encoding it also) but check we do not send more than
+ * LDAP_SERVER_MAX_REPLY_SIZE of responses as a way to limit the
+ * amount of data a client can make us allocate.
+ */
+NTSTATUS ldapsrv_queue_reply(struct ldapsrv_call *call, struct ldapsrv_reply *reply)
+{
+	NTSTATUS status = ldapsrv_encode(call, reply);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (call->reply_size > call->reply_size + reply->blob.length
+	    || call->reply_size + reply->blob.length > LDAP_SERVER_MAX_REPLY_SIZE) {
+		DBG_WARNING("Refusing to queue LDAP search response size "
+			    "of more than %zu bytes\n",
+			    LDAP_SERVER_MAX_REPLY_SIZE);
+		TALLOC_FREE(reply->blob.data);
+		return NT_STATUS_FILE_TOO_LARGE;
+	}
+
+	call->reply_size += reply->blob.length;
+
 	DLIST_ADD_END(call->replies, reply);
+
+	return status;
 }
 
 static NTSTATUS ldapsrv_unwilling(struct ldapsrv_call *call, int error)
@@ -502,16 +567,157 @@ static int ldapsrv_rename_with_controls(struct ldapsrv_call *call,
 	return ret;
 }
 
+
+
+struct ldapsrv_context {
+	struct ldapsrv_call *call;
+	int extended_type;
+	bool attributesonly;
+	struct ldb_control **controls;
+	size_t count; /* For notificaiton only */
+};
+
+static int ldap_server_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+	struct ldapsrv_context *ctx = talloc_get_type(req->context, struct ldapsrv_context);
+	struct ldapsrv_call *call = ctx->call;
+	struct ldb_context *ldb = call->conn->ldb;
+	unsigned int j;
+	struct ldapsrv_reply *ent_r = NULL;
+	struct ldap_SearchResEntry *ent;
+	int ret;
+	NTSTATUS status;
+
+	if (!ares) {
+		return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+	}
+	if (ares->error != LDB_SUCCESS) {
+		return ldb_request_done(req, ares->error);
+	}
+
+	switch (ares->type) {
+	case LDB_REPLY_ENTRY:
+	{
+		struct ldb_message *msg = ares->message;
+		ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
+		if (ent_r == NULL) {
+			return ldb_oom(ldb);
+		}
+
+		ctx->count++;
+
+		/*
+		 * Put the LDAP search response data under ent_r->msg
+		 * so we can free that later once encoded
+		 */
+		talloc_steal(ent_r->msg, msg);
+
+		ent = &ent_r->msg->r.SearchResultEntry;
+		ent->dn = ldb_dn_get_extended_linearized(ent_r, msg->dn,
+							 ctx->extended_type);
+		ent->num_attributes = 0;
+		ent->attributes = NULL;
+		if (msg->num_elements == 0) {
+			goto queue_reply;
+		}
+		ent->num_attributes = msg->num_elements;
+		ent->attributes = talloc_array(ent_r, struct ldb_message_element, ent->num_attributes);
+		if (ent->attributes == NULL) {
+			return ldb_oom(ldb);
+		}
+
+		for (j=0; j < ent->num_attributes; j++) {
+			ent->attributes[j].name = msg->elements[j].name;
+			ent->attributes[j].num_values = 0;
+			ent->attributes[j].values = NULL;
+			if (ctx->attributesonly && (msg->elements[j].num_values == 0)) {
+				continue;
+			}
+			ent->attributes[j].num_values = msg->elements[j].num_values;
+			ent->attributes[j].values = msg->elements[j].values;
+		}
+queue_reply:
+		status = ldapsrv_queue_reply(call, ent_r);
+		if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_TOO_LARGE)) {
+			ret = ldb_request_done(req,
+					       LDB_ERR_SIZE_LIMIT_EXCEEDED);
+			ldb_asprintf_errstring(ldb,
+					       "LDAP search response size "
+					       "limited to %zu bytes\n",
+					       LDAP_SERVER_MAX_REPLY_SIZE);
+		} else if (!NT_STATUS_IS_OK(status)) {
+			ret = ldb_request_done(req,
+					       ldb_operr(ldb));
+		} else {
+			ret = LDB_SUCCESS;
+		}
+		break;
+	}
+	case LDB_REPLY_REFERRAL:
+	{
+		struct ldap_SearchResRef *ent_ref;
+
+		/*
+		 * TODO: This should be handled by the notification
+		 * module not here
+		 */
+		if (call->notification.busy) {
+			ret = LDB_SUCCESS;
+			break;
+		}
+
+		ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultReference);
+		if (ent_r == NULL) {
+			return ldb_oom(ldb);


-- 
Samba Shared Repository



More information about the samba-cvs mailing list