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_parse_tree *tree;
52 : struct ldb_dn *basedn;
53 : struct ldb_dn *dn;
54 : char *wellknown_object;
55 : int extended_type;
56 : };
57 :
58 : static const char *wkattr[] = {
59 : "wellKnownObjects",
60 : "otherWellKnownObjects",
61 : NULL
62 : };
63 :
64 : static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops;
65 :
66 : /* An extra layer of indirection because LDB does not allow the original request to be altered */
67 :
68 10732778 : static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
69 : {
70 10732778 : int ret = LDB_ERR_OPERATIONS_ERROR;
71 : struct extended_search_context *ac;
72 10732778 : ac = talloc_get_type(req->context, struct extended_search_context);
73 :
74 10732778 : if (ares->error != LDB_SUCCESS) {
75 187 : ret = ldb_module_done(ac->req, ares->controls,
76 : ares->response, ares->error);
77 : } else {
78 10732591 : switch (ares->type) {
79 5444414 : case LDB_REPLY_ENTRY:
80 :
81 5444414 : ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
82 5444414 : break;
83 5645 : case LDB_REPLY_REFERRAL:
84 :
85 5645 : ret = ldb_module_send_referral(ac->req, ares->referral);
86 5645 : break;
87 5282532 : case LDB_REPLY_DONE:
88 :
89 5282532 : ret = ldb_module_done(ac->req, ares->controls,
90 : ares->response, ares->error);
91 5282532 : break;
92 : }
93 : }
94 10732778 : return ret;
95 : }
96 :
97 11554862 : static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
98 : {
99 : struct extended_search_context *ac;
100 : struct ldb_request *down_req;
101 : struct ldb_message_element *el;
102 : int ret;
103 : unsigned int i, j;
104 11554862 : size_t wkn_len = 0;
105 11554862 : char *valstr = NULL;
106 11554862 : const char *found = NULL;
107 :
108 11554862 : ac = talloc_get_type(req->context, struct extended_search_context);
109 :
110 11554862 : if (!ares) {
111 0 : return ldb_module_done(ac->req, NULL, NULL,
112 : LDB_ERR_OPERATIONS_ERROR);
113 : }
114 11554862 : if (ares->error != LDB_SUCCESS) {
115 36 : return ldb_module_done(ac->req, ares->controls,
116 : ares->response, ares->error);
117 : }
118 :
119 11554826 : switch (ares->type) {
120 5721410 : case LDB_REPLY_ENTRY:
121 5721410 : if (ac->basedn) {
122 : /* we have more than one match! This can
123 : happen as S-1-5-17 appears twice in a
124 : normal provision. We need to return
125 : NO_SUCH_OBJECT */
126 37264 : const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
127 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
128 37264 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
129 37264 : return ldb_module_done(ac->req, NULL, NULL,
130 : LDB_ERR_NO_SUCH_OBJECT);
131 : }
132 :
133 5684146 : if (!ac->wellknown_object) {
134 5100738 : ac->basedn = talloc_steal(ac, ares->message->dn);
135 5100738 : break;
136 : }
137 :
138 583408 : wkn_len = strlen(ac->wellknown_object);
139 :
140 1311734 : for (j=0; wkattr[j]; j++) {
141 :
142 947571 : el = ldb_msg_find_element(ares->message, wkattr[j]);
143 947571 : if (!el) {
144 728322 : ac->basedn = NULL;
145 728322 : continue;
146 : }
147 :
148 2117534 : for (i=0; i < el->num_values; i++) {
149 2117526 : valstr = talloc_strndup(ac,
150 1081746 : (const char *)el->values[i].data,
151 1081746 : el->values[i].length);
152 1081746 : if (!valstr) {
153 0 : ldb_oom(ldb_module_get_ctx(ac->module));
154 0 : return ldb_module_done(ac->req, NULL, NULL,
155 : LDB_ERR_OPERATIONS_ERROR);
156 : }
157 :
158 1081746 : if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
159 862501 : talloc_free(valstr);
160 862501 : continue;
161 : }
162 :
163 219245 : found = &valstr[wkn_len];
164 219245 : break;
165 : }
166 219249 : if (found) {
167 219245 : break;
168 : }
169 : }
170 :
171 583408 : if (!found) {
172 364163 : break;
173 : }
174 :
175 219245 : ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
176 219245 : talloc_free(valstr);
177 219245 : if (!ac->basedn) {
178 0 : ldb_oom(ldb_module_get_ctx(ac->module));
179 0 : return ldb_module_done(ac->req, NULL, NULL,
180 : LDB_ERR_OPERATIONS_ERROR);
181 : }
182 :
183 219245 : break;
184 :
185 0 : case LDB_REPLY_REFERRAL:
186 0 : break;
187 :
188 5833416 : case LDB_REPLY_DONE:
189 :
190 5833416 : if (!ac->basedn) {
191 550697 : const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
192 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
193 550697 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
194 550697 : return ldb_module_done(ac->req, NULL, NULL,
195 : LDB_ERR_NO_SUCH_OBJECT);
196 : }
197 :
198 5282719 : switch (ac->req->operation) {
199 5156873 : case LDB_SEARCH:
200 23666961 : ret = ldb_build_search_req_ex(&down_req,
201 5156873 : ldb_module_get_ctx(ac->module), ac->req,
202 : ac->basedn,
203 5156873 : ac->req->op.search.scope,
204 : ac->tree,
205 5156873 : ac->req->op.search.attrs,
206 5156873 : ac->req->controls,
207 : ac, extended_final_callback,
208 : ac->req);
209 5156873 : LDB_REQ_SET_LOCATION(down_req);
210 5156873 : break;
211 0 : case LDB_ADD:
212 : {
213 0 : struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
214 0 : if (!add_msg) {
215 0 : ldb_oom(ldb_module_get_ctx(ac->module));
216 0 : return ldb_module_done(ac->req, NULL, NULL,
217 : LDB_ERR_OPERATIONS_ERROR);
218 : }
219 :
220 0 : add_msg->dn = ac->basedn;
221 :
222 0 : ret = ldb_build_add_req(&down_req,
223 0 : ldb_module_get_ctx(ac->module), ac->req,
224 : add_msg,
225 0 : ac->req->controls,
226 : ac, extended_final_callback,
227 : ac->req);
228 0 : LDB_REQ_SET_LOCATION(down_req);
229 0 : break;
230 : }
231 125687 : case LDB_MODIFY:
232 : {
233 125687 : struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
234 125687 : if (!mod_msg) {
235 0 : ldb_oom(ldb_module_get_ctx(ac->module));
236 0 : return ldb_module_done(ac->req, NULL, NULL,
237 : LDB_ERR_OPERATIONS_ERROR);
238 : }
239 :
240 125687 : mod_msg->dn = ac->basedn;
241 :
242 364939 : ret = ldb_build_mod_req(&down_req,
243 125687 : ldb_module_get_ctx(ac->module), ac->req,
244 : mod_msg,
245 125687 : ac->req->controls,
246 : ac, extended_final_callback,
247 : ac->req);
248 125687 : LDB_REQ_SET_LOCATION(down_req);
249 125687 : break;
250 : }
251 122 : case LDB_DELETE:
252 366 : ret = ldb_build_del_req(&down_req,
253 122 : ldb_module_get_ctx(ac->module), ac->req,
254 : ac->basedn,
255 122 : ac->req->controls,
256 : ac, extended_final_callback,
257 : ac->req);
258 122 : LDB_REQ_SET_LOCATION(down_req);
259 122 : break;
260 37 : case LDB_RENAME:
261 148 : ret = ldb_build_rename_req(&down_req,
262 37 : ldb_module_get_ctx(ac->module), ac->req,
263 : ac->basedn,
264 37 : ac->req->op.rename.newdn,
265 37 : ac->req->controls,
266 : ac, extended_final_callback,
267 : ac->req);
268 37 : LDB_REQ_SET_LOCATION(down_req);
269 37 : break;
270 0 : default:
271 0 : return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
272 : }
273 :
274 5282719 : if (ret != LDB_SUCCESS) {
275 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
276 : }
277 :
278 5282719 : return ldb_next_request(ac->module, down_req);
279 : }
280 5684146 : talloc_free(ares);
281 5684146 : return LDB_SUCCESS;
282 : }
283 :
284 :
285 : /*
286 : windows ldap searchs don't allow a baseDN with more
287 : than one extended component, or an extended
288 : component and a string DN
289 :
290 : We only enforce this over ldap, not for internal
291 : use, as there are just too many places where we
292 : internally want to use a DN that has come from a
293 : search with extended DN enabled, or comes from a DRS
294 : naming context.
295 :
296 : Enforcing this would also make debugging samba much
297 : harder, as we'd need to use ldb_dn_minimise() in a
298 : lot of places, and that would lose the DN string
299 : which is so useful for working out what a request is
300 : for
301 : */
302 5895057 : static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
303 : {
304 5895057 : int num_components = ldb_dn_get_comp_num(dn);
305 5895057 : int num_ex_components = ldb_dn_get_extended_comp_num(dn);
306 :
307 5895057 : if (num_ex_components == 0) {
308 23123 : return true;
309 : }
310 :
311 6281448 : if ((num_components != 0 || num_ex_components != 1) &&
312 409514 : ldb_req_is_untrusted(req)) {
313 0 : return false;
314 : }
315 5871934 : return true;
316 : }
317 :
318 :
319 : struct extended_dn_filter_ctx {
320 : bool test_only;
321 : bool matched;
322 : struct ldb_module *module;
323 : struct ldb_request *req;
324 : struct dsdb_schema *schema;
325 : uint32_t dsdb_flags;
326 : };
327 :
328 : /*
329 : create a always non-matching node from a equality node
330 : */
331 155 : static void set_parse_tree_false(struct ldb_parse_tree *tree)
332 : {
333 155 : const char *attr = tree->u.equality.attr;
334 155 : struct ldb_val value = tree->u.equality.value;
335 155 : tree->operation = LDB_OP_EXTENDED;
336 155 : tree->u.extended.attr = attr;
337 155 : tree->u.extended.value = value;
338 155 : tree->u.extended.rule_id = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
339 155 : tree->u.extended.dnAttributes = 0;
340 155 : }
341 :
342 : /*
343 : called on all nodes in the parse tree
344 : */
345 36723352 : static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
346 : {
347 : struct extended_dn_filter_ctx *filter_ctx;
348 : int ret;
349 36723352 : struct ldb_dn *dn = NULL;
350 : const struct ldb_val *sid_val, *guid_val;
351 36723352 : const char *no_attrs[] = { NULL };
352 : struct ldb_result *res;
353 36723352 : const struct dsdb_attribute *attribute = NULL;
354 36723352 : bool has_extended_component = false;
355 : enum ldb_scope scope;
356 : struct ldb_dn *base_dn;
357 : const char *expression;
358 : uint32_t dsdb_flags;
359 :
360 36723352 : if (tree->operation != LDB_OP_EQUALITY && tree->operation != LDB_OP_EXTENDED) {
361 32739369 : return LDB_SUCCESS;
362 : }
363 :
364 3983983 : filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
365 :
366 3983983 : if (filter_ctx->test_only && filter_ctx->matched) {
367 : /* the tree already matched */
368 31061 : return LDB_SUCCESS;
369 : }
370 :
371 3952922 : if (!filter_ctx->schema) {
372 : /* Schema not setup yet */
373 16786 : return LDB_SUCCESS;
374 : }
375 3936136 : if (tree->operation == LDB_OP_EQUALITY) {
376 2761942 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
377 1174194 : } else if (tree->operation == LDB_OP_EXTENDED) {
378 1174194 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.extended.attr);
379 : }
380 3936136 : if (attribute == NULL) {
381 62 : return LDB_SUCCESS;
382 : }
383 :
384 3936074 : if (attribute->dn_format != DSDB_NORMAL_DN) {
385 3717799 : return LDB_SUCCESS;
386 : }
387 :
388 218275 : if (tree->operation == LDB_OP_EQUALITY) {
389 197564 : has_extended_component = (memchr(tree->u.equality.value.data, '<',
390 : tree->u.equality.value.length) != NULL);
391 20711 : } else if (tree->operation == LDB_OP_EXTENDED) {
392 20711 : has_extended_component = (memchr(tree->u.extended.value.data, '<',
393 : tree->u.extended.value.length) != NULL);
394 : }
395 :
396 : /*
397 : * Don't turn it into an extended DN if we're talking to OpenLDAP.
398 : * We just check the module_ops pointer instead of adding a private
399 : * pointer and a boolean to tell us the exact same thing.
400 : */
401 218275 : if (!has_extended_component) {
402 216172 : if (!attribute->one_way_link) {
403 167650 : return LDB_SUCCESS;
404 : }
405 :
406 48522 : if (ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops) {
407 0 : return LDB_SUCCESS;
408 : }
409 : }
410 :
411 50625 : if (tree->operation == LDB_OP_EQUALITY) {
412 48240 : dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
413 2385 : } else if (tree->operation == LDB_OP_EXTENDED
414 2385 : && (strcmp(tree->u.extended.rule_id, SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL) == 0)) {
415 36 : dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.extended.value);
416 : }
417 50625 : if (dn == NULL) {
418 : /* testing against windows shows that we don't raise
419 : an error here */
420 2349 : return LDB_SUCCESS;
421 : }
422 :
423 48276 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
424 48276 : sid_val = ldb_dn_get_extended_component(dn, "SID");
425 :
426 : /*
427 : * Is the attribute indexed? By treating confidential attributes
428 : * as unindexed, we force searches to go through the unindexed
429 : * search path, avoiding observable timing differences.
430 : */
431 93123 : if (!guid_val && !sid_val &&
432 46188 : (attribute->searchFlags & SEARCH_FLAG_ATTINDEX) &&
433 15 : !(attribute->searchFlags & SEARCH_FLAG_CONFIDENTIAL))
434 : {
435 : /* if it is indexed, then fixing the string DN will do
436 : no good here, as we will not find the attribute in
437 : the index. So for now fall through to a standard DN
438 : component comparison */
439 15 : return LDB_SUCCESS;
440 : }
441 :
442 48261 : if (filter_ctx->test_only) {
443 : /* we need to copy the tree */
444 23920 : filter_ctx->matched = true;
445 23920 : return LDB_SUCCESS;
446 : }
447 :
448 24341 : if (!ldb_dn_match_allowed(dn, filter_ctx->req)) {
449 : /* we need to make this element of the filter always
450 : be false */
451 0 : set_parse_tree_false(tree);
452 0 : return LDB_SUCCESS;
453 : }
454 :
455 24341 : dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE;
456 :
457 24341 : if (guid_val) {
458 694 : expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val));
459 694 : scope = LDB_SCOPE_SUBTREE;
460 694 : base_dn = NULL;
461 694 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
462 23647 : } else if (sid_val) {
463 524 : expression = talloc_asprintf(filter_ctx, "objectSID=%s", ldb_binary_encode(filter_ctx, *sid_val));
464 524 : scope = LDB_SCOPE_SUBTREE;
465 524 : base_dn = NULL;
466 524 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
467 : } else {
468 : /* fallback to searching using the string DN as the base DN */
469 23123 : expression = "objectClass=*";
470 23123 : base_dn = dn;
471 23123 : scope = LDB_SCOPE_BASE;
472 : }
473 :
474 24341 : ret = dsdb_module_search(filter_ctx->module,
475 : filter_ctx,
476 : &res,
477 : base_dn,
478 : scope,
479 : no_attrs,
480 : dsdb_flags,
481 : filter_ctx->req,
482 : "%s", expression);
483 24341 : if (scope == LDB_SCOPE_BASE && ret == LDB_ERR_NO_SUCH_OBJECT) {
484 : /* note that this will need to change for multi-domain
485 : support */
486 155 : set_parse_tree_false(tree);
487 155 : return LDB_SUCCESS;
488 : }
489 :
490 24186 : if (ret != LDB_SUCCESS) {
491 0 : return LDB_SUCCESS;
492 : }
493 :
494 :
495 24186 : if (res->count != 1) {
496 186 : return LDB_SUCCESS;
497 : }
498 :
499 : /* replace the search expression element with the matching DN */
500 24000 : if (tree->operation == LDB_OP_EQUALITY) {
501 23982 : tree->u.equality.value.data =
502 23982 : (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
503 23982 : if (tree->u.equality.value.data == NULL) {
504 0 : return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
505 : }
506 23982 : tree->u.equality.value.length = strlen((const char *)tree->u.equality.value.data);
507 18 : } else if (tree->operation == LDB_OP_EXTENDED) {
508 18 : tree->u.extended.value.data =
509 18 : (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
510 18 : if (tree->u.extended.value.data == NULL) {
511 0 : return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
512 : }
513 18 : tree->u.extended.value.length = strlen((const char *)tree->u.extended.value.data);
514 : }
515 24000 : talloc_free(res);
516 :
517 24000 : filter_ctx->matched = true;
518 24000 : return LDB_SUCCESS;
519 : }
520 :
521 : /*
522 : fix the parse tree to change any extended DN components to their
523 : canonical form
524 : */
525 12097170 : static int extended_dn_fix_filter(struct ldb_module *module,
526 : struct ldb_request *req,
527 : uint32_t default_dsdb_flags,
528 : struct ldb_parse_tree **down_tree)
529 : {
530 : struct extended_dn_filter_ctx *filter_ctx;
531 : int ret;
532 :
533 12097170 : *down_tree = NULL;
534 :
535 12097170 : filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
536 12097170 : if (filter_ctx == NULL) {
537 0 : return ldb_module_oom(module);
538 : }
539 :
540 : /* first pass through the existing tree to see if anything
541 : needs to be modified. Filtering DNs on the input side is rare,
542 : so this avoids copying the parse tree in most cases */
543 12097170 : filter_ctx->test_only = true;
544 12097170 : filter_ctx->matched = false;
545 12097170 : filter_ctx->module = module;
546 12097170 : filter_ctx->req = req;
547 12097170 : filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
548 12097170 : filter_ctx->dsdb_flags= default_dsdb_flags;
549 :
550 12097170 : ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
551 12097170 : if (ret != LDB_SUCCESS) {
552 0 : talloc_free(filter_ctx);
553 0 : return ret;
554 : }
555 :
556 12097170 : if (!filter_ctx->matched) {
557 : /* nothing matched, no need for a new parse tree */
558 12073250 : talloc_free(filter_ctx);
559 12073250 : return LDB_SUCCESS;
560 : }
561 :
562 23920 : filter_ctx->test_only = false;
563 23920 : filter_ctx->matched = false;
564 :
565 23920 : *down_tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
566 23920 : if (*down_tree == NULL) {
567 0 : return ldb_oom(ldb_module_get_ctx(module));
568 : }
569 :
570 23920 : ret = ldb_parse_tree_walk(*down_tree, extended_dn_filter_callback, filter_ctx);
571 23920 : if (ret != LDB_SUCCESS) {
572 0 : talloc_free(filter_ctx);
573 0 : return ret;
574 : }
575 :
576 23920 : talloc_free(filter_ctx);
577 23920 : return LDB_SUCCESS;
578 : }
579 :
580 : /*
581 : fix DNs and filter expressions to cope with the semantics of
582 : extended DNs
583 : */
584 12414614 : static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
585 : {
586 : struct extended_search_context *ac;
587 12414614 : struct ldb_request *down_req = NULL;
588 12414614 : struct ldb_parse_tree *down_tree = NULL;
589 : int ret;
590 12414614 : struct ldb_dn *base_dn = NULL;
591 12414614 : enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
592 12414614 : const char *base_dn_filter = NULL;
593 12414614 : const char * const *base_dn_attrs = NULL;
594 12414614 : char *wellknown_object = NULL;
595 : static const char *no_attr[] = {
596 : NULL
597 : };
598 12414614 : uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN;
599 :
600 12414614 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) {
601 5080638 : dsdb_flags |= DSDB_SEARCH_SHOW_DELETED;
602 : }
603 12414614 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) {
604 6123364 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
605 : }
606 12414614 : if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
607 119556 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
608 : }
609 :
610 12414614 : if (req->operation == LDB_SEARCH) {
611 12097170 : ret = extended_dn_fix_filter(module, req, dsdb_flags, &down_tree);
612 12097170 : if (ret != LDB_SUCCESS) {
613 0 : return ret;
614 : }
615 : }
616 :
617 12414614 : if (!ldb_dn_has_extended(dn)) {
618 : /* Move along there isn't anything to see here */
619 6543898 : if (down_tree == NULL) {
620 6519981 : down_req = req;
621 : } else {
622 23917 : ret = ldb_build_search_req_ex(&down_req,
623 : ldb_module_get_ctx(module), req,
624 : req->op.search.base,
625 : req->op.search.scope,
626 : down_tree,
627 : req->op.search.attrs,
628 : req->controls,
629 : req, dsdb_next_callback,
630 : req);
631 23917 : if (ret != LDB_SUCCESS) {
632 0 : return ret;
633 : }
634 23917 : LDB_REQ_SET_LOCATION(down_req);
635 : }
636 :
637 6543898 : return ldb_next_request(module, down_req);
638 : } else {
639 : /* It looks like we need to map the DN */
640 : const struct ldb_val *sid_val, *guid_val, *wkguid_val;
641 :
642 5870716 : if (!ldb_dn_match_allowed(dn, req)) {
643 0 : return ldb_error(ldb_module_get_ctx(module),
644 : LDB_ERR_INVALID_DN_SYNTAX, "invalid number of DN components");
645 : }
646 :
647 5870716 : sid_val = ldb_dn_get_extended_component(dn, "SID");
648 5870716 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
649 5870716 : wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
650 :
651 : /*
652 : prioritise the GUID - we have had instances of
653 : duplicate SIDs in the database in the
654 : ForeignSecurityPrinciples due to provision errors
655 : */
656 5870716 : if (guid_val) {
657 4465845 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
658 4465845 : base_dn = NULL;
659 4465845 : base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
660 : ldb_binary_encode(req, *guid_val));
661 4465845 : if (!base_dn_filter) {
662 0 : return ldb_oom(ldb_module_get_ctx(module));
663 : }
664 4465845 : base_dn_scope = LDB_SCOPE_SUBTREE;
665 4465845 : base_dn_attrs = no_attr;
666 :
667 1404871 : } else if (sid_val) {
668 821463 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
669 821463 : base_dn = NULL;
670 821463 : base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
671 : ldb_binary_encode(req, *sid_val));
672 821463 : if (!base_dn_filter) {
673 0 : return ldb_oom(ldb_module_get_ctx(module));
674 : }
675 821463 : base_dn_scope = LDB_SCOPE_SUBTREE;
676 821463 : base_dn_attrs = no_attr;
677 :
678 583408 : } else if (wkguid_val) {
679 : char *wkguid_dup;
680 : char *tail_str;
681 : char *p;
682 :
683 583408 : wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
684 :
685 583408 : p = strchr(wkguid_dup, ',');
686 583408 : if (!p) {
687 0 : return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
688 : "Invalid WKGUID format");
689 : }
690 :
691 583408 : p[0] = '\0';
692 583408 : p++;
693 :
694 583408 : wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
695 583408 : if (!wellknown_object) {
696 0 : return ldb_oom(ldb_module_get_ctx(module));
697 : }
698 :
699 583408 : tail_str = p;
700 :
701 583408 : base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
702 583408 : talloc_free(wkguid_dup);
703 583408 : if (!base_dn) {
704 0 : return ldb_oom(ldb_module_get_ctx(module));
705 : }
706 583408 : base_dn_filter = talloc_strdup(req, "(objectClass=*)");
707 583408 : if (!base_dn_filter) {
708 0 : return ldb_oom(ldb_module_get_ctx(module));
709 : }
710 583408 : base_dn_scope = LDB_SCOPE_BASE;
711 583408 : base_dn_attrs = wkattr;
712 : } else {
713 0 : return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
714 : "Invalid extended DN component");
715 : }
716 :
717 5870716 : ac = talloc_zero(req, struct extended_search_context);
718 5870716 : if (ac == NULL) {
719 0 : return ldb_oom(ldb_module_get_ctx(module));
720 : }
721 :
722 5870716 : ac->module = module;
723 5870716 : ac->req = req;
724 5870716 : ac->tree = (down_tree != NULL) ? down_tree : req->op.search.tree;
725 5870716 : ac->dn = dn;
726 5870716 : ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
727 5870716 : ac->wellknown_object = wellknown_object;
728 :
729 : /* If the base DN was an extended DN (perhaps a well known
730 : * GUID) then search for that, so we can proceed with the original operation */
731 :
732 5870716 : ret = ldb_build_search_req(&down_req,
733 : ldb_module_get_ctx(module), ac,
734 : base_dn,
735 : base_dn_scope,
736 : base_dn_filter,
737 : base_dn_attrs,
738 : NULL,
739 : ac, extended_base_callback,
740 : req);
741 5870716 : LDB_REQ_SET_LOCATION(down_req);
742 5870716 : if (ret != LDB_SUCCESS) {
743 0 : return ldb_operr(ldb_module_get_ctx(module));
744 : }
745 :
746 5870716 : ret = dsdb_request_add_controls(down_req, dsdb_flags);
747 5870716 : if (ret != LDB_SUCCESS) {
748 0 : return ret;
749 : }
750 :
751 : /* perform the search */
752 5870716 : return ldb_next_request(module, down_req);
753 : }
754 : }
755 :
756 12097170 : static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
757 : {
758 12097170 : return extended_dn_in_fix(module, req, req->op.search.base);
759 : }
760 :
761 243238 : static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
762 : {
763 243238 : return extended_dn_in_fix(module, req, req->op.mod.message->dn);
764 : }
765 :
766 73534 : static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
767 : {
768 73534 : return extended_dn_in_fix(module, req, req->op.del.dn);
769 : }
770 :
771 672 : static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
772 : {
773 672 : return extended_dn_in_fix(module, req, req->op.rename.olddn);
774 : }
775 :
776 : static const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
777 : .name = "extended_dn_in",
778 : .search = extended_dn_in_search,
779 : .modify = extended_dn_in_modify,
780 : .del = extended_dn_in_del,
781 : .rename = extended_dn_in_rename,
782 : };
783 :
784 : static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops = {
785 : .name = "extended_dn_in_openldap",
786 : .search = extended_dn_in_search,
787 : .modify = extended_dn_in_modify,
788 : .del = extended_dn_in_del,
789 : .rename = extended_dn_in_rename,
790 : };
791 :
792 4310 : int ldb_extended_dn_in_module_init(const char *version)
793 : {
794 : int ret;
795 4310 : LDB_MODULE_CHECK_VERSION(version);
796 4310 : ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
797 4310 : if (ret != LDB_SUCCESS) {
798 0 : return ret;
799 : }
800 4310 : return ldb_register_module(&ldb_extended_dn_in_module_ops);
801 : }
|