libcli/security: fix sid_type_lookup().
[kai/samba.git] / libcli / ldap / ldap_message.c
index e8ec716e64118ebc6a18272b13497fcc43b2f6e8..7756e731b247fd08796c0303d228dd5eaf098d22 100644 (file)
@@ -84,6 +84,144 @@ static bool add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
        return true;
 }
 
+static bool ldap_decode_control_value(void *mem_ctx, DATA_BLOB value,
+                                     const struct ldap_control_handler *handlers,
+                                     struct ldb_control *ctrl)
+{
+       int i;
+
+       if (!handlers) {
+               return true;
+       }
+
+       for (i = 0; handlers[i].oid != NULL; i++) {
+               if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+                       if (!handlers[i].decode || !handlers[i].decode(mem_ctx, value, &ctrl->data)) {
+                               return false;
+                       }
+                       break;
+               }
+       }
+       if (handlers[i].oid == NULL) {
+               return false;
+       }
+
+       return true;
+}
+
+static 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;
+       }
+
+       if (!asn1_read_OctetString(data, mem_ctx, &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)) {
+               bool critical;
+               if (!asn1_read_BOOLEAN(data, &critical)) {
+                       return false;
+               }
+               ctrl->critical = critical;
+       } else {
+               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;
+       }
+
+end_tag:
+       if (!asn1_end_tag(data)) {
+               return false;
+       }
+
+       return true;
+}
+
+static bool ldap_encode_control(void *mem_ctx, struct asn1_data *data,
+                               const struct ldap_control_handler *handlers,
+                               struct ldb_control *ctrl)
+{
+       DATA_BLOB value;
+       int i;
+
+       if (!handlers) {
+               return false;
+       }
+
+       for (i = 0; handlers[i].oid != NULL; i++) {
+               if (!ctrl->oid) {
+                       /* not encoding this control, the OID has been
+                        * set to NULL indicating it isn't really
+                        * here */
+                       return true;
+               }
+               if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+                       if (!handlers[i].encode) {
+                               if (ctrl->critical) {
+                                       return false;
+                               } else {
+                                       /* not encoding this control */
+                                       return true;
+                               }
+                       }
+                       if (!handlers[i].encode(mem_ctx, ctrl->data, &value)) {
+                               return false;
+                       }
+                       break;
+               }
+       }
+       if (handlers[i].oid == NULL) {
+               return false;
+       }
+
+       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;
+               }
+       }
+
+       if (!ctrl->data) {
+               goto pop_tag;
+       }
+
+       if (!asn1_write_OctetString(data, value.data, value.length)) {
+               return false;
+       }
+
+pop_tag:
+       if (!asn1_pop_tag(data)) {
+               return false;
+       }
+
+       return true;
+}
+
 static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
 {
        int i;
@@ -244,7 +382,9 @@ static void ldap_encode_response(struct asn1_data *data, struct ldap_Result *res
        }
 }
 
-_PUBLIC_ bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CTX *mem_ctx)
+_PUBLIC_ bool ldap_encode(struct ldap_message *msg,
+                         const struct ldap_control_handler *control_handlers,
+                         DATA_BLOB *result, TALLOC_CTX *mem_ctx)
 {
        struct asn1_data *data = asn1_init(mem_ctx);
        int i, j;
@@ -300,6 +440,8 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CT
        }
        case LDAP_TAG_UnbindRequest: {
 /*             struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
+               asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type));
+               asn1_pop_tag(data);
                break;
        }
        case LDAP_TAG_SearchRequest: {
@@ -531,7 +673,11 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg, DATA_BLOB *result, TALLOC_CT
                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])) {
+                       if (!ldap_encode_control(mem_ctx, data,
+                                                control_handlers,
+                                                msg->controls[i])) {
+                               DEBUG(1,("Unable to encode control %s\n",
+                                        msg->controls[i]->oid));
                                return false;
                        }
                }
@@ -923,13 +1069,13 @@ static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
                                ret->u.extended.attr = talloc_strdup(ret, "*");
                        }
                        ret->u.extended.rule_id      = talloc_steal(ret, oid);
-                       ret->u.extended.value.data   = talloc_steal(ret, value);
+                       ret->u.extended.value.data   = (uint8_t *)talloc_steal(ret, value);
                        ret->u.extended.value.length = strlen(value);
                        ret->u.extended.dnAttributes = dnAttributes;
                } else {
                        ret->operation               = LDB_OP_EQUALITY;
                        ret->u.equality.attr         = talloc_steal(ret, attr);
-                       ret->u.equality.value.data   = talloc_steal(ret, value);
+                       ret->u.equality.value.data   = (uint8_t *)talloc_steal(ret, value);
                        ret->u.equality.value.length = strlen(value);
                }
                if (!asn1_end_tag(data)) {
@@ -993,7 +1139,9 @@ static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
 
 /* This routine returns LDAP status codes */
 
-_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
+_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
+                             const struct ldap_control_handler *control_handlers,
+                             struct ldap_message *msg)
 {
        uint8_t tag;
 
@@ -1087,13 +1235,17 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
 
        case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
                struct ldap_SearchRequest *r = &msg->r.SearchRequest;
+               int sizelimit, timelimit;
+               const char **attrs = NULL;
                msg->type = LDAP_TAG_SearchRequest;
                asn1_start_tag(data, tag);
                asn1_read_OctetString_talloc(msg, data, &r->basedn);
-               asn1_read_enumerated(data, (int *)&(r->scope));
-               asn1_read_enumerated(data, (int *)&(r->deref));
-               asn1_read_Integer(data, &r->sizelimit);
-               asn1_read_Integer(data, &r->timelimit);
+               asn1_read_enumerated(data, (int *)(void *)&(r->scope));
+               asn1_read_enumerated(data, (int *)(void *)&(r->deref));
+               asn1_read_Integer(data, &sizelimit);
+               r->sizelimit = sizelimit;
+               asn1_read_Integer(data, &timelimit);
+               r->timelimit = timelimit;
                asn1_read_BOOLEAN(data, &r->attributesonly);
 
                r->tree = ldap_decode_filter_tree(msg, data);
@@ -1113,10 +1265,11 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                                                          &attr))
                                return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
                        if (!add_string_to_array(msg, attr,
-                                                &r->attributes,
+                                                &attrs,
                                                 &r->num_attributes))
                                return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
                }
+               r->attributes = attrs;
 
                asn1_end_tag(data);
                asn1_end_tag(data);
@@ -1423,7 +1576,9 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
                                return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
                        }
                        
-                       if (!ldap_decode_control_value(ctrl, value, ctrl[i])) {
+                       if (!ldap_decode_control_value(ctrl, value,
+                                                      control_handlers,
+                                                      ctrl[i])) {
                                if (ctrl[i]->critical) {
                                        ctrl[i]->data = NULL;
                                        decoded[i] = false;
@@ -1462,5 +1617,12 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data, struct ldap_message *msg)
 */
 NTSTATUS ldap_full_packet(void *private_data, DATA_BLOB blob, size_t *packet_size)
 {
-       return asn1_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+       if (blob.length < 6) {
+               /*
+                * We need at least 6 bytes to workout the length
+                * of the pdu.
+                */
+               return STATUS_MORE_ENTRIES;
+       }
+       return asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
 }