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"
38 * Make a and 'and' or 'or' tree from the two supplied elements
40 static struct ldb_parse_tree
*make_parse_list(struct ldb_module
*module
,
41 TALLOC_CTX
*mem_ctx
, enum ldb_parse_op op
,
42 struct ldb_parse_tree
*first_arm
, struct ldb_parse_tree
*second_arm
)
44 struct ldb_context
*ldb
;
45 struct ldb_parse_tree
*list
;
47 ldb
= ldb_module_get_ctx(module
);
49 list
= talloc(mem_ctx
, struct ldb_parse_tree
);
56 list
->u
.list
.num_elements
= 2;
57 list
->u
.list
.elements
= talloc_array(list
, struct ldb_parse_tree
*, 2);
58 if (!list
->u
.list
.elements
) {
62 list
->u
.list
.elements
[0] = talloc_steal(list
, first_arm
);
63 list
->u
.list
.elements
[1] = talloc_steal(list
, second_arm
);
68 * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
70 static struct ldb_parse_tree
*make_match_tree(struct ldb_module
*module
,
74 struct ldb_val
*match
)
76 struct ldb_context
*ldb
;
77 struct ldb_parse_tree
*match_tree
;
79 ldb
= ldb_module_get_ctx(module
);
81 match_tree
= talloc(mem_ctx
, struct ldb_parse_tree
);
83 /* Depending on what type of match was selected, fill in the right part of the union */
85 match_tree
->operation
= op
;
87 case LDB_OP_SUBSTRING
:
88 match_tree
->u
.substring
.attr
= attr
;
90 match_tree
->u
.substring
.start_with_wildcard
= 0;
91 match_tree
->u
.substring
.end_with_wildcard
= 1;
92 match_tree
->u
.substring
.chunks
= talloc_array(match_tree
, struct ldb_val
*, 2);
94 if (match_tree
->u
.substring
.chunks
== NULL
){
95 talloc_free(match_tree
);
99 match_tree
->u
.substring
.chunks
[0] = match
;
100 match_tree
->u
.substring
.chunks
[1] = NULL
;
102 case LDB_OP_EQUALITY
:
103 match_tree
->u
.equality
.attr
= attr
;
104 match_tree
->u
.equality
.value
= *match
;
107 talloc_free(match_tree
);
115 struct ldb_module
*module
;
116 struct ldb_request
*req
;
120 * Given the match for an 'ambigious name resolution' query, create a
121 * parse tree with an 'or' of all the anr attributes in the schema.
125 * Callback function to do the heavy lifting for the parse tree walker
127 static int anr_replace_value(struct anr_context
*ac
,
129 struct ldb_val
*match
,
130 struct ldb_parse_tree
**ntree
)
132 struct ldb_parse_tree
*tree
= NULL
;
133 struct ldb_module
*module
= ac
->module
;
134 struct ldb_parse_tree
*match_tree
;
135 struct dsdb_attribute
*cur
;
136 const struct dsdb_schema
*schema
;
137 struct ldb_context
*ldb
;
139 enum ldb_parse_op op
;
141 ldb
= ldb_module_get_ctx(module
);
143 schema
= dsdb_get_schema(ldb
, ac
);
145 ldb_asprintf_errstring(ldb
, "no schema with which to construct anr filter");
146 return LDB_ERR_OPERATIONS_ERROR
;
149 ac
->found_anr
= true;
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 occurances 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 static int anr_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
288 struct anr_context
*ac
;
290 ac
= talloc_get_type(req
->context
, struct anr_context
);
293 return ldb_module_done(ac
->req
, NULL
, NULL
,
294 LDB_ERR_OPERATIONS_ERROR
);
296 if (ares
->error
!= LDB_SUCCESS
) {
297 return ldb_module_done(ac
->req
, ares
->controls
,
298 ares
->response
, ares
->error
);
301 switch (ares
->type
) {
302 case LDB_REPLY_ENTRY
:
303 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
305 case LDB_REPLY_REFERRAL
:
306 return ldb_module_send_referral(ac
->req
, ares
->referral
);
309 return ldb_module_done(ac
->req
, ares
->controls
,
310 ares
->response
, LDB_SUCCESS
);
317 static int anr_search(struct ldb_module
*module
, struct ldb_request
*req
)
319 struct ldb_context
*ldb
;
320 struct ldb_parse_tree
*anr_tree
;
321 struct ldb_request
*down_req
;
322 struct anr_context
*ac
;
325 ldb
= ldb_module_get_ctx(module
);
327 ac
= talloc(req
, struct anr_context
);
334 ac
->found_anr
= false;
337 printf("oldanr : %s\n", ldb_filter_from_tree (0, req
->op
.search
.tree
));
340 ret
= anr_replace_subtrees(ac
, req
->op
.search
.tree
, "anr", &anr_tree
);
341 if (ret
!= LDB_SUCCESS
) {
342 return ldb_operr(ldb
);
345 if (!ac
->found_anr
) {
347 return ldb_next_request(module
, req
);
350 ret
= ldb_build_search_req_ex(&down_req
,
353 req
->op
.search
.scope
,
355 req
->op
.search
.attrs
,
357 ac
, anr_search_callback
,
359 LDB_REQ_SET_LOCATION(down_req
);
360 if (ret
!= LDB_SUCCESS
) {
361 return ldb_operr(ldb
);
363 talloc_steal(down_req
, anr_tree
);
365 return ldb_next_request(module
, down_req
);
368 static const struct ldb_module_ops ldb_anr_module_ops
= {
373 int ldb_anr_module_init(const char *version
)
375 LDB_MODULE_CHECK_VERSION(version
);
376 return ldb_register_module(&ldb_anr_module_ops
);