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 vadcx-master-patch-75612 fe003de8 Lines: 450 528 85.2 %
Date: 2024-02-29 22:57:05 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     3015958 : static void acl_element_mark_access_checked(struct ldb_message_element *el)
      93             : {
      94     3015958 :         el->flags |= LDB_FLAG_INTERNAL_ACCESS_CHECKED;
      95     3015958 : }
      96             : 
      97     5303672 : static bool acl_element_is_access_checked(const struct ldb_message_element *el)
      98             : {
      99     5303672 :         return (el->flags & LDB_FLAG_INTERNAL_ACCESS_CHECKED) != 0;
     100             : }
     101             : 
     102    80431097 : static bool attr_in_vec(const struct ldb_attr_vec *vec, const char *attr)
     103             : {
     104    80431097 :         const char **found = NULL;
     105             : 
     106    80431097 :         if (vec == NULL) {
     107           0 :                 return false;
     108             :         }
     109             : 
     110   147793257 :         BINARY_ARRAY_SEARCH_V(vec->attrs,
     111             :                               vec->len,
     112             :                               attr,
     113             :                               ldb_attr_cmp,
     114             :                               found);
     115    80431097 :         return found != NULL;
     116             : }
     117             : 
     118      215178 : static int acl_attr_cmp_fn(const char *a, const char **b)
     119             : {
     120      215178 :         return ldb_attr_cmp(a, *b);
     121             : }
     122             : 
     123      288677 : static int attr_vec_add_unique(TALLOC_CTX *mem_ctx,
     124             :                                struct ldb_attr_vec *vec,
     125             :                                const char *attr)
     126             : {
     127      288677 :         const char **exact = NULL;
     128      288677 :         const char **next = NULL;
     129      288677 :         size_t next_idx = 0;
     130             : 
     131      503855 :         BINARY_ARRAY_SEARCH_GTE(vec->attrs,
     132             :                                 vec->len,
     133             :                                 attr,
     134             :                                 acl_attr_cmp_fn,
     135             :                                 exact,
     136             :                                 next);
     137      288663 :         if (exact != NULL) {
     138       70121 :                 return LDB_SUCCESS;
     139             :         }
     140             : 
     141      218556 :         if (vec->len == SIZE_MAX) {
     142           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     143             :         }
     144             : 
     145      218556 :         if (next != NULL) {
     146       65884 :                 next_idx = next - vec->attrs;
     147             :         }
     148             : 
     149      218556 :         if (vec->len >= vec->capacity) {
     150      149070 :                 const char **attrs = NULL;
     151             : 
     152      149070 :                 if (vec->capacity == 0) {
     153      137217 :                         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      149070 :                 attrs = talloc_realloc(mem_ctx, vec->attrs, const char *, vec->capacity);
     162      149070 :                 if (attrs == NULL) {
     163           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     164             :                 }
     165             : 
     166      149070 :                 vec->attrs = attrs;
     167             :         }
     168      218556 :         SMB_ASSERT(vec->len < vec->capacity);
     169             : 
     170      218556 :         if (next == NULL) {
     171      152672 :                 vec->attrs[vec->len++] = attr;
     172             :         } else {
     173       65884 :                 size_t count = (vec->len - next_idx) * sizeof (vec->attrs[0]);
     174       65884 :                 memmove(&vec->attrs[next_idx + 1],
     175       65884 :                         &vec->attrs[next_idx],
     176             :                         count);
     177             : 
     178       65884 :                 vec->attrs[next_idx] = attr;
     179       65884 :                 ++vec->len;
     180             :         }
     181             : 
     182      218542 :         return LDB_SUCCESS;
     183             : }
     184             : 
     185     1306321 : 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     1306321 :         return ldb_attr_in_list(attrs_always_present, attr);
     196             : }
     197             : 
     198      975757 : 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      975757 :         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     4515396 : 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     4515664 :         const char *attr = NULL;
     216        1580 :         unsigned int i;
     217        1580 :         int ret;
     218             : 
     219     4515664 :         if (tree == NULL) {
     220           0 :                 return 0;
     221             :         }
     222             : 
     223     4515664 :         switch (tree->operation) {
     224     1456413 :         case LDB_OP_OR:
     225             :         case LDB_OP_AND:                /* attributes stored in list of subtrees */
     226     4436049 :                 for (i = 0; i < tree->u.list.num_elements; i++) {
     227     2980158 :                         ret = ldb_parse_tree_collect_acl_attrs(module, mem_ctx,
     228     2979114 :                                                                attrs, tree->u.list.elements[i]);
     229     2979114 :                         if (ret) {
     230           0 :                                 return ret;
     231             :                         }
     232             :                 }
     233     1456413 :                 return 0;
     234             : 
     235      752018 :         case LDB_OP_NOT:                /* attributes stored in single subtree */
     236      752018 :                 return ldb_parse_tree_collect_acl_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
     237             : 
     238     1306321 :         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     1306321 :                 if (ldb_attr_always_present(tree->u.present.attr)) {
     251             :                         /* No need to check this attribute. */
     252     1290993 :                         return 0;
     253             :                 }
     254             : 
     255       14820 :                 if (ldb_attr_always_visible(tree->u.present.attr)) {
     256             :                         /* No need to check this attribute. */
     257        1308 :                         return 0;
     258             :                 }
     259             : 
     260       13510 :                 break;
     261             : 
     262      960937 :         case LDB_OP_EQUALITY:
     263      960937 :                 if (ldb_attr_always_visible(tree->u.equality.attr)) {
     264             :                         /* No need to check this attribute. */
     265      724957 :                         return 0;
     266             :                 }
     267             : 
     268      235700 :                 break;
     269             : 
     270       39453 :         default:                        /* single attribute in tree */
     271       39453 :                 break;
     272             :         }
     273             : 
     274      288677 :         attr = ldb_parse_tree_get_attr(tree);
     275      288677 :         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     2211467 : 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     2211467 :         struct ldb_dn *parent_dn = NULL;
     295             : 
     296             :         /* We may have a cached result from earlier in this search */
     297     2211467 :         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     1439867 :                 int cmp_base = ldb_dn_compare_base(ac->last_parent_dn,
     304             :                                                    msg->dn);
     305     1439867 :                 if (cmp_base == 0) {
     306             :                         /* Now check if it is a direct parent */
     307     1358668 :                         parent_dn = ldb_dn_get_parent(ac, msg->dn);
     308     1358668 :                         if (parent_dn == NULL) {
     309           0 :                                 return ldb_oom(ldb_module_get_ctx(ac->module));
     310             :                         }
     311     1358668 :                         if (ldb_dn_compare(ac->last_parent_dn,
     312             :                                            parent_dn) == 0) {
     313     1287271 :                                 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     1287271 :                                 return ac->last_parent_check_ret;
     326             :                         }
     327             :                 }
     328             :         }
     329             : 
     330             :         {
     331      924196 :                 TALLOC_CTX *frame = NULL;
     332      924196 :                 frame = talloc_stackframe();
     333             : 
     334             :                 /*
     335             :                  * This may have been set in the block above, don't
     336             :                  * re-parse
     337             :                  */
     338      924196 :                 if (parent_dn == NULL) {
     339      852799 :                         parent_dn = ldb_dn_get_parent(ac, msg->dn);
     340      852799 :                         if (parent_dn == NULL) {
     341           0 :                                 TALLOC_FREE(frame);
     342           0 :                                 return ldb_oom(ldb_module_get_ctx(ac->module));
     343             :                         }
     344             :                 }
     345      924196 :                 ret = dsdb_module_check_access_on_dn(ac->module,
     346             :                                                      frame,
     347             :                                                      parent_dn,
     348             :                                                      SEC_ADS_LIST,
     349             :                                                      NULL, req);
     350      924196 :                 talloc_unlink(ac, ac->last_parent_dn);
     351      924196 :                 ac->last_parent_dn = parent_dn;
     352      924196 :                 ac->last_parent_check_ret = ret;
     353             : 
     354      924196 :                 TALLOC_FREE(frame);
     355             :         }
     356      923930 :         return ret;
     357             : }
     358             : 
     359     2305223 : 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     2305223 :         instanceType = ldb_msg_find_attr_as_uint(msg,
     368             :                                                  "instanceType", 0);
     369     2305223 :         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
     370             :                 /*
     371             :                  * NC_HEAD objects are always visible
     372             :                  */
     373       93740 :                 return LDB_SUCCESS;
     374             :         }
     375             : 
     376     2211467 :         ret = aclread_check_parent(ac, msg, req);
     377     2211467 :         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     2169909 :                 return LDB_SUCCESS;
     384             :         }
     385       41038 :         if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     386           0 :                 return ret;
     387             :         }
     388             : 
     389       41038 :         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       41038 :         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       28366 :         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     3648536 : 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     3648536 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     467         172 :         struct aclread_private *private_data
     468     3648536 :                 = talloc_get_type_abort(ldb_module_get_private(ac->module),
     469             :                                   struct aclread_private);
     470         172 :         enum ndr_err_code ndr_err;
     471             : 
     472     3648536 :         sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor");
     473     3648536 :         if (sd_element == NULL) {
     474           0 :                 return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS,
     475             :                                  "nTSecurityDescriptor is missing");
     476             :         }
     477             : 
     478     3648536 :         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     3648536 :         if (private_data->sd_cached != NULL &&
     489     7253722 :             private_data->sd_cached_blob.data != NULL &&
     490     3626861 :             ldb_val_equal_exact(&sd_element->values[0],
     491     3626861 :                                 &private_data->sd_cached_blob)) {
     492     2467719 :                 *sd = private_data->sd_cached;
     493     2467719 :                 return LDB_SUCCESS;
     494             :         }
     495             : 
     496     1180817 :         *sd = talloc(private_data, struct security_descriptor);
     497     1180817 :         if(!*sd) {
     498           0 :                 return ldb_oom(ldb);
     499             :         }
     500     1180817 :         ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, *sd,
     501             :                              (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
     502             : 
     503     1180817 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     504           0 :                 TALLOC_FREE(*sd);
     505           0 :                 return ldb_operr(ldb);
     506             :         }
     507             : 
     508     1180817 :         talloc_unlink(private_data, private_data->sd_cached_blob.data);
     509     1180817 :         private_data->sd_cached_blob = ldb_val_dup(private_data,
     510     1180817 :                                                    &sd_element->values[0]);
     511     1180817 :         if (private_data->sd_cached_blob.data == NULL) {
     512           0 :                 TALLOC_FREE(*sd);
     513           0 :                 return ldb_operr(ldb);
     514             :         }
     515             : 
     516     1180817 :         talloc_unlink(private_data, private_data->sd_cached);
     517     1180817 :         private_data->sd_cached = *sd;
     518             : 
     519     1180817 :         return LDB_SUCCESS;
     520             : }
     521             : 
     522             : /* Check whether the attribute is a password attribute. */
     523     6962581 : static bool attr_is_secret(const char *attr, const struct aclread_private *private_data)
     524             : {
     525     6962581 :         const char **found = NULL;
     526             : 
     527     6962581 :         if (private_data->password_attrs == NULL) {
     528           0 :                 return false;
     529             :         }
     530             : 
     531    37375577 :         BINARY_ARRAY_SEARCH_V(private_data->password_attrs,
     532             :                               private_data->num_password_attrs,
     533             :                               attr,
     534             :                               ldb_attr_cmp,
     535             :                               found);
     536     6962581 :         return found != NULL;
     537             : }
     538             : 
     539             : /*
     540             :  * Returns the access mask required to read a given attribute
     541             :  */
     542     6961926 : static uint32_t get_attr_access_mask(const struct dsdb_attribute *attr,
     543             :                                      uint32_t sd_flags)
     544             : {
     545             : 
     546     6961926 :         uint32_t access_mask = 0;
     547         307 :         bool is_sd;
     548             : 
     549             :         /* nTSecurityDescriptor is a special case */
     550     6961926 :         is_sd = (ldb_attr_cmp("nTSecurityDescriptor",
     551             :                               attr->lDAPDisplayName) == 0);
     552             : 
     553     6961926 :         if (is_sd) {
     554       24334 :                 if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
     555       23223 :                         access_mask |= SEC_STD_READ_CONTROL;
     556             :                 }
     557       24334 :                 if (sd_flags & SECINFO_DACL) {
     558       24307 :                         access_mask |= SEC_STD_READ_CONTROL;
     559             :                 }
     560       24334 :                 if (sd_flags & SECINFO_SACL) {
     561       22658 :                         access_mask |= SEC_FLAG_SYSTEM_SECURITY;
     562             :                 }
     563             :         } else {
     564     6937285 :                 access_mask = SEC_ADS_READ_PROP;
     565             :         }
     566             : 
     567     6961926 :         if (attr->searchFlags & SEARCH_FLAG_CONFIDENTIAL) {
     568        5324 :                 access_mask |= SEC_ADS_CONTROL_ACCESS;
     569             :         }
     570             : 
     571     6961926 :         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     6962581 : 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     6962581 :         const struct dsdb_attribute *attr = NULL;
     590         307 :         uint32_t access_mask;
     591     6962581 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     592             : 
     593     6962581 :         if (attr_is_secret(el->name, private_data)) {
     594         655 :                 ldb_msg_element_mark_inaccessible(el);
     595         655 :                 return LDB_SUCCESS;
     596             :         }
     597             : 
     598             :         /* Look up the attribute in the schema. */
     599     6961926 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
     600     6961926 :         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     6961926 :         access_mask = get_attr_access_mask(attr, ac->sd_flags);
     609     6961926 :         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     6961926 :         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     6961926 :         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     622       30062 :                 ldb_msg_element_mark_inaccessible(el);
     623     6931864 :         } 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     6961619 :         return LDB_SUCCESS;
     632             : }
     633             : 
     634     3648536 : 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     3648536 :         if (ac->schema == NULL) {
     645      597022 :                 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     646             : 
     647             :                 /* Cache the schema for later use. */
     648      597022 :                 ac->schema = dsdb_get_schema(ldb, ac);
     649             : 
     650      597022 :                 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     3648536 :         ret = aclread_get_sd_from_ldb_message(ac, msg, &ctx->sd);
     658     3648536 :         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     3648536 :         } 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     3648536 :         ctx->objectclass = dsdb_get_structural_oc_from_msg(ac->schema, msg);
     673     3648536 :         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     3648536 :         ret = samdb_result_dom_sid_buf(msg, "objectSid", &ctx->sid_buf);
     682     3648536 :         if (ret == LDB_SUCCESS) {
     683     3042871 :                 ctx->sid = &ctx->sid_buf;
     684      605665 :         } else if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
     685             :                 /* This is expected. */
     686      605665 :                 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     3648364 :         return LDB_SUCCESS;
     695             : }
     696             : 
     697             : /*
     698             :  * Whether this attribute was added to perform access checks and must be
     699             :  * removed.
     700             :  */
     701    10339733 : static bool should_remove_attr(const char *attr, const struct aclread_context *ac)
     702             : {
     703    10339733 :         if (ac->added_nTSecurityDescriptor &&
     704    10059841 :             ldb_attr_cmp("nTSecurityDescriptor", attr) == 0)
     705             :         {
     706     1457359 :                 return true;
     707             :         }
     708             : 
     709     8882106 :         if (ac->added_objectSid &&
     710     6113838 :             ldb_attr_cmp("objectSid", attr) == 0)
     711             :         {
     712      853851 :                 return true;
     713             :         }
     714             : 
     715     8028171 :         if (ac->added_instanceType &&
     716     5508997 :             ldb_attr_cmp("instanceType", attr) == 0)
     717             :         {
     718     1362501 :                 return true;
     719             :         }
     720             : 
     721     6665404 :         if (ac->added_objectClass &&
     722     4136270 :             ldb_attr_cmp("objectClass", attr) == 0)
     723             :         {
     724     1361732 :                 return true;
     725             :         }
     726             : 
     727     5303363 :         return false;
     728             : }
     729             : 
     730     2437633 : static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
     731             : {
     732         572 :         struct aclread_context *ac;
     733     2437633 :         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     2437633 :         ac = talloc_get_type_abort(req->context, struct aclread_context);
     740     2437633 :         if (!ares) {
     741           0 :                 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR );
     742             :         }
     743     2437633 :         if (ares->error != LDB_SUCCESS) {
     744           8 :                 return ldb_module_done(ac->req, ares->controls,
     745             :                                        ares->response, ares->error);
     746             :         }
     747     2437625 :         switch (ares->type) {
     748     1509598 :         case LDB_REPLY_ENTRY:
     749     1509598 :                 msg = ares->message;
     750             : 
     751     1509598 :                 if (!ldb_dn_is_null(msg->dn)) {
     752             :                         /*
     753             :                          * this is a real object, so we have
     754             :                          * to check for visibility
     755             :                          */
     756     1509598 :                         ret = aclread_check_object_visible(ac, msg, req);
     757     1509598 :                         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     758       27637 :                                 return LDB_SUCCESS;
     759     1481961 :                         } 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     5329986 :                 for (i = 0; i < msg->num_elements; ++i) {
     772     5044884 :                         struct ldb_message_element *el = &msg->elements[i];
     773             : 
     774             :                         /* Remove attributes added to perform access checks. */
     775     5044884 :                         if (should_remove_attr(el->name, ac)) {
     776     3802943 :                                 ldb_msg_element_mark_inaccessible(el);
     777     3802943 :                                 continue;
     778             :                         }
     779             : 
     780     1241941 :                         if (acl_element_is_access_checked(el)) {
     781             :                                 /* We will have already checked this attribute. */
     782       45082 :                                 continue;
     783             :                         }
     784             : 
     785             :                         /*
     786             :                          * We need to fetch the security descriptor to check
     787             :                          * this attribute.
     788             :                          */
     789     1196773 :                         break;
     790             :                 }
     791             : 
     792     1481961 :                 if (i == msg->num_elements) {
     793             :                         /* All elements have been checked. */
     794      285102 :                         goto reply_entry_done;
     795             :                 }
     796             : 
     797     1196859 :                 ret = setup_access_check_context(ac, msg, &acl_ctx);
     798     1196859 :                 if (ret != LDB_SUCCESS) {
     799           0 :                         return ret;
     800             :                 }
     801             : 
     802     1196859 :                 private_data = talloc_get_type_abort(ldb_module_get_private(ac->module),
     803             :                                                      struct aclread_private);
     804             : 
     805     6491794 :                 for (/* begin where we left off */; i < msg->num_elements; ++i) {
     806     5294849 :                         struct ldb_message_element *el = &msg->elements[i];
     807             : 
     808             :                         /* Remove attributes added to perform access checks. */
     809     5294849 :                         if (should_remove_attr(el->name, ac)) {
     810     1233118 :                                 ldb_msg_element_mark_inaccessible(el);
     811     1233118 :                                 continue;
     812             :                         }
     813             : 
     814     4061731 :                         if (acl_element_is_access_checked(el)) {
     815             :                                 /* We will have already checked this attribute. */
     816      115108 :                                 continue;
     817             :                         }
     818             : 
     819             :                         /*
     820             :                          * We need to check whether the attribute is secret,
     821             :                          * confidential, or access-controlled.
     822             :                          */
     823     3946844 :                         ret = acl_redact_attr(ac,
     824             :                                               el,
     825             :                                               ac,
     826             :                                               private_data,
     827             :                                               msg,
     828             :                                               ac->schema,
     829     3946623 :                                               acl_ctx.sd,
     830             :                                               acl_ctx.sid,
     831             :                                               acl_ctx.objectclass);
     832     3946623 :                         if (ret != LDB_SUCCESS) {
     833           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
     834             :                         }
     835             :                 }
     836             : 
     837     1196859 :         reply_entry_done:
     838     1481961 :                 ldb_msg_remove_inaccessible(msg);
     839             : 
     840     1481961 :                 ac->num_entries++;
     841     1481961 :                 return ldb_module_send_entry(ac->req, msg, ares->controls);
     842      135043 :         case LDB_REPLY_REFERRAL:
     843      135043 :                 return ldb_module_send_referral(ac->req, ares->referral);
     844      792984 :         case LDB_REPLY_DONE:
     845      792984 :                 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      789726 :                 return ldb_module_done(ac->req, ares->controls,
     856             :                                         ares->response, LDB_SUCCESS);
     857             : 
     858             :         }
     859           0 :         return LDB_SUCCESS;
     860             : }
     861             : 
     862             : 
     863    34542185 : static int aclread_search(struct ldb_module *module, struct ldb_request *req)
     864             : {
     865     1941955 :         struct ldb_context *ldb;
     866     1941955 :         int ret;
     867     1941955 :         struct aclread_context *ac;
     868     1941955 :         struct ldb_request *down_req;
     869     1941955 :         bool am_system;
     870     1941955 :         struct ldb_result *res;
     871     1941955 :         struct aclread_private *p;
     872    34542185 :         bool need_sd = false;
     873    34542185 :         bool explicit_sd_flags = false;
     874    34542185 :         bool is_untrusted = ldb_req_is_untrusted(req);
     875     1941955 :         static const char * const _all_attrs[] = { "*", NULL };
     876    34542185 :         bool all_attrs = false;
     877    34542185 :         const char * const *attrs = NULL;
     878     1941955 :         static const char *acl_attrs[] = {
     879             :                 "instanceType",
     880             :                 NULL
     881             :         };
     882             : 
     883    34542185 :         ldb = ldb_module_get_ctx(module);
     884    34542185 :         p = talloc_get_type(ldb_module_get_private(module), struct aclread_private);
     885             : 
     886    34542185 :         am_system = dsdb_have_system_access(module,
     887             :                                             req,
     888             :                                             SYSTEM_CONTROL_KEEP_CRITICAL);
     889             : 
     890             :         /* skip access checks if we are system or system control is supplied
     891             :          * or this is not LDAP server request */
     892    34542185 :         if (!p || !p->enabled ||
     893     7481154 :             am_system ||
     894     7481154 :             !is_untrusted) {
     895    33684858 :                 return ldb_next_request(module, req);
     896             :         }
     897             :         /* no checks on special dn */
     898      857327 :         if (ldb_dn_is_special(req->op.search.base)) {
     899       61174 :                 return ldb_next_request(module, req);
     900             :         }
     901             : 
     902      796153 :         ac = talloc_zero(req, struct aclread_context);
     903      796153 :         if (ac == NULL) {
     904           0 :                 return ldb_oom(ldb);
     905             :         }
     906      796153 :         ac->module = module;
     907      796153 :         ac->req = req;
     908             : 
     909      796153 :         attrs = req->op.search.attrs;
     910      796153 :         if (attrs == NULL) {
     911       83143 :                 all_attrs = true;
     912       83143 :                 attrs = _all_attrs;
     913      713008 :         } else if (ldb_attr_in_list(attrs, "*")) {
     914       17492 :                 all_attrs = true;
     915             :         }
     916             : 
     917             :         /*
     918             :          * In theory we should also check for the SD control but control verification is
     919             :          * expensive so we'd better had the ntsecuritydescriptor to the list of
     920             :          * searched attribute and then remove it !
     921             :          */
     922      796153 :         ac->sd_flags = dsdb_request_sd_flags(ac->req, &explicit_sd_flags);
     923             : 
     924      796153 :         if (ldb_attr_in_list(attrs, "nTSecurityDescriptor")) {
     925       21995 :                 need_sd = false;
     926      774158 :         } else if (explicit_sd_flags && all_attrs) {
     927         306 :                 need_sd = false;
     928             :         } else {
     929      773852 :                 need_sd = true;
     930             :         }
     931             : 
     932      796153 :         if (!all_attrs) {
     933      695516 :                 if (!ldb_attr_in_list(attrs, "instanceType")) {
     934      684814 :                         attrs = ldb_attr_list_copy_add(ac, attrs, "instanceType");
     935      684814 :                         if (attrs == NULL) {
     936           0 :                                 return ldb_oom(ldb);
     937             :                         }
     938      684814 :                         ac->added_instanceType = true;
     939             :                 }
     940      695516 :                 if (!ldb_attr_in_list(req->op.search.attrs, "objectSid")) {
     941      675170 :                         attrs = ldb_attr_list_copy_add(ac, attrs, "objectSid");
     942      675170 :                         if (attrs == NULL) {
     943           0 :                                 return ldb_oom(ldb);
     944             :                         }
     945      675170 :                         ac->added_objectSid = true;
     946             :                 }
     947      695516 :                 if (!ldb_attr_in_list(req->op.search.attrs, "objectClass")) {
     948      684027 :                         attrs = ldb_attr_list_copy_add(ac, attrs, "objectClass");
     949      684027 :                         if (attrs == NULL) {
     950           0 :                                 return ldb_oom(ldb);
     951             :                         }
     952      684027 :                         ac->added_objectClass = true;
     953             :                 }
     954             :         }
     955             : 
     956      796153 :         if (need_sd) {
     957      773852 :                 attrs = ldb_attr_list_copy_add(ac, attrs, "nTSecurityDescriptor");
     958      773852 :                 if (attrs == NULL) {
     959           0 :                         return ldb_oom(ldb);
     960             :                 }
     961      773852 :                 ac->added_nTSecurityDescriptor = true;
     962             :         }
     963             : 
     964      796153 :         ac->am_administrator = dsdb_module_am_administrator(module);
     965             : 
     966             :         /* check accessibility of base */
     967      796153 :         if (!ldb_dn_is_null(req->op.search.base)) {
     968      795887 :                 ret = dsdb_module_search_dn(module, req, &res, req->op.search.base,
     969             :                                             acl_attrs,
     970             :                                             DSDB_FLAG_NEXT_MODULE |
     971             :                                             DSDB_FLAG_AS_SYSTEM |
     972             :                                             DSDB_SEARCH_SHOW_RECYCLED,
     973             :                                             req);
     974      795887 :                 if (ret != LDB_SUCCESS) {
     975         262 :                         return ldb_error(ldb, ret,
     976             :                                         "acl_read: Error retrieving instanceType for base.");
     977             :                 }
     978      795625 :                 ret = aclread_check_object_visible(ac, res->msgs[0], req);
     979      795625 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
     980        8649 :                         if (req->op.search.scope == LDB_SCOPE_BASE) {
     981        2889 :                                 return ldb_module_done(req, NULL, NULL,
     982             :                                                        LDB_ERR_NO_SUCH_OBJECT);
     983             :                         }
     984             :                         /*
     985             :                          * Defer LDB_ERR_NO_SUCH_OBJECT,
     986             :                          * we may return sub objects
     987             :                          */
     988        5760 :                         ac->base_invisible = true;
     989      786976 :                 } else if (ret != LDB_SUCCESS) {
     990           0 :                         return ldb_module_done(req, NULL, NULL, ret);
     991             :                 }
     992             :         }
     993             : 
     994      793002 :         ret = ldb_build_search_req_ex(&down_req,
     995             :                                       ldb, ac,
     996             :                                       req->op.search.base,
     997             :                                       req->op.search.scope,
     998             :                                       req->op.search.tree,
     999             :                                       attrs,
    1000             :                                       req->controls,
    1001             :                                       ac, aclread_callback,
    1002             :                                       req);
    1003             : 
    1004      793002 :         if (ret != LDB_SUCCESS) {
    1005           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1006             :         }
    1007             : 
    1008             :         /*
    1009             :          * We provide 'ac' as the control value, which is then used by the
    1010             :          * callback to avoid double-work.
    1011             :          */
    1012      793002 :         ret = ldb_request_add_control(down_req, DSDB_CONTROL_ACL_READ_OID, false, ac);
    1013      793002 :         if (ret != LDB_SUCCESS) {
    1014           0 :                         return ldb_error(ldb, ret,
    1015             :                                         "acl_read: Error adding acl_read control.");
    1016             :         }
    1017             : 
    1018      793002 :         return ldb_next_request(module, down_req);
    1019             : }
    1020             : 
    1021             : /*
    1022             :  * Here we mark inaccessible attributes known to be looked for in the
    1023             :  * filter. This only redacts attributes found in the search expression. If any
    1024             :  * extended attribute match rules examine different attributes without their own
    1025             :  * access control checks, a security bypass is possible.
    1026             :  */
    1027   120527184 : static int acl_redact_msg_for_filter(struct ldb_module *module, struct ldb_request *req, struct ldb_message *msg)
    1028             : {
    1029   120527184 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1030   120527184 :         const struct aclread_private *private_data = NULL;
    1031   120527184 :         struct ldb_control *control = NULL;
    1032   120527184 :         struct aclread_context *ac = NULL;
    1033     2762027 :         struct access_check_context acl_ctx;
    1034     2762027 :         int ret;
    1035     2762027 :         unsigned i;
    1036             : 
    1037             :         /*
    1038             :          * The private data contains a list of attributes which are to be
    1039             :          * considered secret.
    1040             :          */
    1041   120527184 :         private_data = talloc_get_type(ldb_module_get_private(module), struct aclread_private);
    1042   120527184 :         if (private_data == NULL) {
    1043           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1044             :                                  "aclread_private data is missing");
    1045             :         }
    1046   120527184 :         if (!private_data->enabled) {
    1047           0 :                 return LDB_SUCCESS;
    1048             :         }
    1049             : 
    1050   120527184 :         control = ldb_request_get_control(req, DSDB_CONTROL_ACL_READ_OID);
    1051   120527184 :         if (control == NULL) {
    1052             :                 /*
    1053             :                  * We've bypassed the acl_read module for this request, and
    1054             :                  * should skip redaction in this case.
    1055             :                  */
    1056   113724497 :                 return LDB_SUCCESS;
    1057             :         }
    1058             : 
    1059     4041000 :         ac = talloc_get_type_abort(control->data, struct aclread_context);
    1060             : 
    1061     4041000 :         if (!ac->got_tree_attrs) {
    1062      784532 :                 ret = ldb_parse_tree_collect_acl_attrs(module, ac, &ac->tree_attrs, req->op.search.tree);
    1063      784532 :                 if (ret != LDB_SUCCESS) {
    1064           0 :                         return ret;
    1065             :                 }
    1066      784532 :                 ac->got_tree_attrs = true;
    1067             :         }
    1068             : 
    1069    59349920 :         for (i = 0; i < msg->num_elements; ++i) {
    1070    57760597 :                 struct ldb_message_element *el = &msg->elements[i];
    1071             : 
    1072             :                 /* Is the attribute mentioned in the search expression? */
    1073    57760597 :                 if (attr_in_vec(&ac->tree_attrs, el->name)) {
    1074             :                         /*
    1075             :                          * We need to fetch the security descriptor to check
    1076             :                          * this element.
    1077             :                          */
    1078     2451591 :                         break;
    1079             :                 }
    1080             : 
    1081             :                 /*
    1082             :                  * This attribute is not in the search filter, so we can leave
    1083             :                  * handling it till aclread_callback(), by which time we know
    1084             :                  * this object is a match. This saves work checking ACLs if the
    1085             :                  * search is unindexed and most objects don't match the filter.
    1086             :                  */
    1087             :         }
    1088             : 
    1089     4041000 :         if (i == msg->num_elements) {
    1090             :                 /* All elements have been checked. */
    1091     1589069 :                 return LDB_SUCCESS;
    1092             :         }
    1093             : 
    1094     2451677 :         ret = setup_access_check_context(ac, msg, &acl_ctx);
    1095     2451677 :         if (ret != LDB_SUCCESS) {
    1096           0 :                 return ret;
    1097             :         }
    1098             : 
    1099             :         /* For every element in the message and the parse tree, check RP. */
    1100             : 
    1101    25122177 :         for (/* begin where we left off */; i < msg->num_elements; ++i) {
    1102    22670500 :                 struct ldb_message_element *el = &msg->elements[i];
    1103             : 
    1104             :                 /* Is the attribute mentioned in the search expression? */
    1105    22670500 :                 if (!attr_in_vec(&ac->tree_attrs, el->name)) {
    1106             :                         /*
    1107             :                          * If not, leave it for later and check the next
    1108             :                          * attribute.
    1109             :                          */
    1110    19654542 :                         continue;
    1111             :                 }
    1112             : 
    1113             :                 /*
    1114             :                  * We need to check whether the attribute is secret,
    1115             :                  * confidential, or access-controlled.
    1116             :                  */
    1117     3016044 :                 ret = acl_redact_attr(ac,
    1118             :                                       el,
    1119             :                                       ac,
    1120             :                                       private_data,
    1121             :                                       msg,
    1122             :                                       ac->schema,
    1123     3015958 :                                       acl_ctx.sd,
    1124             :                                       acl_ctx.sid,
    1125             :                                       acl_ctx.objectclass);
    1126     3015958 :                 if (ret != LDB_SUCCESS) {
    1127           0 :                         return ret;
    1128             :                 }
    1129             : 
    1130     3017002 :                 acl_element_mark_access_checked(el);
    1131             :         }
    1132             : 
    1133     2451591 :         return LDB_SUCCESS;
    1134             : }
    1135             : 
    1136    11873400 : static int ldb_attr_cmp_fn(const void *_a, const void *_b)
    1137             : {
    1138    11873400 :         const char * const *a = _a;
    1139    11873400 :         const char * const *b = _b;
    1140             : 
    1141    11873400 :         return ldb_attr_cmp(*a, *b);
    1142             : }
    1143             : 
    1144      179900 : static int aclread_init(struct ldb_module *module)
    1145             : {
    1146      179900 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1147        5975 :         unsigned int i, n, j;
    1148      179900 :         TALLOC_CTX *mem_ctx = NULL;
    1149        5975 :         int ret;
    1150        5975 :         bool userPassword_support;
    1151        5975 :         static const char * const attrs[] = { "passwordAttribute", NULL };
    1152        5975 :         static const char * const secret_attrs[] = {
    1153             :                 DSDB_SECRET_ATTRIBUTES
    1154             :         };
    1155        5975 :         struct ldb_result *res;
    1156        5975 :         struct ldb_message *msg;
    1157        5975 :         struct ldb_message_element *password_attributes;
    1158      179900 :         struct aclread_private *p = talloc_zero(module, struct aclread_private);
    1159      179900 :         if (p == NULL) {
    1160           0 :                 return ldb_module_oom(module);
    1161             :         }
    1162      179900 :         p->enabled = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"), NULL, "acl", "search", true);
    1163             : 
    1164      179900 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
    1165      179900 :         if (ret != LDB_SUCCESS) {
    1166           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
    1167             :                           "acl_module_init: Unable to register sd_flags control with rootdse!\n");
    1168           0 :                 return ldb_operr(ldb);
    1169             :         }
    1170             : 
    1171      179900 :         ldb_module_set_private(module, p);
    1172             : 
    1173      179900 :         mem_ctx = talloc_new(module);
    1174      179900 :         if (!mem_ctx) {
    1175           0 :                 return ldb_oom(ldb);
    1176             :         }
    1177             : 
    1178      179900 :         ret = dsdb_module_search_dn(module, mem_ctx, &res,
    1179             :                                     ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
    1180             :                                     attrs,
    1181             :                                     DSDB_FLAG_NEXT_MODULE |
    1182             :                                     DSDB_FLAG_AS_SYSTEM,
    1183             :                                     NULL);
    1184      179900 :         if (ret != LDB_SUCCESS) {
    1185           0 :                 goto done;
    1186             :         }
    1187      179900 :         if (res->count == 0) {
    1188           0 :                 goto done;
    1189             :         }
    1190             : 
    1191      179900 :         if (res->count > 1) {
    1192           0 :                 talloc_free(mem_ctx);
    1193           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    1194             :         }
    1195             : 
    1196      179900 :         msg = res->msgs[0];
    1197             : 
    1198      179900 :         password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
    1199      179900 :         if (!password_attributes) {
    1200           0 :                 goto done;
    1201             :         }
    1202      179900 :         p->password_attrs = talloc_array(p, const char *,
    1203             :                         password_attributes->num_values +
    1204             :                         ARRAY_SIZE(secret_attrs));
    1205      179900 :         if (!p->password_attrs) {
    1206           0 :                 talloc_free(mem_ctx);
    1207           0 :                 return ldb_oom(ldb);
    1208             :         }
    1209             : 
    1210      173925 :         n = 0;
    1211     3777834 :         for (i=0; i < password_attributes->num_values; i++) {
    1212     3597934 :                 p->password_attrs[n] = (const char *)password_attributes->values[i].data;
    1213     3597934 :                 talloc_steal(p->password_attrs, password_attributes->values[i].data);
    1214     3597934 :                 n++;
    1215             :         }
    1216             : 
    1217     2698500 :         for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
    1218     3528375 :                 bool found = false;
    1219             : 
    1220    32921700 :                 for (j=0; j < n; j++) {
    1221    32921634 :                         if (strcasecmp(p->password_attrs[j], secret_attrs[i]) == 0) {
    1222     2434900 :                                 found = true;
    1223     2434900 :                                 break;
    1224             :                         }
    1225             :                 }
    1226             : 
    1227     2518600 :                 if (found) {
    1228     2518534 :                         continue;
    1229             :                 }
    1230             : 
    1231         132 :                 p->password_attrs[n] = talloc_strdup(p->password_attrs,
    1232          66 :                                                      secret_attrs[i]);
    1233          66 :                 if (p->password_attrs[n] == NULL) {
    1234           0 :                         talloc_free(mem_ctx);
    1235           0 :                         return ldb_oom(ldb);
    1236             :                 }
    1237          66 :                 n++;
    1238             :         }
    1239      179900 :         p->num_password_attrs = n;
    1240             : 
    1241             :         /* Sort the password attributes so we can use binary search. */
    1242      179900 :         TYPESAFE_QSORT(p->password_attrs, p->num_password_attrs, ldb_attr_cmp_fn);
    1243             : 
    1244      179900 :         ret = ldb_register_redact_callback(ldb, acl_redact_msg_for_filter, module);
    1245      179900 :         if (ret != LDB_SUCCESS) {
    1246           0 :                 return ret;
    1247             :         }
    1248             : 
    1249      179900 : done:
    1250      179900 :         talloc_free(mem_ctx);
    1251      179900 :         ret = ldb_next_init(module);
    1252             : 
    1253      179900 :         if (ret != LDB_SUCCESS) {
    1254           0 :                 return ret;
    1255             :         }
    1256             : 
    1257      179900 :         if (p->password_attrs != NULL) {
    1258             :                 /*
    1259             :                  * Check this after the modules have be initialised so we can
    1260             :                  * actually read the backend DB.
    1261             :                  */
    1262      179900 :                 userPassword_support = dsdb_user_password_support(module,
    1263             :                                                                   module,
    1264             :                                                                   NULL);
    1265      179900 :                 if (!userPassword_support) {
    1266      173285 :                         const char **found = NULL;
    1267             : 
    1268             :                         /*
    1269             :                          * Remove the userPassword attribute, as it is not
    1270             :                          * considered secret.
    1271             :                          */
    1272      866425 :                         BINARY_ARRAY_SEARCH_V(p->password_attrs,
    1273             :                                               p->num_password_attrs,
    1274             :                                               "userPassword",
    1275             :                                               ldb_attr_cmp,
    1276             :                                               found);
    1277      173285 :                         if (found != NULL) {
    1278      173285 :                                 size_t found_idx = found - p->password_attrs;
    1279             : 
    1280             :                                 /* Shift following elements backwards by one. */
    1281      173285 :                                 for (i = found_idx; i < p->num_password_attrs - 1; ++i) {
    1282           0 :                                         p->password_attrs[i] = p->password_attrs[i + 1];
    1283             :                                 }
    1284      173285 :                                 --p->num_password_attrs;
    1285             :                         }
    1286             :                 }
    1287             :         }
    1288      173925 :         return ret;
    1289             : }
    1290             : 
    1291             : static const struct ldb_module_ops ldb_aclread_module_ops = {
    1292             :         .name              = "aclread",
    1293             :         .search            = aclread_search,
    1294             :         .init_context      = aclread_init
    1295             : };
    1296             : 
    1297        5950 : int ldb_aclread_module_init(const char *version)
    1298             : {
    1299        5950 :         LDB_MODULE_CHECK_VERSION(version);
    1300        5950 :         return ldb_register_module(&ldb_aclread_module_ops);
    1301             : }

Generated by: LCOV version 1.14