r8529: Matching against the wrong union
[metze/samba/wip.git] / source4 / 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 2 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, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26 /*
27  *  Name: ldb
28  *
29  *  Component: ldb expression matching
30  *
31  *  Description: ldb expression matching 
32  *
33  *  Author: Andrew Tridgell
34  */
35
36 #include "includes.h"
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_private.h"
39
40
41 /*
42   check if the scope matches in a search result
43 */
44 static int ldb_match_scope(struct ldb_context *ldb,
45                            const char *base_str,
46                            const char *dn_str,
47                            enum ldb_scope scope)
48 {
49         struct ldb_dn *base;
50         struct ldb_dn *dn;
51         int ret = 0;
52
53         if (base_str == NULL) {
54                 return 1;
55         }
56
57         base = ldb_dn_explode_casefold(ldb, base_str);
58         if (base == NULL) return 0;
59
60         dn = ldb_dn_explode_casefold(ldb, dn_str);
61         if (dn == NULL) {
62                 talloc_free(base);
63                 return 0;
64         }
65
66         switch (scope) {
67         case LDB_SCOPE_BASE:
68                 if (ldb_dn_compare(ldb, base, dn) == 0) {
69                         ret = 1;
70                 }
71                 break;
72
73         case LDB_SCOPE_ONELEVEL:
74                 if (dn->comp_num != base->comp_num) {
75                         if (ldb_dn_compare_base(ldb, base, dn) == 0) {
76                                 ret = 1;
77                         }
78                 }
79                 break;
80                 
81         case LDB_SCOPE_SUBTREE:
82         default:
83                 if (ldb_dn_compare_base(ldb, base, dn) == 0) {
84                         ret = 1;
85                 }
86                 break;
87         }
88
89         talloc_free(base);
90         talloc_free(dn);
91         return ret;
92 }
93
94
95 /*
96   match if node is present
97 */
98 static int ldb_match_present(struct ldb_context *ldb, 
99                             struct ldb_message *msg,
100                             struct ldb_parse_tree *tree,
101                             const char *base,
102                             enum ldb_scope scope)
103 {
104
105         if (ldb_attr_cmp(tree->u.present.attr, "dn") == 0) {
106                 return 1;
107         }
108
109         if (ldb_msg_find_element(msg, tree->u.present.attr)) {
110                 return 1;
111         }
112
113         return 0;
114 }
115
116 /*
117   match a simple leaf node
118 */
119 static int ldb_match_simple(struct ldb_context *ldb, 
120                             struct ldb_message *msg,
121                             struct ldb_parse_tree *tree,
122                             const char *base,
123                             enum ldb_scope scope)
124 {
125         unsigned int i;
126         struct ldb_message_element *el;
127         const struct ldb_attrib_handler *h;
128         struct ldb_dn *msgdn, *valuedn;
129         int ret;
130
131         if (ldb_attr_cmp(tree->u.simple.attr, "dn") == 0) {
132
133                 msgdn = ldb_dn_explode_casefold(ldb, msg->dn);
134                 if (msgdn == NULL) return 0;
135
136                 valuedn = ldb_dn_explode_casefold(ldb, tree->u.simple.value.data);
137                 if (valuedn == NULL) {
138                         talloc_free(msgdn);
139                         return 0;
140                 }
141
142                 ret = ldb_dn_compare(ldb, msgdn, valuedn);
143
144                 talloc_free(msgdn);
145                 talloc_free(valuedn);
146
147                 if (ret == 0) return 1;
148                 return 0;
149         }
150
151         el = ldb_msg_find_element(msg, tree->u.simple.attr);
152         if (el == NULL) {
153                 return 0;
154         }
155
156         h = ldb_attrib_handler(ldb, el->name);
157
158         for (i=0;i<el->num_values;i++) {
159                 if (h->comparison_fn(ldb, ldb, &tree->u.simple.value, 
160                                      &el->values[i]) == 0) {
161                         return 1;
162                 }
163         }
164
165         return 0;
166 }
167
168 static int ldb_wildcard_compare(struct ldb_context *ldb,
169                                 struct ldb_parse_tree *tree,
170                                 const struct ldb_val value)
171 {
172         const struct ldb_attrib_handler *h;
173         struct ldb_val val;
174         struct ldb_val cnk;
175         struct ldb_val *chunk;
176         char *p, *g;
177         char *save_p = NULL;
178         int c = 0;
179
180         h = ldb_attrib_handler(ldb, tree->u.substring.attr);
181
182         if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
183                 return -1;
184
185         save_p = val.data;
186         cnk.data = NULL;
187
188         if ( ! tree->u.substring.start_with_wildcard ) {
189
190                 chunk = tree->u.substring.chunks[c];
191                 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
192
193                 /* FIXME: case of embedded nulls */
194                 if (strncmp(val.data, cnk.data, cnk.length) != 0) goto failed;
195                 val.length -= cnk.length;
196                 val.data += cnk.length;
197                 c++;
198                 talloc_free(cnk.data);
199                 cnk.data = NULL;
200         }
201
202         while (tree->u.substring.chunks[c]) {
203
204                 chunk = tree->u.substring.chunks[c];
205                 if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
206
207                 /* FIXME: case of embedded nulls */
208                 p = strstr(val.data, cnk.data);
209                 if (p == NULL) goto failed;
210                 if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
211                         do { /* greedy */
212                                 g = strstr(p + cnk.length, cnk.data);
213                                 if (g) p = g;
214                         } while(g);
215                 }
216                 val.length = val.length - (p - (char *)(val.data)) - cnk.length;
217                 val.data = p + cnk.length;
218                 c++;
219                 talloc_free(cnk.data);
220                 cnk.data = NULL;
221         }
222
223         if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
224         talloc_free(save_p);
225         return 1;
226
227 failed:
228         talloc_free(save_p);
229         talloc_free(cnk.data);
230         return 0;
231 }
232
233 /*
234   match a simple leaf node
235 */
236 static int ldb_match_substring(struct ldb_context *ldb, 
237                                struct ldb_message *msg,
238                                struct ldb_parse_tree *tree,
239                                const char *base,
240                                enum ldb_scope scope)
241 {
242         unsigned int i;
243         struct ldb_message_element *el;
244
245         el = ldb_msg_find_element(msg, tree->u.simple.attr);
246         if (el == NULL) {
247                 return 0;
248         }
249
250         for (i = 0; i < el->num_values; i++) {
251                 if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
252                         return 1;
253                 }
254         }
255
256         return 0;
257 }
258
259
260 /*
261   bitwise-and comparator
262 */
263 static int ldb_comparator_and(struct ldb_val *v1, struct ldb_val *v2)
264 {
265         uint64_t i1, i2;
266         i1 = strtoull(v1->data, NULL, 0);
267         i2 = strtoull(v2->data, NULL, 0);
268         return ((i1 & i2) == i2);
269 }
270
271 /*
272   bitwise-or comparator
273 */
274 static int ldb_comparator_or(struct ldb_val *v1, struct ldb_val *v2)
275 {
276         uint64_t i1, i2;
277         i1 = strtoull(v1->data, NULL, 0);
278         i2 = strtoull(v2->data, NULL, 0);
279         return ((i1 & i2) != 0);
280 }
281
282
283 /*
284   extended match, handles things like bitops
285 */
286 static int ldb_match_extended(struct ldb_context *ldb, 
287                               struct ldb_message *msg,
288                               struct ldb_parse_tree *tree,
289                               const char *base,
290                               enum ldb_scope scope)
291 {
292         int i;
293         const struct {
294                 const char *oid;
295                 int (*comparator)(struct ldb_val *, struct ldb_val *);
296         } rules[] = {
297                 { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
298                 { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
299         };
300         int (*comp)(struct ldb_val *, struct ldb_val *) = NULL;
301         struct ldb_message_element *el;
302
303         if (tree->u.extended.dnAttributes) {
304                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
305                 return -1;
306         }
307         if (tree->u.extended.rule_id == NULL) {
308                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
309                 return -1;
310         }
311         if (tree->u.extended.attr == NULL) {
312                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
313                 return -1;
314         }
315
316         for (i=0;i<ARRAY_SIZE(rules);i++) {
317                 if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
318                         comp = rules[i].comparator;
319                         break;
320                 }
321         }
322         if (comp == NULL) {
323                 ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
324                           tree->u.extended.rule_id);
325                 return -1;
326         }
327
328         /* find the message element */
329         el = ldb_msg_find_element(msg, tree->u.extended.attr);
330         if (el == NULL) {
331                 return 0;
332         }
333
334         for (i=0;i<el->num_values;i++) {
335                 int ret = comp(&el->values[i], &tree->u.extended.value);
336                 if (ret == -1 || ret == 1) return ret;
337         }
338
339         return 0;
340 }
341
342 /*
343   return 0 if the given parse tree matches the given message. Assumes
344   the message is in sorted order
345
346   return 1 if it matches, and 0 if it doesn't match
347
348   this is a recursive function, and does short-circuit evaluation
349  */
350 static int ldb_match_message(struct ldb_context *ldb, 
351                              struct ldb_message *msg,
352                              struct ldb_parse_tree *tree,
353                              const char *base,
354                              enum ldb_scope scope)
355 {
356         unsigned int i;
357         int v;
358
359         switch (tree->operation) {
360         case LDB_OP_SIMPLE:
361                 return ldb_match_simple(ldb, msg, tree, base, scope);
362
363         case LDB_OP_PRESENT:
364                 return ldb_match_present(ldb, msg, tree, base, scope);
365
366         case LDB_OP_SUBSTRING:
367                 return ldb_match_substring(ldb, msg, tree, base, scope);
368
369         case LDB_OP_EXTENDED:
370                 return ldb_match_extended(ldb, msg, tree, base, scope);
371
372         case LDB_OP_NOT:
373                 return ! ldb_match_message(ldb, msg, tree->u.isnot.child, base, scope);
374
375         case LDB_OP_AND:
376                 for (i=0;i<tree->u.list.num_elements;i++) {
377                         v = ldb_match_message(ldb, msg, tree->u.list.elements[i],
378                                                base, 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],
386                                               base, scope);
387                         if (v) return 1;
388                 }
389                 return 0;
390         }
391
392         return 0;
393 }
394
395 int ldb_match_msg(struct ldb_context *ldb,
396                   struct ldb_message *msg,
397                   struct ldb_parse_tree *tree,
398                   const char *base,
399                   enum ldb_scope scope)
400 {
401         if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
402                 return 0;
403         }
404
405         return ldb_match_message(ldb, msg, tree, base, scope);
406 }