4 Copyright (C) Andrew Tridgell 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb pack/unpack
29 * Description: pack/unpack routines for ldb messages as key/value blobs
31 * Author: Andrew Tridgell
34 #include "ldb_private.h"
36 /* change this if the data format ever changes */
37 #define LDB_PACKING_FORMAT 0x26011967
39 /* old packing formats */
40 #define LDB_PACKING_FORMAT_NODN 0x26011966
42 /* use a portable integer format */
43 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
47 p[1] = (val>>8) & 0xFF;
48 p[2] = (val>>16) & 0xFF;
49 p[3] = (val>>24) & 0xFF;
52 static unsigned int pull_uint32(uint8_t *p, int ofs)
55 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
58 static int attribute_storable_values(const struct ldb_message_element *el)
60 if (el->num_values == 0) return 0;
62 if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
64 return el->num_values;
68 pack a ldb message into a linear buffer in a ldb_val
70 note that this routine avoids saving elements with zero values,
71 as these are equivalent to having no element
73 caller frees the data buffer after use
75 int ldb_pack_data(struct ldb_context *ldb,
76 const struct ldb_message *message,
79 unsigned int i, j, real_elements=0;
80 size_t size, dn_len, attr_len, value_len;
85 dn = ldb_dn_get_linearized(message->dn);
91 /* work out how big it needs to be */
97 if (size + dn_len < size) {
104 * First calcuate the buffer size we need, and check for
107 for (i=0;i<message->num_elements;i++) {
108 if (attribute_storable_values(&message->elements[i]) == 0) {
114 if (size + 5 < size) {
120 attr_len = strlen(message->elements[i].name);
121 if (size + attr_len < size) {
127 for (j=0;j<message->elements[i].num_values;j++) {
128 if (size + 5 < size) {
134 value_len = message->elements[i].values[j].length;
135 if (size + value_len < size) {
144 data->data = talloc_array(ldb, uint8_t, size);
152 put_uint32(p, 0, LDB_PACKING_FORMAT);
153 put_uint32(p, 4, real_elements);
156 /* the dn needs to be packed so we can be case preserving
157 while hashing on a case folded dn */
159 memcpy(p, dn, len+1);
162 for (i=0;i<message->num_elements;i++) {
163 if (attribute_storable_values(&message->elements[i]) == 0) {
166 len = strlen(message->elements[i].name);
167 memcpy(p, message->elements[i].name, len+1);
169 put_uint32(p, 0, message->elements[i].num_values);
171 for (j=0;j<message->elements[i].num_values;j++) {
172 put_uint32(p, 0, message->elements[i].values[j].length);
173 memcpy(p+4, message->elements[i].values[j].data,
174 message->elements[i].values[j].length);
175 p[4+message->elements[i].values[j].length] = 0;
176 p += 4 + message->elements[i].values[j].length + 1;
183 static bool ldb_consume_element_data(uint8_t **pp, size_t *premaining)
185 unsigned int remaining = *premaining;
187 uint32_t num_values = pull_uint32(p, 0);
196 for (j = 0; j < num_values; j++) {
197 len = pull_uint32(p, 0);
202 if (len > remaining) {
209 *premaining = remaining;
216 * Unpack a ldb message from a linear buffer in ldb_val
218 * Providing a list of attributes to this function allows selective unpacking.
219 * Giving a NULL list (or a list_size of 0) unpacks all the attributes.
221 int ldb_unpack_data_only_attr_list_flags(struct ldb_context *ldb,
222 const struct ldb_val *data,
223 struct ldb_message *message,
224 const char * const *list,
225 unsigned int list_size,
227 unsigned int *nb_elements_in_db)
234 unsigned int nelem = 0;
236 unsigned int found = 0;
242 message->elements = NULL;
245 if (data->length < 8) {
250 format = pull_uint32(p, 0);
251 message->num_elements = pull_uint32(p, 4);
253 if (nb_elements_in_db) {
254 *nb_elements_in_db = message->num_elements;
257 remaining = data->length - 8;
260 case LDB_PACKING_FORMAT_NODN:
264 case LDB_PACKING_FORMAT:
266 * With this check, we know that the DN at p is \0
269 dn_len = strnlen((char *)p, remaining);
270 if (dn_len == remaining) {
274 if (flags & LDB_UNPACK_DATA_FLAG_NO_DN) {
277 message->dn = ldb_dn_new(message, ldb, (char *)p);
278 if (message->dn == NULL) {
284 * Redundant: by definition, remaining must be more
285 * than one less than dn_len, as otherwise it would be
288 if (remaining < dn_len + 1) {
292 remaining -= dn_len + 1;
301 if (message->num_elements == 0) {
305 if (message->num_elements > remaining / 6) {
310 message->elements = talloc_zero_array(message, struct ldb_message_element,
311 message->num_elements);
312 if (!message->elements) {
317 for (i=0;i<message->num_elements;i++) {
318 const char *attr = NULL;
320 struct ldb_message_element *element = NULL;
322 if (remaining < 10) {
327 * With this check, we know that the attribute name at
328 * p is \0 terminated.
330 attr_len = strnlen((char *)p, remaining-6);
331 if (attr_len == remaining-6) {
342 * The general idea is to reduce allocations by skipping over
343 * attributes that we do not actually care about.
345 * This is a bit expensive but normally the list is pretty small
346 * also the cost of freeing unused attributes is quite important
347 * and can dwarf the cost of looping.
349 if (list_size != 0) {
354 * We know that p has a \0 terminator before the
355 * end of the buffer due to the check above.
357 for (h = 0; h < list_size && found < list_size; h++) {
358 if (ldb_attr_cmp(attr, list[h]) == 0) {
366 if (remaining < (attr_len + 1)) {
370 remaining -= attr_len + 1;
372 if (!ldb_consume_element_data(&p, &remaining)) {
379 element = &message->elements[nelem];
380 if (flags & LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC) {
381 element->name = attr;
383 element->name = talloc_memdup(message->elements, attr, attr_len+1);
385 if (element->name == NULL) {
392 if (remaining < (attr_len + 1)) {
396 remaining -= attr_len + 1;
398 element->num_values = pull_uint32(p, 0);
399 element->values = NULL;
400 if (element->num_values != 0) {
401 element->values = talloc_array(message->elements,
403 element->num_values);
404 if (!element->values) {
415 for (j = 0; j < element->num_values; j++) {
422 len = pull_uint32(p, 0);
423 if (remaining < len) {
432 element->values[j].length = len;
433 if (flags & LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC) {
434 element->values[j].data = p + 4;
436 element->values[j].data = talloc_size(element->values, len+1);
437 if (element->values[j].data == NULL) {
441 memcpy(element->values[j].data, p + 4,
443 element->values[j].data[len] = 0;
451 * Adapt the number of elements to the real number of unpacked elements,
452 * it means that we overallocated elements array.
454 message->num_elements = nelem;
457 * Shrink the allocated size. On current talloc behaviour
458 * this will help if we skipped 32 or more attributes.
460 message->elements = talloc_realloc(message, message->elements,
461 struct ldb_message_element,
462 message->num_elements);
464 if (remaining != 0) {
465 ldb_debug(ldb, LDB_DEBUG_ERROR,
466 "Error: %zu bytes unread in ldb_unpack_data_only_attr_list",
473 talloc_free(message->elements);
478 * Unpack a ldb message from a linear buffer in ldb_val
480 * Providing a list of attributes to this function allows selective unpacking.
481 * Giving a NULL list (or a list_size of 0) unpacks all the attributes.
483 * Free with ldb_unpack_data_free()
485 int ldb_unpack_data_only_attr_list(struct ldb_context *ldb,
486 const struct ldb_val *data,
487 struct ldb_message *message,
488 const char * const *list,
489 unsigned int list_size,
490 unsigned int *nb_elements_in_db)
492 return ldb_unpack_data_only_attr_list_flags(ldb,
501 int ldb_unpack_data(struct ldb_context *ldb,
502 const struct ldb_val *data,
503 struct ldb_message *message)
505 return ldb_unpack_data_only_attr_list(ldb, data, message, NULL, 0, NULL);