root/source3/lib/ldb/common/ldb_match.c

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

DEFINITIONS

This source file includes following definitions.
  1. ldb_match_scope
  2. ldb_match_present
  3. ldb_match_comparison
  4. ldb_match_equality
  5. ldb_wildcard_compare
  6. ldb_match_substring
  7. ldb_comparator_and
  8. ldb_comparator_or
  9. ldb_match_extended
  10. ldb_match_message
  11. ldb_match_msg

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Tridgell  2004-2005
   5    Copyright (C) Simo Sorce            2005
   6 
   7      ** NOTE! The following LGPL license applies to the ldb
   8      ** library. This does NOT imply that all of Samba is released
   9      ** under the LGPL
  10    
  11    This library is free software; you can redistribute it and/or
  12    modify it under the terms of the GNU Lesser General Public
  13    License as published by the Free Software Foundation; either
  14    version 3 of the License, or (at your option) any later version.
  15 
  16    This library is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19    Lesser General Public License for more details.
  20 
  21    You should have received a copy of the GNU Lesser General Public
  22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 /*
  26  *  Name: ldb
  27  *
  28  *  Component: ldb expression matching
  29  *
  30  *  Description: ldb expression matching 
  31  *
  32  *  Author: Andrew Tridgell
  33  */
  34 
  35 #include "includes.h"
  36 #include "ldb/include/includes.h"
  37 
  38 /*
  39   check if the scope matches in a search result
  40 */
  41 static int ldb_match_scope(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
  42                            const struct ldb_dn *base,
  43                            const struct ldb_dn *dn,
  44                            enum ldb_scope scope)
  45 {
  46         int ret = 0;
  47 
  48         if (base == NULL || dn == NULL) {
  49                 return 1;
  50         }
  51 
  52         switch (scope) {
  53         case LDB_SCOPE_BASE:
  54                 if (ldb_dn_compare(ldb, base, dn) == 0) {
  55                         ret = 1;
  56                 }
  57                 break;
  58 
  59         case LDB_SCOPE_ONELEVEL:
  60                 if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
  61                         if (ldb_dn_compare_base(ldb, base, dn) == 0) {
  62                                 ret = 1;
  63                         }
  64                 }
  65                 break;
  66                 
  67         case LDB_SCOPE_SUBTREE:
  68         default:
  69                 if (ldb_dn_compare_base(ldb, base, dn) == 0) {
  70                         ret = 1;
  71                 }
  72                 break;
  73         }
  74 
  75         return ret;
  76 }
  77 
  78 
  79 /*
  80   match if node is present
  81 */
  82 static int ldb_match_present(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
  83                              const struct ldb_message *msg,
  84                              const struct ldb_parse_tree *tree,
  85                              enum ldb_scope scope)
  86 {
  87         if (ldb_attr_dn(tree->u.present.attr) == 0) {
  88                 return 1;
  89         }
  90 
  91         if (ldb_msg_find_element(msg, tree->u.present.attr)) {
  92                 return 1;
  93         }
  94 
  95         return 0;
  96 }
  97 
  98 static int ldb_match_comparison(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
  99                                 const struct ldb_message *msg,
 100                                 const struct ldb_parse_tree *tree,
 101                                 enum ldb_scope scope,
 102                                 enum ldb_parse_op comp_op)
 103 {
 104         unsigned int i;
 105         struct ldb_message_element *el;
 106         const struct ldb_attrib_handler *h;
 107         int ret;
 108 
 109         /* FIXME: APPROX comparison not handled yet */
 110         if (comp_op == LDB_OP_APPROX) return 0;
 111 
 112         el = ldb_msg_find_element(msg, tree->u.comparison.attr);
 113         if (el == NULL) {
 114                 return 0;
 115         }
 116 
 117         h = ldb_attrib_handler(ldb, el->name);
 118 
 119         for (i = 0; i < el->num_values; i++) {
 120                 ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
 121 
 122                 if (ret == 0) {
 123                         return 1;
 124                 }
 125                 if (ret > 0 && comp_op == LDB_OP_GREATER) {
 126                         return 1;
 127                 }
 128                 if (ret < 0 && comp_op == LDB_OP_LESS) {
 129                         return 1;
 130                 }
 131         }
 132 
 133         return 0;
 134 }
 135 
 136 /*
 137   match a simple leaf node
 138 */
 139 static int ldb_match_equality(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 140                               const struct ldb_message *msg,
 141                               const struct ldb_parse_tree *tree,
 142                               enum ldb_scope scope)
 143 {
 144         unsigned int i;
 145         struct ldb_message_element *el;
 146         const struct ldb_attrib_handler *h;
 147         struct ldb_dn *valuedn;
 148         int ret;
 149 
 150         if (ldb_attr_dn(tree->u.equality.attr) == 0) {
 151                 valuedn = ldb_dn_explode_casefold(ldb, ldb,
 152                                                   (char *)tree->u.equality.value.data);
 153                 if (valuedn == NULL) {
 154                         return 0;
 155                 }
 156 
 157                 ret = ldb_dn_compare(ldb, msg->dn, valuedn);
 158 
 159                 talloc_free(valuedn);
 160 
 161                 if (ret == 0) return 1;
 162                 return 0;
 163         }
 164 
 165         /* TODO: handle the "*" case derived from an extended search
 166            operation without the attibute type defined */
 167         el = ldb_msg_find_element(msg, tree->u.equality.attr);
 168         if (el == NULL) {
 169                 return 0;
 170         }
 171 
 172         h = ldb_attrib_handler(ldb, el->name);
 173 
 174         for (i=0;i<el->num_values;i++) {
 175                 if (h->comparison_fn(ldb, ldb, &tree->u.equality.value, 
 176                                      &el->values[i]) == 0) {
 177                         return 1;
 178                 }
 179         }
 180 
 181         return 0;
 182 }
 183 
 184 static int ldb_wildcard_compare(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 185                                 const struct ldb_parse_tree *tree,
 186                                 const struct ldb_val value)
 187 {
 188         const struct ldb_attrib_handler *h;
 189         struct ldb_val val;
 190         struct ldb_val cnk;
 191         struct ldb_val *chunk;
 192         char *p, *g;
 193         uint8_t *save_p = NULL;
 194         int c = 0;
 195 
 196         h = ldb_attrib_handler(ldb, tree->u.substring.attr);
 197 
 198         if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
 199                 return -1;
 200 
 201         save_p = val.data;
 202         cnk.data = NULL;
 203 
 204         if ( ! tree->u.substring.start_with_wildcard ) {
 205 
 206                 chunk = tree->u.substring.chunks[c];
 207                 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
 208 
 209                 /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
 210                 if (cnk.length > val.length) {
 211                         goto failed;
 212                 }
 213                 if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
 214                 val.length -= cnk.length;
 215                 val.data += cnk.length;
 216                 c++;
 217                 talloc_free(cnk.data);
 218                 cnk.data = NULL;
 219         }
 220 
 221         while (tree->u.substring.chunks[c]) {
 222 
 223                 chunk = tree->u.substring.chunks[c];
 224                 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
 225 
 226                 /* FIXME: case of embedded nulls */
 227                 p = strstr((char *)val.data, (char *)cnk.data);
 228                 if (p == NULL) goto failed;
 229                 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
 230                         do { /* greedy */
 231                                 g = strstr((char *)p + cnk.length, (char *)cnk.data);
 232                                 if (g) p = g;
 233                         } while(g);
 234                 }
 235                 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
 236                 val.data = (uint8_t *)(p + cnk.length);
 237                 c++;
 238                 talloc_free(cnk.data);
 239                 cnk.data = NULL;
 240         }
 241 
 242         if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
 243         talloc_free(save_p);
 244         return 1;
 245 
 246 failed:
 247         talloc_free(save_p);
 248         talloc_free(cnk.data);
 249         return 0;
 250 }
 251 
 252 /*
 253   match a simple leaf node
 254 */
 255 static int ldb_match_substring(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 256                                const struct ldb_message *msg,
 257                                const struct ldb_parse_tree *tree,
 258                                enum ldb_scope scope)
 259 {
 260         unsigned int i;
 261         struct ldb_message_element *el;
 262 
 263         el = ldb_msg_find_element(msg, tree->u.substring.attr);
 264         if (el == NULL) {
 265                 return 0;
 266         }
 267 
 268         for (i = 0; i < el->num_values; i++) {
 269                 if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
 270                         return 1;
 271                 }
 272         }
 273 
 274         return 0;
 275 }
 276 
 277 
 278 /*
 279   bitwise-and comparator
 280 */
 281 static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
     /* [<][>][^][v][top][bottom][index][help] */
 282 {
 283         uint64_t i1, i2;
 284         i1 = strtoull((char *)v1->data, NULL, 0);
 285         i2 = strtoull((char *)v2->data, NULL, 0);
 286         return ((i1 & i2) == i2);
 287 }
 288 
 289 /*
 290   bitwise-or comparator
 291 */
 292 static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
     /* [<][>][^][v][top][bottom][index][help] */
 293 {
 294         uint64_t i1, i2;
 295         i1 = strtoull((char *)v1->data, NULL, 0);
 296         i2 = strtoull((char *)v2->data, NULL, 0);
 297         return ((i1 & i2) != 0);
 298 }
 299 
 300 
 301 /*
 302   extended match, handles things like bitops
 303 */
 304 static int ldb_match_extended(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 305                               const struct ldb_message *msg,
 306                               const struct ldb_parse_tree *tree,
 307                               enum ldb_scope scope)
 308 {
 309         int i;
 310         const struct {
 311                 const char *oid;
 312                 int (*comparator)(const struct ldb_val *, const struct ldb_val *);
 313         } rules[] = {
 314                 { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
 315                 { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
 316         };
 317         int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
 318         struct ldb_message_element *el;
 319 
 320         if (tree->u.extended.dnAttributes) {
 321                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
 322                 return -1;
 323         }
 324         if (tree->u.extended.rule_id == NULL) {
 325                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
 326                 return -1;
 327         }
 328         if (tree->u.extended.attr == NULL) {
 329                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
 330                 return -1;
 331         }
 332 
 333         for (i=0;i<ARRAY_SIZE(rules);i++) {
 334                 if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
 335                         comp = rules[i].comparator;
 336                         break;
 337                 }
 338         }
 339         if (comp == NULL) {
 340                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
 341                           tree->u.extended.rule_id);
 342                 return -1;
 343         }
 344 
 345         /* find the message element */
 346         el = ldb_msg_find_element(msg, tree->u.extended.attr);
 347         if (el == NULL) {
 348                 return 0;
 349         }
 350 
 351         for (i=0;i<el->num_values;i++) {
 352                 int ret = comp(&el->values[i], &tree->u.extended.value);
 353                 if (ret == -1 || ret == 1) return ret;
 354         }
 355 
 356         return 0;
 357 }
 358 
 359 /*
 360   return 0 if the given parse tree matches the given message. Assumes
 361   the message is in sorted order
 362 
 363   return 1 if it matches, and 0 if it doesn't match
 364 
 365   this is a recursive function, and does short-circuit evaluation
 366  */
 367 static int ldb_match_message(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 368                              const struct ldb_message *msg,
 369                              const struct ldb_parse_tree *tree,
 370                              enum ldb_scope scope)
 371 {
 372         unsigned int i;
 373         int v;
 374 
 375         switch (tree->operation) {
 376         case LDB_OP_AND:
 377                 for (i=0;i<tree->u.list.num_elements;i++) {
 378                         v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
 379                         if (!v) return 0;
 380                 }
 381                 return 1;
 382 
 383         case LDB_OP_OR:
 384                 for (i=0;i<tree->u.list.num_elements;i++) {
 385                         v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
 386                         if (v) return 1;
 387                 }
 388                 return 0;
 389 
 390         case LDB_OP_NOT:
 391                 return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
 392 
 393         case LDB_OP_EQUALITY:
 394                 return ldb_match_equality(ldb, msg, tree, scope);
 395 
 396         case LDB_OP_SUBSTRING:
 397                 return ldb_match_substring(ldb, msg, tree, scope);
 398 
 399         case LDB_OP_GREATER:
 400                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
 401 
 402         case LDB_OP_LESS:
 403                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
 404 
 405         case LDB_OP_PRESENT:
 406                 return ldb_match_present(ldb, msg, tree, scope);
 407 
 408         case LDB_OP_APPROX:
 409                 return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
 410 
 411         case LDB_OP_EXTENDED:
 412                 return ldb_match_extended(ldb, msg, tree, scope);
 413 
 414         }
 415 
 416         return 0;
 417 }
 418 
 419 int ldb_match_msg(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 420                   const struct ldb_message *msg,
 421                   const struct ldb_parse_tree *tree,
 422                   const struct ldb_dn *base,
 423                   enum ldb_scope scope)
 424 {
 425         if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
 426                 return 0;
 427         }
 428 
 429         return ldb_match_message(ldb, msg, tree, scope);
 430 }

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