summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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"
/*