LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - acl.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 800 1063 75.3 %
Date: 2024-06-13 04:01:37 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /*
       2             :   ldb database library
       3             : 
       4             :   Copyright (C) Simo Sorce 2006-2008
       5             :   Copyright (C) Nadezhda Ivanova 2009
       6             :   Copyright (C) Anatoliy Atanasov  2009
       7             : 
       8             :   This program is free software; you can redistribute it and/or modify
       9             :   it under the terms of the GNU General Public License as published by
      10             :   the Free Software Foundation; either version 3 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   This program is distributed in the hope that it will be useful,
      14             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :   GNU General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU General Public License
      19             :   along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : /*
      23             :  *  Name: ldb
      24             :  *
      25             :  *  Component: ldb ACL module
      26             :  *
      27             :  *  Description: Module that performs authorisation access checks based on the
      28             :  *               account's security context and the DACL of the object being polled.
      29             :  *               Only DACL checks implemented at this point
      30             :  *
      31             :  *  Authors: Nadezhda Ivanova, Anatoliy Atanasov
      32             :  */
      33             : 
      34             : #include "includes.h"
      35             : #include "ldb_module.h"
      36             : #include "auth/auth.h"
      37             : #include "libcli/security/security.h"
      38             : #include "dsdb/samdb/samdb.h"
      39             : #include "librpc/gen_ndr/ndr_security.h"
      40             : #include "param/param.h"
      41             : #include "dsdb/samdb/ldb_modules/util.h"
      42             : #include "lib/util/tsort.h"
      43             : #include "system/kerberos.h"
      44             : #include "auth/kerberos/kerberos.h"
      45             : 
      46             : #undef strcasecmp
      47             : #undef strncasecmp
      48             : 
      49             : struct acl_private {
      50             :         bool acl_search;
      51             :         const char **password_attrs;
      52             :         void *cached_schema_ptr;
      53             :         uint64_t cached_schema_metadata_usn;
      54             :         uint64_t cached_schema_loaded_usn;
      55             :         const char **confidential_attrs;
      56             : };
      57             : 
      58             : struct acl_context {
      59             :         struct ldb_module *module;
      60             :         struct ldb_request *req;
      61             :         bool am_system;
      62             :         bool am_administrator;
      63             :         bool constructed_attrs;
      64             :         bool allowedAttributes;
      65             :         bool allowedAttributesEffective;
      66             :         bool allowedChildClasses;
      67             :         bool allowedChildClassesEffective;
      68             :         bool sDRightsEffective;
      69             :         struct dsdb_schema *schema;
      70             : };
      71             : 
      72      108013 : static int acl_module_init(struct ldb_module *module)
      73             : {
      74             :         struct ldb_context *ldb;
      75             :         struct acl_private *data;
      76             :         int ret;
      77             : 
      78      108013 :         ldb = ldb_module_get_ctx(module);
      79             : 
      80      108013 :         data = talloc_zero(module, struct acl_private);
      81      108013 :         if (data == NULL) {
      82           0 :                 return ldb_oom(ldb);
      83             :         }
      84             : 
      85      108013 :         data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
      86             :                                         NULL, "acl", "search", true);
      87      108013 :         ldb_module_set_private(module, data);
      88             : 
      89      108013 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
      90      108013 :         if (ret != LDB_SUCCESS) {
      91           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
      92             :                           "acl_module_init: Unable to register control with rootdse!\n");
      93           0 :                 return ldb_operr(ldb);
      94             :         }
      95             : 
      96      108013 :         return ldb_next_init(module);
      97             : }
      98             : 
      99          22 : static int acl_allowedAttributes(struct ldb_module *module,
     100             :                                  const struct dsdb_schema *schema,
     101             :                                  struct ldb_message *sd_msg,
     102             :                                  struct ldb_message *msg,
     103             :                                  struct acl_context *ac)
     104             : {
     105             :         struct ldb_message_element *oc_el;
     106          22 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     107             :         TALLOC_CTX *mem_ctx;
     108             :         const char **attr_list;
     109             :         int i, ret;
     110             :         const struct dsdb_class *objectclass;
     111             : 
     112             :         /* If we don't have a schema yet, we can't do anything... */
     113          22 :         if (schema == NULL) {
     114           0 :                 ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
     115           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     116             :         }
     117             : 
     118             :         /* Must remove any existing attribute */
     119          22 :         if (ac->allowedAttributes) {
     120           4 :                 ldb_msg_remove_attr(msg, "allowedAttributes");
     121             :         }
     122             : 
     123          22 :         mem_ctx = talloc_new(msg);
     124          22 :         if (!mem_ctx) {
     125           0 :                 return ldb_oom(ldb);
     126             :         }
     127             : 
     128          22 :         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
     129          22 :         attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
     130          22 :         if (!attr_list) {
     131           0 :                 ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
     132           0 :                 talloc_free(mem_ctx);
     133           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     134             :         }
     135             : 
     136             :         /*
     137             :          * Get the top-most structural object class for the ACL check
     138             :          */
     139          22 :         objectclass = dsdb_get_last_structural_class(ac->schema,
     140             :                                                      oc_el);
     141          22 :         if (objectclass == NULL) {
     142           0 :                 ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
     143             :                                        ldb_dn_get_linearized(sd_msg->dn));
     144           0 :                 talloc_free(mem_ctx);
     145           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     146             :         }
     147             : 
     148          22 :         if (ac->allowedAttributes) {
     149         938 :                 for (i=0; attr_list && attr_list[i]; i++) {
     150         934 :                         ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
     151             :                 }
     152             :         }
     153          22 :         if (ac->allowedAttributesEffective) {
     154             :                 struct security_descriptor *sd;
     155          22 :                 struct dom_sid *sid = NULL;
     156          22 :                 struct ldb_control *as_system = ldb_request_get_control(ac->req,
     157             :                                                                         LDB_CONTROL_AS_SYSTEM_OID);
     158             : 
     159          22 :                 if (as_system != NULL) {
     160           0 :                         as_system->critical = 0;
     161             :                 }
     162             : 
     163          22 :                 ldb_msg_remove_attr(msg, "allowedAttributesEffective");
     164          22 :                 if (ac->am_system || as_system) {
     165           0 :                         for (i=0; attr_list && attr_list[i]; i++) {
     166           0 :                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
     167             :                         }
     168           0 :                         return LDB_SUCCESS;
     169             :                 }
     170             : 
     171          22 :                 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
     172             : 
     173          22 :                 if (ret != LDB_SUCCESS) {
     174           0 :                         return ret;
     175             :                 }
     176             : 
     177          22 :                 sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
     178        3568 :                 for (i=0; attr_list && attr_list[i]; i++) {
     179        3546 :                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
     180        3546 :                                                                                         attr_list[i]);
     181        3546 :                         if (!attr) {
     182           0 :                                 return ldb_operr(ldb);
     183             :                         }
     184             :                         /* remove constructed attributes */
     185        3546 :                         if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
     186        3016 :                             || attr->systemOnly
     187        1685 :                             || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
     188        1989 :                                 continue;
     189             :                         }
     190        1557 :                         ret = acl_check_access_on_attribute(module,
     191             :                                                             msg,
     192             :                                                             sd,
     193             :                                                             sid,
     194             :                                                             SEC_ADS_WRITE_PROP,
     195             :                                                             attr,
     196             :                                                             objectclass);
     197        1557 :                         if (ret == LDB_SUCCESS) {
     198         531 :                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
     199             :                         }
     200             :                 }
     201             :         }
     202          22 :         return LDB_SUCCESS;
     203             : }
     204             : 
     205           0 : static int acl_childClasses(struct ldb_module *module,
     206             :                             const struct dsdb_schema *schema,
     207             :                             struct ldb_message *sd_msg,
     208             :                             struct ldb_message *msg,
     209             :                             const char *attrName)
     210             : {
     211             :         struct ldb_message_element *oc_el;
     212             :         struct ldb_message_element *allowedClasses;
     213             :         const struct dsdb_class *sclass;
     214             :         unsigned int i, j;
     215             :         int ret;
     216             : 
     217             :         /* If we don't have a schema yet, we can't do anything... */
     218           0 :         if (schema == NULL) {
     219           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add childClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
     220           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     221             :         }
     222             : 
     223             :         /* Must remove any existing attribute, or else confusion reins */
     224           0 :         ldb_msg_remove_attr(msg, attrName);
     225           0 :         ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
     226           0 :         if (ret != LDB_SUCCESS) {
     227           0 :                 return ret;
     228             :         }
     229             : 
     230           0 :         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
     231             : 
     232           0 :         for (i=0; oc_el && i < oc_el->num_values; i++) {
     233           0 :                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
     234           0 :                 if (!sclass) {
     235             :                         /* We don't know this class?  what is going on? */
     236           0 :                         continue;
     237             :                 }
     238             : 
     239           0 :                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
     240           0 :                         ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
     241             :                 }
     242             :         }
     243           0 :         if (allowedClasses->num_values > 1) {
     244           0 :                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
     245           0 :                 for (i=1 ; i < allowedClasses->num_values; i++) {
     246           0 :                         struct ldb_val *val1 = &allowedClasses->values[i-1];
     247           0 :                         struct ldb_val *val2 = &allowedClasses->values[i];
     248           0 :                         if (data_blob_cmp(val1, val2) == 0) {
     249           0 :                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
     250           0 :                                 allowedClasses->num_values--;
     251           0 :                                 i--;
     252             :                         }
     253             :                 }
     254             :         }
     255             : 
     256           0 :         return LDB_SUCCESS;
     257             : }
     258             : 
     259          18 : static int acl_childClassesEffective(struct ldb_module *module,
     260             :                                      const struct dsdb_schema *schema,
     261             :                                      struct ldb_message *sd_msg,
     262             :                                      struct ldb_message *msg,
     263             :                                      struct acl_context *ac)
     264             : {
     265             :         struct ldb_message_element *oc_el;
     266          18 :         struct ldb_message_element *allowedClasses = NULL;
     267             :         const struct dsdb_class *sclass;
     268             :         struct security_descriptor *sd;
     269          18 :         struct ldb_control *as_system = ldb_request_get_control(ac->req,
     270             :                                                                 LDB_CONTROL_AS_SYSTEM_OID);
     271          18 :         struct dom_sid *sid = NULL;
     272             :         unsigned int i, j;
     273             :         int ret;
     274             : 
     275          18 :         if (as_system != NULL) {
     276           0 :                 as_system->critical = 0;
     277             :         }
     278             : 
     279          18 :         if (ac->am_system || as_system) {
     280           0 :                 return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
     281             :         }
     282             : 
     283             :         /* If we don't have a schema yet, we can't do anything... */
     284          18 :         if (schema == NULL) {
     285           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add allowedChildClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
     286           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     287             :         }
     288             : 
     289             :         /* Must remove any existing attribute, or else confusion reins */
     290          18 :         ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
     291             : 
     292          18 :         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
     293          18 :         ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
     294          18 :         if (ret != LDB_SUCCESS) {
     295           0 :                 return ret;
     296             :         }
     297             : 
     298          18 :         sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
     299          54 :         for (i=0; oc_el && i < oc_el->num_values; i++) {
     300          36 :                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
     301          36 :                 if (!sclass) {
     302             :                         /* We don't know this class?  what is going on? */
     303           0 :                         continue;
     304             :                 }
     305             : 
     306        1698 :                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
     307             :                         const struct dsdb_class *sc;
     308             : 
     309        1662 :                         sc = dsdb_class_by_lDAPDisplayName(schema,
     310        1662 :                                                            sclass->possibleInferiors[j]);
     311        1662 :                         if (!sc) {
     312             :                                 /* We don't know this class?  what is going on? */
     313           0 :                                 continue;
     314             :                         }
     315             : 
     316        1662 :                         ret = acl_check_access_on_objectclass(module, ac,
     317             :                                                               sd, sid,
     318             :                                                               SEC_ADS_CREATE_CHILD,
     319             :                                                               sc);
     320        1662 :                         if (ret == LDB_SUCCESS) {
     321           9 :                                 ldb_msg_add_string(msg, "allowedChildClassesEffective",
     322           9 :                                                    sclass->possibleInferiors[j]);
     323             :                         }
     324             :                 }
     325             :         }
     326          18 :         allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
     327          18 :         if (!allowedClasses) {
     328           9 :                 return LDB_SUCCESS;
     329             :         }
     330             : 
     331           9 :         if (allowedClasses->num_values > 1) {
     332           0 :                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
     333           0 :                 for (i=1 ; i < allowedClasses->num_values; i++) {
     334           0 :                         struct ldb_val *val1 = &allowedClasses->values[i-1];
     335           0 :                         struct ldb_val *val2 = &allowedClasses->values[i];
     336           0 :                         if (data_blob_cmp(val1, val2) == 0) {
     337           0 :                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
     338           0 :                                 allowedClasses->num_values--;
     339           0 :                                 i--;
     340             :                         }
     341             :                 }
     342             :         }
     343           9 :         return LDB_SUCCESS;
     344             : }
     345             : 
     346          36 : static int acl_sDRightsEffective(struct ldb_module *module,
     347             :                                  struct ldb_message *sd_msg,
     348             :                                  struct ldb_message *msg,
     349             :                                  struct acl_context *ac)
     350             : {
     351          36 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     352             :         struct ldb_message_element *rightsEffective;
     353             :         int ret;
     354             :         struct security_descriptor *sd;
     355          36 :         struct ldb_control *as_system = ldb_request_get_control(ac->req,
     356             :                                                                 LDB_CONTROL_AS_SYSTEM_OID);
     357          36 :         struct dom_sid *sid = NULL;
     358          36 :         uint32_t flags = 0;
     359             : 
     360          36 :         if (as_system != NULL) {
     361           0 :                 as_system->critical = 0;
     362             :         }
     363             : 
     364             :         /* Must remove any existing attribute, or else confusion reins */
     365          36 :         ldb_msg_remove_attr(msg, "sDRightsEffective");
     366          36 :         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
     367          36 :         if (ret != LDB_SUCCESS) {
     368           0 :                 return ret;
     369             :         }
     370          36 :         if (ac->am_system || as_system) {
     371           0 :                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
     372             :         } else {
     373             :                 const struct dsdb_class *objectclass;
     374             :                 const struct dsdb_attribute *attr;
     375             : 
     376          36 :                 objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
     377          36 :                 if (objectclass == NULL) {
     378           0 :                         return ldb_operr(ldb);
     379             :                 }
     380             : 
     381          36 :                 attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
     382             :                                                          "nTSecurityDescriptor");
     383          36 :                 if (attr == NULL) {
     384           0 :                         return ldb_operr(ldb);
     385             :                 }
     386             : 
     387             :                 /* Get the security descriptor from the message */
     388          36 :                 ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
     389          36 :                 if (ret != LDB_SUCCESS) {
     390           0 :                         return ret;
     391             :                 }
     392          36 :                 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
     393          36 :                 ret = acl_check_access_on_attribute(module,
     394             :                                                     msg,
     395             :                                                     sd,
     396             :                                                     sid,
     397             :                                                     SEC_STD_WRITE_OWNER,
     398             :                                                     attr,
     399             :                                                     objectclass);
     400          36 :                 if (ret == LDB_SUCCESS) {
     401          18 :                         flags |= SECINFO_OWNER | SECINFO_GROUP;
     402             :                 }
     403          36 :                 ret = acl_check_access_on_attribute(module,
     404             :                                                     msg,
     405             :                                                     sd,
     406             :                                                     sid,
     407             :                                                     SEC_STD_WRITE_DAC,
     408             :                                                     attr,
     409             :                                                     objectclass);
     410          36 :                 if (ret == LDB_SUCCESS) {
     411          27 :                         flags |= SECINFO_DACL;
     412             :                 }
     413          36 :                 ret = acl_check_access_on_attribute(module,
     414             :                                                     msg,
     415             :                                                     sd,
     416             :                                                     sid,
     417             :                                                     SEC_FLAG_SYSTEM_SECURITY,
     418             :                                                     attr,
     419             :                                                     objectclass);
     420          36 :                 if (ret == LDB_SUCCESS) {
     421           9 :                         flags |= SECINFO_SACL;
     422             :                 }
     423             :         }
     424          36 :         return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
     425             :                                   "sDRightsEffective", flags);
     426             : }
     427             : 
     428         559 : static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
     429             :                                   struct ldb_context *ldb,
     430             :                                   const struct ldb_val *spn_value,
     431             :                                   uint32_t userAccountControl,
     432             :                                   const struct ldb_val *samAccountName,
     433             :                                   const struct ldb_val *dnsHostName,
     434             :                                   const char *netbios_name,
     435             :                                   const char *ntds_guid)
     436             : {
     437             :         int ret, princ_size;
     438             :         krb5_context krb_ctx;
     439             :         krb5_error_code kerr;
     440             :         krb5_principal principal;
     441             :         char *instanceName;
     442             :         char *serviceType;
     443             :         char *serviceName;
     444         559 :         const char *spn_value_str = NULL;
     445             :         size_t account_name_len;
     446         559 :         const char *forest_name = samdb_forest_name(ldb, mem_ctx);
     447         559 :         const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
     448         559 :         struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
     449             :                                                           struct loadparm_context);
     450         920 :         bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
     451         361 :                 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
     452             : 
     453         878 :         spn_value_str = talloc_strndup(mem_ctx,
     454         559 :                                        (const char *)spn_value->data,
     455         240 :                                        spn_value->length);
     456         559 :         if (spn_value_str == NULL) {
     457           0 :                 return ldb_oom(ldb);
     458             :         }
     459             : 
     460         559 :         if (spn_value->length == samAccountName->length &&
     461           0 :             strncasecmp((const char *)spn_value->data,
     462           0 :                         (const char *)samAccountName->data,
     463           0 :                         spn_value->length) == 0)
     464             :         {
     465             :                 /* MacOS X sets this value, and setting an SPN of your
     466             :                  * own samAccountName is both pointless and safe */
     467           0 :                 return LDB_SUCCESS;
     468             :         }
     469             : 
     470         559 :         kerr = smb_krb5_init_context_basic(mem_ctx,
     471             :                                            lp_ctx,
     472             :                                            &krb_ctx);
     473         559 :         if (kerr != 0) {
     474           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
     475             :                                  "Could not initialize kerberos context.");
     476             :         }
     477             : 
     478         559 :         ret = krb5_parse_name(krb_ctx, spn_value_str, &principal);
     479         559 :         if (ret) {
     480           0 :                 krb5_free_context(krb_ctx);
     481           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
     482             :         }
     483             : 
     484         559 :         princ_size = krb5_princ_size(krb_ctx, principal);
     485         559 :         if (princ_size < 2) {
     486           0 :                 DBG_WARNING("princ_size=%d\n", princ_size);
     487           0 :                 goto fail;
     488             :         }
     489             : 
     490         559 :         instanceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
     491             :                                                           principal, 1);
     492         559 :         serviceType = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
     493             :                                                          principal, 0);
     494         559 :         if (krb5_princ_size(krb_ctx, principal) == 3) {
     495         409 :                 serviceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
     496             :                                                                  principal, 2);
     497             :         } else {
     498         150 :                 serviceName = NULL;
     499             :         }
     500             : 
     501         559 :         if (serviceName) {
     502         409 :                 if (!is_dc) {
     503          81 :                         DBG_WARNING("is_dc=false, serviceName=%s,"
     504             :                                     "serviceType=%s\n", serviceName,
     505             :                                   serviceType);
     506          81 :                         goto fail;
     507             :                 }
     508         328 :                 if (strcasecmp(serviceType, "ldap") == 0) {
     509         151 :                         if (strcasecmp(serviceName, netbios_name) != 0 &&
     510          73 :                             strcasecmp(serviceName, forest_name) != 0) {
     511          36 :                                 DBG_WARNING("serviceName=%s\n", serviceName);
     512          36 :                                 goto fail;
     513             :                         }
     514             : 
     515         218 :                 } else if (strcasecmp(serviceType, "gc") == 0) {
     516          36 :                         if (strcasecmp(serviceName, forest_name) != 0) {
     517          18 :                                 DBG_WARNING("serviceName=%s\n", serviceName);
     518          18 :                                 goto fail;
     519             :                         }
     520             :                 } else {
     521         213 :                         if (strcasecmp(serviceName, base_domain) != 0 &&
     522          55 :                             strcasecmp(serviceName, netbios_name) != 0) {
     523          18 :                                 DBG_WARNING("serviceType=%s, "
     524             :                                             "serviceName=%s\n",
     525             :                                             serviceType, serviceName);
     526          18 :                                 goto fail;
     527             :                         }
     528             :                 }
     529             :         }
     530             : 
     531         406 :         account_name_len = samAccountName->length;
     532         640 :         if (account_name_len &&
     533         406 :             samAccountName->data[account_name_len - 1] == '$')
     534             :         {
     535             :                 /* Account for the '$' character. */
     536         406 :                 --account_name_len;
     537             :         }
     538             : 
     539             :         /* instanceName can be samAccountName without $ or dnsHostName
     540             :          * or "ntds_guid._msdcs.forest_domain for DC objects */
     541         406 :         if (strlen(instanceName) == account_name_len
     542         214 :             && strncasecmp(instanceName,
     543         214 :                            (const char *)samAccountName->data,
     544             :                            account_name_len) == 0)
     545             :         {
     546         214 :                 goto success;
     547             :         }
     548         304 :         if ((dnsHostName != NULL) &&
     549         278 :             strlen(instanceName) == dnsHostName->length &&
     550         232 :             (strncasecmp(instanceName,
     551         146 :                          (const char *)dnsHostName->data,
     552          60 :                          dnsHostName->length) == 0))
     553             :         {
     554         146 :                 goto success;
     555             :         }
     556          46 :         if (is_dc) {
     557             :                 const char *guid_str;
     558          37 :                 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
     559             :                                            ntds_guid,
     560             :                                            forest_name);
     561          37 :                 if (strcasecmp(instanceName, guid_str) == 0) {
     562          19 :                         goto success;
     563             :                 }
     564             :         }
     565             : 
     566          27 : fail:
     567         180 :         krb5_free_principal(krb_ctx, principal);
     568         180 :         krb5_free_context(krb_ctx);
     569         480 :         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
     570             :                       "acl: spn validation failed for "
     571             :                       "spn[%.*s] uac[0x%x] account[%.*s] hostname[%.*s] "
     572             :                       "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
     573         180 :                       (int)spn_value->length, spn_value->data,
     574             :                       (unsigned)userAccountControl,
     575         180 :                       (int)samAccountName->length, samAccountName->data,
     576         180 :                       dnsHostName != NULL ? (int)dnsHostName->length : 0,
     577             :                       dnsHostName != NULL ? (const char *)dnsHostName->data : "",
     578             :                       netbios_name, ntds_guid,
     579             :                       forest_name, base_domain);
     580         180 :         return LDB_ERR_CONSTRAINT_VIOLATION;
     581             : 
     582         379 : success:
     583         379 :         krb5_free_principal(krb_ctx, principal);
     584         379 :         krb5_free_context(krb_ctx);
     585         379 :         return LDB_SUCCESS;
     586             : }
     587             : 
     588             : /*
     589             :  * Passing in 'el' is critical, we want to check all the values.
     590             :  *
     591             :  */
     592        1269 : static int acl_check_spn(TALLOC_CTX *mem_ctx,
     593             :                          struct ldb_module *module,
     594             :                          struct ldb_request *req,
     595             :                          const struct ldb_message_element *el,
     596             :                          struct security_descriptor *sd,
     597             :                          struct dom_sid *sid,
     598             :                          const struct dsdb_attribute *attr,
     599             :                          const struct dsdb_class *objectclass,
     600             :                          const struct ldb_control *implicit_validated_write_control)
     601             : {
     602             :         int ret;
     603             :         unsigned int i;
     604        1269 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     605        1269 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     606             :         struct ldb_result *acl_res;
     607             :         struct ldb_result *netbios_res;
     608        1269 :         struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
     609             :         uint32_t userAccountControl;
     610             :         const char *netbios_name;
     611        1269 :         const struct ldb_val *dns_host_name_val = NULL;
     612        1269 :         const struct ldb_val *sam_account_name_val = NULL;
     613             :         struct GUID ntds;
     614        1269 :         char *ntds_guid = NULL;
     615             : 
     616             :         static const char *acl_attrs[] = {
     617             :                 "samAccountName",
     618             :                 "dnsHostName",
     619             :                 "userAccountControl",
     620             :                 NULL
     621             :         };
     622             :         static const char *netbios_attrs[] = {
     623             :                 "nETBIOSName",
     624             :                 NULL
     625             :         };
     626             : 
     627        1269 :         if (implicit_validated_write_control != NULL) {
     628             :                 /*
     629             :                  * The validated write control dispenses with ACL
     630             :                  * checks. We act as if we have an implicit Self Write
     631             :                  * privilege, but, assuming we don't have Write
     632             :                  * Property, still proceed with further validation
     633             :                  * checks.
     634             :                  */
     635             :         } else {
     636             :                 /* if we have wp, we can do whatever we like */
     637        1263 :                 if (acl_check_access_on_attribute(module,
     638             :                                                   tmp_ctx,
     639             :                                                   sd,
     640             :                                                   sid,
     641             :                                                   SEC_ADS_WRITE_PROP,
     642             :                                                   attr, objectclass) == LDB_SUCCESS) {
     643         668 :                         talloc_free(tmp_ctx);
     644         668 :                         return LDB_SUCCESS;
     645             :                 }
     646             : 
     647         595 :                 ret = acl_check_extended_right(tmp_ctx,
     648             :                                                module,
     649             :                                                req,
     650             :                                                objectclass,
     651             :                                                sd,
     652             :                                                acl_user_token(module),
     653             :                                                GUID_DRS_VALIDATE_SPN,
     654             :                                                SEC_ADS_SELF_WRITE,
     655             :                                                sid);
     656             : 
     657         595 :                 if (ret != LDB_SUCCESS) {
     658          36 :                         dsdb_acl_debug(sd, acl_user_token(module),
     659          36 :                                        req->op.mod.message->dn,
     660             :                                        true,
     661             :                                        10);
     662          36 :                         talloc_free(tmp_ctx);
     663          36 :                         return ret;
     664             :                 }
     665             :         }
     666             : 
     667             :         /*
     668             :          * If we have "validated write spn", allow delete of any
     669             :          * existing value (this keeps constrained delete to the same
     670             :          * rules as unconstrained)
     671             :          */
     672         565 :         if (req->operation == LDB_MODIFY) {
     673             :                 /*
     674             :                  * If not add or replace (eg delete),
     675             :                  * return success
     676             :                  */
     677         846 :                 if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
     678         501 :                     LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
     679             :                 {
     680          18 :                         talloc_free(tmp_ctx);
     681          18 :                         return LDB_SUCCESS;
     682             :                 }
     683             :         }
     684             : 
     685         547 :         ret = dsdb_module_search_dn(module, tmp_ctx,
     686         547 :                                     &acl_res, req->op.mod.message->dn,
     687             :                                     acl_attrs,
     688             :                                     DSDB_FLAG_NEXT_MODULE |
     689             :                                     DSDB_FLAG_AS_SYSTEM |
     690             :                                     DSDB_SEARCH_SHOW_RECYCLED,
     691             :                                     req);
     692         547 :         if (ret != LDB_SUCCESS) {
     693           0 :                 talloc_free(tmp_ctx);
     694           0 :                 return ret;
     695             :         }
     696             : 
     697         547 :         dns_host_name_val = ldb_msg_find_ldb_val(acl_res->msgs[0], "dNSHostName");
     698             : 
     699         547 :         ret = dsdb_msg_get_single_value(req->op.mod.message,
     700             :                                         "dNSHostName",
     701             :                                         dns_host_name_val,
     702             :                                         &dns_host_name_val,
     703             :                                         req->operation);
     704         547 :         if (ret != LDB_SUCCESS) {
     705           0 :                 talloc_free(tmp_ctx);
     706           0 :                 return ret;
     707             :         }
     708             : 
     709         547 :         userAccountControl = ldb_msg_find_attr_as_uint(acl_res->msgs[0], "userAccountControl", 0);
     710             : 
     711         547 :         sam_account_name_val = ldb_msg_find_ldb_val(acl_res->msgs[0], "sAMAccountName");
     712             : 
     713         547 :         ret = dsdb_msg_get_single_value(req->op.mod.message,
     714             :                                         "sAMAccountName",
     715             :                                         sam_account_name_val,
     716             :                                         &sam_account_name_val,
     717             :                                         req->operation);
     718         547 :         if (ret != LDB_SUCCESS) {
     719           0 :                 talloc_free(tmp_ctx);
     720           0 :                 return ret;
     721             :         }
     722             : 
     723         547 :         ret = dsdb_module_search(module, tmp_ctx,
     724             :                                  &netbios_res, partitions_dn,
     725             :                                  LDB_SCOPE_ONELEVEL,
     726             :                                  netbios_attrs,
     727             :                                  DSDB_FLAG_NEXT_MODULE |
     728             :                                  DSDB_FLAG_AS_SYSTEM,
     729             :                                  req,
     730             :                                  "(ncName=%s)",
     731             :                                  ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
     732             : 
     733         547 :         netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
     734             : 
     735             :         /* NTDSDSA objectGuid of object we are checking SPN for */
     736         547 :         if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
     737         397 :                 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
     738         397 :                                                              req->op.mod.message->dn, &ntds, req);
     739         397 :                 if (ret != LDB_SUCCESS) {
     740           0 :                         ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
     741           0 :                                                ldb_dn_get_linearized(req->op.mod.message->dn),
     742             :                                                ldb_strerror(ret));
     743           0 :                         talloc_free(tmp_ctx);
     744           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     745             :                 }
     746         397 :                 ntds_guid = GUID_string(tmp_ctx, &ntds);
     747             :         }
     748             : 
     749         926 :         for (i=0; i < el->num_values; i++) {
     750         878 :                 ret = acl_validate_spn_value(tmp_ctx,
     751             :                                              ldb,
     752         559 :                                              &el->values[i],
     753             :                                              userAccountControl,
     754             :                                              sam_account_name_val,
     755             :                                              dns_host_name_val,
     756             :                                              netbios_name,
     757             :                                              ntds_guid);
     758         559 :                 if (ret != LDB_SUCCESS) {
     759         180 :                         talloc_free(tmp_ctx);
     760         180 :                         return ret;
     761             :                 }
     762             :         }
     763         367 :         talloc_free(tmp_ctx);
     764         367 :         return LDB_SUCCESS;
     765             : }
     766             : 
     767         645 : static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
     768             :                                    struct ldb_module *module,
     769             :                                    struct ldb_request *req,
     770             :                                    const struct ldb_message_element *el,
     771             :                                    struct security_descriptor *sd,
     772             :                                    struct dom_sid *sid,
     773             :                                    const struct dsdb_attribute *attr,
     774             :                                    const struct dsdb_class *objectclass,
     775             :                                    const struct ldb_control *implicit_validated_write_control)
     776             : {
     777             :         int ret;
     778             :         unsigned i;
     779         645 :         TALLOC_CTX *tmp_ctx = NULL;
     780         645 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     781         645 :         const struct dsdb_schema *schema = NULL;
     782         645 :         const struct ldb_message_element *allowed_suffixes = NULL;
     783         645 :         struct ldb_result *nc_res = NULL;
     784         645 :         struct ldb_dn *nc_root = NULL;
     785         645 :         const char *nc_dns_name = NULL;
     786         645 :         const char *dnsHostName_str = NULL;
     787             :         size_t dns_host_name_len;
     788             :         size_t account_name_len;
     789         645 :         const struct ldb_message *msg = NULL;
     790         645 :         const struct ldb_message *search_res = NULL;
     791         645 :         const struct ldb_val *samAccountName = NULL;
     792         645 :         const struct ldb_val *dnsHostName = NULL;
     793         645 :         const struct dsdb_class *computer_objectclass = NULL;
     794             :         bool is_subclass;
     795             : 
     796             :         static const char *nc_attrs[] = {
     797             :                 "msDS-AllowedDNSSuffixes",
     798             :                 NULL
     799             :         };
     800             : 
     801         645 :         tmp_ctx = talloc_new(mem_ctx);
     802         645 :         if (tmp_ctx == NULL) {
     803           0 :                 return ldb_oom(ldb);
     804             :         }
     805             : 
     806         645 :         if (implicit_validated_write_control != NULL) {
     807             :                 /*
     808             :                  * The validated write control dispenses with ACL
     809             :                  * checks. We act as if we have an implicit Self Write
     810             :                  * privilege, but, assuming we don't have Write
     811             :                  * Property, still proceed with further validation
     812             :                  * checks.
     813             :                  */
     814             :         } else {
     815             :                 /* if we have wp, we can do whatever we like */
     816         618 :                 ret = acl_check_access_on_attribute(module,
     817             :                                                     tmp_ctx,
     818             :                                                     sd,
     819             :                                                     sid,
     820             :                                                     SEC_ADS_WRITE_PROP,
     821             :                                                     attr, objectclass);
     822         618 :                 if (ret == LDB_SUCCESS) {
     823         414 :                         talloc_free(tmp_ctx);
     824         414 :                         return LDB_SUCCESS;
     825             :                 }
     826             : 
     827         204 :                 ret = acl_check_extended_right(tmp_ctx,
     828             :                                                module,
     829             :                                                req,
     830             :                                                objectclass,
     831             :                                                sd,
     832             :                                                acl_user_token(module),
     833             :                                                GUID_DRS_DNS_HOST_NAME,
     834             :                                                SEC_ADS_SELF_WRITE,
     835             :                                                sid);
     836             : 
     837         204 :                 if (ret != LDB_SUCCESS) {
     838          78 :                         dsdb_acl_debug(sd, acl_user_token(module),
     839          78 :                                        req->op.mod.message->dn,
     840             :                                        true,
     841             :                                        10);
     842          78 :                         talloc_free(tmp_ctx);
     843          78 :                         return ret;
     844             :                 }
     845             :         }
     846             : 
     847             :         /*
     848             :          * If we have "validated write dnshostname", allow delete of
     849             :          * any existing value (this keeps constrained delete to the
     850             :          * same rules as unconstrained)
     851             :          */
     852         153 :         if (req->operation == LDB_MODIFY) {
     853         153 :                 struct ldb_result *acl_res = NULL;
     854             : 
     855             :                 static const char *acl_attrs[] = {
     856             :                         "sAMAccountName",
     857             :                         NULL
     858             :                 };
     859             : 
     860         153 :                 msg = req->op.mod.message;
     861             : 
     862             :                 /*
     863             :                  * If not add or replace (eg delete),
     864             :                  * return success
     865             :                  */
     866         250 :                 if ((el->flags
     867         153 :                      & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0)
     868             :                 {
     869           0 :                         talloc_free(tmp_ctx);
     870           0 :                         return LDB_SUCCESS;
     871             :                 }
     872             : 
     873         153 :                 ret = dsdb_module_search_dn(module, tmp_ctx,
     874          56 :                                             &acl_res, msg->dn,
     875             :                                             acl_attrs,
     876             :                                             DSDB_FLAG_NEXT_MODULE |
     877             :                                             DSDB_FLAG_AS_SYSTEM |
     878             :                                             DSDB_SEARCH_SHOW_RECYCLED,
     879             :                                             req);
     880         153 :                 if (ret != LDB_SUCCESS) {
     881           0 :                         talloc_free(tmp_ctx);
     882           0 :                         return ret;
     883             :                 }
     884             : 
     885         153 :                 search_res = acl_res->msgs[0];
     886           0 :         } else if (req->operation == LDB_ADD) {
     887           0 :                 msg = req->op.add.message;
     888           0 :                 search_res = msg;
     889             :         } else {
     890           0 :                 talloc_free(tmp_ctx);
     891           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     892             :         }
     893             : 
     894             :         /* Check if the account has objectclass 'computer' or 'server'. */
     895             : 
     896         153 :         schema = dsdb_get_schema(ldb, req);
     897         153 :         if (schema == NULL) {
     898           0 :                 talloc_free(tmp_ctx);
     899           0 :                 return ldb_operr(ldb);
     900             :         }
     901             : 
     902         153 :         computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
     903         153 :         if (computer_objectclass == NULL) {
     904           0 :                 talloc_free(tmp_ctx);
     905           0 :                 return ldb_operr(ldb);
     906             :         }
     907             : 
     908         153 :         is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
     909         153 :         if (!is_subclass) {
     910             :                 /* The account is not a computer -- check if it's a server. */
     911             : 
     912           0 :                 const struct dsdb_class *server_objectclass = NULL;
     913             : 
     914           0 :                 server_objectclass = dsdb_class_by_lDAPDisplayName(schema, "server");
     915           0 :                 if (server_objectclass == NULL) {
     916           0 :                         talloc_free(tmp_ctx);
     917           0 :                         return ldb_operr(ldb);
     918             :                 }
     919             : 
     920           0 :                 is_subclass = dsdb_is_subclass_of(schema, objectclass, server_objectclass);
     921           0 :                 if (!is_subclass) {
     922             :                         /* Not a computer or server, so no need to validate. */
     923           0 :                         talloc_free(tmp_ctx);
     924           0 :                         return LDB_SUCCESS;
     925             :                 }
     926             :         }
     927             : 
     928         153 :         samAccountName = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
     929             : 
     930         153 :         ret = dsdb_msg_get_single_value(msg,
     931             :                                         "sAMAccountName",
     932             :                                         samAccountName,
     933             :                                         &samAccountName,
     934             :                                         req->operation);
     935         153 :         if (ret != LDB_SUCCESS) {
     936           0 :                 talloc_free(tmp_ctx);
     937           0 :                 return ret;
     938             :         }
     939             : 
     940         153 :         account_name_len = samAccountName->length;
     941         153 :         if (account_name_len && samAccountName->data[account_name_len - 1] == '$') {
     942             :                 /* Account for the '$' character. */
     943         144 :                 --account_name_len;
     944             :         }
     945             : 
     946             :         /* Check for add or replace requests with no value. */
     947         153 :         if (el->num_values == 0) {
     948           9 :                 talloc_free(tmp_ctx);
     949           9 :                 return ldb_operr(ldb);
     950             :         }
     951         144 :         dnsHostName = &el->values[0];
     952             : 
     953         144 :         dnsHostName_str = (const char *)dnsHostName->data;
     954         144 :         dns_host_name_len = dnsHostName->length;
     955             : 
     956             :         /* Check that sAMAccountName matches the new dNSHostName. */
     957             : 
     958         144 :         if (dns_host_name_len < account_name_len) {
     959          18 :                 goto fail;
     960             :         }
     961         126 :         if (strncasecmp(dnsHostName_str,
     962         126 :                         (const char *)samAccountName->data,
     963             :                         account_name_len) != 0)
     964             :         {
     965          24 :                 goto fail;
     966             :         }
     967             : 
     968         102 :         dnsHostName_str += account_name_len;
     969         102 :         dns_host_name_len -= account_name_len;
     970             : 
     971             :         /* Check the '.' character */
     972             : 
     973         160 :         if (dns_host_name_len == 0 || *dnsHostName_str != '.') {
     974           8 :                 goto fail;
     975             :         }
     976             : 
     977          72 :         ++dnsHostName_str;
     978          72 :         --dns_host_name_len;
     979             : 
     980             :         /* Now we check the suffix. */
     981             : 
     982          72 :         ret = dsdb_find_nc_root(ldb,
     983             :                                 tmp_ctx,
     984          28 :                                 search_res->dn,
     985             :                                 &nc_root);
     986          72 :         if (ret != LDB_SUCCESS) {
     987           0 :                 talloc_free(tmp_ctx);
     988           0 :                 return ret;
     989             :         }
     990             : 
     991          72 :         nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root);
     992          72 :         if (nc_dns_name == NULL) {
     993           0 :                 talloc_free(tmp_ctx);
     994           0 :                 return ldb_operr(ldb);
     995             :         }
     996             : 
     997         103 :         if (strlen(nc_dns_name) == dns_host_name_len &&
     998          51 :             strncasecmp(dnsHostName_str,
     999             :                         nc_dns_name,
    1000             :                         dns_host_name_len) == 0)
    1001             :         {
    1002             :                 /* It matches -- success. */
    1003          51 :                 talloc_free(tmp_ctx);
    1004          51 :                 return LDB_SUCCESS;
    1005             :         }
    1006             : 
    1007             :         /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */
    1008             : 
    1009          21 :         ret = dsdb_module_search_dn(module, tmp_ctx,
    1010             :                                     &nc_res, nc_root,
    1011             :                                     nc_attrs,
    1012             :                                     DSDB_FLAG_NEXT_MODULE |
    1013             :                                     DSDB_FLAG_AS_SYSTEM |
    1014             :                                     DSDB_SEARCH_SHOW_RECYCLED,
    1015             :                                     req);
    1016          21 :         if (ret != LDB_SUCCESS) {
    1017           0 :                 talloc_free(tmp_ctx);
    1018           0 :                 return ret;
    1019             :         }
    1020             : 
    1021          21 :         allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0],
    1022             :                                                 "msDS-AllowedDNSSuffixes");
    1023          21 :         if (allowed_suffixes == NULL) {
    1024          12 :                 goto fail;
    1025             :         }
    1026             : 
    1027           9 :         for (i = 0; i < allowed_suffixes->num_values; ++i) {
    1028           9 :                 const struct ldb_val *suffix = &allowed_suffixes->values[i];
    1029             : 
    1030          14 :                 if (suffix->length == dns_host_name_len &&
    1031           9 :                     strncasecmp(dnsHostName_str,
    1032           9 :                                 (const char *)suffix->data,
    1033             :                                 dns_host_name_len) == 0)
    1034             :                 {
    1035             :                         /* It matches -- success. */
    1036           9 :                         talloc_free(tmp_ctx);
    1037           9 :                         return LDB_SUCCESS;
    1038             :                 }
    1039             :         }
    1040             : 
    1041          22 : fail:
    1042         196 :         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
    1043             :                       "acl: hostname validation failed for "
    1044             :                       "hostname[%.*s] account[%.*s]\n",
    1045          84 :                       (int)dnsHostName->length, dnsHostName->data,
    1046         140 :                       (int)samAccountName->length, samAccountName->data);
    1047          84 :         talloc_free(tmp_ctx);
    1048          84 :         return LDB_ERR_CONSTRAINT_VIOLATION;
    1049             : }
    1050             : 
    1051      320277 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
    1052             : {
    1053             :         int ret;
    1054             :         struct ldb_dn *parent;
    1055             :         struct ldb_context *ldb;
    1056             :         const struct dsdb_schema *schema;
    1057             :         const struct dsdb_class *objectclass;
    1058             :         struct ldb_control *as_system;
    1059             :         struct ldb_message_element *el;
    1060      320277 :         unsigned int instanceType = 0;
    1061             : 
    1062      320277 :         if (ldb_dn_is_special(req->op.add.message->dn)) {
    1063         371 :                 return ldb_next_request(module, req);
    1064             :         }
    1065             : 
    1066      319906 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    1067      319906 :         if (as_system != NULL) {
    1068          75 :                 as_system->critical = 0;
    1069             :         }
    1070             : 
    1071      319906 :         if (dsdb_module_am_system(module) || as_system) {
    1072        3842 :                 return ldb_next_request(module, req);
    1073             :         }
    1074             : 
    1075      316064 :         ldb = ldb_module_get_ctx(module);
    1076             : 
    1077      316064 :         parent = ldb_dn_get_parent(req, req->op.add.message->dn);
    1078      316064 :         if (parent == NULL) {
    1079           0 :                 return ldb_oom(ldb);
    1080             :         }
    1081             : 
    1082      316064 :         schema = dsdb_get_schema(ldb, req);
    1083      316064 :         if (!schema) {
    1084           0 :                 return ldb_operr(ldb);
    1085             :         }
    1086             : 
    1087      316064 :         objectclass = dsdb_get_structural_oc_from_msg(schema, req->op.add.message);
    1088      316064 :         if (!objectclass) {
    1089           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1090             :                                        "acl: unable to find or validate structural objectClass on %s\n",
    1091           0 :                                        ldb_dn_get_linearized(req->op.add.message->dn));
    1092           0 :                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
    1093             :         }
    1094             : 
    1095      316064 :         el = ldb_msg_find_element(req->op.add.message, "instanceType");
    1096      316064 :         if ((el != NULL) && (el->num_values != 1)) {
    1097           1 :                 ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
    1098           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1099             :         }
    1100             : 
    1101      316063 :         instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
    1102             :                                                  "instanceType", 0);
    1103      316063 :         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
    1104             :                 static const char *no_attrs[] = { NULL };
    1105             :                 struct ldb_result *partition_res;
    1106             :                 struct ldb_dn *partitions_dn;
    1107             : 
    1108         356 :                 partitions_dn = samdb_partitions_dn(ldb, req);
    1109         356 :                 if (!partitions_dn) {
    1110           0 :                         ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
    1111           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1112             :                 }
    1113             : 
    1114         356 :                 ret = dsdb_module_search(module, req, &partition_res,
    1115             :                                          partitions_dn, LDB_SCOPE_ONELEVEL,
    1116             :                                          no_attrs,
    1117             :                                          DSDB_FLAG_NEXT_MODULE |
    1118             :                                          DSDB_FLAG_AS_SYSTEM |
    1119             :                                          DSDB_SEARCH_ONE_ONLY |
    1120             :                                          DSDB_SEARCH_SHOW_RECYCLED,
    1121             :                                          req,
    1122             :                                          "(&(nCName=%s)(objectClass=crossRef))",
    1123         356 :                                          ldb_dn_get_linearized(req->op.add.message->dn));
    1124             : 
    1125         356 :                 if (ret == LDB_SUCCESS) {
    1126             :                         /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
    1127           0 :                         ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
    1128             :                                                              SEC_ADS_WRITE_PROP,
    1129             :                                                              &objectclass->schemaIDGUID, req);
    1130           0 :                         if (ret != LDB_SUCCESS) {
    1131           0 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1132             :                                                        "acl: ACL check failed on crossRef object %s: %s\n",
    1133           0 :                                                        ldb_dn_get_linearized(partition_res->msgs[0]->dn),
    1134             :                                                        ldb_errstring(ldb));
    1135           0 :                                 return ret;
    1136             :                         }
    1137             : 
    1138             :                         /*
    1139             :                          * TODO: Remaining checks, like if we are
    1140             :                          * the naming master etc need to be handled
    1141             :                          * in the instanceType module
    1142             :                          */
    1143           0 :                         return ldb_next_request(module, req);
    1144             :                 }
    1145             : 
    1146             :                 /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
    1147         356 :                 ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
    1148             :                                                      SEC_ADS_CREATE_CHILD,
    1149             :                                                      &objectclass->schemaIDGUID, req);
    1150         584 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
    1151         228 :                     ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
    1152             :                 {
    1153             :                         /* Allow provision bootstrap */
    1154         228 :                         ret = LDB_SUCCESS;
    1155             :                 }
    1156         356 :                 if (ret != LDB_SUCCESS) {
    1157           0 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1158             :                                                "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
    1159             :                                                ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
    1160           0 :                         return ret;
    1161             :                 }
    1162             : 
    1163             :                 /*
    1164             :                  * TODO: Remaining checks, like if we are the naming
    1165             :                  * master and adding the crossRef object need to be
    1166             :                  * handled in the instanceType module
    1167             :                  */
    1168         356 :                 return ldb_next_request(module, req);
    1169             :         }
    1170             : 
    1171      315707 :         ret = dsdb_module_check_access_on_dn(module, req, parent,
    1172             :                                              SEC_ADS_CREATE_CHILD,
    1173             :                                              &objectclass->schemaIDGUID, req);
    1174      315707 :         if (ret != LDB_SUCCESS) {
    1175          24 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1176             :                                        "acl: unable to get access to %s\n",
    1177          24 :                                        ldb_dn_get_linearized(req->op.add.message->dn));
    1178          24 :                 return ret;
    1179             :         }
    1180      315683 :         return ldb_next_request(module, req);
    1181             : }
    1182             : 
    1183             : /* checks if modifications are allowed on "Member" attribute */
    1184        6253 : static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
    1185             :                                      struct ldb_module *module,
    1186             :                                      struct ldb_request *req,
    1187             :                                      struct security_descriptor *sd,
    1188             :                                      struct dom_sid *sid,
    1189             :                                      const struct dsdb_attribute *attr,
    1190             :                                      const struct dsdb_class *objectclass)
    1191             : {
    1192             :         int ret;
    1193             :         unsigned int i;
    1194        6253 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1195             :         struct ldb_dn *user_dn;
    1196             :         struct ldb_message_element *member_el;
    1197        6253 :         const struct ldb_message *msg = NULL;
    1198             : 
    1199        6253 :         if (req->operation == LDB_MODIFY) {
    1200        6253 :                 msg = req->op.mod.message;
    1201           0 :         } else if (req->operation == LDB_ADD) {
    1202           0 :                 msg = req->op.add.message;
    1203             :         } else {
    1204           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1205             :         }
    1206             : 
    1207             :         /* if we have wp, we can do whatever we like */
    1208        6253 :         if (acl_check_access_on_attribute(module,
    1209             :                                           mem_ctx,
    1210             :                                           sd,
    1211             :                                           sid,
    1212             :                                           SEC_ADS_WRITE_PROP,
    1213             :                                           attr, objectclass) == LDB_SUCCESS) {
    1214        6193 :                 return LDB_SUCCESS;
    1215             :         }
    1216             :         /* if we are adding/deleting ourselves, check for self membership */
    1217          60 :         ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
    1218          60 :                                   &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
    1219             :                                   &user_dn);
    1220          60 :         if (ret != LDB_SUCCESS) {
    1221           0 :                 return ret;
    1222             :         }
    1223          60 :         member_el = ldb_msg_find_element(msg, "member");
    1224          60 :         if (!member_el) {
    1225           0 :                 return ldb_operr(ldb);
    1226             :         }
    1227             :         /* user can only remove oneself */
    1228          60 :         if (member_el->num_values == 0) {
    1229           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1230             :         }
    1231          87 :         for (i = 0; i < member_el->num_values; i++) {
    1232         118 :                 if (strcasecmp((const char *)member_el->values[i].data,
    1233          69 :                                ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
    1234          42 :                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1235             :                 }
    1236             :         }
    1237          18 :         ret = acl_check_extended_right(mem_ctx,
    1238             :                                        module,
    1239             :                                        req,
    1240             :                                        objectclass,
    1241             :                                        sd,
    1242             :                                        acl_user_token(module),
    1243             :                                        GUID_DRS_SELF_MEMBERSHIP,
    1244             :                                        SEC_ADS_SELF_WRITE,
    1245             :                                        sid);
    1246          18 :         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1247           9 :                 dsdb_acl_debug(sd, acl_user_token(module),
    1248           4 :                                msg->dn,
    1249             :                                true,
    1250             :                                10);
    1251             :         }
    1252          18 :         return ret;
    1253             : }
    1254             : 
    1255       12757 : static int acl_check_password_rights(
    1256             :         TALLOC_CTX *mem_ctx,
    1257             :         struct ldb_module *module,
    1258             :         struct ldb_request *req,
    1259             :         struct security_descriptor *sd,
    1260             :         struct dom_sid *sid,
    1261             :         const struct dsdb_class *objectclass,
    1262             :         bool userPassword,
    1263             :         struct  dsdb_control_password_acl_validation **control_for_response)
    1264             : {
    1265       12757 :         int ret = LDB_SUCCESS;
    1266       12757 :         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
    1267       12757 :         unsigned int del_val_cnt = 0, add_val_cnt = 0, rep_val_cnt = 0;
    1268             :         struct ldb_message_element *el;
    1269             :         struct ldb_message *msg;
    1270       12757 :         struct ldb_control *c = NULL;
    1271       12757 :         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
    1272             :                                         "unicodePwd", NULL }, **l;
    1273       12757 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1274       12757 :         struct dsdb_control_password_acl_validation *pav = NULL;
    1275             : 
    1276       12757 :         if (tmp_ctx == NULL) {
    1277           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1278             :         }
    1279             : 
    1280       12757 :         pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
    1281       12757 :         if (pav == NULL) {
    1282           0 :                 talloc_free(tmp_ctx);
    1283           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1284             :         }
    1285             :         /*
    1286             :          * Set control_for_response to pav so it can be added to the response
    1287             :          * and be passed up to the audit_log module which uses it to identify
    1288             :          * password reset attempts.
    1289             :          */
    1290       12757 :         *control_for_response = pav;
    1291             : 
    1292       12757 :         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
    1293       12757 :         if (c != NULL) {
    1294         424 :                 pav->pwd_reset = false;
    1295             : 
    1296             :                 /*
    1297             :                  * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
    1298             :                  * have a user password change and not a set as the message
    1299             :                  * looks like. In it's value blob it contains the NT and/or LM
    1300             :                  * hash of the old password specified by the user.  This control
    1301             :                  * is used by the SAMR and "kpasswd" password change mechanisms.
    1302             :                  *
    1303             :                  * This control can't be used by real LDAP clients,
    1304             :                  * the only caller is samdb_set_password_internal(),
    1305             :                  * so we don't have to strict verification of the input.
    1306             :                  */
    1307         424 :                 ret = acl_check_extended_right(tmp_ctx,
    1308             :                                                module,
    1309             :                                                req,
    1310             :                                                objectclass,
    1311             :                                                sd,
    1312             :                                                acl_user_token(module),
    1313             :                                                GUID_DRS_USER_CHANGE_PASSWORD,
    1314             :                                                SEC_ADS_CONTROL_ACCESS,
    1315             :                                                sid);
    1316         424 :                 goto checked;
    1317             :         }
    1318             : 
    1319       12333 :         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
    1320       12333 :         if (c != NULL) {
    1321         234 :                 pav->pwd_reset = true;
    1322             : 
    1323             :                 /*
    1324             :                  * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
    1325             :                  * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
    1326             :                  * have a force password set.
    1327             :                  * This control is used by the SAMR/NETLOGON/LSA password
    1328             :                  * reset mechanisms.
    1329             :                  *
    1330             :                  * This control can't be used by real LDAP clients,
    1331             :                  * the only caller is samdb_set_password_internal(),
    1332             :                  * so we don't have to strict verification of the input.
    1333             :                  */
    1334         234 :                 ret = acl_check_extended_right(tmp_ctx,
    1335             :                                                module,
    1336             :                                                req,
    1337             :                                                objectclass,
    1338             :                                                sd,
    1339             :                                                acl_user_token(module),
    1340             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1341             :                                                SEC_ADS_CONTROL_ACCESS,
    1342             :                                                sid);
    1343         234 :                 goto checked;
    1344             :         }
    1345             : 
    1346       12099 :         el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
    1347       12099 :         if (el != NULL) {
    1348             :                 /*
    1349             :                  * dBCSPwd is only allowed with a control.
    1350             :                  */
    1351           0 :                 talloc_free(tmp_ctx);
    1352           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1353             :         }
    1354             : 
    1355       12099 :         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
    1356       12099 :         if (msg == NULL) {
    1357           0 :                 return ldb_module_oom(module);
    1358             :         }
    1359       48396 :         for (l = passwordAttrs; *l != NULL; l++) {
    1360       36297 :                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
    1361        9701 :                         continue;
    1362             :                 }
    1363             : 
    1364       58013 :                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
    1365       13821 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
    1366        1729 :                                 ++del_attr_cnt;
    1367        1729 :                                 del_val_cnt += el->num_values;
    1368             :                         }
    1369       13821 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
    1370        1697 :                                 ++add_attr_cnt;
    1371        1697 :                                 add_val_cnt += el->num_values;
    1372             :                         }
    1373       13821 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
    1374       10395 :                                 ++rep_attr_cnt;
    1375       10395 :                                 rep_val_cnt += el->num_values;
    1376             :                         }
    1377       13821 :                         ldb_msg_remove_element(msg, el);
    1378             :                 }
    1379             :         }
    1380             : 
    1381             :         /* single deletes will be handled by the "password_hash" LDB module
    1382             :          * later in the stack, so we let it though here */
    1383       12099 :         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
    1384          49 :                 talloc_free(tmp_ctx);
    1385          49 :                 return LDB_SUCCESS;
    1386             :         }
    1387             : 
    1388             : 
    1389       12050 :         if (rep_attr_cnt > 0) {
    1390       10381 :                 pav->pwd_reset = true;
    1391             : 
    1392       10381 :                 ret = acl_check_extended_right(tmp_ctx,
    1393             :                                                module,
    1394             :                                                req,
    1395             :                                                objectclass,
    1396             :                                                sd,
    1397             :                                                acl_user_token(module),
    1398             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1399             :                                                SEC_ADS_CONTROL_ACCESS,
    1400             :                                                sid);
    1401       10381 :                 goto checked;
    1402             :         }
    1403             : 
    1404        1669 :         if (add_attr_cnt != del_attr_cnt) {
    1405          81 :                 pav->pwd_reset = true;
    1406             : 
    1407          81 :                 ret = acl_check_extended_right(tmp_ctx,
    1408             :                                                module,
    1409             :                                                req,
    1410             :                                                objectclass,
    1411             :                                                sd,
    1412             :                                                acl_user_token(module),
    1413             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1414             :                                                SEC_ADS_CONTROL_ACCESS,
    1415             :                                                sid);
    1416          81 :                 goto checked;
    1417             :         }
    1418             : 
    1419        1588 :         if (add_val_cnt == 1 && del_val_cnt == 1) {
    1420         925 :                 pav->pwd_reset = false;
    1421             : 
    1422         925 :                 ret = acl_check_extended_right(tmp_ctx,
    1423             :                                                module,
    1424             :                                                req,
    1425             :                                                objectclass,
    1426             :                                                sd,
    1427             :                                                acl_user_token(module),
    1428             :                                                GUID_DRS_USER_CHANGE_PASSWORD,
    1429             :                                                SEC_ADS_CONTROL_ACCESS,
    1430             :                                                sid);
    1431             :                 /* Very strange, but we get constraint violation in this case */
    1432         925 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1433          18 :                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
    1434             :                 }
    1435         925 :                 goto checked;
    1436             :         }
    1437             : 
    1438         663 :         if (add_val_cnt == 1 && del_val_cnt == 0) {
    1439         453 :                 pav->pwd_reset = true;
    1440             : 
    1441         453 :                 ret = acl_check_extended_right(tmp_ctx,
    1442             :                                                module,
    1443             :                                                req,
    1444             :                                                objectclass,
    1445             :                                                sd,
    1446             :                                                acl_user_token(module),
    1447             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1448             :                                                SEC_ADS_CONTROL_ACCESS,
    1449             :                                                sid);
    1450             :                 /* Very strange, but we get constraint violation in this case */
    1451         453 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1452          21 :                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
    1453             :                 }
    1454         453 :                 goto checked;
    1455             :         }
    1456             : 
    1457             :         /*
    1458             :          * Everything else is handled by the password_hash module where it will
    1459             :          * fail, but with the correct error code when the module is again
    1460             :          * checking the attributes. As the change request will lack the
    1461             :          * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
    1462             :          * any modification attempt that went this way will be rejected.
    1463             :          */
    1464             : 
    1465         210 :         talloc_free(tmp_ctx);
    1466         210 :         return LDB_SUCCESS;
    1467             : 
    1468       12498 : checked:
    1469       12498 :         if (ret != LDB_SUCCESS) {
    1470         123 :                 dsdb_acl_debug(sd, acl_user_token(module),
    1471         123 :                                req->op.mod.message->dn,
    1472             :                                true,
    1473             :                                10);
    1474         123 :                 talloc_free(tmp_ctx);
    1475         123 :                 return ret;
    1476             :         }
    1477             : 
    1478       12375 :         ret = ldb_request_add_control(req,
    1479             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
    1480       12375 :         if (ret != LDB_SUCCESS) {
    1481           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
    1482             :                           "Unable to register ACL validation control!\n");
    1483           0 :                 return ret;
    1484             :         }
    1485       12375 :         return LDB_SUCCESS;
    1486             : }
    1487             : 
    1488             : /*
    1489             :  * Context needed by acl_callback
    1490             :  */
    1491             : struct acl_callback_context {
    1492             :         struct ldb_request *request;
    1493             :         struct ldb_module *module;
    1494             : };
    1495             : 
    1496             : /*
    1497             :  * @brief Copy the password validation control to the reply.
    1498             :  *
    1499             :  * Copy the dsdb_control_password_acl_validation control from the request,
    1500             :  * to the reply.  The control is used by the audit_log module to identify
    1501             :  * password rests.
    1502             :  *
    1503             :  * @param req the ldb request.
    1504             :  * @param ares the result, updated with the control.
    1505             :  */
    1506       85379 : static void copy_password_acl_validation_control(
    1507             :         struct ldb_request *req,
    1508             :         struct ldb_reply *ares)
    1509             : {
    1510       85379 :         struct ldb_control *pav_ctrl = NULL;
    1511       85379 :         struct dsdb_control_password_acl_validation *pav = NULL;
    1512             : 
    1513       85379 :         pav_ctrl = ldb_request_get_control(
    1514             :                 discard_const(req),
    1515             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
    1516       85379 :         if (pav_ctrl == NULL) {
    1517       73004 :                 return;
    1518             :         }
    1519             : 
    1520       12375 :         pav = talloc_get_type_abort(
    1521             :                 pav_ctrl->data,
    1522             :                 struct dsdb_control_password_acl_validation);
    1523       12375 :         if (pav == NULL) {
    1524           0 :                 return;
    1525             :         }
    1526       12375 :         ldb_reply_add_control(
    1527             :                 ares,
    1528             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
    1529             :                 false,
    1530             :                 pav);
    1531             : }
    1532             : /*
    1533             :  * @brief call back function for acl_modify.
    1534             :  *
    1535             :  * Calls acl_copy to copy the dsdb_control_password_acl_validation from
    1536             :  * the request to the reply.
    1537             :  *
    1538             :  * @param req the ldb_request.
    1539             :  * @param ares the operation result.
    1540             :  *
    1541             :  * @return the LDB_STATUS
    1542             :  */
    1543       85389 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
    1544             : {
    1545       85389 :         struct acl_callback_context *ac = NULL;
    1546             : 
    1547       85389 :         ac = talloc_get_type(req->context, struct acl_callback_context);
    1548             : 
    1549       85389 :         if (!ares) {
    1550           0 :                 return ldb_module_done(
    1551             :                         ac->request,
    1552             :                         NULL,
    1553             :                         NULL,
    1554             :                         LDB_ERR_OPERATIONS_ERROR);
    1555             :         }
    1556             : 
    1557             :         /* pass on to the callback */
    1558       85389 :         switch (ares->type) {
    1559           0 :         case LDB_REPLY_ENTRY:
    1560           0 :                 return ldb_module_send_entry(
    1561             :                         ac->request,
    1562             :                         ares->message,
    1563             :                         ares->controls);
    1564             : 
    1565          10 :         case LDB_REPLY_REFERRAL:
    1566          10 :                 return ldb_module_send_referral(
    1567             :                         ac->request,
    1568             :                         ares->referral);
    1569             : 
    1570       85379 :         case LDB_REPLY_DONE:
    1571             :                 /*
    1572             :                  * Copy the ACL control from the request to the response
    1573             :                  */
    1574       85379 :                 copy_password_acl_validation_control(req, ares);
    1575       85379 :                 return ldb_module_done(
    1576             :                         ac->request,
    1577             :                         ares->controls,
    1578             :                         ares->response,
    1579             :                         ares->error);
    1580             : 
    1581           0 :         default:
    1582             :                 /* Can't happen */
    1583           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1584             :         }
    1585             : }
    1586             : 
    1587      366347 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
    1588             : {
    1589             :         int ret;
    1590      366347 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1591             :         const struct dsdb_schema *schema;
    1592             :         unsigned int i;
    1593             :         const struct dsdb_class *objectclass;
    1594             :         struct ldb_result *acl_res;
    1595             :         struct security_descriptor *sd;
    1596      366347 :         struct dom_sid *sid = NULL;
    1597             :         struct ldb_control *as_system;
    1598             :         struct ldb_control *is_undelete;
    1599      366347 :         struct ldb_control *implicit_validated_write_control = NULL;
    1600             :         bool userPassword;
    1601      366347 :         bool password_rights_checked = false;
    1602             :         TALLOC_CTX *tmp_ctx;
    1603      366347 :         const struct ldb_message *msg = req->op.mod.message;
    1604             :         static const char *acl_attrs[] = {
    1605             :                 "nTSecurityDescriptor",
    1606             :                 "objectClass",
    1607             :                 "objectSid",
    1608             :                 NULL
    1609             :         };
    1610      366347 :         struct acl_callback_context *context = NULL;
    1611      366347 :         struct ldb_request *new_req = NULL;
    1612      366347 :         struct  dsdb_control_password_acl_validation *pav = NULL;
    1613      366347 :         struct ldb_control **controls = NULL;
    1614             : 
    1615      366347 :         if (ldb_dn_is_special(msg->dn)) {
    1616         558 :                 return ldb_next_request(module, req);
    1617             :         }
    1618             : 
    1619      365789 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    1620      365789 :         if (as_system != NULL) {
    1621      123635 :                 as_system->critical = 0;
    1622             :         }
    1623             : 
    1624      365789 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    1625             : 
    1626      365789 :         implicit_validated_write_control = ldb_request_get_control(
    1627             :                 req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
    1628      365789 :         if (implicit_validated_write_control != NULL) {
    1629          84 :                 implicit_validated_write_control->critical = 0;
    1630             :         }
    1631             : 
    1632             :         /* Don't print this debug statement if elements[0].name is going to be NULL */
    1633      365789 :         if (msg->num_elements > 0) {
    1634      365508 :                 DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
    1635             :         }
    1636      365789 :         if (dsdb_module_am_system(module) || as_system) {
    1637      278852 :                 return ldb_next_request(module, req);
    1638             :         }
    1639             : 
    1640       86937 :         tmp_ctx = talloc_new(req);
    1641       86937 :         if (tmp_ctx == NULL) {
    1642           0 :                 return ldb_oom(ldb);
    1643             :         }
    1644             : 
    1645       86937 :         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
    1646             :                                     acl_attrs,
    1647             :                                     DSDB_FLAG_NEXT_MODULE |
    1648             :                                     DSDB_FLAG_AS_SYSTEM |
    1649             :                                     DSDB_SEARCH_SHOW_RECYCLED,
    1650             :                                     req);
    1651             : 
    1652       86937 :         if (ret != LDB_SUCCESS) {
    1653         121 :                 goto fail;
    1654             :         }
    1655             : 
    1656       86816 :         userPassword = dsdb_user_password_support(module, req, req);
    1657             : 
    1658       86816 :         schema = dsdb_get_schema(ldb, tmp_ctx);
    1659       86816 :         if (!schema) {
    1660           0 :                 talloc_free(tmp_ctx);
    1661           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1662             :                                  "acl_modify: Error obtaining schema.");
    1663             :         }
    1664             : 
    1665       86816 :         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
    1666       86816 :         if (ret != LDB_SUCCESS) {
    1667           0 :                 talloc_free(tmp_ctx);
    1668           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1669             :                                  "acl_modify: Error retrieving security descriptor.");
    1670             :         }
    1671             :         /* Theoretically we pass the check if the object has no sd */
    1672       86816 :         if (!sd) {
    1673           0 :                 goto success;
    1674             :         }
    1675             : 
    1676       86816 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    1677       86816 :         if (!objectclass) {
    1678           0 :                 talloc_free(tmp_ctx);
    1679           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1680             :                                  "acl_modify: Error retrieving object class for GUID.");
    1681             :         }
    1682       86816 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    1683      198188 :         for (i=0; i < msg->num_elements; i++) {
    1684      112807 :                 const struct ldb_message_element *el = &msg->elements[i];
    1685             :                 const struct dsdb_attribute *attr;
    1686             : 
    1687             :                 /*
    1688             :                  * This basic attribute existence check with the right errorcode
    1689             :                  * is needed since this module is the first one which requests
    1690             :                  * schema attribute information.
    1691             :                  * The complete attribute checking is done in the
    1692             :                  * "objectclass_attrs" module behind this one.
    1693             :                  *
    1694             :                  * NOTE: "clearTextPassword" is not defined in the schema.
    1695             :                  */
    1696      112807 :                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
    1697      112807 :                 if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
    1698           4 :                         ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
    1699             :                                                "on entry '%s' was not found in the schema!",
    1700           2 :                                                req->op.mod.message->elements[i].name,
    1701           2 :                                        ldb_dn_get_linearized(req->op.mod.message->dn));
    1702           2 :                         ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
    1703           2 :                         goto fail;
    1704             :                 }
    1705             : 
    1706      112805 :                 if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
    1707       25232 :                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
    1708       25232 :                         uint32_t access_mask = 0;
    1709             : 
    1710       25232 :                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
    1711       11381 :                                 access_mask |= SEC_STD_WRITE_OWNER;
    1712             :                         }
    1713       25232 :                         if (sd_flags & SECINFO_DACL) {
    1714       25145 :                                 access_mask |= SEC_STD_WRITE_DAC;
    1715             :                         }
    1716       25232 :                         if (sd_flags & SECINFO_SACL) {
    1717       11312 :                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
    1718             :                         }
    1719             : 
    1720       25232 :                         ret = acl_check_access_on_attribute(module,
    1721             :                                                             tmp_ctx,
    1722             :                                                             sd,
    1723             :                                                             sid,
    1724             :                                                             access_mask,
    1725             :                                                             attr,
    1726             :                                                             objectclass);
    1727       25232 :                         if (ret != LDB_SUCCESS) {
    1728           0 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1729             :                                                        "Object %s has no write dacl access\n",
    1730           0 :                                                        ldb_dn_get_linearized(msg->dn));
    1731           0 :                                 dsdb_acl_debug(sd,
    1732             :                                                acl_user_token(module),
    1733           0 :                                                msg->dn,
    1734             :                                                true,
    1735             :                                                10);
    1736           0 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1737           0 :                                 goto fail;
    1738             :                         }
    1739       87573 :                 } else if (ldb_attr_cmp("member", el->name) == 0) {
    1740        6253 :                         ret = acl_check_self_membership(tmp_ctx,
    1741             :                                                         module,
    1742             :                                                         req,
    1743             :                                                         sd,
    1744             :                                                         sid,
    1745             :                                                         attr,
    1746             :                                                         objectclass);
    1747        6253 :                         if (ret != LDB_SUCCESS) {
    1748          51 :                                 goto fail;
    1749             :                         }
    1750       81320 :                 } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
    1751             :                         /* this one is not affected by any rights, we should let it through
    1752             :                            so that passwords_hash returns the correct error */
    1753          60 :                         continue;
    1754       81260 :                 } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
    1755       58633 :                            (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
    1756       68009 :                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
    1757             :                         /*
    1758             :                          * Ideally we would do the acl_check_password_rights
    1759             :                          * before we checked the other attributes, i.e. in a
    1760             :                          * loop before the current one.
    1761             :                          * Have not done this as yet in order to limit the size
    1762             :                          * of the change. To limit the possibility of breaking
    1763             :                          * the ACL logic.
    1764             :                          */
    1765       14380 :                         if (password_rights_checked) {
    1766        1623 :                                 continue;
    1767             :                         }
    1768       12757 :                         ret = acl_check_password_rights(tmp_ctx,
    1769             :                                                         module,
    1770             :                                                         req,
    1771             :                                                         sd,
    1772             :                                                         sid,
    1773             :                                                         objectclass,
    1774             :                                                         userPassword,
    1775             :                                                         &pav);
    1776       12757 :                         if (ret != LDB_SUCCESS) {
    1777         123 :                                 goto fail;
    1778             :                         }
    1779       12634 :                         password_rights_checked = true;
    1780       66880 :                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
    1781        1269 :                         ret = acl_check_spn(tmp_ctx,
    1782             :                                             module,
    1783             :                                             req,
    1784             :                                             el,
    1785             :                                             sd,
    1786             :                                             sid,
    1787             :                                             attr,
    1788             :                                             objectclass,
    1789             :                                             implicit_validated_write_control);
    1790        1269 :                         if (ret != LDB_SUCCESS) {
    1791         216 :                                 goto fail;
    1792             :                         }
    1793       65611 :                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
    1794         645 :                         ret = acl_check_dns_host_name(tmp_ctx,
    1795             :                                                       module,
    1796             :                                                       req,
    1797             :                                                       el,
    1798             :                                                       sd,
    1799             :                                                       sid,
    1800             :                                                       attr,
    1801             :                                                       objectclass,
    1802             :                                                       implicit_validated_write_control);
    1803         645 :                         if (ret != LDB_SUCCESS) {
    1804         171 :                                 goto fail;
    1805             :                         }
    1806       64966 :                 } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
    1807             :                         /*
    1808             :                          * in case of undelete op permissions on
    1809             :                          * isDeleted are irrelevant and
    1810             :                          * distinguishedName is removed by the
    1811             :                          * tombstone_reanimate module
    1812             :                          */
    1813         274 :                         continue;
    1814       64692 :                 } else if (implicit_validated_write_control != NULL) {
    1815             :                         /* Allow the update. */
    1816         252 :                         continue;
    1817             :                 } else {
    1818       64440 :                         ret = acl_check_access_on_attribute(module,
    1819             :                                                             tmp_ctx,
    1820             :                                                             sd,
    1821             :                                                             sid,
    1822             :                                                             SEC_ADS_WRITE_PROP,
    1823             :                                                             attr,
    1824             :                                                             objectclass);
    1825       64440 :                         if (ret != LDB_SUCCESS) {
    1826         872 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1827             :                                                        "Object %s has no write property access\n",
    1828          37 :                                                        ldb_dn_get_linearized(msg->dn));
    1829         872 :                                 dsdb_acl_debug(sd,
    1830             :                                                acl_user_token(module),
    1831          37 :                                                msg->dn,
    1832             :                                                true,
    1833             :                                                10);
    1834         872 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1835         872 :                                 goto fail;
    1836             :                         }
    1837             :                 }
    1838             :         }
    1839             : 
    1840       85381 : success:
    1841       85381 :         talloc_free(tmp_ctx);
    1842       85381 :         context = talloc_zero(req, struct acl_callback_context);
    1843             : 
    1844       85381 :         if (context == NULL) {
    1845           0 :                 return ldb_oom(ldb);
    1846             :         }
    1847       85381 :         context->request = req;
    1848       85381 :         context->module  = module;
    1849       85381 :         ret = ldb_build_mod_req(
    1850             :                 &new_req,
    1851             :                 ldb,
    1852             :                 req,
    1853             :                 req->op.mod.message,
    1854             :                 req->controls,
    1855             :                 context,
    1856             :                 acl_callback,
    1857             :                 req);
    1858       85381 :         if (ret != LDB_SUCCESS) {
    1859           0 :                 return ret;
    1860             :         }
    1861       85381 :         return ldb_next_request(module, new_req);
    1862        1556 : fail:
    1863        1556 :         talloc_free(tmp_ctx);
    1864             :         /*
    1865             :          * We copy the pav into the result, so that the password reset
    1866             :          * logging code in audit_log can log failed password reset attempts.
    1867             :          */
    1868        1556 :         if (pav) {
    1869         123 :                 struct ldb_control *control = NULL;
    1870             : 
    1871         123 :                 controls = talloc_zero_array(req, struct ldb_control *, 2);
    1872         123 :                 if (controls == NULL) {
    1873           0 :                         return ldb_oom(ldb);
    1874             :                 }
    1875             : 
    1876         123 :                 control = talloc(controls, struct ldb_control);
    1877             : 
    1878         123 :                 if (control == NULL) {
    1879           0 :                         return ldb_oom(ldb);
    1880             :                 }
    1881             : 
    1882         123 :                 control->oid= talloc_strdup(
    1883             :                         control,
    1884             :                         DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
    1885         123 :                 if (control->oid == NULL) {
    1886           0 :                         return ldb_oom(ldb);
    1887             :                 }
    1888         123 :                 control->critical    = false;
    1889         123 :                 control->data        = pav;
    1890         123 :                 *controls = control;
    1891             :         }
    1892        1556 :         return ldb_module_done(req, controls, NULL, ret);
    1893             : }
    1894             : 
    1895             : /* similar to the modify for the time being.
    1896             :  * We need to consider the special delete tree case, though - TODO */
    1897       47753 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
    1898             : {
    1899             :         int ret;
    1900             :         struct ldb_dn *parent;
    1901             :         struct ldb_context *ldb;
    1902             :         struct ldb_dn *nc_root;
    1903             :         struct ldb_control *as_system;
    1904             :         const struct dsdb_schema *schema;
    1905             :         const struct dsdb_class *objectclass;
    1906       47753 :         struct security_descriptor *sd = NULL;
    1907       47753 :         struct dom_sid *sid = NULL;
    1908             :         struct ldb_result *acl_res;
    1909             :         static const char *acl_attrs[] = {
    1910             :                 "nTSecurityDescriptor",
    1911             :                 "objectClass",
    1912             :                 "objectSid",
    1913             :                 NULL
    1914             :         };
    1915             : 
    1916       47753 :         if (ldb_dn_is_special(req->op.del.dn)) {
    1917           1 :                 return ldb_next_request(module, req);
    1918             :         }
    1919             : 
    1920       47752 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    1921       47752 :         if (as_system != NULL) {
    1922       18377 :                 as_system->critical = 0;
    1923             :         }
    1924             : 
    1925       47752 :         if (dsdb_module_am_system(module) || as_system) {
    1926       19483 :                 return ldb_next_request(module, req);
    1927             :         }
    1928             : 
    1929       28269 :         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
    1930             : 
    1931       28269 :         ldb = ldb_module_get_ctx(module);
    1932             : 
    1933       28269 :         parent = ldb_dn_get_parent(req, req->op.del.dn);
    1934       28269 :         if (parent == NULL) {
    1935           0 :                 return ldb_oom(ldb);
    1936             :         }
    1937             : 
    1938             :         /* Make sure we aren't deleting a NC */
    1939             : 
    1940       28269 :         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
    1941       28269 :         if (ret != LDB_SUCCESS) {
    1942           0 :                 return ret;
    1943             :         }
    1944       28269 :         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
    1945           0 :                 talloc_free(nc_root);
    1946           0 :                 DEBUG(10,("acl:deleting a NC\n"));
    1947             :                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
    1948           0 :                 return ldb_module_done(req, NULL, NULL,
    1949             :                                        LDB_ERR_UNWILLING_TO_PERFORM);
    1950             :         }
    1951       28269 :         talloc_free(nc_root);
    1952             : 
    1953       28269 :         ret = dsdb_module_search_dn(module, req, &acl_res,
    1954             :                                     req->op.del.dn, acl_attrs,
    1955             :                                     DSDB_FLAG_NEXT_MODULE |
    1956             :                                     DSDB_FLAG_AS_SYSTEM |
    1957             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    1958             :         /* we sould be able to find the parent */
    1959       28269 :         if (ret != LDB_SUCCESS) {
    1960           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    1961             :                           ldb_dn_get_linearized(req->op.rename.olddn)));
    1962           0 :                 return ret;
    1963             :         }
    1964             : 
    1965       28269 :         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
    1966       28269 :         if (ret != LDB_SUCCESS) {
    1967           0 :                 return ldb_operr(ldb);
    1968             :         }
    1969       28269 :         if (!sd) {
    1970           0 :                 return ldb_operr(ldb);
    1971             :         }
    1972             : 
    1973       28269 :         schema = dsdb_get_schema(ldb, req);
    1974       28269 :         if (!schema) {
    1975           0 :                 return ldb_operr(ldb);
    1976             :         }
    1977             : 
    1978       28269 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    1979             : 
    1980       28269 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    1981       28269 :         if (!objectclass) {
    1982           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1983             :                                  "acl_modify: Error retrieving object class for GUID.");
    1984             :         }
    1985             : 
    1986       28269 :         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
    1987        2402 :                 ret = acl_check_access_on_objectclass(module, req, sd, sid,
    1988             :                                                       SEC_ADS_DELETE_TREE,
    1989             :                                                       objectclass);
    1990        2402 :                 if (ret != LDB_SUCCESS) {
    1991           0 :                         return ret;
    1992             :                 }
    1993             : 
    1994        2402 :                 return ldb_next_request(module, req);
    1995             :         }
    1996             : 
    1997             :         /* First check if we have delete object right */
    1998       25867 :         ret = acl_check_access_on_objectclass(module, req, sd, sid,
    1999             :                                               SEC_STD_DELETE,
    2000             :                                               objectclass);
    2001       25867 :         if (ret == LDB_SUCCESS) {
    2002       25664 :                 return ldb_next_request(module, req);
    2003             :         }
    2004             : 
    2005             :         /* Nope, we don't have delete object. Lets check if we have delete
    2006             :          * child on the parent */
    2007         203 :         ret = dsdb_module_check_access_on_dn(module, req, parent,
    2008             :                                              SEC_ADS_DELETE_CHILD,
    2009             :                                              &objectclass->schemaIDGUID,
    2010             :                                              req);
    2011         203 :         if (ret != LDB_SUCCESS) {
    2012          10 :                 return ret;
    2013             :         }
    2014             : 
    2015         193 :         return ldb_next_request(module, req);
    2016             : }
    2017         265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
    2018             :                                          struct ldb_module *module,
    2019             :                                          struct ldb_request *req,
    2020             :                                          struct ldb_dn *nc_root)
    2021             : {
    2022             :         int ret;
    2023             :         struct ldb_result *acl_res;
    2024         265 :         struct security_descriptor *sd = NULL;
    2025         265 :         struct dom_sid *sid = NULL;
    2026         265 :         const struct dsdb_schema *schema = NULL;
    2027         265 :         const struct dsdb_class *objectclass = NULL;
    2028         265 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    2029             :         static const char *acl_attrs[] = {
    2030             :                 "nTSecurityDescriptor",
    2031             :                 "objectClass",
    2032             :                 "objectSid",
    2033             :                 NULL
    2034             :         };
    2035             : 
    2036         265 :         ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
    2037             :                                     nc_root, acl_attrs,
    2038             :                                     DSDB_FLAG_NEXT_MODULE |
    2039             :                                     DSDB_FLAG_AS_SYSTEM |
    2040             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2041         265 :         if (ret != LDB_SUCCESS) {
    2042           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2043             :                           ldb_dn_get_linearized(nc_root)));
    2044           0 :                 return ret;
    2045             :         }
    2046             : 
    2047         265 :         ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
    2048         265 :         sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
    2049         265 :         schema = dsdb_get_schema(ldb, req);
    2050         265 :         if (!schema) {
    2051           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    2052             :         }
    2053         265 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2054         265 :         if (ret != LDB_SUCCESS || !sd) {
    2055           0 :                 return ldb_operr(ldb_module_get_ctx(module));
    2056             :         }
    2057         265 :         return acl_check_extended_right(mem_ctx,
    2058             :                                         module,
    2059             :                                         req,
    2060             :                                         objectclass,
    2061             :                                         sd,
    2062             :                                         acl_user_token(module),
    2063             :                                         GUID_DRS_REANIMATE_TOMBSTONE,
    2064             :                                         SEC_ADS_CONTROL_ACCESS, sid);
    2065             : }
    2066             : 
    2067         925 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
    2068             : {
    2069             :         int ret;
    2070             :         struct ldb_dn *oldparent;
    2071             :         struct ldb_dn *newparent;
    2072             :         const struct dsdb_schema *schema;
    2073             :         const struct dsdb_class *objectclass;
    2074         925 :         const struct dsdb_attribute *attr = NULL;
    2075             :         struct ldb_context *ldb;
    2076         925 :         struct security_descriptor *sd = NULL;
    2077         925 :         struct dom_sid *sid = NULL;
    2078             :         struct ldb_result *acl_res;
    2079             :         struct ldb_dn *nc_root;
    2080             :         struct ldb_control *as_system;
    2081             :         struct ldb_control *is_undelete;
    2082             :         TALLOC_CTX *tmp_ctx;
    2083             :         const char *rdn_name;
    2084             :         static const char *acl_attrs[] = {
    2085             :                 "nTSecurityDescriptor",
    2086             :                 "objectClass",
    2087             :                 "objectSid",
    2088             :                 NULL
    2089             :         };
    2090             : 
    2091         925 :         if (ldb_dn_is_special(req->op.rename.olddn)) {
    2092           0 :                 return ldb_next_request(module, req);
    2093             :         }
    2094             : 
    2095         925 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    2096         925 :         if (as_system != NULL) {
    2097           0 :                 as_system->critical = 0;
    2098             :         }
    2099             : 
    2100         925 :         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
    2101         925 :         if (dsdb_module_am_system(module) || as_system) {
    2102         312 :                 return ldb_next_request(module, req);
    2103             :         }
    2104             : 
    2105         613 :         ldb = ldb_module_get_ctx(module);
    2106             : 
    2107         613 :         tmp_ctx = talloc_new(req);
    2108         613 :         if (tmp_ctx == NULL) {
    2109           0 :                 return ldb_oom(ldb);
    2110             :         }
    2111             : 
    2112         613 :         oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
    2113         613 :         if (oldparent == NULL) {
    2114           0 :                 return ldb_oom(ldb);
    2115             :         }
    2116         613 :         newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
    2117         613 :         if (newparent == NULL) {
    2118           0 :                 return ldb_oom(ldb);
    2119             :         }
    2120             : 
    2121             :         /* Make sure we aren't renaming/moving a NC */
    2122             : 
    2123         613 :         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
    2124         613 :         if (ret != LDB_SUCCESS) {
    2125           0 :                 return ret;
    2126             :         }
    2127         613 :         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
    2128           0 :                 talloc_free(nc_root);
    2129           0 :                 DEBUG(10,("acl:renaming/moving a NC\n"));
    2130             :                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
    2131           0 :                 return ldb_module_done(req, NULL, NULL,
    2132             :                                        LDB_ERR_UNWILLING_TO_PERFORM);
    2133             :         }
    2134             : 
    2135             :         /* special check for undelete operation */
    2136         613 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    2137         613 :         if (is_undelete != NULL) {
    2138         265 :                 is_undelete->critical = 0;
    2139         265 :                 ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
    2140         265 :                 if (ret != LDB_SUCCESS) {
    2141           9 :                         talloc_free(tmp_ctx);
    2142           9 :                         return ret;
    2143             :                 }
    2144             :         }
    2145         604 :         talloc_free(nc_root);
    2146             : 
    2147             :         /* Look for the parent */
    2148             : 
    2149         604 :         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
    2150             :                                     req->op.rename.olddn, acl_attrs,
    2151             :                                     DSDB_FLAG_NEXT_MODULE |
    2152             :                                     DSDB_FLAG_AS_SYSTEM |
    2153             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2154             :         /* we sould be able to find the parent */
    2155         604 :         if (ret != LDB_SUCCESS) {
    2156           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2157             :                           ldb_dn_get_linearized(req->op.rename.olddn)));
    2158           0 :                 talloc_free(tmp_ctx);
    2159           0 :                 return ret;
    2160             :         }
    2161             : 
    2162         604 :         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
    2163         604 :         if (ret != LDB_SUCCESS) {
    2164           0 :                 talloc_free(tmp_ctx);
    2165           0 :                 return ldb_operr(ldb);
    2166             :         }
    2167         604 :         if (!sd) {
    2168           0 :                 talloc_free(tmp_ctx);
    2169           0 :                 return ldb_operr(ldb);
    2170             :         }
    2171             : 
    2172         604 :         schema = dsdb_get_schema(ldb, acl_res);
    2173         604 :         if (!schema) {
    2174           0 :                 talloc_free(tmp_ctx);
    2175           0 :                 return ldb_operr(ldb);
    2176             :         }
    2177             : 
    2178         604 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    2179             : 
    2180         604 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2181         604 :         if (!objectclass) {
    2182           0 :                 talloc_free(tmp_ctx);
    2183           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2184             :                                  "acl_modify: Error retrieving object class for GUID.");
    2185             :         }
    2186             : 
    2187         604 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
    2188         604 :         if (attr == NULL) {
    2189           0 :                 talloc_free(tmp_ctx);
    2190           0 :                 return ldb_operr(ldb);
    2191             :         }
    2192             : 
    2193         604 :         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
    2194             :                                             SEC_ADS_WRITE_PROP,
    2195             :                                             attr, objectclass);
    2196         604 :         if (ret != LDB_SUCCESS) {
    2197          19 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2198             :                                        "Object %s has no wp on %s\n",
    2199             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    2200           8 :                                        attr->lDAPDisplayName);
    2201          19 :                 dsdb_acl_debug(sd,
    2202             :                           acl_user_token(module),
    2203             :                           req->op.rename.olddn,
    2204             :                           true,
    2205             :                           10);
    2206          19 :                 talloc_free(tmp_ctx);
    2207          19 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2208             :         }
    2209             : 
    2210         585 :         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
    2211         585 :         if (rdn_name == NULL) {
    2212           0 :                 talloc_free(tmp_ctx);
    2213           0 :                 return ldb_operr(ldb);
    2214             :         }
    2215             : 
    2216         585 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
    2217         585 :         if (attr == NULL) {
    2218           0 :                 talloc_free(tmp_ctx);
    2219           0 :                 return ldb_operr(ldb);
    2220             :         }
    2221             : 
    2222         585 :         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
    2223             :                                             SEC_ADS_WRITE_PROP,
    2224             :                                             attr, objectclass);
    2225         585 :         if (ret != LDB_SUCCESS) {
    2226           9 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2227             :                                        "Object %s has no wp on %s\n",
    2228             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    2229           4 :                                        attr->lDAPDisplayName);
    2230           9 :                 dsdb_acl_debug(sd,
    2231             :                           acl_user_token(module),
    2232             :                           req->op.rename.olddn,
    2233             :                           true,
    2234             :                           10);
    2235           9 :                 talloc_free(tmp_ctx);
    2236           9 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2237             :         }
    2238             : 
    2239         576 :         if (ldb_dn_compare(oldparent, newparent) == 0) {
    2240             :                 /* regular rename, not move, nothing more to do */
    2241         207 :                 talloc_free(tmp_ctx);
    2242         207 :                 return ldb_next_request(module, req);
    2243             :         }
    2244             : 
    2245             :         /* new parent should have create child */
    2246         369 :         ret = dsdb_module_check_access_on_dn(module, req, newparent,
    2247             :                                              SEC_ADS_CREATE_CHILD,
    2248             :                                              &objectclass->schemaIDGUID, req);
    2249         369 :         if (ret != LDB_SUCCESS) {
    2250           9 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2251             :                                        "acl:access_denied renaming %s",
    2252             :                                        ldb_dn_get_linearized(req->op.rename.olddn));
    2253           9 :                 talloc_free(tmp_ctx);
    2254           9 :                 return ret;
    2255             :         }
    2256             : 
    2257             :         /* do we have delete object on the object? */
    2258             :         /* this access is not necessary for undelete ops */
    2259         360 :         if (is_undelete == NULL) {
    2260         126 :                 ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
    2261             :                                                       SEC_STD_DELETE,
    2262             :                                                       objectclass);
    2263         126 :                 if (ret == LDB_SUCCESS) {
    2264          99 :                         talloc_free(tmp_ctx);
    2265          99 :                         return ldb_next_request(module, req);
    2266             :                 }
    2267             :                 /* what about delete child on the current parent */
    2268          27 :                 ret = dsdb_module_check_access_on_dn(module, req, oldparent,
    2269             :                                                      SEC_ADS_DELETE_CHILD,
    2270             :                                                      &objectclass->schemaIDGUID,
    2271             :                                                      req);
    2272          27 :                 if (ret != LDB_SUCCESS) {
    2273           9 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2274             :                                                "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
    2275           9 :                         talloc_free(tmp_ctx);
    2276           9 :                         return ldb_module_done(req, NULL, NULL, ret);
    2277             :                 }
    2278             :         }
    2279         252 :         talloc_free(tmp_ctx);
    2280             : 
    2281         252 :         return ldb_next_request(module, req);
    2282             : }
    2283             : 
    2284      609924 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
    2285             :                                                 struct acl_private *data)
    2286             : {
    2287             :         struct dsdb_attribute *a;
    2288      609924 :         uint32_t n = 0;
    2289             : 
    2290      609924 :         if (data->acl_search) {
    2291             :                 /*
    2292             :                  * If acl:search is activated, the acl_read module
    2293             :                  * protects confidential attributes.
    2294             :                  */
    2295      609924 :                 return LDB_SUCCESS;
    2296             :         }
    2297             : 
    2298           0 :         if ((ac->schema == data->cached_schema_ptr) &&
    2299           0 :             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
    2300             :         {
    2301           0 :                 return LDB_SUCCESS;
    2302             :         }
    2303             : 
    2304           0 :         data->cached_schema_ptr = NULL;
    2305           0 :         data->cached_schema_loaded_usn = 0;
    2306           0 :         data->cached_schema_metadata_usn = 0;
    2307           0 :         TALLOC_FREE(data->confidential_attrs);
    2308             : 
    2309           0 :         if (ac->schema == NULL) {
    2310           0 :                 return LDB_SUCCESS;
    2311             :         }
    2312             : 
    2313           0 :         for (a = ac->schema->attributes; a; a = a->next) {
    2314           0 :                 const char **attrs = data->confidential_attrs;
    2315             : 
    2316           0 :                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
    2317           0 :                         continue;
    2318             :                 }
    2319             : 
    2320           0 :                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
    2321           0 :                 if (attrs == NULL) {
    2322           0 :                         TALLOC_FREE(data->confidential_attrs);
    2323           0 :                         return ldb_module_oom(ac->module);
    2324             :                 }
    2325             : 
    2326           0 :                 attrs[n] = a->lDAPDisplayName;
    2327           0 :                 attrs[n+1] = NULL;
    2328           0 :                 n++;
    2329             : 
    2330           0 :                 data->confidential_attrs = attrs;
    2331             :         }
    2332             : 
    2333           0 :         data->cached_schema_ptr = ac->schema;
    2334           0 :         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
    2335             : 
    2336           0 :         return LDB_SUCCESS;
    2337             : }
    2338             : 
    2339    33274425 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
    2340             : {
    2341             :         struct acl_context *ac;
    2342             :         struct acl_private *data;
    2343             :         struct ldb_result *acl_res;
    2344             :         static const char *acl_attrs[] = {
    2345             :                 "objectClass",
    2346             :                 "nTSecurityDescriptor",
    2347             :                 "objectSid",
    2348             :                 NULL
    2349             :         };
    2350             :         int ret;
    2351             :         unsigned int i;
    2352             : 
    2353    33274425 :         ac = talloc_get_type(req->context, struct acl_context);
    2354    33274425 :         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
    2355    33274425 :         if (!ares) {
    2356           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    2357             :                                        LDB_ERR_OPERATIONS_ERROR);
    2358             :         }
    2359    33274425 :         if (ares->error != LDB_SUCCESS) {
    2360      665456 :                 return ldb_module_done(ac->req, ares->controls,
    2361             :                                        ares->response, ares->error);
    2362             :         }
    2363             : 
    2364    32608969 :         switch (ares->type) {
    2365    26643254 :         case LDB_REPLY_ENTRY:
    2366    26643254 :                 if (ac->constructed_attrs) {
    2367          76 :                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn, 
    2368             :                                                     acl_attrs,
    2369             :                                                     DSDB_FLAG_NEXT_MODULE |
    2370             :                                                     DSDB_FLAG_AS_SYSTEM |
    2371             :                                                     DSDB_SEARCH_SHOW_RECYCLED,
    2372             :                                                     req);
    2373          76 :                         if (ret != LDB_SUCCESS) {
    2374           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2375             :                         }
    2376             :                 }
    2377             : 
    2378    26643254 :                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
    2379          36 :                         ret = acl_allowedAttributes(ac->module, ac->schema,
    2380          22 :                                                     acl_res->msgs[0],
    2381             :                                                     ares->message, ac);
    2382          22 :                         if (ret != LDB_SUCCESS) {
    2383           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2384             :                         }
    2385             :                 }
    2386             : 
    2387    26643254 :                 if (ac->allowedChildClasses) {
    2388           0 :                         ret = acl_childClasses(ac->module, ac->schema,
    2389           0 :                                                acl_res->msgs[0],
    2390             :                                                ares->message,
    2391             :                                                "allowedChildClasses");
    2392           0 :                         if (ret != LDB_SUCCESS) {
    2393           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2394             :                         }
    2395             :                 }
    2396             : 
    2397    26643254 :                 if (ac->allowedChildClassesEffective) {
    2398          28 :                         ret = acl_childClassesEffective(ac->module, ac->schema,
    2399          18 :                                                         acl_res->msgs[0],
    2400             :                                                         ares->message, ac);
    2401          18 :                         if (ret != LDB_SUCCESS) {
    2402           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2403             :                         }
    2404             :                 }
    2405             : 
    2406    26643254 :                 if (ac->sDRightsEffective) {
    2407          56 :                         ret = acl_sDRightsEffective(ac->module,
    2408          36 :                                                     acl_res->msgs[0],
    2409             :                                                     ares->message, ac);
    2410          36 :                         if (ret != LDB_SUCCESS) {
    2411           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2412             :                         }
    2413             :                 }
    2414             : 
    2415    26643254 :                 if (data == NULL) {
    2416           0 :                         return ldb_module_send_entry(ac->req, ares->message,
    2417             :                                                      ares->controls);
    2418             :                 }
    2419             : 
    2420    26643254 :                 if (ac->am_system) {
    2421           0 :                         return ldb_module_send_entry(ac->req, ares->message,
    2422             :                                                      ares->controls);
    2423             :                 }
    2424             : 
    2425    26643254 :                 if (ac->am_administrator) {
    2426     9045317 :                         return ldb_module_send_entry(ac->req, ares->message,
    2427             :                                                      ares->controls);
    2428             :                 }
    2429             : 
    2430    17597937 :                 if (data->confidential_attrs != NULL) {
    2431           0 :                         for (i = 0; data->confidential_attrs[i]; i++) {
    2432           0 :                                 ldb_msg_remove_attr(ares->message,
    2433           0 :                                                     data->confidential_attrs[i]);
    2434             :                         }
    2435             :                 }
    2436             : 
    2437    17597937 :                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
    2438             : 
    2439      426385 :         case LDB_REPLY_REFERRAL:
    2440      426385 :                 return ldb_module_send_referral(ac->req, ares->referral);
    2441             : 
    2442     5539330 :         case LDB_REPLY_DONE:
    2443     5539330 :                 return ldb_module_done(ac->req, ares->controls,
    2444             :                                        ares->response, LDB_SUCCESS);
    2445             : 
    2446             :         }
    2447           0 :         return LDB_SUCCESS;
    2448             : }
    2449             : 
    2450    20055289 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
    2451             : {
    2452             :         struct ldb_context *ldb;
    2453             :         struct acl_context *ac;
    2454    20055289 :         struct ldb_parse_tree *down_tree = req->op.search.tree;
    2455             :         struct ldb_request *down_req;
    2456             :         struct acl_private *data;
    2457             :         int ret;
    2458             :         unsigned int i;
    2459    20055289 :         bool modify_search = true;
    2460             : 
    2461    20055289 :         if (ldb_dn_is_special(req->op.search.base)) {
    2462      737905 :                 return ldb_next_request(module, req);
    2463             :         }
    2464             : 
    2465    19317384 :         ldb = ldb_module_get_ctx(module);
    2466             : 
    2467    19317384 :         ac = talloc_zero(req, struct acl_context);
    2468    19317384 :         if (ac == NULL) {
    2469           0 :                 return ldb_oom(ldb);
    2470             :         }
    2471    19317384 :         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
    2472             : 
    2473    19317384 :         ac->module = module;
    2474    19317384 :         ac->req = req;
    2475    19317384 :         ac->am_system = dsdb_module_am_system(module);
    2476    19317384 :         ac->am_administrator = dsdb_module_am_administrator(module);
    2477    19317384 :         ac->constructed_attrs = false;
    2478    19317384 :         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
    2479    19317384 :         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
    2480    19317384 :         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
    2481    19317384 :         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
    2482    19317384 :         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
    2483    19317384 :         ac->schema = dsdb_get_schema(ldb, ac);
    2484             : 
    2485    19317384 :         ac->constructed_attrs |= ac->allowedAttributes;
    2486    19317384 :         ac->constructed_attrs |= ac->allowedChildClasses;
    2487    19317384 :         ac->constructed_attrs |= ac->allowedChildClassesEffective;
    2488    19317384 :         ac->constructed_attrs |= ac->allowedAttributesEffective;
    2489    19317384 :         ac->constructed_attrs |= ac->sDRightsEffective;
    2490             : 
    2491    19317384 :         if (data == NULL) {
    2492           0 :                 modify_search = false;
    2493             :         }
    2494    19317384 :         if (ac->am_system) {
    2495    13112446 :                 modify_search = false;
    2496             :         }
    2497             : 
    2498    19317384 :         if (!ac->constructed_attrs && !modify_search) {
    2499    13112446 :                 talloc_free(ac);
    2500    13112446 :                 return ldb_next_request(module, req);
    2501             :         }
    2502             : 
    2503     6204938 :         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
    2504     6204938 :         if (data == NULL) {
    2505           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2506             :                                  "acl_private data is missing");
    2507             :         }
    2508             : 
    2509     6204938 :         if (!ac->am_system && !ac->am_administrator) {
    2510      609924 :                 ret = acl_search_update_confidential_attrs(ac, data);
    2511      609924 :                 if (ret != LDB_SUCCESS) {
    2512           0 :                         return ret;
    2513             :                 }
    2514             : 
    2515      609924 :                 if (data->confidential_attrs != NULL) {
    2516           0 :                         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
    2517           0 :                         if (down_tree == NULL) {
    2518           0 :                                 return ldb_oom(ldb);
    2519             :                         }
    2520             : 
    2521           0 :                         for (i = 0; data->confidential_attrs[i]; i++) {
    2522           0 :                                 ldb_parse_tree_attr_replace(down_tree,
    2523           0 :                                                             data->confidential_attrs[i],
    2524             :                                                             "kludgeACLredactedattribute");
    2525             :                         }
    2526             :                 }
    2527             :         }
    2528             : 
    2529     6204938 :         ret = ldb_build_search_req_ex(&down_req,
    2530             :                                       ldb, ac,
    2531             :                                       req->op.search.base,
    2532             :                                       req->op.search.scope,
    2533             :                                       down_tree,
    2534             :                                       req->op.search.attrs,
    2535             :                                       req->controls,
    2536             :                                       ac, acl_search_callback,
    2537             :                                       req);
    2538     6204938 :         LDB_REQ_SET_LOCATION(down_req);
    2539     6204938 :         if (ret != LDB_SUCCESS) {
    2540           0 :                 return ret;
    2541             :         }
    2542             :         /* perform the search */
    2543     6204938 :         return ldb_next_request(module, down_req);
    2544             : }
    2545             : 
    2546      892965 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
    2547             : {
    2548      892965 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    2549      892965 :         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    2550             : 
    2551             :         /* allow everybody to read the sequence number */
    2552      892965 :         if (strcmp(req->op.extended.oid,
    2553             :                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
    2554      887885 :                 return ldb_next_request(module, req);
    2555             :         }
    2556             : 
    2557        5380 :         if (dsdb_module_am_system(module) ||
    2558         300 :             dsdb_module_am_administrator(module) || as_system) {
    2559        5080 :                 return ldb_next_request(module, req);
    2560             :         } else {
    2561           0 :                 ldb_asprintf_errstring(ldb,
    2562             :                                        "acl_extended: "
    2563             :                                        "attempted database modify not permitted. "
    2564             :                                        "User %s is not SYSTEM or an administrator",
    2565             :                                        acl_user_name(req, module));
    2566           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2567             :         }
    2568             : }
    2569             : 
    2570             : static const struct ldb_module_ops ldb_acl_module_ops = {
    2571             :         .name              = "acl",
    2572             :         .search            = acl_search,
    2573             :         .add               = acl_add,
    2574             :         .modify            = acl_modify,
    2575             :         .del               = acl_delete,
    2576             :         .rename            = acl_rename,
    2577             :         .extended          = acl_extended,
    2578             :         .init_context      = acl_module_init
    2579             : };
    2580             : 
    2581        4310 : int ldb_acl_module_init(const char *version)
    2582             : {
    2583        4310 :         LDB_MODULE_CHECK_VERSION(version);
    2584        4310 :         return ldb_register_module(&ldb_acl_module_ops);
    2585             : }

Generated by: LCOV version 1.13