4 Copyright (C) Andrew Tridgell 2005
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 2 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
25 attribute handlers for well known attribute types, selected by syntax OID
30 #include "ldb/include/includes.h"
33 default handler that just copies a ldb_val.
35 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
36 const struct ldb_val *in, struct ldb_val *out)
38 *out = ldb_val_dup(mem_ctx, in);
39 if (in->length > 0 && out->data == NULL) {
47 a case folding copy handler, removing leading and trailing spaces and
48 multiple internal spaces
50 We exploit the fact that utf8 never uses the space octet except for
53 static int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
54 const struct ldb_val *in, struct ldb_val *out)
58 if (!in || !out || !(in->data)) {
62 out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
63 if (out->data == NULL) {
64 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
68 s = (char *)(out->data);
70 /* remove trailing spaces if any */
72 while (s[l - 1] == ' ') l--;
75 /* remove leading spaces if any */
77 for (t = s; *s == ' '; s++) ;
79 /* remove leading spaces by moving down the string */
85 /* check middle spaces */
86 while ((t = strchr(s, ' ')) != NULL) {
87 for (s = t; *s == ' '; s++) ;
92 /* remove all spaces but one by moving down the string */
97 out->length = strlen((char *)out->data);
104 canonicalise a ldap Integer
105 rfc2252 specifies it should be in decimal form
107 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
108 const struct ldb_val *in, struct ldb_val *out)
111 long long i = strtoll((char *)in->data, &end, 0);
115 out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
116 if (out->data == NULL) {
119 out->length = strlen((char *)out->data);
126 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
127 const struct ldb_val *v1, const struct ldb_val *v2)
129 return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
133 compare two binary blobs
135 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
136 const struct ldb_val *v1, const struct ldb_val *v2)
138 if (v1->length != v2->length) {
139 return v1->length - v2->length;
141 return memcmp(v1->data, v2->data, v1->length);
145 compare two case insensitive strings, ignoring multiple whitespaces
146 and leading and trailing whitespaces
147 see rfc2252 section 8.1
149 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
150 const struct ldb_val *v1, const struct ldb_val *v2)
152 const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
153 while (*s1 == ' ') s1++;
154 while (*s2 == ' ') s2++;
155 /* TODO: make utf8 safe, possibly with helper function from application */
157 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
160 while (s1[0] == s1[1]) s1++;
161 while (s2[0] == s2[1]) s2++;
165 if (! (*s1 && *s2)) {
166 /* remove trailing spaces only if one of the pointers
167 * has reached the end of the strings otherwise we
168 * can mistakenly match.
169 * ex. "domain users" <-> "domainUpdates"
171 while (*s1 == ' ') s1++;
172 while (*s2 == ' ') s2++;
174 return (int)(toupper(*s1)) - (int)(toupper(*s2));
178 canonicalise a attribute in DN format
180 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
181 const struct ldb_val *in, struct ldb_val *out)
189 dn = ldb_dn_explode_casefold(ldb, (char *)in->data);
194 out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
195 if (out->data == NULL) {
198 out->length = strlen((char *)out->data);
211 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
212 const struct ldb_val *v1, const struct ldb_val *v2)
214 struct ldb_dn *dn1 = NULL, *dn2 = NULL;
217 dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data);
218 if (dn1 == NULL) return -1;
220 dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data);
226 ret = ldb_dn_compare(ldb, dn1, dn2);
234 compare two objectclasses, looking at subclasses
236 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
237 const struct ldb_val *v1, const struct ldb_val *v2)
240 const char **subclasses;
241 ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
245 subclasses = ldb_subclass_list(ldb, (char *)v1->data);
246 if (subclasses == NULL) {
249 for (i=0;subclasses[i];i++) {
251 vs.data = discard_const(subclasses[i]);
252 vs.length = strlen(subclasses[i]);
253 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
261 compare two utc time values. 1 second resolution
263 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
264 const struct ldb_val *v1, const struct ldb_val *v2)
267 t1 = ldb_string_to_time((char *)v1->data);
268 t2 = ldb_string_to_time((char *)v2->data);
269 return (int)t2 - (int)t1;
273 canonicalise a utc time
275 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
276 const struct ldb_val *in, struct ldb_val *out)
278 time_t t = ldb_string_to_time((char *)in->data);
279 out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
280 if (out->data == NULL) {
283 out->length = strlen((char *)out->data);
288 table of standard attribute handlers
290 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
292 .attr = LDB_SYNTAX_INTEGER,
294 .ldif_read_fn = ldb_handler_copy,
295 .ldif_write_fn = ldb_handler_copy,
296 .canonicalise_fn = ldb_canonicalise_Integer,
297 .comparison_fn = ldb_comparison_Integer
300 .attr = LDB_SYNTAX_OCTET_STRING,
302 .ldif_read_fn = ldb_handler_copy,
303 .ldif_write_fn = ldb_handler_copy,
304 .canonicalise_fn = ldb_handler_copy,
305 .comparison_fn = ldb_comparison_binary
308 .attr = LDB_SYNTAX_DIRECTORY_STRING,
310 .ldif_read_fn = ldb_handler_copy,
311 .ldif_write_fn = ldb_handler_copy,
312 .canonicalise_fn = ldb_handler_fold,
313 .comparison_fn = ldb_comparison_fold
316 .attr = LDB_SYNTAX_DN,
318 .ldif_read_fn = ldb_handler_copy,
319 .ldif_write_fn = ldb_handler_copy,
320 .canonicalise_fn = ldb_canonicalise_dn,
321 .comparison_fn = ldb_comparison_dn
324 .attr = LDB_SYNTAX_OBJECTCLASS,
326 .ldif_read_fn = ldb_handler_copy,
327 .ldif_write_fn = ldb_handler_copy,
328 .canonicalise_fn = ldb_handler_fold,
329 .comparison_fn = ldb_comparison_objectclass
332 .attr = LDB_SYNTAX_UTC_TIME,
334 .ldif_read_fn = ldb_handler_copy,
335 .ldif_write_fn = ldb_handler_copy,
336 .canonicalise_fn = ldb_canonicalise_utctime,
337 .comparison_fn = ldb_comparison_utctime
343 return the attribute handlers for a given syntax name
345 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
349 unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
350 /* TODO: should be replaced with a binary search */
351 for (i=0;i<num_handlers;i++) {
352 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
353 return &ldb_standard_attribs[i];