summaryrefslogtreecommitdiff
path: root/source4/lib/ldb
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/ldb')
-rw-r--r--source4/lib/ldb/Makefile.in5
-rw-r--r--source4/lib/ldb/common/ldb.c5
-rw-r--r--source4/lib/ldb/common/ldb_controls.c108
-rw-r--r--source4/lib/ldb/common/ldb_dn.c33
-rw-r--r--source4/lib/ldb/common/ldb_modules.c16
-rw-r--r--source4/lib/ldb/config.mk24
-rw-r--r--source4/lib/ldb/include/ldb.h57
-rw-r--r--source4/lib/ldb/include/ldb_errors.h2
-rw-r--r--source4/lib/ldb/include/ldb_private.h18
-rw-r--r--source4/lib/ldb/ldb_ildap/ldb_ildap.c22
-rw-r--r--source4/lib/ldb/ldb_ldap/ldb_ldap.c3
-rw-r--r--source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c8
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_index.c1
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_search.c1
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb.c6
-rw-r--r--source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c1
-rw-r--r--source4/lib/ldb/modules/objectclass.c6
-rw-r--r--source4/lib/ldb/modules/operational.c4
-rw-r--r--source4/lib/ldb/modules/paged_results.c296
-rw-r--r--source4/lib/ldb/modules/rdn_name.c4
-rw-r--r--source4/lib/ldb/modules/schema.c4
-rw-r--r--source4/lib/ldb/modules/skel.c8
-rw-r--r--source4/lib/ldb/modules/sort.c265
-rw-r--r--source4/lib/ldb/samba/ldif_handlers.c1
-rw-r--r--source4/lib/ldb/tools/ldbadd.c1
-rw-r--r--source4/lib/ldb/tools/ldbdel.c1
-rw-r--r--source4/lib/ldb/tools/ldbedit.c1
-rw-r--r--source4/lib/ldb/tools/ldbmodify.c1
-rw-r--r--source4/lib/ldb/tools/ldbrename.c1
-rw-r--r--source4/lib/ldb/tools/ldbsearch.c14
-rw-r--r--source4/lib/ldb/tools/ldbtest.c1
31 files changed, 880 insertions, 38 deletions
diff --git a/source4/lib/ldb/Makefile.in b/source4/lib/ldb/Makefile.in
index 5a6155edd0..bde2388b82 100644
--- a/source4/lib/ldb/Makefile.in
+++ b/source4/lib/ldb/Makefile.in
@@ -57,10 +57,11 @@ COMMON_OBJ=common/ldb.o common/ldb_ldif.o \
common/ldb_parse.o common/ldb_msg.o common/ldb_utf8.o \
common/ldb_debug.o common/ldb_modules.o \
common/ldb_dn.o common/ldb_match.o common/ldb_attributes.o \
- common/attrib_handlers.o
+ common/attrib_handlers.o common/ldb_controls.o common/qsort.o
MODULES_OBJ=modules/operational.o modules/schema.o modules/rdn_name.o \
- modules/objectclass.o modules/ldb_map.o
+ modules/objectclass.o modules/ldb_map.o \
+ modules/paged_results.o modules/sort.o
OBJS = $(MODULES_OBJ) $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LDAP_OBJ) $(LDB_SQLITE3_OBJ)
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index 6095f4fc04..604f02a1f7 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -307,6 +307,7 @@ int ldb_search(struct ldb_context *ldb,
request.op.search.scope = scope;
request.op.search.tree = tree;
request.op.search.attrs = attrs;
+ request.controls = NULL;
ret = ldb_request(ldb, &request);
@@ -332,6 +333,7 @@ int ldb_add(struct ldb_context *ldb,
request.operation = LDB_REQ_ADD;
request.op.add.message = message;
+ request.controls = NULL;
return ldb_request(ldb, &request);
}
@@ -350,6 +352,7 @@ int ldb_modify(struct ldb_context *ldb,
request.operation = LDB_REQ_MODIFY;
request.op.mod.message = message;
+ request.controls = NULL;
return ldb_request(ldb, &request);
}
@@ -364,6 +367,7 @@ int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn)
request.operation = LDB_REQ_DELETE;
request.op.del.dn = dn;
+ request.controls = NULL;
return ldb_request(ldb, &request);
}
@@ -378,6 +382,7 @@ int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct
request.operation = LDB_REQ_RENAME;
request.op.rename.olddn = olddn;
request.op.rename.newdn = newdn;
+ request.controls = NULL;
return ldb_request(ldb, &request);
}
diff --git a/source4/lib/ldb/common/ldb_controls.c b/source4/lib/ldb/common/ldb_controls.c
new file mode 100644
index 0000000000..e4c4c64a6f
--- /dev/null
+++ b/source4/lib/ldb/common/ldb_controls.c
@@ -0,0 +1,108 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb_controls.c
+ *
+ * Component: ldb controls utility functions
+ *
+ * Description: helper functions for control modules
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+
+/* check if a control with the specified "oid" exist and return it */
+/* returns NULL if not found */
+struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid)
+{
+ int i;
+
+ /* check if there's a paged request control */
+ if (controls != NULL) {
+ for (i = 0; controls[i]; i++) {
+ if (strcmp(oid, controls[i]->oid) == 0) {
+ break;
+ }
+ }
+
+ return controls[i];
+ }
+
+ return NULL;
+}
+
+/* saves the current controls list into the "saver" and replace the one in req with a new one excluding
+the "exclude" control */
+/* returns False on error */
+int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
+{
+ struct ldb_control **lcs;
+ int i, j;
+
+ *saver = req->controls;
+ for (i = 0; req->controls[i]; i++);
+ if (i == 1) {
+ req->controls = NULL;
+ return 1;
+ }
+
+ lcs = talloc_array(req, struct ldb_control *, i);
+ if (!lcs) {
+ return 0;
+ }
+
+ for (i = 0, j = 0; (*saver)[i]; i++) {
+ if (exclude == (*saver)[i]) continue;
+ lcs[j] = (*saver)[i];
+ j++;
+ }
+ lcs[j] = NULL;
+
+ req->controls = lcs;
+ return 1;
+}
+
+/* check if there's any control marked as critical in the list */
+/* return True if any, False if none */
+int check_critical_controls(struct ldb_control **controls)
+{
+ int i;
+
+ if (controls == NULL) {
+ return 0;
+ }
+
+ for (i = 0; controls[i]; i++) {
+ if (controls[i]->critical) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c
index 4ae00ee6dc..5ed54ae316 100644
--- a/source4/lib/ldb/common/ldb_dn.c
+++ b/source4/lib/ldb/common/ldb_dn.c
@@ -417,6 +417,39 @@ failed:
return NULL;
}
+struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn)
+{
+ struct ldb_dn *edn; /* the exploded dn */
+
+ if (dn == NULL) return NULL;
+
+ if (strncasecmp(dn, "<GUID=", 6) == 0) {
+ /* this is special DN returned when the
+ * exploded_dn control is used
+ */
+
+ /* Allocate a structure to hold the exploded DN */
+ edn = ldb_dn_new(mem_ctx);
+
+ edn->comp_num = 1;
+ edn->components = talloc(edn, struct ldb_dn_component);
+ if (edn->components == NULL) goto failed;
+ edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL);
+ if (edn->components[0].name == NULL) goto failed;
+ edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn);
+ if (edn->components[0].value.data== NULL) goto failed;
+ edn->components[0].value.length = strlen(dn);
+ return edn;
+
+ }
+
+ return ldb_dn_explode(mem_ctx, dn);
+
+failed:
+ talloc_free(edn);
+ return NULL;
+}
+
char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn)
{
char *dn, *value;
diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c
index 5c2e36d431..26a397dccc 100644
--- a/source4/lib/ldb/common/ldb_modules.c
+++ b/source4/lib/ldb/common/ldb_modules.c
@@ -131,12 +131,15 @@ int ldb_load_modules(struct ldb_context *ldb, const char *options[])
{ "operational", operational_module_init },
{ "rdn_name", rdn_name_module_init },
{ "objectclass", objectclass_module_init },
+ { "paged_results", paged_results_module_init },
+ { "server_sort", server_sort_module_init },
#ifdef _SAMBA_BUILD_
{ "objectguid", objectguid_module_init },
{ "samldb", samldb_module_init },
{ "samba3sam", ldb_samba3sam_module_init },
{ "proxy", proxy_module_init },
{ "rootdse", rootdse_module_init },
+ { "extended_dn", extended_dn_module_init },
{ "password_hash", password_hash_module_init },
#endif
{ NULL, NULL }
@@ -198,7 +201,7 @@ int ldb_load_modules(struct ldb_context *ldb, const char *options[])
int m;
for (m=0;well_known_modules[m].name;m++) {
if (strcmp(modules[i], well_known_modules[m].name) == 0) {
- current = well_known_modules[m].init(ldb, options);
+ current = well_known_modules[m].init(ldb, LDB_MODULES_INIT_STAGE_1, options);
if (current == NULL) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "function 'init_module' in %s fails\n", modules[i]);
return -1;
@@ -213,6 +216,17 @@ int ldb_load_modules(struct ldb_context *ldb, const char *options[])
}
}
+ /* second stage init */
+ for (i = 0; modules[i] != NULL; i++) {
+ int m;
+ for (m = 0; well_known_modules[m].name; m++) {
+ if (strcmp(modules[i], well_known_modules[m].name) == 0) {
+ well_known_modules[m].init(ldb, LDB_MODULES_INIT_STAGE_2, options);
+ break;
+ }
+ }
+ }
+
talloc_free(modules);
return 0;
}
diff --git a/source4/lib/ldb/config.mk b/source4/lib/ldb/config.mk
index 13280bac68..cbd91a6de6 100644
--- a/source4/lib/ldb/config.mk
+++ b/source4/lib/ldb/config.mk
@@ -1,4 +1,24 @@
################################################
+# Start MODULE libldb_sort
+[MODULE::libldb_sort]
+SUBSYSTEM = LIBLDB
+OUTPUT_TYPE = MERGEDOBJ
+OBJ_FILES = \
+ modules/sort.o
+# End MODULE libldb_sort
+################################################
+
+################################################
+# Start MODULE libldb_paged_results
+[MODULE::libldb_paged_results]
+SUBSYSTEM = LIBLDB
+OUTPUT_TYPE = MERGEDOBJ
+OBJ_FILES = \
+ modules/paged_results.o
+# End MODULE libldb_paged_results
+################################################
+
+################################################
# Start MODULE libldb_operational
[MODULE::libldb_operational]
SUBSYSTEM = LIBLDB
@@ -118,7 +138,9 @@ OBJ_FILES = \
common/ldb_match.o \
common/ldb_attributes.o \
common/attrib_handlers.o \
- common/ldb_dn.o
+ common/ldb_dn.o \
+ common/ldb_controls.o \
+ common/qsort.o
REQUIRED_SUBSYSTEMS = \
LIBREPLACE LIBTALLOC LDBSAMBA
NOPROTO = YES
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index 9c3b033091..299a5d171e 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -141,12 +141,6 @@ struct ldb_context;
typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *);
-struct ldb_module;
-
-/* module initialisation function */
-typedef struct ldb_module *(*ldb_module_init_t)(struct ldb_context *, const char **);
-
-
/* debugging uses one of the following levels */
enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR,
LDB_DEBUG_WARNING, LDB_DEBUG_TRACE};
@@ -253,7 +247,41 @@ struct ldb_attrib_handler {
#define LDB_SYNTAX_UTC_TIME "1.3.6.1.4.1.1466.115.121.1.53"
#define LDB_SYNTAX_OBJECTCLASS "LDB_SYNTAX_OBJECTCLASS"
-struct ldb_controls;
+/* sorting helpers */
+typedef int (*ldb_qsort_cmp_fn_t) (const void *, const void *, const void *);
+
+#define LDB_CONTROL_PAGED_RESULTS_OID "1.2.840.113556.1.4.319"
+#define LDB_CONTROL_EXTENDED_DN_OID "1.2.840.113556.1.4.529"
+#define LDB_CONTROL_SERVER_SORT_OID "1.2.840.113556.1.4.473"
+#define LDB_CONTROL_SORT_RESP_OID "1.2.840.113556.1.4.474"
+
+struct ldb_paged_control {
+ int size;
+ int cookie_len;
+ char *cookie;
+};
+
+struct ldb_extended_dn_control {
+ int type;
+};
+
+struct ldb_server_sort_control {
+ char *attributeName;
+ char *orderingRule;
+ int reverse;
+};
+
+struct ldb_sort_resp_control {
+ int result;
+ char *attr_desc;
+};
+
+struct ldb_control {
+ const char *oid;
+ int critical;
+ void *data;
+};
+
struct ldb_credentials;
enum ldb_request_type {
@@ -261,12 +289,14 @@ enum ldb_request_type {
LDB_REQ_ADD,
LDB_REQ_MODIFY,
LDB_REQ_DELETE,
- LDB_REQ_RENAME
+ LDB_REQ_RENAME,
+ LDB_REQ_REGISTER
};
struct ldb_result {
unsigned int count;
struct ldb_message **msgs;
+ struct ldb_control **controls;
};
struct ldb_search {
@@ -294,6 +324,10 @@ struct ldb_rename {
const struct ldb_dn *newdn;
};
+struct ldb_register_control {
+ const char *oid;
+};
+
struct ldb_request {
int operation;
@@ -304,9 +338,10 @@ struct ldb_request {
struct ldb_modify mod;
struct ldb_delete del;
struct ldb_rename rename;
+ struct ldb_register_control reg;
} op;
- struct ldb_controls *controls;
+ struct ldb_control **controls;
struct ldb_credentials *creds;
};
@@ -427,6 +462,7 @@ int ldb_dn_check_special(const struct ldb_dn *dn, const char *check);
char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value);
struct ldb_dn *ldb_dn_new(void *mem_ctx);
struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn);
+struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn);
char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn);
char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *edn);
int ldb_dn_compare_base(struct ldb_context *ldb, const struct ldb_dn *base, const struct ldb_dn *dn);
@@ -565,4 +601,7 @@ time_t ldb_string_to_time(const char *s);
char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn);
char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn);
+
+
+void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp);
#endif
diff --git a/source4/lib/ldb/include/ldb_errors.h b/source4/lib/ldb/include/ldb_errors.h
index f59b39f92a..a93d3cd388 100644
--- a/source4/lib/ldb/include/ldb_errors.h
+++ b/source4/lib/ldb/include/ldb_errors.h
@@ -52,7 +52,7 @@
/* 9 RESERVED */
#define LDB_ERR_REFERRAL 10
#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11
-#define LDB_ERR_UNAVAILABLE_CRITICAL_EXTENSION 12
+#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12
#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13
#define LDB_ERR_SASL_BIND_IN_PROGRESS 14
#define LDB_ERR_NO_SUCH_ATTRIBUTE 16
diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h
index d0aec6e137..e8a4d1820a 100644
--- a/source4/lib/ldb/include/ldb_private.h
+++ b/source4/lib/ldb/include/ldb_private.h
@@ -104,7 +104,9 @@ struct ldb_context {
};
/* the modules init function */
-typedef struct ldb_module *(*ldb_module_init_function)(struct ldb_context *ldb, const char *options[]);
+#define LDB_MODULES_INIT_STAGE_1 1
+#define LDB_MODULES_INIT_STAGE_2 2
+typedef struct ldb_module *(*ldb_module_init_t)(struct ldb_context *, int stage, const char **);
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
@@ -147,10 +149,12 @@ int lsqlite3_connect(struct ldb_context *ldb,
const char *url,
unsigned int flags,
const char *options[]);
-struct ldb_module *operational_module_init(struct ldb_context *ldb, const char *options[]);
-struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[]);
-struct ldb_module *rdn_name_module_init(struct ldb_context *ldb, const char *options[]);
-struct ldb_module *objectclass_module_init(struct ldb_context *ldb, const char *options[]);
+struct ldb_module *objectclass_module_init(struct ldb_context *ldb, int stage, const char *options[]);
+struct ldb_module *operational_module_init(struct ldb_context *ldb, int stage, const char *options[]);
+struct ldb_module *paged_results_module_init(struct ldb_context *ldb, int stage, const char *options[]);
+struct ldb_module *rdn_name_module_init(struct ldb_context *ldb, int stage, const char *options[]);
+struct ldb_module *schema_module_init(struct ldb_context *ldb, int stage, const char *options[]);
+struct ldb_module *server_sort_module_init(struct ldb_context *ldb, int stage, const char *options[]);
int ldb_match_msg(struct ldb_context *ldb,
@@ -179,4 +183,8 @@ int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
+/* The following definitions come from lib/ldb/common/ldb_controls.c */
+struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid);
+int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver);
+int check_critical_controls(struct ldb_control **controls);
#endif
diff --git a/source4/lib/ldb/ldb_ildap/ldb_ildap.c b/source4/lib/ldb/ldb_ildap/ldb_ildap.c
index 0802469079..ff00a61163 100644
--- a/source4/lib/ldb/ldb_ildap/ldb_ildap.c
+++ b/source4/lib/ldb/ldb_ildap/ldb_ildap.c
@@ -148,11 +148,14 @@ static void ildb_rootdse(struct ldb_module *module);
*/
static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
enum ldb_scope scope, struct ldb_parse_tree *tree,
- const char * const *attrs, struct ldb_result **res)
+ const char * const *attrs,
+ struct ldb_control **control_req,
+ struct ldb_result **res)
{
struct ildb_private *ildb = module->private_data;
int count, i;
struct ldap_message **ldapres, *msg;
+ struct ldap_Control **controls = NULL;
char *search_base;
NTSTATUS status;
@@ -189,9 +192,12 @@ static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba
}
(*res)->count = 0;
(*res)->msgs = NULL;
+ (*res)->controls = NULL;
- status = ildap_search_bytree(ildb->ldap, search_base, scope, tree, attrs,
- 0, &ldapres);
+ status = ildap_search_bytree(ildb->ldap, search_base, scope, tree, attrs, 0,
+ (struct ldap_Control **)control_req,
+ &controls,
+ &ldapres);
talloc_free(search_base);
if (!NT_STATUS_IS_OK(status)) {
ildb_map_error(ildb, status);
@@ -230,7 +236,7 @@ static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba
}
(*res)->msgs[i+1] = NULL;
- (*res)->msgs[i]->dn = ldb_dn_explode((*res)->msgs[i], search->dn);
+ (*res)->msgs[i]->dn = ldb_dn_explode_or_special((*res)->msgs[i], search->dn);
if ((*res)->msgs[i]->dn == NULL) {
goto failed;
}
@@ -242,6 +248,11 @@ static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba
talloc_free(ldapres);
(*res)->count = count;
+
+ if (controls) {
+ (*res)->controls = (struct ldb_control **)talloc_steal(*res, controls);
+ }
+
return LDB_SUCCESS;
failed:
@@ -407,6 +418,7 @@ static int ildb_request(struct ldb_module *module, struct ldb_request *req)
req->op.search.scope,
req->op.search.tree,
req->op.search.attrs,
+ req->controls,
&req->op.search.res);
case LDB_REQ_ADD:
@@ -449,7 +461,7 @@ static void ildb_rootdse(struct ldb_module *module)
int ret;
ret = ildb_search_bytree(module, empty_dn, LDB_SCOPE_BASE,
ldb_parse_tree(empty_dn, "dn=dc=rootDSE"),
- NULL, &res);
+ NULL, NULL, &res);
if (ret == LDB_SUCCESS && res->count == 1) {
ildb->rootDSE = talloc_steal(ildb, res->msgs[0]);
}
diff --git a/source4/lib/ldb/ldb_ldap/ldb_ldap.c b/source4/lib/ldb/ldb_ldap/ldb_ldap.c
index 893ad0dd2a..8207b5f592 100644
--- a/source4/lib/ldb/ldb_ldap/ldb_ldap.c
+++ b/source4/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -219,6 +219,7 @@ static int lldb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba
}
(*res)->count = 0;
(*res)->msgs = NULL;
+ (*res)->controls = NULL;
lldb->last_rc = ldap_search_s(lldb->ldap, search_base, ldap_scope,
expression,
@@ -272,7 +273,7 @@ static int lldb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba
goto failed;
}
- (*res)->msgs[msg_count]->dn = ldb_dn_explode((*res)->msgs[msg_count], dn);
+ (*res)->msgs[msg_count]->dn = ldb_dn_explode_or_special((*res)->msgs[msg_count], dn);
ldap_memfree(dn);
if (!(*res)->msgs[msg_count]->dn) {
goto failed;
diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
index 1d23478941..464c8ce69f 100644
--- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
+++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -984,6 +984,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d
(*res)->msgs = talloc_steal(*res, msgs.msgs);
(*res)->count = msgs.count;
+ (*res)->controls = NULL;
talloc_free(local_ctx);
return LDB_SUCCESS;
@@ -1783,6 +1784,11 @@ destructor(void *p)
static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req)
{
+ /* check for oustanding critical controls and return an error if found */
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
switch (req->operation) {
case LDB_REQ_SEARCH:
@@ -1791,7 +1797,7 @@ static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req)
req->op.search.scope,
req->op.search.tree,
req->op.search.attrs,
- req->op.search.res);
+ &req->op.search.res);
case LDB_REQ_ADD:
return lsqlite3_add(module, req->op.add.message);
diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c
index 75514fac83..cf9ad3b7fe 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_index.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_index.c
@@ -709,6 +709,7 @@ int ltdb_search_indexed(struct ldb_module *module,
}
(*res)->count = 0;
(*res)->msgs = NULL;
+ (*res)->controls = NULL;
if (scope == LDB_SCOPE_BASE) {
/* with BASE searches only one DN can match */
diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c
index 01a87e00b1..aa5cb40712 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_search.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_search.c
@@ -441,6 +441,7 @@ static int ltdb_search_full(struct ldb_module *module,
return -1;
}
+ result->controls = NULL;
result->msgs = talloc_steal(result, sinfo->msgs);
result->count = sinfo->count;
*res = result;
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
index ebee029d9c..432c713336 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -737,6 +737,12 @@ static int ltdb_del_trans(struct ldb_module *module)
static int ltdb_request(struct ldb_module *module, struct ldb_request *req)
{
+ /* check for oustanding critical controls and return an error if found */
+
+ if (check_critical_controls(req->controls)) {
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
switch (req->operation) {
case LDB_REQ_SEARCH:
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
index c2e65cf825..3a18f5df88 100644
--- a/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
+++ b/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
@@ -24,6 +24,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
/*
diff --git a/source4/lib/ldb/modules/objectclass.c b/source4/lib/ldb/modules/objectclass.c
index 9891ed8eb1..7a037cc98a 100644
--- a/source4/lib/ldb/modules/objectclass.c
+++ b/source4/lib/ldb/modules/objectclass.c
@@ -108,6 +108,7 @@ static int objectclass_handle(struct ldb_module *module, struct ldb_request *req
search_request->op.search.scope = LDB_SCOPE_BASE;
search_request->op.search.tree = ldb_parse_tree(module->ldb, NULL);
search_request->op.search.attrs = attrs;
+ search_request->controls = NULL;
ret = ldb_next_request(module, search_request);
if (ret) {
@@ -273,6 +274,7 @@ static int objectclass_handle(struct ldb_module *module, struct ldb_request *req
modify_request->operation = LDB_REQ_MODIFY;
modify_request->op.mod.message = modify_msg;
+ modify_request->controls = NULL;
/* And now push the write into the database */
ret = ldb_next_request(module, modify_request);
@@ -303,10 +305,12 @@ static const struct ldb_module_ops objectclass_ops = {
.request = objectclass_request,
};
-struct ldb_module *objectclass_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *objectclass_module_init(struct ldb_context *ldb, int stage, const char *options[])
{
struct ldb_module *ctx;
+ if (stage != LDB_MODULES_INIT_STAGE_1) return NULL;
+
ctx = talloc(ldb, struct ldb_module);
if (!ctx)
return NULL;
diff --git a/source4/lib/ldb/modules/operational.c b/source4/lib/ldb/modules/operational.c
index 65d9f12e34..09de0936a1 100644
--- a/source4/lib/ldb/modules/operational.c
+++ b/source4/lib/ldb/modules/operational.c
@@ -368,10 +368,12 @@ static const struct ldb_module_ops operational_ops = {
/* the init function */
-struct ldb_module *operational_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *operational_module_init(struct ldb_context *ldb, int stage, const char *options[])
{
struct ldb_module *ctx;
+ if (stage != LDB_MODULES_INIT_STAGE_1) return NULL;
+
ctx = talloc(ldb, struct ldb_module);
if (!ctx)
return NULL;
diff --git a/source4/lib/ldb/modules/paged_results.c b/source4/lib/ldb/modules/paged_results.c
new file mode 100644
index 0000000000..31b73d2ae4
--- /dev/null
+++ b/source4/lib/ldb/modules/paged_results.c
@@ -0,0 +1,296 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb paged results control module
+ *
+ * Description: this module caches a complete search and sends back
+ * results in chunks as asked by the client
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+
+#include <time.h>
+
+struct results_store {
+ char *cookie;
+ time_t timestamp;
+ int num_sent;
+ struct ldb_result *result;
+ struct results_store *prev;
+ struct results_store *next;
+};
+
+struct private_data {
+
+ int next_free_id;
+ struct results_store *store;
+
+};
+
+
+static struct results_store *new_store(struct private_data *priv)
+{
+ struct results_store *new;
+ int new_id = priv->next_free_id++;
+
+ /* TODO: we should have a limit on the number of
+ * outstanding paged searches
+ */
+
+ new = talloc(priv, struct results_store);
+ if (!new) return NULL;
+
+ new->cookie = talloc_asprintf(new, "%d", new_id);
+ if (!new->cookie) {
+ talloc_free(new);
+ return NULL;
+ }
+
+ new->timestamp = time(NULL);
+
+ new->num_sent = 0;
+ new->result = NULL;
+
+ /* put this entry as first */
+ new->prev = NULL;
+ new->next = priv->store;
+ if (priv->store != NULL) priv->store->prev = new;
+ priv->store = new;
+
+ return new;
+}
+
+static void remove_store(struct results_store *store)
+{
+ if (store->prev) {
+ store->prev->next = store->next;
+ }
+ if (store->next) {
+ store->next->prev = store->prev;
+ }
+ talloc_free(store);
+}
+
+/* search */
+static int paged_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct private_data *private_data = talloc_get_type(module->private_data, struct private_data);
+ struct results_store *current = NULL;
+ struct ldb_result *paged_result;
+ struct ldb_control **saved_controls;
+ struct ldb_control *control;
+ struct ldb_paged_control *paged_ctrl;
+ struct ldb_paged_control *paged_ret;
+ int i, ret;
+
+ /* check if there's a paged request control */
+ control = get_control_from_list(req->controls, LDB_CONTROL_PAGED_RESULTS_OID);
+
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control);
+
+ /* check if it is a continuation search the store */
+ if (paged_ctrl->cookie_len != 0) {
+ for (current = private_data->store; current; current = current->next) {
+ if (strcmp(current->cookie, paged_ctrl->cookie) == 0) {
+ current->timestamp = time(NULL);
+ break;
+ }
+ }
+ if (current == NULL) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ /* is this a brand new paged request ? */
+ if (current == NULL) {
+
+ /* save controls list and remove this one from the list */
+ if (!save_controls(control, req, &saved_controls)) {
+ return LDB_ERR_OTHER;
+ }
+
+ /* perform the search */
+ ret = ldb_next_request(module, req);
+
+ /* restore original controls list */
+ if (req->controls) talloc_free(req->controls);
+ req->controls = saved_controls;
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* create a new entry in the cache */
+ current = new_store(private_data);
+ if (!current) {
+ return LDB_ERR_OTHER;
+ }
+
+ /* steal the search result */
+ current->result = talloc_steal(current, req->op.search.res);
+ req->op.search.res = NULL;
+ }
+
+ /* create a container for the next batch of results */
+ paged_result = talloc(current, struct ldb_result);
+ if (!paged_result) {
+ return LDB_ERR_OTHER;
+ }
+ paged_result->count = 0;
+ paged_result->msgs = NULL;
+ paged_result->controls = NULL;
+
+ /* check if it is an abandon */
+ if (paged_ctrl->size == 0) {
+ req->op.search.res = talloc_steal(private_data, paged_result);
+ remove_store(current);
+ return LDB_SUCCESS;
+ }
+
+ /* return a batch of results */
+
+ paged_result->controls = talloc_array(paged_result, struct ldb_control *, 2);
+ if (!paged_result->controls) {
+ talloc_free(paged_result);
+ return LDB_ERR_OTHER;
+ }
+
+ paged_result->controls[0] = talloc(paged_result->controls, struct ldb_control);
+ if (!paged_result->controls[0]) {
+ talloc_free(paged_result);
+ return LDB_ERR_OTHER;
+ }
+ paged_result->controls[0]->oid = talloc_strdup(paged_result->controls[0], LDB_CONTROL_PAGED_RESULTS_OID);
+ paged_result->controls[0]->critical = 0;
+ paged_result->controls[1] = NULL;
+
+ paged_ret = talloc(paged_result->controls[0], struct ldb_paged_control);
+ if (!paged_ret) {
+ talloc_free(paged_result);
+ return LDB_ERR_OTHER;
+ }
+ paged_result->controls[0]->data = paged_ret;
+
+ if (paged_ctrl->size >= current->result->count) {
+ paged_ret->size = 0;
+ paged_ret->cookie = NULL;
+ paged_ret->cookie_len = 0;
+ paged_result->count = current->result->count;
+ current->result->count = 0;
+ } else {
+ paged_ret->size = current->result->count;
+ paged_ret->cookie = talloc_strdup(paged_ret, current->cookie);
+ paged_ret->cookie_len = strlen(paged_ret->cookie) + 1;
+ paged_result->count = paged_ctrl->size;
+ current->result->count -= paged_ctrl->size;
+ }
+
+ paged_result->msgs = talloc_array(paged_result, struct ldb_message *, paged_result->count + 1);
+ if (!paged_result->msgs) {
+ talloc_free(paged_result);
+ return LDB_ERR_OTHER;
+ }
+ for (i = 0; i < paged_result->count; i++) {
+ paged_result->msgs[i] = talloc_steal(paged_result->msgs, current->result->msgs[current->num_sent + i]);
+ }
+ current->num_sent += paged_result->count;
+ paged_result->msgs[paged_result->count] = NULL;
+
+ req->op.search.res = paged_result;
+
+ return LDB_SUCCESS;
+}
+
+static int paged_request(struct ldb_module *module, struct ldb_request *req)
+{
+ switch (req->operation) {
+
+ case LDB_REQ_SEARCH:
+ return paged_search(module, req);
+
+ default:
+ return ldb_next_request(module, req);
+
+ }
+}
+
+static const struct ldb_module_ops paged_ops = {
+ .name = "paged_results",
+ .request = paged_request,
+};
+
+struct ldb_module *paged_results_module_init(struct ldb_context *ldb, int stage, const char *options[])
+{
+ struct ldb_module *ctx;
+ struct private_data *data;
+
+ if (stage == LDB_MODULES_INIT_STAGE_2) {
+ struct ldb_request request;
+ int ret;
+
+ request.operation = LDB_REQ_REGISTER;
+ request.op.reg.oid = LDB_CONTROL_PAGED_RESULTS_OID;
+ request.controls = NULL;
+
+ ret = ldb_request(ldb, &request);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "paged_request: Unable to register control with rootdse!\n");
+ }
+
+ return NULL;
+ }
+
+ ctx = talloc(ldb, struct ldb_module);
+ if (!ctx)
+ return NULL;
+
+ data = talloc(ctx, struct private_data);
+ if (data == NULL) {
+ talloc_free(ctx);
+ return NULL;
+ }
+
+ data->next_free_id = 1;
+ data->store = NULL;
+ ctx->private_data = data;
+
+ ctx->ldb = ldb;
+ ctx->prev = ctx->next = NULL;
+ ctx->ops = &paged_ops;
+
+ return ctx;
+}
diff --git a/source4/lib/ldb/modules/rdn_name.c b/source4/lib/ldb/modules/rdn_name.c
index f35cff916c..f6dbc38740 100644
--- a/source4/lib/ldb/modules/rdn_name.c
+++ b/source4/lib/ldb/modules/rdn_name.c
@@ -214,10 +214,12 @@ static const struct ldb_module_ops rdn_name_ops = {
/* the init function */
-struct ldb_module *rdn_name_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *rdn_name_module_init(struct ldb_context *ldb, int stage, const char *options[])
{
struct ldb_module *ctx;
+ if (stage != LDB_MODULES_INIT_STAGE_1) return NULL;
+
ctx = talloc(ldb, struct ldb_module);
if (!ctx)
return NULL;
diff --git a/source4/lib/ldb/modules/schema.c b/source4/lib/ldb/modules/schema.c
index 9fb2efee30..778f52885c 100644
--- a/source4/lib/ldb/modules/schema.c
+++ b/source4/lib/ldb/modules/schema.c
@@ -484,10 +484,12 @@ static const struct ldb_module_ops schema_ops = {
.request = schema_request
};
-struct ldb_module *schema_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *schema_module_init(struct ldb_context *ldb, int stage, const char *options[])
{
struct ldb_module *ctx;
+ if (stage != LDB_MODULES_INIT_STAGE_1) return NULL;
+
ctx = talloc(ldb, struct ldb_module);
if (!ctx) {
return NULL;
diff --git a/source4/lib/ldb/modules/skel.c b/source4/lib/ldb/modules/skel.c
index 1bbb81f288..dacbd6960e 100644
--- a/source4/lib/ldb/modules/skel.c
+++ b/source4/lib/ldb/modules/skel.c
@@ -131,11 +131,17 @@ static const struct ldb_module_ops skel_ops = {
.del_transaction = skel_del_trans,
};
-struct ldb_module *skel_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *skel_module_init(struct ldb_context *ldb, int stage, const char *options[])
{
struct ldb_module *ctx;
struct private_data *data;
+ if (stage == LDB_MODULES_INIT_STAGE_2) {
+ /* second stage init stuff */
+ /* see control modules as example */
+ return NULL;
+ }
+
ctx = talloc(ldb, struct ldb_module);
if (!ctx)
return NULL;
diff --git a/source4/lib/ldb/modules/sort.c b/source4/lib/ldb/modules/sort.c
new file mode 100644
index 0000000000..2757647710
--- /dev/null
+++ b/source4/lib/ldb/modules/sort.c
@@ -0,0 +1,265 @@
+/*
+ ldb database library
+
+ Copyright (C) Simo Sorce 2005
+
+ ** NOTE! The following LGPL license applies to the ldb
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * Name: ldb
+ *
+ * Component: ldb server side sort control module
+ *
+ * Description: this module sorts the results of a search
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+
+struct opaque {
+ struct ldb_context *ldb;
+ const struct ldb_attrib_handler *h;
+ const char *attribute;
+ int reverse;
+ int result;
+};
+
+static int build_response(struct ldb_result *res, int result, const char *desc)
+{
+ struct ldb_sort_resp_control *resp;
+ int i;
+
+ if (res->controls) {
+ for (i = 0; res->controls[i]; i++);
+ res->controls = talloc_realloc(res, res->controls, struct ldb_control *, i + 2);
+ } else {
+ i = 0;
+ res->controls = talloc_array(res, struct ldb_control *, 2);
+ }
+ if (! res->controls )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ res->controls[i+1] = NULL;
+ res->controls[i] = talloc(res->controls, struct ldb_control);
+ if (! res->controls[i] )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ res->controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
+ res->controls[i]->critical = 0;
+
+ resp = talloc(res->controls[i], struct ldb_sort_resp_control);
+ if (! resp )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ resp->result = result;
+ resp->attr_desc = talloc_strdup(resp, desc);
+
+ if (! resp->attr_desc )
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ res->controls[i]->data = resp;
+
+ return LDB_SUCCESS;
+}
+
+static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
+{
+ struct opaque *data = (struct opaque *)opaque;
+ struct ldb_message_element *el1, *el2;
+
+ if (data->result != 0) {
+ /* an error occurred previously,
+ * let's exit the sorting by returning always 0 */
+ return 0;
+ }
+
+ el1 = ldb_msg_find_element(*msg1, data->attribute);
+ el2 = ldb_msg_find_element(*msg2, data->attribute);
+
+ if (!el1 || !el2) {
+ /* the attribute was not found return and
+ * set an error */
+ data->result = 53;
+ return 0;
+ }
+
+ if (data->reverse)
+ return data->h->comparison_fn(data->ldb, data, &el2->values[0], &el1->values[0]);
+
+ return data->h->comparison_fn(data->ldb, data, &el1->values[0], &el2->values[0]);
+}
+
+/* search */
+static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_result *sort_result = NULL;
+ struct ldb_control *control;
+ struct ldb_control **saved_controls;
+ struct ldb_server_sort_control **sort_ctrls;
+ int ret, result = 0;
+ int do_sort = 1;
+
+ /* check if there's a paged request control */
+ control = get_control_from_list(req->controls, LDB_CONTROL_SERVER_SORT_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
+
+ /* FIXME: we do not support more than one attribute for sorting right now */
+ /* FIXME: we need to check if the attribute type exist or return an error */
+ if (sort_ctrls[1] != NULL)
+ do_sort = 0;
+
+ if (!do_sort && control->critical) {
+ sort_result = talloc_zero(req, struct ldb_result);
+ if (!sort_result)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ req->op.search.res = sort_result;
+
+ /* 53 = unwilling to perform */
+ if ((ret = build_response(sort_result, 53, "sort control is not complete yet")) != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+ }
+
+ /* save it locally and remove it from the list */
+ if (!save_controls(control, req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_next_request(module, req);
+
+ if (req->controls) talloc_free(req->controls);
+ req->controls = saved_controls;
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* SORT HERE */
+ if (do_sort) {
+ struct opaque *data;
+
+ data = talloc(module, struct opaque);
+ if (!data)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ data->attribute = sort_ctrls[0]->attributeName;
+ data->reverse = sort_ctrls[0]->reverse;
+ data->ldb = module->ldb;
+ data->h = ldb_attrib_handler(data->ldb, data->attribute);
+ data->result = 0;
+ sort_result = req->op.search.res;
+
+ /* FIXME: I don't like to use a static structure like sort_control
+ * we need to either:
+ * a) write a qsort function that takes a third void parameter
+ * or
+ * b) prepare a structure with all elements pre digested like:
+ * struct element {
+ * struct ldb_message_element *el;
+ * struct ldb_message *msg;
+ * }
+ *
+ * this mean we will have to do a linear scan of
+ * the msgs array to build the new sort array, and
+ * then do a linear scan of the resulting array
+ * to rebuild the msgs array in the original shape.
+ */
+
+ ldb_qsort(sort_result->msgs,
+ sort_result->count,
+ sizeof(struct ldb_message *),
+ data,
+ (ldb_qsort_cmp_fn_t)sort_compare);
+
+ result = data->result;
+
+ talloc_free(data);
+ } else {
+ result = 53;
+ }
+
+ if ((ret = build_response(sort_result, result, "sort control is not complete yet")) != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int server_sort(struct ldb_module *module, struct ldb_request *req)
+{
+ switch (req->operation) {
+
+ case LDB_REQ_SEARCH:
+ return server_sort_search(module, req);
+
+ default:
+ return ldb_next_request(module, req);
+
+ }
+}
+
+static const struct ldb_module_ops server_sort_ops = {
+ .name = "server_sort",
+ .request = server_sort,
+};
+
+struct ldb_module *server_sort_module_init(struct ldb_context *ldb, int stage, const char *options[])
+{
+ struct ldb_module *ctx;
+
+ if (stage == LDB_MODULES_INIT_STAGE_2) {
+ struct ldb_request request;
+ int ret;
+
+ request.operation = LDB_REQ_REGISTER;
+ request.op.reg.oid = LDB_CONTROL_SERVER_SORT_OID;
+ request.controls = NULL;
+
+ ret = ldb_request(ldb, &request);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "server_sort: Unable to register control with rootdse!\n");
+ }
+
+ return NULL;
+ }
+
+ ctx = talloc(ldb, struct ldb_module);
+ if (!ctx)
+ return NULL;
+
+ ctx->ldb = ldb;
+ ctx->prev = ctx->next = NULL;
+ ctx->ops = &server_sort_ops;
+ ctx->private_data = NULL;
+
+ return ctx;
+}
diff --git a/source4/lib/ldb/samba/ldif_handlers.c b/source4/lib/ldb/samba/ldif_handlers.c
index 51cb3f8d78..84270195dc 100644
--- a/source4/lib/ldb/samba/ldif_handlers.c
+++ b/source4/lib/ldb/samba/ldif_handlers.c
@@ -25,6 +25,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_private.h"
+#include "librpc/gen_ndr/ndr_security.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "dsdb/samdb/samdb.h"
diff --git a/source4/lib/ldb/tools/ldbadd.c b/source4/lib/ldb/tools/ldbadd.c
index c22cfde4ec..058f4dc751 100644
--- a/source4/lib/ldb/tools/ldbadd.c
+++ b/source4/lib/ldb/tools/ldbadd.c
@@ -35,6 +35,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_
diff --git a/source4/lib/ldb/tools/ldbdel.c b/source4/lib/ldb/tools/ldbdel.c
index a6574a5088..6da8d0269f 100644
--- a/source4/lib/ldb/tools/ldbdel.c
+++ b/source4/lib/ldb/tools/ldbdel.c
@@ -35,6 +35,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_
diff --git a/source4/lib/ldb/tools/ldbedit.c b/source4/lib/ldb/tools/ldbedit.c
index 8818777ceb..4d47cf27c9 100644
--- a/source4/lib/ldb/tools/ldbedit.c
+++ b/source4/lib/ldb/tools/ldbedit.c
@@ -35,6 +35,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_
diff --git a/source4/lib/ldb/tools/ldbmodify.c b/source4/lib/ldb/tools/ldbmodify.c
index f067aef3f8..4c78e485b5 100644
--- a/source4/lib/ldb/tools/ldbmodify.c
+++ b/source4/lib/ldb/tools/ldbmodify.c
@@ -34,6 +34,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_
diff --git a/source4/lib/ldb/tools/ldbrename.c b/source4/lib/ldb/tools/ldbrename.c
index f225246cc7..4b3b27c130 100644
--- a/source4/lib/ldb/tools/ldbrename.c
+++ b/source4/lib/ldb/tools/ldbrename.c
@@ -36,6 +36,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_
diff --git a/source4/lib/ldb/tools/ldbsearch.c b/source4/lib/ldb/tools/ldbsearch.c
index c493356405..a340e16d08 100644
--- a/source4/lib/ldb/tools/ldbsearch.c
+++ b/source4/lib/ldb/tools/ldbsearch.c
@@ -35,6 +35,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_
@@ -55,12 +56,12 @@ static void usage(void)
exit(1);
}
-struct ldb_context *ldbsearch_ldb;
-
static int do_compare_msg(struct ldb_message **el1,
- struct ldb_message **el2)
+ struct ldb_message **el2,
+ void *opaque)
{
- return ldb_dn_compare(ldbsearch_ldb, (*el1)->dn, (*el2)->dn);
+ struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
+ return ldb_dn_compare(ldb, (*el1)->dn, (*el2)->dn);
}
static int do_search(struct ldb_context *ldb,
@@ -81,10 +82,9 @@ static int do_search(struct ldb_context *ldb,
printf("# returned %d records\n", ret);
- ldbsearch_ldb = ldb;
if (sort_attribs) {
- qsort(result->msgs, ret, sizeof(struct ldb_message *),
- (comparison_fn_t)do_compare_msg);
+ ldb_qsort(result->msgs, ret, sizeof(struct ldb_message *),
+ ldb, (ldb_qsort_cmp_fn_t)do_compare_msg);
}
for (i = 0; i < result->count; i++) {
diff --git a/source4/lib/ldb/tools/ldbtest.c b/source4/lib/ldb/tools/ldbtest.c
index f79f5c6b4c..7abc1bfcef 100644
--- a/source4/lib/ldb/tools/ldbtest.c
+++ b/source4/lib/ldb/tools/ldbtest.c
@@ -35,6 +35,7 @@
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
#include "ldb/tools/cmdline.h"
#ifdef _SAMBA_BUILD_