Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Simo Sorce 2005-2008
5 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : /*
22 : * Name: ldb
23 : *
24 : * Component: ldb extended dn control module
25 : *
26 : * Description: this module interprets DNs of the form <SID=S-1-2-4456> into normal DNs.
27 : *
28 : * Authors: Simo Sorce
29 : * Andrew Bartlett
30 : */
31 :
32 : #include "includes.h"
33 : #include <ldb.h>
34 : #include <ldb_errors.h>
35 : #include <ldb_module.h>
36 : #include "dsdb/samdb/samdb.h"
37 : #include "dsdb/samdb/ldb_modules/util.h"
38 : #include "lib/ldb-samba/ldb_matching_rules.h"
39 :
40 : #undef strncasecmp
41 :
42 : /*
43 : TODO: if relax is not set then we need to reject the fancy RMD_* and
44 : DELETED extended DN codes
45 : */
46 :
47 : /* search */
48 : struct extended_search_context {
49 : struct ldb_module *module;
50 : struct ldb_request *req;
51 : struct ldb_dn *basedn;
52 : struct ldb_dn *dn;
53 : char *wellknown_object;
54 : int extended_type;
55 : };
56 :
57 : static const char *wkattr[] = {
58 : "wellKnownObjects",
59 : "otherWellKnownObjects",
60 : NULL
61 : };
62 :
63 : static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops;
64 :
65 : /* An extra layer of indirection because LDB does not allow the original request to be altered */
66 :
67 7427084 : static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
68 : {
69 7427084 : int ret = LDB_ERR_OPERATIONS_ERROR;
70 : struct extended_search_context *ac;
71 7427084 : ac = talloc_get_type(req->context, struct extended_search_context);
72 :
73 7427084 : if (ares->error != LDB_SUCCESS) {
74 0 : ret = ldb_module_done(ac->req, ares->controls,
75 : ares->response, ares->error);
76 : } else {
77 7427084 : switch (ares->type) {
78 3571004 : case LDB_REPLY_ENTRY:
79 :
80 3571004 : ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
81 3571004 : break;
82 4991 : case LDB_REPLY_REFERRAL:
83 :
84 4991 : ret = ldb_module_send_referral(ac->req, ares->referral);
85 4991 : break;
86 3851089 : case LDB_REPLY_DONE:
87 :
88 3851089 : ret = ldb_module_done(ac->req, ares->controls,
89 : ares->response, ares->error);
90 3851089 : break;
91 : }
92 : }
93 7427084 : return ret;
94 : }
95 :
96 8945048 : static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
97 : {
98 : struct extended_search_context *ac;
99 : struct ldb_request *down_req;
100 : struct ldb_message_element *el;
101 : int ret;
102 : unsigned int i, j;
103 8945048 : size_t wkn_len = 0;
104 8945048 : char *valstr = NULL;
105 8945048 : const char *found = NULL;
106 :
107 8945048 : ac = talloc_get_type(req->context, struct extended_search_context);
108 :
109 8945048 : if (!ares) {
110 0 : return ldb_module_done(ac->req, NULL, NULL,
111 : LDB_ERR_OPERATIONS_ERROR);
112 : }
113 8945048 : if (ares->error != LDB_SUCCESS) {
114 40 : return ldb_module_done(ac->req, ares->controls,
115 : ares->response, ares->error);
116 : }
117 :
118 8945008 : switch (ares->type) {
119 4443025 : case LDB_REPLY_ENTRY:
120 4443025 : if (ac->basedn) {
121 : /* we have more than one match! This can
122 : happen as S-1-5-17 appears twice in a
123 : normal provision. We need to return
124 : NO_SUCH_OBJECT */
125 43062 : const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
126 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
127 43062 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
128 43062 : return ldb_module_done(ac->req, NULL, NULL,
129 : LDB_ERR_NO_SUCH_OBJECT);
130 : }
131 :
132 4399963 : if (!ac->wellknown_object) {
133 3615006 : ac->basedn = talloc_steal(ac, ares->message->dn);
134 3615006 : break;
135 : }
136 :
137 784957 : wkn_len = strlen(ac->wellknown_object);
138 :
139 1796581 : for (j=0; wkattr[j]; j++) {
140 :
141 1290769 : el = ldb_msg_find_element(ares->message, wkattr[j]);
142 1290769 : if (!el) {
143 1011620 : ac->basedn = NULL;
144 1011620 : continue;
145 : }
146 :
147 2667615 : for (i=0; i < el->num_values; i++) {
148 2667990 : valstr = talloc_strndup(ac,
149 1373533 : (const char *)el->values[i].data,
150 1373533 : el->values[i].length);
151 1373533 : if (!valstr) {
152 0 : ldb_oom(ldb_module_get_ctx(ac->module));
153 0 : return ldb_module_done(ac->req, NULL, NULL,
154 : LDB_ERR_OPERATIONS_ERROR);
155 : }
156 :
157 1373533 : if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
158 1094388 : talloc_free(valstr);
159 1094388 : continue;
160 : }
161 :
162 279145 : found = &valstr[wkn_len];
163 279145 : break;
164 : }
165 279149 : if (found) {
166 278762 : break;
167 : }
168 : }
169 :
170 784957 : if (!found) {
171 437775 : break;
172 : }
173 :
174 279145 : ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
175 279145 : talloc_free(valstr);
176 279145 : if (!ac->basedn) {
177 0 : ldb_oom(ldb_module_get_ctx(ac->module));
178 0 : return ldb_module_done(ac->req, NULL, NULL,
179 : LDB_ERR_OPERATIONS_ERROR);
180 : }
181 :
182 278762 : break;
183 :
184 0 : case LDB_REPLY_REFERRAL:
185 0 : break;
186 :
187 4501983 : case LDB_REPLY_DONE:
188 :
189 4501983 : if (!ac->basedn) {
190 650894 : const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
191 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
192 650894 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
193 650894 : return ldb_module_done(ac->req, NULL, NULL,
194 : LDB_ERR_NO_SUCH_OBJECT);
195 : }
196 :
197 3851089 : switch (ac->req->operation) {
198 3703427 : case LDB_SEARCH:
199 19446377 : ret = ldb_build_search_req_ex(&down_req,
200 3589050 : ldb_module_get_ctx(ac->module), ac->req,
201 : ac->basedn,
202 3589050 : ac->req->op.search.scope,
203 3589050 : ac->req->op.search.tree,
204 3589050 : ac->req->op.search.attrs,
205 3589050 : ac->req->controls,
206 : ac, extended_final_callback,
207 : ac->req);
208 3703427 : LDB_REQ_SET_LOCATION(down_req);
209 3703427 : break;
210 0 : case LDB_ADD:
211 : {
212 0 : struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
213 0 : if (!add_msg) {
214 0 : ldb_oom(ldb_module_get_ctx(ac->module));
215 0 : return ldb_module_done(ac->req, NULL, NULL,
216 : LDB_ERR_OPERATIONS_ERROR);
217 : }
218 :
219 0 : add_msg->dn = ac->basedn;
220 :
221 0 : ret = ldb_build_add_req(&down_req,
222 0 : ldb_module_get_ctx(ac->module), ac->req,
223 : add_msg,
224 0 : ac->req->controls,
225 : ac, extended_final_callback,
226 : ac->req);
227 0 : LDB_REQ_SET_LOCATION(down_req);
228 0 : break;
229 : }
230 147500 : case LDB_MODIFY:
231 : {
232 147500 : struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
233 147500 : if (!mod_msg) {
234 0 : ldb_oom(ldb_module_get_ctx(ac->module));
235 0 : return ldb_module_done(ac->req, NULL, NULL,
236 : LDB_ERR_OPERATIONS_ERROR);
237 : }
238 :
239 147500 : mod_msg->dn = ac->basedn;
240 :
241 415798 : ret = ldb_build_mod_req(&down_req,
242 144278 : ldb_module_get_ctx(ac->module), ac->req,
243 : mod_msg,
244 144278 : ac->req->controls,
245 : ac, extended_final_callback,
246 : ac->req);
247 147500 : LDB_REQ_SET_LOCATION(down_req);
248 147500 : break;
249 : }
250 129 : case LDB_DELETE:
251 373 : ret = ldb_build_del_req(&down_req,
252 122 : ldb_module_get_ctx(ac->module), ac->req,
253 : ac->basedn,
254 122 : ac->req->controls,
255 : ac, extended_final_callback,
256 : ac->req);
257 129 : LDB_REQ_SET_LOCATION(down_req);
258 129 : break;
259 33 : case LDB_RENAME:
260 132 : ret = ldb_build_rename_req(&down_req,
261 33 : ldb_module_get_ctx(ac->module), ac->req,
262 : ac->basedn,
263 33 : ac->req->op.rename.newdn,
264 33 : ac->req->controls,
265 : ac, extended_final_callback,
266 : ac->req);
267 33 : LDB_REQ_SET_LOCATION(down_req);
268 33 : break;
269 0 : default:
270 0 : return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
271 : }
272 :
273 3851089 : if (ret != LDB_SUCCESS) {
274 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
275 : }
276 :
277 3851089 : return ldb_next_request(ac->module, down_req);
278 : }
279 4399963 : talloc_free(ares);
280 4399963 : return LDB_SUCCESS;
281 : }
282 :
283 :
284 : /*
285 : windows ldap searchs don't allow a baseDN with more
286 : than one extended component, or an extended
287 : component and a string DN
288 :
289 : We only enforce this over ldap, not for internal
290 : use, as there are just too many places where we
291 : internally want to use a DN that has come from a
292 : search with extended DN enabled, or comes from a DRS
293 : naming context.
294 :
295 : Enforcing this would also make debugging samba much
296 : harder, as we'd need to use ldb_dn_minimise() in a
297 : lot of places, and that would lose the DN string
298 : which is so useful for working out what a request is
299 : for
300 : */
301 4574152 : static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
302 : {
303 4574152 : int num_components = ldb_dn_get_comp_num(dn);
304 4574152 : int num_ex_components = ldb_dn_get_extended_comp_num(dn);
305 :
306 4574152 : if (num_ex_components == 0) {
307 25469 : return true;
308 : }
309 :
310 5010537 : if ((num_components != 0 || num_ex_components != 1) &&
311 463191 : ldb_req_is_untrusted(req)) {
312 99 : return false;
313 : }
314 4350623 : return true;
315 : }
316 :
317 :
318 : struct extended_dn_filter_ctx {
319 : bool test_only;
320 : bool matched;
321 : struct ldb_module *module;
322 : struct ldb_request *req;
323 : struct dsdb_schema *schema;
324 : uint32_t dsdb_flags;
325 : };
326 :
327 : /*
328 : create a always non-matching node from a equality node
329 : */
330 218 : static void set_parse_tree_false(struct ldb_parse_tree *tree)
331 : {
332 234 : const char *attr = tree->u.equality.attr;
333 234 : struct ldb_val value = tree->u.equality.value;
334 234 : tree->operation = LDB_OP_EXTENDED;
335 218 : tree->u.extended.attr = attr;
336 234 : tree->u.extended.value = value;
337 234 : tree->u.extended.rule_id = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
338 234 : tree->u.extended.dnAttributes = 0;
339 218 : }
340 :
341 : /*
342 : called on all nodes in the parse tree
343 : */
344 44417709 : static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
345 : {
346 : struct extended_dn_filter_ctx *filter_ctx;
347 : int ret;
348 44417709 : struct ldb_dn *dn = NULL;
349 : const struct ldb_val *sid_val, *guid_val;
350 44417709 : const char *no_attrs[] = { NULL };
351 : struct ldb_result *res;
352 44417709 : const struct dsdb_attribute *attribute = NULL;
353 44417709 : bool has_extended_component = false;
354 : enum ldb_scope scope;
355 : struct ldb_dn *base_dn;
356 : const char *expression;
357 : uint32_t dsdb_flags;
358 :
359 44417709 : if (tree->operation != LDB_OP_EQUALITY && tree->operation != LDB_OP_EXTENDED) {
360 37269029 : return LDB_SUCCESS;
361 : }
362 :
363 4782952 : filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
364 :
365 4782952 : if (filter_ctx->test_only && filter_ctx->matched) {
366 : /* the tree already matched */
367 33421 : return LDB_SUCCESS;
368 : }
369 :
370 4748810 : if (!filter_ctx->schema) {
371 : /* Schema not setup yet */
372 24856 : return LDB_SUCCESS;
373 : }
374 4722945 : if (tree->operation == LDB_OP_EQUALITY) {
375 3474269 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
376 1248676 : } else if (tree->operation == LDB_OP_EXTENDED) {
377 1248676 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.extended.attr);
378 : }
379 4722945 : if (attribute == NULL) {
380 62 : return LDB_SUCCESS;
381 : }
382 :
383 4722883 : if (attribute->dn_format != DSDB_NORMAL_DN) {
384 4356748 : return LDB_SUCCESS;
385 : }
386 :
387 241423 : if (tree->operation == LDB_OP_EQUALITY) {
388 226501 : has_extended_component = (memchr(tree->u.equality.value.data, '<',
389 : tree->u.equality.value.length) != NULL);
390 14922 : } else if (tree->operation == LDB_OP_EXTENDED) {
391 14922 : has_extended_component = (memchr(tree->u.extended.value.data, '<',
392 : tree->u.extended.value.length) != NULL);
393 : }
394 :
395 : /*
396 : * Don't turn it into an extended DN if we're talking to OpenLDAP.
397 : * We just check the module_ops pointer instead of adding a private
398 : * pointer and a boolean to tell us the exact same thing.
399 : */
400 241423 : if (!has_extended_component) {
401 237733 : if (!attribute->one_way_link) {
402 177727 : return LDB_SUCCESS;
403 : }
404 :
405 56507 : if (ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops) {
406 0 : return LDB_SUCCESS;
407 : }
408 : }
409 :
410 60197 : if (tree->operation == LDB_OP_EQUALITY) {
411 56895 : dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
412 3302 : } else if (tree->operation == LDB_OP_EXTENDED
413 3302 : && (strcmp(tree->u.extended.rule_id, SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL) == 0)) {
414 36 : dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.extended.value);
415 : }
416 60045 : if (dn == NULL) {
417 : /* testing against windows shows that we don't raise
418 : an error here */
419 3114 : return LDB_SUCCESS;
420 : }
421 :
422 56931 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
423 56931 : sid_val = ldb_dn_get_extended_component(dn, "SID");
424 :
425 56931 : if (!guid_val && !sid_val && (attribute->searchFlags & SEARCH_FLAG_ATTINDEX)) {
426 : /* if it is indexed, then fixing the string DN will do
427 : no good here, as we will not find the attribute in
428 : the index. So for now fall through to a standard DN
429 : component comparison */
430 15 : return LDB_SUCCESS;
431 : }
432 :
433 56916 : if (filter_ctx->test_only) {
434 : /* we need to copy the tree */
435 27849 : filter_ctx->matched = true;
436 27849 : return LDB_SUCCESS;
437 : }
438 :
439 29067 : if (!ldb_dn_match_allowed(dn, filter_ctx->req)) {
440 : /* we need to make this element of the filter always
441 : be false */
442 99 : set_parse_tree_false(tree);
443 99 : return LDB_SUCCESS;
444 : }
445 :
446 28968 : dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE;
447 :
448 28968 : if (guid_val) {
449 168 : expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val));
450 168 : scope = LDB_SCOPE_SUBTREE;
451 168 : base_dn = NULL;
452 168 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
453 28800 : } else if (sid_val) {
454 1994 : expression = talloc_asprintf(filter_ctx, "objectSID=%s", ldb_binary_encode(filter_ctx, *sid_val));
455 1994 : scope = LDB_SCOPE_SUBTREE;
456 1994 : base_dn = NULL;
457 1994 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
458 : } else {
459 : /* fallback to searching using the string DN as the base DN */
460 25469 : expression = "objectClass=*";
461 25469 : base_dn = dn;
462 25469 : scope = LDB_SCOPE_BASE;
463 : }
464 :
465 28968 : ret = dsdb_module_search(filter_ctx->module,
466 : filter_ctx,
467 : &res,
468 : base_dn,
469 : scope,
470 : no_attrs,
471 : dsdb_flags,
472 : filter_ctx->req,
473 : "%s", expression);
474 28968 : if (scope == LDB_SCOPE_BASE && ret == LDB_ERR_NO_SUCH_OBJECT) {
475 : /* note that this will need to change for multi-domain
476 : support */
477 135 : set_parse_tree_false(tree);
478 135 : return LDB_SUCCESS;
479 : }
480 :
481 28833 : if (ret != LDB_SUCCESS) {
482 0 : return LDB_SUCCESS;
483 : }
484 :
485 :
486 28833 : if (res->count != 1) {
487 220 : return LDB_SUCCESS;
488 : }
489 :
490 : /* replace the search expression element with the matching DN */
491 28613 : if (tree->operation == LDB_OP_EQUALITY) {
492 28595 : tree->u.equality.value.data =
493 28595 : (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
494 28595 : if (tree->u.equality.value.data == NULL) {
495 0 : return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
496 : }
497 28595 : tree->u.equality.value.length = strlen((const char *)tree->u.equality.value.data);
498 18 : } else if (tree->operation == LDB_OP_EXTENDED) {
499 18 : tree->u.extended.value.data =
500 18 : (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
501 18 : if (tree->u.extended.value.data == NULL) {
502 0 : return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
503 : }
504 18 : tree->u.extended.value.length = strlen((const char *)tree->u.extended.value.data);
505 : }
506 28613 : talloc_free(res);
507 :
508 28613 : filter_ctx->matched = true;
509 28613 : return LDB_SUCCESS;
510 : }
511 :
512 : /*
513 : fix the parse tree to change any extended DN components to their
514 : canonical form
515 : */
516 14484341 : static int extended_dn_fix_filter(struct ldb_module *module,
517 : struct ldb_request *req,
518 : uint32_t default_dsdb_flags)
519 : {
520 : struct extended_dn_filter_ctx *filter_ctx;
521 : int ret;
522 :
523 14484341 : filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
524 14484341 : if (filter_ctx == NULL) {
525 0 : return ldb_module_oom(module);
526 : }
527 :
528 : /* first pass through the existing tree to see if anything
529 : needs to be modified. Filtering DNs on the input side is rare,
530 : so this avoids copying the parse tree in most cases */
531 14484341 : filter_ctx->test_only = true;
532 14484341 : filter_ctx->matched = false;
533 14484341 : filter_ctx->module = module;
534 14484341 : filter_ctx->req = req;
535 14484341 : filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
536 14484341 : filter_ctx->dsdb_flags= default_dsdb_flags;
537 :
538 14484341 : ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
539 14484341 : if (ret != LDB_SUCCESS) {
540 0 : talloc_free(filter_ctx);
541 0 : return ret;
542 : }
543 :
544 14484341 : if (!filter_ctx->matched) {
545 : /* nothing matched, no need for a new parse tree */
546 14456492 : talloc_free(filter_ctx);
547 14456492 : return LDB_SUCCESS;
548 : }
549 :
550 27849 : filter_ctx->test_only = false;
551 27849 : filter_ctx->matched = false;
552 :
553 27849 : req->op.search.tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
554 27849 : if (req->op.search.tree == NULL) {
555 0 : return ldb_oom(ldb_module_get_ctx(module));
556 : }
557 :
558 27849 : ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
559 27849 : if (ret != LDB_SUCCESS) {
560 0 : talloc_free(filter_ctx);
561 0 : return ret;
562 : }
563 :
564 27849 : talloc_free(filter_ctx);
565 27849 : return LDB_SUCCESS;
566 : }
567 :
568 : /*
569 : fix DNs and filter expressions to cope with the semantics of
570 : extended DNs
571 : */
572 14841559 : static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
573 : {
574 : struct extended_search_context *ac;
575 : struct ldb_request *down_req;
576 : int ret;
577 14841559 : struct ldb_dn *base_dn = NULL;
578 14841559 : enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
579 14841559 : const char *base_dn_filter = NULL;
580 14841559 : const char * const *base_dn_attrs = NULL;
581 14841559 : char *wellknown_object = NULL;
582 : static const char *no_attr[] = {
583 : NULL
584 : };
585 14841559 : uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN;
586 :
587 14841559 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) {
588 2453238 : dsdb_flags |= DSDB_SEARCH_SHOW_DELETED;
589 : }
590 14841559 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) {
591 3648999 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
592 : }
593 14841559 : if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
594 143594 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
595 : }
596 :
597 14841559 : if (req->operation == LDB_SEARCH) {
598 14484341 : ret = extended_dn_fix_filter(module, req, dsdb_flags);
599 14484341 : if (ret != LDB_SUCCESS) {
600 0 : return ret;
601 : }
602 : }
603 :
604 14841559 : if (!ldb_dn_has_extended(dn)) {
605 : /* Move along there isn't anything to see here */
606 10296474 : return ldb_next_request(module, req);
607 : } else {
608 : /* It looks like we need to map the DN */
609 : const struct ldb_val *sid_val, *guid_val, *wkguid_val;
610 :
611 4545085 : if (!ldb_dn_match_allowed(dn, req)) {
612 0 : return ldb_error(ldb_module_get_ctx(module),
613 : LDB_ERR_INVALID_DN_SYNTAX, "invalid number of DN components");
614 : }
615 :
616 4545085 : sid_val = ldb_dn_get_extended_component(dn, "SID");
617 4545085 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
618 4545085 : wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
619 :
620 : /*
621 : prioritise the GUID - we have had instances of
622 : duplicate SIDs in the database in the
623 : ForeignSecurityPrinciples due to provision errors
624 : */
625 4545085 : if (guid_val) {
626 2891551 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
627 2891551 : base_dn = NULL;
628 2891551 : base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
629 : ldb_binary_encode(req, *guid_val));
630 2891551 : if (!base_dn_filter) {
631 0 : return ldb_oom(ldb_module_get_ctx(module));
632 : }
633 2790921 : base_dn_scope = LDB_SCOPE_SUBTREE;
634 2790921 : base_dn_attrs = no_attr;
635 :
636 1653534 : } else if (sid_val) {
637 868577 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
638 868577 : base_dn = NULL;
639 868577 : base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
640 : ldb_binary_encode(req, *sid_val));
641 868577 : if (!base_dn_filter) {
642 0 : return ldb_oom(ldb_module_get_ctx(module));
643 : }
644 841009 : base_dn_scope = LDB_SCOPE_SUBTREE;
645 841009 : base_dn_attrs = no_attr;
646 :
647 784957 : } else if (wkguid_val) {
648 : char *wkguid_dup;
649 : char *tail_str;
650 : char *p;
651 :
652 784957 : wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
653 :
654 784957 : p = strchr(wkguid_dup, ',');
655 784957 : if (!p) {
656 0 : return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
657 : "Invalid WKGUID format");
658 : }
659 :
660 784957 : p[0] = '\0';
661 784957 : p++;
662 :
663 784957 : wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
664 784957 : if (!wellknown_object) {
665 0 : return ldb_oom(ldb_module_get_ctx(module));
666 : }
667 :
668 784957 : tail_str = p;
669 :
670 784957 : base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
671 784957 : talloc_free(wkguid_dup);
672 784957 : if (!base_dn) {
673 0 : return ldb_oom(ldb_module_get_ctx(module));
674 : }
675 784957 : base_dn_filter = talloc_strdup(req, "(objectClass=*)");
676 784957 : if (!base_dn_filter) {
677 0 : return ldb_oom(ldb_module_get_ctx(module));
678 : }
679 716537 : base_dn_scope = LDB_SCOPE_BASE;
680 716537 : base_dn_attrs = wkattr;
681 : } else {
682 0 : return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
683 : "Invalid extended DN component");
684 : }
685 :
686 4545085 : ac = talloc_zero(req, struct extended_search_context);
687 4545085 : if (ac == NULL) {
688 0 : return ldb_oom(ldb_module_get_ctx(module));
689 : }
690 :
691 4545085 : ac->module = module;
692 4545085 : ac->req = req;
693 4545085 : ac->dn = dn;
694 4545085 : ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
695 4545085 : ac->wellknown_object = wellknown_object;
696 :
697 : /* If the base DN was an extended DN (perhaps a well known
698 : * GUID) then search for that, so we can proceed with the original operation */
699 :
700 4545085 : ret = ldb_build_search_req(&down_req,
701 : ldb_module_get_ctx(module), ac,
702 : base_dn,
703 : base_dn_scope,
704 : base_dn_filter,
705 : base_dn_attrs,
706 : NULL,
707 : ac, extended_base_callback,
708 : req);
709 4545085 : LDB_REQ_SET_LOCATION(down_req);
710 4545085 : if (ret != LDB_SUCCESS) {
711 0 : return ldb_operr(ldb_module_get_ctx(module));
712 : }
713 :
714 4545085 : ret = dsdb_request_add_controls(down_req, dsdb_flags);
715 4545085 : if (ret != LDB_SUCCESS) {
716 0 : return ret;
717 : }
718 :
719 : /* perform the search */
720 4545085 : return ldb_next_request(module, down_req);
721 : }
722 : }
723 :
724 14484341 : static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
725 : {
726 14484341 : return extended_dn_in_fix(module, req, req->op.search.base);
727 : }
728 :
729 279508 : static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
730 : {
731 279508 : return extended_dn_in_fix(module, req, req->op.mod.message->dn);
732 : }
733 :
734 76780 : static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
735 : {
736 76780 : return extended_dn_in_fix(module, req, req->op.del.dn);
737 : }
738 :
739 930 : static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
740 : {
741 930 : return extended_dn_in_fix(module, req, req->op.rename.olddn);
742 : }
743 :
744 : static const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
745 : .name = "extended_dn_in",
746 : .search = extended_dn_in_search,
747 : .modify = extended_dn_in_modify,
748 : .del = extended_dn_in_del,
749 : .rename = extended_dn_in_rename,
750 : };
751 :
752 : static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops = {
753 : .name = "extended_dn_in_openldap",
754 : .search = extended_dn_in_search,
755 : .modify = extended_dn_in_modify,
756 : .del = extended_dn_in_del,
757 : .rename = extended_dn_in_rename,
758 : };
759 :
760 5536 : int ldb_extended_dn_in_module_init(const char *version)
761 : {
762 : int ret;
763 5536 : LDB_MODULE_CHECK_VERSION(version);
764 5536 : ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
765 5536 : if (ret != LDB_SUCCESS) {
766 0 : return ret;
767 : }
768 5536 : return ldb_register_module(&ldb_extended_dn_in_module_ops);
769 : }
|