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, see <http://www.gnu.org/licenses/>.
27 * Component: ldb pack/unpack
29 * Description: pack/unpack routines for ldb messages as key/value blobs
31 * Author: Andrew Tridgell
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
)
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
)
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;
88 ldb
= ldb_module_get_ctx(module
);
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
;
165 unsigned int remaining
;
170 ldb
= ldb_module_get_ctx(module
);
171 message
->elements
= NULL
;
174 if (data
->dsize
< 8) {
179 format
= pull_uint32(p
, 0);
180 message
->num_elements
= pull_uint32(p
, 4);
183 remaining
= data
->dsize
- 8;
186 case LTDB_PACKING_FORMAT_NODN
:
190 case LTDB_PACKING_FORMAT
:
191 len
= strnlen((char *)p
, remaining
);
192 if (len
== remaining
) {
196 message
->dn
= ldb_dn_new(message
, ldb
, (char *)p
);
197 if (message
->dn
== NULL
) {
201 remaining
-= len
+ 1;
210 if (message
->num_elements
== 0) {
211 message
->elements
= NULL
;
215 if (message
->num_elements
> remaining
/ 6) {
220 message
->elements
= talloc_array(message
, struct ldb_message_element
, message
->num_elements
);
221 if (!message
->elements
) {
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) {
234 len
= strnlen((char *)p
, remaining
-6);
235 if (len
== remaining
-6) {
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
) {
249 remaining
-= 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
,
256 message
->elements
[i
].num_values
);
257 if (!message
->elements
[i
].values
) {
264 for (j
=0;j
<message
->elements
[i
].num_values
;j
++) {
265 len
= pull_uint32(p
, 0);
266 if (len
> remaining
-5) {
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
) {
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;
285 if (remaining
!= 0) {
286 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
287 "Error: %d bytes unread in ltdb_unpack_data", remaining
);
293 talloc_free(message
->elements
);