• 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/common/
1/*
2   ldb database library
3
4   Copyright (C) Andrew Tridgell  2005
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  attribute handlers for well known attribute types, selected by syntax OID
25  see rfc2252
26*/
27
28#include "ldb_private.h"
29#include "system/locale.h"
30#include "ldb_handlers.h"
31
32/*
33  default handler that just copies a ldb_val.
34*/
35int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
36		     const struct ldb_val *in, struct ldb_val *out)
37{
38	*out = ldb_val_dup(mem_ctx, in);
39	if (in->length > 0 && out->data == NULL) {
40		ldb_oom(ldb);
41		return -1;
42	}
43	return 0;
44}
45
46/*
47  a case folding copy handler, removing leading and trailing spaces and
48  multiple internal spaces
49
50  We exploit the fact that utf8 never uses the space octet except for
51  the space itself
52*/
53int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54			    const struct ldb_val *in, struct ldb_val *out)
55{
56	char *s, *t;
57	int l;
58
59	if (!in || !out || !(in->data)) {
60		return -1;
61	}
62
63	out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length);
64	if (out->data == NULL) {
65		ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%.*s]", (int)in->length, (const char *)in->data);
66		return -1;
67	}
68
69	s = (char *)(out->data);
70
71	/* remove trailing spaces if any */
72	l = strlen(s);
73	while (l > 0 && s[l - 1] == ' ') l--;
74	s[l] = '\0';
75
76	/* remove leading spaces if any */
77	if (*s == ' ') {
78		for (t = s; *s == ' '; s++) ;
79
80		/* remove leading spaces by moving down the string */
81		memmove(t, s, l);
82
83		s = t;
84	}
85
86	/* check middle spaces */
87	while ((t = strchr(s, ' ')) != NULL) {
88		for (s = t; *s == ' '; s++) ;
89
90		if ((s - t) > 1) {
91			l = strlen(s);
92
93			/* remove all spaces but one by moving down the string */
94			memmove(t + 1, s, l);
95		}
96	}
97
98	out->length = strlen((char *)out->data);
99	return 0;
100}
101
102
103
104/*
105  canonicalise a ldap Integer
106  rfc2252 specifies it should be in decimal form
107*/
108static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
109				    const struct ldb_val *in, struct ldb_val *out)
110{
111	char *end;
112	long long i = strtoll((char *)in->data, &end, 0);
113	if (*end != 0) {
114		return -1;
115	}
116	out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
117	if (out->data == NULL) {
118		return -1;
119	}
120	out->length = strlen((char *)out->data);
121	return 0;
122}
123
124/*
125  compare two Integers
126*/
127static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
128				  const struct ldb_val *v1, const struct ldb_val *v2)
129{
130	return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
131}
132
133/*
134  canonicalise a ldap Boolean
135  rfc2252 specifies it should be either "TRUE" or "FALSE"
136*/
137static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
138			     const struct ldb_val *in, struct ldb_val *out)
139{
140	if (strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
141		out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
142		out->length = 4;
143	} else if (strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
144		out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
145		out->length = 4;
146	} else {
147		return -1;
148	}
149	return 0;
150}
151
152/*
153  compare two Booleans
154*/
155static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
156			   const struct ldb_val *v1, const struct ldb_val *v2)
157{
158	if (v1->length != v2->length) {
159		return v1->length - v2->length;
160	}
161	return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
162}
163
164
165/*
166  compare two binary blobs
167*/
168int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
169			  const struct ldb_val *v1, const struct ldb_val *v2)
170{
171	if (v1->length != v2->length) {
172		return v1->length - v2->length;
173	}
174	return memcmp(v1->data, v2->data, v1->length);
175}
176
177/*
178  compare two case insensitive strings, ignoring multiple whitespaces
179  and leading and trailing whitespaces
180  see rfc2252 section 8.1
181
182  try to optimize for the ascii case,
183  but if we find out an utf8 codepoint revert to slower but correct function
184*/
185int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
186			       const struct ldb_val *v1, const struct ldb_val *v2)
187{
188	const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
189	size_t n1 = v1->length, n2 = v2->length;
190	char *b1, *b2;
191	const char *u1, *u2;
192	int ret;
193	while (n1 && *s1 == ' ') { s1++; n1--; };
194	while (n2 && *s2 == ' ') { s2++; n2--; };
195
196	while (n1 && n2 && *s1 && *s2) {
197		/* the first 127 (0x7F) chars are ascii and utf8 guarantes they
198		 * never appear in multibyte sequences */
199		if (((unsigned char)s1[0]) & 0x80) goto utf8str;
200		if (((unsigned char)s2[0]) & 0x80) goto utf8str;
201		if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
202			break;
203		if (*s1 == ' ') {
204			while (n1 && s1[0] == s1[1]) { s1++; n1--; }
205			while (n2 && s2[0] == s2[1]) { s2++; n2--; }
206		}
207		s1++; s2++;
208		n1--; n2--;
209	}
210
211	/* check for trailing spaces only if the other pointers has
212	 * reached the end of the strings otherwise we can
213	 * mistakenly match.  ex. "domain users" <->
214	 * "domainUpdates"
215	 */
216	if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
217		while (n1 && *s1 == ' ') { s1++; n1--; }
218	}
219	if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
220		while (n2 && *s2 == ' ') { s2++; n2--; }
221	}
222	if (n1 == 0 && n2 != 0) {
223		return -(int)toupper(*s2);
224	}
225	if (n2 == 0 && n1 != 0) {
226		return (int)toupper(*s1);
227	}
228	if (n2 == 0 && n2 == 0) {
229		return 0;
230	}
231	return (int)toupper(*s1) - (int)toupper(*s2);
232
233utf8str:
234	/* no need to recheck from the start, just from the first utf8 char found */
235	b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
236	b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
237
238	if (!b1 || !b2) {
239		/* One of the strings was not UTF8, so we have no
240		 * options but to do a binary compare */
241		talloc_free(b1);
242		talloc_free(b2);
243		if (memcmp(s1, s2, MIN(n1, n2)) == 0) {
244			if (n1 == n2) return 0;
245			if (n1 > n2) {
246				return (int)toupper(s1[n2]);
247			} else {
248				return -(int)toupper(s2[n1]);
249			}
250		}
251	}
252
253	u1 = b1;
254	u2 = b2;
255
256	while (*u1 & *u2) {
257		if (*u1 != *u2)
258			break;
259		if (*u1 == ' ') {
260			while (u1[0] == u1[1]) u1++;
261			while (u2[0] == u2[1]) u2++;
262		}
263		u1++; u2++;
264	}
265	if (! (*u1 && *u2)) {
266		while (*u1 == ' ') u1++;
267		while (*u2 == ' ') u2++;
268	}
269	ret = (int)(*u1 - *u2);
270
271	talloc_free(b1);
272	talloc_free(b2);
273
274	return ret;
275}
276
277
278/*
279  canonicalise a attribute in DN format
280*/
281static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
282			       const struct ldb_val *in, struct ldb_val *out)
283{
284	struct ldb_dn *dn;
285	int ret = -1;
286
287	out->length = 0;
288	out->data = NULL;
289
290	dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
291	if ( ! ldb_dn_validate(dn)) {
292		return LDB_ERR_INVALID_DN_SYNTAX;
293	}
294
295	out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
296	if (out->data == NULL) {
297		goto done;
298	}
299	out->length = strlen((char *)out->data);
300
301	ret = 0;
302
303done:
304	talloc_free(dn);
305
306	return ret;
307}
308
309/*
310  compare two dns
311*/
312static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
313			     const struct ldb_val *v1, const struct ldb_val *v2)
314{
315	struct ldb_dn *dn1 = NULL, *dn2 = NULL;
316	int ret;
317
318	dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
319	if ( ! ldb_dn_validate(dn1)) return -1;
320
321	dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
322	if ( ! ldb_dn_validate(dn2)) {
323		talloc_free(dn1);
324		return -1;
325	}
326
327	ret = ldb_dn_compare(dn1, dn2);
328
329	talloc_free(dn1);
330	talloc_free(dn2);
331	return ret;
332}
333
334/*
335  compare two utc time values. 1 second resolution
336*/
337static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
338				  const struct ldb_val *v1, const struct ldb_val *v2)
339{
340	time_t t1, t2;
341	t1 = ldb_string_to_time((char *)v1->data);
342	t2 = ldb_string_to_time((char *)v2->data);
343	return (int)t2 - (int)t1;
344}
345
346/*
347  canonicalise a utc time
348*/
349static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
350				    const struct ldb_val *in, struct ldb_val *out)
351{
352	time_t t = ldb_string_to_time((char *)in->data);
353	out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
354	if (out->data == NULL) {
355		return -1;
356	}
357	out->length = strlen((char *)out->data);
358	return 0;
359}
360
361/*
362  table of standard attribute handlers
363*/
364static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
365	{
366		.name            = LDB_SYNTAX_INTEGER,
367		.ldif_read_fn    = ldb_handler_copy,
368		.ldif_write_fn   = ldb_handler_copy,
369		.canonicalise_fn = ldb_canonicalise_Integer,
370		.comparison_fn   = ldb_comparison_Integer
371	},
372	{
373		.name            = LDB_SYNTAX_OCTET_STRING,
374		.ldif_read_fn    = ldb_handler_copy,
375		.ldif_write_fn   = ldb_handler_copy,
376		.canonicalise_fn = ldb_handler_copy,
377		.comparison_fn   = ldb_comparison_binary
378	},
379	{
380		.name            = LDB_SYNTAX_DIRECTORY_STRING,
381		.ldif_read_fn    = ldb_handler_copy,
382		.ldif_write_fn   = ldb_handler_copy,
383		.canonicalise_fn = ldb_handler_fold,
384		.comparison_fn   = ldb_comparison_fold
385	},
386	{
387		.name            = LDB_SYNTAX_DN,
388		.ldif_read_fn    = ldb_handler_copy,
389		.ldif_write_fn   = ldb_handler_copy,
390		.canonicalise_fn = ldb_canonicalise_dn,
391		.comparison_fn   = ldb_comparison_dn
392	},
393	{
394		.name            = LDB_SYNTAX_OBJECTCLASS,
395		.ldif_read_fn    = ldb_handler_copy,
396		.ldif_write_fn   = ldb_handler_copy,
397		.canonicalise_fn = ldb_handler_fold,
398		.comparison_fn   = ldb_comparison_fold
399	},
400	{
401		.name            = LDB_SYNTAX_UTC_TIME,
402		.ldif_read_fn    = ldb_handler_copy,
403		.ldif_write_fn   = ldb_handler_copy,
404		.canonicalise_fn = ldb_canonicalise_utctime,
405		.comparison_fn   = ldb_comparison_utctime
406	},
407	{
408		.name            = LDB_SYNTAX_BOOLEAN,
409		.ldif_read_fn    = ldb_handler_copy,
410		.ldif_write_fn   = ldb_handler_copy,
411		.canonicalise_fn = ldb_canonicalise_Boolean,
412		.comparison_fn   = ldb_comparison_Boolean
413	},
414};
415
416
417/*
418  return the attribute handlers for a given syntax name
419*/
420const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
421							    const char *syntax)
422{
423	int i;
424	unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
425	/* TODO: should be replaced with a binary search */
426	for (i=0;i<num_handlers;i++) {
427		if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
428			return &ldb_standard_syntaxes[i];
429		}
430	}
431	return NULL;
432}
433