s4:dsdb: add support for DSDB_OPENLDAP_DEREFERENCE_CONTROL
[kai/samba.git] / source4 / libcli / ldap / ldap_controls.c
index 79c16afc9518a357905e04acc73b232df1ff36f8..109837c2bf2f155e675fc6dbca9739cdd3bf401a 100644 (file)
@@ -6,7 +6,7 @@
     
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
 */
 
 #include "includes.h"
-#include "libcli/util/asn_1.h"
+#include "../lib/util/asn1.h"
 #include "libcli/ldap/ldap.h"
 #include "lib/ldb/include/ldb.h"
+#include "libcli/ldap/ldap_proto.h"
+#include "dsdb/samdb/samdb.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);
+       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)
+static bool decode_server_sort_response(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB attr;
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_sort_resp_control *lsrc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lsrc = talloc(mem_ctx, struct ldb_sort_resp_control);
        if (!lsrc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_enumerated(data, &(lsrc->result))) {
-               return False;
+               return false;
        }
 
        lsrc->attr_desc = NULL;
        if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
                if (!asn1_read_OctetString(data, mem_ctx, &attr)) {
-                       return False;
+                       return false;
                }
                lsrc->attr_desc = talloc_strndup(lsrc, (const char *)attr.data, attr.length);
                if (!lsrc->attr_desc) {
-                       return False;
+                       return false;
                }
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lsrc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB attr;
        DATA_BLOB rule;
@@ -84,14 +85,14 @@ static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
        struct ldb_server_sort_control **lssc;
        int num;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        lssc = NULL;
@@ -99,46 +100,46 @@ static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
        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;
+                       return false;
                }
                lssc[num] = talloc_zero(lssc, struct ldb_server_sort_control);
                if (!lssc[num]) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_read_OctetString(data, mem_ctx, &attr)) {
-                       return False;
+                       return false;
                }
 
                lssc[num]->attributeName = talloc_strndup(lssc[num], (const char *)attr.data, attr.length);
                if (!lssc [num]->attributeName) {
-                       return False;
+                       return false;
                }
        
                if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
                        if (!asn1_read_OctetString(data, mem_ctx, &rule)) {
-                               return False;
+                               return false;
                        }
                        lssc[num]->orderingRule = talloc_strndup(lssc[num], (const char *)rule.data, rule.length);
                        if (!lssc[num]->orderingRule) {
-                               return False;
+                               return false;
                        }
                }
 
                if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
-                       BOOL reverse;
+                       bool reverse;
                        if (!asn1_read_BOOLEAN(data, &reverse)) {
-                       return False;
+                       return false;
                        }
                        lssc[num]->reverse = reverse;
                }
        
                if (!asn1_end_tag(data)) {
-                       return False;
+                       return false;
                }
        }
 
@@ -147,248 +148,255 @@ static BOOL decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void **out)
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lssc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
-       struct asn1_data *data = asn1_init(mem_ctx);
+       struct asn1_data *data;
        struct ldb_extended_dn_control *ledc;
 
-       if (!data) return False;
+       /* The content of this control is optional */
+       if (in.length == 0) {
+               *out = NULL;
+               return true;
+       }
+
+       data = asn1_init(mem_ctx);
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        ledc = talloc(mem_ctx, struct ldb_extended_dn_control);
        if (!ledc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(ledc->type))) {
-               return False;
+               return false;
        }
        
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = ledc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_sd_flags_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_sd_flags_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_sd_flags_control *lsdfc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lsdfc = talloc(mem_ctx, struct ldb_sd_flags_control);
        if (!lsdfc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(lsdfc->secinfo_flags))) {
-               return False;
+               return false;
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lsdfc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_search_options_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_search_options_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_search_options_control *lsoc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lsoc = talloc(mem_ctx, struct ldb_search_options_control);
        if (!lsoc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(lsoc->search_options))) {
-               return False;
+               return false;
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lsoc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB cookie;
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_paged_control *lprc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lprc = talloc(mem_ctx, struct ldb_paged_control);
        if (!lprc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(lprc->size))) {
-               return False;
+               return false;
        }
        
        if (!asn1_read_OctetString(data, mem_ctx, &cookie)) {
-               return False;
+               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;
+                       return false;
                }
        } else {
                lprc->cookie = NULL;
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lprc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_dirsync_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_dirsync_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB cookie;
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_dirsync_control *ldc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        ldc = talloc(mem_ctx, struct ldb_dirsync_control);
        if (!ldc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(ldc->flags))) {
-               return False;
+               return false;
        }
        
        if (!asn1_read_Integer(data, &(ldc->max_attributes))) {
-               return False;
+               return false;
        }
        
        if (!asn1_read_OctetString(data, mem_ctx, &cookie)) {
-               return False;
+               return false;
        }
        ldc->cookie_len = cookie.length;
        if (ldc->cookie_len) {
                ldc->cookie = talloc_memdup(ldc, cookie.data, cookie.length);
 
                if (!(ldc->cookie)) {
-                       return False;
+                       return false;
                }
        } else {
                ldc->cookie = NULL;
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = ldc;
 
-       return True;
+       return true;
 }
 
 /* seem that this controls has 2 forms one in case it is used with
  * a Search Request and another when used ina Search Response
  */
-static BOOL decode_asq_control(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_asq_control(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB source_attribute;
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_asq_control *lac;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lac = talloc(mem_ctx, struct ldb_asq_control);
        if (!lac) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
 
                if (!asn1_read_OctetString(data, mem_ctx, &source_attribute)) {
-                       return False;
+                       return false;
                }
                lac->src_attr_len = source_attribute.length;
                if (lac->src_attr_len) {
                        lac->source_attribute = talloc_strndup(lac, (const char *)source_attribute.data, source_attribute.length);
 
                        if (!(lac->source_attribute)) {
-                               return False;
+                               return false;
                        }
                } else {
                        lac->source_attribute = NULL;
@@ -399,96 +407,96 @@ static BOOL decode_asq_control(void *mem_ctx, DATA_BLOB in, void **out)
        } else if (asn1_peek_tag(data, ASN1_ENUMERATED)) {
 
                if (!asn1_read_enumerated(data, &(lac->result))) {
-                       return False;
+                       return false;
                }
 
                lac->request = 0;
 
        } else {
-               return False;
+               return false;
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lac;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_domain_scope_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_domain_scope_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        if (in.length != 0) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL decode_notification_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_notification_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        if (in.length != 0) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL decode_show_deleted_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_show_deleted_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        if (in.length != 0) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL decode_permissive_modify_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_permissive_modify_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        if (in.length != 0) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL decode_manageDSAIT_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_manageDSAIT_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        if (in.length != 0) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL decode_vlv_request(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_vlv_request(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB assertion_value, context_id;
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_vlv_req_control *lvrc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lvrc = talloc(mem_ctx, struct ldb_vlv_req_control);
        if (!lvrc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(lvrc->beforeCount))) {
-               return False;
+               return false;
        }
        
        if (!asn1_read_Integer(data, &(lvrc->afterCount))) {
-               return False;
+               return false;
        }
 
        if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
@@ -496,27 +504,27 @@ static BOOL decode_vlv_request(void *mem_ctx, DATA_BLOB in, void **out)
                lvrc->type = 0;
                
                if (!asn1_start_tag(data, ASN1_CONTEXT(0))) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_read_Integer(data, &(lvrc->match.byOffset.offset))) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_read_Integer(data, &(lvrc->match.byOffset.contentCount))) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_end_tag(data)) { /*SEQUENCE*/
-                       return False;
+                       return false;
                }
 
                if (!asn1_end_tag(data)) { /*CONTEXT*/
-                       return False;
+                       return false;
                }
 
        } else {
@@ -524,38 +532,38 @@ static BOOL decode_vlv_request(void *mem_ctx, DATA_BLOB in, void **out)
                lvrc->type = 1;
 
                if (!asn1_start_tag(data, ASN1_CONTEXT(1))) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_read_OctetString(data, mem_ctx, &assertion_value)) {
-                       return False;
+                       return false;
                }
                lvrc->match.gtOrEq.value_len = assertion_value.length;
                if (lvrc->match.gtOrEq.value_len) {
                        lvrc->match.gtOrEq.value = talloc_memdup(lvrc, assertion_value.data, assertion_value.length);
 
                        if (!(lvrc->match.gtOrEq.value)) {
-                               return False;
+                               return false;
                        }
                } else {
                        lvrc->match.gtOrEq.value = NULL;
                }
 
                if (!asn1_end_tag(data)) { /*CONTEXT*/
-                       return False;
+                       return false;
                }
        }
 
        if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
                if (!asn1_read_OctetString(data, mem_ctx, &context_id)) {
-                       return False;
+                       return false;
                }
                lvrc->ctxid_len = context_id.length;
                if (lvrc->ctxid_len) {
                        lvrc->contextId = talloc_memdup(lvrc, context_id.data, context_id.length);
 
                        if (!(lvrc->contextId)) {
-                               return False;
+                               return false;
                        }
                } else {
                        lvrc->contextId = NULL;
@@ -566,54 +574,54 @@ static BOOL decode_vlv_request(void *mem_ctx, DATA_BLOB in, void **out)
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lvrc;
 
-       return True;
+       return true;
 }
 
-static BOOL decode_vlv_response(void *mem_ctx, DATA_BLOB in, void **out)
+static bool decode_vlv_response(void *mem_ctx, DATA_BLOB in, void **out)
 {
        DATA_BLOB context_id;
        struct asn1_data *data = asn1_init(mem_ctx);
        struct ldb_vlv_resp_control *lvrc;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_load(data, in)) {
-               return False;
+               return false;
        }
 
        lvrc = talloc(mem_ctx, struct ldb_vlv_resp_control);
        if (!lvrc) {
-               return False;
+               return false;
        }
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_Integer(data, &(lvrc->targetPosition))) {
-               return False;
+               return false;
        }
        
        if (!asn1_read_Integer(data, &(lvrc->contentCount))) {
-               return False;
+               return false;
        }
        
        if (!asn1_read_enumerated(data, &(lvrc->vlv_result))) {
-               return False;
+               return false;
        }
 
        if (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
                if (!asn1_read_OctetString(data, mem_ctx, &context_id)) {
-                       return False;
+                       return false;
                }
                lvrc->contextId = talloc_strndup(lvrc, (const char *)context_id.data, context_id.length);
                if (!lvrc->contextId) {
-                       return False;
+                       return false;
                }
                lvrc->ctxid_len = context_id.length;
        } else {
@@ -622,455 +630,575 @@ static BOOL decode_vlv_response(void *mem_ctx, DATA_BLOB in, void **out)
        }
 
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = lvrc;
 
-       return True;
+       return true;
 }
 
-static BOOL encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
+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 = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_enumerated(data, lsrc->result)) {
-               return False;
+               return false;
        }
 
        if (lsrc->attr_desc) {
                if (!asn1_write_OctetString(data, lsrc->attr_desc, strlen(lsrc->attr_desc))) {
-                       return False;
+                       return false;
                }
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
+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 = asn1_init(mem_ctx);
        int num;
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        for (num = 0; lssc[num]; num++) {
                if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-                       return False;
+                       return false;
                }
                
                if (!asn1_write_OctetString(data, lssc[num]->attributeName, strlen(lssc[num]->attributeName))) {
-                       return False;
+                       return false;
                }
 
                if (lssc[num]->orderingRule) {
                        if (!asn1_write_OctetString(data, lssc[num]->orderingRule, strlen(lssc[num]->orderingRule))) {
-                               return False;
+                               return false;
                        }
                }
 
                if (lssc[num]->reverse) {
                        if (!asn1_write_BOOLEAN(data, lssc[num]->reverse)) {
-                               return False;
+                               return false;
                        }
                }
 
                if (!asn1_pop_tag(data)) {
-                       return False;
+                       return false;
                }
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
+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 = asn1_init(mem_ctx);
+       struct asn1_data *data;
 
-       if (!data) return False;
+       if (!in) {
+               *out = data_blob(NULL, 0);
+               return true;
+       }
+
+       data = asn1_init(mem_ctx);
+
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, ledc->type)) {
-               return False;
+               return false;
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        struct ldb_sd_flags_control *lsdfc = talloc_get_type(in, struct ldb_sd_flags_control);
        struct asn1_data *data = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lsdfc->secinfo_flags)) {
-               return False;
+               return false;
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        struct ldb_search_options_control *lsoc = talloc_get_type(in, struct ldb_search_options_control);
        struct asn1_data *data = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lsoc->search_options)) {
-               return False;
+               return false;
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
+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 = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lprc->size)) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_OctetString(data, lprc->cookie, lprc->cookie_len)) {
-               return False;
+               return false;
        }       
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
 /* seem that this controls has 2 forms one in case it is used with
  * a Search Request and another when used ina Search Response
  */
-static BOOL encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        struct ldb_asq_control *lac = talloc_get_type(in, struct ldb_asq_control);
        struct asn1_data *data = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (lac->request) {
 
                if (!asn1_write_OctetString(data, lac->source_attribute, lac->src_attr_len)) {
-                       return False;
+                       return false;
                }
        } else {
                if (!asn1_write_enumerated(data, lac->result)) {
-                       return False;
+                       return false;
                }
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        struct ldb_dirsync_control *ldc = talloc_get_type(in, struct ldb_dirsync_control);
        struct asn1_data *data = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, ldc->flags)) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, ldc->max_attributes)) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_OctetString(data, ldc->cookie, ldc->cookie_len)) {
-               return False;
+               return false;
        }       
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_domain_scope_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_domain_scope_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        if (in) {
-               return False;
+               return false;
        }
 
        *out = data_blob(NULL, 0);
-       return True;
+       return true;
 }
 
-static BOOL encode_notification_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_notification_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        if (in) {
-               return False;
+               return false;
        }
 
        *out = data_blob(NULL, 0);
-       return True;
+       return true;
 }
 
-static BOOL encode_show_deleted_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_show_deleted_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        if (in) {
-               return False;
+               return false;
        }
 
        *out = data_blob(NULL, 0);
-       return True;
+       return true;
 }
 
-static BOOL encode_permissive_modify_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_permissive_modify_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        if (in) {
-               return False;
+               return false;
        }
 
        *out = data_blob(NULL, 0);
-       return True;
+       return true;
 }
 
-static BOOL encode_manageDSAIT_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_manageDSAIT_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        if (in) {
-               return False;
+               return false;
        }
 
        *out = data_blob(NULL, 0);
-       return True;
+       return true;
 }
 
-static BOOL encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        struct ldb_vlv_req_control *lvrc = talloc_get_type(in, struct ldb_vlv_req_control);
        struct asn1_data *data = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lvrc->beforeCount)) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lvrc->afterCount)) {
-               return False;
+               return false;
        }
 
        if (lvrc->type == 0) {
                if (!asn1_push_tag(data, ASN1_CONTEXT(0))) {
-                       return False;
+                       return false;
                }
                
                if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-                       return False;
+                       return false;
                }
                
                if (!asn1_write_Integer(data, lvrc->match.byOffset.offset)) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_write_Integer(data, lvrc->match.byOffset.contentCount)) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_pop_tag(data)) { /*SEQUENCE*/
-                       return False;
+                       return false;
                }
 
                if (!asn1_pop_tag(data)) { /*CONTEXT*/
-                       return False;
+                       return false;
                }
        } else {
                if (!asn1_push_tag(data, ASN1_CONTEXT(1))) {
-                       return False;
+                       return false;
                }
                
                if (!asn1_write_OctetString(data, lvrc->match.gtOrEq.value, lvrc->match.gtOrEq.value_len)) {
-                       return False;
+                       return false;
                }
 
                if (!asn1_pop_tag(data)) { /*CONTEXT*/
-                       return False;
+                       return false;
                }
        }
 
        if (lvrc->ctxid_len) {
                if (!asn1_write_OctetString(data, lvrc->contextId, lvrc->ctxid_len)) {
-                       return False;
+                       return false;
                }
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
 
-       return True;
+       return true;
 }
 
-static BOOL encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
+static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
 {
        struct ldb_vlv_resp_control *lvrc = talloc_get_type(in, struct ldb_vlv_resp_control);
        struct asn1_data *data = asn1_init(mem_ctx);
 
-       if (!data) return False;
+       if (!data) return false;
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lvrc->targetPosition)) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_Integer(data, lvrc->contentCount)) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_enumerated(data, lvrc->vlv_result)) {
-               return False;
+               return false;
        }
 
        if (lvrc->ctxid_len) {
                if (!asn1_write_OctetString(data, lvrc->contextId, lvrc->ctxid_len)) {
-                       return False;
+                       return false;
                }
        }
 
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
+       }
+
+       *out = data_blob_talloc(mem_ctx, data->data, data->length);
+       if (out->data == NULL) {
+               return false;
+       }
+       talloc_free(data);
+
+       return true;
+}
+
+static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+       struct dsdb_openldap_dereference_control *control = talloc_get_type(in, struct dsdb_openldap_dereference_control);
+       int i,j;
+       struct asn1_data *data = asn1_init(mem_ctx);
+
+       if (!data) return false;
+       
+       if (!control) return false;
+       
+       if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+               return false;
+       }
+       
+       for (i=0; control->dereference && control->dereference[i]; i++) {
+               if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+                       return false;
+               }
+               if (!asn1_write_OctetString(data, control->dereference[i]->source_attribute, strlen(control->dereference[i]->source_attribute))) {
+                       return false;
+               }
+               if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+                       return false;
+               }
+               for (j=0; control->dereference && control->dereference[i]->dereference_attribute[j]; j++) {
+                       if (!asn1_write_OctetString(data, control->dereference[i]->dereference_attribute[j], 
+                                                   strlen(control->dereference[i]->dereference_attribute[j]))) {
+                               return false;
+                       }
+               }
+               
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
        }
+       asn1_pop_tag(data);
 
        *out = data_blob_talloc(mem_ctx, data->data, data->length);
        if (out->data == NULL) {
-               return False;
+               return false;
        }
        talloc_free(data);
+       return true;
+}
+
+static bool decode_openldap_dereference(void *mem_ctx, DATA_BLOB in, void **out)
+{
+       struct asn1_data *data = asn1_init(mem_ctx);
+       struct dsdb_openldap_dereference_result_control *control;
+       struct dsdb_openldap_dereference_result **r = NULL;
+       int i = 0;
+       if (!data) return false;
+
+       control = talloc(mem_ctx, struct dsdb_openldap_dereference_result_control);
+       if (!control) return false;
+
+       if (!asn1_load(data, in)) {
+               return false;
+       }
+
+       control = talloc(mem_ctx, struct dsdb_openldap_dereference_result_control);
+       if (!control) {
+               return false;
+       }
+
+       if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+               return false;
+       }
+
+       while (asn1_tag_remaining(data) > 0) {                                  
+               r = talloc_realloc(control, r, struct dsdb_openldap_dereference_result *, i + 2);
+               if (!r) {
+                       return false;
+               }
+               r[i] = talloc_zero(r, struct dsdb_openldap_dereference_result);
+               if (!r[i]) {
+                       return false;
+               }
+
+               if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+                       return false;
+               }
+               
+               asn1_read_OctetString_talloc(r[i], data, &r[i]->source_attribute);
+               asn1_read_OctetString_talloc(r[i], data, &r[i]->dereferenced_dn);
+               if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
+                       if (!asn1_start_tag(data, ASN1_CONTEXT(0))) {
+                               return false;
+                       }
+                       
+                       ldap_decode_attribs_bare(r, data, &r[i]->attributes,
+                                                &r[i]->num_attributes);
+                       
+                       if (!asn1_end_tag(data)) {
+                               return false;
+                       }
+               }
+               if (!asn1_end_tag(data)) {
+                       return false;
+               }
+               i++;
+               r[i] = NULL;
+       }
+
+       if (!asn1_end_tag(data)) {
+               return false;
+       }
+
+       control->attributes = r;
+       *out = control;
 
-       return True;
+       return true;
 }
 
 struct control_handler ldap_known_controls[] = {
@@ -1093,73 +1221,75 @@ struct control_handler ldap_known_controls[] = {
        { "1.3.6.1.4.1.7165.4.3.2", NULL, NULL },
 /* DSDB_EXTENDED_REPLICATED_OBJECTS_OID is internal only, and has no network representation */
        { "1.3.6.1.4.1.7165.4.4.1", NULL, NULL },
+       { DSDB_OPENLDAP_DEREFERENCE_CONTROL, decode_openldap_dereference, encode_openldap_dereference},
        { NULL, NULL, NULL }
 };
 
-BOOL ldap_decode_control_value(void *mem_ctx, DATA_BLOB value, struct ldb_control *ctrl)
+bool ldap_decode_control_value(void *mem_ctx, DATA_BLOB value, struct ldb_control *ctrl)
 {
        int i;
 
        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].decode || !ldap_known_controls[i].decode(mem_ctx, value, &ctrl->data)) {
-                               return False;
+                               return false;
                        }
                        break;
                }
        }
        if (ldap_known_controls[i].oid == NULL) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-BOOL ldap_decode_control_wrapper(void *mem_ctx, struct asn1_data *data, struct ldb_control *ctrl, DATA_BLOB *value)
+bool ldap_decode_control_wrapper(void *mem_ctx, struct asn1_data *data, struct ldb_control *ctrl, DATA_BLOB *value)
 {
        DATA_BLOB oid;
 
        if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_read_OctetString(data, mem_ctx, &oid)) {
-               return False;
+               return false;
        }
        ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
        if (!ctrl->oid) {
-               return False;
+               return false;
        }
 
        if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
-               BOOL critical;
+               bool critical;
                if (!asn1_read_BOOLEAN(data, &critical)) {
-                       return False;
+                       return false;
                }
                ctrl->critical = critical;
        } else {
-               ctrl->critical = False;
+               ctrl->critical = false;
        }
 
        ctrl->data = NULL;
 
        if (!asn1_peek_tag(data, ASN1_OCTET_STRING)) {
+               *value = data_blob(NULL, 0);
                goto end_tag;
        }
 
        if (!asn1_read_OctetString(data, mem_ctx, value)) {
-               return False;
+               return false;
        }
 
 end_tag:
        if (!asn1_end_tag(data)) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }
 
-BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldb_control *ctrl)
+bool ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldb_control *ctrl)
 {
        DATA_BLOB value;
        int i;
@@ -1168,33 +1298,33 @@ BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldb_contr
                if (strcmp(ldap_known_controls[i].oid, ctrl->oid) == 0) {
                        if (!ldap_known_controls[i].encode) {
                                if (ctrl->critical) {
-                                       return False;
+                                       return false;
                                } else {
                                        /* not encoding this control */
-                                       return True;
+                                       return true;
                                }
                        }
                        if (!ldap_known_controls[i].encode(mem_ctx, ctrl->data, &value)) {
-                               return False;
+                               return false;
                        }
                        break;
                }
        }
        if (ldap_known_controls[i].oid == NULL) {
-               return False;
+               return false;
        }
 
        if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
-               return False;
+               return false;
        }
 
        if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
-               return False;
+               return false;
        }
 
        if (ctrl->critical) {
                if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
-                       return False;
+                       return false;
                }
        }
 
@@ -1203,13 +1333,13 @@ BOOL ldap_encode_control(void *mem_ctx, struct asn1_data *data, struct ldb_contr
        }
 
        if (!asn1_write_OctetString(data, value.data, value.length)) {
-               return False;
+               return false;
        }
 
 pop_tag:
        if (!asn1_pop_tag(data)) {
-               return False;
+               return false;
        }
 
-       return True;
+       return true;
 }