summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2006-01-06 04:01:23 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:49:47 -0500
commitc908d0b2aa111659e57a73efb8c33c413965c846 (patch)
tree8446f4dbff222ced9466f70c8f0ef42d87f5cda6 /source4
parente011ab7e1d9d624b4fd926dc3f15df2ab5f756e6 (diff)
downloadsamba-c908d0b2aa111659e57a73efb8c33c413965c846.tar.gz
samba-c908d0b2aa111659e57a73efb8c33c413965c846.tar.bz2
samba-c908d0b2aa111659e57a73efb8c33c413965c846.zip
r12733: Merge ldap/ldb controls into main tree
There's still lot of work to do but the patch is stable enough to be pushed into the main samba4 tree. Simo. (This used to be commit 77125feaff252cab44d26593093a9c211c846ce8)
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/config.mk11
-rw-r--r--source4/dsdb/samdb/ldb_modules/extended_dn.c308
-rw-r--r--source4/dsdb/samdb/ldb_modules/objectguid.c4
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c7
-rw-r--r--source4/dsdb/samdb/ldb_modules/proxy.c5
-rw-r--r--source4/dsdb/samdb/ldb_modules/rootdse.c56
-rw-r--r--source4/dsdb/samdb/ldb_modules/samba3sam.c4
-rw-r--r--source4/dsdb/samdb/ldb_modules/samldb.c4
-rw-r--r--source4/ldap_server/ldap_backend.c14
-rw-r--r--source4/ldap_server/ldap_bind.c1
-rw-r--r--source4/ldap_server/ldap_server.h16
-rw-r--r--source4/ldap_server/ldap_simple_ldb.c77
-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
-rw-r--r--source4/libcli/cldap/cldap.c2
-rw-r--r--source4/libcli/ldap/config.mk3
-rw-r--r--source4/libcli/ldap/ldap.c39
-rw-r--r--source4/libcli/ldap/ldap.h7
-rw-r--r--source4/libcli/ldap/ldap_bind.c5
-rw-r--r--source4/libcli/ldap/ldap_client.c1
-rw-r--r--source4/libcli/ldap/ldap_controls.c470
-rw-r--r--source4/libcli/ldap/ldap_ildap.c14
-rw-r--r--source4/libcli/ldap/ldap_msg.c3
-rw-r--r--source4/libcli/ldap/ldap_ndr.c1
53 files changed, 1870 insertions, 100 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk
index a18d2c4359..7fc0522034 100644
--- a/source4/dsdb/samdb/ldb_modules/config.mk
+++ b/source4/dsdb/samdb/ldb_modules/config.mk
@@ -69,3 +69,14 @@ REQUIRED_SUBSYSTEMS = \
# End MODULE libldb_rootdse
################################################
+################################################
+# Start MODULE libldb_extended_dn
+[MODULE::libldb_extended_dn]
+SUBSYSTEM = LIBLDB
+OUTPUT_TYPE = MERGEDOBJ
+OBJ_FILES = \
+ extended_dn.o
+#
+# End MODULE libldb_extended_dn
+################################################
+
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn.c b/source4/dsdb/samdb/ldb_modules/extended_dn.c
new file mode 100644
index 0000000000..49af8604d5
--- /dev/null
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn.c
@@ -0,0 +1,308 @@
+/*
+ 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 extended dn control module
+ *
+ * Description: this module builds a special dn
+ *
+ * Author: Simo Sorce
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+#include "dsdb/samdb/samdb.h"
+
+#include <time.h>
+
+static BOOL is_attr_in_list(const char * const * attrs, const char *attr)
+{
+ int i;
+
+ for (i = 0; attrs[i]; i++) {
+ if (strcasecmp(attrs[i], attr) == 0)
+ return True;
+ }
+
+ return False;
+}
+
+static char **copy_attrs(void *mem_ctx, const char * const * attrs)
+{
+ char **new;
+ int i, num;
+
+ for (num = 0; attrs[num]; num++);
+
+ new = talloc_array(mem_ctx, char *, num + 1);
+ if (!new) return NULL;
+
+ for(i = 0; i < num; i++) {
+ new[i] = talloc_strdup(new, attrs[i]);
+ if (!new[i]) {
+ talloc_free(new);
+ return NULL;
+ }
+ }
+ new[i] = NULL;
+
+ return new;
+}
+
+static BOOL add_attrs(void *mem_ctx, char ***attrs, const char *attr)
+{
+ char **new;
+ int num;
+
+ for (num = 0; (*attrs)[num]; num++);
+
+ new = talloc_realloc(mem_ctx, *attrs, char *, num + 2);
+ if (!new) return False;
+
+ *attrs = new;
+
+ new[num] = talloc_strdup(new, attr);
+ if (!new[num]) return False;
+
+ new[num + 1] = NULL;
+
+ return True;
+}
+
+static BOOL inject_extended_dn(struct ldb_message *msg,
+ int type,
+ BOOL remove_guid,
+ BOOL remove_sid)
+{
+ const struct ldb_val *val;
+ struct GUID guid;
+ struct dom_sid *sid;
+ char *object_guid;
+ char *object_sid;
+ char *new_dn, *dn;
+
+ dn = ldb_dn_linearize(msg, msg->dn);
+ if (!dn)
+ return False;
+
+ /* retrieve object_guid */
+ guid = samdb_result_guid(msg, "objectGUID");
+ object_guid = GUID_string(msg, &guid);
+ if (!object_guid)
+ return False;
+
+ if (remove_guid)
+ ldb_msg_remove_attr(msg, "objectGUID");
+
+ /* retrieve object_sid */
+ object_sid = NULL;
+ sid = samdb_result_dom_sid(msg, msg, "objectSID");
+ if (sid) {
+ object_sid = dom_sid_string(msg, sid);
+ if (!object_sid)
+ return False;
+
+ if (remove_sid)
+ ldb_msg_remove_attr(msg, "objectSID");
+ }
+
+ /* TODO: handle type */
+ switch (type) {
+ case 0:
+ case 1:
+ if (object_sid) {
+ new_dn = talloc_asprintf(msg, "<GUID=%s>;<SID=%s>;%s",
+ object_guid, object_sid, dn);
+ } else {
+ new_dn = talloc_asprintf(msg, "<GUID=%s>;%s",
+ object_guid, dn);
+ }
+ break;
+ default:
+ return False;
+ }
+
+ if (!new_dn)
+ return False;
+
+ msg->dn = ldb_dn_explode_or_special(msg, new_dn);
+ if (!msg->dn)
+ return False;
+
+ val = ldb_msg_find_ldb_val(msg, "distinguishedName");
+ if (val) {
+ ldb_msg_remove_attr(msg, "distinguishedName");
+ if (ldb_msg_add_string(msg, "distinguishedName", new_dn))
+ return False;
+ }
+
+ return True;
+}
+
+/* search */
+static int extended_search(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_result *extended_result;
+ struct ldb_control *control;
+ struct ldb_control **saved_controls;
+ struct ldb_extended_dn_control *extended_ctrl;
+ int i, ret;
+ const char * const *saved_attrs = NULL;
+ char **new_attrs;
+ BOOL remove_guid = False;
+ BOOL remove_sid = False;
+
+ /* check if there's a paged request control */
+ control = get_control_from_list(req->controls, LDB_CONTROL_EXTENDED_DN_OID);
+ if (control == NULL) {
+ /* not found go on */
+ return ldb_next_request(module, req);
+ }
+
+ extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control);
+
+ /* save it locally and remove it from the list */
+ if (!save_controls(control, req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* check if attrs only is specified, in that case check wether we need to modify them */
+ if (req->op.search.attrs) {
+ if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
+ remove_guid = True;
+ }
+ if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
+ remove_sid = True;
+ }
+ if (remove_guid || remove_sid) {
+ new_attrs = copy_attrs(req, req->op.search.attrs);
+ if (!new_attrs)
+ return LDB_ERR_OPERATIONS_ERROR;
+
+ saved_attrs = req->op.search.attrs;
+
+ if (remove_guid) {
+ if (!add_attrs(req, &new_attrs, "objectGUID"))
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (remove_sid) {
+ if (!add_attrs(req, &new_attrs, "objectSID"))
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->op.search.attrs = (const char * const *)new_attrs;
+ }
+ }
+
+ ret = ldb_next_request(module, req);
+
+ /* put request back into original shape */
+ /* TODO: build a new req and don't touch the original one */
+
+ if (req->controls) talloc_free(req->controls);
+ req->controls = saved_controls;
+
+ if (saved_attrs) {
+ talloc_free(new_attrs);
+ req->op.search.attrs = saved_attrs;
+ }
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ extended_result = req->op.search.res;
+
+ for (i = 0; i < extended_result->count; i++) {
+ /* TODO: the following funtion updates only dn and
+ * distinguishedName. We still need to address other
+ * DN entries like objectCategory
+ */
+ if (!inject_extended_dn(extended_result->msgs[i],
+ extended_ctrl->type,
+ remove_guid, remove_sid)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int extended_request(struct ldb_module *module, struct ldb_request *req)
+{
+ switch (req->operation) {
+
+ case LDB_REQ_SEARCH:
+ return extended_search(module, req);
+
+ default:
+ return ldb_next_request(module, req);
+
+ }
+}
+
+static const struct ldb_module_ops extended_dn_ops = {
+ .name = "extended_dn",
+ .request = extended_request,
+};
+
+#ifdef HAVE_DLOPEN_DISABLED
+struct ldb_module *init_module(struct ldb_context *ldb, int stage, const char *options[])
+#else
+struct ldb_module *extended_dn_module_init(struct ldb_context *ldb, int stage, const char *options[])
+#endif
+{
+ 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_EXTENDED_DN_OID;
+ request.controls = NULL;
+
+ ret = ldb_request(ldb, &request);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "extended_dn: 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 = &extended_dn_ops;
+ ctx->private_data = NULL;
+
+ return ctx;
+}
diff --git a/source4/dsdb/samdb/ldb_modules/objectguid.c b/source4/dsdb/samdb/ldb_modules/objectguid.c
index c9063af6ef..935f92c55b 100644
--- a/source4/dsdb/samdb/ldb_modules/objectguid.c
+++ b/source4/dsdb/samdb/ldb_modules/objectguid.c
@@ -128,10 +128,12 @@ static const struct ldb_module_ops objectguid_ops = {
/* the init function */
-struct ldb_module *objectguid_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *objectguid_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/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index e0fc50f242..82e4639a23 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -147,6 +147,7 @@ static int password_hash_handle(struct ldb_module *module, struct ldb_request *r
search_request->op.search.scope = LDB_SCOPE_BASE;
search_request->op.search.tree = ldb_parse_tree(module->ldb, NULL);
search_request->op.search.attrs = old_user_attrs;
+ search_request->controls = NULL;
old_ret = ldb_next_request(module, search_request);
}
@@ -253,6 +254,7 @@ static int password_hash_handle(struct ldb_module *module, struct ldb_request *r
search_request->op.search.scope = LDB_SCOPE_BASE;
search_request->op.search.tree = ldb_parse_tree(module->ldb, NULL);
search_request->op.search.attrs = user_attrs;
+ search_request->controls = NULL;
ret = ldb_next_request(module, search_request);
if (ret) {
@@ -656,6 +658,7 @@ static int password_hash_handle(struct ldb_module *module, struct ldb_request *r
modify_request->operation = LDB_REQ_MODIFY;
modify_request->op.mod.message = modify_msg;
+ modify_request->controls = NULL;
ret = ldb_next_request(module, modify_request);
@@ -714,10 +717,12 @@ static const struct ldb_module_ops password_hash_ops = {
/* the init function */
-struct ldb_module *password_hash_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *password_hash_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/dsdb/samdb/ldb_modules/proxy.c b/source4/dsdb/samdb/ldb_modules/proxy.c
index cbe404fc4b..540f4241b9 100644
--- a/source4/dsdb/samdb/ldb_modules/proxy.c
+++ b/source4/dsdb/samdb/ldb_modules/proxy.c
@@ -288,6 +288,7 @@ static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *re
newreq.op.search.scope = req->op.search.scope;
newreq.op.search.attrs = req->op.search.attrs;
newreq.op.search.res = req->op.search.res;
+ newreq.controls = req->controls;
ret = ldb_request(proxy->upstream, &newreq);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(module, talloc_strdup(module, ldb_errstring(proxy->upstream)));
@@ -332,10 +333,12 @@ static const struct ldb_module_ops proxy_ops = {
.request = proxy_request
};
-struct ldb_module *proxy_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *proxy_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/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c
index 93bc9903ed..8e0c231301 100644
--- a/source4/dsdb/samdb/ldb_modules/rootdse.c
+++ b/source4/dsdb/samdb/ldb_modules/rootdse.c
@@ -4,6 +4,7 @@
rootDSE ldb module
Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Simo Sorce 2005
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
@@ -27,6 +28,11 @@
#include "auth/gensec/gensec.h"
#include <time.h>
+struct private_data {
+ int num_controls;
+ char **controls;
+};
+
/*
return 1 if a specific attribute has been requested
*/
@@ -42,6 +48,7 @@ static int do_attribute(const char * const *attrs, const char *name)
*/
static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_request *req)
{
+ struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
struct ldb_search *s = &req->op.search;
struct ldb_message *msg;
struct cli_credentials *server_creds;
@@ -63,6 +70,16 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_request *re
}
}
+ if (do_attribute(s->attrs, "supportedControl")) {
+ int i;
+ for (i = 0; i < priv->num_controls; i++) {
+ if (ldb_msg_add_string(msg, "supportedControl",
+ priv->controls[i]) != 0) {
+ goto failed;
+ }
+ }
+ }
+
server_creds = talloc_get_type(ldb_get_opaque(module->ldb, "server_credentials"),
struct cli_credentials);
if (do_attribute(s->attrs, "supportedSASLMechanisms")) {
@@ -130,12 +147,35 @@ static int rootdse_search_bytree(struct ldb_module *module, struct ldb_request *
return ret;
}
+static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
+{
+ struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
+ char **list;
+
+ list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
+ if (!list) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ list[priv->num_controls] = talloc_strdup(list, req->op.reg.oid);
+ if (!list[priv->num_controls]) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ priv->num_controls += 1;
+ priv->controls = list;
+
+ return LDB_SUCCESS;
+}
+
static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
{
switch (req->operation) {
case LDB_REQ_SEARCH:
return rootdse_search_bytree(module, req);
+ case LDB_REQ_REGISTER:
+ return rootdse_register_control(module, req);
default:
break;
}
@@ -147,18 +187,30 @@ static const struct ldb_module_ops rootdse_ops = {
.request = rootdse_request
};
-struct ldb_module *rootdse_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *rootdse_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_1) 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->num_controls = 0;
+ data->controls = NULL;
+ ctx->private_data = data;
+
ctx->ldb = ldb;
ctx->prev = ctx->next = NULL;
ctx->ops = &rootdse_ops;
- ctx->private_data = NULL;
return ctx;
}
diff --git a/source4/dsdb/samdb/ldb_modules/samba3sam.c b/source4/dsdb/samdb/ldb_modules/samba3sam.c
index 429710c2c5..035321a90b 100644
--- a/source4/dsdb/samdb/ldb_modules/samba3sam.c
+++ b/source4/dsdb/samdb/ldb_modules/samba3sam.c
@@ -878,7 +878,9 @@ const struct ldb_map_attribute samba3_attributes[] =
};
/* the init function */
-struct ldb_module *ldb_samba3sam_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *ldb_samba3sam_module_init(struct ldb_context *ldb, int stage, const char *options[])
{
+ if (stage != LDB_MODULES_INIT_STAGE_1) return NULL;
+
return ldb_map_init(ldb, samba3_attributes, samba3_objectclasses, "samba3sam");
}
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index 7bf25994e2..82c2d4d0cc 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -583,10 +583,12 @@ static const struct ldb_module_ops samldb_ops = {
/* the init function */
-struct ldb_module *samldb_module_init(struct ldb_context *ldb, const char *options[])
+struct ldb_module *samldb_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/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
index 637ce7bd63..1e6d05a9bd 100644
--- a/source4/ldap_server/ldap_backend.c
+++ b/source4/ldap_server/ldap_backend.c
@@ -21,6 +21,7 @@
#include "includes.h"
#include "ldap_server/ldap_server.h"
#include "dlinklist.h"
+#include "libcli/ldap/ldap.h"
struct ldapsrv_reply *ldapsrv_init_reply(struct ldapsrv_call *call, uint8_t type)
@@ -39,6 +40,7 @@ struct ldapsrv_reply *ldapsrv_init_reply(struct ldapsrv_call *call, uint8_t type
reply->msg->messageid = call->request->messageid;
reply->msg->type = type;
+ reply->msg->controls = NULL;
return reply;
}
@@ -108,7 +110,7 @@ static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call)
return NT_STATUS_OK;
}
- return part->ops->Search(part, call, req);
+ return part->ops->Search(part, call);
}
static NTSTATUS ldapsrv_ModifyRequest(struct ldapsrv_call *call)
@@ -125,7 +127,7 @@ static NTSTATUS ldapsrv_ModifyRequest(struct ldapsrv_call *call)
return ldapsrv_unwilling(call, 53);
}
- return part->ops->Modify(part, call, req);
+ return part->ops->Modify(part, call);
}
static NTSTATUS ldapsrv_AddRequest(struct ldapsrv_call *call)
@@ -142,7 +144,7 @@ static NTSTATUS ldapsrv_AddRequest(struct ldapsrv_call *call)
return ldapsrv_unwilling(call, 53);
}
- return part->ops->Add(part, call, req);
+ return part->ops->Add(part, call);
}
static NTSTATUS ldapsrv_DelRequest(struct ldapsrv_call *call)
@@ -159,7 +161,7 @@ static NTSTATUS ldapsrv_DelRequest(struct ldapsrv_call *call)
return ldapsrv_unwilling(call, 53);
}
- return part->ops->Del(part, call, req);
+ return part->ops->Del(part, call);
}
static NTSTATUS ldapsrv_ModifyDNRequest(struct ldapsrv_call *call)
@@ -177,7 +179,7 @@ static NTSTATUS ldapsrv_ModifyDNRequest(struct ldapsrv_call *call)
return ldapsrv_unwilling(call, 53);
}
- return part->ops->ModifyDN(part, call, req);
+ return part->ops->ModifyDN(part, call);
}
static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call)
@@ -194,7 +196,7 @@ static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call)
return ldapsrv_unwilling(call, 53);
}
- return part->ops->Compare(part, call, req);
+ return part->ops->Compare(part, call);
}
static NTSTATUS ldapsrv_AbandonRequest(struct ldapsrv_call *call)
diff --git a/source4/ldap_server/ldap_bind.c b/source4/ldap_server/ldap_bind.c
index feb36135a8..4a0ee0044d 100644
--- a/source4/ldap_server/ldap_bind.c
+++ b/source4/ldap_server/ldap_bind.c
@@ -21,6 +21,7 @@
#include "includes.h"
#include "ldap_server/ldap_server.h"
#include "auth/auth.h"
+#include "libcli/ldap/ldap.h"
#include "smbd/service_stream.h"
#include "dsdb/samdb/samdb.h"
diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h
index d25f52bf4e..267b6fb9a7 100644
--- a/source4/ldap_server/ldap_server.h
+++ b/source4/ldap_server/ldap_server.h
@@ -53,14 +53,14 @@ struct ldapsrv_partition_ops {
const char *name;
NTSTATUS (*Init)(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn);
NTSTATUS (*Bind)(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn);
- NTSTATUS (*Search)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_SearchRequest *r);
- NTSTATUS (*Modify)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ModifyRequest *r);
- NTSTATUS (*Add)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_AddRequest *r);
- NTSTATUS (*Del)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_DelRequest *r);
- NTSTATUS (*ModifyDN)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ModifyDNRequest *r);
- NTSTATUS (*Compare)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_CompareRequest *r);
- NTSTATUS (*Abandon)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_AbandonRequest *r);
- NTSTATUS (*Extended)(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ExtendedRequest *r);
+ NTSTATUS (*Search)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*Modify)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*Add)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*Del)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*ModifyDN)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*Compare)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*Abandon)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
+ NTSTATUS (*Extended)(struct ldapsrv_partition *partition, struct ldapsrv_call *call);
};
struct ldapsrv_partition {
diff --git a/source4/ldap_server/ldap_simple_ldb.c b/source4/ldap_server/ldap_simple_ldb.c
index 0421bb42ab..fd89a19737 100644
--- a/source4/ldap_server/ldap_simple_ldb.c
+++ b/source4/ldap_server/ldap_simple_ldb.c
@@ -21,6 +21,7 @@
#include "includes.h"
#include "ldap_server/ldap_server.h"
+#include "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_errors.h"
#include "dsdb/samdb/samdb.h"
@@ -49,6 +50,41 @@ static int sldb_map_error(struct ldapsrv_partition *partition, int ldb_ret,
return ldb_ret;
}
+static int sldb_get_ldb_controls(void *mem_ctx, struct ldap_Control **controls, struct ldb_control ***lcontrols)
+{
+ struct ldb_control **lctrl;
+ int i, l;
+
+ if (controls == NULL || controls[0] == NULL) {
+ *lcontrols = NULL;
+ return LDB_SUCCESS;
+ }
+
+ l = 0;
+ lctrl = NULL;
+ *lcontrols = NULL;
+
+ for (i = 0; controls[i] != NULL; i++) {
+ lctrl = talloc_realloc(mem_ctx, lctrl, struct ldb_control *, l + 2);
+ if (lctrl == NULL) {
+ return LDB_ERR_OTHER;
+ }
+ lctrl[l] = talloc(lctrl, struct ldb_control);
+ if (lctrl[l] == NULL) {
+ return LDB_ERR_OTHER;
+ }
+ lctrl[l]->oid = controls[i]->oid;
+ lctrl[l]->critical = controls[i]->critical;
+ lctrl[l]->data = controls[i]->value;
+ l++;
+ }
+ lctrl[l] = NULL;
+
+ *lcontrols = lctrl;
+
+ return LDB_SUCCESS;
+}
+
/*
connect to the sam database
*/
@@ -86,9 +122,9 @@ NTSTATUS sldb_Bind(struct ldapsrv_partition *partition, struct ldapsrv_connectio
return status;
}
-static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
- struct ldap_SearchRequest *r)
+static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call)
{
+ struct ldap_SearchRequest *r = &call->request->r.SearchRequest;
void *local_ctx;
struct ldb_dn *basedn;
struct ldap_Result *done;
@@ -153,6 +189,14 @@ static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_
lreq.op.search.scope = scope;
lreq.op.search.tree = r->tree;
lreq.op.search.attrs = attrs;
+ ret = sldb_get_ldb_controls(local_ctx, call->request->controls, &lreq.controls);
+
+ if (ret != LDB_SUCCESS) {
+ /* get_ldb_controls fails only on a critical internal error or when
+ * a control is defined as critical but it is not supported
+ */
+ goto reply;
+ }
ret = ldb_request(samdb, &lreq);
@@ -199,6 +243,10 @@ reply:
done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
NT_STATUS_HAVE_NO_MEMORY(done_r);
+ done = &done_r->msg->r.SearchResultDone;
+ done->dn = NULL;
+ done->referral = NULL;
+
if (ret == LDB_SUCCESS) {
if (res->count >= success_limit) {
DEBUG(10,("sldb_Search: results: [%d]\n", res->count));
@@ -209,17 +257,17 @@ reply:
result = LDAP_NO_SUCH_OBJECT;
errstr = ldb_errstring(samdb);
}
+ if (res->controls) {
+ done_r->msg->controls = (struct ldap_Control **)(res->controls);
+ }
} else {
DEBUG(10,("sldb_Search: error\n"));
result = ret;
errstr = ldb_errstring(samdb);
}
- done = &done_r->msg->r.SearchResultDone;
- done->dn = NULL;
done->resultcode = result;
done->errormessage = (errstr?talloc_strdup(done_r, errstr):NULL);
- done->referral = NULL;
talloc_free(local_ctx);
@@ -227,9 +275,9 @@ reply:
return NT_STATUS_OK;
}
-static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
- struct ldap_AddRequest *r)
+static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call)
{
+ struct ldap_AddRequest *r = &call->request->r.AddRequest;
void *local_ctx;
struct ldb_dn *dn;
struct ldap_Result *add_result;
@@ -317,9 +365,9 @@ reply:
return NT_STATUS_OK;
}
-static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
- struct ldap_DelRequest *r)
+static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call)
{
+ struct ldap_DelRequest *r = &call->request->r.DelRequest;
void *local_ctx;
struct ldb_dn *dn;
struct ldap_Result *del_result;
@@ -360,9 +408,9 @@ reply:
return NT_STATUS_OK;
}
-static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
- struct ldap_ModifyRequest *r)
+static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call)
{
+ struct ldap_ModifyRequest *r = &call->request->r.ModifyRequest;
void *local_ctx;
struct ldb_dn *dn;
struct ldap_Result *modify_result;
@@ -461,9 +509,9 @@ reply:
return NT_STATUS_OK;
}
-static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
- struct ldap_CompareRequest *r)
+static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call)
{
+ struct ldap_CompareRequest *r = &call->request->r.CompareRequest;
void *local_ctx;
struct ldb_dn *dn;
struct ldap_Result *compare;
@@ -531,8 +579,9 @@ reply:
return NT_STATUS_OK;
}
-static NTSTATUS sldb_ModifyDN(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ModifyDNRequest *r)
+static NTSTATUS sldb_ModifyDN(struct ldapsrv_partition *partition, struct ldapsrv_call *call)
{
+ struct ldap_ModifyDNRequest *r = &call->request->r.ModifyDNRequest;
void *local_ctx;
struct ldb_dn *olddn, *newdn, *newrdn;
struct ldb_dn *parentdn = NULL;
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_
diff --git a/source4/libcli/cldap/cldap.c b/source4/libcli/cldap/cldap.c
index d406b50baf..a6710cf32c 100644
--- a/source4/libcli/cldap/cldap.c
+++ b/source4/libcli/cldap/cldap.c
@@ -319,7 +319,6 @@ struct cldap_request *cldap_search_send(struct cldap_socket *cldap,
if (msg == NULL) goto failed;
msg->messageid = req->message_id;
msg->type = LDAP_TAG_SearchRequest;
- msg->num_controls = 0;
msg->controls = NULL;
search = &msg->r.SearchRequest;
@@ -380,7 +379,6 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
msg = talloc(req, struct ldap_message);
if (msg == NULL) goto failed;
msg->messageid = io->messageid;
- msg->num_controls = 0;
msg->controls = NULL;
if (io->response) {
diff --git a/source4/libcli/ldap/config.mk b/source4/libcli/ldap/config.mk
index 912cb133bf..59d2d1ea30 100644
--- a/source4/libcli/ldap/config.mk
+++ b/source4/libcli/ldap/config.mk
@@ -7,7 +7,8 @@ OBJ_FILES = ldap.o \
ldap_bind.o \
ldap_msg.o \
ldap_ndr.o \
- ldap_ildap.o
+ ldap_ildap.o \
+ ldap_controls.o
REQUIRED_SUBSYSTEMS = LIBCLI_UTILS LIBEVENTS GENSEC SOCKET NDR_SAMR LIBTLS \
LIBPACKET
# End SUBSYSTEM LIBCLI_LDAP
diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c
index c699820cea..d021fc3bd6 100644
--- a/source4/libcli/ldap/ldap.c
+++ b/source4/libcli/ldap/ldap.c
@@ -455,6 +455,18 @@ BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ct
return False;
}
+ if (msg->controls != NULL) {
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+
+ for (i = 0; msg->controls[i] != NULL; i++) {
+ if (!ldap_encode_control(mem_ctx, &data, msg->controls[i])) {
+ return False;
+ }
+ }
+
+ asn1_pop_tag(&data);
+ }
+
asn1_pop_tag(&data);
if (data.has_error) {
@@ -1243,42 +1255,35 @@ BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
return False;
}
- msg->num_controls = 0;
msg->controls = NULL;
if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
int i;
- struct ldap_Control *ctrl = NULL;
+ struct ldap_Control **ctrl = NULL;
asn1_start_tag(data, ASN1_CONTEXT(0));
for (i=0; asn1_peek_tag(data, ASN1_SEQUENCE(0)); i++) {
asn1_start_tag(data, ASN1_SEQUENCE(0));
- ctrl = talloc_realloc(msg, ctrl, struct ldap_Control, i+1);
+ ctrl = talloc_realloc(msg, ctrl, struct ldap_Control *, i+2);
if (!ctrl) {
return False;
}
- ctrl[i].oid = NULL;
- ctrl[i].critical = False;
- ctrl[i].value = data_blob(NULL, 0);
- asn1_read_OctetString_talloc(ctrl, data, &ctrl[i].oid);
-
- if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
- asn1_read_BOOLEAN(data, &ctrl[i].critical);
+ ctrl[i] = talloc(ctrl, struct ldap_Control);
+ if (!ctrl[i]) {
+ return False;
}
- if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
- asn1_read_OctetString(data, &ctrl[i].value);
- if (ctrl[i].value.data) {
- talloc_steal(msg, ctrl[i].value.data);
- }
+ if (!ldap_decode_control(ctrl, data, ctrl[i])) {
+ return False;
}
- asn1_end_tag(data);
}
- msg->num_controls = i;
+
+ ctrl[i] = NULL;
+
msg->controls = ctrl;
asn1_end_tag(data);
diff --git a/source4/libcli/ldap/ldap.h b/source4/libcli/ldap/ldap.h
index b6e69ff8e6..5283553f13 100644
--- a/source4/libcli/ldap/ldap.h
+++ b/source4/libcli/ldap/ldap.h
@@ -243,15 +243,14 @@ union ldap_Request {
struct ldap_Control {
const char *oid;
BOOL critical;
- DATA_BLOB value;
+ void *value;
};
struct ldap_message {
- uint32_t messageid;
+ int messageid;
enum ldap_request_tag type;
union ldap_Request r;
- int num_controls;
- struct ldap_Control *controls;
+ struct ldap_Control **controls;
};
#include "libcli/ldap/ldap_proto.h"
diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c
index 6b1c321d49..1f6ef77631 100644
--- a/source4/libcli/ldap/ldap_bind.c
+++ b/source4/libcli/ldap/ldap_bind.c
@@ -23,6 +23,7 @@
*/
#include "includes.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
#include "auth/auth.h"
@@ -41,6 +42,7 @@ static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *con
res->r.BindRequest.dn = talloc_strdup(res, dn);
res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
res->r.BindRequest.creds.password = talloc_strdup(res, pw);
+ res->controls = NULL;
return res;
}
@@ -128,6 +130,7 @@ static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn,
res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
res->r.BindRequest.creds.SASL.secblob = *secblob;
+ res->controls = NULL;
return res;
}
@@ -186,7 +189,7 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr
}
status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
- False, &sasl_mechs_msgs);
+ False, NULL, NULL, &sasl_mechs_msgs);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n",
nt_errstr(status)));
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 9b1a4ef9d5..9103e939e7 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -28,6 +28,7 @@
#include "dlinklist.h"
#include "lib/events/events.h"
#include "lib/socket/socket.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
#include "libcli/composite/composite.h"
#include "lib/stream/packet.h"
diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
new file mode 100644
index 0000000000..55e7a94aa7
--- /dev/null
+++ b/source4/libcli/ldap/ldap_controls.c
@@ -0,0 +1,470 @@
+/*
+ Unix SMB/CIFS mplementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Simo Sorce 2005
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "system/iconv.h"
+#include "libcli/util/asn_1.h"
+#include "libcli/ldap/ldap.h"
+#include "lib/ldb/include/ldb.h"
+
+struct control_handler {
+ const char *oid;
+ BOOL (*decode)(void *mem_ctx, DATA_BLOB in, void **out);
+ BOOL (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
+};
+
+static BOOL decode_server_sort_response(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ DATA_BLOB attr;
+ struct asn1_data data;
+ struct ldb_sort_resp_control *lsrc;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ lsrc = talloc(mem_ctx, struct ldb_sort_resp_control);
+ if (!lsrc) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_enumerated(&data, &(lsrc->result))) {
+ return False;
+ }
+
+ lsrc->attr_desc = NULL;
+ if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
+ if (!asn1_read_OctetString(&data, &attr)) {
+ return False;
+ }
+ lsrc->attr_desc = talloc_strndup(lsrc, attr.data, attr.length);
+ if (!lsrc->attr_desc) {
+ return False;
+ }
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = lsrc;
+
+ return True;
+}
+
+static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ DATA_BLOB attr;
+ DATA_BLOB rule;
+ struct asn1_data data;
+ struct ldb_server_sort_control **lssc;
+ int num;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ lssc = NULL;
+
+ for (num = 0; asn1_peek_tag(&data, ASN1_SEQUENCE(0)); num++) {
+ lssc = talloc_realloc(mem_ctx, lssc, struct ldb_server_sort_control *, num + 2);
+ if (!lssc) {
+ return False;
+ }
+ lssc[num] = talloc(lssc, struct ldb_server_sort_control);
+ if (!lssc[num]) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_OctetString(&data, &attr)) {
+ return False;
+ }
+
+ lssc[num]->attributeName = talloc_strndup(lssc[num], attr.data, attr.length);
+ if (!lssc [num]->attributeName) {
+ return False;
+ }
+
+ if (asn1_peek_tag(&data, ASN1_OCTET_STRING)) {
+ if (!asn1_read_OctetString(&data, &rule)) {
+ return False;
+ }
+ lssc[num]->orderingRule = talloc_strndup(lssc[num], rule.data, rule.length);
+ if (!lssc[num]->orderingRule) {
+ return False;
+ }
+ }
+
+ if (asn1_peek_tag(&data, ASN1_BOOLEAN)) {
+ if (!asn1_read_BOOLEAN(&data, &(lssc[num]->reverse))) {
+ return False;
+ }
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+ }
+
+ lssc[num] = NULL;
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = lssc;
+
+ return True;
+}
+
+static BOOL decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ struct asn1_data data;
+ struct ldb_extended_dn_control *ledc;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ ledc = talloc(mem_ctx, struct ldb_extended_dn_control);
+ if (!ledc) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_Integer(&data, &(ledc->type))) {
+ return False;
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = ledc;
+
+ return True;
+}
+
+static BOOL decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void **out)
+{
+ DATA_BLOB cookie;
+ struct asn1_data data;
+ struct ldb_paged_control *lprc;
+
+ if (!asn1_load(&data, in)) {
+ return False;
+ }
+
+ lprc = talloc(mem_ctx, struct ldb_paged_control);
+ if (!lprc) {
+ return False;
+ }
+
+ if (!asn1_start_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_Integer(&data, &(lprc->size))) {
+ return False;
+ }
+
+ if (!asn1_read_OctetString(&data, &cookie)) {
+ return False;
+ }
+ lprc->cookie_len = cookie.length;
+ if (lprc->cookie_len) {
+ lprc->cookie = talloc_memdup(lprc, cookie.data, cookie.length);
+
+ if (!(lprc->cookie)) {
+ return False;
+ }
+ } else {
+ lprc->cookie = NULL;
+ }
+
+ if (!asn1_end_tag(&data)) {
+ return False;
+ }
+
+ *out = lprc;
+
+ return True;
+}
+
+static BOOL encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
+ struct asn1_data data;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_enumerated(&data, lsrc->result)) {
+ return False;
+ }
+
+ if (lsrc->attr_desc) {
+ if (!asn1_write_OctetString(&data, lsrc->attr_desc, strlen(lsrc->attr_desc))) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
+ struct asn1_data data;
+ int num;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ for (num = 0; lssc[num]; num++) {
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_OctetString(&data, lssc[num]->attributeName, strlen(lssc[num]->attributeName))) {
+ return False;
+ }
+
+ if (lssc[num]->orderingRule) {
+ if (!asn1_write_OctetString(&data, lssc[num]->orderingRule, strlen(lssc[num]->orderingRule))) {
+ return False;
+ }
+ }
+
+ if (lssc[num]->reverse) {
+ if (!asn1_write_BOOLEAN(&data, lssc[num]->reverse)) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_extended_dn_control *ledc = talloc_get_type(in, struct ldb_extended_dn_control);
+ struct asn1_data data;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_Integer(&data, ledc->type)) {
+ return False;
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+static BOOL encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+ struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
+ struct asn1_data data;
+
+ ZERO_STRUCT(data);
+
+ if (!asn1_push_tag(&data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_Integer(&data, lprc->size)) {
+ return False;
+ }
+
+ if (!asn1_write_OctetString(&data, lprc->cookie, lprc->cookie_len)) {
+ return False;
+ }
+
+ if (!asn1_pop_tag(&data)) {
+ return False;
+ }
+
+ *out = data_blob_talloc(mem_ctx, data.data, data.length);
+ if (out->data == NULL) {
+ return False;
+ }
+
+ return True;
+}
+
+struct control_handler ldap_known_controls[] = {
+ { "1.2.840.113556.1.4.319", decode_paged_results_request, encode_paged_results_request },
+ { "1.2.840.113556.1.4.529", decode_extended_dn_request, encode_extended_dn_request },
+ { "1.2.840.113556.1.4.473", decode_server_sort_request, encode_server_sort_request },
+ { "1.2.840.113556.1.4.474", decode_server_sort_response, encode_server_sort_response },
+ { NULL, NULL, NULL }
+};
+
+BOOL ldap_decode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
+{
+ int i;
+ DATA_BLOB oid;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_read_OctetString(data, &oid)) {
+ return False;
+ }
+ ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
+ if (!(ctrl->oid)) {
+ return False;
+ }
+
+ if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
+ if (!asn1_read_BOOLEAN(data, &(ctrl->critical))) {
+ return False;
+ }
+ } else {
+ ctrl->critical = False;
+ }
+
+ ctrl->value = NULL;
+
+ for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
+ if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
+
+ if (!asn1_read_OctetString(data, &value)) {
+ return False;
+ }
+ if (!ldap_known_controls[i].decode(mem_ctx, value, &(ctrl->value))) {
+ return False;
+ }
+ break;
+ }
+ }
+ if (ldap_known_controls[i].oid == NULL) {
+ return False;
+ }
+
+ if (!asn1_end_tag(data)) {
+ return False;
+ }
+
+ return True;
+}
+
+BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldap_Control *ctrl)
+{
+ DATA_BLOB value;
+ int i;
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+ return False;
+ }
+
+ if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
+ return False;
+ }
+
+ if (ctrl->critical) {
+ if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
+ return False;
+ }
+ }
+
+ for (i = 0; ldap_known_controls[i].oid != NULL; i++) {
+ if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
+ if (!ldap_known_controls[i].encode(mem_ctx, ctrl->value, &value)) {
+ return False;
+ }
+ break;
+ }
+ }
+ if (ldap_known_controls[i].oid == NULL) {
+ return False;
+ }
+
+ if (value.length != 0) {
+ if (!asn1_write_OctetString(data, value.data, value.length)) {
+ return False;
+ }
+ }
+
+ if (!asn1_pop_tag(data)) {
+ return False;
+ }
+
+ return True;
+}
diff --git a/source4/libcli/ldap/ldap_ildap.c b/source4/libcli/ldap/ldap_ildap.c
index f29685a67c..a5227ec37f 100644
--- a/source4/libcli/ldap/ldap_ildap.c
+++ b/source4/libcli/ldap/ldap_ildap.c
@@ -22,6 +22,7 @@
*/
#include "includes.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
/*
@@ -156,6 +157,8 @@ int ildap_count_entries(struct ldap_connection *conn, struct ldap_message **res)
NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
int scope, struct ldb_parse_tree *tree,
const char * const *attrs, BOOL attributesonly,
+ struct ldap_Control **control_req,
+ struct ldap_Control ***control_res,
struct ldap_message ***results)
{
struct ldap_message *msg;
@@ -163,6 +166,8 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
NTSTATUS status;
struct ldap_request *req;
+ if (control_res)
+ *control_res = NULL;
*results = NULL;
msg = new_ldap_message(conn);
@@ -180,6 +185,7 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
msg->r.SearchRequest.tree = tree;
msg->r.SearchRequest.num_attributes = n;
msg->r.SearchRequest.attributes = discard_const(attrs);
+ msg->controls = control_req;
req = ldap_request_send(conn, msg);
talloc_steal(msg, req);
@@ -191,6 +197,9 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
if (res->type == LDAP_TAG_SearchResultDone) {
status = ldap_check_response(conn, &res->r.GeneralResult);
+ if (control_res) {
+ *control_res = talloc_steal(conn, res->controls);
+ }
break;
}
@@ -219,12 +228,15 @@ NTSTATUS ildap_search_bytree(struct ldap_connection *conn, const char *basedn,
NTSTATUS ildap_search(struct ldap_connection *conn, const char *basedn,
int scope, const char *expression,
const char * const *attrs, BOOL attributesonly,
+ struct ldap_Control **control_req,
+ struct ldap_Control ***control_res,
struct ldap_message ***results)
{
struct ldb_parse_tree *tree = ldb_parse_tree(conn, expression);
NTSTATUS status;
status = ildap_search_bytree(conn, basedn, scope, tree, attrs,
- attributesonly, results);
+ attributesonly, control_req,
+ control_res, results);
talloc_free(tree);
return status;
}
diff --git a/source4/libcli/ldap/ldap_msg.c b/source4/libcli/ldap/ldap_msg.c
index c77d9eb356..d74aa500ca 100644
--- a/source4/libcli/ldap/ldap_msg.c
+++ b/source4/libcli/ldap/ldap_msg.c
@@ -23,12 +23,13 @@
*/
#include "includes.h"
+#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
{
- return talloc(mem_ctx, struct ldap_message);
+ return talloc_zero(mem_ctx, struct ldap_message);
}
diff --git a/source4/libcli/ldap/ldap_ndr.c b/source4/libcli/ldap/ldap_ndr.c
index 1d5e4ccf20..0cccdbe971 100644
--- a/source4/libcli/ldap/ldap_ndr.c
+++ b/source4/libcli/ldap/ldap_ndr.c
@@ -23,6 +23,7 @@
#include "includes.h"
#include "libcli/ldap/ldap.h"
+#include "librpc/gen_ndr/ndr_security.h"
#include "librpc/gen_ndr/ndr_misc.h"
/*