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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb pack/unpack
30 * Description: pack/unpack routines for ldb messages as key/value blobs
32 * Author: Andrew Tridgell
35 #include "ldb_includes.h"
38 /* change this if the data format ever changes */
39 #define LTDB_PACKING_FORMAT 0x26011967
41 /* old packing formats */
42 #define LTDB_PACKING_FORMAT_NODN 0x26011966
44 /* use a portable integer format */
45 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
49 p[1] = (val>>8) & 0xFF;
50 p[2] = (val>>16) & 0xFF;
51 p[3] = (val>>24) & 0xFF;
54 static unsigned int pull_uint32(uint8_t *p, int ofs)
57 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
60 static int attribute_storable_values(const struct ldb_message_element *el)
62 if (el->num_values == 0) return 0;
64 if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
66 if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
68 return el->num_values;
72 pack a ldb message into a linear buffer in a TDB_DATA
74 note that this routine avoids saving elements with zero values,
75 as these are equivalent to having no element
77 caller frees the data buffer after use
79 int ltdb_pack_data(struct ldb_module *module,
80 const struct ldb_message *message,
81 struct TDB_DATA *data)
83 struct ldb_context *ldb = module->ldb;
84 unsigned int i, j, real_elements=0;
90 dn = ldb_dn_get_linearized(message->dn);
96 /* work out how big it needs to be */
99 size += 1 + strlen(dn);
101 for (i=0;i<message->num_elements;i++) {
102 if (attribute_storable_values(&message->elements[i]) == 0) {
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;
115 data->dptr = talloc_array(ldb, uint8_t, size);
123 put_uint32(p, 0, LTDB_PACKING_FORMAT);
124 put_uint32(p, 4, real_elements);
127 /* the dn needs to be packed so we can be case preserving
128 while hashing on a case folded dn */
130 memcpy(p, dn, len+1);
133 for (i=0;i<message->num_elements;i++) {
134 if (attribute_storable_values(&message->elements[i]) == 0) {
137 len = strlen(message->elements[i].name);
138 memcpy(p, message->elements[i].name, len+1);
140 put_uint32(p, 0, message->elements[i].num_values);
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;
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 = module->ldb;
165 unsigned int remaining;
170 message->elements = NULL;
173 if (data->dsize < 8) {
178 format = pull_uint32(p, 0);
179 message->num_elements = pull_uint32(p, 4);
182 remaining = data->dsize - 8;
185 case LTDB_PACKING_FORMAT_NODN:
189 case LTDB_PACKING_FORMAT:
190 len = strnlen((char *)p, remaining);
191 if (len == remaining) {
195 message->dn = ldb_dn_new(message, ldb, (char *)p);
196 if (message->dn == NULL) {
200 remaining -= len + 1;
209 if (message->num_elements == 0) {
210 message->elements = NULL;
214 if (message->num_elements > remaining / 6) {
219 message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
220 if (!message->elements) {
225 memset(message->elements, 0,
226 message->num_elements * sizeof(struct ldb_message_element));
228 for (i=0;i<message->num_elements;i++) {
229 if (remaining < 10) {
233 len = strnlen((char *)p, remaining-6);
234 if (len == remaining-6) {
238 message->elements[i].flags = 0;
239 message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
240 if (message->elements[i].name == NULL) {
244 remaining -= len + 1;
246 message->elements[i].num_values = pull_uint32(p, 0);
247 message->elements[i].values = NULL;
248 if (message->elements[i].num_values != 0) {
249 message->elements[i].values = talloc_array(message->elements,
251 message->elements[i].num_values);
252 if (!message->elements[i].values) {
259 for (j=0;j<message->elements[i].num_values;j++) {
260 len = pull_uint32(p, 0);
261 if (len > remaining-5) {
266 message->elements[i].values[j].length = len;
267 message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
268 if (message->elements[i].values[j].data == NULL) {
272 memcpy(message->elements[i].values[j].data, p+4, len);
273 message->elements[i].values[j].data[len] = 0;
275 remaining -= len+4+1;
280 if (remaining != 0) {
281 ldb_debug(ldb, LDB_DEBUG_ERROR,
282 "Error: %d bytes unread in ltdb_unpack_data\n", remaining);
288 talloc_free(message->elements);