root/source3/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_objectclass
  10. ldb_comparison_utctime
  11. ldb_canonicalise_utctime
  12. ldb_attrib_handler_syntax

   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 "includes.h"
  29 #include "ldb/include/includes.h"
  30 #include "system/locale.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 static 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         if (!in || !out || !(in->data)) {
  59                 return -1;
  60         }
  61 
  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);
  65                 return -1;
  66         }
  67 
  68         s = (char *)(out->data);
  69         
  70         /* remove trailing spaces if any */
  71         l = strlen(s);
  72         while (l > 0 && s[l - 1] == ' ') l--;
  73         s[l] = '\0';
  74         
  75         /* remove leading spaces if any */
  76         if (*s == ' ') {
  77                 for (t = s; *s == ' '; s++) ;
  78 
  79                 /* remove leading spaces by moving down the string */
  80                 memmove(t, s, l);
  81 
  82                 s = t;
  83         }
  84 
  85         /* check middle spaces */
  86         while ((t = strchr(s, ' ')) != NULL) {
  87                 for (s = t; *s == ' '; s++) ;
  88 
  89                 if ((s - t) > 1) {
  90                         l = strlen(s);
  91 
  92                         /* remove all spaces but one by moving down the string */
  93                         memmove(t + 1, s, l);
  94                 }
  95         }
  96 
  97         out->length = strlen((char *)out->data);
  98         return 0;
  99 }
 100 
 101 
 102 
 103 /*
 104   canonicalise a ldap Integer
 105   rfc2252 specifies it should be in decimal form
 106 */
 107 static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 108                                     const struct ldb_val *in, struct ldb_val *out)
 109 {
 110         char *end;
 111         long long i = strtoll((char *)in->data, &end, 0);
 112         if (*end != 0) {
 113                 return -1;
 114         }
 115         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
 116         if (out->data == NULL) {
 117                 return -1;
 118         }
 119         out->length = strlen((char *)out->data);
 120         return 0;
 121 }
 122 
 123 /*
 124   compare two Integers
 125 */
 126 static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 127                                   const struct ldb_val *v1, const struct ldb_val *v2)
 128 {
 129         return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
 130 }
 131 
 132 /*
 133   compare two binary blobs
 134 */
 135 int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 136                           const struct ldb_val *v1, const struct ldb_val *v2)
 137 {
 138         if (v1->length != v2->length) {
 139                 return v1->length - v2->length;
 140         }
 141         return memcmp(v1->data, v2->data, v1->length);
 142 }
 143 
 144 /*
 145   compare two case insensitive strings, ignoring multiple whitespaces
 146   and leading and trailing whitespaces
 147   see rfc2252 section 8.1
 148         
 149   try to optimize for the ascii case,
 150   but if we find out an utf8 codepoint revert to slower but correct function
 151 */
 152 static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 153                                const struct ldb_val *v1, const struct ldb_val *v2)
 154 {
 155         const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
 156         const char *u1, *u2;
 157         char *b1, *b2;
 158         int ret;
 159         while (*s1 == ' ') s1++;
 160         while (*s2 == ' ') s2++;
 161         /* TODO: make utf8 safe, possibly with helper function from application */
 162         while (*s1 && *s2) {
 163                 /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
 164                  * never appear in multibyte sequences */
 165                 if (((unsigned char)s1[0]) & 0x80) goto utf8str;
 166                 if (((unsigned char)s2[0]) & 0x80) goto utf8str;
 167                 if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
 168                         break;
 169                 if (*s1 == ' ') {
 170                         while (s1[0] == s1[1]) s1++;
 171                         while (s2[0] == s2[1]) s2++;
 172                 }
 173                 s1++; s2++;
 174         }
 175         if (! (*s1 && *s2)) {
 176                 /* check for trailing spaces only if one of the pointers
 177                  * has reached the end of the strings otherwise we
 178                  * can mistakenly match.
 179                  * ex. "domain users" <-> "domainUpdates"
 180                  */
 181                 while (*s1 == ' ') s1++;
 182                 while (*s2 == ' ') s2++;
 183         }
 184         return (int)(toupper(*s1)) - (int)(toupper(*s2));
 185 
 186 utf8str:
 187         /* no need to recheck from the start, just from the first utf8 char found */
 188         b1 = ldb_casefold(ldb, mem_ctx, s1);
 189         b2 = ldb_casefold(ldb, mem_ctx, s2);
 190 
 191         if (b1 && b2) {
 192                 /* Both strings converted correctly */
 193 
 194                 u1 = b1;
 195                 u2 = b2;
 196         } else {
 197                 /* One of the strings was not UTF8, so we have no options but to do a binary compare */
 198 
 199                 u1 = s1;
 200                 u2 = s2;
 201         }
 202 
 203         while (*u1 & *u2) {
 204                 if (*u1 != *u2)
 205                         break;
 206                 if (*u1 == ' ') {
 207                         while (u1[0] == u1[1]) u1++;
 208                         while (u2[0] == u2[1]) u2++;
 209                 }
 210                 u1++; u2++;
 211         }
 212         if (! (*u1 && *u2)) {
 213                 while (*u1 == ' ') u1++;
 214                 while (*u2 == ' ') u2++;
 215         }
 216         ret = (int)(*u1 - *u2);
 217 
 218         talloc_free(b1);
 219         talloc_free(b2);
 220         
 221         return ret;
 222 }
 223 
 224 /*
 225   canonicalise a attribute in DN format
 226 */
 227 static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 228                                const struct ldb_val *in, struct ldb_val *out)
 229 {
 230         struct ldb_dn *dn;
 231         int ret = -1;
 232 
 233         out->length = 0;
 234         out->data = NULL;
 235 
 236         dn = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)in->data);
 237         if (dn == NULL) {
 238                 return -1;
 239         }
 240 
 241         out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn);
 242         if (out->data == NULL) {
 243                 goto done;
 244         }
 245         out->length = strlen((char *)out->data);
 246 
 247         ret = 0;
 248 
 249 done:
 250         talloc_free(dn);
 251 
 252         return ret;
 253 }
 254 
 255 /*
 256   compare two dns
 257 */
 258 static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 259                              const struct ldb_val *v1, const struct ldb_val *v2)
 260 {
 261         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
 262         int ret;
 263 
 264         dn1 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v1->data);
 265         if (dn1 == NULL) return -1;
 266 
 267         dn2 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v2->data);
 268         if (dn2 == NULL) {
 269                 talloc_free(dn1);
 270                 return -1;
 271         } 
 272 
 273         ret = ldb_dn_compare(ldb, dn1, dn2);
 274 
 275         talloc_free(dn1);
 276         talloc_free(dn2);
 277         return ret;
 278 }
 279 
 280 /*
 281   compare two objectclasses, looking at subclasses
 282 */
 283 static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 284                                       const struct ldb_val *v1, const struct ldb_val *v2)
 285 {
 286         int ret, i;
 287         const char **subclasses;
 288         ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
 289         if (ret == 0) {
 290                 return 0;
 291         }
 292         subclasses = ldb_subclass_list(ldb, (char *)v1->data);
 293         if (subclasses == NULL) {
 294                 return ret;
 295         }
 296         for (i=0;subclasses[i];i++) {
 297                 struct ldb_val vs;
 298                 vs.data = discard_const_p(uint8_t, subclasses[i]);
 299                 vs.length = strlen(subclasses[i]);
 300                 if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
 301                         return 0;
 302                 }
 303         }
 304         return ret;
 305 }
 306 
 307 /*
 308   compare two utc time values. 1 second resolution
 309 */
 310 static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 311                                   const struct ldb_val *v1, const struct ldb_val *v2)
 312 {
 313         time_t t1, t2;
 314         t1 = ldb_string_to_time((char *)v1->data);
 315         t2 = ldb_string_to_time((char *)v2->data);
 316         return (int)t2 - (int)t1;
 317 }
 318 
 319 /*
 320   canonicalise a utc time
 321 */
 322 static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 323                                     const struct ldb_val *in, struct ldb_val *out)
 324 {
 325         time_t t = ldb_string_to_time((char *)in->data);
 326         out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
 327         if (out->data == NULL) {
 328                 return -1;
 329         }
 330         out->length = strlen((char *)out->data);
 331         return 0;
 332 }
 333 
 334 /*
 335   table of standard attribute handlers
 336 */
 337 static const struct ldb_attrib_handler ldb_standard_attribs[] = {
 338         { 
 339                 .attr            = LDB_SYNTAX_INTEGER,
 340                 .flags           = 0,
 341                 .ldif_read_fn    = ldb_handler_copy,
 342                 .ldif_write_fn   = ldb_handler_copy,
 343                 .canonicalise_fn = ldb_canonicalise_Integer,
 344                 .comparison_fn   = ldb_comparison_Integer
 345         },
 346         { 
 347                 .attr            = LDB_SYNTAX_OCTET_STRING,
 348                 .flags           = 0,
 349                 .ldif_read_fn    = ldb_handler_copy,
 350                 .ldif_write_fn   = ldb_handler_copy,
 351                 .canonicalise_fn = ldb_handler_copy,
 352                 .comparison_fn   = ldb_comparison_binary
 353         },
 354         { 
 355                 .attr            = LDB_SYNTAX_DIRECTORY_STRING,
 356                 .flags           = 0,
 357                 .ldif_read_fn    = ldb_handler_copy,
 358                 .ldif_write_fn   = ldb_handler_copy,
 359                 .canonicalise_fn = ldb_handler_fold,
 360                 .comparison_fn   = ldb_comparison_fold
 361         },
 362         { 
 363                 .attr            = LDB_SYNTAX_DN,
 364                 .flags           = 0,
 365                 .ldif_read_fn    = ldb_handler_copy,
 366                 .ldif_write_fn   = ldb_handler_copy,
 367                 .canonicalise_fn = ldb_canonicalise_dn,
 368                 .comparison_fn   = ldb_comparison_dn
 369         },
 370         { 
 371                 .attr            = LDB_SYNTAX_OBJECTCLASS,
 372                 .flags           = 0,
 373                 .ldif_read_fn    = ldb_handler_copy,
 374                 .ldif_write_fn   = ldb_handler_copy,
 375                 .canonicalise_fn = ldb_handler_fold,
 376                 .comparison_fn   = ldb_comparison_objectclass
 377         },
 378         { 
 379                 .attr            = LDB_SYNTAX_UTC_TIME,
 380                 .flags           = 0,
 381                 .ldif_read_fn    = ldb_handler_copy,
 382                 .ldif_write_fn   = ldb_handler_copy,
 383                 .canonicalise_fn = ldb_canonicalise_utctime,
 384                 .comparison_fn   = ldb_comparison_utctime
 385         }
 386 };
 387 
 388 
 389 /*
 390   return the attribute handlers for a given syntax name
 391 */
 392 const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 393                                                            const char *syntax)
 394 {
 395         int i;
 396         unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
 397         /* TODO: should be replaced with a binary search */
 398         for (i=0;i<num_handlers;i++) {
 399                 if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
 400                         return &ldb_standard_attribs[i];
 401                 }
 402         }
 403         return NULL;
 404 }
 405 

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