added the rest of the ldb_modify() code, which required a fairly large
[samba.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 int ldb_val_equal(const struct ldb_val *v1, const 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, j;
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                         if (strcmp(tree->u.simple.value.data, "*") == 0) {
127                                 return 1;
128                         }
129                         for (j=0;j<msg->elements[i].num_values;j++) {
130                                 if (ldb_val_equal(&msg->elements[i].values[j], 
131                                                   &tree->u.simple.value)) {
132                                         return 1;
133                                 }
134                         }
135                 }
136         }
137
138         return 0;
139 }
140
141 /*
142   return 0 if the given parse tree matches the given message. Assumes
143   the message is in sorted order
144
145   return 1 if it matches, and 0 if it doesn't match
146
147   this is a recursive function, and does short-circuit evaluation
148  */
149 int ldb_message_match(struct ldb_context *ldb, 
150                       struct ldb_message *msg,
151                       struct ldb_parse_tree *tree,
152                       const char *base,
153                       enum ldb_scope scope)
154 {
155         int v, i;
156
157         switch (tree->operation) {
158         case LDB_OP_SIMPLE:
159                 break;
160
161         case LDB_OP_NOT:
162                 return ! ldb_message_match(ldb, msg, tree->u.not.child, base, scope);
163
164         case LDB_OP_AND:
165                 for (i=0;i<tree->u.list.num_elements;i++) {
166                         v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
167                                               base, scope);
168                         if (!v) return 0;
169                 }
170                 return 1;
171
172         case LDB_OP_OR:
173                 for (i=0;i<tree->u.list.num_elements;i++) {
174                         v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
175                                               base, scope);
176                         if (v) return 1;
177                 }
178                 return 0;
179         }
180
181         return match_leaf(ldb, msg, tree, base, scope);
182 }