s4/ldap: Test to expoit ldb_ildap bug in case of nested search requests
authorKamen Mazdrashki <kamen.mazdrashki@postpath.com>
Mon, 25 Jan 2010 01:17:29 +0000 (03:17 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 29 Jan 2010 13:09:53 +0000 (14:09 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
source4/torture/config.mk
source4/torture/ldap/common.c
source4/torture/ldap/nested_search.c [new file with mode: 0644]

index f7762db4fdded6e76972167d047b40df2ec56598..34df547e2169497b917e0f87ec6d8f515963a4d0 100644 (file)
@@ -200,7 +200,8 @@ PRIVATE_DEPENDENCIES = \
 # End SUBSYSTEM TORTURE_LDAP
 #################################
 
-TORTURE_LDAP_OBJ_FILES = $(addprefix $(torturesrcdir)/ldap/, common.o basic.o schema.o uptodatevector.o cldap.o cldapbench.o ldap_sort.o)
+TORTURE_LDAP_OBJ_FILES = $(addprefix $(torturesrcdir)/ldap/, common.o basic.o schema.o uptodatevector.o \
+       cldap.o cldapbench.o ldap_sort.o nested_search.o)
 
 $(eval $(call proto_header_template,$(torturesrcdir)/ldap/proto.h,$(TORTURE_LDAP_OBJ_FILES:.o=.c)))
 
index 4a2bc2e3916d455bc661a1aa55d435ba4c93fdc0..38911750e07bd63175962498702d48b092a1f06f 100644 (file)
@@ -109,6 +109,7 @@ NTSTATUS torture_ldap_init(void)
        torture_suite_add_simple_test(suite, "CLDAP", torture_cldap);
        torture_suite_add_simple_test(suite, "SCHEMA", torture_ldap_schema);
        torture_suite_add_simple_test(suite, "UPTODATEVECTOR", torture_ldap_uptodatevector);
+       torture_suite_add_simple_test(suite, "NESTED-SEARCH", test_ldap_nested_search);
 
        suite->description = talloc_strdup(suite, "LDAP and CLDAP tests");
 
diff --git a/source4/torture/ldap/nested_search.c b/source4/torture/ldap/nested_search.c
new file mode 100644 (file)
index 0000000..978c880
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   BRIEF FILE DESCRIPTION
+
+   Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb.h"
+#include "ldb_wrap.h"
+#include "lib/cmdline/popt_common.h"
+#include "torture/torture.h"
+
+#define torture_assert_res(torture_ctx,expr,cmt,_res) \
+       if (!(expr)) { \
+               torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \
+               return _res; \
+       }
+
+
+struct nested_search_context {
+       struct torture_context *tctx;
+       struct ldb_dn *root_dn;
+       struct ldb_context *ldb;
+       struct ldb_result *ldb_res;
+};
+
+/*
+ * ldb_search handler - used to executed a nested
+ * ldap search request during LDB_REPLY_ENTRY handling
+ */
+static int nested_search_callback(struct ldb_request *req,
+                                 struct ldb_reply *ares)
+{
+       int i;
+       int res;
+       struct nested_search_context *sctx;
+       struct ldb_result *ldb_res;
+       struct ldb_message *ldb_msg;
+       static const char *attrs[] = {
+               "rootDomainNamingContext",
+               "configurationNamingContext",
+               "schemaNamingContext",
+               "defaultNamingContext",
+               NULL
+       };
+
+       sctx = talloc_get_type(req->context, struct nested_search_context);
+
+       /* sanity check */
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+               torture_comment(sctx->tctx, "nested_search_callback: LDB_REPLY_ENTRY\n");
+               ldb_msg = ares->message;
+               torture_assert_res(sctx->tctx, ldb_msg, "ares->message is NULL!", LDB_ERR_OPERATIONS_ERROR);
+               torture_assert_res(sctx->tctx, ldb_msg->num_elements, "No elements returned!", LDB_ERR_OPERATIONS_ERROR);
+               torture_assert_res(sctx->tctx, ldb_msg->elements, "elements member is NULL!", LDB_ERR_OPERATIONS_ERROR);
+               break;
+       case LDB_REPLY_DONE:
+               torture_comment(sctx->tctx, "nested_search_callback: LDB_REPLY_DONE\n");
+               break;
+       case LDB_REPLY_REFERRAL:
+               torture_comment(sctx->tctx, "nested_search_callback: LDB_REPLY_REFERRAL\n");
+               break;
+       }
+
+       /* switch context and let default handler do its job */
+       req->context = sctx->ldb_res;
+       res = ldb_search_default_callback(req, ares);
+       req->context = sctx;
+       if (res != LDB_SUCCESS) {
+               return res;
+       }
+
+       /* not a search reply, then get out */
+       if (ares->type != LDB_REPLY_ENTRY) {
+               return res;
+       }
+
+
+       res = ldb_search(sctx->ldb, sctx, &ldb_res, sctx->root_dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)");
+       if (res != LDB_SUCCESS) {
+               torture_warning(sctx->tctx,
+                               "Search on RootDSE failed in search_entry handler: %s",
+                               ldb_errstring(sctx->ldb));
+               return LDB_SUCCESS;
+       }
+
+       torture_assert_res(sctx->tctx, ldb_res->count == 1, "One message expected here", LDB_ERR_OPERATIONS_ERROR);
+
+       ldb_msg = ldb_res->msgs[0];
+       torture_assert_res(sctx->tctx, ldb_msg->num_elements == (ARRAY_SIZE(attrs)-1),
+                          "Search returned different number of elts than requested", LDB_ERR_OPERATIONS_ERROR);
+       for (i = 0; i < ldb_msg->num_elements; i++) {
+               const char *msg;
+               struct ldb_message_element *elt1;
+               struct ldb_message_element *elt2;
+
+               elt2 = &ldb_msg->elements[i];
+               msg = talloc_asprintf(sctx, "Processing element: %s", elt2->name);
+               elt1 = ldb_msg_find_element(sctx->ldb_res->msgs[0], elt2->name);
+               torture_assert_res(sctx->tctx, elt1, msg, LDB_ERR_OPERATIONS_ERROR);
+
+               /* compare elements */
+               torture_assert_res(sctx->tctx, elt2->flags == elt1->flags, "", LDB_ERR_OPERATIONS_ERROR);
+               torture_assert_res(sctx->tctx, elt2->num_values == elt1->num_values, "", LDB_ERR_OPERATIONS_ERROR);
+       }
+       /* TODO: check returned result */
+
+       return LDB_SUCCESS;
+}
+
+/**
+ * Test nested search execution against RootDSE
+ * on remote LDAP server.
+ */
+bool test_ldap_nested_search(struct torture_context *tctx)
+{
+       int ret;
+       char *url;
+       const char *host = torture_setting_string(tctx, "host", NULL);
+       struct ldb_request *req;
+       struct nested_search_context *sctx;
+       static const char *attrs[] = {
+/*
+               "rootDomainNamingContext",
+               "configurationNamingContext",
+               "schemaNamingContext",
+               "defaultNamingContext",
+*/
+               "*",
+               NULL
+       };
+
+       sctx = talloc_zero(tctx, struct nested_search_context);
+       torture_assert(tctx, sctx, "Not enough memory");
+       sctx->tctx = tctx;
+
+       url = talloc_asprintf(sctx, "ldap://%s/", host);
+       if (!url) {
+               torture_assert(tctx, url, "Not enough memory");
+       }
+
+       torture_comment(tctx, "Connecting to: %s\n", url);
+       sctx->ldb = ldb_wrap_connect(sctx, tctx->ev, tctx->lp_ctx, url,
+                                    NULL,
+                                    cmdline_credentials,
+                                    0);
+       torture_assert(tctx, sctx->ldb, "Failed to create ldb connection");
+
+       /* prepare context for searching */
+       sctx->root_dn = ldb_dn_new(sctx, sctx->ldb, NULL);
+       sctx->ldb_res = talloc_zero(sctx, struct ldb_result);
+
+       /* build search request */
+       ret = ldb_build_search_req(&req,
+                                  sctx->ldb,
+                                  sctx,
+                                  sctx->root_dn, LDB_SCOPE_BASE,
+                                  "(objectClass=*)", attrs, NULL,
+                                  sctx, nested_search_callback,
+                                  NULL);
+       if (ret != LDB_SUCCESS) {
+               torture_result(tctx, TORTURE_FAIL,
+                              __location__ ": Allocating request failed: %s", ldb_errstring(sctx->ldb));
+               return false;
+       }
+
+       ret = ldb_request(sctx->ldb, req);
+       if (ret != LDB_SUCCESS) {
+               torture_result(tctx, TORTURE_FAIL,
+                              __location__ ": Search failed: %s", ldb_errstring(sctx->ldb));
+               return false;
+       }
+
+       ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+       if (ret != LDB_SUCCESS) {
+               torture_result(tctx, TORTURE_FAIL,
+                              __location__ ": Search error: %s", ldb_errstring(sctx->ldb));
+               return false;
+       }
+
+       /* TODO: check returned result */
+
+       talloc_free(sctx);
+       return true;
+}
+