root/source4/lib/ldb/common/attrib_handlers.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ldb_handler_copy
  2. ldb_handler_fold
  3. ldb_canonicalise_Integer
  4. ldb_comparison_Integer
  5. ldb_comparison_binary
  6. ldb_comparison_fold
  7. ldb_canonicalise_dn
  8. ldb_comparison_dn
  9. ldb_comparison_utctime
  10. ldb_canonicalise_utctime
  11. ldb_standard_syntax_by_name

   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 */
  35 int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  53 int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  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]", 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 */
 108 int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 127 int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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   compare two binary blobs
 135 */
 136 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 137                           const struct ldb_val *v1, const struct ldb_val *v2)
 138 {
 139         if (v1->length != v2->length) {
 140                 return v1->length - v2->length;
 141         }
 142         return memcmp(v1->data, v2->data, v1->length);
 143 }
 144 
 145 /*
 146   compare two case insensitive strings, ignoring multiple whitespaces
 147   and leading and trailing whitespaces
 148   see rfc2252 section 8.1
 149         
 150   try to optimize for the ascii case,
 151   but if we find out an utf8 codepoint revert to slower but correct function
 152 */
 153 int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 154                                const struct ldb_val *v1, const struct ldb_val *v2)
 155 {
 156         const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
 157         size_t n1 = v1->length, n2 = v2->length;
 158         const char *u1, *u2;
 159         char *b1, *b2;
 160         int ret;
 161         while (*s1 == ' ' && n1) { s1++; n1--; };
 162         while (*s2 == ' ' && n2) { s2++; n2--; };
 163         /* TODO: make utf8 safe, possibly with helper function from application */
 164         while (*s1 && *s2 && n1 && n2) {
 165                 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
 166                  * never appear in multibyte sequences */
 167                 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
 168                 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
 169                 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
 170                         break;
 171                 if (*s1 == ' ') {
 172                         while (s1[0] == s1[1] && n1) { s1++; n1--; }
 173                         while (s2[0] == s2[1] && n2) { s2++; n2--; }
 174                 }
 175                 s1++; s2++;
 176                 n1--; n2--;
 177         }
 178         if (! (*s1 && *s2)) {
 179                 /* check for trailing spaces only if one of the pointers
 180                  * has reached the end of the strings otherwise we
 181                  * can mistakenly match.
 182                  * ex. "domain users" <-> "domainUpdates"
 183                  */
 184                 while (*s1 == ' ') { s1++; n1--; }
 185                 while (*s2 == ' ') { s2++; n2--; }
 186         }
 187         if (n1 != n2) {
 188                 return n1 - n2;
 189         }
 190         return (int)(toupper(*s1)) - (int)(toupper(*s2));
 191 
 192 utf8str:
 193         /* no need to recheck from the start, just from the first utf8 char found */
 194         b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
 195         b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
 196 
 197         if (b1 && b2) {
 198                 /* Both strings converted correctly */
 199 
 200                 u1 = b1;
 201                 u2 = b2;
 202         } else {
 203                 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
 204 
 205                 u1 = s1;
 206                 u2 = s2;
 207         }
 208 
 209         while (*u1 & *u2) {
 210                 if (*u1 != *u2)
 211                         break;
 212                 if (*u1 == ' ') {
 213                         while (u1[0] == u1[1]) u1++;
 214                         while (u2[0] == u2[1]) u2++;
 215                 }
 216                 u1++; u2++;
 217         }
 218         if (! (*u1 && *u2)) {
 219                 while (*u1 == ' ') u1++;
 220                 while (*u2 == ' ') u2++;
 221         }
 222         ret = (int)(*u1 - *u2);
 223 
 224         talloc_free(b1);
 225         talloc_free(b2);
 226         
 227         return ret;
 228 }
 229 
 230 
 231 /*
 232   canonicalise a attribute in DN format
 233 */
 234 int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 235                                const struct ldb_val *in, struct ldb_val *out)
 236 {
 237         struct ldb_dn *dn;
 238         int ret = -1;
 239 
 240         out->length = 0;
 241         out->data = NULL;
 242 
 243         dn = ldb_dn_from_ldb_val(ldb, mem_ctx, in);
 244         if ( ! ldb_dn_validate(dn)) {
 245                 return LDB_ERR_INVALID_DN_SYNTAX;
 246         }
 247 
 248         out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
 249         if (out->data == NULL) {
 250                 goto done;
 251         }
 252         out->length = strlen((char *)out->data);
 253 
 254         ret = 0;
 255 
 256 done:
 257         talloc_free(dn);
 258 
 259         return ret;
 260 }
 261 
 262 /*
 263   compare two dns
 264 */
 265 int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 266                              const struct ldb_val *v1, const struct ldb_val *v2)
 267 {
 268         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
 269         int ret;
 270 
 271         dn1 = ldb_dn_from_ldb_val(ldb, mem_ctx, v1);
 272         if ( ! ldb_dn_validate(dn1)) return -1;
 273 
 274         dn2 = ldb_dn_from_ldb_val(ldb, mem_ctx, v2);
 275         if ( ! ldb_dn_validate(dn2)) {
 276                 talloc_free(dn1);
 277                 return -1;
 278         } 
 279 
 280         ret = ldb_dn_compare(dn1, dn2);
 281 
 282         talloc_free(dn1);
 283         talloc_free(dn2);
 284         return ret;
 285 }
 286 
 287 /*
 288   compare two utc time values. 1 second resolution
 289 */
 290 int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 291                                   const struct ldb_val *v1, const struct ldb_val *v2)
 292 {
 293         time_t t1, t2;
 294         t1 = ldb_string_to_time((char *)v1->data);
 295         t2 = ldb_string_to_time((char *)v2->data);
 296         return (int)t2 - (int)t1;
 297 }
 298 
 299 /*
 300   canonicalise a utc time
 301 */
 302 int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 303                                     const struct ldb_val *in, struct ldb_val *out)
 304 {
 305         time_t t = ldb_string_to_time((char *)in->data);
 306         out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
 307         if (out->data == NULL) {
 308                 return -1;
 309         }
 310         out->length = strlen((char *)out->data);
 311         return 0;
 312 }
 313 
 314 /*
 315   table of standard attribute handlers
 316 */
 317 static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
 318         { 
 319                 .name            = LDB_SYNTAX_INTEGER,
 320                 .ldif_read_fn    = ldb_handler_copy,
 321                 .ldif_write_fn   = ldb_handler_copy,
 322                 .canonicalise_fn = ldb_canonicalise_Integer,
 323                 .comparison_fn   = ldb_comparison_Integer
 324         },
 325         { 
 326                 .name            = LDB_SYNTAX_OCTET_STRING,
 327                 .ldif_read_fn    = ldb_handler_copy,
 328                 .ldif_write_fn   = ldb_handler_copy,
 329                 .canonicalise_fn = ldb_handler_copy,
 330                 .comparison_fn   = ldb_comparison_binary
 331         },
 332         { 
 333                 .name            = LDB_SYNTAX_DIRECTORY_STRING,
 334                 .ldif_read_fn    = ldb_handler_copy,
 335                 .ldif_write_fn   = ldb_handler_copy,
 336                 .canonicalise_fn = ldb_handler_fold,
 337                 .comparison_fn   = ldb_comparison_fold
 338         },
 339         { 
 340                 .name            = LDB_SYNTAX_DN,
 341                 .ldif_read_fn    = ldb_handler_copy,
 342                 .ldif_write_fn   = ldb_handler_copy,
 343                 .canonicalise_fn = ldb_canonicalise_dn,
 344                 .comparison_fn   = ldb_comparison_dn
 345         },
 346         { 
 347                 .name            = LDB_SYNTAX_OBJECTCLASS,
 348                 .ldif_read_fn    = ldb_handler_copy,
 349                 .ldif_write_fn   = ldb_handler_copy,
 350                 .canonicalise_fn = ldb_handler_fold,
 351                 .comparison_fn   = ldb_comparison_fold
 352         },
 353         { 
 354                 .name            = LDB_SYNTAX_UTC_TIME,
 355                 .ldif_read_fn    = ldb_handler_copy,
 356                 .ldif_write_fn   = ldb_handler_copy,
 357                 .canonicalise_fn = ldb_canonicalise_utctime,
 358                 .comparison_fn   = ldb_comparison_utctime
 359         }
 360 };
 361 
 362 
 363 /*
 364   return the attribute handlers for a given syntax name
 365 */
 366 const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 367                                                             const char *syntax)
 368 {
 369         int i;
 370         unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
 371         /* TODO: should be replaced with a binary search */
 372         for (i=0;i<num_handlers;i++) {
 373                 if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
 374                         return &ldb_standard_syntaxes[i];
 375                 }
 376         }
 377         return NULL;
 378 }

/* [<][>][^][v][top][bottom][index][help] */