diff options
-rw-r--r-- | source4/libcli/ldap/ldap.c | 184 |
1 files changed, 107 insertions, 77 deletions
diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c index f383d08074..2718dd7e34 100644 --- a/source4/libcli/ldap/ldap.c +++ b/source4/libcli/ldap/ldap.c @@ -413,122 +413,152 @@ static void ldap_decode_response(TALLOC_CTX *mem_ctx, } } -static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, struct asn1_data *data, - const char **filterp) +static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx, + struct asn1_data *data) { uint8_t filter_tag, tag_desc; - char *filter = NULL; - - *filterp = NULL; + struct ldb_parse_tree *ret; - if (!asn1_peek_uint8(data, &filter_tag)) - return False; + if (!asn1_peek_uint8(data, &filter_tag)) { + return NULL; + } tag_desc = filter_tag; filter_tag &= 0x1f; /* strip off the asn1 stuff */ tag_desc &= 0xe0; - switch(filter_tag) { - case 0: { - /* AND of one or more filters */ - if (tag_desc != 0xa0) /* context compount */ - return False; - - asn1_start_tag(data, ASN1_CONTEXT(0)); + ret = talloc(mem_ctx, struct ldb_parse_tree); + if (ret == NULL) return NULL; - filter = talloc_strdup(mem_ctx, "(&"); - if (filter == NULL) - return False; - - while (asn1_tag_remaining(data) > 0) { - const char *subfilter; - if (!ldap_decode_filter(mem_ctx, data, &subfilter)) - return False; - filter = talloc_asprintf_append(filter, "%s", subfilter); - if (filter == NULL) - return False; + switch(filter_tag) { + case 0: + case 1: + /* AND or OR of one or more filters */ + ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR; + ret->u.list.num_elements = 0; + ret->u.list.elements = NULL; + + if (tag_desc != 0xa0) { + /* context compount */ + goto failed; } - asn1_end_tag(data); - - filter = talloc_asprintf_append(filter, ")"); - break; - } - case 1: { - /* OR of one or more filters */ - if (tag_desc != 0xa0) /* context compount */ - return False; - asn1_start_tag(data, ASN1_CONTEXT(1)); - - filter = talloc_strdup(mem_ctx, "(|"); - if (filter == NULL) - return False; + if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) { + goto failed; + } while (asn1_tag_remaining(data) > 0) { - const char *subfilter; - if (!ldap_decode_filter(mem_ctx, data, &subfilter)) - return False; - filter = talloc_asprintf_append(filter, "%s", subfilter); - if (filter == NULL) - return False; + struct ldb_parse_tree *subtree; + subtree = ldap_decode_filter_tree(ret, data); + if (subtree == NULL) { + goto failed; + } + ret->u.list.elements = + talloc_realloc(ret, ret->u.list.elements, + struct ldb_parse_tree *, + ret->u.list.num_elements+1); + if (ret->u.list.elements == NULL) { + goto failed; + } + talloc_steal(ret->u.list.elements, subtree); + ret->u.list.elements[ret->u.list.num_elements] = subtree; + ret->u.list.num_elements++; + } + if (!asn1_end_tag(data)) { + goto failed; } - - asn1_end_tag(data); - - filter = talloc_asprintf_append(filter, ")"); break; - } + case 3: { /* equalityMatch */ const char *attrib; DATA_BLOB value; - struct ldb_val val; - if (tag_desc != 0xa0) /* context compound */ - return False; + ret->operation = LDB_OP_SIMPLE; + + if (tag_desc != 0xa0) { + /* context compound */ + goto failed; + } + asn1_start_tag(data, ASN1_CONTEXT(3)); asn1_read_OctetString_talloc(mem_ctx, data, &attrib); asn1_read_OctetString(data, &value); asn1_end_tag(data); - if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) - return False; - val.data = value.data; - val.length = value.length; - filter = talloc_asprintf(mem_ctx, "(%s=%s)", - attrib, ldb_binary_encode(mem_ctx, val)); - data_blob_free(&value); + if ((data->has_error) || (attrib == NULL) || (value.data == NULL)) { + goto failed; + } + ret->u.simple.attr = talloc_steal(ret, attrib); + ret->u.simple.value.data = talloc_steal(ret, value.data); + ret->u.simple.value.length = value.length; break; } case 7: { /* Normal presence, "attribute=*" */ int attr_len; - char *attr_name; - if (tag_desc != 0x80) /* context simple */ - return False; - if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7))) - return False; + if (tag_desc != 0x80) { + /* context simple */ + goto failed; + } + if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(7))) { + goto failed; + } + + ret->operation = LDB_OP_SIMPLE; + attr_len = asn1_tag_remaining(data); - attr_name = malloc(attr_len+1); - if (attr_name == NULL) - return False; - asn1_read(data, attr_name, attr_len); - attr_name[attr_len] = '\0'; - filter = talloc_asprintf(mem_ctx, "(%s=*)", attr_name); - SAFE_FREE(attr_name); - asn1_end_tag(data); + + ret->u.simple.attr = talloc_size(ret, attr_len+1); + if (ret->u.simple.attr == NULL) { + goto failed; + } + if (!asn1_read(data, ret->u.simple.attr, attr_len)) { + goto failed; + } + ret->u.simple.attr[attr_len] = 0; + ret->u.simple.value.data = talloc_strdup(ret, "*"); + if (ret->u.simple.value.data == NULL) { + goto failed; + } + ret->u.simple.value.length = 1; + if (!asn1_end_tag(data)) { + goto failed; + } break; } default: - return False; + DEBUG(0,("Unsupported LDAP filter operation 0x%x\n", filter_tag)); + goto failed; } - if (filter == NULL) - return False; + + return ret; - *filterp = filter; +failed: + talloc_free(ret); + DEBUG(0,("Failed to parse ASN.1 LDAP filter\n")); + return NULL; +} + + +static BOOL ldap_decode_filter(TALLOC_CTX *mem_ctx, struct asn1_data *data, + const char **filterp) +{ + struct ldb_parse_tree *tree; + tree = ldap_decode_filter_tree(mem_ctx, data); + if (tree == NULL) { + return False; + } + *filterp = ldb_filter_from_tree(mem_ctx, tree); + talloc_free(tree); + if (*filterp == NULL) { + return False; + } return True; } + + static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data, struct ldap_attribute *attrib) { |