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

Generated by: LCOV version 1.13