• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/lib/ldb/ldb_tdb/
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_tdb.h"
35
36/* change this if the data format ever changes */
37#define LTDB_PACKING_FORMAT 0x26011967
38
39/* old packing formats */
40#define LTDB_PACKING_FORMAT_NODN 0x26011966
41
42/* use a portable integer format */
43static 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
52static 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
58static 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, "dn") == 0) return 0;
63
64	if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
65
66	return el->num_values;
67}
68
69/*
70  pack a ldb message into a linear buffer in a TDB_DATA
71
72  note that this routine avoids saving elements with zero values,
73  as these are equivalent to having no element
74
75  caller frees the data buffer after use
76*/
77int ltdb_pack_data(struct ldb_module *module,
78		   const struct ldb_message *message,
79		   struct TDB_DATA *data)
80{
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;
87
88	ldb = ldb_module_get_ctx(module);
89
90	dn = ldb_dn_get_linearized(message->dn);
91	if (dn == NULL) {
92		errno = ENOMEM;
93		return -1;
94	}
95
96	/* work out how big it needs to be */
97	size = 8;
98
99	size += 1 + strlen(dn);
100
101	for (i=0;i<message->num_elements;i++) {
102		if (attribute_storable_values(&message->elements[i]) == 0) {
103			continue;
104		}
105
106		real_elements++;
107
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;
111		}
112	}
113
114	/* allocate it */
115	data->dptr = talloc_array(ldb, uint8_t, size);
116	if (!data->dptr) {
117		errno = ENOMEM;
118		return -1;
119	}
120	data->dsize = size;
121
122	p = data->dptr;
123	put_uint32(p, 0, LTDB_PACKING_FORMAT);
124	put_uint32(p, 4, real_elements);
125	p += 8;
126
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;
132
133	for (i=0;i<message->num_elements;i++) {
134		if (attribute_storable_values(&message->elements[i]) == 0) {
135			continue;
136		}
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;
148		}
149	}
150
151	return 0;
152}
153
154/*
155  unpack a ldb message from a linear buffer in TDB_DATA
156
157  Free with ltdb_unpack_data_free()
158*/
159int ltdb_unpack_data(struct ldb_module *module,
160		     const struct TDB_DATA *data,
161		     struct ldb_message *message)
162{
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;
169
170	ldb = ldb_module_get_ctx(module);
171	message->elements = NULL;
172
173	p = data->dptr;
174	if (data->dsize < 8) {
175		errno = EIO;
176		goto failed;
177	}
178
179	format = pull_uint32(p, 0);
180	message->num_elements = pull_uint32(p, 4);
181	p += 8;
182
183	remaining = data->dsize - 8;
184
185	switch (format) {
186	case LTDB_PACKING_FORMAT_NODN:
187		message->dn = NULL;
188		break;
189
190	case LTDB_PACKING_FORMAT:
191		len = strnlen((char *)p, remaining);
192		if (len == remaining) {
193			errno = EIO;
194			goto failed;
195		}
196		message->dn = ldb_dn_new(message, ldb, (char *)p);
197		if (message->dn == NULL) {
198			errno = ENOMEM;
199			goto failed;
200		}
201		remaining -= len + 1;
202		p += len + 1;
203		break;
204
205	default:
206		errno = EIO;
207		goto failed;
208	}
209
210	if (message->num_elements == 0) {
211		message->elements = NULL;
212		return 0;
213	}
214
215	if (message->num_elements > remaining / 6) {
216		errno = EIO;
217		goto failed;
218	}
219
220	message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
221	if (!message->elements) {
222		errno = ENOMEM;
223		goto failed;
224	}
225
226	memset(message->elements, 0,
227	       message->num_elements * sizeof(struct ldb_message_element));
228
229	for (i=0;i<message->num_elements;i++) {
230		if (remaining < 10) {
231			errno = EIO;
232			goto failed;
233		}
234		len = strnlen((char *)p, remaining-6);
235		if (len == remaining-6) {
236			errno = EIO;
237			goto failed;
238		}
239		if (len == 0) {
240			errno = EIO;
241			goto failed;
242		}
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;
248		}
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;
260			}
261		}
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;
269			}
270
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;
276			}
277			memcpy(message->elements[i].values[j].data, p+4, len);
278			message->elements[i].values[j].data[len] = 0;
279
280			remaining -= len+4+1;
281			p += len+4+1;
282		}
283	}
284
285	if (remaining != 0) {
286		ldb_debug(ldb, LDB_DEBUG_ERROR,
287			  "Error: %d bytes unread in ltdb_unpack_data", remaining);
288	}
289
290	return 0;
291
292failed:
293	talloc_free(message->elements);
294	return -1;
295}
296