LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - acl_read.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 452 530 85.3 %
Date: 2024-04-13 12:30:31 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /*
       2             :   ldb database library
       3             : 
       4             :   Copyright (C) Simo Sorce 2006-2008
       5             :   Copyright (C) Nadezhda Ivanova 2010
       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 ACL Read module
      25             :  *
      26             :  *  Description: Module that performs authorisation access checks on read requests
      27             :  *               Only DACL checks implemented at this point
      28             :  *
      29             :  *  Author: Nadezhda Ivanova
      30             :  */
      31             : 
      32             : #include "includes.h"
      33             : #include "ldb_module.h"
      34             : #include "auth/auth.h"
      35             : #include "libcli/security/security.h"
      36             : #include "dsdb/samdb/samdb.h"
      37             : #include "librpc/gen_ndr/ndr_security.h"
      38             : #include "param/param.h"
      39             : #include "dsdb/samdb/ldb_modules/util.h"
      40             : #include "lib/util/binsearch.h"
      41             : 
      42             : #undef strcasecmp
      43             : 
      44             : struct ldb_attr_vec {
      45             :         const char** attrs;
      46             :         size_t len;
      47             :         size_t capacity;
      48             : };
      49             : 
      50             : struct aclread_context {
      51             :         struct ldb_module *module;
      52             :         struct ldb_request *req;
      53             :         const struct dsdb_schema *schema;
      54             :         uint32_t sd_flags;
      55             :         bool added_nTSecurityDescriptor;
      56             :         bool added_instanceType;
      57             :         bool added_objectSid;
      58             :         bool added_objectClass;
      59             : 
      60             :         bool do_list_object_initialized;
      61             :         bool do_list_object;
      62             :         bool base_invisible;
      63             :         uint64_t num_entries;
      64             : 
      65             :         /* cache on the last parent we checked in this search */
      66             :         struct ldb_dn *last_parent_dn;
      67             :         int last_parent_check_ret;
      68             : 
      69             :         bool am_administrator;
      70             : 
      71             :         bool got_tree_attrs;
      72             :         struct ldb_attr_vec tree_attrs;
      73             : };
      74             : 
      75             : struct aclread_private {
      76             :         bool enabled;
      77             : 
      78             :         /* cache of the last SD we read during any search */
      79             :         struct security_descriptor *sd_cached;
      80             :         struct ldb_val sd_cached_blob;
      81             :         const char **password_attrs;
      82             :         size_t num_password_attrs;
      83             : };
      84             : 
      85             : struct access_check_context {
      86             :         struct security_descriptor *sd;
      87             :         struct dom_sid sid_buf;
      88             :         const struct dom_sid *sid;
      89             :         const struct dsdb_class *objectclass;
      90             : };
      91             : 
      92     3012794 : static void acl_element_mark_access_checked(struct ldb_message_element *el)
      93             : {
      94     3012794 :         el->flags |= LDB_FLAG_INTERNAL_ACCESS_CHECKED;
      95     3012794 : }
      96             : 
      97     5080264 : static bool acl_element_is_access_checked(const struct ldb_message_element *el)
      98             : {
      99     5080264 :         return (el->flags & LDB_FLAG_INTERNAL_ACCESS_CHECKED) != 0;
     100             : }
     101             : 
     102    80084638 : static bool attr_in_vec(const struct ldb_attr_vec *vec, const char *attr)
     103             : {
     104    80084638 :         const char **found = NULL;
     105             : 
     106    80084638 :         if (vec == NULL) {
     107           0 :                 return false;
     108             :         }
     109             : 
     110   147370372 :         BINARY_ARRAY_SEARCH_V(vec->attrs,
     111             :                               vec->len,
     112             :                               attr,
     113             :                               ldb_attr_cmp,
     114             :                               found);
     115    80084638 :         return found != NULL;
     116             : }
     117             : 
     118      215108 : static int acl_attr_cmp_fn(const char *a, const char **b)
     119             : {
     120      215108 :         return ldb_attr_cmp(a, *b);
     121             : }
     122             : 
     123      288618 : static int attr_vec_add_unique(TALLOC_CTX *mem_ctx,
     124             :                                struct ldb_attr_vec *vec,
     125             :                                const char *attr)
     126             : {
     127      288618 :         const char **exact = NULL;
     128      288618 :         const char **next = NULL;
     129      288618 :         size_t next_idx = 0;
     130             : 
     131      503726 :         BINARY_ARRAY_SEARCH_GTE(vec->attrs,
     132             :                                 vec->len,
     133             :                                 attr,
     134             :                                 acl_attr_cmp_fn,
     135             :                                 exact,
     136             :                                 next);
     137      288604 :         if (exact != NULL) {
     138       70112 :                 return LDB_SUCCESS;
     139             :         }
     140             : 
     141      218506 :         if (vec->len == SIZE_MAX) {
     142           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     143             :         }
     144             : 
     145      218506 :         if (next != NULL) {
     146       65827 :                 next_idx = next - vec->attrs;
     147             :         }
     148             : 
     149      218506 :         if (vec->len >= vec->capacity) {
     150      149061 :                 const char **attrs = NULL;
     151             : 
     152      149061 :                 if (vec->capacity == 0) {
     153      137208 :                         vec->capacity = 4;
     154             :                 } else {
     155       11853 :                         if (vec->capacity > SIZE_MAX / 2) {
     156           0 :                                 return LDB_ERR_OPERATIONS_ERROR;
     157             :                         }
     158       11853 :                         vec->capacity *= 2;
     159             :                 }
     160             : 
     161      149061 :                 attrs = talloc_realloc(mem_ctx, vec->attrs, const char *, vec->capacity);
     162      149061 :                 if (attrs == NULL) {
     163           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     164             :                 }
     165             : 
     166      149061 :                 vec->attrs = attrs;
     167             :         }
     168      218506 :         SMB_ASSERT(vec->len < vec->capacity);
     169             : 
     170      218506 :         if (next == NULL) {
     171      152679 :                 vec->attrs[vec->len++] = attr;
     172             :         } else {
     173       65827 :                 size_t count = (vec->len - next_idx) * sizeof (vec->attrs[0]);
     174       65827 :                 memmove(&vec->attrs[next_idx + 1],
     175       65827 :                         &vec->attrs[next_idx],
     176             :                         count);
     177             : 
     178       65827 :                 vec->attrs[next_idx] = attr;
     179       65827 :                 ++vec->len;
     180             :         }
     181             : 
     182      218492 :         return LDB_SUCCESS;
     183             : }
     184             : 
     185     1271787 : static bool ldb_attr_always_present(const char *attr)
     186             : {
     187         510 :         static const char * const attrs_always_present[] = {
     188             :                 "objectClass",
     189             :                 "distinguishedName",
     190             :                 "name",
     191             :                 "objectGUID",
     192             :                 NULL
     193             :         };
     194             : 
     195     1271787 :         return ldb_attr_in_list(attrs_always_present, attr);
     196             : }
     197             : 
     198      975699 : static bool ldb_attr_always_visible(const char *attr)
     199             : {
     200         282 :         static const char * const attrs_always_visible[] = {
     201             :                 "isDeleted",
     202             :                 "isRecycled",
     203             :                 NULL
     204             :         };
     205             : 
     206      975699 :         return ldb_attr_in_list(attrs_always_visible, attr);
     207             : }
     208             : 
     209             : /* Collect a list of attributes required to match a given parse tree. */
     210     4463342 : static int ldb_parse_tree_collect_acl_attrs(const struct ldb_module *module,
     211             :                                             TALLOC_CTX *mem_ctx,
     212             :                                             struct ldb_attr_vec *attrs,
     213             :                                             const struct ldb_parse_tree *tree)
     214             : {
     215     4463610 :         const char *attr = NULL;
     216        1580 :         unsigned int i;
     217        1580 :         int ret;
     218             : 
     219     4463610 :         if (tree == NULL) {
     220           0 :                 return 0;
     221             :         }
     222             : 
     223     4463610 :         switch (tree->operation) {
     224     1439063 :         case LDB_OP_OR:
     225             :         case LDB_OP_AND:                /* attributes stored in list of subtrees */
     226     4383991 :                 for (i = 0; i < tree->u.list.num_elements; i++) {
     227     2945450 :                         ret = ldb_parse_tree_collect_acl_attrs(module, mem_ctx,
     228     2944406 :                                                                attrs, tree->u.list.elements[i]);
     229     2944406 :                         if (ret) {
     230           0 :                                 return ret;
     231             :                         }
     232             :                 }
     233     1439063 :                 return 0;
     234             : 
     235      751986 :         case LDB_OP_NOT:                /* attributes stored in single subtree */
     236      751986 :                 return ldb_parse_tree_collect_acl_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
     237             : 
     238     1271787 :         case LDB_OP_PRESENT:
     239             :                 /*
     240             :                  * If the search filter is checking for an attribute's presence,
     241             :                  * and the attribute is always present, we can skip access
     242             :                  * rights checks. Every object has these attributes, and so
     243             :                  * there's no security reason to hide their presence.
     244             :                  * Note: the acl.py tests (e.g. test_search1()) rely on this
     245             :                  * exception.  I.e. even if we lack Read Property (RP) rights
     246             :                  * for a child object, it should still appear as a visible
     247             :                  * object in 'objectClass=*' searches, so long as we have List
     248             :                  * Contents (LC) rights for the object.
     249             :                  */
     250     1271787 :                 if (ldb_attr_always_present(tree->u.present.attr)) {
     251             :                         /* No need to check this attribute. */
     252     1256407 :                         return 0;
     253             :                 }
     254             : 
     255       14872 :                 if (ldb_attr_always_visible(tree->u.present.attr)) {
     256             :                         /* No need to check this attribute. */
     257        1308 :                         return 0;
     258             :                 }
     259             : 
     260       13562 :                 break;
     261             : 
     262      960827 :         case LDB_OP_EQUALITY:
     263      960827 :                 if (ldb_attr_always_visible(tree->u.equality.attr)) {
     264             :                         /* No need to check this attribute. */
     265      724930 :                         return 0;
     266             :                 }
     267             : 
     268      235617 :                 break;
     269             : 
     270       39425 :         default:                        /* single attribute in tree */
     271       39425 :                 break;
     272             :         }
     273             : 
     274      288618 :         attr = ldb_parse_tree_get_attr(tree);
     275      288618 :         return attr_vec_add_unique(mem_ctx, attrs, attr);
     276             : }
     277             : 
     278             : /*
     279             :  * the object has a parent, so we have to check for visibility
     280             :  *
     281             :  * This helper function uses a per-search cache to avoid checking the
     282             :  * parent object for each of many possible children.  This is likely
     283             :  * to help on SCOPE_ONE searches and on typical tree structures for
     284             :  * SCOPE_SUBTREE, where an OU has many users as children.
     285             :  *
     286             :  * We rely for safety on the DB being locked for reads during the full
     287             :  * search.
     288             :  */
     289     2176617 : static int aclread_check_parent(struct aclread_context *ac,
     290             :                                 struct ldb_message *msg,
     291             :                                 struct ldb_request *req)
     292             : {
     293         520 :         int ret;
     294     2176617 :         struct ldb_dn *parent_dn = NULL;
     295             : 
     296             :         /* We may have a cached result from earlier in this search */
     297     2176617 :         if (ac->last_parent_dn != NULL) {
     298             :                 /*
     299             :                  * We try the no-allocation ldb_dn_compare_base()
     300             :                  * first however it will not tell parents and
     301             :                  * grand-parents apart
     302             :                  */
     303     1422376 :                 int cmp_base = ldb_dn_compare_base(ac->last_parent_dn,
     304             :                                                    msg->dn);
     305     1422376 :                 if (cmp_base == 0) {
     306             :                         /* Now check if it is a direct parent */
     307     1342692 :                         parent_dn = ldb_dn_get_parent(ac, msg->dn);
     308     1342692 :                         if (parent_dn == NULL) {
     309           0 :                                 return ldb_oom(ldb_module_get_ctx(ac->module));
     310             :                         }
     311     1342692 :                         if (ldb_dn_compare(ac->last_parent_dn,
     312             :                                            parent_dn) == 0) {
     313     1271988 :                                 TALLOC_FREE(parent_dn);
     314             : 
     315             :                                 /*
     316             :                                  * If we checked the same parent last
     317             :                                  * time, then return the cached
     318             :                                  * result.
     319             :                                  *
     320             :                                  * The cache is valid as long as the
     321             :                                  * search as the DB is read locked and
     322             :                                  * the session_info (connected user)
     323             :                                  * is constant.
     324             :                                  */
     325     1271988 :                                 return ac->last_parent_check_ret;
     326             :                         }
     327             :                 }
     328             :         }
     329             : 
     330             :         {
     331      904629 :                 TALLOC_CTX *frame = NULL;
     332      904629 :                 frame = talloc_stackframe();
     333             : 
     334             :                 /*
     335             :                  * This may have been set in the block above, don't
     336             :                  * re-parse
     337             :                  */
     338      904629 :                 if (parent_dn == NULL) {
     339      833925 :                         parent_dn = ldb_dn_get_parent(ac, msg->dn);
     340      833925 :                         if (parent_dn == NULL) {
     341           0 :                                 TALLOC_FREE(frame);
     342           0 :                                 return ldb_oom(ldb_module_get_ctx(ac->module));
     343             :                         }
     344             :                 }
     345      904629 :                 ret = dsdb_module_check_access_on_dn(ac->module,
     346             :                                                      frame,
     347             :                                                      parent_dn,
     348             :                                                      SEC_ADS_LIST,
     349             :                                                      NULL, req);
     350      904629 :                 talloc_unlink(ac, ac->last_parent_dn);
     351      904629 :                 ac->last_parent_dn = parent_dn;
     352      904629 :                 ac->last_parent_check_ret = ret;
     353             : 
     354      904629 :                 TALLOC_FREE(frame);
     355             :         }
     356      904363 :         return ret;
     357             : }
     358             : 
     359     2270431 : static int aclread_check_object_visible(struct aclread_context *ac,
     360             :                                         struct ldb_message *msg,
     361             :                                         struct ldb_request *req)
     362             : {
     363         536 :         uint32_t instanceType;
     364         536 :         int ret;
     365             : 
     366             :         /* get the object instance type */
     367     2270431 :         instanceType = ldb_msg_find_attr_as_uint(msg,
     368             :                                                  "instanceType", 0);
     369     2270431 :         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
     370             :                 /*
     371             :                  * NC_HEAD objects are always visible
     372             :                  */
     373       93798 :                 return LDB_SUCCESS;
     374             :         }
     375             : 
     376     2176617 :         ret = aclread_check_parent(ac, msg, req);
     377     2176617 :         if (ret == LDB_SUCCESS) {
     378             :                 /*
     379             :                  * SEC_ADS_LIST (List Children) alone
     380             :                  * on the parent is enough to make the
     381             :                  * object visible.
     382             :                  */
     383     2135065 :                 return LDB_SUCCESS;
     384             :         }
     385       41032 :         if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     386           0 :                 return ret;
     387             :         }
     388             : 
     389       41032 :         if (!ac->do_list_object_initialized) {
     390             :                 /*
     391             :                  * We only call dsdb_do_list_object() once
     392             :                  * and only when needed in order to
     393             :                  * check the dSHeuristics for fDoListObject.
     394             :                  */
     395       16280 :                 ac->do_list_object = dsdb_do_list_object(ac->module, ac, req);
     396       16280 :                 ac->do_list_object_initialized = true;
     397             :         }
     398             : 
     399       41032 :         if (ac->do_list_object) {
     400       12672 :                 TALLOC_CTX *frame = talloc_stackframe();
     401       12672 :                 struct ldb_dn *parent_dn = NULL;
     402             : 
     403             :                 /*
     404             :                  * Here we're in "List Object" mode (fDoListObject=true).
     405             :                  *
     406             :                  * If SEC_ADS_LIST (List Children) is not
     407             :                  * granted on the parent, we need to check if
     408             :                  * SEC_ADS_LIST_OBJECT (List Object) is granted
     409             :                  * on the parent and also on the object itself.
     410             :                  *
     411             :                  * We could optimize this similar to aclread_check_parent(),
     412             :                  * but that would require quite a bit of restructuring,
     413             :                  * so that we cache the granted access bits instead
     414             :                  * of just the result for 'SEC_ADS_LIST (List Children)'.
     415             :                  *
     416             :                  * But as this is the uncommon case and
     417             :                  * 'SEC_ADS_LIST (List Children)' is most likely granted
     418             :                  * on most of the objects, we'll just implement what
     419             :                  * we have to.
     420             :                  */
     421             : 
     422       12672 :                 parent_dn = ldb_dn_get_parent(frame, msg->dn);
     423       12672 :                 if (parent_dn == NULL) {
     424           0 :                         TALLOC_FREE(frame);
     425           0 :                         return ldb_oom(ldb_module_get_ctx(ac->module));
     426             :                 }
     427       12672 :                 ret = dsdb_module_check_access_on_dn(ac->module,
     428             :                                                      frame,
     429             :                                                      parent_dn,
     430             :                                                      SEC_ADS_LIST_OBJECT,
     431             :                                                      NULL, req);
     432       12672 :                 if (ret != LDB_SUCCESS) {
     433        6048 :                         TALLOC_FREE(frame);
     434        6048 :                         return ret;
     435             :                 }
     436        6624 :                 ret = dsdb_module_check_access_on_dn(ac->module,
     437             :                                                      frame,
     438             :                                                      msg->dn,
     439             :                                                      SEC_ADS_LIST_OBJECT,
     440             :                                                      NULL, req);
     441        6624 :                 if (ret != LDB_SUCCESS) {
     442        1872 :                         TALLOC_FREE(frame);
     443        1872 :                         return ret;
     444             :                 }
     445             : 
     446        4752 :                 TALLOC_FREE(frame);
     447        4752 :                 return LDB_SUCCESS;
     448             :         }
     449             : 
     450       28360 :         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
     451             : }
     452             : 
     453             : /*
     454             :  * The sd returned from this function is valid until the next call on
     455             :  * this module context
     456             :  *
     457             :  * This helper function uses a cache on the module private data to
     458             :  * speed up repeated use of the same SD.
     459             :  */
     460             : 
     461     3631643 : static int aclread_get_sd_from_ldb_message(struct aclread_context *ac,
     462             :                                            const struct ldb_message *acl_res,
     463             :                                            struct security_descriptor **sd)
     464             : {
     465         172 :         struct ldb_message_element *sd_element;
     466     3631643 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     467         172 :         struct aclread_private *private_data
     468     3631643 :                 = talloc_get_type_abort(ldb_module_get_private(ac->module),
     469             :                                   struct aclread_private);
     470         172 :         enum ndr_err_code ndr_err;
     471             : 
     472     3631643 :         sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor");
     473     3631643 :         if (sd_element == NULL) {
     474           0 :                 return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS,
     475             :                                  "nTSecurityDescriptor is missing");
     476             :         }
     477             : 
     478     3631643 :         if (sd_element->num_values != 1) {
     479           0 :                 return ldb_operr(ldb);
     480             :         }
     481             : 
     482             :         /*
     483             :          * The time spent in ndr_pull_security_descriptor() is quite
     484             :          * expensive, so we check if this is the same binary blob as last
     485             :          * time, and if so return the memory tree from that previous parse.
     486             :          */
     487             : 
     488     3631643 :         if (private_data->sd_cached != NULL &&
     489     7220680 :             private_data->sd_cached_blob.data != NULL &&
     490     3610340 :             ldb_val_equal_exact(&sd_element->values[0],
     491     3610340 :                                 &private_data->sd_cached_blob)) {
     492     2448655 :                 *sd = private_data->sd_cached;
     493     2448655 :                 return LDB_SUCCESS;
     494             :         }
     495             : 
     496     1182988 :         *sd = talloc(private_data, struct security_descriptor);
     497     1182988 :         if(!*sd) {
     498           0 :                 return ldb_oom(ldb);
     499             :         }
     500     1182988 :         ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, *sd,
     501             :                              (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
     502             : 
     503     1182988 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     504           0 :                 TALLOC_FREE(*sd);
     505           0 :                 return ldb_operr(ldb);
     506             :         }
     507             : 
     508     1182988 :         talloc_unlink(private_data, private_data->sd_cached_blob.data);
     509     1182988 :         private_data->sd_cached_blob = ldb_val_dup(private_data,
     510     1182988 :                                                    &sd_element->values[0]);
     511     1182988 :         if (private_data->sd_cached_blob.data == NULL) {
     512           0 :                 TALLOC_FREE(*sd);
     513           0 :                 return ldb_operr(ldb);
     514             :         }
     515             : 
     516     1182988 :         talloc_unlink(private_data, private_data->sd_cached);
     517     1182988 :         private_data->sd_cached = *sd;
     518             : 
     519     1182988 :         return LDB_SUCCESS;
     520             : }
     521             : 
     522             : /* Check whether the attribute is a password attribute. */
     523     6750062 : static bool attr_is_secret(const char *attr, const struct aclread_private *private_data)
     524             : {
     525     6750062 :         const char **found = NULL;
     526             : 
     527     6750062 :         if (private_data->password_attrs == NULL) {
     528           0 :                 return false;
     529             :         }
     530             : 
     531    36214011 :         BINARY_ARRAY_SEARCH_V(private_data->password_attrs,
     532             :                               private_data->num_password_attrs,
     533             :                               attr,
     534             :                               ldb_attr_cmp,
     535             :                               found);
     536     6750062 :         return found != NULL;
     537             : }
     538             : 
     539             : /*
     540             :  * Returns the access mask required to read a given attribute
     541             :  */
     542     6748833 : static uint32_t get_attr_access_mask(const struct dsdb_attribute *attr,
     543             :                                      uint32_t sd_flags)
     544             : {
     545             : 
     546     6748833 :         uint32_t access_mask = 0;
     547         307 :         bool is_sd;
     548             : 
     549             :         /* nTSecurityDescriptor is a special case */
     550     6748833 :         is_sd = (ldb_attr_cmp("nTSecurityDescriptor",
     551             :                               attr->lDAPDisplayName) == 0);
     552             : 
     553     6748833 :         if (is_sd) {
     554       24311 :                 if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
     555       23200 :                         access_mask |= SEC_STD_READ_CONTROL;
     556             :                 }
     557       24311 :                 if (sd_flags & SECINFO_DACL) {
     558       24284 :                         access_mask |= SEC_STD_READ_CONTROL;
     559             :                 }
     560       24311 :                 if (sd_flags & SECINFO_SACL) {
     561       22643 :                         access_mask |= SEC_FLAG_SYSTEM_SECURITY;
     562             :                 }
     563             :         } else {
     564     6724215 :                 access_mask = SEC_ADS_READ_PROP;
     565             :         }
     566             : 
     567     6748833 :         if (attr->searchFlags & SEARCH_FLAG_CONFIDENTIAL) {
     568        5324 :                 access_mask |= SEC_ADS_CONTROL_ACCESS;
     569             :         }
     570             : 
     571     6748833 :         return access_mask;
     572             : }
     573             : 
     574             : /*
     575             :  * Checks that the user has sufficient access rights to view an attribute, else
     576             :  * marks it as inaccessible.
     577             :  */
     578     6750062 : static int acl_redact_attr(TALLOC_CTX *mem_ctx,
     579             :                            struct ldb_message_element *el,
     580             :                            struct aclread_context *ac,
     581             :                            const struct aclread_private *private_data,
     582             :                            const struct ldb_message *msg,
     583             :                            const struct dsdb_schema *schema,
     584             :                            const struct security_descriptor *sd,
     585             :                            const struct dom_sid *sid,
     586             :                            const struct dsdb_class *objectclass)
     587             : {
     588         307 :         int ret;
     589     6750062 :         const struct dsdb_attribute *attr = NULL;
     590         307 :         uint32_t access_mask;
     591     6750062 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     592             : 
     593     6750062 :         if (attr_is_secret(el->name, private_data)) {
     594        1229 :                 ldb_msg_element_mark_inaccessible(el);
     595        1229 :                 return LDB_SUCCESS;
     596             :         }
     597             : 
     598             :         /* Look up the attribute in the schema. */
     599     6748833 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
     600     6748833 :         if (!attr) {
     601           0 :                 ldb_debug_set(ldb,
     602             :                               LDB_DEBUG_FATAL,
     603             :                               "acl_read: %s cannot find attr[%s] in schema\n",
     604           0 :                               ldb_dn_get_linearized(msg->dn), el->name);
     605           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     606             :         }
     607             : 
     608     6748833 :         access_mask = get_attr_access_mask(attr, ac->sd_flags);
     609     6748833 :         if (access_mask == 0) {
     610           0 :                 DBG_ERR("Could not determine access mask for attribute %s\n",
     611             :                         el->name);
     612           0 :                 ldb_msg_element_mark_inaccessible(el);
     613           0 :                 return LDB_SUCCESS;
     614             :         }
     615             : 
     616             :         /* We must check whether the user has rights to view the attribute. */
     617             : 
     618     6748833 :         ret = acl_check_access_on_attribute_implicit_owner(ac->module, mem_ctx, sd, sid,
     619             :                                                            access_mask, attr, objectclass,
     620             :                                                            IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
     621     6748833 :         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     622       30062 :                 ldb_msg_element_mark_inaccessible(el);
     623     6718771 :         } else if (ret != LDB_SUCCESS) {
     624           0 :                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
     625             :                               "acl_read: %s check attr[%s] gives %s - %s\n",
     626           0 :                               ldb_dn_get_linearized(msg->dn), el->name,
     627             :                               ldb_strerror(ret), ldb_errstring(ldb));
     628           0 :                 return ret;
     629             :         }
     630             : 
     631     6748526 :         return LDB_SUCCESS;
     632             : }
     633             : 
     634     3631643 : static int setup_access_check_context(struct aclread_context *ac,
     635             :                                       const struct ldb_message *msg,
     636             :                                       struct access_check_context *ctx)
     637             : {
     638         172 :         int ret;
     639             : 
     640             :         /*
     641             :          * Fetch the schema so we can check which attributes are
     642             :          * considered confidential.
     643             :          */
     644     3631643 :         if (ac->schema == NULL) {
     645      583335 :                 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     646             : 
     647             :                 /* Cache the schema for later use. */
     648      583335 :                 ac->schema = dsdb_get_schema(ldb, ac);
     649             : 
     650      583335 :                 if (ac->schema == NULL) {
     651           0 :                         return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
     652             :                                          "aclread_callback: Error obtaining schema.");
     653             :                 }
     654             :         }
     655             : 
     656             :         /* Fetch the object's security descriptor. */
     657     3631643 :         ret = aclread_get_sd_from_ldb_message(ac, msg, &ctx->sd);
     658     3631643 :         if (ret != LDB_SUCCESS) {
     659           0 :                 ldb_debug_set(ldb_module_get_ctx(ac->module), LDB_DEBUG_FATAL,
     660             :                               "acl_read: cannot get descriptor of %s: %s\n",
     661           0 :                               ldb_dn_get_linearized(msg->dn), ldb_strerror(ret));
     662           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     663     3631643 :         } else if (ctx->sd == NULL) {
     664           0 :                 ldb_debug_set(ldb_module_get_ctx(ac->module), LDB_DEBUG_FATAL,
     665             :                               "acl_read: cannot get descriptor of %s (attribute not found)\n",
     666           0 :                               ldb_dn_get_linearized(msg->dn));
     667           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     668             :         }
     669             :         /*
     670             :          * Get the most specific structural object class for the ACL check
     671             :          */
     672     3631643 :         ctx->objectclass = dsdb_get_structural_oc_from_msg(ac->schema, msg);
     673     3631643 :         if (ctx->objectclass == NULL) {
     674           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
     675             :                                        "acl_read: Failed to find a structural class for %s",
     676           0 :                                        ldb_dn_get_linearized(msg->dn));
     677           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     678             :         }
     679             : 
     680             :         /* Fetch the object's SID. */
     681     3631643 :         ret = samdb_result_dom_sid_buf(msg, "objectSid", &ctx->sid_buf);
     682     3631643 :         if (ret == LDB_SUCCESS) {
     683     3041100 :                 ctx->sid = &ctx->sid_buf;
     684      590543 :         } else if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     685             :                 /* This is expected. */
     686      590543 :                 ctx->sid = NULL;
     687             :         } else {
     688           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
     689             :                                        "acl_read: Failed to parse objectSid as dom_sid for %s",
     690           0 :                                        ldb_dn_get_linearized(msg->dn));
     691           0 :                 return ret;
     692             :         }
     693             : 
     694     3631471 :         return LDB_SUCCESS;
     695             : }
     696             : 
     697             : /*
     698             :  * Whether this attribute was added to perform access checks and must be
     699             :  * removed.
     700             :  */
     701    10091845 : static bool should_remove_attr(const char *attr, const struct aclread_context *ac)
     702             : {
     703    10091845 :         if (ac->added_nTSecurityDescriptor &&
     704     9811722 :             ldb_attr_cmp("nTSecurityDescriptor", attr) == 0)
     705             :         {
     706     1439918 :                 return true;
     707             :         }
     708             : 
     709     8651659 :         if (ac->added_objectSid &&
     710     6106677 :             ldb_attr_cmp("objectSid", attr) == 0)
     711             :         {
     712      853906 :                 return true;
     713             :         }
     714             : 
     715     7797669 :         if (ac->added_instanceType &&
     716     5502253 :             ldb_attr_cmp("instanceType", attr) == 0)
     717             :         {
     718     1358952 :                 return true;
     719             :         }
     720             : 
     721     6438451 :         if (ac->added_objectClass &&
     722     4132755 :             ldb_attr_cmp("objectClass", attr) == 0)
     723             :         {
     724     1358187 :                 return true;
     725             :         }
     726             : 
     727     5079955 :         return false;
     728             : }
     729             : 
     730     2402754 : static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
     731             : {
     732         572 :         struct aclread_context *ac;
     733     2402754 :         struct aclread_private *private_data = NULL;
     734         572 :         struct ldb_message *msg;
     735         572 :         int ret;
     736         572 :         unsigned int i;
     737         572 :         struct access_check_context acl_ctx;
     738             : 
     739     2402754 :         ac = talloc_get_type_abort(req->context, struct aclread_context);
     740     2402754 :         if (!ares) {
     741           0 :                 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR );
     742             :         }
     743     2402754 :         if (ares->error != LDB_SUCCESS) {
     744           8 :                 return ldb_module_done(ac->req, ares->controls,
     745             :                                        ares->response, ares->error);
     746             :         }
     747     2402746 :         switch (ares->type) {
     748     1492128 :         case LDB_REPLY_ENTRY:
     749     1492128 :                 msg = ares->message;
     750             : 
     751     1492128 :                 if (!ldb_dn_is_null(msg->dn)) {
     752             :                         /*
     753             :                          * this is a real object, so we have
     754             :                          * to check for visibility
     755             :                          */
     756     1492128 :                         ret = aclread_check_object_visible(ac, msg, req);
     757     1492128 :                         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     758       27631 :                                 return LDB_SUCCESS;
     759     1464497 :                         } else if (ret != LDB_SUCCESS) {
     760           0 :                                 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     761           0 :                                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
     762             :                                               "acl_read: %s check parent %s - %s\n",
     763             :                                               ldb_dn_get_linearized(msg->dn),
     764             :                                               ldb_strerror(ret),
     765             :                                               ldb_errstring(ldb));
     766           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
     767             :                         }
     768             :                 }
     769             : 
     770             :                 /* for every element in the message check RP */
     771     5303372 :                 for (i = 0; i < msg->num_elements; ++i) {
     772     5021869 :                         struct ldb_message_element *el = &msg->elements[i];
     773             : 
     774             :                         /* Remove attributes added to perform access checks. */
     775     5021869 :                         if (should_remove_attr(el->name, ac)) {
     776     3793917 :                                 ldb_msg_element_mark_inaccessible(el);
     777     3793917 :                                 continue;
     778             :                         }
     779             : 
     780     1227952 :                         if (acl_element_is_access_checked(el)) {
     781             :                                 /* We will have already checked this attribute. */
     782       44958 :                                 continue;
     783             :                         }
     784             : 
     785             :                         /*
     786             :                          * We need to fetch the security descriptor to check
     787             :                          * this attribute.
     788             :                          */
     789     1182908 :                         break;
     790             :                 }
     791             : 
     792     1464497 :                 if (i == msg->num_elements) {
     793             :                         /* All elements have been checked. */
     794      281503 :                         goto reply_entry_done;
     795             :                 }
     796             : 
     797     1182994 :                 ret = setup_access_check_context(ac, msg, &acl_ctx);
     798     1182994 :                 if (ret != LDB_SUCCESS) {
     799           0 :                         return ret;
     800             :                 }
     801             : 
     802     1182994 :                 private_data = talloc_get_type_abort(ldb_module_get_private(ac->module),
     803             :                                                      struct aclread_private);
     804             : 
     805     6253056 :                 for (/* begin where we left off */; i < msg->num_elements; ++i) {
     806     5069976 :                         struct ldb_message_element *el = &msg->elements[i];
     807             : 
     808             :                         /* Remove attributes added to perform access checks. */
     809     5069976 :                         if (should_remove_attr(el->name, ac)) {
     810     1217664 :                                 ldb_msg_element_mark_inaccessible(el);
     811     1217664 :                                 continue;
     812             :                         }
     813             : 
     814     3852312 :                         if (acl_element_is_access_checked(el)) {
     815             :                                 /* We will have already checked this attribute. */
     816      115044 :                                 continue;
     817             :                         }
     818             : 
     819             :                         /*
     820             :                          * We need to check whether the attribute is secret,
     821             :                          * confidential, or access-controlled.
     822             :                          */
     823     3737489 :                         ret = acl_redact_attr(ac,
     824             :                                               el,
     825             :                                               ac,
     826             :                                               private_data,
     827             :                                               msg,
     828             :                                               ac->schema,
     829     3737268 :                                               acl_ctx.sd,
     830             :                                               acl_ctx.sid,
     831             :                                               acl_ctx.objectclass);
     832     3737268 :                         if (ret != LDB_SUCCESS) {
     833           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
     834             :                         }
     835             :                 }
     836             : 
     837     1182994 :         reply_entry_done:
     838     1464497 :                 ldb_msg_remove_inaccessible(msg);
     839             : 
     840     1464497 :                 ac->num_entries++;
     841     1464497 :                 return ldb_module_send_entry(ac->req, msg, ares->controls);
     842      134956 :         case LDB_REPLY_REFERRAL:
     843      134956 :                 return ldb_module_send_referral(ac->req, ares->referral);
     844      775662 :         case LDB_REPLY_DONE:
     845      775662 :                 if (ac->base_invisible && ac->num_entries == 0) {
     846             :                         /*
     847             :                          * If the base is invisible and we didn't
     848             :                          * returned any object, we need to return
     849             :                          * NO_SUCH_OBJECT.
     850             :                          */
     851        3258 :                         return ldb_module_done(ac->req,
     852             :                                                NULL, NULL,
     853             :                                                LDB_ERR_NO_SUCH_OBJECT);
     854             :                 }
     855      772404 :                 return ldb_module_done(ac->req, ares->controls,
     856             :                                         ares->response, LDB_SUCCESS);
     857             : 
     858             :         }
     859           0 :         return LDB_SUCCESS;
     860             : }
     861             : 
     862             : 
     863    34151878 : static int aclread_search(struct ldb_module *module, struct ldb_request *req)
     864             : {
     865     1948687 :         struct ldb_context *ldb;
     866     1948687 :         int ret;
     867     1948687 :         struct aclread_context *ac;
     868     1948687 :         struct ldb_request *down_req;
     869     1948687 :         bool am_system;
     870     1948687 :         struct ldb_result *res;
     871     1948687 :         struct aclread_private *p;
     872    34151878 :         bool need_sd = false;
     873    34151878 :         bool explicit_sd_flags = false;
     874    34151878 :         bool is_untrusted = ldb_req_is_untrusted(req);
     875     1948687 :         static const char * const _all_attrs[] = { "*", NULL };
     876    34151878 :         bool all_attrs = false;
     877    34151878 :         const char * const *attrs = NULL;
     878     1948687 :         static const char *acl_attrs[] = {
     879             :                 "instanceType",
     880             :                 NULL
     881             :         };
     882             : 
     883    34151878 :         ldb = ldb_module_get_ctx(module);
     884    34151878 :         p = talloc_get_type(ldb_module_get_private(module), struct aclread_private);
     885             : 
     886    34151878 :         am_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID) != NULL;
     887    34151878 :         if (!am_system) {
     888    18299727 :                 am_system = dsdb_module_am_system(module);
     889             :         }
     890             : 
     891             :         /* skip access checks if we are system or system control is supplied
     892             :          * or this is not LDAP server request */
     893    34151878 :         if (!p || !p->enabled ||
     894     7465330 :             am_system ||
     895     7465330 :             !is_untrusted) {
     896    33312084 :                 return ldb_next_request(module, req);
     897             :         }
     898             :         /* no checks on special dn */
     899      839794 :         if (ldb_dn_is_special(req->op.search.base)) {
     900       60963 :                 return ldb_next_request(module, req);
     901             :         }
     902             : 
     903      778831 :         ac = talloc_zero(req, struct aclread_context);
     904      778831 :         if (ac == NULL) {
     905           0 :                 return ldb_oom(ldb);
     906             :         }
     907      778831 :         ac->module = module;
     908      778831 :         ac->req = req;
     909             : 
     910      778831 :         attrs = req->op.search.attrs;
     911      778831 :         if (attrs == NULL) {
     912       69373 :                 all_attrs = true;
     913       69373 :                 attrs = _all_attrs;
     914      709456 :         } else if (ldb_attr_in_list(attrs, "*")) {
     915       17492 :                 all_attrs = true;
     916             :         }
     917             : 
     918             :         /*
     919             :          * In theory we should also check for the SD control but control verification is
     920             :          * expensive so we'd better had the ntsecuritydescriptor to the list of
     921             :          * searched attribute and then remove it !
     922             :          */
     923      778831 :         ac->sd_flags = dsdb_request_sd_flags(ac->req, &explicit_sd_flags);
     924             : 
     925      778831 :         if (ldb_attr_in_list(attrs, "nTSecurityDescriptor")) {
     926       21984 :                 need_sd = false;
     927      756847 :         } else if (explicit_sd_flags && all_attrs) {
     928         306 :                 need_sd = false;
     929             :         } else {
     930      756541 :                 need_sd = true;
     931             :         }
     932             : 
     933      778831 :         if (!all_attrs) {
     934      691964 :                 if (!ldb_attr_in_list(attrs, "instanceType")) {
     935      681262 :                         attrs = ldb_attr_list_copy_add(ac, attrs, "instanceType");
     936      681262 :                         if (attrs == NULL) {
     937           0 :                                 return ldb_oom(ldb);
     938             :                         }
     939      681262 :                         ac->added_instanceType = true;
     940             :                 }
     941      691964 :                 if (!ldb_attr_in_list(req->op.search.attrs, "objectSid")) {
     942      671570 :                         attrs = ldb_attr_list_copy_add(ac, attrs, "objectSid");
     943      671570 :                         if (attrs == NULL) {
     944           0 :                                 return ldb_oom(ldb);
     945             :                         }
     946      671570 :                         ac->added_objectSid = true;
     947             :                 }
     948      691964 :                 if (!ldb_attr_in_list(req->op.search.attrs, "objectClass")) {
     949      680479 :                         attrs = ldb_attr_list_copy_add(ac, attrs, "objectClass");
     950      680479 :                         if (attrs == NULL) {
     951           0 :                                 return ldb_oom(ldb);
     952             :                         }
     953      680479 :                         ac->added_objectClass = true;
     954             :                 }
     955             :         }
     956             : 
     957      778831 :         if (need_sd) {
     958      756541 :                 attrs = ldb_attr_list_copy_add(ac, attrs, "nTSecurityDescriptor");
     959      756541 :                 if (attrs == NULL) {
     960           0 :                         return ldb_oom(ldb);
     961             :                 }
     962      756541 :                 ac->added_nTSecurityDescriptor = true;
     963             :         }
     964             : 
     965      778831 :         ac->am_administrator = dsdb_module_am_administrator(module);
     966             : 
     967             :         /* check accessibility of base */
     968      778831 :         if (!ldb_dn_is_null(req->op.search.base)) {
     969      778565 :                 ret = dsdb_module_search_dn(module, req, &res, req->op.search.base,
     970             :                                             acl_attrs,
     971             :                                             DSDB_FLAG_NEXT_MODULE |
     972             :                                             DSDB_FLAG_AS_SYSTEM |
     973             :                                             DSDB_SEARCH_SHOW_RECYCLED,
     974             :                                             req);
     975      778565 :                 if (ret != LDB_SUCCESS) {
     976         262 :                         return ldb_error(ldb, ret,
     977             :                                         "acl_read: Error retrieving instanceType for base.");
     978             :                 }
     979      778303 :                 ret = aclread_check_object_visible(ac, res->msgs[0], req);
     980      778303 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     981        8649 :                         if (req->op.search.scope == LDB_SCOPE_BASE) {
     982        2889 :                                 return ldb_module_done(req, NULL, NULL,
     983             :                                                        LDB_ERR_NO_SUCH_OBJECT);
     984             :                         }
     985             :                         /*
     986             :                          * Defer LDB_ERR_NO_SUCH_OBJECT,
     987             :                          * we may return sub objects
     988             :                          */
     989        5760 :                         ac->base_invisible = true;
     990      769654 :                 } else if (ret != LDB_SUCCESS) {
     991           0 :                         return ldb_module_done(req, NULL, NULL, ret);
     992             :                 }
     993             :         }
     994             : 
     995      775680 :         ret = ldb_build_search_req_ex(&down_req,
     996             :                                       ldb, ac,
     997             :                                       req->op.search.base,
     998             :                                       req->op.search.scope,
     999             :                                       req->op.search.tree,
    1000             :                                       attrs,
    1001             :                                       req->controls,
    1002             :                                       ac, aclread_callback,
    1003             :                                       req);
    1004             : 
    1005      775680 :         if (ret != LDB_SUCCESS) {
    1006           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1007             :         }
    1008             : 
    1009             :         /*
    1010             :          * We provide 'ac' as the control value, which is then used by the
    1011             :          * callback to avoid double-work.
    1012             :          */
    1013      775680 :         ret = ldb_request_add_control(down_req, DSDB_CONTROL_ACL_READ_OID, false, ac);
    1014      775680 :         if (ret != LDB_SUCCESS) {
    1015           0 :                         return ldb_error(ldb, ret,
    1016             :                                         "acl_read: Error adding acl_read control.");
    1017             :         }
    1018             : 
    1019      775680 :         return ldb_next_request(module, down_req);
    1020             : }
    1021             : 
    1022             : /*
    1023             :  * Here we mark inaccessible attributes known to be looked for in the
    1024             :  * filter. This only redacts attributes found in the search expression. If any
    1025             :  * extended attribute match rules examine different attributes without their own
    1026             :  * access control checks, a security bypass is possible.
    1027             :  */
    1028   119122260 : static int acl_redact_msg_for_filter(struct ldb_module *module, struct ldb_request *req, struct ldb_message *msg)
    1029             : {
    1030   119122260 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1031   119122260 :         const struct aclread_private *private_data = NULL;
    1032   119122260 :         struct ldb_control *control = NULL;
    1033   119122260 :         struct aclread_context *ac = NULL;
    1034     2775202 :         struct access_check_context acl_ctx;
    1035     2775202 :         int ret;
    1036     2775202 :         unsigned i;
    1037             : 
    1038             :         /*
    1039             :          * The private data contains a list of attributes which are to be
    1040             :          * considered secret.
    1041             :          */
    1042   119122260 :         private_data = talloc_get_type(ldb_module_get_private(module), struct aclread_private);
    1043   119122260 :         if (private_data == NULL) {
    1044           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1045             :                                  "aclread_private data is missing");
    1046             :         }
    1047   119122260 :         if (!private_data->enabled) {
    1048           0 :                 return LDB_SUCCESS;
    1049             :         }
    1050             : 
    1051   119122260 :         control = ldb_request_get_control(req, DSDB_CONTROL_ACL_READ_OID);
    1052   119122260 :         if (control == NULL) {
    1053             :                 /*
    1054             :                  * We've bypassed the acl_read module for this request, and
    1055             :                  * should skip redaction in this case.
    1056             :                  */
    1057   112327000 :                 return LDB_SUCCESS;
    1058             :         }
    1059             : 
    1060     4020398 :         ac = talloc_get_type_abort(control->data, struct aclread_context);
    1061             : 
    1062     4020398 :         if (!ac->got_tree_attrs) {
    1063      767218 :                 ret = ldb_parse_tree_collect_acl_attrs(module, ac, &ac->tree_attrs, req->op.search.tree);
    1064      767218 :                 if (ret != LDB_SUCCESS) {
    1065           0 :                         return ret;
    1066             :                 }
    1067      767218 :                 ac->got_tree_attrs = true;
    1068             :         }
    1069             : 
    1070    59020685 :         for (i = 0; i < msg->num_elements; ++i) {
    1071    57448936 :                 struct ldb_message_element *el = &msg->elements[i];
    1072             : 
    1073             :                 /* Is the attribute mentioned in the search expression? */
    1074    57448936 :                 if (attr_in_vec(&ac->tree_attrs, el->name)) {
    1075             :                         /*
    1076             :                          * We need to fetch the security descriptor to check
    1077             :                          * this element.
    1078             :                          */
    1079     2448563 :                         break;
    1080             :                 }
    1081             : 
    1082             :                 /*
    1083             :                  * This attribute is not in the search filter, so we can leave
    1084             :                  * handling it till aclread_callback(), by which time we know
    1085             :                  * this object is a match. This saves work checking ACLs if the
    1086             :                  * search is unindexed and most objects don't match the filter.
    1087             :                  */
    1088             :         }
    1089             : 
    1090     4020398 :         if (i == msg->num_elements) {
    1091             :                 /* All elements have been checked. */
    1092     1571495 :                 return LDB_SUCCESS;
    1093             :         }
    1094             : 
    1095     2448649 :         ret = setup_access_check_context(ac, msg, &acl_ctx);
    1096     2448649 :         if (ret != LDB_SUCCESS) {
    1097           0 :                 return ret;
    1098             :         }
    1099             : 
    1100             :         /* For every element in the message and the parse tree, check RP. */
    1101             : 
    1102    25084351 :         for (/* begin where we left off */; i < msg->num_elements; ++i) {
    1103    22635702 :                 struct ldb_message_element *el = &msg->elements[i];
    1104             : 
    1105             :                 /* Is the attribute mentioned in the search expression? */
    1106    22635702 :                 if (!attr_in_vec(&ac->tree_attrs, el->name)) {
    1107             :                         /*
    1108             :                          * If not, leave it for later and check the next
    1109             :                          * attribute.
    1110             :                          */
    1111    19622908 :                         continue;
    1112             :                 }
    1113             : 
    1114             :                 /*
    1115             :                  * We need to check whether the attribute is secret,
    1116             :                  * confidential, or access-controlled.
    1117             :                  */
    1118     3012880 :                 ret = acl_redact_attr(ac,
    1119             :                                       el,
    1120             :                                       ac,
    1121             :                                       private_data,
    1122             :                                       msg,
    1123             :                                       ac->schema,
    1124     3012794 :                                       acl_ctx.sd,
    1125             :                                       acl_ctx.sid,
    1126             :                                       acl_ctx.objectclass);
    1127     3012794 :                 if (ret != LDB_SUCCESS) {
    1128           0 :                         return ret;
    1129             :                 }
    1130             : 
    1131     3013841 :                 acl_element_mark_access_checked(el);
    1132             :         }
    1133             : 
    1134     2448563 :         return LDB_SUCCESS;
    1135             : }
    1136             : 
    1137    11943096 : static int ldb_attr_cmp_fn(const void *_a, const void *_b)
    1138             : {
    1139    11943096 :         const char * const *a = _a;
    1140    11943096 :         const char * const *b = _b;
    1141             : 
    1142    11943096 :         return ldb_attr_cmp(*a, *b);
    1143             : }
    1144             : 
    1145      180956 : static int aclread_init(struct ldb_module *module)
    1146             : {
    1147      180956 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1148        6012 :         unsigned int i, n, j;
    1149      180956 :         TALLOC_CTX *mem_ctx = NULL;
    1150        6012 :         int ret;
    1151        6012 :         bool userPassword_support;
    1152        6012 :         static const char * const attrs[] = { "passwordAttribute", NULL };
    1153        6012 :         static const char * const secret_attrs[] = {
    1154             :                 DSDB_SECRET_ATTRIBUTES
    1155             :         };
    1156        6012 :         struct ldb_result *res;
    1157        6012 :         struct ldb_message *msg;
    1158        6012 :         struct ldb_message_element *password_attributes;
    1159      180956 :         struct aclread_private *p = talloc_zero(module, struct aclread_private);
    1160      180956 :         if (p == NULL) {
    1161           0 :                 return ldb_module_oom(module);
    1162             :         }
    1163      180956 :         p->enabled = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"), NULL, "acl", "search", true);
    1164             : 
    1165      180956 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
    1166      180956 :         if (ret != LDB_SUCCESS) {
    1167           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
    1168             :                           "acl_module_init: Unable to register sd_flags control with rootdse!\n");
    1169           0 :                 return ldb_operr(ldb);
    1170             :         }
    1171             : 
    1172      180956 :         ldb_module_set_private(module, p);
    1173             : 
    1174      180956 :         mem_ctx = talloc_new(module);
    1175      180956 :         if (!mem_ctx) {
    1176           0 :                 return ldb_oom(ldb);
    1177             :         }
    1178             : 
    1179      180956 :         ret = dsdb_module_search_dn(module, mem_ctx, &res,
    1180             :                                     ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
    1181             :                                     attrs,
    1182             :                                     DSDB_FLAG_NEXT_MODULE |
    1183             :                                     DSDB_FLAG_AS_SYSTEM,
    1184             :                                     NULL);
    1185      180956 :         if (ret != LDB_SUCCESS) {
    1186           0 :                 goto done;
    1187             :         }
    1188      180956 :         if (res->count == 0) {
    1189           0 :                 goto done;
    1190             :         }
    1191             : 
    1192      180956 :         if (res->count > 1) {
    1193           0 :                 talloc_free(mem_ctx);
    1194           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    1195             :         }
    1196             : 
    1197      180956 :         msg = res->msgs[0];
    1198             : 
    1199      180956 :         password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
    1200      180956 :         if (!password_attributes) {
    1201           0 :                 goto done;
    1202             :         }
    1203      180956 :         p->password_attrs = talloc_array(p, const char *,
    1204             :                         password_attributes->num_values +
    1205             :                         ARRAY_SIZE(secret_attrs));
    1206      180956 :         if (!p->password_attrs) {
    1207           0 :                 talloc_free(mem_ctx);
    1208           0 :                 return ldb_oom(ldb);
    1209             :         }
    1210             : 
    1211      174944 :         n = 0;
    1212     3800010 :         for (i=0; i < password_attributes->num_values; i++) {
    1213     3619054 :                 p->password_attrs[n] = (const char *)password_attributes->values[i].data;
    1214     3619054 :                 talloc_steal(p->password_attrs, password_attributes->values[i].data);
    1215     3619054 :                 n++;
    1216             :         }
    1217             : 
    1218     2714340 :         for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
    1219     3549412 :                 bool found = false;
    1220             : 
    1221    33114948 :                 for (j=0; j < n; j++) {
    1222    33114882 :                         if (strcasecmp(p->password_attrs[j], secret_attrs[i]) == 0) {
    1223     2449166 :                                 found = true;
    1224     2449166 :                                 break;
    1225             :                         }
    1226             :                 }
    1227             : 
    1228     2533384 :                 if (found) {
    1229     2533318 :                         continue;
    1230             :                 }
    1231             : 
    1232         132 :                 p->password_attrs[n] = talloc_strdup(p->password_attrs,
    1233          66 :                                                      secret_attrs[i]);
    1234          66 :                 if (p->password_attrs[n] == NULL) {
    1235           0 :                         talloc_free(mem_ctx);
    1236           0 :                         return ldb_oom(ldb);
    1237             :                 }
    1238          66 :                 n++;
    1239             :         }
    1240      180956 :         p->num_password_attrs = n;
    1241             : 
    1242             :         /* Sort the password attributes so we can use binary search. */
    1243      180956 :         TYPESAFE_QSORT(p->password_attrs, p->num_password_attrs, ldb_attr_cmp_fn);
    1244             : 
    1245      180956 :         ret = ldb_register_redact_callback(ldb, acl_redact_msg_for_filter, module);
    1246      180956 :         if (ret != LDB_SUCCESS) {
    1247           0 :                 return ret;
    1248             :         }
    1249             : 
    1250      180956 : done:
    1251      180956 :         talloc_free(mem_ctx);
    1252      180956 :         ret = ldb_next_init(module);
    1253             : 
    1254      180956 :         if (ret != LDB_SUCCESS) {
    1255           0 :                 return ret;
    1256             :         }
    1257             : 
    1258      180956 :         if (p->password_attrs != NULL) {
    1259             :                 /*
    1260             :                  * Check this after the modules have be initialised so we can
    1261             :                  * actually read the backend DB.
    1262             :                  */
    1263      180956 :                 userPassword_support = dsdb_user_password_support(module,
    1264             :                                                                   module,
    1265             :                                                                   NULL);
    1266      180956 :                 if (!userPassword_support) {
    1267      174507 :                         const char **found = NULL;
    1268             : 
    1269             :                         /*
    1270             :                          * Remove the userPassword attribute, as it is not
    1271             :                          * considered secret.
    1272             :                          */
    1273      872535 :                         BINARY_ARRAY_SEARCH_V(p->password_attrs,
    1274             :                                               p->num_password_attrs,
    1275             :                                               "userPassword",
    1276             :                                               ldb_attr_cmp,
    1277             :                                               found);
    1278      174507 :                         if (found != NULL) {
    1279      174507 :                                 size_t found_idx = found - p->password_attrs;
    1280             : 
    1281             :                                 /* Shift following elements backwards by one. */
    1282      174507 :                                 for (i = found_idx; i < p->num_password_attrs - 1; ++i) {
    1283           0 :                                         p->password_attrs[i] = p->password_attrs[i + 1];
    1284             :                                 }
    1285      174507 :                                 --p->num_password_attrs;
    1286             :                         }
    1287             :                 }
    1288             :         }
    1289      174944 :         return ret;
    1290             : }
    1291             : 
    1292             : static const struct ldb_module_ops ldb_aclread_module_ops = {
    1293             :         .name              = "aclread",
    1294             :         .search            = aclread_search,
    1295             :         .init_context      = aclread_init
    1296             : };
    1297             : 
    1298        5908 : int ldb_aclread_module_init(const char *version)
    1299             : {
    1300        5908 :         LDB_MODULE_CHECK_VERSION(version);
    1301        5908 :         return ldb_register_module(&ldb_aclread_module_ops);
    1302             : }

Generated by: LCOV version 1.14