LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - extended_dn_in.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 329 376 87.5 %
Date: 2024-02-28 12:06:22 Functions: 12 12 100.0 %

          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    17426995 : static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
      69             : {
      70    17426995 :         int ret = LDB_ERR_OPERATIONS_ERROR;
      71      720854 :         struct extended_search_context *ac;
      72    17426995 :         ac = talloc_get_type(req->context, struct extended_search_context);
      73             : 
      74    17426995 :         if (ares->error != LDB_SUCCESS) {
      75         215 :                 ret = ldb_module_done(ac->req, ares->controls,
      76             :                                       ares->response, ares->error);
      77             :         } else {
      78    17426780 :                 switch (ares->type) {
      79     8628273 :                 case LDB_REPLY_ENTRY:
      80             :                         
      81     8628273 :                         ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
      82     8628273 :                         break;
      83        5480 :                 case LDB_REPLY_REFERRAL:
      84             :                         
      85        5480 :                         ret = ldb_module_send_referral(ac->req, ares->referral);
      86        5480 :                         break;
      87     8793027 :                 case LDB_REPLY_DONE:
      88             :                         
      89     8793027 :                         ret = ldb_module_done(ac->req, ares->controls,
      90             :                                               ares->response, ares->error);
      91     8793027 :                         break;
      92             :                 }
      93             :         }
      94    17426995 :         return ret;
      95             : }
      96             : 
      97    19122134 : static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
      98             : {
      99      922661 :         struct extended_search_context *ac;
     100      922661 :         struct ldb_request *down_req;
     101      922661 :         struct ldb_message_element *el;
     102      922661 :         int ret;
     103      922661 :         unsigned int i, j;
     104    19122134 :         size_t wkn_len = 0;
     105    19122134 :         char *valstr = NULL;
     106    19122134 :         const char *found = NULL;
     107             : 
     108    19122134 :         ac = talloc_get_type(req->context, struct extended_search_context);
     109             : 
     110    19122134 :         if (!ares) {
     111           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     112             :                                         LDB_ERR_OPERATIONS_ERROR);
     113             :         }
     114    19122134 :         if (ares->error != LDB_SUCCESS) {
     115          58 :                 return ldb_module_done(ac->req, ares->controls,
     116             :                                         ares->response, ares->error);
     117             :         }
     118             : 
     119    19122076 :         switch (ares->type) {
     120     9453170 :         case LDB_REPLY_ENTRY:
     121     9453170 :                 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       53397 :                         const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
     127             :                                                           ldb_dn_get_extended_linearized(req, ac->dn, 1));
     128       53397 :                         ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
     129       53397 :                         return ldb_module_done(ac->req, NULL, NULL,
     130             :                                                LDB_ERR_NO_SUCH_OBJECT);
     131             :                 }
     132             : 
     133     9399773 :                 if (!ac->wellknown_object) {
     134     8467433 :                         ac->basedn = talloc_steal(ac, ares->message->dn);
     135     8467433 :                         break;
     136             :                 }
     137             : 
     138      932340 :                 wkn_len = strlen(ac->wellknown_object);
     139             : 
     140     2038730 :                 for (j=0; wkattr[j]; j++) {
     141             : 
     142     1485596 :                         el = ldb_msg_find_element(ares->message, wkattr[j]);
     143     1485596 :                         if (!el) {
     144     1106264 :                                 ac->basedn = NULL;
     145     1106264 :                                 continue;
     146             :                         }
     147             : 
     148     1952724 :                         for (i=0; i < el->num_values; i++) {
     149     1955014 :                                 valstr = talloc_strndup(ac,
     150     1952598 :                                                         (const char *)el->values[i].data,
     151     1952598 :                                                         el->values[i].length);
     152     1952598 :                                 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     1952598 :                                 if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
     159     1573392 :                                         talloc_free(valstr);
     160     1573392 :                                         continue;
     161             :                                 }
     162             : 
     163      379206 :                                 found = &valstr[wkn_len];
     164      379206 :                                 break;
     165             :                         }
     166      379332 :                         if (found) {
     167      378768 :                                 break;
     168             :                         }
     169             :                 }
     170             : 
     171      932340 :                 if (!found) {
     172      476405 :                         break;
     173             :                 }
     174             : 
     175      379206 :                 ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
     176      379206 :                 talloc_free(valstr);
     177      379206 :                 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      378768 :                 break;
     184             : 
     185           0 :         case LDB_REPLY_REFERRAL:
     186           0 :                 break;
     187             : 
     188     9668906 :         case LDB_REPLY_DONE:
     189             : 
     190     9668906 :                 if (!ac->basedn) {
     191      875664 :                         const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
     192             :                                                           ldb_dn_get_extended_linearized(req, ac->dn, 1));
     193      875664 :                         ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
     194      875664 :                         return ldb_module_done(ac->req, NULL, NULL,
     195             :                                                LDB_ERR_NO_SUCH_OBJECT);
     196             :                 }
     197             : 
     198     8793242 :                 switch (ac->req->operation) {
     199     8634627 :                 case LDB_SEARCH:
     200     8634627 :                         ret = ldb_build_search_req_ex(&down_req,
     201     8263710 :                                                       ldb_module_get_ctx(ac->module), ac->req,
     202             :                                                       ac->basedn,
     203     8263710 :                                                       ac->req->op.search.scope,
     204             :                                                       ac->tree,
     205     8263710 :                                                       ac->req->op.search.attrs,
     206     8263710 :                                                       ac->req->controls,
     207             :                                                       ac, extended_final_callback, 
     208             :                                                       ac->req);
     209     8634627 :                         LDB_REQ_SET_LOCATION(down_req);
     210     8634627 :                         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      158449 :                 case LDB_MODIFY:
     232             :                 {
     233      158449 :                         struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
     234      158449 :                         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      158449 :                         mod_msg->dn = ac->basedn;
     241             : 
     242      158449 :                         ret = ldb_build_mod_req(&down_req,
     243      154622 :                                                 ldb_module_get_ctx(ac->module), ac->req,
     244             :                                                 mod_msg, 
     245      154622 :                                                 ac->req->controls,
     246             :                                                 ac, extended_final_callback, 
     247             :                                                 ac->req);
     248      158449 :                         LDB_REQ_SET_LOCATION(down_req);
     249      158449 :                         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     8793242 :                 if (ret != LDB_SUCCESS) {
     275           0 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
     276             :                 }
     277             : 
     278     8793242 :                 return ldb_next_request(ac->module, down_req);
     279             :         }
     280     9399773 :         talloc_free(ares);
     281     9399773 :         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     9761357 : static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
     303             : {
     304     9761357 :         int num_components = ldb_dn_get_comp_num(dn);
     305     9761357 :         int num_ex_components = ldb_dn_get_extended_comp_num(dn);
     306             : 
     307     9761357 :         if (num_ex_components == 0) {
     308       35477 :                 return true;
     309             :         }
     310             : 
     311    10259212 :         if ((num_components != 0 || num_ex_components != 1) &&
     312      535053 :             ldb_req_is_untrusted(req)) {
     313         178 :                 return false;
     314             :         }
     315     9254206 :         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    61384102 : static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
     346             : {
     347     3535513 :         struct extended_dn_filter_ctx *filter_ctx;
     348     3535513 :         int ret;
     349    61384102 :         struct ldb_dn *dn = NULL;
     350     3535513 :         const struct ldb_val *sid_val, *guid_val;
     351    61384102 :         const char *no_attrs[] = { NULL };
     352     3535513 :         struct ldb_result *res;
     353    61384102 :         const struct dsdb_attribute *attribute = NULL;
     354    61384102 :         bool has_extended_component = false;
     355     3535513 :         enum ldb_scope scope;
     356     3535513 :         struct ldb_dn *base_dn;
     357     3535513 :         const char *expression;
     358     3535513 :         uint32_t dsdb_flags;
     359             : 
     360    61384102 :         if (tree->operation != LDB_OP_EQUALITY && tree->operation != LDB_OP_EXTENDED) {
     361    50082888 :                 return LDB_SUCCESS;
     362             :         }
     363             : 
     364     8077397 :         filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
     365             : 
     366     8077397 :         if (filter_ctx->test_only && filter_ctx->matched) {
     367             :                 /* the tree already matched */
     368       47654 :                 return LDB_SUCCESS;
     369             :         }
     370             : 
     371     8028454 :         if (!filter_ctx->schema) {
     372             :                 /* Schema not setup yet */
     373       30406 :                 return LDB_SUCCESS;
     374             :         }
     375     7996997 :         if (tree->operation == LDB_OP_EQUALITY) {
     376     4875184 :                 attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
     377     3121813 :         } else if (tree->operation == LDB_OP_EXTENDED) {
     378     3121813 :                 attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.extended.attr);
     379             :         }
     380     7996997 :         if (attribute == NULL) {
     381          62 :                 return LDB_SUCCESS;
     382             :         }
     383             : 
     384     7996935 :         if (attribute->dn_format != DSDB_NORMAL_DN) {
     385     7397985 :                 return LDB_SUCCESS;
     386             :         }
     387             : 
     388      298233 :         if (tree->operation == LDB_OP_EQUALITY) {
     389      274749 :                 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      298233 :         if (!has_extended_component) {
     402      295202 :                 if (!attribute->one_way_link) {
     403      212873 :                         return LDB_SUCCESS;
     404             :                 }
     405             : 
     406       77296 :                 if (ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops) {
     407           0 :                         return LDB_SUCCESS;
     408             :                 }
     409             :         }
     410             : 
     411       80327 :         if (tree->operation == LDB_OP_EQUALITY) {
     412       77319 :                 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       80175 :         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       77355 :         guid_val = ldb_dn_get_extended_component(dn, "GUID");
     424       77355 :         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       77355 :         if (!guid_val && !sid_val &&
     432       74680 :             (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       77340 :         if (filter_ctx->test_only) {
     443             :                 /* we need to copy the tree */
     444       38344 :                 filter_ctx->matched = true;
     445       38344 :                 return LDB_SUCCESS;
     446             :         }
     447             : 
     448       38996 :         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       38818 :         dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE;
     456             : 
     457       38818 :         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       38086 :         } 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       35477 :                 expression = "objectClass=*";
     470       35477 :                 base_dn = dn;
     471       35477 :                 scope = LDB_SCOPE_BASE;
     472             :         }
     473             : 
     474       38818 :         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       38818 :         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       38643 :         if (ret != LDB_SUCCESS) {
     491           0 :                 return LDB_SUCCESS;
     492             :         }
     493             : 
     494             : 
     495       38643 :         if (res->count != 1) {
     496         352 :                 return LDB_SUCCESS;
     497             :         }
     498             : 
     499             :         /* replace the search expression element with the matching DN */
     500       38291 :         if (tree->operation == LDB_OP_EQUALITY) {
     501       39984 :                 tree->u.equality.value.data =
     502       38273 :                         (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
     503       38273 :                 if (tree->u.equality.value.data == NULL) {
     504           0 :                         return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
     505             :                 }
     506       38273 :                 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       38291 :         talloc_free(res);
     516             : 
     517       38291 :         filter_ctx->matched = true;
     518       38291 :         return LDB_SUCCESS;
     519             : }
     520             : 
     521             : /*
     522             :   fix the parse tree to change any extended DN components to their
     523             :   canonical form
     524             :  */
     525    20029171 : 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     1156860 :         struct extended_dn_filter_ctx *filter_ctx;
     531     1156860 :         int ret;
     532             : 
     533    20029171 :         *down_tree = NULL;
     534             : 
     535    20029171 :         filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
     536    20029171 :         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    20029171 :         filter_ctx->test_only = true;
     544    20029171 :         filter_ctx->matched   = false;
     545    20029171 :         filter_ctx->module    = module;
     546    20029171 :         filter_ctx->req       = req;
     547    20029171 :         filter_ctx->schema    = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
     548    20029171 :         filter_ctx->dsdb_flags= default_dsdb_flags;
     549             : 
     550    20029171 :         ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
     551    20029171 :         if (ret != LDB_SUCCESS) {
     552           0 :                 talloc_free(filter_ctx);
     553           0 :                 return ret;
     554             :         }
     555             : 
     556    20029171 :         if (!filter_ctx->matched) {
     557             :                 /* nothing matched, no need for a new parse tree */
     558    19990827 :                 talloc_free(filter_ctx);
     559    19990827 :                 return LDB_SUCCESS;
     560             :         }
     561             : 
     562       38344 :         filter_ctx->test_only = false;
     563       38344 :         filter_ctx->matched   = false;
     564             : 
     565       38344 :         *down_tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
     566       38344 :         if (*down_tree == NULL) {
     567           0 :                 return ldb_oom(ldb_module_get_ctx(module));
     568             :         }
     569             : 
     570       38344 :         ret = ldb_parse_tree_walk(*down_tree, extended_dn_filter_callback, filter_ctx);
     571       38344 :         if (ret != LDB_SUCCESS) {
     572           0 :                 talloc_free(filter_ctx);
     573           0 :                 return ret;
     574             :         }
     575             : 
     576       38344 :         talloc_free(filter_ctx);
     577       38344 :         return LDB_SUCCESS;
     578             : }
     579             : 
     580             : /*
     581             :   fix DNs and filter expressions to cope with the semantics of
     582             :   extended DNs
     583             :  */
     584    20461820 : static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
     585             : {
     586     1174247 :         struct extended_search_context *ac;
     587    20461820 :         struct ldb_request *down_req = NULL;
     588    20461820 :         struct ldb_parse_tree *down_tree = NULL;
     589     1174247 :         int ret;
     590    20461820 :         struct ldb_dn *base_dn = NULL;
     591    20461820 :         enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
     592    20461820 :         const char *base_dn_filter = NULL;
     593    20461820 :         const char * const *base_dn_attrs = NULL;
     594    20461820 :         char *wellknown_object = NULL;
     595     1174247 :         static const char *no_attr[] = {
     596             :                 NULL
     597             :         };
     598    20461820 :         uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN;
     599             : 
     600    20461820 :         if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) {
     601     8755349 :                 dsdb_flags |= DSDB_SEARCH_SHOW_DELETED;
     602             :         }
     603    20461820 :         if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) {
     604    10231084 :                 dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
     605             :         }
     606    20461820 :         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
     607      146356 :                 dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
     608             :         }
     609             : 
     610    20461820 :         if (req->operation == LDB_SEARCH) {
     611    20029171 :                 ret = extended_dn_fix_filter(module, req, dsdb_flags, &down_tree);
     612    20029171 :                 if (ret != LDB_SUCCESS) {
     613           0 :                         return ret;
     614             :                 }
     615             :         }
     616             : 
     617    20461820 :         if (!ldb_dn_has_extended(dn)) {
     618             :                 /* Move along there isn't anything to see here */
     619    10739459 :                 if (down_tree == NULL) {
     620    10701118 :                         down_req = req;
     621             :                 } else {
     622       38341 :                         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       38341 :                         if (ret != LDB_SUCCESS) {
     632           0 :                                 return ret;
     633             :                         }
     634       38341 :                         LDB_REQ_SET_LOCATION(down_req);
     635             :                 }
     636             : 
     637    10739459 :                 return ldb_next_request(module, down_req);
     638             :         } else {
     639             :                 /* It looks like we need to map the DN */
     640      469769 :                 const struct ldb_val *sid_val, *guid_val, *wkguid_val;
     641             : 
     642     9722361 :                 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     9722361 :                 sid_val = ldb_dn_get_extended_component(dn, "SID");
     648     9722361 :                 guid_val = ldb_dn_get_extended_component(dn, "GUID");
     649     9722361 :                 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     9722361 :                 if (guid_val) {
     657     7400239 :                         dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
     658     7400239 :                         base_dn = NULL;
     659     7400239 :                         base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
     660             :                                                          ldb_binary_encode(req, *guid_val));
     661     7400239 :                         if (!base_dn_filter) {
     662           0 :                                 return ldb_oom(ldb_module_get_ctx(module));
     663             :                         }
     664     7057061 :                         base_dn_scope = LDB_SCOPE_SUBTREE;
     665     7057061 :                         base_dn_attrs = no_attr;
     666             : 
     667     2322122 :                 } else if (sid_val) {
     668     1389782 :                         dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
     669     1389782 :                         base_dn = NULL;
     670     1389782 :                         base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
     671             :                                                          ldb_binary_encode(req, *sid_val));
     672     1389782 :                         if (!base_dn_filter) {
     673           0 :                                 return ldb_oom(ldb_module_get_ctx(module));
     674             :                         }
     675     1340358 :                         base_dn_scope = LDB_SCOPE_SUBTREE;
     676     1340358 :                         base_dn_attrs = no_attr;
     677             : 
     678      932340 :                 } else if (wkguid_val) {
     679       77167 :                         char *wkguid_dup;
     680       77167 :                         char *tail_str;
     681       77167 :                         char *p;
     682             : 
     683      932340 :                         wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
     684             : 
     685      932340 :                         p = strchr(wkguid_dup, ',');
     686      932340 :                         if (!p) {
     687           0 :                                 return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
     688             :                                                  "Invalid WKGUID format");
     689             :                         }
     690             : 
     691      932340 :                         p[0] = '\0';
     692      932340 :                         p++;
     693             : 
     694      932340 :                         wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
     695      932340 :                         if (!wellknown_object) {
     696           0 :                                 return ldb_oom(ldb_module_get_ctx(module));
     697             :                         }
     698             : 
     699      932340 :                         tail_str = p;
     700             : 
     701      932340 :                         base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
     702      932340 :                         talloc_free(wkguid_dup);
     703      932340 :                         if (!base_dn) {
     704           0 :                                 return ldb_oom(ldb_module_get_ctx(module));
     705             :                         }
     706      932340 :                         base_dn_filter = talloc_strdup(req, "(objectClass=*)");
     707      932340 :                         if (!base_dn_filter) {
     708           0 :                                 return ldb_oom(ldb_module_get_ctx(module));
     709             :                         }
     710      855173 :                         base_dn_scope = LDB_SCOPE_BASE;
     711      855173 :                         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     9722361 :                 ac = talloc_zero(req, struct extended_search_context);
     718     9722361 :                 if (ac == NULL) {
     719           0 :                         return ldb_oom(ldb_module_get_ctx(module));
     720             :                 }
     721             :                 
     722     9722361 :                 ac->module = module;
     723     9722361 :                 ac->req = req;
     724     9722361 :                 ac->tree = (down_tree != NULL) ? down_tree : req->op.search.tree;
     725     9722361 :                 ac->dn = dn;
     726     9722361 :                 ac->basedn = NULL;  /* Filled in if the search finds the DN by SID/GUID etc */
     727     9722361 :                 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     9722361 :                 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     9722361 :                 LDB_REQ_SET_LOCATION(down_req);
     742     9722361 :                 if (ret != LDB_SUCCESS) {
     743           0 :                         return ldb_operr(ldb_module_get_ctx(module));
     744             :                 }
     745             : 
     746     9722361 :                 ret = dsdb_request_add_controls(down_req, dsdb_flags);
     747     9722361 :                 if (ret != LDB_SUCCESS) {
     748           0 :                         return ret;
     749             :                 }
     750             : 
     751             :                 /* perform the search */
     752     9722361 :                 return ldb_next_request(module, down_req);
     753             :         }
     754             : }
     755             : 
     756    20029171 : static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
     757             : {
     758    20029171 :         return extended_dn_in_fix(module, req, req->op.search.base);
     759             : }
     760             : 
     761      321147 : static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
     762             : {
     763      321147 :         return extended_dn_in_fix(module, req, req->op.mod.message->dn);
     764             : }
     765             : 
     766      110222 : static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
     767             : {
     768      110222 :         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        5922 : int ldb_extended_dn_in_module_init(const char *version)
     793             : {
     794         393 :         int ret;
     795        5922 :         LDB_MODULE_CHECK_VERSION(version);
     796        5922 :         ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
     797        5922 :         if (ret != LDB_SUCCESS) {
     798           0 :                 return ret;
     799             :         }
     800        5922 :         return ldb_register_module(&ldb_extended_dn_in_module_ops);
     801             : }

Generated by: LCOV version 1.14