r12733: Merge ldap/ldb controls into main tree
authorSimo Sorce <idra@samba.org>
Fri, 6 Jan 2006 04:01:23 +0000 (04:01 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:49:47 +0000 (13:49 -0500)
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)

53 files changed:
source4/dsdb/samdb/ldb_modules/config.mk
source4/dsdb/samdb/ldb_modules/extended_dn.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/objectguid.c
source4/dsdb/samdb/ldb_modules/password_hash.c
source4/dsdb/samdb/ldb_modules/proxy.c
source4/dsdb/samdb/ldb_modules/rootdse.c
source4/dsdb/samdb/ldb_modules/samba3sam.c
source4/dsdb/samdb/ldb_modules/samldb.c
source4/ldap_server/ldap_backend.c
source4/ldap_server/ldap_bind.c
source4/ldap_server/ldap_server.h
source4/ldap_server/ldap_simple_ldb.c
source4/lib/ldb/Makefile.in
source4/lib/ldb/common/ldb.c
source4/lib/ldb/common/ldb_controls.c [new file with mode: 0644]
source4/lib/ldb/common/ldb_dn.c
source4/lib/ldb/common/ldb_modules.c
source4/lib/ldb/config.mk
source4/lib/ldb/include/ldb.h
source4/lib/ldb/include/ldb_errors.h
source4/lib/ldb/include/ldb_private.h
source4/lib/ldb/ldb_ildap/ldb_ildap.c
source4/lib/ldb/ldb_ldap/ldb_ldap.c
source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
source4/lib/ldb/ldb_tdb/ldb_index.c
source4/lib/ldb/ldb_tdb/ldb_search.c
source4/lib/ldb/ldb_tdb/ldb_tdb.c
source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c
source4/lib/ldb/modules/objectclass.c
source4/lib/ldb/modules/operational.c
source4/lib/ldb/modules/paged_results.c [new file with mode: 0644]
source4/lib/ldb/modules/rdn_name.c
source4/lib/ldb/modules/schema.c
source4/lib/ldb/modules/skel.c
source4/lib/ldb/modules/sort.c [new file with mode: 0644]
source4/lib/ldb/samba/ldif_handlers.c
source4/lib/ldb/tools/ldbadd.c
source4/lib/ldb/tools/ldbdel.c
source4/lib/ldb/tools/ldbedit.c
source4/lib/ldb/tools/ldbmodify.c
source4/lib/ldb/tools/ldbrename.c
source4/lib/ldb/tools/ldbsearch.c
source4/lib/ldb/tools/ldbtest.c
source4/libcli/cldap/cldap.c
source4/libcli/ldap/config.mk
source4/libcli/ldap/ldap.c
source4/libcli/ldap/ldap.h
source4/libcli/ldap/ldap_bind.c
source4/libcli/ldap/ldap_client.c
source4/libcli/ldap/ldap_controls.c [new file with mode: 0644]
source4/libcli/ldap/ldap_ildap.c
source4/libcli/ldap/ldap_msg.c
source4/libcli/ldap/ldap_ndr.c

index a18d2c435976e15787038585d81859f53fe370cb..7fc0522034ec71dcf5f28b03f69c9914c8ef1554 100644 (file)
@@ -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 (file)
index 0000000..49af860
--- /dev/null
@@ -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;
+}
index c9063af6ef950f5b2ed193be65d2990276d5a1b8..935f92c55bd009d5cd46e6f53a129e07cf07b0f8 100644 (file)
@@ -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;
index e0fc50f242d2d49cf637d7ef802c9397f5def610..82e4639a23a1700ece9af388f6fd195b7267d6c7 100644 (file)
@@ -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;
index cbe404fc4bc5acc9f124306d4393f6a5e9af9a6f..540f4241b9917f7c6c595b1ba0e902d0d86a232b 100644 (file)
@@ -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;
index 93bc9903ed76ba444ae50d30d14e09bf5c3af127..8e0c231301736324d0ac966317b9055c56d6e099 100644 (file)
@@ -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
 #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;
 }
index 429710c2c54fd721ae859c04eeea2f1562ea27e7..035321a90b5cc7353fabddce4450acdc6427872b 100644 (file)
@@ -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");
 }
index 7bf25994e28309174760af55cd7939ba42ebf743..82c2d4d0cc03679d6ad3f097bd07988525e7df7b 100644 (file)
@@ -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;
index 637ce7bd6380419f74776207a48ef0128ce14be1..1e6d05a9bdb76ead0fba418c0a164c9079b92c43 100644 (file)
@@ -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)
index feb36135a88cb598d8909f93a584f1ee4fe53ea6..4a0ee0044dd8b97eaa6741c3cb0ccf2060aeb231 100644 (file)
@@ -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"
 
index d25f52bf4e96f861aa4525d15a119228a896c6a6..267b6fb9a7e542694392d7bfb2dfdb62da3db5ce 100644 (file)
@@ -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 {
index 0421bb42abf6a46e3ee72770054f1dc2ad79a48f..fd89a19737304eb3859a117ad136c72d197ad6c7 100644 (file)
@@ -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;
index 5a6155edd061bc2070dbd5ec3ba6374d25fab95e..bde2388b820f042811608d22dbf41002b5e4f6a2 100644 (file)
@@ -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)
 
index 6095f4fc04ce2a7efea971a8f31857083b5012ad..604f02a1f75e77a863ce0b5eb3e5b11badca17e6 100644 (file)
@@ -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 (file)
index 0000000..e4c4c64
--- /dev/null
@@ -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;
+}
index 4ae00ee6dc505ba2451766361ce05d163995fe63..5ed54ae3161e3fca68a4367242e3d841e7687821 100644 (file)
@@ -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;
index 5c2e36d431c52659c0c830e6961be2158fca0c81..26a397dccc77dd61507f08a394ea2140d5fb1ba5 100644 (file)
@@ -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; 
 }
index 13280bac686af16de1d8f7b04f3cfa63107b974a..cbd91a6de65b02302d0363634430b26a85737629 100644 (file)
@@ -1,3 +1,23 @@
+################################################
+# 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]
@@ -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
index 9c3b03309182dcafd9633cc0457556632e639d5b..299a5d171e7ccc79618a5ff7881f526433a69411 100644 (file)
@@ -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_control*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
index f59b39f92ad94232fcb1405c24710223b5f8decb..a93d3cd388e4c8f87301e271530286dbf36c810d 100644 (file)
@@ -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
index d0aec6e1372be6ef55180e6cf77373f348680819..e8a4d1820a20b9109edae4598fd1630d935cfd28 100644 (file)
@@ -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
index 08024690792ab175aae76957a8b9c93f120c9cc8..ff00a61163a925801d9b99c1bbba7014ef584092 100644 (file)
@@ -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]);
        }
index 893ad0dd2a77456c3be9b891c9cad736742151b6..8207b5f592fc639cdf4ab1d433c750370b1d54e3 100644 (file)
@@ -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;
index 1d23478941c837a58b0cc6383c9a3595cf377ce0..464c8ce69fa5b1fcc58d02d8a31100ae734d8156 100644 (file)
@@ -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);
index 75514fac83bc22de7a624323129eeb6108fab5e1..cf9ad3b7fea722dbe8b88a393d94c267ba01c15b 100644 (file)
@@ -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 */
index 01a87e00b19665be025cc896fc28844f233bac88..aa5cb407122be564e9a31074a6c0e65c5f21641b 100644 (file)
@@ -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;
index ebee029d9cf504b3c3ea90f3e31655b3325f7d8a..432c71333613fe527feb91b54bbad28076a61fa1 100644 (file)
@@ -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:
index c2e65cf82577be2fb2f39278e17ae050b8ee7dc3..3a18f5df88d2de0409190a5d920fde07d1651576 100644 (file)
@@ -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"
 
 /*
index 9891ed8eb1fd94176013437bc4d00334b4326823..7a037cc98aa0e4addae8adb15e3ce5523820200e 100644 (file)
@@ -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;
index 65d9f12e34a50ec4576e404739122507e6e1651f..09de0936a17c26a6bd90f15079bfe8485e527292 100644 (file)
@@ -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 (file)
index 0000000..31b73d2
--- /dev/null
@@ -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;
+}
index f35cff916c25aeb0fa995d64ec84fa094f2d8516..f6dbc387402ab7d40edd265f7c9a56a2bc3bd36b 100644 (file)
@@ -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;
index 9fb2efee30c7d96f093f26beac56ebf1c598aa6e..778f52885cc7d3e8eb1d0114542fbfcf4a52eb59 100644 (file)
@@ -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;
index 1bbb81f2881a8b0a10086d3cca18c11d94f25bc4..dacbd6960ede2f6d5c3ddcabcea8d42f0eba4a99 100644 (file)
@@ -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 (file)
index 0000000..2757647
--- /dev/null
@@ -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;
+}
index 51cb3f8d78f7719fceeb8af94e12becc411e5e03..84270195dc9a525ff87c55195b016a48476f803d 100644 (file)
@@ -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"
 
index c22cfde4ecea60b115857f34a0ecd9db35b44200..058f4dc751b0770b7db7e65a1946a90639caf591 100644 (file)
@@ -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_
index a6574a50885e8fbdbe8be775bbf61a08af11ff90..6da8d0269f904d9c9033e980670036c1fe7eff1f 100644 (file)
@@ -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_
index 8818777ceb201da3ddc9f7b1b95ccd18c0bc0d27..4d47cf27c9f23294cfe687d6b2cbef0e3ac44f69 100644 (file)
@@ -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_
index f067aef3f8cbef95e9db6cde3731bba153fed641..4c78e485b5e41b471076a5f076ac17eee5914ba2 100644 (file)
@@ -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_
index f225246cc78ea326cbea9033cf393aa59f3c9a29..4b3b27c130078fdd765c1809b48ef34e68da6db1 100644 (file)
@@ -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_
index c493356405aaf3d602bf60880b9a1d90cb1181a6..a340e16d08c835a5206660055d6815f3f8225443 100644 (file)
@@ -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++) {
index f79f5c6b4c968789a4c57c814e225e74e71d3e6e..7abc1bfcef1949fb1339826edbea1129fb2cb18c 100644 (file)
@@ -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_
index d406b50baf385039c26ede70761e132d2b16b56f..a6710cf32c47df18cb81d3088b0168ab950117e3 100644 (file)
@@ -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) {
index 912cb133bf0b6a23b8dde2ea1884d4c3e7987b36..59d2d1ea303767c53e717f752ee88d10e05cbd20 100644 (file)
@@ -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
index c699820cea33f117cc1a9460cac7363071091226..d021fc3bd61cd2fdeefce2ca4808f286f866c273 100644 (file)
@@ -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);
index b6e69ff8e6926a3c3661543cff13ef4280bc7eaf..5283553f13e3adacaa57f69f30b2517e5ae9adb2 100644 (file)
@@ -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"
index 6b1c321d49e95d4967494e54ced0c719b54efb0f..1f6ef77631fb954ad88ec88f34df4fe6ee294c80 100644 (file)
@@ -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)));
index 9b1a4ef9d5fa35351863ba29908eadea2582b0fa..9103e939e706d95b81b3e2f40f2856989d5f9991 100644 (file)
@@ -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 (file)
index 0000000..55e7a94
--- /dev/null
@@ -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;
+}
index f29685a67c63c58fb0310e00f0a9a9c32a3999ce..a5227ec37f58d812c1317617fff0b9a00dc81620 100644 (file)
@@ -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;
 }
index c77d9eb356e35ff4c32f8c4ebddca0874d07d157..d74aa500ca4d9128efb6307b97e8a865aef678ad 100644 (file)
 */
 
 #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);
 }
 
 
index 1d5e4ccf20203ecff07f570b0e0c24ea9e84a99c..0cccdbe9719ae5185a5e54be2084b3acc1307ff2 100644 (file)
@@ -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"
 
 /*