r26613: Add a function to write a DATA_BLOB into an LDAPString.
[samba.git] / source4 / libcli / ldap / ldap.c
index 1e308d584783cfdafe7df66a12d119d2dba3d7e7..586f2fa6531ca49200fb9720858d15c9ce8b2fe2 100644 (file)
@@ -9,7 +9,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,
@@ -18,8 +18,7 @@
    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/>.
    
 */
 
@@ -28,7 +27,7 @@
 #include "libcli/ldap/ldap.h"
 
 
-static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
+static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
 {
        int i;
 
@@ -38,7 +37,7 @@ static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
                asn1_push_tag(data, ASN1_CONTEXT(tree->operation==LDB_OP_AND?0:1));
                for (i=0; i<tree->u.list.num_elements; i++) {
                        if (!ldap_push_filter(data, tree->u.list.elements[i])) {
-                               return False;
+                               return false;
                        }
                }
                asn1_pop_tag(data);
@@ -47,7 +46,7 @@ static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
        case LDB_OP_NOT:
                asn1_push_tag(data, ASN1_CONTEXT(2));
                if (!ldap_push_filter(data, tree->u.isnot.child)) {
-                       return False;
+                       return false;
                }
                asn1_pop_tag(data);
                break;
@@ -78,7 +77,7 @@ static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
                i = 0;
                if ( ! tree->u.substring.start_with_wildcard) {
                        asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
-                       asn1_write_LDAPString(data, (char *)tree->u.substring.chunks[i]->data);
+                       asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i]);
                        asn1_pop_tag(data);
                        i++;
                }
@@ -92,7 +91,7 @@ static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
                                ctx = 1;
                        }
                        asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx));
-                       asn1_write_LDAPString(data, (char *)tree->u.substring.chunks[i]->data);
+                       asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i]);
                        asn1_pop_tag(data);
                        i++;
                }
@@ -158,7 +157,7 @@ static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
                        asn1_pop_tag(data);
                }
                asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3));
-               asn1_write_LDAPString(data, (char *)tree->u.extended.value.data);
+               asn1_write_DATA_BLOB_LDAPString(data, &tree->u.extended.value);
                asn1_pop_tag(data);
                asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4));
                asn1_write_uint8(data, tree->u.extended.dnAttributes);
@@ -167,7 +166,7 @@ static BOOL ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree
                break;
 
        default:
-               return False;
+               return false;
        }
        return !data->has_error;
 }
@@ -188,57 +187,58 @@ static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *res
        }
 }
 
-BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx)
+bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx)
 {
-       struct asn1_data data;
+       struct asn1_data *data = asn1_init(mem_ctx);
        int i, j;
 
-       ZERO_STRUCT(data);
-       asn1_push_tag(&data, ASN1_SEQUENCE(0));
-       asn1_write_Integer(&data, msg->messageid);
+       if (!data) return false;
+
+       asn1_push_tag(data, ASN1_SEQUENCE(0));
+       asn1_write_Integer(data, msg->messageid);
 
        switch (msg->type) {
        case LDAP_TAG_BindRequest: {
                struct ldap_BindRequest *r = &msg->r.BindRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_Integer(&data, r->version);
-               asn1_write_OctetString(&data, r->dn,
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_Integer(data, r->version);
+               asn1_write_OctetString(data, r->dn,
                                       (r->dn != NULL) ? strlen(r->dn) : 0);
 
                switch (r->mechanism) {
                case LDAP_AUTH_MECH_SIMPLE:
                        /* context, primitive */
-                       asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
-                       asn1_write(&data, r->creds.password,
+                       asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
+                       asn1_write(data, r->creds.password,
                                   strlen(r->creds.password));
-                       asn1_pop_tag(&data);
+                       asn1_pop_tag(data);
                        break;
                case LDAP_AUTH_MECH_SASL:
                        /* context, constructed */
-                       asn1_push_tag(&data, ASN1_CONTEXT(3));
-                       asn1_write_OctetString(&data, r->creds.SASL.mechanism,
+                       asn1_push_tag(data, ASN1_CONTEXT(3));
+                       asn1_write_OctetString(data, r->creds.SASL.mechanism,
                                               strlen(r->creds.SASL.mechanism));
                        if (r->creds.SASL.secblob) {
-                               asn1_write_OctetString(&data, r->creds.SASL.secblob->data,
+                               asn1_write_OctetString(data, r->creds.SASL.secblob->data,
                                                       r->creds.SASL.secblob->length);
                        }
-                       asn1_pop_tag(&data);
+                       asn1_pop_tag(data);
                        break;
                default:
-                       return False;
+                       return false;
                }
 
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_BindResponse: {
                struct ldap_BindResponse *r = &msg->r.BindResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, &r->response);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, &r->response);
                if (r->SASL.secblob) {
-                       asn1_write_ContextSimple(&data, 7, r->SASL.secblob);
+                       asn1_write_ContextSimple(data, 7, r->SASL.secblob);
                }
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_UnbindRequest: {
@@ -247,272 +247,272 @@ BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ct
        }
        case LDAP_TAG_SearchRequest: {
                struct ldap_SearchRequest *r = &msg->r.SearchRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->basedn, strlen(r->basedn));
-               asn1_write_enumerated(&data, r->scope);
-               asn1_write_enumerated(&data, r->deref);
-               asn1_write_Integer(&data, r->sizelimit);
-               asn1_write_Integer(&data, r->timelimit);
-               asn1_write_BOOLEAN(&data, r->attributesonly);
-
-               if (!ldap_push_filter(&data, r->tree)) {
-                       return False;
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->basedn, strlen(r->basedn));
+               asn1_write_enumerated(data, r->scope);
+               asn1_write_enumerated(data, r->deref);
+               asn1_write_Integer(data, r->sizelimit);
+               asn1_write_Integer(data, r->timelimit);
+               asn1_write_BOOLEAN(data, r->attributesonly);
+
+               if (!ldap_push_filter(data, r->tree)) {
+                       return false;
                }
 
-               asn1_push_tag(&data, ASN1_SEQUENCE(0));
+               asn1_push_tag(data, ASN1_SEQUENCE(0));
                for (i=0; i<r->num_attributes; i++) {
-                       asn1_write_OctetString(&data, r->attributes[i],
+                       asn1_write_OctetString(data, r->attributes[i],
                                               strlen(r->attributes[i]));
                }
-               asn1_pop_tag(&data);
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_SearchResultEntry: {
                struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->dn, strlen(r->dn));
-               asn1_push_tag(&data, ASN1_SEQUENCE(0));
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->dn, strlen(r->dn));
+               asn1_push_tag(data, ASN1_SEQUENCE(0));
                for (i=0; i<r->num_attributes; i++) {
                        struct ldb_message_element *attr = &r->attributes[i];
-                       asn1_push_tag(&data, ASN1_SEQUENCE(0));
-                       asn1_write_OctetString(&data, attr->name,
+                       asn1_push_tag(data, ASN1_SEQUENCE(0));
+                       asn1_write_OctetString(data, attr->name,
                                               strlen(attr->name));
-                       asn1_push_tag(&data, ASN1_SEQUENCE(1));
+                       asn1_push_tag(data, ASN1_SEQUENCE(1));
                        for (j=0; j<attr->num_values; j++) {
-                               asn1_write_OctetString(&data,
+                               asn1_write_OctetString(data,
                                                       attr->values[j].data,
                                                       attr->values[j].length);
                        }
-                       asn1_pop_tag(&data);
-                       asn1_pop_tag(&data);
+                       asn1_pop_tag(data);
+                       asn1_pop_tag(data);
                }
-               asn1_pop_tag(&data);
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_SearchResultDone: {
                struct ldap_Result *r = &msg->r.SearchResultDone;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, r);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, r);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_ModifyRequest: {
                struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->dn, strlen(r->dn));
-               asn1_push_tag(&data, ASN1_SEQUENCE(0));
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->dn, strlen(r->dn));
+               asn1_push_tag(data, ASN1_SEQUENCE(0));
 
                for (i=0; i<r->num_mods; i++) {
                        struct ldb_message_element *attrib = &r->mods[i].attrib;
-                       asn1_push_tag(&data, ASN1_SEQUENCE(0));
-                       asn1_write_enumerated(&data, r->mods[i].type);
-                       asn1_push_tag(&data, ASN1_SEQUENCE(0));
-                       asn1_write_OctetString(&data, attrib->name,
+                       asn1_push_tag(data, ASN1_SEQUENCE(0));
+                       asn1_write_enumerated(data, r->mods[i].type);
+                       asn1_push_tag(data, ASN1_SEQUENCE(0));
+                       asn1_write_OctetString(data, attrib->name,
                                               strlen(attrib->name));
-                       asn1_push_tag(&data, ASN1_SET);
+                       asn1_push_tag(data, ASN1_SET);
                        for (j=0; j<attrib->num_values; j++) {
-                               asn1_write_OctetString(&data,
+                               asn1_write_OctetString(data,
                                                       attrib->values[j].data,
                                                       attrib->values[j].length);
        
                        }
-                       asn1_pop_tag(&data);
-                       asn1_pop_tag(&data);
-                       asn1_pop_tag(&data);
+                       asn1_pop_tag(data);
+                       asn1_pop_tag(data);
+                       asn1_pop_tag(data);
                }
                
-               asn1_pop_tag(&data);
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_ModifyResponse: {
                struct ldap_Result *r = &msg->r.ModifyResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, r);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, r);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_AddRequest: {
                struct ldap_AddRequest *r = &msg->r.AddRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->dn, strlen(r->dn));
-               asn1_push_tag(&data, ASN1_SEQUENCE(0));
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->dn, strlen(r->dn));
+               asn1_push_tag(data, ASN1_SEQUENCE(0));
 
                for (i=0; i<r->num_attributes; i++) {
                        struct ldb_message_element *attrib = &r->attributes[i];
-                       asn1_push_tag(&data, ASN1_SEQUENCE(0));
-                       asn1_write_OctetString(&data, attrib->name,
+                       asn1_push_tag(data, ASN1_SEQUENCE(0));
+                       asn1_write_OctetString(data, attrib->name,
                                               strlen(attrib->name));
-                       asn1_push_tag(&data, ASN1_SET);
+                       asn1_push_tag(data, ASN1_SET);
                        for (j=0; j<r->attributes[i].num_values; j++) {
-                               asn1_write_OctetString(&data,
+                               asn1_write_OctetString(data,
                                                       attrib->values[j].data,
                                                       attrib->values[j].length);
                        }
-                       asn1_pop_tag(&data);
-                       asn1_pop_tag(&data);
+                       asn1_pop_tag(data);
+                       asn1_pop_tag(data);
                }
-               asn1_pop_tag(&data);
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_AddResponse: {
                struct ldap_Result *r = &msg->r.AddResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, r);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, r);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_DelRequest: {
                struct ldap_DelRequest *r = &msg->r.DelRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
-               asn1_write(&data, r->dn, strlen(r->dn));
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type));
+               asn1_write(data, r->dn, strlen(r->dn));
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_DelResponse: {
                struct ldap_Result *r = &msg->r.DelResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, r);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, r);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_ModifyDNRequest: {
                struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->dn, strlen(r->dn));
-               asn1_write_OctetString(&data, r->newrdn, strlen(r->newrdn));
-               asn1_write_BOOLEAN(&data, r->deleteolddn);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->dn, strlen(r->dn));
+               asn1_write_OctetString(data, r->newrdn, strlen(r->newrdn));
+               asn1_write_BOOLEAN(data, r->deleteolddn);
                if (r->newsuperior) {
-                       asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
-                       asn1_write(&data, r->newsuperior,
+                       asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
+                       asn1_write(data, r->newsuperior,
                                   strlen(r->newsuperior));
-                       asn1_pop_tag(&data);
+                       asn1_pop_tag(data);
                }
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_ModifyDNResponse: {
                struct ldap_Result *r = &msg->r.ModifyDNResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, r);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, r);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_CompareRequest: {
                struct ldap_CompareRequest *r = &msg->r.CompareRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->dn, strlen(r->dn));
-               asn1_push_tag(&data, ASN1_SEQUENCE(0));
-               asn1_write_OctetString(&data, r->attribute,
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->dn, strlen(r->dn));
+               asn1_push_tag(data, ASN1_SEQUENCE(0));
+               asn1_write_OctetString(data, r->attribute,
                                       strlen(r->attribute));
-               asn1_write_OctetString(&data, r->value.data,
+               asn1_write_OctetString(data, r->value.data,
                                       r->value.length);
-               asn1_pop_tag(&data);
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_CompareResponse: {
                struct ldap_Result *r = &msg->r.ModifyDNResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, r);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, r);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_AbandonRequest: {
                struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION_SIMPLE(msg->type));
-               asn1_write_implicit_Integer(&data, r->messageid);
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type));
+               asn1_write_implicit_Integer(data, r->messageid);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_SearchResultReference: {
                struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_write_OctetString(&data, r->referral, strlen(r->referral));
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_write_OctetString(data, r->referral, strlen(r->referral));
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_ExtendedRequest: {
                struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(0));
-               asn1_write(&data, r->oid, strlen(r->oid));
-               asn1_pop_tag(&data);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0));
+               asn1_write(data, r->oid, strlen(r->oid));
+               asn1_pop_tag(data);
                if (r->value) {
-                       asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(1));
-                       asn1_write(&data, r->value->data, r->value->length);
-                       asn1_pop_tag(&data);
+                       asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1));
+                       asn1_write(data, r->value->data, r->value->length);
+                       asn1_pop_tag(data);
                }
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_ExtendedResponse: {
                struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
-               asn1_push_tag(&data, ASN1_APPLICATION(msg->type));
-               ldap_encode_response(&data, &r->response);
+               asn1_push_tag(data, ASN1_APPLICATION(msg->type));
+               ldap_encode_response(data, &r->response);
                if (r->oid) {
-                       asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(10));
-                       asn1_write(&data, r->oid, strlen(r->oid));
-                       asn1_pop_tag(&data);
+                       asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(10));
+                       asn1_write(data, r->oid, strlen(r->oid));
+                       asn1_pop_tag(data);
                }
                if (r->value) {
-                       asn1_push_tag(&data, ASN1_CONTEXT_SIMPLE(11));
-                       asn1_write(&data, r->value->data, r->value->length);
-                       asn1_pop_tag(&data);
+                       asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(11));
+                       asn1_write(data, r->value->data, r->value->length);
+                       asn1_pop_tag(data);
                }
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
                break;
        }
        default:
-               return False;
+               return false;
        }
 
        if (msg->controls != NULL) {
-               asn1_push_tag(&data, ASN1_CONTEXT(0));
+               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;
+                       if (!ldap_encode_control(mem_ctx, data, msg->controls[i])) {
+                               return false;
                        }
                }
 
-               asn1_pop_tag(&data);
+               asn1_pop_tag(data);
        }
 
-       asn1_pop_tag(&data);
+       asn1_pop_tag(data);
 
-       if (data.has_error) {
-               asn1_free(&data);
-               return False;
+       if (data->has_error) {
+               asn1_free(data);
+               return false;
        }
 
-       *result = data_blob_talloc(mem_ctx, data.data, data.length);
-       asn1_free(&data);
-       return True;
+       *result = data_blob_talloc(mem_ctx, data->data, data->length);
+       asn1_free(data);
+       return true;
 }
 
 static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
                                      DATA_BLOB blob)
 {
-       char *result = talloc_size(mem_ctx, blob.length+1);
+       char *result = talloc_array(mem_ctx, char, blob.length+1);
        memcpy(result, blob.data, blob.length);
        result[blob.length] = '\0';
        return result;
 }
 
-static BOOL asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
+static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
                                         struct asn1_data *data,
                                         const char **result)
 {
        DATA_BLOB string;
-       if (!asn1_read_OctetString(data, &string))
-               return False;
+       if (!asn1_read_OctetString(data, mem_ctx, &string))
+               return false;
        *result = blob2string_talloc(mem_ctx, string);
        data_blob_free(&string);
-       return True;
+       return true;
 }
 
 static void ldap_decode_response(TALLOC_CTX *mem_ctx,
@@ -631,7 +631,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 
                asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
                asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
-               asn1_read_OctetString(data, &value);
+               asn1_read_OctetString(data, mem_ctx, &value);
                asn1_end_tag(data);
                if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
                        goto failed;
@@ -653,7 +653,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
                if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
                        goto failed;
                }
-               if (!asn1_read_OctetString(data, &attr)) {
+               if (!asn1_read_OctetString(data, mem_ctx, &attr)) {
                        goto failed;
                }
 
@@ -673,7 +673,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
                        if (subs_tag > 2) goto failed;
 
                        asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(subs_tag));
-                       asn1_read_LDAPString(data, &value);
+                       asn1_read_LDAPString(data, mem_ctx, &value);
                        asn1_end_tag(data);
 
                        switch (subs_tag) {
@@ -743,7 +743,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 
                asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
                asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
-               asn1_read_OctetString(data, &value);
+               asn1_read_OctetString(data, mem_ctx, &value);
                asn1_end_tag(data);
                if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
                        goto failed;
@@ -762,7 +762,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 
                asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
                asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
-               asn1_read_OctetString(data, &value);
+               asn1_read_OctetString(data, mem_ctx, &value);
                asn1_end_tag(data);
                if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
                        goto failed;
@@ -781,7 +781,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
                if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(filter_tag))) {
                        goto failed;
                }
-               if (!asn1_read_LDAPString(data, &attr)) {
+               if (!asn1_read_LDAPString(data, ret, &attr)) {
                        goto failed;
                }
 
@@ -800,7 +800,7 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
 
                asn1_start_tag(data, ASN1_CONTEXT(filter_tag));
                asn1_read_OctetString_talloc(mem_ctx, data, &attrib);
-               asn1_read_OctetString(data, &value);
+               asn1_read_OctetString(data, mem_ctx, &value);
                asn1_end_tag(data);
                if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) {
                        goto failed;
@@ -825,16 +825,16 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
                /* either oid or type must be defined */
                if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
                        asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(1));
-                       asn1_read_LDAPString(data, &oid);
+                       asn1_read_LDAPString(data, ret, &oid);
                        asn1_end_tag(data);
                }
                if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(2))) {      /* optional  */
                        asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(2));
-                       asn1_read_LDAPString(data, &attr);
+                       asn1_read_LDAPString(data, ret, &attr);
                        asn1_end_tag(data);
                }
                asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(3));
-               asn1_read_LDAPString(data, &value);
+               asn1_read_LDAPString(data, ret, &value);
                asn1_end_tag(data);
                /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
                   it is not marked as OPTIONAL but openldap tools
@@ -902,7 +902,7 @@ static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
        asn1_start_tag(data, ASN1_SET);
        while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
                DATA_BLOB blob;
-               asn1_read_OctetString(data, &blob);
+               asn1_read_OctetString(data, mem_ctx, &blob);
                add_value_to_attrib(mem_ctx, &blob, attrib);
        }
        asn1_end_tag(data);
@@ -955,7 +955,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                                return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
                        }
                        if (pwlen != 0) {
-                               char *pw = talloc_size(msg, pwlen+1);
+                               char *pw = talloc_array(msg, char, pwlen+1);
                                if (!pw) {
                                        return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
                                }
@@ -970,7 +970,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                        asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism);
                        if (asn1_peek_tag(data, ASN1_OCTET_STRING)) { /* optional */
                                DATA_BLOB tmp_blob = data_blob(NULL, 0);
-                               asn1_read_OctetString(data, &tmp_blob);
+                               asn1_read_OctetString(data, msg, &tmp_blob);
                                r->creds.SASL.secblob = talloc(msg, DATA_BLOB);
                                if (!r->creds.SASL.secblob) {
                                        return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
@@ -1162,7 +1162,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                if (len == -1) {
                        return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
                }
-               dn = talloc_size(msg, len+1);
+               dn = talloc_array(msg, char, len+1);
                if (dn == NULL)
                        break;
                asn1_read(data, dn, len);
@@ -1198,7 +1198,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                        if (len == -1) {
                                return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
                        }
-                       newsup = talloc_size(msg, len+1);
+                       newsup = talloc_array(msg, char, len+1);
                        if (newsup == NULL) {
                                return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
                        }
@@ -1228,7 +1228,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                asn1_read_OctetString_talloc(msg, data, &r->dn);
                asn1_start_tag(data, ASN1_SEQUENCE(0));
                asn1_read_OctetString_talloc(msg, data, &r->attribute);
-               asn1_read_OctetString(data, &r->value);
+               asn1_read_OctetString(data, msg, &r->value);
                if (r->value.data) {
                        talloc_steal(msg, r->value.data);
                }
@@ -1325,10 +1325,12 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
        }
 
        msg->controls = NULL;
+       msg->controls_decoded = NULL;
 
        if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
                int i = 0;
                struct ldb_control **ctrl = NULL;
+               bool *decoded = NULL;
 
                asn1_start_tag(data, ASN1_CONTEXT(0));
 
@@ -1341,6 +1343,11 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                                return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
                        }
 
+                       decoded = talloc_realloc(msg, decoded, bool, i+1);
+                       if (!decoded) {
+                               return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+                       }
+
                        ctrl[i] = talloc(ctrl, struct ldb_control);
                        if (!ctrl[i]) {
                                return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
@@ -1352,12 +1359,15 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                        
                        if (!ldap_decode_control_value(ctrl, value, ctrl[i])) {
                                if (ctrl[i]->critical) {
-                                       return NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
+                                       ctrl[i]->data = NULL;
+                                       decoded[i] = false;
+                                       i++;
                                } else {
                                        talloc_free(ctrl[i]);
                                        ctrl[i] = NULL;
                                }
                        } else {
+                               decoded[i] = true;
                                i++;
                        }
                }
@@ -1367,6 +1377,7 @@ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                }
 
                msg->controls = ctrl;
+               msg->controls_decoded = decoded;
 
                asn1_end_tag(data);
        }