4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5 Copyright (C) Simo Sorce <idra@samba.org> 2008
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: ldb anr module
27 * Description: module to implement 'ambiguous name resolution'
29 * Author: Andrew Bartlett
33 #include "ldb_module.h"
34 #include "dsdb/samdb/samdb.h"
37 * Make a and 'and' or 'or' tree from the two supplied elements
39 static struct ldb_parse_tree
*make_parse_list(struct ldb_module
*module
,
40 TALLOC_CTX
*mem_ctx
, enum ldb_parse_op op
,
41 struct ldb_parse_tree
*first_arm
, struct ldb_parse_tree
*second_arm
)
43 struct ldb_context
*ldb
;
44 struct ldb_parse_tree
*list
;
46 ldb
= ldb_module_get_ctx(module
);
48 list
= talloc(mem_ctx
, struct ldb_parse_tree
);
55 list
->u
.list
.num_elements
= 2;
56 list
->u
.list
.elements
= talloc_array(list
, struct ldb_parse_tree
*, 2);
57 if (!list
->u
.list
.elements
) {
61 list
->u
.list
.elements
[0] = talloc_steal(list
, first_arm
);
62 list
->u
.list
.elements
[1] = talloc_steal(list
, second_arm
);
67 * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
69 static struct ldb_parse_tree
*make_match_tree(struct ldb_module
*module
,
73 struct ldb_val
*match
)
75 struct ldb_context
*ldb
;
76 struct ldb_parse_tree
*match_tree
;
78 ldb
= ldb_module_get_ctx(module
);
80 match_tree
= talloc(mem_ctx
, struct ldb_parse_tree
);
82 /* Depending on what type of match was selected, fill in the right part of the union */
84 match_tree
->operation
= op
;
86 case LDB_OP_SUBSTRING
:
87 match_tree
->u
.substring
.attr
= attr
;
89 match_tree
->u
.substring
.start_with_wildcard
= 0;
90 match_tree
->u
.substring
.end_with_wildcard
= 1;
91 match_tree
->u
.substring
.chunks
= talloc_array(match_tree
, struct ldb_val
*, 2);
93 if (match_tree
->u
.substring
.chunks
== NULL
){
94 talloc_free(match_tree
);
98 match_tree
->u
.substring
.chunks
[0] = match
;
99 match_tree
->u
.substring
.chunks
[1] = NULL
;
101 case LDB_OP_EQUALITY
:
102 match_tree
->u
.equality
.attr
= attr
;
103 match_tree
->u
.equality
.value
= *match
;
106 talloc_free(match_tree
);
114 struct ldb_module
*module
;
115 struct ldb_request
*req
;
119 * Given the match for an 'ambigious name resolution' query, create a
120 * parse tree with an 'or' of all the anr attributes in the schema.
124 * Callback function to do the heavy lifting for the parse tree walker
126 static int anr_replace_value(struct anr_context
*ac
,
128 struct ldb_val
*match
,
129 struct ldb_parse_tree
**ntree
)
131 struct ldb_parse_tree
*tree
= NULL
;
132 struct ldb_module
*module
= ac
->module
;
133 struct ldb_parse_tree
*match_tree
;
134 struct dsdb_attribute
*cur
;
135 const struct dsdb_schema
*schema
;
136 struct ldb_context
*ldb
;
138 enum ldb_parse_op op
;
140 ldb
= ldb_module_get_ctx(module
);
142 schema
= dsdb_get_schema(ldb
);
144 ldb_asprintf_errstring(ldb
, "no schema with which to construct anr filter");
145 return LDB_ERR_OPERATIONS_ERROR
;
148 ac
->found_anr
= true;
150 if (match
->length
> 1 && match
->data
[0] == '=') {
151 struct ldb_val
*match2
= talloc(mem_ctx
, struct ldb_val
);
152 *match2
= data_blob_const(match
->data
+1, match
->length
- 1);
155 return LDB_ERR_OPERATIONS_ERROR
;
158 op
= LDB_OP_EQUALITY
;
160 op
= LDB_OP_SUBSTRING
;
162 for (cur
= schema
->attributes
; cur
; cur
= cur
->next
) {
163 if (!(cur
->searchFlags
& SEARCH_FLAG_ANR
)) continue;
164 match_tree
= make_match_tree(module
, mem_ctx
, op
, cur
->lDAPDisplayName
, match
);
167 /* Inject an 'or' with the current tree */
168 tree
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
, tree
, match_tree
);
171 return LDB_ERR_OPERATIONS_ERROR
;
179 /* If the search term has a space in it,
180 split it up at the first space. */
182 p
= memchr(match
->data
, ' ', match
->length
);
185 struct ldb_parse_tree
*first_split_filter
, *second_split_filter
, *split_filters
, *match_tree_1
, *match_tree_2
;
186 struct ldb_val
*first_match
= talloc(tree
, struct ldb_val
);
187 struct ldb_val
*second_match
= talloc(tree
, struct ldb_val
);
188 if (!first_match
|| !second_match
) {
190 return LDB_ERR_OPERATIONS_ERROR
;
192 *first_match
= data_blob_const(match
->data
, p
-match
->data
);
193 *second_match
= data_blob_const(p
+1, match
->length
- (p
-match
->data
) - 1);
195 /* Add (|(&(givenname=first)(sn=second))(&(givenname=second)(sn=first))) */
197 match_tree_1
= make_match_tree(module
, mem_ctx
, op
, "givenName", first_match
);
198 match_tree_2
= make_match_tree(module
, mem_ctx
, op
, "sn", second_match
);
200 first_split_filter
= make_parse_list(module
, ac
, LDB_OP_AND
, match_tree_1
, match_tree_2
);
201 if (first_split_filter
== NULL
){
203 return LDB_ERR_OPERATIONS_ERROR
;
206 match_tree_1
= make_match_tree(module
, mem_ctx
, op
, "sn", first_match
);
207 match_tree_2
= make_match_tree(module
, mem_ctx
, op
, "givenName", second_match
);
209 second_split_filter
= make_parse_list(module
, ac
, LDB_OP_AND
, match_tree_1
, match_tree_2
);
210 if (second_split_filter
== NULL
){
212 return LDB_ERR_OPERATIONS_ERROR
;
215 split_filters
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
,
216 first_split_filter
, second_split_filter
);
217 if (split_filters
== NULL
) {
219 return LDB_ERR_OPERATIONS_ERROR
;
223 /* Inject an 'or' with the current tree */
224 tree
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
, tree
, split_filters
);
226 tree
= split_filters
;
234 replace any occurances of an attribute with a new, generated attribute tree
236 static int anr_replace_subtrees(struct anr_context
*ac
,
237 struct ldb_parse_tree
*tree
,
239 struct ldb_parse_tree
**ntree
)
244 switch (tree
->operation
) {
247 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
248 ret
= anr_replace_subtrees(ac
, tree
->u
.list
.elements
[i
],
249 attr
, &tree
->u
.list
.elements
[i
]);
250 if (ret
!= LDB_SUCCESS
) {
257 ret
= anr_replace_subtrees(ac
, tree
->u
.isnot
.child
, attr
, &tree
->u
.isnot
.child
);
258 if (ret
!= LDB_SUCCESS
) {
263 case LDB_OP_EQUALITY
:
264 if (ldb_attr_cmp(tree
->u
.equality
.attr
, attr
) == 0) {
265 ret
= anr_replace_value(ac
, tree
, &tree
->u
.equality
.value
, ntree
);
266 if (ret
!= LDB_SUCCESS
) {
271 case LDB_OP_SUBSTRING
:
272 if (ldb_attr_cmp(tree
->u
.substring
.attr
, attr
) == 0) {
273 if (tree
->u
.substring
.start_with_wildcard
== 0 &&
274 tree
->u
.substring
.end_with_wildcard
== 1 &&
275 tree
->u
.substring
.chunks
[0] != NULL
&&
276 tree
->u
.substring
.chunks
[1] == NULL
) {
277 ret
= anr_replace_value(ac
, tree
, tree
->u
.substring
.chunks
[0], ntree
);
278 if (ret
!= LDB_SUCCESS
) {
291 static int anr_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
293 struct anr_context
*ac
;
295 ac
= talloc_get_type(req
->context
, struct anr_context
);
298 return ldb_module_done(ac
->req
, NULL
, NULL
,
299 LDB_ERR_OPERATIONS_ERROR
);
301 if (ares
->error
!= LDB_SUCCESS
) {
302 return ldb_module_done(ac
->req
, ares
->controls
,
303 ares
->response
, ares
->error
);
306 switch (ares
->type
) {
307 case LDB_REPLY_ENTRY
:
308 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
310 case LDB_REPLY_REFERRAL
:
311 return ldb_module_send_referral(ac
->req
, ares
->referral
);
314 return ldb_module_done(ac
->req
, ares
->controls
,
315 ares
->response
, LDB_SUCCESS
);
322 static int anr_search(struct ldb_module
*module
, struct ldb_request
*req
)
324 struct ldb_context
*ldb
;
325 struct ldb_parse_tree
*anr_tree
;
326 struct ldb_request
*down_req
;
327 struct anr_context
*ac
;
330 ldb
= ldb_module_get_ctx(module
);
332 ac
= talloc(req
, struct anr_context
);
335 return LDB_ERR_OPERATIONS_ERROR
;
340 ac
->found_anr
= false;
343 printf("oldanr : %s\n", ldb_filter_from_tree (0, req
->op
.search
.tree
));
346 ret
= anr_replace_subtrees(ac
, req
->op
.search
.tree
, "anr", &anr_tree
);
347 if (ret
!= LDB_SUCCESS
) {
348 return LDB_ERR_OPERATIONS_ERROR
;
351 if (!ac
->found_anr
) {
353 return ldb_next_request(module
, req
);
356 ret
= ldb_build_search_req_ex(&down_req
,
359 req
->op
.search
.scope
,
361 req
->op
.search
.attrs
,
363 ac
, anr_search_callback
,
365 if (ret
!= LDB_SUCCESS
) {
366 return LDB_ERR_OPERATIONS_ERROR
;
368 talloc_steal(down_req
, anr_tree
);
370 return ldb_next_request(module
, down_req
);
373 _PUBLIC_
const struct ldb_module_ops ldb_anr_module_ops
= {