diff options
author | Matthieu Patou <mat@matws.net> | 2012-12-27 21:38:29 -0800 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2015-12-17 03:23:20 +0100 |
commit | abcd35f942468e8e51dbc7b976055232df41d421 (patch) | |
tree | da21a6f1fdea6175bf46b59d3de978dee5fdc646 /lib/ldb/common | |
parent | 1595f56634a8950c4493799b30c2dbe254466751 (diff) | |
download | samba-abcd35f942468e8e51dbc7b976055232df41d421.tar.gz |
ldb: introduce ldb_unpack_data_withlist to unpack partial list of attributes
When provided with non NULL list ldb_unpack_data_withlist will only
unpack attributes that are specified in the list (+ distinguished name)
ldb_unpack_data is changed to call ldb_unpack_data_withlist behind the
scene.
(for modifications found by testing, and re-indentation requested in review)
Signed-off-by: Adrian Cochrane <adrianc@catalyst.net.nz>
Sadly a signed-off-by was not available from Matthieu Patou for the original
version of this patch posted to samba-technical for comment, so instead:
(for supervision of Adrian)
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11602
Diffstat (limited to 'lib/ldb/common')
-rw-r--r-- | lib/ldb/common/ldb_pack.c | 130 |
1 files changed, 109 insertions, 21 deletions
diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c index 4382d5b1be0..5524542dcd9 100644 --- a/lib/ldb/common/ldb_pack.c +++ b/lib/ldb/common/ldb_pack.c @@ -146,20 +146,52 @@ int ldb_pack_data(struct ldb_context *ldb, return 0; } +static bool ldb_consume_element_data(uint8_t **pp, unsigned int *premaining) +{ + unsigned int remaining = *premaining; + uint8_t *p = *pp; + uint32_t num_values = pull_uint32(p, 0); + uint32_t len; + int j; + + p += 4; + remaining -= 4; + for (j = 0; j < num_values; j++) { + len = pull_uint32(p, 0); + if (len > remaining - 5) { + return false; + } + remaining -= len + 4 + 1; + p += len + 4 + 1; + } + + *premaining = remaining; + *pp = p; + return true; +} /* unpack a ldb message from a linear buffer in ldb_val Free with ldb_unpack_data_free() */ -int ldb_unpack_data(struct ldb_context *ldb, - const struct ldb_val *data, - struct ldb_message *message) +int ldb_unpack_data_withlist(struct ldb_context *ldb, + const struct ldb_val *data, + struct ldb_message *message, + const char * const *list, + unsigned int list_size, + unsigned int *nb_elements_in_db) { uint8_t *p; unsigned int remaining; unsigned int i, j; unsigned format; + unsigned int nelem = 0; size_t len; + unsigned int found = 0; + + if (list == NULL) { + list_size = 0; + } message->elements = NULL; @@ -172,6 +204,9 @@ int ldb_unpack_data(struct ldb_context *ldb, format = pull_uint32(p, 0); message->num_elements = pull_uint32(p, 4); p += 8; + if (nb_elements_in_db) { + *nb_elements_in_db = message->num_elements; + } remaining = data->length - 8; @@ -209,7 +244,8 @@ int ldb_unpack_data(struct ldb_context *ldb, goto failed; } - message->elements = talloc_array(message, struct ldb_message_element, message->num_elements); + message->elements = talloc_array(message, struct ldb_message_element, + message->num_elements); if (!message->elements) { errno = ENOMEM; goto failed; @@ -219,6 +255,9 @@ int ldb_unpack_data(struct ldb_context *ldb, message->num_elements * sizeof(struct ldb_message_element)); for (i=0;i<message->num_elements;i++) { + const char *attr = NULL; + struct ldb_message_element *element = NULL; + if (remaining < 10) { errno = EIO; goto failed; @@ -232,51 +271,93 @@ int ldb_unpack_data(struct ldb_context *ldb, errno = EIO; goto failed; } - message->elements[i].flags = 0; - message->elements[i].name = talloc_strndup(message->elements, (char *)p, len); - if (message->elements[i].name == NULL) { + attr = (char *)p; + /* + * This is a bit expensive but normally the list is pretty small + * also the cost of freeing unused attributes is quite important + * and can dwarf the cost of looping + */ + if (list_size != 0) { + bool keep = false; + int h; + + /* + * We know that p has a \0 terminator before the + * end of the buffer due to the check above. + */ + for (h = 0; h < list_size && found < list_size; h++) { + if (ldb_attr_cmp(attr, list[h]) == 0) { + keep = true; + found++; + break; + } + } + + if (!keep) { + remaining -= len + 1; + p += len + 1; + if (!ldb_consume_element_data(&p, &remaining)) { + errno = EIO; + goto failed; + } + continue; + } + } + element = &message->elements[nelem]; + element->name = talloc_strndup(message->elements, (char *)p, len); + if (element->name == NULL) { errno = ENOMEM; goto failed; } + element->flags = 0; remaining -= len + 1; p += len + 1; - message->elements[i].num_values = pull_uint32(p, 0); - message->elements[i].values = NULL; - if (message->elements[i].num_values != 0) { - message->elements[i].values = talloc_array(message->elements, - struct ldb_val, - message->elements[i].num_values); - if (!message->elements[i].values) { + element->num_values = pull_uint32(p, 0); + element->values = NULL; + if (element->num_values != 0) { + element->values = talloc_array(message->elements, + struct ldb_val, + element->num_values); + if (!element->values) { errno = ENOMEM; goto failed; } } p += 4; remaining -= 4; - for (j=0;j<message->elements[i].num_values;j++) { + for (j = 0; j < element->num_values; j++) { len = pull_uint32(p, 0); if (len > remaining-5) { errno = EIO; goto failed; } - message->elements[i].values[j].length = len; - message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1); - if (message->elements[i].values[j].data == NULL) { + element->values[j].length = len; + element->values[j].data = talloc_size(element->values, len+1); + if (element->values[j].data == NULL) { errno = ENOMEM; goto failed; } - memcpy(message->elements[i].values[j].data, p+4, len); - message->elements[i].values[j].data[len] = 0; + memcpy(element->values[j].data, p + 4, + len); + element->values[j].data[len] = 0; remaining -= len+4+1; p += len+4+1; } + nelem++; } + /* + * Adapt the number of elements to the real number of unpacked elements, + * it means that we overallocated elements array, I guess it's not that + * bad. + */ + message->num_elements = nelem; if (remaining != 0) { ldb_debug(ldb, LDB_DEBUG_ERROR, - "Error: %d bytes unread in ldb_unpack_data", remaining); + "Error: %d bytes unread in ldb_unpack_data_withlist", + remaining); } return 0; @@ -285,3 +366,10 @@ failed: talloc_free(message->elements); return -1; } + +int ldb_unpack_data(struct ldb_context *ldb, + const struct ldb_val *data, + struct ldb_message *message) +{ + return ldb_unpack_data_withlist(ldb, data, message, NULL, 0, NULL); +} |