5524542dcd9255ab9c9492515e2a75bf0091b05d
[nivanova/samba-autobuild/.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;
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 + strlen(dn);
95
96         for (i=0;i<message->num_elements;i++) {
97                 if (attribute_storable_values(&message->elements[i]) == 0) {
98                         continue;
99                 }
100
101                 real_elements++;
102
103                 size += 1 + strlen(message->elements[i].name) + 4;
104                 for (j=0;j<message->elements[i].num_values;j++) {
105                         size += 4 + message->elements[i].values[j].length + 1;
106                 }
107         }
108
109         /* allocate it */
110         data->data = talloc_array(ldb, uint8_t, size);
111         if (!data->data) {
112                 errno = ENOMEM;
113                 return -1;
114         }
115         data->length = size;
116
117         p = data->data;
118         put_uint32(p, 0, LDB_PACKING_FORMAT);
119         put_uint32(p, 4, real_elements);
120         p += 8;
121
122         /* the dn needs to be packed so we can be case preserving
123            while hashing on a case folded dn */
124         len = strlen(dn);
125         memcpy(p, dn, len+1);
126         p += len + 1;
127
128         for (i=0;i<message->num_elements;i++) {
129                 if (attribute_storable_values(&message->elements[i]) == 0) {
130                         continue;
131                 }
132                 len = strlen(message->elements[i].name);
133                 memcpy(p, message->elements[i].name, len+1);
134                 p += len + 1;
135                 put_uint32(p, 0, message->elements[i].num_values);
136                 p += 4;
137                 for (j=0;j<message->elements[i].num_values;j++) {
138                         put_uint32(p, 0, message->elements[i].values[j].length);
139                         memcpy(p+4, message->elements[i].values[j].data,
140                                message->elements[i].values[j].length);
141                         p[4+message->elements[i].values[j].length] = 0;
142                         p += 4 + message->elements[i].values[j].length + 1;
143                 }
144         }
145
146         return 0;
147 }
148
149 static bool ldb_consume_element_data(uint8_t **pp, unsigned int *premaining)
150 {
151         unsigned int remaining = *premaining;
152         uint8_t *p = *pp;
153         uint32_t num_values = pull_uint32(p, 0);
154         uint32_t len;
155         int j;
156
157         p += 4;
158         remaining -= 4;
159         for (j = 0; j < num_values; j++) {
160                 len = pull_uint32(p, 0);
161                 if (len > remaining - 5) {
162                         return false;
163                 }
164                 remaining -= len + 4 + 1;
165                 p += len + 4 + 1;
166         }
167
168         *premaining = remaining;
169         *pp = p;
170         return true;
171 }
172 /*
173   unpack a ldb message from a linear buffer in ldb_val
174
175   Free with ldb_unpack_data_free()
176 */
177 int ldb_unpack_data_withlist(struct ldb_context *ldb,
178                              const struct ldb_val *data,
179                              struct ldb_message *message,
180                              const char * const *list,
181                              unsigned int list_size,
182                              unsigned int *nb_elements_in_db)
183 {
184         uint8_t *p;
185         unsigned int remaining;
186         unsigned int i, j;
187         unsigned format;
188         unsigned int nelem = 0;
189         size_t len;
190         unsigned int found = 0;
191
192         if (list == NULL) {
193                 list_size = 0;
194         }
195
196         message->elements = NULL;
197
198         p = data->data;
199         if (data->length < 8) {
200                 errno = EIO;
201                 goto failed;
202         }
203
204         format = pull_uint32(p, 0);
205         message->num_elements = pull_uint32(p, 4);
206         p += 8;
207         if (nb_elements_in_db) {
208                 *nb_elements_in_db = message->num_elements;
209         }
210
211         remaining = data->length - 8;
212
213         switch (format) {
214         case LDB_PACKING_FORMAT_NODN:
215                 message->dn = NULL;
216                 break;
217
218         case LDB_PACKING_FORMAT:
219                 len = strnlen((char *)p, remaining);
220                 if (len == remaining) {
221                         errno = EIO;
222                         goto failed;
223                 }
224                 message->dn = ldb_dn_new(message, ldb, (char *)p);
225                 if (message->dn == NULL) {
226                         errno = ENOMEM;
227                         goto failed;
228                 }
229                 remaining -= len + 1;
230                 p += len + 1;
231                 break;
232
233         default:
234                 errno = EIO;
235                 goto failed;
236         }
237
238         if (message->num_elements == 0) {
239                 return 0;
240         }
241
242         if (message->num_elements > remaining / 6) {
243                 errno = EIO;
244                 goto failed;
245         }
246
247         message->elements = talloc_array(message, struct ldb_message_element,
248                                          message->num_elements);
249         if (!message->elements) {
250                 errno = ENOMEM;
251                 goto failed;
252         }
253
254         memset(message->elements, 0,
255                message->num_elements * sizeof(struct ldb_message_element));
256
257         for (i=0;i<message->num_elements;i++) {
258                 const char *attr = NULL;
259                 struct ldb_message_element *element = NULL;
260
261                 if (remaining < 10) {
262                         errno = EIO;
263                         goto failed;
264                 }
265                 len = strnlen((char *)p, remaining-6);
266                 if (len == remaining-6) {
267                         errno = EIO;
268                         goto failed;
269                 }
270                 if (len == 0) {
271                         errno = EIO;
272                         goto failed;
273                 }
274                 attr = (char *)p;
275                 /*
276                  * This is a bit expensive but normally the list is pretty small
277                  * also the cost of freeing unused attributes is quite important
278                  * and can dwarf the cost of looping
279                  */
280                 if (list_size != 0) {
281                         bool keep = false;
282                         int h;
283
284                         /*
285                          * We know that p has a \0 terminator before the
286                          * end of the buffer due to the check above.
287                          */
288                         for (h = 0; h < list_size && found < list_size; h++) {
289                                 if (ldb_attr_cmp(attr, list[h]) == 0) {
290                                         keep = true;
291                                         found++;
292                                         break;
293                                 }
294                         }
295
296                         if (!keep) {
297                                 remaining -= len + 1;
298                                 p += len + 1;
299                                 if (!ldb_consume_element_data(&p, &remaining)) {
300                                         errno = EIO;
301                                         goto failed;
302                                 }
303                                 continue;
304                         }
305                 }
306                 element = &message->elements[nelem];
307                 element->name = talloc_strndup(message->elements, (char *)p, len);
308                 if (element->name == NULL) {
309                         errno = ENOMEM;
310                         goto failed;
311                 }
312                 element->flags = 0;
313                 remaining -= len + 1;
314                 p += len + 1;
315                 element->num_values = pull_uint32(p, 0);
316                 element->values = NULL;
317                 if (element->num_values != 0) {
318                         element->values = talloc_array(message->elements,
319                                                        struct ldb_val,
320                                                        element->num_values);
321                         if (!element->values) {
322                                 errno = ENOMEM;
323                                 goto failed;
324                         }
325                 }
326                 p += 4;
327                 remaining -= 4;
328                 for (j = 0; j < element->num_values; j++) {
329                         len = pull_uint32(p, 0);
330                         if (len > remaining-5) {
331                                 errno = EIO;
332                                 goto failed;
333                         }
334
335                         element->values[j].length = len;
336                         element->values[j].data = talloc_size(element->values, len+1);
337                         if (element->values[j].data == NULL) {
338                                 errno = ENOMEM;
339                                 goto failed;
340                         }
341                         memcpy(element->values[j].data, p + 4,
342                                len);
343                         element->values[j].data[len] = 0;
344
345                         remaining -= len+4+1;
346                         p += len+4+1;
347                 }
348                 nelem++;
349         }
350         /*
351          * Adapt the number of elements to the real number of unpacked elements,
352          * it means that we overallocated elements array, I guess it's not that
353          * bad.
354          */
355         message->num_elements = nelem;
356
357         if (remaining != 0) {
358                 ldb_debug(ldb, LDB_DEBUG_ERROR,
359                           "Error: %d bytes unread in ldb_unpack_data_withlist",
360                           remaining);
361         }
362
363         return 0;
364
365 failed:
366         talloc_free(message->elements);
367         return -1;
368 }
369
370 int ldb_unpack_data(struct ldb_context *ldb,
371                     const struct ldb_val *data,
372                     struct ldb_message *message)
373 {
374         return ldb_unpack_data_withlist(ldb, data, message, NULL, 0, NULL);
375 }