s4-ldb: cope better with corruption of tdb records
[Samba/aatanasov.git] / source4 / lib / ldb / ldb_tdb / ldb_pack.c
blobe7aeb47e72d8bf4d627092004786a8848d44ff26
1 /*
2 ldb database library
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
8 ** under the LGPL
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/>.
25 * Name: ldb
27 * Component: ldb pack/unpack
29 * Description: pack/unpack routines for ldb messages as key/value blobs
31 * Author: Andrew Tridgell
34 #include "ldb_tdb.h"
36 /* change this if the data format ever changes */
37 #define LTDB_PACKING_FORMAT 0x26011967
39 /* old packing formats */
40 #define LTDB_PACKING_FORMAT_NODN 0x26011966
42 /* use a portable integer format */
43 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
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;
52 static unsigned int pull_uint32(uint8_t *p, int ofs)
54 p += 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, "dn") == 0) return 0;
64 if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
66 return el->num_values;
70 pack a ldb message into a linear buffer in a TDB_DATA
72 note that this routine avoids saving elements with zero values,
73 as these are equivalent to having no element
75 caller frees the data buffer after use
77 int ltdb_pack_data(struct ldb_module *module,
78 const struct ldb_message *message,
79 struct TDB_DATA *data)
81 struct ldb_context *ldb;
82 unsigned int i, j, real_elements=0;
83 size_t size;
84 const char *dn;
85 uint8_t *p;
86 size_t len;
88 ldb = ldb_module_get_ctx(module);
90 dn = ldb_dn_get_linearized(message->dn);
91 if (dn == NULL) {
92 errno = ENOMEM;
93 return -1;
96 /* work out how big it needs to be */
97 size = 8;
99 size += 1 + strlen(dn);
101 for (i=0;i<message->num_elements;i++) {
102 if (attribute_storable_values(&message->elements[i]) == 0) {
103 continue;
106 real_elements++;
108 size += 1 + strlen(message->elements[i].name) + 4;
109 for (j=0;j<message->elements[i].num_values;j++) {
110 size += 4 + message->elements[i].values[j].length + 1;
114 /* allocate it */
115 data->dptr = talloc_array(ldb, uint8_t, size);
116 if (!data->dptr) {
117 errno = ENOMEM;
118 return -1;
120 data->dsize = size;
122 p = data->dptr;
123 put_uint32(p, 0, LTDB_PACKING_FORMAT);
124 put_uint32(p, 4, real_elements);
125 p += 8;
127 /* the dn needs to be packed so we can be case preserving
128 while hashing on a case folded dn */
129 len = strlen(dn);
130 memcpy(p, dn, len+1);
131 p += len + 1;
133 for (i=0;i<message->num_elements;i++) {
134 if (attribute_storable_values(&message->elements[i]) == 0) {
135 continue;
137 len = strlen(message->elements[i].name);
138 memcpy(p, message->elements[i].name, len+1);
139 p += len + 1;
140 put_uint32(p, 0, message->elements[i].num_values);
141 p += 4;
142 for (j=0;j<message->elements[i].num_values;j++) {
143 put_uint32(p, 0, message->elements[i].values[j].length);
144 memcpy(p+4, message->elements[i].values[j].data,
145 message->elements[i].values[j].length);
146 p[4+message->elements[i].values[j].length] = 0;
147 p += 4 + message->elements[i].values[j].length + 1;
151 return 0;
155 unpack a ldb message from a linear buffer in TDB_DATA
157 Free with ltdb_unpack_data_free()
159 int ltdb_unpack_data(struct ldb_module *module,
160 const struct TDB_DATA *data,
161 struct ldb_message *message)
163 struct ldb_context *ldb;
164 uint8_t *p;
165 unsigned int remaining;
166 unsigned int i, j;
167 unsigned format;
168 size_t len;
170 ldb = ldb_module_get_ctx(module);
171 message->elements = NULL;
173 p = data->dptr;
174 if (data->dsize < 8) {
175 errno = EIO;
176 goto failed;
179 format = pull_uint32(p, 0);
180 message->num_elements = pull_uint32(p, 4);
181 p += 8;
183 remaining = data->dsize - 8;
185 switch (format) {
186 case LTDB_PACKING_FORMAT_NODN:
187 message->dn = NULL;
188 break;
190 case LTDB_PACKING_FORMAT:
191 len = strnlen((char *)p, remaining);
192 if (len == remaining) {
193 errno = EIO;
194 goto failed;
196 message->dn = ldb_dn_new(message, ldb, (char *)p);
197 if (message->dn == NULL) {
198 errno = ENOMEM;
199 goto failed;
201 remaining -= len + 1;
202 p += len + 1;
203 break;
205 default:
206 errno = EIO;
207 goto failed;
210 if (message->num_elements == 0) {
211 message->elements = NULL;
212 return 0;
215 if (message->num_elements > remaining / 6) {
216 errno = EIO;
217 goto failed;
220 message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
221 if (!message->elements) {
222 errno = ENOMEM;
223 goto failed;
226 memset(message->elements, 0,
227 message->num_elements * sizeof(struct ldb_message_element));
229 for (i=0;i<message->num_elements;i++) {
230 if (remaining < 10) {
231 errno = EIO;
232 goto failed;
234 len = strnlen((char *)p, remaining-6);
235 if (len == remaining-6) {
236 errno = EIO;
237 goto failed;
239 if (len == 0) {
240 errno = EIO;
241 goto failed;
243 message->elements[i].flags = 0;
244 message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
245 if (message->elements[i].name == NULL) {
246 errno = ENOMEM;
247 goto failed;
249 remaining -= len + 1;
250 p += len + 1;
251 message->elements[i].num_values = pull_uint32(p, 0);
252 message->elements[i].values = NULL;
253 if (message->elements[i].num_values != 0) {
254 message->elements[i].values = talloc_array(message->elements,
255 struct ldb_val,
256 message->elements[i].num_values);
257 if (!message->elements[i].values) {
258 errno = ENOMEM;
259 goto failed;
262 p += 4;
263 remaining -= 4;
264 for (j=0;j<message->elements[i].num_values;j++) {
265 len = pull_uint32(p, 0);
266 if (len > remaining-5) {
267 errno = EIO;
268 goto failed;
271 message->elements[i].values[j].length = len;
272 message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
273 if (message->elements[i].values[j].data == NULL) {
274 errno = ENOMEM;
275 goto failed;
277 memcpy(message->elements[i].values[j].data, p+4, len);
278 message->elements[i].values[j].data[len] = 0;
280 remaining -= len+4+1;
281 p += len+4+1;
285 if (remaining != 0) {
286 ldb_debug(ldb, LDB_DEBUG_ERROR,
287 "Error: %d bytes unread in ltdb_unpack_data", remaining);
290 return 0;
292 failed:
293 talloc_free(message->elements);
294 return -1;