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 17507157 : static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
69 : {
70 17507157 : int ret = LDB_ERR_OPERATIONS_ERROR;
71 720998 : struct extended_search_context *ac;
72 17507157 : ac = talloc_get_type(req->context, struct extended_search_context);
73 :
74 17507157 : if (ares->error != LDB_SUCCESS) {
75 215 : ret = ldb_module_done(ac->req, ares->controls,
76 : ares->response, ares->error);
77 : } else {
78 17506942 : switch (ares->type) {
79 8666104 : case LDB_REPLY_ENTRY:
80 :
81 8666104 : ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
82 8666104 : break;
83 5420 : case LDB_REPLY_REFERRAL:
84 :
85 5420 : ret = ldb_module_send_referral(ac->req, ares->referral);
86 5420 : break;
87 8835418 : case LDB_REPLY_DONE:
88 :
89 8835418 : ret = ldb_module_done(ac->req, ares->controls,
90 : ares->response, ares->error);
91 8835418 : break;
92 : }
93 : }
94 17507157 : return ret;
95 : }
96 :
97 19210162 : static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
98 : {
99 922805 : struct extended_search_context *ac;
100 922805 : struct ldb_request *down_req;
101 922805 : struct ldb_message_element *el;
102 922805 : int ret;
103 922805 : unsigned int i, j;
104 19210162 : size_t wkn_len = 0;
105 19210162 : char *valstr = NULL;
106 19210162 : const char *found = NULL;
107 :
108 19210162 : ac = talloc_get_type(req->context, struct extended_search_context);
109 :
110 19210162 : if (!ares) {
111 0 : return ldb_module_done(ac->req, NULL, NULL,
112 : LDB_ERR_OPERATIONS_ERROR);
113 : }
114 19210162 : if (ares->error != LDB_SUCCESS) {
115 58 : return ldb_module_done(ac->req, ares->controls,
116 : ares->response, ares->error);
117 : }
118 :
119 19210104 : switch (ares->type) {
120 9496260 : case LDB_REPLY_ENTRY:
121 9496260 : 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 53746 : const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
127 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
128 53746 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
129 53746 : return ldb_module_done(ac->req, NULL, NULL,
130 : LDB_ERR_NO_SUCH_OBJECT);
131 : }
132 :
133 9442514 : if (!ac->wellknown_object) {
134 8509767 : ac->basedn = talloc_steal(ac, ares->message->dn);
135 8509767 : break;
136 : }
137 :
138 932747 : wkn_len = strlen(ac->wellknown_object);
139 :
140 2039199 : for (j=0; wkattr[j]; j++) {
141 :
142 1486064 : el = ldb_msg_find_element(ares->message, wkattr[j]);
143 1486064 : if (!el) {
144 1106266 : ac->basedn = NULL;
145 1106266 : continue;
146 : }
147 :
148 1955811 : for (i=0; i < el->num_values; i++) {
149 1958041 : valstr = talloc_strndup(ac,
150 1955625 : (const char *)el->values[i].data,
151 1955625 : el->values[i].length);
152 1955625 : 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 1955625 : if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
159 1576013 : talloc_free(valstr);
160 1576013 : continue;
161 : }
162 :
163 379612 : found = &valstr[wkn_len];
164 379612 : break;
165 : }
166 379798 : if (found) {
167 379174 : break;
168 : }
169 : }
170 :
171 932747 : if (!found) {
172 476406 : break;
173 : }
174 :
175 379612 : ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
176 379612 : talloc_free(valstr);
177 379612 : 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 379174 : break;
184 :
185 0 : case LDB_REPLY_REFERRAL:
186 0 : break;
187 :
188 9713844 : case LDB_REPLY_DONE:
189 :
190 9713844 : if (!ac->basedn) {
191 878211 : const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
192 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
193 878211 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
194 878211 : return ldb_module_done(ac->req, NULL, NULL,
195 : LDB_ERR_NO_SUCH_OBJECT);
196 : }
197 :
198 8835633 : switch (ac->req->operation) {
199 8677210 : case LDB_SEARCH:
200 8677210 : ret = ldb_build_search_req_ex(&down_req,
201 8306221 : ldb_module_get_ctx(ac->module), ac->req,
202 : ac->basedn,
203 8306221 : ac->req->op.search.scope,
204 : ac->tree,
205 8306221 : ac->req->op.search.attrs,
206 8306221 : ac->req->controls,
207 : ac, extended_final_callback,
208 : ac->req);
209 8677210 : LDB_REQ_SET_LOCATION(down_req);
210 8677210 : 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 158257 : case LDB_MODIFY:
232 : {
233 158257 : struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
234 158257 : 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 158257 : mod_msg->dn = ac->basedn;
241 :
242 158257 : ret = ldb_build_mod_req(&down_req,
243 154430 : ldb_module_get_ctx(ac->module), ac->req,
244 : mod_msg,
245 154430 : ac->req->controls,
246 : ac, extended_final_callback,
247 : ac->req);
248 158257 : LDB_REQ_SET_LOCATION(down_req);
249 158257 : break;
250 : }
251 129 : case LDB_DELETE:
252 129 : 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 129 : LDB_REQ_SET_LOCATION(down_req);
259 129 : break;
260 37 : case LDB_RENAME:
261 37 : 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 8835633 : if (ret != LDB_SUCCESS) {
275 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
276 : }
277 :
278 8835633 : return ldb_next_request(ac->module, down_req);
279 : }
280 9442514 : talloc_free(ares);
281 9442514 : return LDB_SUCCESS;
282 : }
283 :
284 :
285 : /*
286 : windows ldap searches 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 9807875 : static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
303 : {
304 9807875 : int num_components = ldb_dn_get_comp_num(dn);
305 9807875 : int num_ex_components = ldb_dn_get_extended_comp_num(dn);
306 :
307 9807875 : if (num_ex_components == 0) {
308 36708 : return true;
309 : }
310 :
311 10305607 : if ((num_components != 0 || num_ex_components != 1) &&
312 536161 : ldb_req_is_untrusted(req)) {
313 178 : return false;
314 : }
315 9299421 : 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 353 : static void set_parse_tree_false(struct ldb_parse_tree *tree)
332 : {
333 353 : const char *attr = tree->u.equality.attr;
334 353 : struct ldb_val value = tree->u.equality.value;
335 353 : tree->operation = LDB_OP_EXTENDED;
336 353 : tree->u.extended.attr = attr;
337 353 : tree->u.extended.value = value;
338 353 : tree->u.extended.rule_id = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
339 353 : tree->u.extended.dnAttributes = 0;
340 337 : }
341 :
342 : /*
343 : called on all nodes in the parse tree
344 : */
345 61753865 : static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
346 : {
347 3520635 : struct extended_dn_filter_ctx *filter_ctx;
348 3520635 : int ret;
349 61753865 : struct ldb_dn *dn = NULL;
350 3520635 : const struct ldb_val *sid_val, *guid_val;
351 61753865 : const char *no_attrs[] = { NULL };
352 3520635 : struct ldb_result *res;
353 61753865 : const struct dsdb_attribute *attribute = NULL;
354 61753865 : bool has_extended_component = false;
355 3520635 : enum ldb_scope scope;
356 3520635 : struct ldb_dn *base_dn;
357 3520635 : const char *expression;
358 3520635 : uint32_t dsdb_flags;
359 :
360 61753865 : if (tree->operation != LDB_OP_EQUALITY && tree->operation != LDB_OP_EXTENDED) {
361 50339705 : return LDB_SUCCESS;
362 : }
363 :
364 8205271 : filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
365 :
366 8205271 : if (filter_ctx->test_only && filter_ctx->matched) {
367 : /* the tree already matched */
368 49962 : return LDB_SUCCESS;
369 : }
370 :
371 8154020 : if (!filter_ctx->schema) {
372 : /* Schema not setup yet */
373 30721 : return LDB_SUCCESS;
374 : }
375 8122248 : if (tree->operation == LDB_OP_EQUALITY) {
376 4955961 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
377 3166287 : } else if (tree->operation == LDB_OP_EXTENDED) {
378 3166287 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.extended.attr);
379 : }
380 8122248 : if (attribute == NULL) {
381 64 : return LDB_SUCCESS;
382 : }
383 :
384 8122184 : if (attribute->dn_format != DSDB_NORMAL_DN) {
385 7517616 : return LDB_SUCCESS;
386 : }
387 :
388 303801 : if (tree->operation == LDB_OP_EQUALITY) {
389 280049 : has_extended_component = (memchr(tree->u.equality.value.data, '<',
390 : tree->u.equality.value.length) != NULL);
391 23752 : } else if (tree->operation == LDB_OP_EXTENDED) {
392 23752 : 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 303801 : if (!has_extended_component) {
402 300770 : if (!attribute->one_way_link) {
403 215927 : return LDB_SUCCESS;
404 : }
405 :
406 79810 : if (ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops) {
407 0 : return LDB_SUCCESS;
408 : }
409 : }
410 :
411 82841 : if (tree->operation == LDB_OP_EQUALITY) {
412 79781 : dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
413 3060 : } else if (tree->operation == LDB_OP_EXTENDED
414 3060 : && (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 82689 : if (dn == NULL) {
418 : /* testing against windows shows that we don't raise
419 : an error here */
420 3024 : return LDB_SUCCESS;
421 : }
422 :
423 79817 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
424 79817 : 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 79817 : if (!guid_val && !sid_val &&
432 77142 : (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 79802 : if (filter_ctx->test_only) {
443 : /* we need to copy the tree */
444 39575 : filter_ctx->matched = true;
445 39575 : return LDB_SUCCESS;
446 : }
447 :
448 40227 : if (!ldb_dn_match_allowed(dn, filter_ctx->req)) {
449 : /* we need to make this element of the filter always
450 : be false */
451 178 : set_parse_tree_false(tree);
452 178 : return LDB_SUCCESS;
453 : }
454 :
455 40049 : dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE;
456 :
457 40049 : if (guid_val) {
458 732 : expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val));
459 732 : scope = LDB_SCOPE_SUBTREE;
460 732 : base_dn = NULL;
461 732 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
462 39317 : } else if (sid_val) {
463 888 : expression = talloc_asprintf(filter_ctx, "objectSID=%s", ldb_binary_encode(filter_ctx, *sid_val));
464 888 : scope = LDB_SCOPE_SUBTREE;
465 888 : base_dn = NULL;
466 888 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
467 : } else {
468 : /* fallback to searching using the string DN as the base DN */
469 36708 : expression = "objectClass=*";
470 36708 : base_dn = dn;
471 36708 : scope = LDB_SCOPE_BASE;
472 : }
473 :
474 40049 : 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 40049 : 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 175 : set_parse_tree_false(tree);
487 175 : return LDB_SUCCESS;
488 : }
489 :
490 39874 : if (ret != LDB_SUCCESS) {
491 0 : return LDB_SUCCESS;
492 : }
493 :
494 :
495 39874 : if (res->count != 1) {
496 352 : return LDB_SUCCESS;
497 : }
498 :
499 : /* replace the search expression element with the matching DN */
500 39522 : if (tree->operation == LDB_OP_EQUALITY) {
501 41215 : tree->u.equality.value.data =
502 39504 : (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
503 39504 : if (tree->u.equality.value.data == NULL) {
504 0 : return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
505 : }
506 39504 : 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 39522 : talloc_free(res);
516 :
517 39522 : filter_ctx->matched = true;
518 39522 : return LDB_SUCCESS;
519 : }
520 :
521 : /*
522 : fix the parse tree to change any extended DN components to their
523 : canonical form
524 : */
525 20146058 : 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 1151916 : struct extended_dn_filter_ctx *filter_ctx;
531 1151916 : int ret;
532 :
533 20146058 : *down_tree = NULL;
534 :
535 20146058 : filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
536 20146058 : 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 20146058 : filter_ctx->test_only = true;
544 20146058 : filter_ctx->matched = false;
545 20146058 : filter_ctx->module = module;
546 20146058 : filter_ctx->req = req;
547 20146058 : filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
548 20146058 : filter_ctx->dsdb_flags= default_dsdb_flags;
549 :
550 20146058 : ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
551 20146058 : if (ret != LDB_SUCCESS) {
552 0 : talloc_free(filter_ctx);
553 0 : return ret;
554 : }
555 :
556 20146058 : if (!filter_ctx->matched) {
557 : /* nothing matched, no need for a new parse tree */
558 20106483 : talloc_free(filter_ctx);
559 20106483 : return LDB_SUCCESS;
560 : }
561 :
562 39575 : filter_ctx->test_only = false;
563 39575 : filter_ctx->matched = false;
564 :
565 39575 : *down_tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
566 39575 : if (*down_tree == NULL) {
567 0 : return ldb_oom(ldb_module_get_ctx(module));
568 : }
569 :
570 39575 : ret = ldb_parse_tree_walk(*down_tree, extended_dn_filter_callback, filter_ctx);
571 39575 : if (ret != LDB_SUCCESS) {
572 0 : talloc_free(filter_ctx);
573 0 : return ret;
574 : }
575 :
576 39575 : talloc_free(filter_ctx);
577 39575 : return LDB_SUCCESS;
578 : }
579 :
580 : /*
581 : fix DNs and filter expressions to cope with the semantics of
582 : extended DNs
583 : */
584 20579294 : static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
585 : {
586 1169303 : struct extended_search_context *ac;
587 20579294 : struct ldb_request *down_req = NULL;
588 20579294 : struct ldb_parse_tree *down_tree = NULL;
589 1169303 : int ret;
590 20579294 : struct ldb_dn *base_dn = NULL;
591 20579294 : enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
592 20579294 : const char *base_dn_filter = NULL;
593 20579294 : const char * const *base_dn_attrs = NULL;
594 20579294 : char *wellknown_object = NULL;
595 1169303 : static const char *no_attr[] = {
596 : NULL
597 : };
598 20579294 : uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN;
599 :
600 20579294 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) {
601 8743235 : dsdb_flags |= DSDB_SEARCH_SHOW_DELETED;
602 : }
603 20579294 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) {
604 10224991 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
605 : }
606 20579294 : if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
607 146386 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
608 : }
609 :
610 20579294 : if (req->operation == LDB_SEARCH) {
611 20146058 : ret = extended_dn_fix_filter(module, req, dsdb_flags, &down_tree);
612 20146058 : if (ret != LDB_SUCCESS) {
613 0 : return ret;
614 : }
615 : }
616 :
617 20579294 : if (!ldb_dn_has_extended(dn)) {
618 : /* Move along there isn't anything to see here */
619 10811646 : if (down_tree == NULL) {
620 10772074 : down_req = req;
621 : } else {
622 39572 : 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 39572 : if (ret != LDB_SUCCESS) {
632 0 : return ret;
633 : }
634 39572 : LDB_REQ_SET_LOCATION(down_req);
635 : }
636 :
637 10811646 : return ldb_next_request(module, down_req);
638 : } else {
639 : /* It looks like we need to map the DN */
640 469841 : const struct ldb_val *sid_val, *guid_val, *wkguid_val;
641 :
642 9767648 : 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 9767648 : sid_val = ldb_dn_get_extended_component(dn, "SID");
648 9767648 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
649 9767648 : 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 9767648 : if (guid_val) {
657 7429704 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
658 7429704 : base_dn = NULL;
659 7429704 : base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
660 : ldb_binary_encode(req, *guid_val));
661 7429704 : if (!base_dn_filter) {
662 0 : return ldb_oom(ldb_module_get_ctx(module));
663 : }
664 7086454 : base_dn_scope = LDB_SCOPE_SUBTREE;
665 7086454 : base_dn_attrs = no_attr;
666 :
667 2337944 : } else if (sid_val) {
668 1405197 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
669 1405197 : base_dn = NULL;
670 1405197 : base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
671 : ldb_binary_encode(req, *sid_val));
672 1405197 : if (!base_dn_filter) {
673 0 : return ldb_oom(ldb_module_get_ctx(module));
674 : }
675 1355773 : base_dn_scope = LDB_SCOPE_SUBTREE;
676 1355773 : base_dn_attrs = no_attr;
677 :
678 932747 : } else if (wkguid_val) {
679 77167 : char *wkguid_dup;
680 77167 : char *tail_str;
681 77167 : char *p;
682 :
683 932747 : wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
684 :
685 932747 : p = strchr(wkguid_dup, ',');
686 932747 : if (!p) {
687 0 : return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
688 : "Invalid WKGUID format");
689 : }
690 :
691 932747 : p[0] = '\0';
692 932747 : p++;
693 :
694 932747 : wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
695 932747 : if (!wellknown_object) {
696 0 : return ldb_oom(ldb_module_get_ctx(module));
697 : }
698 :
699 932747 : tail_str = p;
700 :
701 932747 : base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
702 932747 : talloc_free(wkguid_dup);
703 932747 : if (!base_dn) {
704 0 : return ldb_oom(ldb_module_get_ctx(module));
705 : }
706 932747 : base_dn_filter = talloc_strdup(req, "(objectClass=*)");
707 932747 : if (!base_dn_filter) {
708 0 : return ldb_oom(ldb_module_get_ctx(module));
709 : }
710 855580 : base_dn_scope = LDB_SCOPE_BASE;
711 855580 : 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 9767648 : ac = talloc_zero(req, struct extended_search_context);
718 9767648 : if (ac == NULL) {
719 0 : return ldb_oom(ldb_module_get_ctx(module));
720 : }
721 :
722 9767648 : ac->module = module;
723 9767648 : ac->req = req;
724 9767648 : ac->tree = (down_tree != NULL) ? down_tree : req->op.search.tree;
725 9767648 : ac->dn = dn;
726 9767648 : ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
727 9767648 : 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 9767648 : 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 9767648 : LDB_REQ_SET_LOCATION(down_req);
742 9767648 : if (ret != LDB_SUCCESS) {
743 0 : return ldb_operr(ldb_module_get_ctx(module));
744 : }
745 :
746 9767648 : ret = dsdb_request_add_controls(down_req, dsdb_flags);
747 9767648 : if (ret != LDB_SUCCESS) {
748 0 : return ret;
749 : }
750 :
751 : /* perform the search */
752 9767648 : return ldb_next_request(module, down_req);
753 : }
754 : }
755 :
756 20146058 : static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
757 : {
758 20146058 : return extended_dn_in_fix(module, req, req->op.search.base);
759 : }
760 :
761 321280 : static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
762 : {
763 321280 : return extended_dn_in_fix(module, req, req->op.mod.message->dn);
764 : }
765 :
766 110676 : static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
767 : {
768 110676 : return extended_dn_in_fix(module, req, req->op.del.dn);
769 : }
770 :
771 1280 : static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
772 : {
773 1280 : 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 6040 : int ldb_extended_dn_in_module_init(const char *version)
793 : {
794 444 : int ret;
795 6040 : LDB_MODULE_CHECK_VERSION(version);
796 6040 : ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
797 6040 : if (ret != LDB_SUCCESS) {
798 0 : return ret;
799 : }
800 6040 : return ldb_register_module(&ldb_extended_dn_in_module_ops);
801 : }
|