r23798: updated old Temple Place FSF addresses to new URL
[sfrench/samba-autobuild/.git] / source3 / lib / ldb / common / ldb_match.c
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,
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, 
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, 
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, 
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,
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, 
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)
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)
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, 
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, 
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,
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 }