ldb: introduce ldb_unpack_data_withlist to unpack partial list of attributes
authorMatthieu Patou <mat@matws.net>
Fri, 28 Dec 2012 05:38:29 +0000 (21:38 -0800)
committerMatthieu Patou <mat@matws.net>
Wed, 27 May 2015 05:01:37 +0000 (22:01 -0700)
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.

lib/ldb/common/ldb_pack.c
lib/ldb/include/ldb_private.h

index 4382d5b1be07beaf86c938e34472d5a819d82342..e722f08124bddccba1054194b243358ff0384eba 100644 (file)
@@ -146,20 +146,55 @@ 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;
+       bool filter;
+       unsigned int found = 0;
+
+       if (list == NULL || list_size == 0) {
+               filter = false;
+       } else {
+               filter = true;
+       }
 
        message->elements = NULL;
 
@@ -172,6 +207,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;
 
@@ -232,51 +270,86 @@ 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) {
+               message->elements[nelem].flags = 0;
+               /*
+                * This is a bit expensive but normally the list is pretty small
+                * also the cost of freeing unsused attributes is quite important
+                * and can dwarf the cost of looping
+                */
+               if (filter) {
+                       bool keep = false;
+                       int h;
+
+                       for (h = 0; h < list_size && found < list_size; h++) {
+                               if (strncasecmp((char*) p, list[h], len) == 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;
+                       }
+               }
+               message->elements[nelem].name = talloc_strndup(message->elements, (char *)p, len);
+               if (message->elements[nelem].name == NULL) {
                        errno = ENOMEM;
                        goto failed;
                }
                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,
+               message->elements[nelem].num_values = pull_uint32(p, 0);
+               message->elements[nelem].values = NULL;
+               if (message->elements[nelem].num_values != 0) {
+                       message->elements[nelem].values = talloc_array(message->elements,
                                                                     struct ldb_val,
-                                                                    message->elements[i].num_values);
-                       if (!message->elements[i].values) {
+                                                                    message->elements[nelem].num_values);
+                       if (!message->elements[nelem].values) {
                                errno = ENOMEM;
                                goto failed;
                        }
                }
                p += 4;
                remaining -= 4;
-               for (j=0;j<message->elements[i].num_values;j++) {
+               for (j=0;j<message->elements[nelem].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) {
+                       message->elements[nelem].values[j].length = len;
+                       message->elements[nelem].values[j].data = talloc_size(message->elements[nelem].values, len+1);
+                       if (message->elements[nelem].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(message->elements[nelem].values[j].data, p + 4,
+                              len);
+                       message->elements[nelem].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 +358,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);
+}
index b4359a74aae66b1c7d4bae1e5013c1e83c8997b7..c8301be8b0ed1a5bda70f0766b77ecb34ff125ae 100644 (file)
@@ -226,6 +226,13 @@ char *ldb_ldif_write_redacted_trace_string(struct ldb_context *ldb, TALLOC_CTX *
 int ldb_pack_data(struct ldb_context *ldb,
                  const struct ldb_message *message,
                  struct ldb_val *data);
+
+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_attributes_indb);
 int ldb_unpack_data(struct ldb_context *ldb,
                    const struct ldb_val *data,
                    struct ldb_message *message);