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 17757214 : static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
69 : {
70 17757214 : int ret = LDB_ERR_OPERATIONS_ERROR;
71 720890 : struct extended_search_context *ac;
72 17757214 : ac = talloc_get_type(req->context, struct extended_search_context);
73 :
74 17757214 : if (ares->error != LDB_SUCCESS) {
75 215 : ret = ldb_module_done(ac->req, ares->controls,
76 : ares->response, ares->error);
77 : } else {
78 17756999 : switch (ares->type) {
79 8811902 : case LDB_REPLY_ENTRY:
80 :
81 8811902 : ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
82 8811902 : break;
83 5668 : case LDB_REPLY_REFERRAL:
84 :
85 5668 : ret = ldb_module_send_referral(ac->req, ares->referral);
86 5668 : break;
87 8939429 : case LDB_REPLY_DONE:
88 :
89 8939429 : ret = ldb_module_done(ac->req, ares->controls,
90 : ares->response, ares->error);
91 8939429 : break;
92 : }
93 : }
94 17757214 : return ret;
95 : }
96 :
97 19415212 : static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
98 : {
99 922697 : struct extended_search_context *ac;
100 922697 : struct ldb_request *down_req;
101 922697 : struct ldb_message_element *el;
102 922697 : int ret;
103 922697 : unsigned int i, j;
104 19415212 : size_t wkn_len = 0;
105 19415212 : char *valstr = NULL;
106 19415212 : const char *found = NULL;
107 :
108 19415212 : ac = talloc_get_type(req->context, struct extended_search_context);
109 :
110 19415212 : if (!ares) {
111 0 : return ldb_module_done(ac->req, NULL, NULL,
112 : LDB_ERR_OPERATIONS_ERROR);
113 : }
114 19415212 : if (ares->error != LDB_SUCCESS) {
115 58 : return ldb_module_done(ac->req, ares->controls,
116 : ares->response, ares->error);
117 : }
118 :
119 19415154 : switch (ares->type) {
120 9599604 : case LDB_REPLY_ENTRY:
121 9599604 : 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 53413 : const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
127 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
128 53413 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
129 53413 : return ldb_module_done(ac->req, NULL, NULL,
130 : LDB_ERR_NO_SUCH_OBJECT);
131 : }
132 :
133 9546191 : if (!ac->wellknown_object) {
134 8546632 : ac->basedn = talloc_steal(ac, ares->message->dn);
135 8546632 : break;
136 : }
137 :
138 999559 : wkn_len = strlen(ac->wellknown_object);
139 :
140 2105949 : for (j=0; wkattr[j]; j++) {
141 :
142 1552815 : el = ldb_msg_find_element(ares->message, wkattr[j]);
143 1552815 : if (!el) {
144 1106264 : ac->basedn = NULL;
145 1106264 : continue;
146 : }
147 :
148 2288531 : for (i=0; i < el->num_values; i++) {
149 2290821 : valstr = talloc_strndup(ac,
150 2288405 : (const char *)el->values[i].data,
151 2288405 : el->values[i].length);
152 2288405 : 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 2288405 : if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
159 1841980 : talloc_free(valstr);
160 1841980 : continue;
161 : }
162 :
163 446425 : found = &valstr[wkn_len];
164 446425 : break;
165 : }
166 446551 : if (found) {
167 445987 : break;
168 : }
169 : }
170 :
171 999559 : if (!found) {
172 476405 : break;
173 : }
174 :
175 446425 : ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
176 446425 : talloc_free(valstr);
177 446425 : 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 445987 : break;
184 :
185 0 : case LDB_REPLY_REFERRAL:
186 0 : break;
187 :
188 9815550 : case LDB_REPLY_DONE:
189 :
190 9815550 : if (!ac->basedn) {
191 875906 : const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
192 : ldb_dn_get_extended_linearized(req, ac->dn, 1));
193 875906 : ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
194 875906 : return ldb_module_done(ac->req, NULL, NULL,
195 : LDB_ERR_NO_SUCH_OBJECT);
196 : }
197 :
198 8939644 : switch (ac->req->operation) {
199 8780030 : case LDB_SEARCH:
200 8780030 : ret = ldb_build_search_req_ex(&down_req,
201 8409095 : ldb_module_get_ctx(ac->module), ac->req,
202 : ac->basedn,
203 8409095 : ac->req->op.search.scope,
204 : ac->tree,
205 8409095 : ac->req->op.search.attrs,
206 8409095 : ac->req->controls,
207 : ac, extended_final_callback,
208 : ac->req);
209 8780030 : LDB_REQ_SET_LOCATION(down_req);
210 8780030 : 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 159448 : case LDB_MODIFY:
232 : {
233 159448 : struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
234 159448 : 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 159448 : mod_msg->dn = ac->basedn;
241 :
242 159448 : ret = ldb_build_mod_req(&down_req,
243 155621 : ldb_module_get_ctx(ac->module), ac->req,
244 : mod_msg,
245 155621 : ac->req->controls,
246 : ac, extended_final_callback,
247 : ac->req);
248 159448 : LDB_REQ_SET_LOCATION(down_req);
249 159448 : 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 8939644 : if (ret != LDB_SUCCESS) {
275 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
276 : }
277 :
278 8939644 : return ldb_next_request(ac->module, down_req);
279 : }
280 9546191 : talloc_free(ares);
281 9546191 : 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 9908035 : static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
303 : {
304 9908035 : int num_components = ldb_dn_get_comp_num(dn);
305 9908035 : int num_ex_components = ldb_dn_get_extended_comp_num(dn);
306 :
307 9908035 : if (num_ex_components == 0) {
308 35495 : return true;
309 : }
310 :
311 10409668 : if ((num_components != 0 || num_ex_components != 1) &&
312 538849 : ldb_req_is_untrusted(req)) {
313 178 : return false;
314 : }
315 9400848 : 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 61781764 : static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
346 : {
347 3495775 : struct extended_dn_filter_ctx *filter_ctx;
348 3495775 : int ret;
349 61781764 : struct ldb_dn *dn = NULL;
350 3495775 : const struct ldb_val *sid_val, *guid_val;
351 61781764 : const char *no_attrs[] = { NULL };
352 3495775 : struct ldb_result *res;
353 61781764 : const struct dsdb_attribute *attribute = NULL;
354 61781764 : bool has_extended_component = false;
355 3495775 : enum ldb_scope scope;
356 3495775 : struct ldb_dn *base_dn;
357 3495775 : const char *expression;
358 3495775 : uint32_t dsdb_flags;
359 :
360 61781764 : if (tree->operation != LDB_OP_EQUALITY && tree->operation != LDB_OP_EXTENDED) {
361 50514911 : return LDB_SUCCESS;
362 : }
363 :
364 8082740 : filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
365 :
366 8082740 : if (filter_ctx->test_only && filter_ctx->matched) {
367 : /* the tree already matched */
368 47690 : return LDB_SUCCESS;
369 : }
370 :
371 8033761 : if (!filter_ctx->schema) {
372 : /* Schema not setup yet */
373 30481 : return LDB_SUCCESS;
374 : }
375 8002229 : if (tree->operation == LDB_OP_EQUALITY) {
376 4878355 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
377 3123874 : } else if (tree->operation == LDB_OP_EXTENDED) {
378 3123874 : attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.extended.attr);
379 : }
380 8002229 : if (attribute == NULL) {
381 62 : return LDB_SUCCESS;
382 : }
383 :
384 8002167 : if (attribute->dn_format != DSDB_NORMAL_DN) {
385 7403151 : return LDB_SUCCESS;
386 : }
387 :
388 298333 : if (tree->operation == LDB_OP_EQUALITY) {
389 274849 : has_extended_component = (memchr(tree->u.equality.value.data, '<',
390 : tree->u.equality.value.length) != NULL);
391 23484 : } else if (tree->operation == LDB_OP_EXTENDED) {
392 23484 : 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 298333 : if (!has_extended_component) {
402 295302 : if (!attribute->one_way_link) {
403 212937 : return LDB_SUCCESS;
404 : }
405 :
406 77332 : if (ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops) {
407 0 : return LDB_SUCCESS;
408 : }
409 : }
410 :
411 80363 : if (tree->operation == LDB_OP_EQUALITY) {
412 77355 : dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
413 3008 : } else if (tree->operation == LDB_OP_EXTENDED
414 3008 : && (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 80211 : if (dn == NULL) {
418 : /* testing against windows shows that we don't raise
419 : an error here */
420 2972 : return LDB_SUCCESS;
421 : }
422 :
423 77391 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
424 77391 : 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 77391 : if (!guid_val && !sid_val &&
432 74716 : (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 77376 : if (filter_ctx->test_only) {
443 : /* we need to copy the tree */
444 38362 : filter_ctx->matched = true;
445 38362 : return LDB_SUCCESS;
446 : }
447 :
448 39014 : 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 38836 : dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE;
456 :
457 38836 : 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 38104 : } 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 35495 : expression = "objectClass=*";
470 35495 : base_dn = dn;
471 35495 : scope = LDB_SCOPE_BASE;
472 : }
473 :
474 38836 : 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 38836 : 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 38661 : if (ret != LDB_SUCCESS) {
491 0 : return LDB_SUCCESS;
492 : }
493 :
494 :
495 38661 : if (res->count != 1) {
496 352 : return LDB_SUCCESS;
497 : }
498 :
499 : /* replace the search expression element with the matching DN */
500 38309 : if (tree->operation == LDB_OP_EQUALITY) {
501 40002 : tree->u.equality.value.data =
502 38291 : (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
503 38291 : if (tree->u.equality.value.data == NULL) {
504 0 : return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
505 : }
506 38291 : 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 38309 : talloc_free(res);
516 :
517 38309 : filter_ctx->matched = true;
518 38309 : return LDB_SUCCESS;
519 : }
520 :
521 : /*
522 : fix the parse tree to change any extended DN components to their
523 : canonical form
524 : */
525 20161546 : 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 1143602 : struct extended_dn_filter_ctx *filter_ctx;
531 1143602 : int ret;
532 :
533 20161546 : *down_tree = NULL;
534 :
535 20161546 : filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
536 20161546 : 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 20161546 : filter_ctx->test_only = true;
544 20161546 : filter_ctx->matched = false;
545 20161546 : filter_ctx->module = module;
546 20161546 : filter_ctx->req = req;
547 20161546 : filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
548 20161546 : filter_ctx->dsdb_flags= default_dsdb_flags;
549 :
550 20161546 : ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
551 20161546 : if (ret != LDB_SUCCESS) {
552 0 : talloc_free(filter_ctx);
553 0 : return ret;
554 : }
555 :
556 20161546 : if (!filter_ctx->matched) {
557 : /* nothing matched, no need for a new parse tree */
558 20123184 : talloc_free(filter_ctx);
559 20123184 : return LDB_SUCCESS;
560 : }
561 :
562 38362 : filter_ctx->test_only = false;
563 38362 : filter_ctx->matched = false;
564 :
565 38362 : *down_tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
566 38362 : if (*down_tree == NULL) {
567 0 : return ldb_oom(ldb_module_get_ctx(module));
568 : }
569 :
570 38362 : ret = ldb_parse_tree_walk(*down_tree, extended_dn_filter_callback, filter_ctx);
571 38362 : if (ret != LDB_SUCCESS) {
572 0 : talloc_free(filter_ctx);
573 0 : return ret;
574 : }
575 :
576 38362 : talloc_free(filter_ctx);
577 38362 : return LDB_SUCCESS;
578 : }
579 :
580 : /*
581 : fix DNs and filter expressions to cope with the semantics of
582 : extended DNs
583 : */
584 20595200 : static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
585 : {
586 1160989 : struct extended_search_context *ac;
587 20595200 : struct ldb_request *down_req = NULL;
588 20595200 : struct ldb_parse_tree *down_tree = NULL;
589 1160989 : int ret;
590 20595200 : struct ldb_dn *base_dn = NULL;
591 20595200 : enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
592 20595200 : const char *base_dn_filter = NULL;
593 20595200 : const char * const *base_dn_attrs = NULL;
594 20595200 : char *wellknown_object = NULL;
595 1160989 : static const char *no_attr[] = {
596 : NULL
597 : };
598 20595200 : uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN;
599 :
600 20595200 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) {
601 8838717 : dsdb_flags |= DSDB_SEARCH_SHOW_DELETED;
602 : }
603 20595200 : if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) {
604 10353466 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
605 : }
606 20595200 : if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
607 146359 : dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
608 : }
609 :
610 20595200 : if (req->operation == LDB_SEARCH) {
611 20161546 : ret = extended_dn_fix_filter(module, req, dsdb_flags, &down_tree);
612 20161546 : if (ret != LDB_SUCCESS) {
613 0 : return ret;
614 : }
615 : }
616 :
617 20595200 : if (!ldb_dn_has_extended(dn)) {
618 : /* Move along there isn't anything to see here */
619 10726179 : if (down_tree == NULL) {
620 10687820 : down_req = req;
621 : } else {
622 38359 : 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 38359 : if (ret != LDB_SUCCESS) {
632 0 : return ret;
633 : }
634 38359 : LDB_REQ_SET_LOCATION(down_req);
635 : }
636 :
637 10726179 : return ldb_next_request(module, down_req);
638 : } else {
639 : /* It looks like we need to map the DN */
640 469787 : const struct ldb_val *sid_val, *guid_val, *wkguid_val;
641 :
642 9869021 : 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 9869021 : sid_val = ldb_dn_get_extended_component(dn, "SID");
648 9869021 : guid_val = ldb_dn_get_extended_component(dn, "GUID");
649 9869021 : 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 9869021 : if (guid_val) {
657 7478895 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
658 7478895 : base_dn = NULL;
659 7478895 : base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
660 : ldb_binary_encode(req, *guid_val));
661 7478895 : if (!base_dn_filter) {
662 0 : return ldb_oom(ldb_module_get_ctx(module));
663 : }
664 7135699 : base_dn_scope = LDB_SCOPE_SUBTREE;
665 7135699 : base_dn_attrs = no_attr;
666 :
667 2390126 : } else if (sid_val) {
668 1390567 : dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
669 1390567 : base_dn = NULL;
670 1390567 : base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
671 : ldb_binary_encode(req, *sid_val));
672 1390567 : if (!base_dn_filter) {
673 0 : return ldb_oom(ldb_module_get_ctx(module));
674 : }
675 1341143 : base_dn_scope = LDB_SCOPE_SUBTREE;
676 1341143 : base_dn_attrs = no_attr;
677 :
678 999559 : } else if (wkguid_val) {
679 77167 : char *wkguid_dup;
680 77167 : char *tail_str;
681 77167 : char *p;
682 :
683 999559 : wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
684 :
685 999559 : p = strchr(wkguid_dup, ',');
686 999559 : if (!p) {
687 0 : return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
688 : "Invalid WKGUID format");
689 : }
690 :
691 999559 : p[0] = '\0';
692 999559 : p++;
693 :
694 999559 : wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
695 999559 : if (!wellknown_object) {
696 0 : return ldb_oom(ldb_module_get_ctx(module));
697 : }
698 :
699 999559 : tail_str = p;
700 :
701 999559 : base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
702 999559 : talloc_free(wkguid_dup);
703 999559 : if (!base_dn) {
704 0 : return ldb_oom(ldb_module_get_ctx(module));
705 : }
706 999559 : base_dn_filter = talloc_strdup(req, "(objectClass=*)");
707 999559 : if (!base_dn_filter) {
708 0 : return ldb_oom(ldb_module_get_ctx(module));
709 : }
710 922392 : base_dn_scope = LDB_SCOPE_BASE;
711 922392 : 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 9869021 : ac = talloc_zero(req, struct extended_search_context);
718 9869021 : if (ac == NULL) {
719 0 : return ldb_oom(ldb_module_get_ctx(module));
720 : }
721 :
722 9869021 : ac->module = module;
723 9869021 : ac->req = req;
724 9869021 : ac->tree = (down_tree != NULL) ? down_tree : req->op.search.tree;
725 9869021 : ac->dn = dn;
726 9869021 : ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
727 9869021 : 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 9869021 : 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 9869021 : LDB_REQ_SET_LOCATION(down_req);
742 9869021 : if (ret != LDB_SUCCESS) {
743 0 : return ldb_operr(ldb_module_get_ctx(module));
744 : }
745 :
746 9869021 : ret = dsdb_request_add_controls(down_req, dsdb_flags);
747 9869021 : if (ret != LDB_SUCCESS) {
748 0 : return ret;
749 : }
750 :
751 : /* perform the search */
752 9869021 : return ldb_next_request(module, down_req);
753 : }
754 : }
755 :
756 20161546 : static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
757 : {
758 20161546 : return extended_dn_in_fix(module, req, req->op.search.base);
759 : }
760 :
761 322154 : static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
762 : {
763 322154 : return extended_dn_in_fix(module, req, req->op.mod.message->dn);
764 : }
765 :
766 110220 : static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
767 : {
768 110220 : 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 5950 : int ldb_extended_dn_in_module_init(const char *version)
793 : {
794 393 : int ret;
795 5950 : LDB_MODULE_CHECK_VERSION(version);
796 5950 : ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
797 5950 : if (ret != LDB_SUCCESS) {
798 0 : return ret;
799 : }
800 5950 : return ldb_register_module(&ldb_extended_dn_in_module_ops);
801 : }
|