cc3a552758386d7c9116535171ae7b6fb73a9549
[metze/samba/wip.git] / lib / ldb / common / ldb_pack.c
1 /*
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
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.
14
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.
19
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/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb pack/unpack
28  *
29  *  Description: pack/unpack routines for ldb messages as key/value blobs
30  *
31  *  Author: Andrew Tridgell
32  */
33
34 #include "ldb_private.h"
35
36 /* change this if the data format ever changes */
37 #define LDB_PACKING_FORMAT 0x26011967
38
39 /* old packing formats */
40 #define LDB_PACKING_FORMAT_NODN 0x26011966
41
42 /* use a portable integer format */
43 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
44 {
45         p += ofs;
46         p[0] = val&0xFF;
47         p[1] = (val>>8)  & 0xFF;
48         p[2] = (val>>16) & 0xFF;
49         p[3] = (val>>24) & 0xFF;
50 }
51
52 static unsigned int pull_uint32(uint8_t *p, int ofs)
53 {
54         p += ofs;
55         return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
56 }
57
58 static int attribute_storable_values(const struct ldb_message_element *el)
59 {
60         if (el->num_values == 0) return 0;
61
62         if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
63
64         return el->num_values;
65 }
66
67 /*
68   pack a ldb message into a linear buffer in a ldb_val
69
70   note that this routine avoids saving elements with zero values,
71   as these are equivalent to having no element
72
73   caller frees the data buffer after use
74 */
75 int ldb_pack_data(struct ldb_context *ldb,
76                   const struct ldb_message *message,
77                   struct ldb_val *data)
78 {
79         unsigned int i, j, real_elements=0;
80         size_t size, dn_len, attr_len, value_len;
81         const char *dn;
82         uint8_t *p;
83         size_t len;
84
85         dn = ldb_dn_get_linearized(message->dn);
86         if (dn == NULL) {
87                 errno = ENOMEM;
88                 return -1;
89         }
90
91         /* work out how big it needs to be */
92         size = 8;
93
94         size += 1;
95
96         dn_len = strlen(dn);
97         if (size + dn_len < size) {
98                 errno = ENOMEM;
99                 return -1;
100         }
101         size += dn_len;
102
103         /*
104          * First calcuate the buffer size we need, and check for
105          * overflows
106          */
107         for (i=0;i<message->num_elements;i++) {
108                 if (attribute_storable_values(&message->elements[i]) == 0) {
109                         continue;
110                 }
111
112                 real_elements++;
113
114                 if (size + 5 < size) {
115                         errno = ENOMEM;
116                         return -1;
117                 }
118                 size += 5;
119
120                 attr_len = strlen(message->elements[i].name);
121                 if (size + attr_len < size) {
122                         errno = ENOMEM;
123                         return -1;
124                 }
125                 size += attr_len;
126
127                 for (j=0;j<message->elements[i].num_values;j++) {
128                         if (size + 5 < size) {
129                                 errno = ENOMEM;
130                                 return -1;
131                         }
132                         size += 5;
133
134                         value_len = message->elements[i].values[j].length;
135                         if (size + value_len < size) {
136                                 errno = ENOMEM;
137                                 return -1;
138                         }
139                         size += value_len;
140                 }
141         }
142
143         /* allocate it */
144         data->data = talloc_array(ldb, uint8_t, size);
145         if (!data->data) {
146                 errno = ENOMEM;
147                 return -1;
148         }
149         data->length = size;
150
151         p = data->data;
152         put_uint32(p, 0, LDB_PACKING_FORMAT);
153         put_uint32(p, 4, real_elements);
154         p += 8;
155
156         /* the dn needs to be packed so we can be case preserving
157            while hashing on a case folded dn */
158         len = dn_len;
159         memcpy(p, dn, len+1);
160         p += len + 1;
161
162         for (i=0;i<message->num_elements;i++) {
163                 if (attribute_storable_values(&message->elements[i]) == 0) {
164                         continue;
165                 }
166                 len = strlen(message->elements[i].name);
167                 memcpy(p, message->elements[i].name, len+1);
168                 p += len + 1;
169                 put_uint32(p, 0, message->elements[i].num_values);
170                 p += 4;
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;
177                 }
178         }
179
180         return 0;
181 }
182
183 static bool ldb_consume_element_data(uint8_t **pp, size_t *premaining)
184 {
185         unsigned int remaining = *premaining;
186         uint8_t *p = *pp;
187         uint32_t num_values = pull_uint32(p, 0);
188         uint32_t len;
189         int j;
190
191         p += 4;
192         if (remaining < 4) {
193                 return false;
194         }
195         remaining -= 4;
196         for (j = 0; j < num_values; j++) {
197                 len = pull_uint32(p, 0);
198                 if (remaining < 5) {
199                         return false;
200                 }
201                 remaining -= 5;
202                 if (len > remaining) {
203                         return false;
204                 }
205                 remaining -= len;
206                 p += len + 4 + 1;
207         }
208
209         *premaining = remaining;
210         *pp = p;
211         return true;
212 }
213
214
215 /*
216  * Unpack a ldb message from a linear buffer in ldb_val
217  *
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.
220  */
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,
226                                          unsigned int flags,
227                                          unsigned int *nb_elements_in_db)
228 {
229         uint8_t *p;
230         size_t remaining;
231         size_t dn_len;
232         unsigned int i, j;
233         unsigned format;
234         unsigned int nelem = 0;
235         size_t len;
236         unsigned int found = 0;
237
238         if (list == NULL) {
239                 list_size = 0;
240         }
241
242         message->elements = NULL;
243
244         p = data->data;
245         if (data->length < 8) {
246                 errno = EIO;
247                 goto failed;
248         }
249
250         format = pull_uint32(p, 0);
251         message->num_elements = pull_uint32(p, 4);
252         p += 8;
253         if (nb_elements_in_db) {
254                 *nb_elements_in_db = message->num_elements;
255         }
256
257         remaining = data->length - 8;
258
259         switch (format) {
260         case LDB_PACKING_FORMAT_NODN:
261                 message->dn = NULL;
262                 break;
263
264         case LDB_PACKING_FORMAT:
265                 /*
266                  * With this check, we know that the DN at p is \0
267                  * terminated.
268                  */
269                 dn_len = strnlen((char *)p, remaining);
270                 if (dn_len == remaining) {
271                         errno = EIO;
272                         goto failed;
273                 }
274                 if (flags & LDB_UNPACK_DATA_FLAG_NO_DN) {
275                         message->dn = NULL;
276                 } else {
277                         message->dn = ldb_dn_new(message, ldb, (char *)p);
278                         if (message->dn == NULL) {
279                                 errno = ENOMEM;
280                                 goto failed;
281                         }
282                 }
283                 /*
284                  * Redundant: by definition, remaining must be more
285                  * than one less than dn_len, as otherwise it would be
286                  * == dn_len
287                  */
288                 if (remaining < dn_len + 1) {
289                         errno = EIO;
290                         goto failed;
291                 }
292                 remaining -= dn_len + 1;
293                 p += dn_len + 1;
294                 break;
295
296         default:
297                 errno = EIO;
298                 goto failed;
299         }
300
301         if (message->num_elements == 0) {
302                 return 0;
303         }
304
305         if (message->num_elements > remaining / 6) {
306                 errno = EIO;
307                 goto failed;
308         }
309
310         message->elements = talloc_zero_array(message, struct ldb_message_element,
311                                               message->num_elements);
312         if (!message->elements) {
313                 errno = ENOMEM;
314                 goto failed;
315         }
316
317         for (i=0;i<message->num_elements;i++) {
318                 const char *attr = NULL;
319                 size_t attr_len;
320                 struct ldb_message_element *element = NULL;
321
322                 if (remaining < 10) {
323                         errno = EIO;
324                         goto failed;
325                 }
326                 /*
327                  * With this check, we know that the attribute name at
328                  * p is \0 terminated.
329                  */
330                 attr_len = strnlen((char *)p, remaining-6);
331                 if (attr_len == remaining-6) {
332                         errno = EIO;
333                         goto failed;
334                 }
335                 if (attr_len == 0) {
336                         errno = EIO;
337                         goto failed;
338                 }
339                 attr = (char *)p;
340
341                 /*
342                  * The general idea is to reduce allocations by skipping over
343                  * attributes that we do not actually care about.
344                  *
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.
348                  */
349                 if (list_size != 0) {
350                         bool keep = false;
351                         int h;
352
353                         /*
354                          * We know that p has a \0 terminator before the
355                          * end of the buffer due to the check above.
356                          */
357                         for (h = 0; h < list_size && found < list_size; h++) {
358                                 if (ldb_attr_cmp(attr, list[h]) == 0) {
359                                         keep = true;
360                                         found++;
361                                         break;
362                                 }
363                         }
364
365                         if (!keep) {
366                                 if (remaining < (attr_len + 1)) {
367                                         errno = EIO;
368                                         goto failed;
369                                 }
370                                 remaining -= attr_len + 1;
371                                 p += attr_len + 1;
372                                 if (!ldb_consume_element_data(&p, &remaining)) {
373                                         errno = EIO;
374                                         goto failed;
375                                 }
376                                 continue;
377                         }
378                 }
379                 element = &message->elements[nelem];
380                 if (flags & LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC) {
381                         element->name = attr;
382                 } else {
383                         element->name = talloc_memdup(message->elements, attr, attr_len+1);
384
385                         if (element->name == NULL) {
386                                 errno = ENOMEM;
387                                 goto failed;
388                         }
389                 }
390                 element->flags = 0;
391
392                 if (remaining < (attr_len + 1)) {
393                         errno = EIO;
394                         goto failed;
395                 }
396                 remaining -= attr_len + 1;
397                 p += 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,
402                                                        struct ldb_val,
403                                                        element->num_values);
404                         if (!element->values) {
405                                 errno = ENOMEM;
406                                 goto failed;
407                         }
408                 }
409                 p += 4;
410                 if (remaining < 4) {
411                         errno = EIO;
412                         goto failed;
413                 }
414                 remaining -= 4;
415                 for (j = 0; j < element->num_values; j++) {
416                         if (remaining < 5) {
417                                 errno = EIO;
418                                 goto failed;
419                         }
420                         remaining -= 5;
421
422                         len = pull_uint32(p, 0);
423                         if (remaining < len) {
424                                 errno = EIO;
425                                 goto failed;
426                         }
427                         if (len + 1 < len) {
428                                 errno = EIO;
429                                 goto failed;
430                         }
431
432                         element->values[j].length = len;
433                         if (flags & LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC) {
434                                 element->values[j].data = p + 4;
435                         } else {
436                                 element->values[j].data = talloc_size(element->values, len+1);
437                                 if (element->values[j].data == NULL) {
438                                         errno = ENOMEM;
439                                         goto failed;
440                                 }
441                                 memcpy(element->values[j].data, p + 4,
442                                        len);
443                                 element->values[j].data[len] = 0;
444                         }
445                         remaining -= len;
446                         p += len+4+1;
447                 }
448                 nelem++;
449         }
450         /*
451          * Adapt the number of elements to the real number of unpacked elements,
452          * it means that we overallocated elements array.
453          */
454         message->num_elements = nelem;
455
456         /*
457          * Shrink the allocated size.  On current talloc behaviour
458          * this will help if we skipped 32 or more attributes.
459          */
460         message->elements = talloc_realloc(message, message->elements,
461                                            struct ldb_message_element,
462                                            message->num_elements);
463
464         if (remaining != 0) {
465                 ldb_debug(ldb, LDB_DEBUG_ERROR,
466                           "Error: %zu bytes unread in ldb_unpack_data_only_attr_list",
467                           remaining);
468         }
469
470         return 0;
471
472 failed:
473         talloc_free(message->elements);
474         return -1;
475 }
476
477 /*
478  * Unpack a ldb message from a linear buffer in ldb_val
479  *
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.
482  *
483  * Free with ldb_unpack_data_free()
484  */
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)
491 {
492         return ldb_unpack_data_only_attr_list_flags(ldb,
493                                                     data,
494                                                     message,
495                                                     list,
496                                                     list_size,
497                                                     0,
498                                                     nb_elements_in_db);
499 }
500
501 int ldb_unpack_data(struct ldb_context *ldb,
502                     const struct ldb_val *data,
503                     struct ldb_message *message)
504 {
505         return ldb_unpack_data_only_attr_list(ldb, data, message, NULL, 0, NULL);
506 }