~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/dsdb/samdb/ldb_modules/anr.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   ldb database library
 
3
 
 
4
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
 
5
   Copyright (C) Simo Sorce <idra@samba.org> 2008
 
6
   Copyright (C) Andrew Tridgell  2004
 
7
    
 
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.
 
12
   
 
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.
 
17
   
 
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/>.
 
20
*/
 
21
 
 
22
/*
 
23
 *  Name: ldb
 
24
 *
 
25
 *  Component: ldb anr module
 
26
 *
 
27
 *  Description: module to implement 'ambiguous name resolution'
 
28
 *
 
29
 *  Author: Andrew Bartlett
 
30
 */
 
31
 
 
32
#include "includes.h"
 
33
#include "ldb_module.h"
 
34
#include "dsdb/samdb/samdb.h"
 
35
 
 
36
/**
 
37
 * Make a and 'and' or 'or' tree from the two supplied elements 
 
38
 */
 
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)
 
42
{
 
43
        struct ldb_context *ldb;
 
44
        struct ldb_parse_tree *list;
 
45
 
 
46
        ldb = ldb_module_get_ctx(module);
 
47
 
 
48
        list = talloc(mem_ctx, struct ldb_parse_tree);
 
49
        if (list == NULL){
 
50
                ldb_oom(ldb);
 
51
                return NULL;
 
52
        }
 
53
        list->operation = op;
 
54
        
 
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) {
 
58
                ldb_oom(ldb);
 
59
                return NULL;
 
60
        }
 
61
        list->u.list.elements[0] = talloc_steal(list, first_arm);
 
62
        list->u.list.elements[1] = talloc_steal(list, second_arm);
 
63
        return list;
 
64
}
 
65
 
 
66
/**
 
67
 * Make an equality or prefix match tree, from the attribute, operation and matching value supplied
 
68
 */
 
69
static struct ldb_parse_tree *make_match_tree(struct ldb_module *module,
 
70
                                       TALLOC_CTX *mem_ctx, enum ldb_parse_op op, 
 
71
                                       const char *attr, const DATA_BLOB *match)
 
72
{
 
73
        struct ldb_context *ldb;
 
74
        struct ldb_parse_tree *match_tree;
 
75
 
 
76
        ldb = ldb_module_get_ctx(module);
 
77
 
 
78
        match_tree = talloc(mem_ctx, struct ldb_parse_tree);
 
79
        
 
80
        /* Depending on what type of match was selected, fill in the right part of the union */
 
81
         
 
82
        match_tree->operation = op;
 
83
        switch (op) {
 
84
        case LDB_OP_SUBSTRING:
 
85
                match_tree->u.substring.attr = attr;
 
86
                
 
87
                match_tree->u.substring.start_with_wildcard = 0;
 
88
                match_tree->u.substring.end_with_wildcard = 1;
 
89
                match_tree->u.substring.chunks = talloc_array(match_tree, struct ldb_val *, 2);
 
90
                
 
91
                if (match_tree->u.substring.chunks == NULL){
 
92
                        ldb_oom(ldb);
 
93
                        return NULL;
 
94
                }
 
95
                match_tree->u.substring.chunks[0] = match;
 
96
                match_tree->u.substring.chunks[1] = NULL;
 
97
                break;
 
98
        case LDB_OP_EQUALITY:
 
99
                match_tree->u.equality.attr = attr;
 
100
                match_tree->u.equality.value = *match;
 
101
                break;
 
102
        }
 
103
        return match_tree;
 
104
}
 
105
 
 
106
struct anr_context {
 
107
        bool found_anr;
 
108
        struct ldb_module *module;
 
109
        struct ldb_request *req;
 
110
};
 
111
 
 
112
/**
 
113
 * Given the match for an 'ambigious name resolution' query, create a
 
114
 * parse tree with an 'or' of all the anr attributes in the schema.  
 
115
 */
 
116
 
 
117
/**
 
118
 * Callback function to do the heavy lifting for the parse tree walker
 
119
 */
 
120
static int anr_replace_value(struct anr_context *ac,
 
121
                             TALLOC_CTX *mem_ctx,
 
122
                             const struct ldb_val *match,
 
123
                             struct ldb_parse_tree **ntree)
 
124
{
 
125
        struct ldb_parse_tree *tree = NULL;
 
126
        struct ldb_module *module = ac->module;
 
127
        struct ldb_parse_tree *match_tree;
 
128
        struct dsdb_attribute *cur;
 
129
        const struct dsdb_schema *schema;
 
130
        struct ldb_context *ldb;
 
131
        uint8_t *p;
 
132
        enum ldb_parse_op op;
 
133
 
 
134
        ldb = ldb_module_get_ctx(module);
 
135
 
 
136
        schema = dsdb_get_schema(ldb);
 
137
        if (!schema) {
 
138
                ldb_asprintf_errstring(ldb, "no schema with which to construct anr filter");
 
139
                return LDB_ERR_OPERATIONS_ERROR;
 
140
        }
 
141
 
 
142
        ac->found_anr = true;
 
143
 
 
144
        if (match->length > 1 && match->data[0] == '=') {
 
145
                DATA_BLOB *match2 = talloc(mem_ctx, DATA_BLOB);
 
146
                *match2 = data_blob_const(match->data+1, match->length - 1);
 
147
                if (match2 == NULL){
 
148
                        ldb_oom(ldb);
 
149
                        return LDB_ERR_OPERATIONS_ERROR;
 
150
                }
 
151
                match = match2;
 
152
                op = LDB_OP_EQUALITY;
 
153
        } else {
 
154
                op = LDB_OP_SUBSTRING;
 
155
        }
 
156
        for (cur = schema->attributes; cur; cur = cur->next) {
 
157
                if (!(cur->searchFlags & SEARCH_FLAG_ANR)) continue;
 
158
                match_tree = make_match_tree(module, mem_ctx, op, cur->lDAPDisplayName, match);
 
159
 
 
160
                if (tree) {
 
161
                        /* Inject an 'or' with the current tree */
 
162
                        tree = make_parse_list(module, mem_ctx,  LDB_OP_OR, tree, match_tree);
 
163
                        if (tree == NULL) {
 
164
                                ldb_oom(ldb);
 
165
                                return LDB_ERR_OPERATIONS_ERROR;
 
166
                        }
 
167
                } else {
 
168
                        tree = match_tree;
 
169
                }
 
170
        }
 
171
 
 
172
        
 
173
        /* If the search term has a space in it, 
 
174
           split it up at the first space.  */
 
175
        
 
176
        p = memchr(match->data, ' ', match->length);
 
177
 
 
178
        if (p) {
 
179
                struct ldb_parse_tree *first_split_filter, *second_split_filter, *split_filters, *match_tree_1, *match_tree_2;
 
180
                DATA_BLOB *first_match = talloc(tree, DATA_BLOB);
 
181
                DATA_BLOB *second_match = talloc(tree, DATA_BLOB);
 
182
                if (!first_match || !second_match) {
 
183
                        ldb_oom(ldb);
 
184
                        return LDB_ERR_OPERATIONS_ERROR;
 
185
                }
 
186
                *first_match = data_blob_const(match->data, p-match->data);
 
187
                *second_match = data_blob_const(p+1, match->length - (p-match->data) - 1);
 
188
                
 
189
                /* Add (|(&(givenname=first)(sn=second))(&(givenname=second)(sn=first))) */
 
190
 
 
191
                match_tree_1 = make_match_tree(module, mem_ctx, op, "givenName", first_match);
 
192
                match_tree_2 = make_match_tree(module, mem_ctx, op, "sn", second_match);
 
193
 
 
194
                first_split_filter = make_parse_list(module, ac,  LDB_OP_AND, match_tree_1, match_tree_2);
 
195
                if (first_split_filter == NULL){
 
196
                        ldb_oom(ldb);
 
197
                        return LDB_ERR_OPERATIONS_ERROR;
 
198
                }
 
199
                
 
200
                match_tree_1 = make_match_tree(module, mem_ctx, op, "sn", first_match);
 
201
                match_tree_2 = make_match_tree(module, mem_ctx, op, "givenName", second_match);
 
202
 
 
203
                second_split_filter = make_parse_list(module, ac,  LDB_OP_AND, match_tree_1, match_tree_2);
 
204
                if (second_split_filter == NULL){
 
205
                        ldb_oom(ldb);
 
206
                        return LDB_ERR_OPERATIONS_ERROR;
 
207
                }
 
208
 
 
209
                split_filters = make_parse_list(module, mem_ctx,  LDB_OP_OR, 
 
210
                                                first_split_filter, second_split_filter);
 
211
                if (split_filters == NULL) {
 
212
                        ldb_oom(ldb);
 
213
                        return LDB_ERR_OPERATIONS_ERROR;
 
214
                }
 
215
 
 
216
                if (tree) {
 
217
                        /* Inject an 'or' with the current tree */
 
218
                        tree = make_parse_list(module, mem_ctx,  LDB_OP_OR, tree, split_filters);
 
219
                } else {
 
220
                        tree = split_filters;
 
221
                }
 
222
        }
 
223
        *ntree = tree;
 
224
        return LDB_SUCCESS;
 
225
}
 
226
 
 
227
/*
 
228
  replace any occurances of an attribute with a new, generated attribute tree
 
229
*/
 
230
static int anr_replace_subtrees(struct anr_context *ac,
 
231
                                struct ldb_parse_tree *tree,
 
232
                                const char *attr,
 
233
                                struct ldb_parse_tree **ntree)
 
234
{
 
235
        int ret;
 
236
        int i;
 
237
 
 
238
        switch (tree->operation) {
 
239
        case LDB_OP_AND:
 
240
        case LDB_OP_OR:
 
241
                for (i=0;i<tree->u.list.num_elements;i++) {
 
242
                        ret = anr_replace_subtrees(ac, tree->u.list.elements[i],
 
243
                                                   attr, &tree->u.list.elements[i]);
 
244
                        if (ret != LDB_SUCCESS) {
 
245
                                return ret;
 
246
                        }
 
247
                        *ntree = tree;
 
248
                }
 
249
                break;
 
250
        case LDB_OP_NOT:
 
251
                ret = anr_replace_subtrees(ac, tree->u.isnot.child, attr, &tree->u.isnot.child);
 
252
                if (ret != LDB_SUCCESS) {
 
253
                        return ret;
 
254
                }
 
255
                *ntree = tree;
 
256
                break;
 
257
        case LDB_OP_EQUALITY:
 
258
                if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
 
259
                        ret = anr_replace_value(ac, tree, &tree->u.equality.value, ntree);
 
260
                        if (ret != LDB_SUCCESS) {
 
261
                                return ret;
 
262
                        }
 
263
                }
 
264
                break;
 
265
        case LDB_OP_SUBSTRING:
 
266
                if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
 
267
                        if (tree->u.substring.start_with_wildcard == 0 &&
 
268
                            tree->u.substring.end_with_wildcard == 1 && 
 
269
                            tree->u.substring.chunks[0] != NULL && 
 
270
                            tree->u.substring.chunks[1] == NULL) {
 
271
                                ret = anr_replace_value(ac, tree, tree->u.substring.chunks[0], ntree);
 
272
                                if (ret != LDB_SUCCESS) {
 
273
                                        return ret;
 
274
                                }
 
275
                        }
 
276
                }
 
277
                break;
 
278
        default:
 
279
                break;
 
280
        }
 
281
 
 
282
        return LDB_SUCCESS;
 
283
}
 
284
 
 
285
static int anr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
 
286
{
 
287
        struct anr_context *ac;
 
288
 
 
289
        ac = talloc_get_type(req->context, struct anr_context);
 
290
 
 
291
        if (!ares) {
 
292
                return ldb_module_done(ac->req, NULL, NULL,
 
293
                                        LDB_ERR_OPERATIONS_ERROR);
 
294
        }
 
295
        if (ares->error != LDB_SUCCESS) {
 
296
                return ldb_module_done(ac->req, ares->controls,
 
297
                                        ares->response, ares->error);
 
298
        }
 
299
 
 
300
        switch (ares->type) {
 
301
        case LDB_REPLY_ENTRY:
 
302
                return ldb_module_send_entry(ac->req, ares->message, ares->controls);
 
303
 
 
304
        case LDB_REPLY_REFERRAL:
 
305
                return ldb_module_send_referral(ac->req, ares->referral);
 
306
 
 
307
        case LDB_REPLY_DONE:
 
308
                return ldb_module_done(ac->req, ares->controls,
 
309
                                        ares->response, LDB_SUCCESS);
 
310
 
 
311
        }
 
312
        return LDB_SUCCESS;
 
313
}
 
314
 
 
315
/* search */
 
316
static int anr_search(struct ldb_module *module, struct ldb_request *req)
 
317
{
 
318
        struct ldb_context *ldb;
 
319
        struct ldb_parse_tree *anr_tree;
 
320
        struct ldb_request *down_req;
 
321
        struct anr_context *ac;
 
322
        int ret;
 
323
 
 
324
        ldb = ldb_module_get_ctx(module);
 
325
 
 
326
        ac = talloc(req, struct anr_context);
 
327
        if (!ac) {
 
328
                ldb_oom(ldb);
 
329
                return LDB_ERR_OPERATIONS_ERROR;
 
330
        }
 
331
 
 
332
        ac->module = module;
 
333
        ac->req = req;
 
334
        ac->found_anr = false;
 
335
 
 
336
#if 0
 
337
        printf("oldanr : %s\n", ldb_filter_from_tree (0, req->op.search.tree));
 
338
#endif
 
339
 
 
340
        ret = anr_replace_subtrees(ac, req->op.search.tree, "anr", &anr_tree);
 
341
        if (ret != LDB_SUCCESS) {
 
342
                return LDB_ERR_OPERATIONS_ERROR;
 
343
        }
 
344
 
 
345
        if (!ac->found_anr) {
 
346
                talloc_free(ac);
 
347
                return ldb_next_request(module, req);
 
348
        }
 
349
 
 
350
        ret = ldb_build_search_req_ex(&down_req,
 
351
                                        ldb, ac,
 
352
                                        req->op.search.base,
 
353
                                        req->op.search.scope,
 
354
                                        anr_tree,
 
355
                                        req->op.search.attrs,
 
356
                                        req->controls,
 
357
                                        ac, anr_search_callback,
 
358
                                        req);
 
359
        if (ret != LDB_SUCCESS) {
 
360
                return LDB_ERR_OPERATIONS_ERROR;
 
361
        }
 
362
        talloc_steal(down_req, anr_tree);
 
363
 
 
364
        return ldb_next_request(module, down_req);
 
365
}
 
366
 
 
367
_PUBLIC_ const struct ldb_module_ops ldb_anr_module_ops = {
 
368
        .name              = "anr",
 
369
        .search = anr_search
 
370
};