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"
35 #include "dsdb/samdb/ldb_modules/util.h"
40 * Make a and 'and' or 'or' tree from the two supplied elements
42 static struct ldb_parse_tree
*make_parse_list(struct ldb_module
*module
,
43 TALLOC_CTX
*mem_ctx
, enum ldb_parse_op op
,
44 struct ldb_parse_tree
*first_arm
, struct ldb_parse_tree
*second_arm
)
46 struct ldb_context
*ldb
;
47 struct ldb_parse_tree
*list
;
49 ldb
= ldb_module_get_ctx(module
);
51 list
= talloc(mem_ctx
, struct ldb_parse_tree
);
58 list
->u
.list
.num_elements
= 2;
59 list
->u
.list
.elements
= talloc_array(list
, struct ldb_parse_tree
*, 2);
60 if (!list
->u
.list
.elements
) {
64 list
->u
.list
.elements
[0] = talloc_steal(list
, first_arm
);
65 list
->u
.list
.elements
[1] = talloc_steal(list
, second_arm
);
70 * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
72 static struct ldb_parse_tree
*make_match_tree(struct ldb_module
*module
,
76 struct ldb_val
*match
)
78 struct ldb_context
*ldb
;
79 struct ldb_parse_tree
*match_tree
;
81 ldb
= ldb_module_get_ctx(module
);
83 match_tree
= talloc(mem_ctx
, struct ldb_parse_tree
);
85 /* Depending on what type of match was selected, fill in the right part of the union */
87 match_tree
->operation
= op
;
89 case LDB_OP_SUBSTRING
:
90 match_tree
->u
.substring
.attr
= attr
;
92 match_tree
->u
.substring
.start_with_wildcard
= 0;
93 match_tree
->u
.substring
.end_with_wildcard
= 1;
94 match_tree
->u
.substring
.chunks
= talloc_array(match_tree
, struct ldb_val
*, 2);
96 if (match_tree
->u
.substring
.chunks
== NULL
){
97 talloc_free(match_tree
);
101 match_tree
->u
.substring
.chunks
[0] = match
;
102 match_tree
->u
.substring
.chunks
[1] = NULL
;
104 case LDB_OP_EQUALITY
:
105 match_tree
->u
.equality
.attr
= attr
;
106 match_tree
->u
.equality
.value
= *match
;
109 talloc_free(match_tree
);
117 struct ldb_module
*module
;
118 struct ldb_request
*req
;
122 * Given the match for an 'ambigious name resolution' query, create a
123 * parse tree with an 'or' of all the anr attributes in the schema.
127 * Callback function to do the heavy lifting for the parse tree walker
129 static int anr_replace_value(struct anr_context
*ac
,
131 struct ldb_val
*match
,
132 struct ldb_parse_tree
**ntree
)
134 struct ldb_parse_tree
*tree
= NULL
;
135 struct ldb_module
*module
= ac
->module
;
136 struct ldb_parse_tree
*match_tree
;
137 struct dsdb_attribute
*cur
;
138 const struct dsdb_schema
*schema
;
139 struct ldb_context
*ldb
;
141 enum ldb_parse_op op
;
143 ldb
= ldb_module_get_ctx(module
);
145 schema
= dsdb_get_schema(ldb
, ac
);
147 ldb_asprintf_errstring(ldb
, "no schema with which to construct anr filter");
148 return LDB_ERR_OPERATIONS_ERROR
;
151 if (match
->length
> 1 && match
->data
[0] == '=') {
152 struct ldb_val
*match2
= talloc(mem_ctx
, struct ldb_val
);
156 *match2
= data_blob_const(match
->data
+1, match
->length
- 1);
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
);
178 /* If the search term has a space in it,
179 split it up at the first space. */
181 p
= memchr(match
->data
, ' ', match
->length
);
184 struct ldb_parse_tree
*first_split_filter
, *second_split_filter
, *split_filters
, *match_tree_1
, *match_tree_2
;
185 struct ldb_val
*first_match
= talloc(tree
, struct ldb_val
);
186 struct ldb_val
*second_match
= talloc(tree
, struct ldb_val
);
187 if (!first_match
|| !second_match
) {
190 *first_match
= data_blob_const(match
->data
, p
-match
->data
);
191 *second_match
= data_blob_const(p
+1, match
->length
- (p
-match
->data
) - 1);
193 /* Add (|(&(givenname=first)(sn=second))(&(givenname=second)(sn=first))) */
195 match_tree_1
= make_match_tree(module
, mem_ctx
, op
, "givenName", first_match
);
196 match_tree_2
= make_match_tree(module
, mem_ctx
, op
, "sn", second_match
);
198 first_split_filter
= make_parse_list(module
, ac
, LDB_OP_AND
, match_tree_1
, match_tree_2
);
199 if (first_split_filter
== NULL
){
203 match_tree_1
= make_match_tree(module
, mem_ctx
, op
, "sn", first_match
);
204 match_tree_2
= make_match_tree(module
, mem_ctx
, op
, "givenName", second_match
);
206 second_split_filter
= make_parse_list(module
, ac
, LDB_OP_AND
, match_tree_1
, match_tree_2
);
207 if (second_split_filter
== NULL
){
211 split_filters
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
,
212 first_split_filter
, second_split_filter
);
213 if (split_filters
== NULL
) {
218 /* Inject an 'or' with the current tree */
219 tree
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
, tree
, split_filters
);
221 tree
= split_filters
;
229 replace any occurrences of an attribute with a new, generated attribute tree
231 static int anr_replace_subtrees(struct anr_context
*ac
,
232 struct ldb_parse_tree
*tree
,
234 struct ldb_parse_tree
**ntree
)
239 switch (tree
->operation
) {
242 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
243 ret
= anr_replace_subtrees(ac
, tree
->u
.list
.elements
[i
],
244 attr
, &tree
->u
.list
.elements
[i
]);
245 if (ret
!= LDB_SUCCESS
) {
252 ret
= anr_replace_subtrees(ac
, tree
->u
.isnot
.child
, attr
, &tree
->u
.isnot
.child
);
253 if (ret
!= LDB_SUCCESS
) {
258 case LDB_OP_EQUALITY
:
259 if (ldb_attr_cmp(tree
->u
.equality
.attr
, attr
) == 0) {
260 ret
= anr_replace_value(ac
, tree
, &tree
->u
.equality
.value
, ntree
);
261 if (ret
!= LDB_SUCCESS
) {
266 case LDB_OP_SUBSTRING
:
267 if (ldb_attr_cmp(tree
->u
.substring
.attr
, attr
) == 0) {
268 if (tree
->u
.substring
.start_with_wildcard
== 0 &&
269 tree
->u
.substring
.end_with_wildcard
== 1 &&
270 tree
->u
.substring
.chunks
[0] != NULL
&&
271 tree
->u
.substring
.chunks
[1] == NULL
) {
272 ret
= anr_replace_value(ac
, tree
, tree
->u
.substring
.chunks
[0], ntree
);
273 if (ret
!= LDB_SUCCESS
) {
286 struct anr_present_ctx
{
292 callback to determine if ANR is in use at all
294 static int parse_tree_anr_present(struct ldb_parse_tree
*tree
, void *private_context
)
296 struct anr_present_ctx
*ctx
= private_context
;
297 switch (tree
->operation
) {
298 case LDB_OP_EQUALITY
:
299 if (ldb_attr_cmp(tree
->u
.equality
.attr
, ctx
->attr
) == 0) {
300 ctx
->found_anr
= true;
306 if (ldb_attr_cmp(tree
->u
.comparison
.attr
, ctx
->attr
) == 0) {
307 ctx
->found_anr
= true;
310 case LDB_OP_SUBSTRING
:
311 if (ldb_attr_cmp(tree
->u
.substring
.attr
, ctx
->attr
) == 0) {
312 ctx
->found_anr
= true;
316 if (ldb_attr_cmp(tree
->u
.present
.attr
, ctx
->attr
) == 0) {
317 ctx
->found_anr
= true;
320 case LDB_OP_EXTENDED
:
321 if (tree
->u
.extended
.attr
&&
322 ldb_attr_cmp(tree
->u
.extended
.attr
, ctx
->attr
) == 0) {
323 ctx
->found_anr
= true;
333 static int anr_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
335 struct anr_context
*ac
;
337 ac
= talloc_get_type(req
->context
, struct anr_context
);
340 return ldb_module_done(ac
->req
, NULL
, NULL
,
341 LDB_ERR_OPERATIONS_ERROR
);
343 if (ares
->error
!= LDB_SUCCESS
) {
344 return ldb_module_done(ac
->req
, ares
->controls
,
345 ares
->response
, ares
->error
);
348 switch (ares
->type
) {
349 case LDB_REPLY_ENTRY
:
350 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
352 case LDB_REPLY_REFERRAL
:
353 return ldb_module_send_referral(ac
->req
, ares
->referral
);
356 return ldb_module_done(ac
->req
, ares
->controls
,
357 ares
->response
, LDB_SUCCESS
);
364 static int anr_search(struct ldb_module
*module
, struct ldb_request
*req
)
366 struct ldb_context
*ldb
;
367 struct ldb_parse_tree
*anr_tree
;
368 struct ldb_request
*down_req
;
369 struct anr_context
*ac
;
370 struct anr_present_ctx ctx
;
371 const char *attr
= "anr";
374 ctx
.found_anr
= false;
377 ldb_parse_tree_walk(req
->op
.search
.tree
,
378 parse_tree_anr_present
,
381 if (!ctx
.found_anr
) {
382 return ldb_next_request(module
, req
);
385 ldb
= ldb_module_get_ctx(module
);
387 ac
= talloc(req
, struct anr_context
);
396 printf("oldanr : %s\n", ldb_filter_from_tree (0, req
->op
.search
.tree
));
399 /* First make a copy, so we don't overwrite caller memory */
401 anr_tree
= ldb_parse_tree_copy_shallow(ac
, req
->op
.search
.tree
);
403 if (anr_tree
== NULL
) {
404 return ldb_operr(ldb
);
407 /* Now expand 'anr' out */
408 ret
= anr_replace_subtrees(ac
, anr_tree
, attr
, &anr_tree
);
409 if (ret
!= LDB_SUCCESS
) {
410 return ldb_operr(ldb
);
413 ret
= ldb_build_search_req_ex(&down_req
,
416 req
->op
.search
.scope
,
418 req
->op
.search
.attrs
,
420 ac
, anr_search_callback
,
422 LDB_REQ_SET_LOCATION(down_req
);
423 if (ret
!= LDB_SUCCESS
) {
424 return ldb_operr(ldb
);
426 talloc_steal(down_req
, anr_tree
);
428 return ldb_next_request(module
, down_req
);
431 static const struct ldb_module_ops ldb_anr_module_ops
= {
436 int ldb_anr_module_init(const char *version
)
438 LDB_MODULE_CHECK_VERSION(version
);
439 return ldb_register_module(&ldb_anr_module_ops
);