make a more recent snapshot of ldb available to interested
[metze/samba/wip.git] / source4 / lib / ldb / ldb_tdb / ldb_match.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
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 2 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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb expression matching
29  *
30  *  Description: ldb expression matching for tdb backend
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36
37
38 /*
39   see if two ldb_val structures contain the same data
40   return 1 for a match, 0 for a mis-match
41 */
42 static int ldb_val_equal(struct ldb_val *v1, struct ldb_val *v2)
43 {
44         if (v1->length != v2->length) return 0;
45
46         if (v1->length == 0) return 1;
47
48         if (memcmp(v1->data, v2->data, v1->length) == 0) {
49                 return 1;
50         }
51
52         return 0;
53 }
54
55 /*
56   check if the scope matches in a search result
57 */
58 static int scope_match(const char *dn, const char *base, enum ldb_scope scope)
59 {
60         size_t dn_len, base_len;
61
62         if (base == NULL) {
63                 return 1;
64         }
65
66         base_len = strlen(base);
67         dn_len = strlen(dn);
68
69         if (strcmp(dn, base) == 0) {
70                 return 1;
71         }
72
73         if (base_len+1 >= dn_len) {
74                 return 0;
75         }
76
77         switch (scope) {
78         case LDB_SCOPE_BASE:
79                 break;
80
81         case LDB_SCOPE_ONELEVEL:
82                 if (strcmp(dn + (dn_len - base_len), base) == 0 &&
83                     dn[dn_len - base_len - 1] == ',' &&
84                     strchr(dn, ',') == &dn[dn_len - base_len - 1]) {
85                         return 1;
86                 }
87                 break;
88                 
89         case LDB_SCOPE_SUBTREE:
90         default:
91                 if (strcmp(dn + (dn_len - base_len), base) == 0 &&
92                     dn[dn_len - base_len - 1] == ',') {
93                         return 1;
94                 }
95                 break;
96         }
97
98         return 0;
99 }
100
101
102 /*
103   match a leaf node
104 */
105 static int match_leaf(struct ldb_context *ldb, 
106                       struct ldb_message *msg,
107                       struct ldb_parse_tree *tree,
108                       const char *base,
109                       enum ldb_scope scope)
110 {
111         int i;
112
113         if (!scope_match(msg->dn, base, scope)) {
114                 return 0;
115         }
116
117         if (strcmp(tree->u.simple.attr, "dn") == 0) {
118                 if (strcmp(tree->u.simple.value.data, "*") == 0) {
119                         return 1;
120                 }
121                 return strcmp(msg->dn, tree->u.simple.value.data) == 0;
122         }
123
124         for (i=0;i<msg->num_elements;i++) {
125                 if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0 &&
126                     (strcmp(tree->u.simple.value.data, "*") == 0 ||
127                      ldb_val_equal(&msg->elements[i].value, &tree->u.simple.value))) {
128                         return 1;
129                 }
130         }
131
132         return 0;
133 }
134
135 /*
136   return 0 if the given parse tree matches the given message. Assumes
137   the message is in sorted order
138
139   return 1 if it matches, and 0 if it doesn't match
140
141   this is a recursive function, and does short-circuit evaluation
142  */
143 int ldb_message_match(struct ldb_context *ldb, 
144                       struct ldb_message *msg,
145                       struct ldb_parse_tree *tree,
146                       const char *base,
147                       enum ldb_scope scope)
148 {
149         int v, i;
150
151         switch (tree->operation) {
152         case LDB_OP_SIMPLE:
153                 break;
154
155         case LDB_OP_NOT:
156                 return ! ldb_message_match(ldb, msg, tree->u.not.child, base, scope);
157
158         case LDB_OP_AND:
159                 for (i=0;i<tree->u.list.num_elements;i++) {
160                         v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
161                                               base, scope);
162                         if (!v) return 0;
163                 }
164                 return 1;
165
166         case LDB_OP_OR:
167                 for (i=0;i<tree->u.list.num_elements;i++) {
168                         v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
169                                               base, scope);
170                         if (v) return 1;
171                 }
172                 return 0;
173         }
174
175         return match_leaf(ldb, msg, tree, base, scope);
176 }