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_includes.h"
34 #include "dsdb/samdb/samdb.h"
37 * Make a and 'and' or 'or' tree from the two supplied elements
39 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_parse_tree
*list
;
45 list
= talloc(mem_ctx
, struct ldb_parse_tree
);
52 list
->u
.list
.num_elements
= 2;
53 list
->u
.list
.elements
= talloc_array(list
, struct ldb_parse_tree
*, 2);
54 if (!list
->u
.list
.elements
) {
58 list
->u
.list
.elements
[0] = talloc_steal(list
, first_arm
);
59 list
->u
.list
.elements
[1] = talloc_steal(list
, second_arm
);
64 * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
66 struct ldb_parse_tree
*make_match_tree(struct ldb_module
*module
,
67 TALLOC_CTX
*mem_ctx
, enum ldb_parse_op op
,
68 const char *attr
, const DATA_BLOB
*match
)
70 struct ldb_parse_tree
*match_tree
;
72 match_tree
= talloc(mem_ctx
, struct ldb_parse_tree
);
74 /* Depending on what type of match was selected, fill in the right part of the union */
76 match_tree
->operation
= op
;
78 case LDB_OP_SUBSTRING
:
79 match_tree
->u
.substring
.attr
= attr
;
81 match_tree
->u
.substring
.start_with_wildcard
= 0;
82 match_tree
->u
.substring
.end_with_wildcard
= 1;
83 match_tree
->u
.substring
.chunks
= talloc_array(match_tree
, struct ldb_val
*, 2);
85 if (match_tree
->u
.substring
.chunks
== NULL
){
89 match_tree
->u
.substring
.chunks
[0] = match
;
90 match_tree
->u
.substring
.chunks
[1] = NULL
;
93 match_tree
->u
.equality
.attr
= attr
;
94 match_tree
->u
.equality
.value
= *match
;
102 struct ldb_module
*module
;
103 struct ldb_request
*req
;
107 * Given the match for an 'ambigious name resolution' query, create a
108 * parse tree with an 'or' of all the anr attributes in the schema.
112 * Callback function to do the heavy lifting for the parse tree walker
114 static int anr_replace_value(struct anr_context
*ac
,
116 const struct ldb_val
*match
,
117 struct ldb_parse_tree
**ntree
)
119 struct ldb_parse_tree
*tree
= NULL
;
120 struct ldb_module
*module
= ac
->module
;
121 struct ldb_parse_tree
*match_tree
;
122 struct dsdb_attribute
*cur
;
123 const struct dsdb_schema
*schema
= dsdb_get_schema(module
->ldb
);
125 enum ldb_parse_op op
;
128 ldb_asprintf_errstring(module
->ldb
, "no schema with which to construct anr filter");
129 return LDB_ERR_OPERATIONS_ERROR
;
132 ac
->found_anr
= true;
134 if (match
->length
> 1 && match
->data
[0] == '=') {
135 DATA_BLOB
*match2
= talloc(mem_ctx
, DATA_BLOB
);
136 *match2
= data_blob_const(match
->data
+1, match
->length
- 1);
138 ldb_oom(module
->ldb
);
139 return LDB_ERR_OPERATIONS_ERROR
;
142 op
= LDB_OP_EQUALITY
;
144 op
= LDB_OP_SUBSTRING
;
146 for (cur
= schema
->attributes
; cur
; cur
= cur
->next
) {
147 if (!(cur
->searchFlags
& SEARCH_FLAG_ANR
)) continue;
148 match_tree
= make_match_tree(module
, mem_ctx
, op
, cur
->lDAPDisplayName
, match
);
151 /* Inject an 'or' with the current tree */
152 tree
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
, tree
, match_tree
);
154 ldb_oom(module
->ldb
);
155 return LDB_ERR_OPERATIONS_ERROR
;
163 /* If the search term has a space in it,
164 split it up at the first space. */
166 p
= memchr(match
->data
, ' ', match
->length
);
169 struct ldb_parse_tree
*first_split_filter
, *second_split_filter
, *split_filters
, *match_tree_1
, *match_tree_2
;
170 DATA_BLOB
*first_match
= talloc(tree
, DATA_BLOB
);
171 DATA_BLOB
*second_match
= talloc(tree
, DATA_BLOB
);
172 if (!first_match
|| !second_match
) {
173 ldb_oom(module
->ldb
);
174 return LDB_ERR_OPERATIONS_ERROR
;
176 *first_match
= data_blob_const(match
->data
, p
-match
->data
);
177 *second_match
= data_blob_const(p
+1, match
->length
- (p
-match
->data
) - 1);
179 /* Add (|(&(givenname=first)(sn=second))(&(givenname=second)(sn=first))) */
181 match_tree_1
= make_match_tree(module
, mem_ctx
, op
, "givenName", first_match
);
182 match_tree_2
= make_match_tree(module
, mem_ctx
, op
, "sn", second_match
);
184 first_split_filter
= make_parse_list(module
, ac
, LDB_OP_AND
, match_tree_1
, match_tree_2
);
185 if (first_split_filter
== NULL
){
186 ldb_oom(module
->ldb
);
187 return LDB_ERR_OPERATIONS_ERROR
;
190 match_tree_1
= make_match_tree(module
, mem_ctx
, op
, "sn", first_match
);
191 match_tree_2
= make_match_tree(module
, mem_ctx
, op
, "givenName", second_match
);
193 second_split_filter
= make_parse_list(module
, ac
, LDB_OP_AND
, match_tree_1
, match_tree_2
);
194 if (second_split_filter
== NULL
){
195 ldb_oom(module
->ldb
);
196 return LDB_ERR_OPERATIONS_ERROR
;
199 split_filters
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
,
200 first_split_filter
, second_split_filter
);
201 if (split_filters
== NULL
) {
202 ldb_oom(module
->ldb
);
203 return LDB_ERR_OPERATIONS_ERROR
;
207 /* Inject an 'or' with the current tree */
208 tree
= make_parse_list(module
, mem_ctx
, LDB_OP_OR
, tree
, split_filters
);
210 tree
= split_filters
;
218 replace any occurances of an attribute with a new, generated attribute tree
220 static int anr_replace_subtrees(struct anr_context
*ac
,
221 struct ldb_parse_tree
*tree
,
223 struct ldb_parse_tree
**ntree
)
228 switch (tree
->operation
) {
231 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
232 ret
= anr_replace_subtrees(ac
, tree
->u
.list
.elements
[i
],
233 attr
, &tree
->u
.list
.elements
[i
]);
234 if (ret
!= LDB_SUCCESS
) {
241 ret
= anr_replace_subtrees(ac
, tree
->u
.isnot
.child
, attr
, &tree
->u
.isnot
.child
);
242 if (ret
!= LDB_SUCCESS
) {
247 case LDB_OP_EQUALITY
:
248 if (ldb_attr_cmp(tree
->u
.equality
.attr
, attr
) == 0) {
249 ret
= anr_replace_value(ac
, tree
, &tree
->u
.equality
.value
, ntree
);
250 if (ret
!= LDB_SUCCESS
) {
255 case LDB_OP_SUBSTRING
:
256 if (ldb_attr_cmp(tree
->u
.substring
.attr
, attr
) == 0) {
257 if (tree
->u
.substring
.start_with_wildcard
== 0 &&
258 tree
->u
.substring
.end_with_wildcard
== 1 &&
259 tree
->u
.substring
.chunks
[0] != NULL
&&
260 tree
->u
.substring
.chunks
[1] == NULL
) {
261 ret
= anr_replace_value(ac
, tree
, tree
->u
.substring
.chunks
[0], ntree
);
262 if (ret
!= LDB_SUCCESS
) {
275 static int anr_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
277 struct anr_context
*ac
;
279 ac
= talloc_get_type(req
->context
, struct anr_context
);
282 return ldb_module_done(ac
->req
, NULL
, NULL
,
283 LDB_ERR_OPERATIONS_ERROR
);
285 if (ares
->error
!= LDB_SUCCESS
) {
286 return ldb_module_done(ac
->req
, ares
->controls
,
287 ares
->response
, ares
->error
);
290 switch (ares
->type
) {
291 case LDB_REPLY_ENTRY
:
292 return ldb_module_send_entry(ac
->req
, ares
->message
);
294 case LDB_REPLY_REFERRAL
:
295 return ldb_module_send_referral(ac
->req
, ares
->referral
);
298 return ldb_module_done(ac
->req
, ares
->controls
,
299 ares
->response
, LDB_SUCCESS
);
306 static int anr_search(struct ldb_module
*module
, struct ldb_request
*req
)
308 struct ldb_parse_tree
*anr_tree
;
309 struct ldb_request
*down_req
;
310 struct anr_context
*ac
;
313 ac
= talloc(req
, struct anr_context
);
315 ldb_oom(module
->ldb
);
316 return LDB_ERR_OPERATIONS_ERROR
;
321 ac
->found_anr
= false;
324 printf("oldanr : %s\n", ldb_filter_from_tree (0, req
->op
.search
.tree
));
327 ret
= anr_replace_subtrees(ac
, req
->op
.search
.tree
, "anr", &anr_tree
);
328 if (ret
!= LDB_SUCCESS
) {
329 return LDB_ERR_OPERATIONS_ERROR
;
332 if (!ac
->found_anr
) {
334 return ldb_next_request(module
, req
);
337 ret
= ldb_build_search_req_ex(&down_req
,
340 req
->op
.search
.scope
,
342 req
->op
.search
.attrs
,
344 ac
, anr_search_callback
,
346 if (ret
!= LDB_SUCCESS
) {
347 return LDB_ERR_OPERATIONS_ERROR
;
349 talloc_steal(down_req
, anr_tree
);
351 return ldb_next_request(module
, down_req
);
354 _PUBLIC_
const struct ldb_module_ops ldb_anr_module_ops
= {