LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - acl.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 985 1302 75.7 %
Date: 2024-05-31 13:13:24 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      181589 : static int acl_module_init(struct ldb_module *module)
      73             : {
      74        6078 :         struct ldb_context *ldb;
      75        6078 :         struct acl_private *data;
      76        6078 :         int ret;
      77             : 
      78      181589 :         ldb = ldb_module_get_ctx(module);
      79             : 
      80      181589 :         data = talloc_zero(module, struct acl_private);
      81      181589 :         if (data == NULL) {
      82           0 :                 return ldb_oom(ldb);
      83             :         }
      84             : 
      85      181589 :         data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
      86             :                                         NULL, "acl", "search", true);
      87      181589 :         ldb_module_set_private(module, data);
      88             : 
      89      181589 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
      90      181589 :         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      181589 :         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           0 :         struct ldb_message_element *oc_el;
     106          22 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     107           0 :         TALLOC_CTX *mem_ctx;
     108           0 :         const char **attr_list;
     109           0 :         int i, ret;
     110           0 :         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         972 :                 for (i=0; attr_list && attr_list[i]; i++) {
     150         968 :                         ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
     151             :                 }
     152             :         }
     153          22 :         if (ac->allowedAttributesEffective) {
     154           0 :                 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        3608 :                 for (i=0; attr_list && attr_list[i]; i++) {
     179        3586 :                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
     180        3586 :                                                                                         attr_list[i]);
     181        3586 :                         if (!attr) {
     182           0 :                                 return ldb_operr(ldb);
     183             :                         }
     184             :                         /* remove constructed attributes */
     185        3586 :                         if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
     186        3044 :                             || attr->systemOnly
     187        1712 :                             || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
     188        2002 :                                 continue;
     189             :                         }
     190        1584 :                         ret = acl_check_access_on_attribute(module,
     191             :                                                             msg,
     192             :                                                             sd,
     193             :                                                             sid,
     194             :                                                             SEC_ADS_WRITE_PROP,
     195             :                                                             attr,
     196             :                                                             objectclass);
     197        1584 :                         if (ret == LDB_SUCCESS) {
     198         552 :                                 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           0 :         struct ldb_message_element *oc_el;
     212           0 :         struct ldb_message_element *allowedClasses;
     213           0 :         const struct dsdb_class *sclass;
     214           0 :         unsigned int i, j;
     215           0 :         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 reigns */
     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           0 :         struct ldb_message_element *oc_el;
     266          18 :         struct ldb_message_element *allowedClasses = NULL;
     267           0 :         const struct dsdb_class *sclass;
     268           0 :         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           0 :         unsigned int i, j;
     273           0 :         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 reigns */
     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        1700 :                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
     307           0 :                         const struct dsdb_class *sc;
     308             : 
     309        1664 :                         sc = dsdb_class_by_lDAPDisplayName(schema,
     310        1664 :                                                            sclass->possibleInferiors[j]);
     311        1664 :                         if (!sc) {
     312             :                                 /* We don't know this class?  what is going on? */
     313           0 :                                 continue;
     314             :                         }
     315             : 
     316        1664 :                         ret = acl_check_access_on_objectclass(module, ac,
     317             :                                                               sd, sid,
     318             :                                                               SEC_ADS_CREATE_CHILD,
     319             :                                                               sc);
     320        1664 :                         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         306 : 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         306 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     352           0 :         struct ldb_message_element *rightsEffective;
     353           0 :         int ret;
     354           0 :         struct security_descriptor *sd;
     355         306 :         struct ldb_control *as_system = ldb_request_get_control(ac->req,
     356             :                                                                 LDB_CONTROL_AS_SYSTEM_OID);
     357         306 :         struct dom_sid *sid = NULL;
     358         306 :         uint32_t flags = 0;
     359             : 
     360         306 :         if (as_system != NULL) {
     361           0 :                 as_system->critical = 0;
     362             :         }
     363             : 
     364             :         /* Must remove any existing attribute, or else confusion reigns */
     365         306 :         ldb_msg_remove_attr(msg, "sDRightsEffective");
     366         306 :         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
     367         306 :         if (ret != LDB_SUCCESS) {
     368           0 :                 return ret;
     369             :         }
     370         306 :         if (ac->am_system || as_system) {
     371           0 :                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
     372             :         } else {
     373           0 :                 const struct dsdb_class *objectclass;
     374           0 :                 const struct dsdb_attribute *attr;
     375             : 
     376         306 :                 objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
     377         306 :                 if (objectclass == NULL) {
     378           0 :                         return ldb_operr(ldb);
     379             :                 }
     380             : 
     381         306 :                 attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
     382             :                                                          "nTSecurityDescriptor");
     383         306 :                 if (attr == NULL) {
     384           0 :                         return ldb_operr(ldb);
     385             :                 }
     386             : 
     387             :                 /* Get the security descriptor from the message */
     388         306 :                 ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
     389         306 :                 if (ret != LDB_SUCCESS) {
     390           0 :                         return ret;
     391             :                 }
     392         306 :                 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
     393         306 :                 ret = acl_check_access_on_attribute(module,
     394             :                                                     msg,
     395             :                                                     sd,
     396             :                                                     sid,
     397             :                                                     SEC_STD_WRITE_OWNER,
     398             :                                                     attr,
     399             :                                                     objectclass);
     400         306 :                 if (ret == LDB_SUCCESS) {
     401         108 :                         flags |= SECINFO_OWNER | SECINFO_GROUP;
     402             :                 }
     403             : 
     404             :                 /*
     405             :                  * This call is made with
     406             :                  * IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS
     407             :                  * and without reference to the dSHeuristics via
     408             :                  * dsdb_block_owner_implicit_rights().  This is
     409             :                  * probably a Windows bug but for now we match
     410             :                  * exactly.
     411             :                  */
     412         306 :                 ret = acl_check_access_on_attribute_implicit_owner(
     413             :                         module,
     414             :                         msg,
     415             :                         sd,
     416             :                         sid,
     417             :                         SEC_STD_WRITE_DAC,
     418             :                         attr,
     419             :                         objectclass,
     420             :                         IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
     421         306 :                 if (ret == LDB_SUCCESS) {
     422          72 :                         flags |= SECINFO_DACL;
     423             :                 }
     424         306 :                 ret = acl_check_access_on_attribute(module,
     425             :                                                     msg,
     426             :                                                     sd,
     427             :                                                     sid,
     428             :                                                     SEC_FLAG_SYSTEM_SECURITY,
     429             :                                                     attr,
     430             :                                                     objectclass);
     431         306 :                 if (ret == LDB_SUCCESS) {
     432           9 :                         flags |= SECINFO_SACL;
     433             :                 }
     434             :         }
     435             : 
     436         306 :         if (flags != (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_SACL)) {
     437         297 :                 const struct ldb_message_element *el = samdb_find_attribute(ldb,
     438             :                                                                             sd_msg,
     439             :                                                                             "objectclass",
     440             :                                                                             "computer");
     441         297 :                 if (el != NULL) {
     442         144 :                         return LDB_SUCCESS;
     443             :                 }
     444             :         }
     445             : 
     446         162 :         return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
     447             :                                   "sDRightsEffective", flags);
     448             : }
     449             : 
     450         577 : static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
     451             :                                   struct ldb_context *ldb,
     452             :                                   const struct ldb_val *spn_value,
     453             :                                   uint32_t userAccountControl,
     454             :                                   const struct ldb_val *samAccountName,
     455             :                                   const struct ldb_val *dnsHostName,
     456             :                                   const char *netbios_name,
     457             :                                   const char *ntds_guid)
     458             : {
     459           0 :         krb5_error_code ret, princ_size;
     460           0 :         krb5_context krb_ctx;
     461           0 :         krb5_error_code kerr;
     462           0 :         krb5_principal principal;
     463         577 :         char *instanceName = NULL;
     464         577 :         char *serviceType = NULL;
     465         577 :         char *serviceName = NULL;
     466         577 :         const char *spn_value_str = NULL;
     467           0 :         size_t account_name_len;
     468         577 :         const char *forest_name = samdb_forest_name(ldb, mem_ctx);
     469         577 :         const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
     470         577 :         struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
     471             :                                                           struct loadparm_context);
     472         956 :         bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
     473         379 :                 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
     474             : 
     475         577 :         spn_value_str = talloc_strndup(mem_ctx,
     476         577 :                                        (const char *)spn_value->data,
     477         577 :                                        spn_value->length);
     478         577 :         if (spn_value_str == NULL) {
     479           0 :                 return ldb_oom(ldb);
     480             :         }
     481             : 
     482         577 :         if (spn_value->length == samAccountName->length &&
     483           0 :             strncasecmp((const char *)spn_value->data,
     484           0 :                         (const char *)samAccountName->data,
     485           0 :                         spn_value->length) == 0)
     486             :         {
     487             :                 /* MacOS X sets this value, and setting an SPN of your
     488             :                  * own samAccountName is both pointless and safe */
     489           0 :                 return LDB_SUCCESS;
     490             :         }
     491             : 
     492         577 :         kerr = smb_krb5_init_context_basic(mem_ctx,
     493             :                                            lp_ctx,
     494             :                                            &krb_ctx);
     495         577 :         if (kerr != 0) {
     496           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
     497             :                                  "Could not initialize kerberos context.");
     498             :         }
     499             : 
     500         577 :         ret = krb5_parse_name(krb_ctx, spn_value_str, &principal);
     501         577 :         if (ret) {
     502           0 :                 krb5_free_context(krb_ctx);
     503           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
     504             :         }
     505             : 
     506         577 :         princ_size = krb5_princ_size(krb_ctx, principal);
     507         577 :         if (princ_size < 2) {
     508           0 :                 DBG_WARNING("princ_size=%d\n", princ_size);
     509           0 :                 goto fail;
     510             :         }
     511             : 
     512         577 :         ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
     513             :                                                           principal, 1, &instanceName);
     514         577 :         if (ret) {
     515           0 :                 goto fail;
     516             :         }
     517         577 :         ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
     518             :                                                  principal, 0, &serviceType);
     519         577 :         if (ret) {
     520           0 :                 goto fail;
     521             :         }
     522         577 :         if (krb5_princ_size(krb_ctx, principal) == 3) {
     523         427 :                 ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
     524             :                                                          principal, 2, &serviceName);
     525         427 :                 if (ret) {
     526           0 :                         goto fail;
     527             :                 }
     528             :         }
     529             : 
     530         577 :         if (serviceName) {
     531         427 :                 if (!is_dc) {
     532          99 :                         DBG_WARNING("is_dc=false, serviceName=%s,"
     533             :                                     "serviceType=%s\n", serviceName,
     534             :                                   serviceType);
     535          99 :                         goto fail;
     536             :                 }
     537         328 :                 if (strcasecmp(serviceType, "ldap") == 0) {
     538         110 :                         if (strcasecmp(serviceName, netbios_name) != 0 &&
     539          73 :                             strcasecmp(serviceName, forest_name) != 0) {
     540          36 :                                 DBG_WARNING("serviceName=%s\n", serviceName);
     541          36 :                                 goto fail;
     542             :                         }
     543             : 
     544         218 :                 } else if (strcasecmp(serviceType, "gc") == 0) {
     545          36 :                         if (strcasecmp(serviceName, forest_name) != 0) {
     546          18 :                                 DBG_WARNING("serviceName=%s\n", serviceName);
     547          18 :                                 goto fail;
     548             :                         }
     549             :                 } else {
     550         182 :                         if (strcasecmp(serviceName, base_domain) != 0 &&
     551          55 :                             strcasecmp(serviceName, netbios_name) != 0) {
     552          18 :                                 DBG_WARNING("serviceType=%s, "
     553             :                                             "serviceName=%s\n",
     554             :                                             serviceType, serviceName);
     555          18 :                                 goto fail;
     556             :                         }
     557             :                 }
     558             :         }
     559             : 
     560         406 :         account_name_len = samAccountName->length;
     561         406 :         if (account_name_len &&
     562         406 :             samAccountName->data[account_name_len - 1] == '$')
     563             :         {
     564             :                 /* Account for the '$' character. */
     565         406 :                 --account_name_len;
     566             :         }
     567             : 
     568             :         /* instanceName can be samAccountName without $ or dnsHostName
     569             :          * or "ntds_guid._msdcs.forest_domain for DC objects */
     570         406 :         if (strlen(instanceName) == account_name_len
     571         214 :             && strncasecmp(instanceName,
     572         214 :                            (const char *)samAccountName->data,
     573             :                            account_name_len) == 0)
     574             :         {
     575         214 :                 goto success;
     576             :         }
     577         192 :         if ((dnsHostName != NULL) &&
     578         192 :             strlen(instanceName) == dnsHostName->length &&
     579         146 :             (strncasecmp(instanceName,
     580         146 :                          (const char *)dnsHostName->data,
     581         146 :                          dnsHostName->length) == 0))
     582             :         {
     583         146 :                 goto success;
     584             :         }
     585          46 :         if (is_dc) {
     586          37 :                 const char *guid_str = NULL;
     587          37 :                 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
     588             :                                            ntds_guid,
     589             :                                            forest_name);
     590          37 :                 if (strcasecmp(instanceName, guid_str) == 0) {
     591          19 :                         goto success;
     592             :                 }
     593             :         }
     594             : 
     595          27 : fail:
     596         198 :         krb5_free_principal(krb_ctx, principal);
     597         198 :         krb5_free_context(krb_ctx);
     598         198 :         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
     599             :                       "acl: spn validation failed for "
     600             :                       "spn[%.*s] uac[0x%x] account[%.*s] hostname[%.*s] "
     601             :                       "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
     602         198 :                       (int)spn_value->length, spn_value->data,
     603             :                       (unsigned)userAccountControl,
     604         198 :                       (int)samAccountName->length, samAccountName->data,
     605         180 :                       dnsHostName != NULL ? (int)dnsHostName->length : 0,
     606             :                       dnsHostName != NULL ? (const char *)dnsHostName->data : "",
     607             :                       netbios_name, ntds_guid,
     608             :                       forest_name, base_domain);
     609         198 :         return LDB_ERR_CONSTRAINT_VIOLATION;
     610             : 
     611         379 : success:
     612         379 :         krb5_free_principal(krb_ctx, principal);
     613         379 :         krb5_free_context(krb_ctx);
     614         379 :         return LDB_SUCCESS;
     615             : }
     616             : 
     617             : /*
     618             :  * Passing in 'el' is critical, we want to check all the values.
     619             :  *
     620             :  */
     621        2203 : static int acl_check_spn(TALLOC_CTX *mem_ctx,
     622             :                          struct ldb_module *module,
     623             :                          struct ldb_request *req,
     624             :                          const struct ldb_message_element *el,
     625             :                          struct security_descriptor *sd,
     626             :                          struct dom_sid *sid,
     627             :                          const struct dsdb_attribute *attr,
     628             :                          const struct dsdb_class *objectclass,
     629             :                          const struct ldb_control *implicit_validated_write_control)
     630             : {
     631          74 :         int ret;
     632          74 :         unsigned int i;
     633        2203 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     634        2203 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     635          74 :         struct ldb_result *acl_res;
     636          74 :         struct ldb_result *netbios_res;
     637        2203 :         struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
     638          74 :         uint32_t userAccountControl;
     639          74 :         const char *netbios_name;
     640        2203 :         const struct ldb_val *dns_host_name_val = NULL;
     641        2203 :         const struct ldb_val *sam_account_name_val = NULL;
     642          74 :         struct GUID ntds;
     643        2203 :         char *ntds_guid = NULL;
     644        2203 :         const struct ldb_message *msg = NULL;
     645        2203 :         const struct ldb_message *search_res = NULL;
     646             : 
     647          74 :         static const char *acl_attrs[] = {
     648             :                 "samAccountName",
     649             :                 "dnsHostName",
     650             :                 "userAccountControl",
     651             :                 NULL
     652             :         };
     653          74 :         static const char *netbios_attrs[] = {
     654             :                 "nETBIOSName",
     655             :                 NULL
     656             :         };
     657             : 
     658        2203 :         if (req->operation == LDB_MODIFY) {
     659        2167 :                 msg = req->op.mod.message;
     660          36 :         } else if (req->operation == LDB_ADD) {
     661          36 :                 msg = req->op.add.message;
     662             :         }
     663             : 
     664        2203 :         if (implicit_validated_write_control != NULL) {
     665             :                 /*
     666             :                  * The validated write control dispenses with ACL
     667             :                  * checks. We act as if we have an implicit Self Write
     668             :                  * privilege, but, assuming we don't have Write
     669             :                  * Property, still proceed with further validation
     670             :                  * checks.
     671             :                  */
     672             :         } else {
     673             :                 /* if we have wp, we can do whatever we like */
     674        2197 :                 if (acl_check_access_on_attribute(module,
     675             :                                                   tmp_ctx,
     676             :                                                   sd,
     677             :                                                   sid,
     678             :                                                   SEC_ADS_WRITE_PROP,
     679             :                                                   attr, objectclass) == LDB_SUCCESS) {
     680        1526 :                         talloc_free(tmp_ctx);
     681        1526 :                         return LDB_SUCCESS;
     682             :                 }
     683             : 
     684         671 :                 ret = acl_check_extended_right(tmp_ctx,
     685             :                                                module,
     686             :                                                req,
     687             :                                                objectclass,
     688             :                                                sd,
     689             :                                                acl_user_token(module),
     690             :                                                GUID_DRS_VALIDATE_SPN,
     691             :                                                SEC_ADS_SELF_WRITE,
     692             :                                                sid);
     693             : 
     694         671 :                 if (ret != LDB_SUCCESS) {
     695          94 :                         dsdb_acl_debug(sd, acl_user_token(module),
     696          94 :                                        msg->dn,
     697             :                                        true,
     698             :                                        10);
     699          94 :                         talloc_free(tmp_ctx);
     700          94 :                         return ret;
     701             :                 }
     702             :         }
     703             : 
     704             :         /*
     705             :          * If we have "validated write spn", allow delete of any
     706             :          * existing value (this keeps constrained delete to the same
     707             :          * rules as unconstrained)
     708             :          */
     709         583 :         if (req->operation == LDB_MODIFY) {
     710             :                 /*
     711             :                  * If not add or replace (eg delete),
     712             :                  * return success
     713             :                  */
     714         565 :                 if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
     715         501 :                     LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
     716             :                 {
     717          18 :                         talloc_free(tmp_ctx);
     718          18 :                         return LDB_SUCCESS;
     719             :                 }
     720             : 
     721         547 :                 ret = dsdb_module_search_dn(module, tmp_ctx,
     722         547 :                                             &acl_res, msg->dn,
     723             :                                             acl_attrs,
     724             :                                             DSDB_FLAG_NEXT_MODULE |
     725             :                                             DSDB_FLAG_AS_SYSTEM |
     726             :                                             DSDB_SEARCH_SHOW_RECYCLED,
     727             :                                             req);
     728         547 :                 if (ret != LDB_SUCCESS) {
     729           0 :                         talloc_free(tmp_ctx);
     730           0 :                         return ret;
     731             :                 }
     732             : 
     733         547 :                 search_res = acl_res->msgs[0];
     734          18 :         } else if (req->operation == LDB_ADD) {
     735          18 :                 search_res = msg;
     736             :         } else {
     737           0 :                 talloc_free(tmp_ctx);
     738           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     739             :         }
     740             : 
     741         565 :         if (req->operation == LDB_MODIFY) {
     742         547 :                 dns_host_name_val = ldb_msg_find_ldb_val(search_res, "dNSHostName");
     743             :         }
     744             : 
     745         565 :         ret = dsdb_msg_get_single_value(msg,
     746             :                                         "dNSHostName",
     747             :                                         dns_host_name_val,
     748             :                                         &dns_host_name_val,
     749             :                                         req->operation);
     750         565 :         if (ret != LDB_SUCCESS) {
     751           0 :                 talloc_free(tmp_ctx);
     752           0 :                 return ret;
     753             :         }
     754             : 
     755         565 :         userAccountControl = ldb_msg_find_attr_as_uint(search_res, "userAccountControl", 0);
     756             : 
     757         565 :         if (req->operation == LDB_MODIFY) {
     758         547 :                 sam_account_name_val = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
     759             :         }
     760             : 
     761         565 :         ret = dsdb_msg_get_single_value(msg,
     762             :                                         "sAMAccountName",
     763             :                                         sam_account_name_val,
     764             :                                         &sam_account_name_val,
     765             :                                         req->operation);
     766         565 :         if (ret != LDB_SUCCESS) {
     767           0 :                 talloc_free(tmp_ctx);
     768           0 :                 return ret;
     769             :         }
     770             : 
     771         565 :         ret = dsdb_module_search(module, tmp_ctx,
     772             :                                  &netbios_res, partitions_dn,
     773             :                                  LDB_SCOPE_ONELEVEL,
     774             :                                  netbios_attrs,
     775             :                                  DSDB_FLAG_NEXT_MODULE |
     776             :                                  DSDB_FLAG_AS_SYSTEM,
     777             :                                  req,
     778             :                                  "(ncName=%s)",
     779             :                                  ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
     780             : 
     781         565 :         netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
     782             : 
     783             :         /*
     784             :          * NTDSDSA objectGuid of object we are checking SPN for
     785             :          *
     786             :          * Note - do we have the necessary attributes for this during an add operation?
     787             :          * How should we test this?
     788             :          */
     789         565 :         if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
     790         397 :                 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
     791         397 :                                                              msg->dn, &ntds, req);
     792         397 :                 if (ret != LDB_SUCCESS) {
     793           0 :                         ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
     794           0 :                                                ldb_dn_get_linearized(msg->dn),
     795             :                                                ldb_strerror(ret));
     796           0 :                         talloc_free(tmp_ctx);
     797           0 :                         return LDB_ERR_OPERATIONS_ERROR;
     798             :                 }
     799         397 :                 ntds_guid = GUID_string(tmp_ctx, &ntds);
     800             :         }
     801             : 
     802         944 :         for (i=0; i < el->num_values; i++) {
     803         577 :                 ret = acl_validate_spn_value(tmp_ctx,
     804             :                                              ldb,
     805         577 :                                              &el->values[i],
     806             :                                              userAccountControl,
     807             :                                              sam_account_name_val,
     808             :                                              dns_host_name_val,
     809             :                                              netbios_name,
     810             :                                              ntds_guid);
     811         577 :                 if (ret != LDB_SUCCESS) {
     812         198 :                         talloc_free(tmp_ctx);
     813         198 :                         return ret;
     814             :                 }
     815             :         }
     816         367 :         talloc_free(tmp_ctx);
     817         367 :         return LDB_SUCCESS;
     818             : }
     819             : 
     820         953 : static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
     821             :                                    struct ldb_module *module,
     822             :                                    struct ldb_request *req,
     823             :                                    const struct ldb_message_element *el,
     824             :                                    struct security_descriptor *sd,
     825             :                                    struct dom_sid *sid,
     826             :                                    const struct dsdb_attribute *attr,
     827             :                                    const struct dsdb_class *objectclass,
     828             :                                    const struct ldb_control *implicit_validated_write_control)
     829             : {
     830          75 :         int ret;
     831          75 :         unsigned i;
     832         953 :         TALLOC_CTX *tmp_ctx = NULL;
     833         953 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     834         953 :         const struct dsdb_schema *schema = NULL;
     835         953 :         const struct ldb_message_element *allowed_suffixes = NULL;
     836         953 :         struct ldb_result *nc_res = NULL;
     837         953 :         struct ldb_dn *nc_root = NULL;
     838         953 :         const char *nc_dns_name = NULL;
     839         953 :         const char *dnsHostName_str = NULL;
     840          75 :         size_t dns_host_name_len;
     841          75 :         size_t account_name_len;
     842         953 :         const struct ldb_message *msg = NULL;
     843         953 :         const struct ldb_message *search_res = NULL;
     844         953 :         const struct ldb_val *samAccountName = NULL;
     845         953 :         const struct ldb_val *dnsHostName = NULL;
     846         953 :         const struct dsdb_class *computer_objectclass = NULL;
     847          75 :         bool is_subclass;
     848             : 
     849          75 :         static const char *nc_attrs[] = {
     850             :                 "msDS-AllowedDNSSuffixes",
     851             :                 NULL
     852             :         };
     853             : 
     854         953 :         tmp_ctx = talloc_new(mem_ctx);
     855         953 :         if (tmp_ctx == NULL) {
     856           0 :                 return ldb_oom(ldb);
     857             :         }
     858             : 
     859         953 :         if (req->operation == LDB_MODIFY) {
     860         953 :                 msg = req->op.mod.message;
     861           0 :         } else if (req->operation == LDB_ADD) {
     862           0 :                 msg = req->op.add.message;
     863             :         }
     864             : 
     865         953 :         if (implicit_validated_write_control != NULL) {
     866             :                 /*
     867             :                  * The validated write control dispenses with ACL
     868             :                  * checks. We act as if we have an implicit Self Write
     869             :                  * privilege, but, assuming we don't have Write
     870             :                  * Property, still proceed with further validation
     871             :                  * checks.
     872             :                  */
     873             :         } else {
     874             :                 /* if we have wp, we can do whatever we like */
     875         917 :                 ret = acl_check_access_on_attribute(module,
     876             :                                                     tmp_ctx,
     877             :                                                     sd,
     878             :                                                     sid,
     879             :                                                     SEC_ADS_WRITE_PROP,
     880             :                                                     attr, objectclass);
     881         917 :                 if (ret == LDB_SUCCESS) {
     882         713 :                         talloc_free(tmp_ctx);
     883         713 :                         return LDB_SUCCESS;
     884             :                 }
     885             : 
     886         204 :                 ret = acl_check_extended_right(tmp_ctx,
     887             :                                                module,
     888             :                                                req,
     889             :                                                objectclass,
     890             :                                                sd,
     891             :                                                acl_user_token(module),
     892             :                                                GUID_DRS_DNS_HOST_NAME,
     893             :                                                SEC_ADS_SELF_WRITE,
     894             :                                                sid);
     895             : 
     896         204 :                 if (ret != LDB_SUCCESS) {
     897          78 :                         dsdb_acl_debug(sd, acl_user_token(module),
     898          78 :                                        msg->dn,
     899             :                                        true,
     900             :                                        10);
     901          78 :                         talloc_free(tmp_ctx);
     902          78 :                         return ret;
     903             :                 }
     904             :         }
     905             : 
     906             :         /*
     907             :          * If we have "validated write dnshostname", allow delete of
     908             :          * any existing value (this keeps constrained delete to the
     909             :          * same rules as unconstrained)
     910             :          */
     911         162 :         if (req->operation == LDB_MODIFY) {
     912         162 :                 struct ldb_result *acl_res = NULL;
     913             : 
     914           3 :                 static const char *acl_attrs[] = {
     915             :                         "sAMAccountName",
     916             :                         NULL
     917             :                 };
     918             : 
     919             :                 /*
     920             :                  * If not add or replace (eg delete),
     921             :                  * return success
     922             :                  */
     923         162 :                 if ((el->flags
     924         162 :                      & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0)
     925             :                 {
     926           0 :                         talloc_free(tmp_ctx);
     927           0 :                         return LDB_SUCCESS;
     928             :                 }
     929             : 
     930         165 :                 ret = dsdb_module_search_dn(module, tmp_ctx,
     931         162 :                                             &acl_res, msg->dn,
     932             :                                             acl_attrs,
     933             :                                             DSDB_FLAG_NEXT_MODULE |
     934             :                                             DSDB_FLAG_AS_SYSTEM |
     935             :                                             DSDB_SEARCH_SHOW_RECYCLED,
     936             :                                             req);
     937         162 :                 if (ret != LDB_SUCCESS) {
     938           0 :                         talloc_free(tmp_ctx);
     939           0 :                         return ret;
     940             :                 }
     941             : 
     942         162 :                 search_res = acl_res->msgs[0];
     943           0 :         } else if (req->operation == LDB_ADD) {
     944           0 :                 search_res = msg;
     945             :         } else {
     946           0 :                 talloc_free(tmp_ctx);
     947           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     948             :         }
     949             : 
     950             :         /* Check if the account has objectclass 'computer' or 'server'. */
     951             : 
     952         162 :         schema = dsdb_get_schema(ldb, req);
     953         162 :         if (schema == NULL) {
     954           0 :                 talloc_free(tmp_ctx);
     955           0 :                 return ldb_operr(ldb);
     956             :         }
     957             : 
     958         162 :         computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
     959         162 :         if (computer_objectclass == NULL) {
     960           0 :                 talloc_free(tmp_ctx);
     961           0 :                 return ldb_operr(ldb);
     962             :         }
     963             : 
     964         162 :         is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
     965         162 :         if (!is_subclass) {
     966             :                 /* The account is not a computer -- check if it's a server. */
     967             : 
     968           0 :                 const struct dsdb_class *server_objectclass = NULL;
     969             : 
     970           0 :                 server_objectclass = dsdb_class_by_lDAPDisplayName(schema, "server");
     971           0 :                 if (server_objectclass == NULL) {
     972           0 :                         talloc_free(tmp_ctx);
     973           0 :                         return ldb_operr(ldb);
     974             :                 }
     975             : 
     976           0 :                 is_subclass = dsdb_is_subclass_of(schema, objectclass, server_objectclass);
     977           0 :                 if (!is_subclass) {
     978             :                         /* Not a computer or server, so no need to validate. */
     979           0 :                         talloc_free(tmp_ctx);
     980           0 :                         return LDB_SUCCESS;
     981             :                 }
     982             :         }
     983             : 
     984         162 :         if (req->operation == LDB_MODIFY) {
     985         162 :                 samAccountName = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
     986             :         }
     987             : 
     988         162 :         ret = dsdb_msg_get_single_value(msg,
     989             :                                         "sAMAccountName",
     990             :                                         samAccountName,
     991             :                                         &samAccountName,
     992             :                                         req->operation);
     993         162 :         if (ret != LDB_SUCCESS) {
     994           0 :                 talloc_free(tmp_ctx);
     995           0 :                 return ret;
     996             :         }
     997             : 
     998         162 :         account_name_len = samAccountName->length;
     999         162 :         if (account_name_len && samAccountName->data[account_name_len - 1] == '$') {
    1000             :                 /* Account for the '$' character. */
    1001         153 :                 --account_name_len;
    1002             :         }
    1003             : 
    1004             :         /* Check for add or replace requests with no value. */
    1005         162 :         if (el->num_values == 0) {
    1006           9 :                 talloc_free(tmp_ctx);
    1007           9 :                 return ldb_operr(ldb);
    1008             :         }
    1009         153 :         dnsHostName = &el->values[0];
    1010             : 
    1011         153 :         dnsHostName_str = (const char *)dnsHostName->data;
    1012         153 :         dns_host_name_len = dnsHostName->length;
    1013             : 
    1014             :         /* Check that sAMAccountName matches the new dNSHostName. */
    1015             : 
    1016         153 :         if (dns_host_name_len < account_name_len) {
    1017          18 :                 goto fail;
    1018             :         }
    1019         135 :         if (strncasecmp(dnsHostName_str,
    1020         135 :                         (const char *)samAccountName->data,
    1021             :                         account_name_len) != 0)
    1022             :         {
    1023          24 :                 goto fail;
    1024             :         }
    1025             : 
    1026         111 :         dnsHostName_str += account_name_len;
    1027         111 :         dns_host_name_len -= account_name_len;
    1028             : 
    1029             :         /* Check the '.' character */
    1030             : 
    1031         111 :         if (dns_host_name_len == 0 || *dnsHostName_str != '.') {
    1032          39 :                 goto fail;
    1033             :         }
    1034             : 
    1035          72 :         ++dnsHostName_str;
    1036          72 :         --dns_host_name_len;
    1037             : 
    1038             :         /* Now we check the suffix. */
    1039             : 
    1040          72 :         ret = dsdb_find_nc_root(ldb,
    1041             :                                 tmp_ctx,
    1042          72 :                                 search_res->dn,
    1043             :                                 &nc_root);
    1044          72 :         if (ret != LDB_SUCCESS) {
    1045           0 :                 talloc_free(tmp_ctx);
    1046           0 :                 return ret;
    1047             :         }
    1048             : 
    1049          72 :         nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root);
    1050          72 :         if (nc_dns_name == NULL) {
    1051           0 :                 talloc_free(tmp_ctx);
    1052           0 :                 return ldb_operr(ldb);
    1053             :         }
    1054             : 
    1055          72 :         if (strlen(nc_dns_name) == dns_host_name_len &&
    1056          51 :             strncasecmp(dnsHostName_str,
    1057             :                         nc_dns_name,
    1058             :                         dns_host_name_len) == 0)
    1059             :         {
    1060             :                 /* It matches -- success. */
    1061          51 :                 talloc_free(tmp_ctx);
    1062          51 :                 return LDB_SUCCESS;
    1063             :         }
    1064             : 
    1065             :         /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */
    1066             : 
    1067          21 :         ret = dsdb_module_search_dn(module, tmp_ctx,
    1068             :                                     &nc_res, nc_root,
    1069             :                                     nc_attrs,
    1070             :                                     DSDB_FLAG_NEXT_MODULE |
    1071             :                                     DSDB_FLAG_AS_SYSTEM |
    1072             :                                     DSDB_SEARCH_SHOW_RECYCLED,
    1073             :                                     req);
    1074          21 :         if (ret != LDB_SUCCESS) {
    1075           0 :                 talloc_free(tmp_ctx);
    1076           0 :                 return ret;
    1077             :         }
    1078             : 
    1079          21 :         allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0],
    1080             :                                                 "msDS-AllowedDNSSuffixes");
    1081          21 :         if (allowed_suffixes == NULL) {
    1082          12 :                 goto fail;
    1083             :         }
    1084             : 
    1085           9 :         for (i = 0; i < allowed_suffixes->num_values; ++i) {
    1086           9 :                 const struct ldb_val *suffix = &allowed_suffixes->values[i];
    1087             : 
    1088           9 :                 if (suffix->length == dns_host_name_len &&
    1089           9 :                     strncasecmp(dnsHostName_str,
    1090           9 :                                 (const char *)suffix->data,
    1091             :                                 dns_host_name_len) == 0)
    1092             :                 {
    1093             :                         /* It matches -- success. */
    1094           9 :                         talloc_free(tmp_ctx);
    1095           9 :                         return LDB_SUCCESS;
    1096             :                 }
    1097             :         }
    1098             : 
    1099           0 : fail:
    1100          93 :         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
    1101             :                       "acl: hostname validation failed for "
    1102             :                       "hostname[%.*s] account[%.*s]\n",
    1103          93 :                       (int)dnsHostName->length, dnsHostName->data,
    1104          93 :                       (int)samAccountName->length, samAccountName->data);
    1105          93 :         talloc_free(tmp_ctx);
    1106          93 :         return LDB_ERR_CONSTRAINT_VIOLATION;
    1107             : }
    1108             : 
    1109             : /* checks if modifications are allowed on "Member" attribute */
    1110        8013 : static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
    1111             :                                      struct ldb_module *module,
    1112             :                                      struct ldb_request *req,
    1113             :                                      struct security_descriptor *sd,
    1114             :                                      struct dom_sid *sid,
    1115             :                                      const struct dsdb_attribute *attr,
    1116             :                                      const struct dsdb_class *objectclass)
    1117             : {
    1118           0 :         int ret;
    1119           0 :         unsigned int i;
    1120        8013 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1121           0 :         struct ldb_dn *user_dn;
    1122           0 :         struct ldb_message_element *member_el;
    1123        8013 :         const struct ldb_message *msg = NULL;
    1124             : 
    1125        8013 :         if (req->operation == LDB_MODIFY) {
    1126        8013 :                 msg = req->op.mod.message;
    1127           0 :         } else if (req->operation == LDB_ADD) {
    1128           0 :                 msg = req->op.add.message;
    1129             :         } else {
    1130           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1131             :         }
    1132             : 
    1133             :         /* if we have wp, we can do whatever we like */
    1134        8013 :         if (acl_check_access_on_attribute(module,
    1135             :                                           mem_ctx,
    1136             :                                           sd,
    1137             :                                           sid,
    1138             :                                           SEC_ADS_WRITE_PROP,
    1139             :                                           attr, objectclass) == LDB_SUCCESS) {
    1140        7953 :                 return LDB_SUCCESS;
    1141             :         }
    1142             :         /* if we are adding/deleting ourselves, check for self membership */
    1143          60 :         ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
    1144          60 :                                   &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
    1145             :                                   &user_dn);
    1146          60 :         if (ret != LDB_SUCCESS) {
    1147           0 :                 return ret;
    1148             :         }
    1149          60 :         member_el = ldb_msg_find_element(msg, "member");
    1150          60 :         if (!member_el) {
    1151           0 :                 return ldb_operr(ldb);
    1152             :         }
    1153             :         /* user can only remove oneself */
    1154          60 :         if (member_el->num_values == 0) {
    1155           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1156             :         }
    1157          87 :         for (i = 0; i < member_el->num_values; i++) {
    1158          69 :                 if (strcasecmp((const char *)member_el->values[i].data,
    1159          69 :                                ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
    1160          42 :                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1161             :                 }
    1162             :         }
    1163          18 :         ret = acl_check_extended_right(mem_ctx,
    1164             :                                        module,
    1165             :                                        req,
    1166             :                                        objectclass,
    1167             :                                        sd,
    1168             :                                        acl_user_token(module),
    1169             :                                        GUID_DRS_SELF_MEMBERSHIP,
    1170             :                                        SEC_ADS_SELF_WRITE,
    1171             :                                        sid);
    1172          18 :         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1173           9 :                 dsdb_acl_debug(sd, acl_user_token(module),
    1174           9 :                                msg->dn,
    1175             :                                true,
    1176             :                                10);
    1177             :         }
    1178          18 :         return ret;
    1179             : }
    1180             : 
    1181      543783 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
    1182             : {
    1183       83679 :         int ret;
    1184       83679 :         struct ldb_dn *parent;
    1185       83679 :         struct ldb_context *ldb;
    1186       83679 :         const struct dsdb_schema *schema;
    1187       83679 :         const struct dsdb_class *objectclass;
    1188      543783 :         const struct dsdb_class *computer_objectclass = NULL;
    1189      543783 :         const struct ldb_message_element *oc_el = NULL;
    1190       83679 :         struct ldb_message_element sorted_oc_el;
    1191      543783 :         struct ldb_control *sd_ctrl = NULL;
    1192       83679 :         struct ldb_message_element *el;
    1193      543783 :         unsigned int instanceType = 0;
    1194      543783 :         struct dsdb_control_calculated_default_sd *control_sd = NULL;
    1195      543783 :         const struct dsdb_attribute *attr = NULL;
    1196      543783 :         const char **must_contain = NULL;
    1197      543783 :         const struct ldb_message *msg = req->op.add.message;
    1198      543783 :         const struct dom_sid *domain_sid = NULL;
    1199      543783 :         int i = 0;
    1200       83679 :         bool attribute_authorization;
    1201       83679 :         bool is_subclass;
    1202             : 
    1203      543783 :         if (ldb_dn_is_special(msg->dn)) {
    1204         538 :                 return ldb_next_request(module, req);
    1205             :         }
    1206             : 
    1207      543245 :         if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
    1208             :         {
    1209        4567 :                 return ldb_next_request(module, req);
    1210             :         }
    1211             : 
    1212      538678 :         ldb = ldb_module_get_ctx(module);
    1213      538678 :         domain_sid = samdb_domain_sid(ldb);
    1214             : 
    1215      538678 :         parent = ldb_dn_get_parent(req, msg->dn);
    1216      538678 :         if (parent == NULL) {
    1217           0 :                 return ldb_oom(ldb);
    1218             :         }
    1219             : 
    1220      538678 :         schema = dsdb_get_schema(ldb, req);
    1221      538678 :         if (!schema) {
    1222           0 :                 return ldb_operr(ldb);
    1223             :         }
    1224             : 
    1225             :         /* Find the objectclass of the new account. */
    1226             : 
    1227      538678 :         oc_el = ldb_msg_find_element(msg, "objectclass");
    1228      538678 :         if (oc_el == NULL) {
    1229           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1230             :                                        "acl: unable to find or validate structural objectClass on %s\n",
    1231           0 :                                        ldb_dn_get_linearized(msg->dn));
    1232           0 :                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
    1233             :         }
    1234             : 
    1235      538678 :         schema = dsdb_get_schema(ldb, req);
    1236      538678 :         if (schema == NULL) {
    1237           0 :                 return ldb_operr(ldb);
    1238             :         }
    1239             : 
    1240      538678 :         ret = dsdb_sort_objectClass_attr(ldb, schema, oc_el, req, &sorted_oc_el);
    1241      538678 :         if (ret != LDB_SUCCESS) {
    1242           0 :                 return ret;
    1243             :         }
    1244             : 
    1245      538678 :         objectclass = dsdb_get_last_structural_class(schema, &sorted_oc_el);
    1246      538678 :         if (objectclass == NULL) {
    1247           0 :                 return ldb_operr(ldb);
    1248             :         }
    1249             : 
    1250      538678 :         el = ldb_msg_find_element(msg, "instanceType");
    1251      538678 :         if ((el != NULL) && (el->num_values != 1)) {
    1252           1 :                 ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
    1253           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1254             :         }
    1255             : 
    1256      538677 :         instanceType = ldb_msg_find_attr_as_uint(msg,
    1257             :                                                  "instanceType", 0);
    1258      538677 :         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
    1259         108 :                 static const char *no_attrs[] = { NULL };
    1260         108 :                 struct ldb_result *partition_res;
    1261         108 :                 struct ldb_dn *partitions_dn;
    1262             : 
    1263         609 :                 partitions_dn = samdb_partitions_dn(ldb, req);
    1264         609 :                 if (!partitions_dn) {
    1265           0 :                         ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
    1266           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1267             :                 }
    1268             : 
    1269         609 :                 ret = dsdb_module_search(module, req, &partition_res,
    1270             :                                          partitions_dn, LDB_SCOPE_ONELEVEL,
    1271             :                                          no_attrs,
    1272             :                                          DSDB_FLAG_NEXT_MODULE |
    1273             :                                          DSDB_FLAG_AS_SYSTEM |
    1274             :                                          DSDB_SEARCH_ONE_ONLY |
    1275             :                                          DSDB_SEARCH_SHOW_RECYCLED,
    1276             :                                          req,
    1277             :                                          "(&(nCName=%s)(objectClass=crossRef))",
    1278         609 :                                          ldb_dn_get_linearized(msg->dn));
    1279             : 
    1280         609 :                 if (ret == LDB_SUCCESS) {
    1281             :                         /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
    1282           0 :                         ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
    1283             :                                                              SEC_ADS_WRITE_PROP,
    1284             :                                                              &objectclass->schemaIDGUID, req);
    1285           0 :                         if (ret != LDB_SUCCESS) {
    1286           0 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1287             :                                                        "acl: ACL check failed on crossRef object %s: %s\n",
    1288           0 :                                                        ldb_dn_get_linearized(partition_res->msgs[0]->dn),
    1289             :                                                        ldb_errstring(ldb));
    1290           0 :                                 return ret;
    1291             :                         }
    1292             : 
    1293             :                         /*
    1294             :                          * TODO: Remaining checks, like if we are
    1295             :                          * the naming master etc need to be handled
    1296             :                          * in the instanceType module
    1297             :                          */
    1298             :                         /* Note - do we need per-attribute checks? */
    1299           0 :                         return ldb_next_request(module, req);
    1300             :                 }
    1301             : 
    1302             :                 /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
    1303         609 :                 ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
    1304             :                                                      SEC_ADS_CREATE_CHILD,
    1305             :                                                      &objectclass->schemaIDGUID, req);
    1306         990 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
    1307         381 :                     ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
    1308             :                 {
    1309             :                         /* Allow provision bootstrap */
    1310         315 :                         ret = LDB_SUCCESS;
    1311             :                 }
    1312         543 :                 if (ret != LDB_SUCCESS) {
    1313           0 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1314             :                                                "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
    1315             :                                                ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
    1316           0 :                         return ret;
    1317             :                 }
    1318             : 
    1319             :                 /*
    1320             :                  * TODO: Remaining checks, like if we are the naming
    1321             :                  * master and adding the crossRef object need to be
    1322             :                  * handled in the instanceType module
    1323             :                  */
    1324             :         } else {
    1325      538068 :                 ret = dsdb_module_check_access_on_dn(module, req, parent,
    1326             :                                                      SEC_ADS_CREATE_CHILD,
    1327             :                                                      &objectclass->schemaIDGUID, req);
    1328      538068 :                 if (ret != LDB_SUCCESS) {
    1329          24 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1330             :                                                "acl: unable to get access to %s\n",
    1331          24 :                                                ldb_dn_get_linearized(msg->dn));
    1332          24 :                         return ret;
    1333             :                 }
    1334             :         }
    1335             : 
    1336      538653 :         attribute_authorization = dsdb_attribute_authz_on_ldap_add(module,
    1337             :                                                                    req,
    1338             :                                                                    req);
    1339      538653 :         if (!attribute_authorization) {
    1340             :                 /* Skip the remaining checks */
    1341      522921 :                 goto success;
    1342             :         }
    1343             : 
    1344             :         /* Check if we have computer objectclass. */
    1345       15732 :         computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
    1346       15732 :         if (computer_objectclass == NULL) {
    1347           0 :                 return ldb_operr(ldb);
    1348             :         }
    1349             : 
    1350       15732 :         is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
    1351       15732 :         if (!is_subclass) {
    1352             :                 /*
    1353             :                  * This object is not a computer (or derived from computer), so
    1354             :                  * skip the remaining checks.
    1355             :                  */
    1356       14958 :                 goto success;
    1357             :         }
    1358             : 
    1359             :         /*
    1360             :          * we have established we have CC right, now check per-attribute
    1361             :          * access based on the default SD
    1362             :          */
    1363             : 
    1364         774 :         sd_ctrl = ldb_request_get_control(req,
    1365             :                                           DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID);
    1366         774 :         if (sd_ctrl == NULL) {
    1367           0 :                 goto success;
    1368             :         }
    1369             : 
    1370             :         {
    1371         774 :                 TALLOC_CTX *tmp_ctx = talloc_new(req);
    1372         774 :                 control_sd = (struct dsdb_control_calculated_default_sd *) sd_ctrl->data;
    1373         774 :                 DBG_DEBUG("Received cookie descriptor %s\n\n",
    1374             :                           sddl_encode(tmp_ctx, control_sd->default_sd, domain_sid));
    1375         774 :                 TALLOC_FREE(tmp_ctx);
    1376             :                 /* Mark the "change" control as uncritical (done) */
    1377         774 :                 sd_ctrl->critical = false;
    1378             :         }
    1379             : 
    1380             :         /*
    1381             :          * At this point we do not yet have the object's SID, so we
    1382             :          * leave it empty. It is irrelevant, as it is used to expand
    1383             :          * Principal-Self, and rights granted to PS will have no effect
    1384             :          * in this case
    1385             :          */
    1386             :         /* check if we have WD, no need to perform other attribute checks if we do */
    1387         774 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, "nTSecurityDescriptor");
    1388         774 :         if (attr == NULL) {
    1389           0 :                 return ldb_operr(ldb);
    1390             :         }
    1391             : 
    1392         774 :         if (control_sd->specified_sacl) {
    1393          18 :                 const struct security_token *token = acl_user_token(module);
    1394          18 :                 bool has_priv = security_token_has_privilege(token, SEC_PRIV_SECURITY);
    1395          18 :                 if (!has_priv) {
    1396          18 :                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1397             :                 }
    1398             :         }
    1399             : 
    1400         756 :         ret = acl_check_access_on_attribute(module,
    1401             :                                             req,
    1402             :                                             control_sd->default_sd,
    1403             :                                             NULL,
    1404             :                                             SEC_STD_WRITE_DAC,
    1405             :                                             attr,
    1406             :                                             objectclass);
    1407         756 :         if (ret == LDB_SUCCESS) {
    1408         486 :                 goto success;
    1409             :         }
    1410             : 
    1411         270 :         if (control_sd->specified_sd) {
    1412         126 :                 bool block_owner_rights = dsdb_block_owner_implicit_rights(module,
    1413             :                                                                            req,
    1414             :                                                                            req);
    1415         126 :                 if (block_owner_rights) {
    1416         108 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1417             :                                                "Object %s has no SD modification rights",
    1418         108 :                                                ldb_dn_get_linearized(msg->dn));
    1419         108 :                         dsdb_acl_debug(control_sd->default_sd,
    1420             :                                        acl_user_token(module),
    1421         108 :                                        msg->dn,
    1422             :                                        true,
    1423             :                                        10);
    1424         108 :                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1425         108 :                         return ret;
    1426             :                 }
    1427             :         }
    1428             : 
    1429         162 :         must_contain = dsdb_full_attribute_list(req, schema, &sorted_oc_el,
    1430             :                                                 DSDB_SCHEMA_ALL_MUST);
    1431         702 :         for (i=0; i < msg->num_elements; i++) {
    1432         603 :                 el = &msg->elements[i];
    1433             : 
    1434         603 :                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
    1435         603 :                 if (attr == NULL && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
    1436           0 :                         ldb_asprintf_errstring(ldb, "acl_add: attribute '%s' "
    1437             :                                                "on entry '%s' was not found in the schema!",
    1438             :                                                el->name,
    1439           0 :                                        ldb_dn_get_linearized(msg->dn));
    1440           0 :                         ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
    1441           0 :                         return ret;
    1442             :                 }
    1443             : 
    1444         603 :                 if (attr != NULL) {
    1445         594 :                         bool found = str_list_check(must_contain, attr->lDAPDisplayName);
    1446             :                         /* do not check the mandatory attributes */
    1447         594 :                         if (found) {
    1448         450 :                                 continue;
    1449             :                         }
    1450             :                 }
    1451             : 
    1452         153 :                 if (ldb_attr_cmp("dBCSPwd", el->name) == 0 ||
    1453         153 :                            ldb_attr_cmp("unicodePwd", el->name) == 0 ||
    1454         144 :                            ldb_attr_cmp("userPassword", el->name) == 0 ||
    1455         126 :                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
    1456          36 :                         continue;
    1457         117 :                 } else if (ldb_attr_cmp("member", el->name) == 0) {
    1458           0 :                         ret = acl_check_self_membership(req,
    1459             :                                                         module,
    1460             :                                                         req,
    1461             :                                                         control_sd->default_sd,
    1462             :                                                         NULL,
    1463             :                                                         attr,
    1464             :                                                         objectclass);
    1465           0 :                         if (ret != LDB_SUCCESS) {
    1466           0 :                                 return ret;
    1467             :                         }
    1468         117 :                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
    1469          36 :                         ret = acl_check_spn(req,
    1470             :                                             module,
    1471             :                                             req,
    1472             :                                             el,
    1473             :                                             control_sd->default_sd,
    1474             :                                             NULL,
    1475             :                                             attr,
    1476             :                                             objectclass,
    1477             :                                             NULL);
    1478          36 :                         if (ret != LDB_SUCCESS) {
    1479          18 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1480             :                                                        "Object %s cannot be created with spn",
    1481          18 :                                                        ldb_dn_get_linearized(msg->dn));
    1482          18 :                                 dsdb_acl_debug(control_sd->default_sd,
    1483             :                                                acl_user_token(module),
    1484          18 :                                                msg->dn,
    1485             :                                                true,
    1486             :                                                10);
    1487          18 :                                 return ret;
    1488             :                         }
    1489          81 :                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
    1490           0 :                         ret = acl_check_dns_host_name(req,
    1491             :                                                       module,
    1492             :                                                       req,
    1493             :                                                       el,
    1494             :                                                       control_sd->default_sd,
    1495             :                                                       NULL,
    1496             :                                                       attr,
    1497             :                                                       objectclass,
    1498             :                                                       NULL);
    1499           0 :                         if (ret != LDB_SUCCESS) {
    1500           0 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1501             :                                                        "Object %s cannot be created with dnsHostName",
    1502           0 :                                                        ldb_dn_get_linearized(msg->dn));
    1503           0 :                                 dsdb_acl_debug(control_sd->default_sd,
    1504             :                                                acl_user_token(module),
    1505           0 :                                                msg->dn,
    1506             :                                                true,
    1507             :                                                10);
    1508           0 :                                 return ret;
    1509             :                         }
    1510             :                 } else {
    1511          81 :                         ret = acl_check_access_on_attribute(module,
    1512             :                                                             req,
    1513             :                                                             control_sd->default_sd,
    1514             :                                                             NULL,
    1515             :                                                             SEC_ADS_WRITE_PROP,
    1516             :                                                             attr,
    1517             :                                                             objectclass);
    1518          81 :                         if (ret != LDB_SUCCESS) {
    1519          45 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1520             :                                                        "Object %s has no write property access",
    1521          45 :                                                        ldb_dn_get_linearized(msg->dn));
    1522          45 :                                 dsdb_acl_debug(control_sd->default_sd,
    1523             :                                                acl_user_token(module),
    1524          45 :                                                msg->dn,
    1525             :                                                true,
    1526             :                                                10);
    1527          45 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1528          45 :                                 return ret;
    1529             :                         }
    1530             :                 }
    1531             :         }
    1532          99 : success:
    1533      538464 :         return ldb_next_request(module, req);
    1534             : }
    1535             : 
    1536       17089 : static int acl_check_password_rights(
    1537             :         TALLOC_CTX *mem_ctx,
    1538             :         struct ldb_module *module,
    1539             :         struct ldb_request *req,
    1540             :         struct security_descriptor *sd,
    1541             :         struct dom_sid *sid,
    1542             :         const struct dsdb_class *objectclass,
    1543             :         bool userPassword,
    1544             :         struct  dsdb_control_password_acl_validation **control_for_response)
    1545             : {
    1546       17089 :         int ret = LDB_SUCCESS;
    1547       17089 :         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
    1548       17089 :         unsigned int del_val_cnt = 0, add_val_cnt = 0;
    1549          72 :         struct ldb_message_element *el;
    1550          72 :         struct ldb_message *msg;
    1551       17089 :         struct ldb_control *c = NULL;
    1552       17089 :         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
    1553             :                                         "unicodePwd", NULL }, **l;
    1554       17089 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1555       17089 :         struct dsdb_control_password_acl_validation *pav = NULL;
    1556             : 
    1557       17089 :         if (tmp_ctx == NULL) {
    1558           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1559             :         }
    1560             : 
    1561       17089 :         pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
    1562       17089 :         if (pav == NULL) {
    1563           0 :                 talloc_free(tmp_ctx);
    1564           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1565             :         }
    1566             :         /*
    1567             :          * Set control_for_response to pav so it can be added to the response
    1568             :          * and be passed up to the audit_log module which uses it to identify
    1569             :          * password reset attempts.
    1570             :          */
    1571       17089 :         *control_for_response = pav;
    1572             : 
    1573       17089 :         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
    1574       17089 :         if (c != NULL) {
    1575         522 :                 pav->pwd_reset = false;
    1576             : 
    1577             :                 /*
    1578             :                  * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
    1579             :                  * have a user password change and not a set as the message
    1580             :                  * looks like. In it's value blob it contains the NT and/or LM
    1581             :                  * hash of the old password specified by the user.  This control
    1582             :                  * is used by the SAMR and "kpasswd" password change mechanisms.
    1583             :                  *
    1584             :                  * This control can't be used by real LDAP clients,
    1585             :                  * the only caller is samdb_set_password_internal(),
    1586             :                  * so we don't have to strict verification of the input.
    1587             :                  */
    1588         522 :                 ret = acl_check_extended_right(tmp_ctx,
    1589             :                                                module,
    1590             :                                                req,
    1591             :                                                objectclass,
    1592             :                                                sd,
    1593             :                                                acl_user_token(module),
    1594             :                                                GUID_DRS_USER_CHANGE_PASSWORD,
    1595             :                                                SEC_ADS_CONTROL_ACCESS,
    1596             :                                                sid);
    1597         522 :                 goto checked;
    1598             :         }
    1599             : 
    1600       16567 :         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
    1601       16567 :         if (c != NULL) {
    1602         310 :                 pav->pwd_reset = true;
    1603             : 
    1604             :                 /*
    1605             :                  * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
    1606             :                  * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
    1607             :                  * have a force password set.
    1608             :                  * This control is used by the SAMR/NETLOGON/LSA password
    1609             :                  * reset mechanisms.
    1610             :                  *
    1611             :                  * This control can't be used by real LDAP clients,
    1612             :                  * the only caller is samdb_set_password_internal(),
    1613             :                  * so we don't have to strict verification of the input.
    1614             :                  */
    1615         310 :                 ret = acl_check_extended_right(tmp_ctx,
    1616             :                                                module,
    1617             :                                                req,
    1618             :                                                objectclass,
    1619             :                                                sd,
    1620             :                                                acl_user_token(module),
    1621             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1622             :                                                SEC_ADS_CONTROL_ACCESS,
    1623             :                                                sid);
    1624         310 :                 goto checked;
    1625             :         }
    1626             : 
    1627       16257 :         el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
    1628       16257 :         if (el != NULL) {
    1629             :                 /*
    1630             :                  * dBCSPwd is only allowed with a control.
    1631             :                  */
    1632           0 :                 talloc_free(tmp_ctx);
    1633           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1634             :         }
    1635             : 
    1636       16257 :         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
    1637       16257 :         if (msg == NULL) {
    1638           0 :                 return ldb_module_oom(module);
    1639             :         }
    1640       65028 :         for (l = passwordAttrs; *l != NULL; l++) {
    1641       48771 :                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
    1642       13465 :                         continue;
    1643             :                 }
    1644             : 
    1645       53647 :                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
    1646       18341 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
    1647        2093 :                                 ++del_attr_cnt;
    1648        2093 :                                 del_val_cnt += el->num_values;
    1649             :                         }
    1650       18341 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
    1651        2057 :                                 ++add_attr_cnt;
    1652        2057 :                                 add_val_cnt += el->num_values;
    1653             :                         }
    1654       18341 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
    1655       14191 :                                 ++rep_attr_cnt;
    1656             :                         }
    1657       18341 :                         ldb_msg_remove_element(msg, el);
    1658             :                 }
    1659             :         }
    1660             : 
    1661             :         /* single deletes will be handled by the "password_hash" LDB module
    1662             :          * later in the stack, so we let it though here */
    1663       16257 :         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
    1664          63 :                 talloc_free(tmp_ctx);
    1665          63 :                 return LDB_SUCCESS;
    1666             :         }
    1667             : 
    1668             : 
    1669       16194 :         if (rep_attr_cnt > 0) {
    1670       14173 :                 pav->pwd_reset = true;
    1671             : 
    1672       14173 :                 ret = acl_check_extended_right(tmp_ctx,
    1673             :                                                module,
    1674             :                                                req,
    1675             :                                                objectclass,
    1676             :                                                sd,
    1677             :                                                acl_user_token(module),
    1678             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1679             :                                                SEC_ADS_CONTROL_ACCESS,
    1680             :                                                sid);
    1681       14173 :                 goto checked;
    1682             :         }
    1683             : 
    1684        2021 :         if (add_attr_cnt != del_attr_cnt) {
    1685          99 :                 pav->pwd_reset = true;
    1686             : 
    1687          99 :                 ret = acl_check_extended_right(tmp_ctx,
    1688             :                                                module,
    1689             :                                                req,
    1690             :                                                objectclass,
    1691             :                                                sd,
    1692             :                                                acl_user_token(module),
    1693             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1694             :                                                SEC_ADS_CONTROL_ACCESS,
    1695             :                                                sid);
    1696          99 :                 goto checked;
    1697             :         }
    1698             : 
    1699        1922 :         if (add_val_cnt == 1 && del_val_cnt == 1) {
    1700        1123 :                 pav->pwd_reset = false;
    1701             : 
    1702        1123 :                 ret = acl_check_extended_right(tmp_ctx,
    1703             :                                                module,
    1704             :                                                req,
    1705             :                                                objectclass,
    1706             :                                                sd,
    1707             :                                                acl_user_token(module),
    1708             :                                                GUID_DRS_USER_CHANGE_PASSWORD,
    1709             :                                                SEC_ADS_CONTROL_ACCESS,
    1710             :                                                sid);
    1711             :                 /* Very strange, but we get constraint violation in this case */
    1712        1123 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1713          18 :                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
    1714             :                 }
    1715        1123 :                 goto checked;
    1716             :         }
    1717             : 
    1718         799 :         if (add_val_cnt == 1 && del_val_cnt == 0) {
    1719         529 :                 pav->pwd_reset = true;
    1720             : 
    1721         529 :                 ret = acl_check_extended_right(tmp_ctx,
    1722             :                                                module,
    1723             :                                                req,
    1724             :                                                objectclass,
    1725             :                                                sd,
    1726             :                                                acl_user_token(module),
    1727             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1728             :                                                SEC_ADS_CONTROL_ACCESS,
    1729             :                                                sid);
    1730             :                 /* Very strange, but we get constraint violation in this case */
    1731         529 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1732          27 :                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
    1733             :                 }
    1734         529 :                 goto checked;
    1735             :         }
    1736             : 
    1737             :         /*
    1738             :          * Everything else is handled by the password_hash module where it will
    1739             :          * fail, but with the correct error code when the module is again
    1740             :          * checking the attributes. As the change request will lack the
    1741             :          * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
    1742             :          * any modification attempt that went this way will be rejected.
    1743             :          */
    1744             : 
    1745         270 :         talloc_free(tmp_ctx);
    1746         270 :         return LDB_SUCCESS;
    1747             : 
    1748       16756 : checked:
    1749       16756 :         if (ret != LDB_SUCCESS) {
    1750         142 :                 dsdb_acl_debug(sd, acl_user_token(module),
    1751         142 :                                req->op.mod.message->dn,
    1752             :                                true,
    1753             :                                10);
    1754         142 :                 talloc_free(tmp_ctx);
    1755         142 :                 return ret;
    1756             :         }
    1757             : 
    1758       16614 :         ret = ldb_request_add_control(req,
    1759             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
    1760       16614 :         if (ret != LDB_SUCCESS) {
    1761           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
    1762             :                           "Unable to register ACL validation control!\n");
    1763           0 :                 return ret;
    1764             :         }
    1765       16542 :         return LDB_SUCCESS;
    1766             : }
    1767             : 
    1768             : /*
    1769             :  * Context needed by acl_callback
    1770             :  */
    1771             : struct acl_callback_context {
    1772             :         struct ldb_request *request;
    1773             :         struct ldb_module *module;
    1774             : };
    1775             : 
    1776             : /*
    1777             :  * @brief Copy the password validation control to the reply.
    1778             :  *
    1779             :  * Copy the dsdb_control_password_acl_validation control from the request,
    1780             :  * to the reply.  The control is used by the audit_log module to identify
    1781             :  * password rests.
    1782             :  *
    1783             :  * @param req the ldb request.
    1784             :  * @param ares the result, updated with the control.
    1785             :  */
    1786      118246 : static void copy_password_acl_validation_control(
    1787             :         struct ldb_request *req,
    1788             :         struct ldb_reply *ares)
    1789             : {
    1790      118246 :         struct ldb_control *pav_ctrl = NULL;
    1791      118246 :         struct dsdb_control_password_acl_validation *pav = NULL;
    1792             : 
    1793      118246 :         pav_ctrl = ldb_request_get_control(
    1794             :                 discard_const(req),
    1795             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
    1796      118246 :         if (pav_ctrl == NULL) {
    1797       98517 :                 return;
    1798             :         }
    1799             : 
    1800       16614 :         pav = talloc_get_type_abort(
    1801             :                 pav_ctrl->data,
    1802             :                 struct dsdb_control_password_acl_validation);
    1803       16614 :         if (pav == NULL) {
    1804           0 :                 return;
    1805             :         }
    1806       16614 :         ldb_reply_add_control(
    1807             :                 ares,
    1808             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
    1809             :                 false,
    1810             :                 pav);
    1811             : }
    1812             : /*
    1813             :  * @brief call back function for acl_modify.
    1814             :  *
    1815             :  * Calls acl_copy to copy the dsdb_control_password_acl_validation from
    1816             :  * the request to the reply.
    1817             :  *
    1818             :  * @param req the ldb_request.
    1819             :  * @param ares the operation result.
    1820             :  *
    1821             :  * @return the LDB_STATUS
    1822             :  */
    1823      118256 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
    1824             : {
    1825      118256 :         struct acl_callback_context *ac = NULL;
    1826             : 
    1827      118256 :         ac = talloc_get_type(req->context, struct acl_callback_context);
    1828             : 
    1829      118256 :         if (!ares) {
    1830           0 :                 return ldb_module_done(
    1831             :                         ac->request,
    1832             :                         NULL,
    1833             :                         NULL,
    1834             :                         LDB_ERR_OPERATIONS_ERROR);
    1835             :         }
    1836             : 
    1837             :         /* pass on to the callback */
    1838      118256 :         switch (ares->type) {
    1839           0 :         case LDB_REPLY_ENTRY:
    1840           0 :                 return ldb_module_send_entry(
    1841             :                         ac->request,
    1842             :                         ares->message,
    1843             :                         ares->controls);
    1844             : 
    1845          10 :         case LDB_REPLY_REFERRAL:
    1846          10 :                 return ldb_module_send_referral(
    1847             :                         ac->request,
    1848             :                         ares->referral);
    1849             : 
    1850      118246 :         case LDB_REPLY_DONE:
    1851             :                 /*
    1852             :                  * Copy the ACL control from the request to the response
    1853             :                  */
    1854      118246 :                 copy_password_acl_validation_control(req, ares);
    1855      118246 :                 return ldb_module_done(
    1856             :                         ac->request,
    1857             :                         ares->controls,
    1858             :                         ares->response,
    1859             :                         ares->error);
    1860             : 
    1861           0 :         default:
    1862             :                 /* Can't happen */
    1863           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1864             :         }
    1865             : }
    1866             : 
    1867      585629 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
    1868             : {
    1869       21592 :         int ret;
    1870      585629 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1871       21592 :         const struct dsdb_schema *schema;
    1872       21592 :         unsigned int i;
    1873       21592 :         const struct dsdb_class *objectclass;
    1874       21592 :         struct ldb_result *acl_res;
    1875       21592 :         struct security_descriptor *sd;
    1876      585629 :         struct dom_sid *sid = NULL;
    1877       21592 :         struct ldb_control *is_undelete;
    1878      585629 :         struct ldb_control *implicit_validated_write_control = NULL;
    1879       21592 :         bool userPassword;
    1880      585629 :         bool password_rights_checked = false;
    1881       21592 :         TALLOC_CTX *tmp_ctx;
    1882      585629 :         const struct ldb_message *msg = req->op.mod.message;
    1883       21592 :         static const char *acl_attrs[] = {
    1884             :                 "nTSecurityDescriptor",
    1885             :                 "objectClass",
    1886             :                 "objectSid",
    1887             :                 NULL
    1888             :         };
    1889      585629 :         struct acl_callback_context *context = NULL;
    1890      585629 :         struct ldb_request *new_req = NULL;
    1891      585629 :         struct  dsdb_control_password_acl_validation *pav = NULL;
    1892      585629 :         struct ldb_control **controls = NULL;
    1893             : 
    1894      585629 :         if (ldb_dn_is_special(msg->dn)) {
    1895         715 :                 return ldb_next_request(module, req);
    1896             :         }
    1897             : 
    1898      584914 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    1899             : 
    1900      584914 :         implicit_validated_write_control = ldb_request_get_control(
    1901             :                 req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
    1902      584914 :         if (implicit_validated_write_control != NULL) {
    1903         147 :                 implicit_validated_write_control->critical = 0;
    1904             :         }
    1905             : 
    1906             :         /* Don't print this debug statement if elements[0].name is going to be NULL */
    1907      584914 :         if (msg->num_elements > 0) {
    1908      584633 :                 DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
    1909             :         }
    1910      584914 :         if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
    1911             :         {
    1912      464893 :                 return ldb_next_request(module, req);
    1913             :         }
    1914             : 
    1915      120021 :         tmp_ctx = talloc_new(req);
    1916      120021 :         if (tmp_ctx == NULL) {
    1917           0 :                 return ldb_oom(ldb);
    1918             :         }
    1919             : 
    1920      120021 :         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
    1921             :                                     acl_attrs,
    1922             :                                     DSDB_FLAG_NEXT_MODULE |
    1923             :                                     DSDB_FLAG_AS_SYSTEM |
    1924             :                                     DSDB_SEARCH_SHOW_RECYCLED,
    1925             :                                     req);
    1926             : 
    1927      120021 :         if (ret != LDB_SUCCESS) {
    1928         122 :                 goto fail;
    1929             :         }
    1930             : 
    1931      119899 :         userPassword = dsdb_user_password_support(module, req, req);
    1932             : 
    1933      119899 :         schema = dsdb_get_schema(ldb, tmp_ctx);
    1934      119899 :         if (!schema) {
    1935           0 :                 talloc_free(tmp_ctx);
    1936           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1937             :                                  "acl_modify: Error obtaining schema.");
    1938             :         }
    1939             : 
    1940      119899 :         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
    1941      119899 :         if (ret != LDB_SUCCESS) {
    1942           0 :                 talloc_free(tmp_ctx);
    1943           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1944             :                                  "acl_modify: Error retrieving security descriptor.");
    1945             :         }
    1946             :         /* Theoretically we pass the check if the object has no sd */
    1947      119899 :         if (!sd) {
    1948           0 :                 goto success;
    1949             :         }
    1950             : 
    1951      119899 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    1952      119899 :         if (!objectclass) {
    1953           0 :                 talloc_free(tmp_ctx);
    1954           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1955             :                                  "acl_modify: Error retrieving object class for GUID.");
    1956             :         }
    1957      119899 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    1958      278711 :         for (i=0; i < msg->num_elements; i++) {
    1959      157273 :                 const struct ldb_message_element *el = &msg->elements[i];
    1960        4863 :                 const struct dsdb_attribute *attr;
    1961             : 
    1962             :                 /*
    1963             :                  * This basic attribute existence check with the right errorcode
    1964             :                  * is needed since this module is the first one which requests
    1965             :                  * schema attribute information.
    1966             :                  * The complete attribute checking is done in the
    1967             :                  * "objectclass_attrs" module behind this one.
    1968             :                  *
    1969             :                  * NOTE: "clearTextPassword" is not defined in the schema.
    1970             :                  */
    1971      157273 :                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
    1972      157273 :                 if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
    1973           4 :                         ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
    1974             :                                                "on entry '%s' was not found in the schema!",
    1975           2 :                                                req->op.mod.message->elements[i].name,
    1976           2 :                                        ldb_dn_get_linearized(req->op.mod.message->dn));
    1977           2 :                         ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
    1978           2 :                         goto fail;
    1979             :                 }
    1980             : 
    1981      157271 :                 if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
    1982       27364 :                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
    1983       27364 :                         uint32_t access_mask = 0;
    1984             : 
    1985          88 :                         bool block_owner_rights;
    1986          88 :                         enum implicit_owner_rights implicit_owner_rights;
    1987             : 
    1988       27364 :                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
    1989       12958 :                                 access_mask |= SEC_STD_WRITE_OWNER;
    1990             :                         }
    1991       27364 :                         if (sd_flags & SECINFO_DACL) {
    1992       27130 :                                 access_mask |= SEC_STD_WRITE_DAC;
    1993             :                         }
    1994       27364 :                         if (sd_flags & SECINFO_SACL) {
    1995       12706 :                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
    1996             :                         }
    1997             : 
    1998       27364 :                         block_owner_rights = !dsdb_module_am_administrator(module);
    1999             : 
    2000       27364 :                         if (block_owner_rights) {
    2001         180 :                                 block_owner_rights = dsdb_block_owner_implicit_rights(module,
    2002             :                                                                                       req,
    2003             :                                                                                       req);
    2004             :                         }
    2005       27364 :                         if (block_owner_rights) {
    2006         162 :                                 block_owner_rights = samdb_find_attribute(ldb,
    2007         162 :                                                                           acl_res->msgs[0],
    2008             :                                                                           "objectclass",
    2009             :                                                                           "computer");
    2010             :                         }
    2011             : 
    2012       27364 :                         implicit_owner_rights = block_owner_rights ?
    2013       27364 :                                 IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
    2014             :                                 IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
    2015             : 
    2016       27364 :                         ret = acl_check_access_on_attribute_implicit_owner(module,
    2017             :                                                                            tmp_ctx,
    2018             :                                                                            sd,
    2019             :                                                                            sid,
    2020             :                                                                            access_mask,
    2021             :                                                                            attr,
    2022             :                                                                            objectclass,
    2023             :                                                                            implicit_owner_rights);
    2024       27364 :                         if (ret != LDB_SUCCESS) {
    2025         108 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2026             :                                                        "Object %s has no write dacl access\n",
    2027         108 :                                                        ldb_dn_get_linearized(msg->dn));
    2028         108 :                                 dsdb_acl_debug(sd,
    2029             :                                                acl_user_token(module),
    2030         108 :                                                msg->dn,
    2031             :                                                true,
    2032             :                                                10);
    2033         108 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2034         108 :                                 goto fail;
    2035             :                         }
    2036      129907 :                 } else if (ldb_attr_cmp("member", el->name) == 0) {
    2037        8013 :                         ret = acl_check_self_membership(tmp_ctx,
    2038             :                                                         module,
    2039             :                                                         req,
    2040             :                                                         sd,
    2041             :                                                         sid,
    2042             :                                                         attr,
    2043             :                                                         objectclass);
    2044        8013 :                         if (ret != LDB_SUCCESS) {
    2045          51 :                                 goto fail;
    2046             :                         }
    2047      121894 :                 } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
    2048             :                         /* this one is not affected by any rights, we should let it through
    2049             :                            so that passwords_hash returns the correct error */
    2050          72 :                         continue;
    2051      121822 :                 } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
    2052        8318 :                            (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
    2053      104287 :                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
    2054             :                         /*
    2055             :                          * Ideally we would do the acl_check_password_rights
    2056             :                          * before we checked the other attributes, i.e. in a
    2057             :                          * loop before the current one.
    2058             :                          * Have not done this as yet in order to limit the size
    2059             :                          * of the change. To limit the possibility of breaking
    2060             :                          * the ACL logic.
    2061             :                          */
    2062       19056 :                         if (password_rights_checked) {
    2063        1967 :                                 continue;
    2064             :                         }
    2065       17089 :                         ret = acl_check_password_rights(tmp_ctx,
    2066             :                                                         module,
    2067             :                                                         req,
    2068             :                                                         sd,
    2069             :                                                         sid,
    2070             :                                                         objectclass,
    2071             :                                                         userPassword,
    2072             :                                                         &pav);
    2073       17089 :                         if (ret != LDB_SUCCESS) {
    2074         142 :                                 goto fail;
    2075             :                         }
    2076       16875 :                         password_rights_checked = true;
    2077      102766 :                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
    2078        2167 :                         ret = acl_check_spn(tmp_ctx,
    2079             :                                             module,
    2080             :                                             req,
    2081             :                                             el,
    2082             :                                             sd,
    2083             :                                             sid,
    2084             :                                             attr,
    2085             :                                             objectclass,
    2086             :                                             implicit_validated_write_control);
    2087        2167 :                         if (ret != LDB_SUCCESS) {
    2088         274 :                                 goto fail;
    2089             :                         }
    2090      100599 :                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
    2091         953 :                         ret = acl_check_dns_host_name(tmp_ctx,
    2092             :                                                       module,
    2093             :                                                       req,
    2094             :                                                       el,
    2095             :                                                       sd,
    2096             :                                                       sid,
    2097             :                                                       attr,
    2098             :                                                       objectclass,
    2099             :                                                       implicit_validated_write_control);
    2100         953 :                         if (ret != LDB_SUCCESS) {
    2101         180 :                                 goto fail;
    2102             :                         }
    2103       99646 :                 } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
    2104             :                         /*
    2105             :                          * in case of undelete op permissions on
    2106             :                          * isDeleted are irrelevant and
    2107             :                          * distinguishedName is removed by the
    2108             :                          * tombstone_reanimate module
    2109             :                          */
    2110         274 :                         continue;
    2111       99372 :                 } else if (implicit_validated_write_control != NULL) {
    2112             :                         /* Allow the update. */
    2113         441 :                         continue;
    2114             :                 } else {
    2115       98931 :                         ret = acl_check_access_on_attribute(module,
    2116             :                                                             tmp_ctx,
    2117             :                                                             sd,
    2118             :                                                             sid,
    2119             :                                                             SEC_ADS_WRITE_PROP,
    2120             :                                                             attr,
    2121             :                                                             objectclass);
    2122       98931 :                         if (ret != LDB_SUCCESS) {
    2123         894 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2124             :                                                        "Object %s has no write property access\n",
    2125         894 :                                                        ldb_dn_get_linearized(msg->dn));
    2126         894 :                                 dsdb_acl_debug(sd,
    2127             :                                                acl_user_token(module),
    2128         894 :                                                msg->dn,
    2129             :                                                true,
    2130             :                                                10);
    2131         894 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2132         894 :                                 goto fail;
    2133             :                         }
    2134             :                 }
    2135             :         }
    2136             : 
    2137      118248 : success:
    2138      118248 :         talloc_free(tmp_ctx);
    2139      118248 :         context = talloc_zero(req, struct acl_callback_context);
    2140             : 
    2141      118248 :         if (context == NULL) {
    2142           0 :                 return ldb_oom(ldb);
    2143             :         }
    2144      118248 :         context->request = req;
    2145      118248 :         context->module  = module;
    2146      118248 :         ret = ldb_build_mod_req(
    2147             :                 &new_req,
    2148             :                 ldb,
    2149             :                 req,
    2150             :                 req->op.mod.message,
    2151             :                 req->controls,
    2152             :                 context,
    2153             :                 acl_callback,
    2154             :                 req);
    2155      118248 :         if (ret != LDB_SUCCESS) {
    2156           0 :                 return ret;
    2157             :         }
    2158      118248 :         return ldb_next_request(module, new_req);
    2159        1773 : fail:
    2160        1773 :         talloc_free(tmp_ctx);
    2161             :         /*
    2162             :          * We copy the pav into the result, so that the password reset
    2163             :          * logging code in audit_log can log failed password reset attempts.
    2164             :          */
    2165        1773 :         if (pav) {
    2166         142 :                 struct ldb_control *control = NULL;
    2167             : 
    2168         142 :                 controls = talloc_zero_array(req, struct ldb_control *, 2);
    2169         142 :                 if (controls == NULL) {
    2170           0 :                         return ldb_oom(ldb);
    2171             :                 }
    2172             : 
    2173         142 :                 control = talloc(controls, struct ldb_control);
    2174             : 
    2175         142 :                 if (control == NULL) {
    2176           0 :                         return ldb_oom(ldb);
    2177             :                 }
    2178             : 
    2179         142 :                 control->oid= talloc_strdup(
    2180             :                         control,
    2181             :                         DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
    2182         142 :                 if (control->oid == NULL) {
    2183           0 :                         return ldb_oom(ldb);
    2184             :                 }
    2185         142 :                 control->critical    = false;
    2186         142 :                 control->data        = pav;
    2187         142 :                 *controls = control;
    2188             :         }
    2189        1773 :         return ldb_module_done(req, controls, NULL, ret);
    2190             : }
    2191             : 
    2192             : /* similar to the modify for the time being.
    2193             :  * We need to consider the special delete tree case, though - TODO */
    2194       72860 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
    2195             : {
    2196         148 :         int ret;
    2197         148 :         struct ldb_dn *parent;
    2198         148 :         struct ldb_context *ldb;
    2199         148 :         struct ldb_dn *nc_root;
    2200         148 :         const struct dsdb_schema *schema;
    2201         148 :         const struct dsdb_class *objectclass;
    2202       72860 :         struct security_descriptor *sd = NULL;
    2203       72860 :         struct dom_sid *sid = NULL;
    2204         148 :         struct ldb_result *acl_res;
    2205         148 :         static const char *acl_attrs[] = {
    2206             :                 "nTSecurityDescriptor",
    2207             :                 "objectClass",
    2208             :                 "objectSid",
    2209             :                 NULL
    2210             :         };
    2211             : 
    2212       72860 :         if (ldb_dn_is_special(req->op.del.dn)) {
    2213           1 :                 return ldb_next_request(module, req);
    2214             :         }
    2215             : 
    2216       72859 :         if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
    2217             :         {
    2218       31757 :                 return ldb_next_request(module, req);
    2219             :         }
    2220             : 
    2221       41102 :         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
    2222             : 
    2223       41102 :         ldb = ldb_module_get_ctx(module);
    2224             : 
    2225       41102 :         parent = ldb_dn_get_parent(req, req->op.del.dn);
    2226       41102 :         if (parent == NULL) {
    2227           0 :                 return ldb_oom(ldb);
    2228             :         }
    2229             : 
    2230             :         /* Make sure we aren't deleting a NC */
    2231             : 
    2232       41102 :         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
    2233       41102 :         if (ret != LDB_SUCCESS) {
    2234           0 :                 return ret;
    2235             :         }
    2236       41102 :         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
    2237           0 :                 talloc_free(nc_root);
    2238           0 :                 DEBUG(10,("acl:deleting a NC\n"));
    2239             :                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
    2240           0 :                 return ldb_module_done(req, NULL, NULL,
    2241             :                                        LDB_ERR_UNWILLING_TO_PERFORM);
    2242             :         }
    2243       41102 :         talloc_free(nc_root);
    2244             : 
    2245       41102 :         ret = dsdb_module_search_dn(module, req, &acl_res,
    2246             :                                     req->op.del.dn, acl_attrs,
    2247             :                                     DSDB_FLAG_NEXT_MODULE |
    2248             :                                     DSDB_FLAG_AS_SYSTEM |
    2249             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2250             :         /* we should be able to find the parent */
    2251       41102 :         if (ret != LDB_SUCCESS) {
    2252           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2253             :                           ldb_dn_get_linearized(req->op.rename.olddn)));
    2254           0 :                 return ret;
    2255             :         }
    2256             : 
    2257       41102 :         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
    2258       41102 :         if (ret != LDB_SUCCESS) {
    2259           0 :                 return ldb_operr(ldb);
    2260             :         }
    2261       41102 :         if (!sd) {
    2262           0 :                 return ldb_operr(ldb);
    2263             :         }
    2264             : 
    2265       41102 :         schema = dsdb_get_schema(ldb, req);
    2266       41102 :         if (!schema) {
    2267           0 :                 return ldb_operr(ldb);
    2268             :         }
    2269             : 
    2270       41102 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    2271             : 
    2272       41102 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2273       41102 :         if (!objectclass) {
    2274           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2275             :                                  "acl_modify: Error retrieving object class for GUID.");
    2276             :         }
    2277             : 
    2278       41102 :         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
    2279        2692 :                 ret = acl_check_access_on_objectclass(module, req, sd, sid,
    2280             :                                                       SEC_ADS_DELETE_TREE,
    2281             :                                                       objectclass);
    2282        2692 :                 if (ret != LDB_SUCCESS) {
    2283           0 :                         return ret;
    2284             :                 }
    2285             : 
    2286        2692 :                 return ldb_next_request(module, req);
    2287             :         }
    2288             : 
    2289             :         /* First check if we have delete object right */
    2290       38410 :         ret = acl_check_access_on_objectclass(module, req, sd, sid,
    2291             :                                               SEC_STD_DELETE,
    2292             :                                               objectclass);
    2293       38410 :         if (ret == LDB_SUCCESS) {
    2294       38105 :                 return ldb_next_request(module, req);
    2295             :         }
    2296             : 
    2297             :         /* Nope, we don't have delete object. Lets check if we have delete
    2298             :          * child on the parent */
    2299         305 :         ret = dsdb_module_check_access_on_dn(module, req, parent,
    2300             :                                              SEC_ADS_DELETE_CHILD,
    2301             :                                              &objectclass->schemaIDGUID,
    2302             :                                              req);
    2303         305 :         if (ret != LDB_SUCCESS) {
    2304          10 :                 return ret;
    2305             :         }
    2306             : 
    2307         295 :         return ldb_next_request(module, req);
    2308             : }
    2309         265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
    2310             :                                          struct ldb_module *module,
    2311             :                                          struct ldb_request *req,
    2312             :                                          struct ldb_dn *nc_root)
    2313             : {
    2314           0 :         int ret;
    2315           0 :         struct ldb_result *acl_res;
    2316         265 :         struct security_descriptor *sd = NULL;
    2317         265 :         struct dom_sid *sid = NULL;
    2318         265 :         const struct dsdb_schema *schema = NULL;
    2319         265 :         const struct dsdb_class *objectclass = NULL;
    2320         265 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    2321           0 :         static const char *acl_attrs[] = {
    2322             :                 "nTSecurityDescriptor",
    2323             :                 "objectClass",
    2324             :                 "objectSid",
    2325             :                 NULL
    2326             :         };
    2327             : 
    2328         265 :         ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
    2329             :                                     nc_root, acl_attrs,
    2330             :                                     DSDB_FLAG_NEXT_MODULE |
    2331             :                                     DSDB_FLAG_AS_SYSTEM |
    2332             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2333         265 :         if (ret != LDB_SUCCESS) {
    2334           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2335             :                           ldb_dn_get_linearized(nc_root)));
    2336           0 :                 return ret;
    2337             :         }
    2338             : 
    2339         265 :         ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
    2340         265 :         sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
    2341         265 :         schema = dsdb_get_schema(ldb, req);
    2342         265 :         if (!schema) {
    2343           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    2344             :         }
    2345         265 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2346         265 :         if (ret != LDB_SUCCESS || !sd) {
    2347           0 :                 return ldb_operr(ldb_module_get_ctx(module));
    2348             :         }
    2349         265 :         return acl_check_extended_right(mem_ctx,
    2350             :                                         module,
    2351             :                                         req,
    2352             :                                         objectclass,
    2353             :                                         sd,
    2354             :                                         acl_user_token(module),
    2355             :                                         GUID_DRS_REANIMATE_TOMBSTONE,
    2356             :                                         SEC_ADS_CONTROL_ACCESS, sid);
    2357             : }
    2358             : 
    2359        1533 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
    2360             : {
    2361           5 :         int ret;
    2362           5 :         struct ldb_dn *oldparent;
    2363           5 :         struct ldb_dn *newparent;
    2364           5 :         const struct dsdb_schema *schema;
    2365           5 :         const struct dsdb_class *objectclass;
    2366        1533 :         const struct dsdb_attribute *attr = NULL;
    2367           5 :         struct ldb_context *ldb;
    2368        1533 :         struct security_descriptor *sd = NULL;
    2369        1533 :         struct dom_sid *sid = NULL;
    2370           5 :         struct ldb_result *acl_res;
    2371           5 :         struct ldb_dn *nc_root;
    2372           5 :         struct ldb_control *is_undelete;
    2373           5 :         TALLOC_CTX *tmp_ctx;
    2374           5 :         const char *rdn_name;
    2375           5 :         static const char *acl_attrs[] = {
    2376             :                 "nTSecurityDescriptor",
    2377             :                 "objectClass",
    2378             :                 "objectSid",
    2379             :                 NULL
    2380             :         };
    2381             : 
    2382        1533 :         if (ldb_dn_is_special(req->op.rename.olddn)) {
    2383           0 :                 return ldb_next_request(module, req);
    2384             :         }
    2385             : 
    2386        1533 :         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
    2387        1533 :         if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
    2388             :         {
    2389         895 :                 return ldb_next_request(module, req);
    2390             :         }
    2391             : 
    2392         638 :         ldb = ldb_module_get_ctx(module);
    2393             : 
    2394         638 :         tmp_ctx = talloc_new(req);
    2395         638 :         if (tmp_ctx == NULL) {
    2396           0 :                 return ldb_oom(ldb);
    2397             :         }
    2398             : 
    2399         638 :         oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
    2400         638 :         if (oldparent == NULL) {
    2401           0 :                 return ldb_oom(ldb);
    2402             :         }
    2403         638 :         newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
    2404         638 :         if (newparent == NULL) {
    2405           0 :                 return ldb_oom(ldb);
    2406             :         }
    2407             : 
    2408             :         /* Make sure we aren't renaming/moving a NC */
    2409             : 
    2410         638 :         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
    2411         638 :         if (ret != LDB_SUCCESS) {
    2412           0 :                 return ret;
    2413             :         }
    2414         638 :         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
    2415           0 :                 talloc_free(nc_root);
    2416           0 :                 DEBUG(10,("acl:renaming/moving a NC\n"));
    2417             :                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
    2418           0 :                 return ldb_module_done(req, NULL, NULL,
    2419             :                                        LDB_ERR_UNWILLING_TO_PERFORM);
    2420             :         }
    2421             : 
    2422             :         /* special check for undelete operation */
    2423         638 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    2424         638 :         if (is_undelete != NULL) {
    2425         265 :                 is_undelete->critical = 0;
    2426         265 :                 ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
    2427         265 :                 if (ret != LDB_SUCCESS) {
    2428           9 :                         talloc_free(tmp_ctx);
    2429           9 :                         return ret;
    2430             :                 }
    2431             :         }
    2432         629 :         talloc_free(nc_root);
    2433             : 
    2434             :         /* Look for the parent */
    2435             : 
    2436         629 :         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
    2437             :                                     req->op.rename.olddn, acl_attrs,
    2438             :                                     DSDB_FLAG_NEXT_MODULE |
    2439             :                                     DSDB_FLAG_AS_SYSTEM |
    2440             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2441             :         /* we should be able to find the parent */
    2442         629 :         if (ret != LDB_SUCCESS) {
    2443           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2444             :                           ldb_dn_get_linearized(req->op.rename.olddn)));
    2445           0 :                 talloc_free(tmp_ctx);
    2446           0 :                 return ret;
    2447             :         }
    2448             : 
    2449         629 :         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
    2450         629 :         if (ret != LDB_SUCCESS) {
    2451           0 :                 talloc_free(tmp_ctx);
    2452           0 :                 return ldb_operr(ldb);
    2453             :         }
    2454         629 :         if (!sd) {
    2455           0 :                 talloc_free(tmp_ctx);
    2456           0 :                 return ldb_operr(ldb);
    2457             :         }
    2458             : 
    2459         629 :         schema = dsdb_get_schema(ldb, acl_res);
    2460         629 :         if (!schema) {
    2461           0 :                 talloc_free(tmp_ctx);
    2462           0 :                 return ldb_operr(ldb);
    2463             :         }
    2464             : 
    2465         629 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    2466             : 
    2467         629 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2468         629 :         if (!objectclass) {
    2469           0 :                 talloc_free(tmp_ctx);
    2470           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2471             :                                  "acl_modify: Error retrieving object class for GUID.");
    2472             :         }
    2473             : 
    2474         629 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
    2475         629 :         if (attr == NULL) {
    2476           0 :                 talloc_free(tmp_ctx);
    2477           0 :                 return ldb_operr(ldb);
    2478             :         }
    2479             : 
    2480         629 :         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
    2481             :                                             SEC_ADS_WRITE_PROP,
    2482             :                                             attr, objectclass);
    2483         629 :         if (ret != LDB_SUCCESS) {
    2484          19 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2485             :                                        "Object %s has no wp on %s\n",
    2486             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    2487          19 :                                        attr->lDAPDisplayName);
    2488          19 :                 dsdb_acl_debug(sd,
    2489             :                           acl_user_token(module),
    2490             :                           req->op.rename.olddn,
    2491             :                           true,
    2492             :                           10);
    2493          19 :                 talloc_free(tmp_ctx);
    2494          19 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2495             :         }
    2496             : 
    2497         610 :         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
    2498         610 :         if (rdn_name == NULL) {
    2499           0 :                 talloc_free(tmp_ctx);
    2500           0 :                 return ldb_operr(ldb);
    2501             :         }
    2502             : 
    2503         610 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
    2504         610 :         if (attr == NULL) {
    2505           0 :                 talloc_free(tmp_ctx);
    2506           0 :                 return ldb_operr(ldb);
    2507             :         }
    2508             : 
    2509         610 :         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
    2510             :                                             SEC_ADS_WRITE_PROP,
    2511             :                                             attr, objectclass);
    2512         610 :         if (ret != LDB_SUCCESS) {
    2513           9 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2514             :                                        "Object %s has no wp on %s\n",
    2515             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    2516           9 :                                        attr->lDAPDisplayName);
    2517           9 :                 dsdb_acl_debug(sd,
    2518             :                           acl_user_token(module),
    2519             :                           req->op.rename.olddn,
    2520             :                           true,
    2521             :                           10);
    2522           9 :                 talloc_free(tmp_ctx);
    2523           9 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2524             :         }
    2525             : 
    2526         601 :         if (ldb_dn_compare(oldparent, newparent) == 0) {
    2527             :                 /* regular rename, not move, nothing more to do */
    2528         232 :                 talloc_free(tmp_ctx);
    2529         232 :                 return ldb_next_request(module, req);
    2530             :         }
    2531             : 
    2532             :         /* new parent should have create child */
    2533         369 :         ret = dsdb_module_check_access_on_dn(module, req, newparent,
    2534             :                                              SEC_ADS_CREATE_CHILD,
    2535             :                                              &objectclass->schemaIDGUID, req);
    2536         369 :         if (ret != LDB_SUCCESS) {
    2537           9 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2538             :                                        "acl:access_denied renaming %s",
    2539             :                                        ldb_dn_get_linearized(req->op.rename.olddn));
    2540           9 :                 talloc_free(tmp_ctx);
    2541           9 :                 return ret;
    2542             :         }
    2543             : 
    2544             :         /* do we have delete object on the object? */
    2545             :         /* this access is not necessary for undelete ops */
    2546         360 :         if (is_undelete == NULL) {
    2547         126 :                 ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
    2548             :                                                       SEC_STD_DELETE,
    2549             :                                                       objectclass);
    2550         126 :                 if (ret == LDB_SUCCESS) {
    2551          99 :                         talloc_free(tmp_ctx);
    2552          99 :                         return ldb_next_request(module, req);
    2553             :                 }
    2554             :                 /* what about delete child on the current parent */
    2555          27 :                 ret = dsdb_module_check_access_on_dn(module, req, oldparent,
    2556             :                                                      SEC_ADS_DELETE_CHILD,
    2557             :                                                      &objectclass->schemaIDGUID,
    2558             :                                                      req);
    2559          27 :                 if (ret != LDB_SUCCESS) {
    2560           9 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2561             :                                                "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
    2562           9 :                         talloc_free(tmp_ctx);
    2563           9 :                         return ldb_module_done(req, NULL, NULL, ret);
    2564             :                 }
    2565             :         }
    2566         252 :         talloc_free(tmp_ctx);
    2567             : 
    2568         252 :         return ldb_next_request(module, req);
    2569             : }
    2570             : 
    2571      832924 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
    2572             :                                                 struct acl_private *data)
    2573             : {
    2574       17584 :         struct dsdb_attribute *a;
    2575      832924 :         uint32_t n = 0;
    2576             : 
    2577      832924 :         if (data->acl_search) {
    2578             :                 /*
    2579             :                  * If acl:search is activated, the acl_read module
    2580             :                  * protects confidential attributes.
    2581             :                  */
    2582      815340 :                 return LDB_SUCCESS;
    2583             :         }
    2584             : 
    2585           0 :         if ((ac->schema == data->cached_schema_ptr) &&
    2586           0 :             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
    2587             :         {
    2588           0 :                 return LDB_SUCCESS;
    2589             :         }
    2590             : 
    2591           0 :         data->cached_schema_ptr = NULL;
    2592           0 :         data->cached_schema_loaded_usn = 0;
    2593           0 :         data->cached_schema_metadata_usn = 0;
    2594           0 :         TALLOC_FREE(data->confidential_attrs);
    2595             : 
    2596           0 :         if (ac->schema == NULL) {
    2597           0 :                 return LDB_SUCCESS;
    2598             :         }
    2599             : 
    2600           0 :         for (a = ac->schema->attributes; a; a = a->next) {
    2601           0 :                 const char **attrs = data->confidential_attrs;
    2602             : 
    2603           0 :                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
    2604           0 :                         continue;
    2605             :                 }
    2606             : 
    2607           0 :                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
    2608           0 :                 if (attrs == NULL) {
    2609           0 :                         TALLOC_FREE(data->confidential_attrs);
    2610           0 :                         return ldb_module_oom(ac->module);
    2611             :                 }
    2612             : 
    2613           0 :                 attrs[n] = a->lDAPDisplayName;
    2614           0 :                 attrs[n+1] = NULL;
    2615           0 :                 n++;
    2616             : 
    2617           0 :                 data->confidential_attrs = attrs;
    2618             :         }
    2619             : 
    2620           0 :         data->cached_schema_ptr = ac->schema;
    2621           0 :         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
    2622             : 
    2623           0 :         return LDB_SUCCESS;
    2624             : }
    2625             : 
    2626    46605063 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
    2627             : {
    2628     1502276 :         struct acl_context *ac;
    2629     1502276 :         struct acl_private *data;
    2630     1502276 :         struct ldb_result *acl_res;
    2631     1502276 :         static const char *acl_attrs[] = {
    2632             :                 "objectClass",
    2633             :                 "nTSecurityDescriptor",
    2634             :                 "objectSid",
    2635             :                 NULL
    2636             :         };
    2637     1502276 :         int ret;
    2638     1502276 :         unsigned int i;
    2639             : 
    2640    46605063 :         ac = talloc_get_type(req->context, struct acl_context);
    2641    46605063 :         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
    2642    46605063 :         if (!ares) {
    2643           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    2644             :                                        LDB_ERR_OPERATIONS_ERROR);
    2645             :         }
    2646    46605063 :         if (ares->error != LDB_SUCCESS) {
    2647     1668749 :                 return ldb_module_done(ac->req, ares->controls,
    2648             :                                        ares->response, ares->error);
    2649             :         }
    2650             : 
    2651    44936314 :         switch (ares->type) {
    2652    35462053 :         case LDB_REPLY_ENTRY:
    2653    35462053 :                 if (ac->constructed_attrs) {
    2654         346 :                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
    2655             :                                                     acl_attrs,
    2656             :                                                     DSDB_FLAG_NEXT_MODULE |
    2657             :                                                     DSDB_FLAG_AS_SYSTEM |
    2658             :                                                     DSDB_SEARCH_SHOW_RECYCLED,
    2659             :                                                     req);
    2660         346 :                         if (ret != LDB_SUCCESS) {
    2661           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2662             :                         }
    2663             :                 }
    2664             : 
    2665    35462053 :                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
    2666          22 :                         ret = acl_allowedAttributes(ac->module, ac->schema,
    2667          22 :                                                     acl_res->msgs[0],
    2668             :                                                     ares->message, ac);
    2669          22 :                         if (ret != LDB_SUCCESS) {
    2670           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2671             :                         }
    2672             :                 }
    2673             : 
    2674    35462053 :                 if (ac->allowedChildClasses) {
    2675           0 :                         ret = acl_childClasses(ac->module, ac->schema,
    2676           0 :                                                acl_res->msgs[0],
    2677             :                                                ares->message,
    2678             :                                                "allowedChildClasses");
    2679           0 :                         if (ret != LDB_SUCCESS) {
    2680           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2681             :                         }
    2682             :                 }
    2683             : 
    2684    35462053 :                 if (ac->allowedChildClassesEffective) {
    2685          18 :                         ret = acl_childClassesEffective(ac->module, ac->schema,
    2686          18 :                                                         acl_res->msgs[0],
    2687             :                                                         ares->message, ac);
    2688          18 :                         if (ret != LDB_SUCCESS) {
    2689           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2690             :                         }
    2691             :                 }
    2692             : 
    2693    35462053 :                 if (ac->sDRightsEffective) {
    2694         306 :                         ret = acl_sDRightsEffective(ac->module,
    2695         306 :                                                     acl_res->msgs[0],
    2696             :                                                     ares->message, ac);
    2697         306 :                         if (ret != LDB_SUCCESS) {
    2698           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2699             :                         }
    2700             :                 }
    2701             : 
    2702    35462053 :                 if (data == NULL) {
    2703           0 :                         return ldb_module_send_entry(ac->req, ares->message,
    2704             :                                                      ares->controls);
    2705             :                 }
    2706             : 
    2707    35462053 :                 if (ac->am_system) {
    2708           0 :                         return ldb_module_send_entry(ac->req, ares->message,
    2709             :                                                      ares->controls);
    2710             :                 }
    2711             : 
    2712    35462053 :                 if (ac->am_administrator) {
    2713    13847183 :                         return ldb_module_send_entry(ac->req, ares->message,
    2714             :                                                      ares->controls);
    2715             :                 }
    2716             : 
    2717    21614870 :                 if (data->confidential_attrs != NULL) {
    2718           0 :                         for (i = 0; data->confidential_attrs[i]; i++) {
    2719           0 :                                 ldb_msg_remove_attr(ares->message,
    2720           0 :                                                     data->confidential_attrs[i]);
    2721             :                         }
    2722             :                 }
    2723             : 
    2724    21614870 :                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
    2725             : 
    2726      801426 :         case LDB_REPLY_REFERRAL:
    2727      801426 :                 return ldb_module_send_referral(ac->req, ares->referral);
    2728             : 
    2729     8672835 :         case LDB_REPLY_DONE:
    2730     8672835 :                 return ldb_module_done(ac->req, ares->controls,
    2731             :                                        ares->response, LDB_SUCCESS);
    2732             : 
    2733             :         }
    2734           0 :         return LDB_SUCCESS;
    2735             : }
    2736             : 
    2737    33076489 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
    2738             : {
    2739     1783375 :         struct ldb_context *ldb;
    2740     1783375 :         struct acl_context *ac;
    2741    33076489 :         struct ldb_parse_tree *down_tree = req->op.search.tree;
    2742     1783375 :         struct ldb_request *down_req;
    2743     1783375 :         struct acl_private *data;
    2744     1783375 :         int ret;
    2745     1783375 :         unsigned int i;
    2746    33076489 :         bool modify_search = true;
    2747             : 
    2748    33076489 :         if (ldb_dn_is_special(req->op.search.base)) {
    2749     1130626 :                 return ldb_next_request(module, req);
    2750             :         }
    2751             : 
    2752    31945863 :         ldb = ldb_module_get_ctx(module);
    2753             : 
    2754    31945863 :         ac = talloc_zero(req, struct acl_context);
    2755    31945863 :         if (ac == NULL) {
    2756           0 :                 return ldb_oom(ldb);
    2757             :         }
    2758    31945863 :         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
    2759             : 
    2760    31945863 :         ac->module = module;
    2761    31945863 :         ac->req = req;
    2762    31945863 :         ac->am_system = dsdb_module_am_system(module);
    2763    31945863 :         ac->am_administrator = dsdb_module_am_administrator(module);
    2764    31945863 :         ac->constructed_attrs = false;
    2765    31945863 :         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
    2766    31945863 :         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
    2767    31945863 :         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
    2768    31945863 :         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
    2769    31945863 :         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
    2770    31945863 :         ac->schema = dsdb_get_schema(ldb, ac);
    2771             : 
    2772    31945863 :         ac->constructed_attrs |= ac->allowedAttributes;
    2773    31945863 :         ac->constructed_attrs |= ac->allowedChildClasses;
    2774    31945863 :         ac->constructed_attrs |= ac->allowedChildClassesEffective;
    2775    31945863 :         ac->constructed_attrs |= ac->allowedAttributesEffective;
    2776    31945863 :         ac->constructed_attrs |= ac->sDRightsEffective;
    2777             : 
    2778    31945863 :         if (data == NULL) {
    2779           0 :                 modify_search = false;
    2780             :         }
    2781    31945863 :         if (ac->am_system) {
    2782    21603711 :                 modify_search = false;
    2783             :         }
    2784             : 
    2785    31945863 :         if (!ac->constructed_attrs && !modify_search) {
    2786    21603711 :                 talloc_free(ac);
    2787    21603711 :                 return ldb_next_request(module, req);
    2788             :         }
    2789             : 
    2790    10342152 :         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
    2791    10342152 :         if (data == NULL) {
    2792           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2793             :                                  "acl_private data is missing");
    2794             :         }
    2795             : 
    2796    10342152 :         if (!ac->am_system && !ac->am_administrator) {
    2797      832924 :                 ret = acl_search_update_confidential_attrs(ac, data);
    2798      832924 :                 if (ret != LDB_SUCCESS) {
    2799           0 :                         return ret;
    2800             :                 }
    2801             : 
    2802      832924 :                 if (data->confidential_attrs != NULL) {
    2803           0 :                         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
    2804           0 :                         if (down_tree == NULL) {
    2805           0 :                                 return ldb_oom(ldb);
    2806             :                         }
    2807             : 
    2808           0 :                         for (i = 0; data->confidential_attrs[i]; i++) {
    2809           0 :                                 ldb_parse_tree_attr_replace(down_tree,
    2810           0 :                                                             data->confidential_attrs[i],
    2811             :                                                             "kludgeACLredactedattribute");
    2812             :                         }
    2813             :                 }
    2814             :         }
    2815             : 
    2816    10342152 :         ret = ldb_build_search_req_ex(&down_req,
    2817             :                                       ldb, ac,
    2818             :                                       req->op.search.base,
    2819             :                                       req->op.search.scope,
    2820             :                                       down_tree,
    2821             :                                       req->op.search.attrs,
    2822             :                                       req->controls,
    2823             :                                       ac, acl_search_callback,
    2824             :                                       req);
    2825    10342152 :         LDB_REQ_SET_LOCATION(down_req);
    2826    10342152 :         if (ret != LDB_SUCCESS) {
    2827           0 :                 return ret;
    2828             :         }
    2829             :         /* perform the search */
    2830    10342152 :         return ldb_next_request(module, down_req);
    2831             : }
    2832             : 
    2833     1285950 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
    2834             : {
    2835     1285950 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    2836             : 
    2837             :         /* allow everybody to read the sequence number */
    2838     1285950 :         if (strcmp(req->op.extended.oid,
    2839             :                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
    2840     1280189 :                 return ldb_next_request(module, req);
    2841             :         }
    2842             : 
    2843        5761 :         if (dsdb_have_system_access(module,
    2844             :                                     req,
    2845         518 :                                     SYSTEM_CONTROL_KEEP_CRITICAL) ||
    2846         518 :             dsdb_module_am_administrator(module))
    2847             :         {
    2848        5761 :                 return ldb_next_request(module, req);
    2849             :         } else {
    2850           0 :                 ldb_asprintf_errstring(ldb,
    2851             :                                        "acl_extended: "
    2852             :                                        "attempted database modify not permitted. "
    2853             :                                        "User %s is not SYSTEM or an administrator",
    2854             :                                        acl_user_name(req, module));
    2855           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2856             :         }
    2857             : }
    2858             : 
    2859             : static const struct ldb_module_ops ldb_acl_module_ops = {
    2860             :         .name              = "acl",
    2861             :         .search            = acl_search,
    2862             :         .add               = acl_add,
    2863             :         .modify            = acl_modify,
    2864             :         .del               = acl_delete,
    2865             :         .rename            = acl_rename,
    2866             :         .extended          = acl_extended,
    2867             :         .init_context      = acl_module_init
    2868             : };
    2869             : 
    2870        6286 : int ldb_acl_module_init(const char *version)
    2871             : {
    2872        6286 :         LDB_MODULE_CHECK_VERSION(version);
    2873        6286 :         return ldb_register_module(&ldb_acl_module_ops);
    2874             : }

Generated by: LCOV version 1.14