s4:ldb Remove LTDB_PACKING_FORMAT_NODN
[Samba/gebeck_regimport.git] / source4 / lib / ldb / ldb_tdb / ldb_pack.c
blob7fe61c020ab15345f19a9af4e7a18b1ce864f921
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 /* use a portable integer format */
40 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
42 p += ofs;
43 p[0] = val&0xFF;
44 p[1] = (val>>8) & 0xFF;
45 p[2] = (val>>16) & 0xFF;
46 p[3] = (val>>24) & 0xFF;
49 static unsigned int pull_uint32(uint8_t *p, int ofs)
51 p += ofs;
52 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
55 static int attribute_storable_values(const struct ldb_message_element *el)
57 if (el->num_values == 0) return 0;
59 if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
61 if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
63 return el->num_values;
67 pack a ldb message into a linear buffer in a TDB_DATA
69 note that this routine avoids saving elements with zero values,
70 as these are equivalent to having no element
72 caller frees the data buffer after use
74 int ltdb_pack_data(struct ldb_module *module,
75 const struct ldb_message *message,
76 struct TDB_DATA *data)
78 struct ldb_context *ldb;
79 unsigned int i, j, real_elements=0;
80 size_t size;
81 const char *dn;
82 uint8_t *p;
83 size_t len;
85 ldb = ldb_module_get_ctx(module);
87 dn = ldb_dn_get_linearized(message->dn);
88 if (dn == NULL) {
89 errno = ENOMEM;
90 return -1;
93 /* work out how big it needs to be */
94 size = 8;
96 size += 1 + strlen(dn);
98 for (i=0;i<message->num_elements;i++) {
99 if (attribute_storable_values(&message->elements[i]) == 0) {
100 continue;
103 real_elements++;
105 size += 1 + strlen(message->elements[i].name) + 4;
106 for (j=0;j<message->elements[i].num_values;j++) {
107 size += 4 + message->elements[i].values[j].length + 1;
111 /* allocate it */
112 data->dptr = talloc_array(ldb, uint8_t, size);
113 if (!data->dptr) {
114 errno = ENOMEM;
115 return -1;
117 data->dsize = size;
119 p = data->dptr;
120 put_uint32(p, 0, LTDB_PACKING_FORMAT);
121 put_uint32(p, 4, real_elements);
122 p += 8;
124 /* the dn needs to be packed so we can be case preserving
125 while hashing on a case folded dn */
126 len = strlen(dn);
127 memcpy(p, dn, len+1);
128 p += len + 1;
130 for (i=0;i<message->num_elements;i++) {
131 if (attribute_storable_values(&message->elements[i]) == 0) {
132 continue;
134 len = strlen(message->elements[i].name);
135 memcpy(p, message->elements[i].name, len+1);
136 p += len + 1;
137 put_uint32(p, 0, message->elements[i].num_values);
138 p += 4;
139 for (j=0;j<message->elements[i].num_values;j++) {
140 put_uint32(p, 0, message->elements[i].values[j].length);
141 memcpy(p+4, message->elements[i].values[j].data,
142 message->elements[i].values[j].length);
143 p[4+message->elements[i].values[j].length] = 0;
144 p += 4 + message->elements[i].values[j].length + 1;
148 return 0;
152 unpack a ldb message from a linear buffer in TDB_DATA
154 Free with ltdb_unpack_data_free()
156 int ltdb_unpack_data(struct ldb_module *module,
157 const struct TDB_DATA *data,
158 struct ldb_message *message)
160 struct ldb_context *ldb;
161 uint8_t *p;
162 unsigned int remaining;
163 unsigned int i, j;
164 unsigned format;
165 size_t len;
167 ldb = ldb_module_get_ctx(module);
168 message->elements = NULL;
170 p = data->dptr;
171 if (data->dsize < 8) {
172 errno = EIO;
173 goto failed;
176 format = pull_uint32(p, 0);
177 message->num_elements = pull_uint32(p, 4);
178 p += 8;
180 remaining = data->dsize - 8;
182 switch (format) {
183 case LTDB_PACKING_FORMAT:
184 len = strnlen((char *)p, remaining);
185 if (len == remaining) {
186 errno = EIO;
187 goto failed;
189 message->dn = ldb_dn_new(message, ldb, (char *)p);
190 if (message->dn == NULL) {
191 errno = ENOMEM;
192 goto failed;
194 remaining -= len + 1;
195 p += len + 1;
196 break;
198 default:
199 errno = EIO;
200 goto failed;
203 if (message->num_elements == 0) {
204 message->elements = NULL;
205 return 0;
208 if (message->num_elements > remaining / 6) {
209 errno = EIO;
210 goto failed;
213 message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
214 if (!message->elements) {
215 errno = ENOMEM;
216 goto failed;
219 memset(message->elements, 0,
220 message->num_elements * sizeof(struct ldb_message_element));
222 for (i=0;i<message->num_elements;i++) {
223 if (remaining < 10) {
224 errno = EIO;
225 goto failed;
227 len = strnlen((char *)p, remaining-6);
228 if (len == remaining-6) {
229 errno = EIO;
230 goto failed;
232 if (len == 0) {
233 errno = EIO;
234 goto failed;
236 message->elements[i].flags = 0;
237 message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
238 if (message->elements[i].name == NULL) {
239 errno = ENOMEM;
240 goto failed;
242 remaining -= len + 1;
243 p += len + 1;
244 message->elements[i].num_values = pull_uint32(p, 0);
245 message->elements[i].values = NULL;
246 if (message->elements[i].num_values != 0) {
247 message->elements[i].values = talloc_array(message->elements,
248 struct ldb_val,
249 message->elements[i].num_values);
250 if (!message->elements[i].values) {
251 errno = ENOMEM;
252 goto failed;
255 p += 4;
256 remaining -= 4;
257 for (j=0;j<message->elements[i].num_values;j++) {
258 len = pull_uint32(p, 0);
259 if (len > remaining-5) {
260 errno = EIO;
261 goto failed;
264 message->elements[i].values[j].length = len;
265 message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
266 if (message->elements[i].values[j].data == NULL) {
267 errno = ENOMEM;
268 goto failed;
270 memcpy(message->elements[i].values[j].data, p+4, len);
271 message->elements[i].values[j].data[len] = 0;
273 remaining -= len+4+1;
274 p += len+4+1;
278 if (remaining != 0) {
279 ldb_debug(ldb, LDB_DEBUG_ERROR,
280 "Error: %d bytes unread in ltdb_unpack_data", remaining);
283 return 0;
285 failed:
286 talloc_free(message->elements);
287 return -1;