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 70ed9daf Lines: 1000 1318 75.9 %
Date: 2024-01-11 09:59:51 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      180740 : static int acl_module_init(struct ldb_module *module)
      73             : {
      74        6008 :         struct ldb_context *ldb;
      75        6008 :         struct acl_private *data;
      76        6008 :         int ret;
      77             : 
      78      180740 :         ldb = ldb_module_get_ctx(module);
      79             : 
      80      180740 :         data = talloc_zero(module, struct acl_private);
      81      180740 :         if (data == NULL) {
      82           0 :                 return ldb_oom(ldb);
      83             :         }
      84             : 
      85      180740 :         data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
      86             :                                         NULL, "acl", "search", true);
      87      180740 :         ldb_module_set_private(module, data);
      88             : 
      89      180740 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
      90      180740 :         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      180740 :         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         952 : 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         952 :         TALLOC_CTX *tmp_ctx = NULL;
     833         952 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     834         952 :         const struct dsdb_schema *schema = NULL;
     835         952 :         const struct ldb_message_element *allowed_suffixes = NULL;
     836         952 :         struct ldb_result *nc_res = NULL;
     837         952 :         struct ldb_dn *nc_root = NULL;
     838         952 :         const char *nc_dns_name = NULL;
     839         952 :         const char *dnsHostName_str = NULL;
     840          75 :         size_t dns_host_name_len;
     841          75 :         size_t account_name_len;
     842         952 :         const struct ldb_message *msg = NULL;
     843         952 :         const struct ldb_message *search_res = NULL;
     844         952 :         const struct ldb_val *samAccountName = NULL;
     845         952 :         const struct ldb_val *dnsHostName = NULL;
     846         952 :         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         952 :         tmp_ctx = talloc_new(mem_ctx);
     855         952 :         if (tmp_ctx == NULL) {
     856           0 :                 return ldb_oom(ldb);
     857             :         }
     858             : 
     859         952 :         if (req->operation == LDB_MODIFY) {
     860         952 :                 msg = req->op.mod.message;
     861           0 :         } else if (req->operation == LDB_ADD) {
     862           0 :                 msg = req->op.add.message;
     863             :         }
     864             : 
     865         952 :         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         916 :                 ret = acl_check_access_on_attribute(module,
     876             :                                                     tmp_ctx,
     877             :                                                     sd,
     878             :                                                     sid,
     879             :                                                     SEC_ADS_WRITE_PROP,
     880             :                                                     attr, objectclass);
     881         916 :                 if (ret == LDB_SUCCESS) {
     882         712 :                         talloc_free(tmp_ctx);
     883         712 :                         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        8015 : 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        8015 :         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        8015 :         const struct ldb_message *msg = NULL;
    1124             : 
    1125        8015 :         if (req->operation == LDB_MODIFY) {
    1126        8015 :                 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        8015 :         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        7955 :                 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      543307 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
    1182             : {
    1183       83657 :         int ret;
    1184       83657 :         struct ldb_dn *parent;
    1185       83657 :         struct ldb_context *ldb;
    1186       83657 :         const struct dsdb_schema *schema;
    1187       83657 :         const struct dsdb_class *objectclass;
    1188      543307 :         const struct dsdb_class *computer_objectclass = NULL;
    1189      543307 :         const struct ldb_message_element *oc_el = NULL;
    1190       83657 :         struct ldb_message_element sorted_oc_el;
    1191       83657 :         struct ldb_control *as_system;
    1192      543307 :         struct ldb_control *sd_ctrl = NULL;
    1193       83657 :         struct ldb_message_element *el;
    1194      543307 :         unsigned int instanceType = 0;
    1195      543307 :         struct dsdb_control_calculated_default_sd *control_sd = NULL;
    1196      543307 :         const struct dsdb_attribute *attr = NULL;
    1197      543307 :         const char **must_contain = NULL;
    1198      543307 :         const struct ldb_message *msg = req->op.add.message;
    1199      543307 :         const struct dom_sid *domain_sid = NULL;
    1200      543307 :         int i = 0;
    1201       83657 :         bool attribute_authorization;
    1202       83657 :         bool is_subclass;
    1203             : 
    1204      543307 :         if (ldb_dn_is_special(msg->dn)) {
    1205         538 :                 return ldb_next_request(module, req);
    1206             :         }
    1207             : 
    1208      542769 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    1209      542769 :         if (as_system != NULL) {
    1210         117 :                 as_system->critical = 0;
    1211             :         }
    1212             : 
    1213      542769 :         if (dsdb_module_am_system(module) || as_system) {
    1214        4527 :                 return ldb_next_request(module, req);
    1215             :         }
    1216             : 
    1217      538242 :         ldb = ldb_module_get_ctx(module);
    1218      538242 :         domain_sid = samdb_domain_sid(ldb);
    1219             : 
    1220      538242 :         parent = ldb_dn_get_parent(req, msg->dn);
    1221      538242 :         if (parent == NULL) {
    1222           0 :                 return ldb_oom(ldb);
    1223             :         }
    1224             : 
    1225      538242 :         schema = dsdb_get_schema(ldb, req);
    1226      538242 :         if (!schema) {
    1227           0 :                 return ldb_operr(ldb);
    1228             :         }
    1229             : 
    1230             :         /* Find the objectclass of the new account. */
    1231             : 
    1232      538242 :         oc_el = ldb_msg_find_element(msg, "objectclass");
    1233      538242 :         if (oc_el == NULL) {
    1234           0 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1235             :                                        "acl: unable to find or validate structural objectClass on %s\n",
    1236           0 :                                        ldb_dn_get_linearized(msg->dn));
    1237           0 :                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
    1238             :         }
    1239             : 
    1240      538242 :         schema = dsdb_get_schema(ldb, req);
    1241      538242 :         if (schema == NULL) {
    1242           0 :                 return ldb_operr(ldb);
    1243             :         }
    1244             : 
    1245      538242 :         ret = dsdb_sort_objectClass_attr(ldb, schema, oc_el, req, &sorted_oc_el);
    1246      538242 :         if (ret != LDB_SUCCESS) {
    1247           0 :                 return ret;
    1248             :         }
    1249             : 
    1250      538242 :         objectclass = dsdb_get_last_structural_class(schema, &sorted_oc_el);
    1251      538242 :         if (objectclass == NULL) {
    1252           0 :                 return ldb_operr(ldb);
    1253             :         }
    1254             : 
    1255      538242 :         el = ldb_msg_find_element(msg, "instanceType");
    1256      538242 :         if ((el != NULL) && (el->num_values != 1)) {
    1257           1 :                 ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
    1258           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1259             :         }
    1260             : 
    1261      538241 :         instanceType = ldb_msg_find_attr_as_uint(msg,
    1262             :                                                  "instanceType", 0);
    1263      538241 :         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
    1264         108 :                 static const char *no_attrs[] = { NULL };
    1265         108 :                 struct ldb_result *partition_res;
    1266         108 :                 struct ldb_dn *partitions_dn;
    1267             : 
    1268         609 :                 partitions_dn = samdb_partitions_dn(ldb, req);
    1269         609 :                 if (!partitions_dn) {
    1270           0 :                         ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
    1271           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1272             :                 }
    1273             : 
    1274         609 :                 ret = dsdb_module_search(module, req, &partition_res,
    1275             :                                          partitions_dn, LDB_SCOPE_ONELEVEL,
    1276             :                                          no_attrs,
    1277             :                                          DSDB_FLAG_NEXT_MODULE |
    1278             :                                          DSDB_FLAG_AS_SYSTEM |
    1279             :                                          DSDB_SEARCH_ONE_ONLY |
    1280             :                                          DSDB_SEARCH_SHOW_RECYCLED,
    1281             :                                          req,
    1282             :                                          "(&(nCName=%s)(objectClass=crossRef))",
    1283         609 :                                          ldb_dn_get_linearized(msg->dn));
    1284             : 
    1285         609 :                 if (ret == LDB_SUCCESS) {
    1286             :                         /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
    1287           0 :                         ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
    1288             :                                                              SEC_ADS_WRITE_PROP,
    1289             :                                                              &objectclass->schemaIDGUID, req);
    1290           0 :                         if (ret != LDB_SUCCESS) {
    1291           0 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1292             :                                                        "acl: ACL check failed on crossRef object %s: %s\n",
    1293           0 :                                                        ldb_dn_get_linearized(partition_res->msgs[0]->dn),
    1294             :                                                        ldb_errstring(ldb));
    1295           0 :                                 return ret;
    1296             :                         }
    1297             : 
    1298             :                         /*
    1299             :                          * TODO: Remaining checks, like if we are
    1300             :                          * the naming master etc need to be handled
    1301             :                          * in the instanceType module
    1302             :                          */
    1303             :                         /* Note - do we need per-attribute checks? */
    1304           0 :                         return ldb_next_request(module, req);
    1305             :                 }
    1306             : 
    1307             :                 /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
    1308         609 :                 ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
    1309             :                                                      SEC_ADS_CREATE_CHILD,
    1310             :                                                      &objectclass->schemaIDGUID, req);
    1311         990 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
    1312         381 :                     ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
    1313             :                 {
    1314             :                         /* Allow provision bootstrap */
    1315         315 :                         ret = LDB_SUCCESS;
    1316             :                 }
    1317         543 :                 if (ret != LDB_SUCCESS) {
    1318           0 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1319             :                                                "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
    1320             :                                                ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
    1321           0 :                         return ret;
    1322             :                 }
    1323             : 
    1324             :                 /*
    1325             :                  * TODO: Remaining checks, like if we are the naming
    1326             :                  * master and adding the crossRef object need to be
    1327             :                  * handled in the instanceType module
    1328             :                  */
    1329             :         } else {
    1330      537632 :                 ret = dsdb_module_check_access_on_dn(module, req, parent,
    1331             :                                                      SEC_ADS_CREATE_CHILD,
    1332             :                                                      &objectclass->schemaIDGUID, req);
    1333      537632 :                 if (ret != LDB_SUCCESS) {
    1334          24 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1335             :                                                "acl: unable to get access to %s\n",
    1336          24 :                                                ldb_dn_get_linearized(msg->dn));
    1337          24 :                         return ret;
    1338             :                 }
    1339             :         }
    1340             : 
    1341      538217 :         attribute_authorization = dsdb_attribute_authz_on_ldap_add(module,
    1342             :                                                                    req,
    1343             :                                                                    req);
    1344      538217 :         if (!attribute_authorization) {
    1345             :                 /* Skip the remaining checks */
    1346      522485 :                 goto success;
    1347             :         }
    1348             : 
    1349             :         /* Check if we have computer objectclass. */
    1350       15732 :         computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
    1351       15732 :         if (computer_objectclass == NULL) {
    1352           0 :                 return ldb_operr(ldb);
    1353             :         }
    1354             : 
    1355       15732 :         is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
    1356       15732 :         if (!is_subclass) {
    1357             :                 /*
    1358             :                  * This object is not a computer (or derived from computer), so
    1359             :                  * skip the remaining checks.
    1360             :                  */
    1361       14958 :                 goto success;
    1362             :         }
    1363             : 
    1364             :         /*
    1365             :          * we have established we have CC right, now check per-attribute
    1366             :          * access based on the default SD
    1367             :          */
    1368             : 
    1369         774 :         sd_ctrl = ldb_request_get_control(req,
    1370             :                                           DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID);
    1371         774 :         if (sd_ctrl == NULL) {
    1372           0 :                 goto success;
    1373             :         }
    1374             : 
    1375             :         {
    1376         774 :                 TALLOC_CTX *tmp_ctx = talloc_new(req);
    1377         774 :                 control_sd = (struct dsdb_control_calculated_default_sd *) sd_ctrl->data;
    1378         774 :                 DBG_DEBUG("Received cookie descriptor %s\n\n",
    1379             :                           sddl_encode(tmp_ctx, control_sd->default_sd, domain_sid));
    1380         774 :                 TALLOC_FREE(tmp_ctx);
    1381             :                 /* Mark the "change" control as uncritical (done) */
    1382         774 :                 sd_ctrl->critical = false;
    1383             :         }
    1384             : 
    1385             :         /*
    1386             :          * At this point we do not yet have the object's SID, so we
    1387             :          * leave it empty. It is irrelevant, as it is used to expand
    1388             :          * Principal-Self, and rights granted to PS will have no effect
    1389             :          * in this case
    1390             :          */
    1391             :         /* check if we have WD, no need to perform other attribute checks if we do */
    1392         774 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, "nTSecurityDescriptor");
    1393         774 :         if (attr == NULL) {
    1394           0 :                 return ldb_operr(ldb);
    1395             :         }
    1396             : 
    1397         774 :         if (control_sd->specified_sacl) {
    1398          18 :                 const struct security_token *token = acl_user_token(module);
    1399          18 :                 bool has_priv = security_token_has_privilege(token, SEC_PRIV_SECURITY);
    1400          18 :                 if (!has_priv) {
    1401          18 :                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1402             :                 }
    1403             :         }
    1404             : 
    1405         756 :         ret = acl_check_access_on_attribute(module,
    1406             :                                             req,
    1407             :                                             control_sd->default_sd,
    1408             :                                             NULL,
    1409             :                                             SEC_STD_WRITE_DAC,
    1410             :                                             attr,
    1411             :                                             objectclass);
    1412         756 :         if (ret == LDB_SUCCESS) {
    1413         486 :                 goto success;
    1414             :         }
    1415             : 
    1416         270 :         if (control_sd->specified_sd) {
    1417         126 :                 bool block_owner_rights = dsdb_block_owner_implicit_rights(module,
    1418             :                                                                            req,
    1419             :                                                                            req);
    1420         126 :                 if (block_owner_rights) {
    1421         108 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1422             :                                                "Object %s has no SD modification rights",
    1423         108 :                                                ldb_dn_get_linearized(msg->dn));
    1424         108 :                         dsdb_acl_debug(control_sd->default_sd,
    1425             :                                        acl_user_token(module),
    1426         108 :                                        msg->dn,
    1427             :                                        true,
    1428             :                                        10);
    1429         108 :                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1430         108 :                         return ret;
    1431             :                 }
    1432             :         }
    1433             : 
    1434         162 :         must_contain = dsdb_full_attribute_list(req, schema, &sorted_oc_el,
    1435             :                                                 DSDB_SCHEMA_ALL_MUST);
    1436         702 :         for (i=0; i < msg->num_elements; i++) {
    1437         603 :                 el = &msg->elements[i];
    1438             : 
    1439         603 :                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
    1440         603 :                 if (attr == NULL && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
    1441           0 :                         ldb_asprintf_errstring(ldb, "acl_add: attribute '%s' "
    1442             :                                                "on entry '%s' was not found in the schema!",
    1443             :                                                el->name,
    1444           0 :                                        ldb_dn_get_linearized(msg->dn));
    1445           0 :                         ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
    1446           0 :                         return ret;
    1447             :                 }
    1448             : 
    1449         603 :                 if (attr != NULL) {
    1450         594 :                         bool found = str_list_check(must_contain, attr->lDAPDisplayName);
    1451             :                         /* do not check the mandatory attributes */
    1452         594 :                         if (found) {
    1453         450 :                                 continue;
    1454             :                         }
    1455             :                 }
    1456             : 
    1457         153 :                 if (ldb_attr_cmp("dBCSPwd", el->name) == 0 ||
    1458         153 :                            ldb_attr_cmp("unicodePwd", el->name) == 0 ||
    1459         144 :                            ldb_attr_cmp("userPassword", el->name) == 0 ||
    1460         126 :                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
    1461          36 :                         continue;
    1462         117 :                 } else if (ldb_attr_cmp("member", el->name) == 0) {
    1463           0 :                         ret = acl_check_self_membership(req,
    1464             :                                                         module,
    1465             :                                                         req,
    1466             :                                                         control_sd->default_sd,
    1467             :                                                         NULL,
    1468             :                                                         attr,
    1469             :                                                         objectclass);
    1470           0 :                         if (ret != LDB_SUCCESS) {
    1471           0 :                                 return ret;
    1472             :                         }
    1473         117 :                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
    1474          36 :                         ret = acl_check_spn(req,
    1475             :                                             module,
    1476             :                                             req,
    1477             :                                             el,
    1478             :                                             control_sd->default_sd,
    1479             :                                             NULL,
    1480             :                                             attr,
    1481             :                                             objectclass,
    1482             :                                             NULL);
    1483          36 :                         if (ret != LDB_SUCCESS) {
    1484          18 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1485             :                                                        "Object %s cannot be created with spn",
    1486          18 :                                                        ldb_dn_get_linearized(msg->dn));
    1487          18 :                                 dsdb_acl_debug(control_sd->default_sd,
    1488             :                                                acl_user_token(module),
    1489          18 :                                                msg->dn,
    1490             :                                                true,
    1491             :                                                10);
    1492          18 :                                 return ret;
    1493             :                         }
    1494          81 :                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
    1495           0 :                         ret = acl_check_dns_host_name(req,
    1496             :                                                       module,
    1497             :                                                       req,
    1498             :                                                       el,
    1499             :                                                       control_sd->default_sd,
    1500             :                                                       NULL,
    1501             :                                                       attr,
    1502             :                                                       objectclass,
    1503             :                                                       NULL);
    1504           0 :                         if (ret != LDB_SUCCESS) {
    1505           0 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1506             :                                                        "Object %s cannot be created with dnsHostName",
    1507           0 :                                                        ldb_dn_get_linearized(msg->dn));
    1508           0 :                                 dsdb_acl_debug(control_sd->default_sd,
    1509             :                                                acl_user_token(module),
    1510           0 :                                                msg->dn,
    1511             :                                                true,
    1512             :                                                10);
    1513           0 :                                 return ret;
    1514             :                         }
    1515             :                 } else {
    1516          81 :                         ret = acl_check_access_on_attribute(module,
    1517             :                                                             req,
    1518             :                                                             control_sd->default_sd,
    1519             :                                                             NULL,
    1520             :                                                             SEC_ADS_WRITE_PROP,
    1521             :                                                             attr,
    1522             :                                                             objectclass);
    1523          81 :                         if (ret != LDB_SUCCESS) {
    1524          45 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    1525             :                                                        "Object %s has no write property access",
    1526          45 :                                                        ldb_dn_get_linearized(msg->dn));
    1527          45 :                                 dsdb_acl_debug(control_sd->default_sd,
    1528             :                                                acl_user_token(module),
    1529          45 :                                                msg->dn,
    1530             :                                                true,
    1531             :                                                10);
    1532          45 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    1533          45 :                                 return ret;
    1534             :                         }
    1535             :                 }
    1536             :         }
    1537          99 : success:
    1538      538028 :         return ldb_next_request(module, req);
    1539             : }
    1540             : 
    1541       16990 : static int acl_check_password_rights(
    1542             :         TALLOC_CTX *mem_ctx,
    1543             :         struct ldb_module *module,
    1544             :         struct ldb_request *req,
    1545             :         struct security_descriptor *sd,
    1546             :         struct dom_sid *sid,
    1547             :         const struct dsdb_class *objectclass,
    1548             :         bool userPassword,
    1549             :         struct  dsdb_control_password_acl_validation **control_for_response)
    1550             : {
    1551       16990 :         int ret = LDB_SUCCESS;
    1552       16990 :         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
    1553       16990 :         unsigned int del_val_cnt = 0, add_val_cnt = 0;
    1554          72 :         struct ldb_message_element *el;
    1555          72 :         struct ldb_message *msg;
    1556       16990 :         struct ldb_control *c = NULL;
    1557       16990 :         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
    1558             :                                         "unicodePwd", NULL }, **l;
    1559       16990 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1560       16990 :         struct dsdb_control_password_acl_validation *pav = NULL;
    1561             : 
    1562       16990 :         if (tmp_ctx == NULL) {
    1563           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1564             :         }
    1565             : 
    1566       16990 :         pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
    1567       16990 :         if (pav == NULL) {
    1568           0 :                 talloc_free(tmp_ctx);
    1569           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1570             :         }
    1571             :         /*
    1572             :          * Set control_for_response to pav so it can be added to the response
    1573             :          * and be passed up to the audit_log module which uses it to identify
    1574             :          * password reset attempts.
    1575             :          */
    1576       16990 :         *control_for_response = pav;
    1577             : 
    1578       16990 :         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
    1579       16990 :         if (c != NULL) {
    1580         522 :                 pav->pwd_reset = false;
    1581             : 
    1582             :                 /*
    1583             :                  * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
    1584             :                  * have a user password change and not a set as the message
    1585             :                  * looks like. In it's value blob it contains the NT and/or LM
    1586             :                  * hash of the old password specified by the user.  This control
    1587             :                  * is used by the SAMR and "kpasswd" password change mechanisms.
    1588             :                  *
    1589             :                  * This control can't be used by real LDAP clients,
    1590             :                  * the only caller is samdb_set_password_internal(),
    1591             :                  * so we don't have to strict verification of the input.
    1592             :                  */
    1593         522 :                 ret = acl_check_extended_right(tmp_ctx,
    1594             :                                                module,
    1595             :                                                req,
    1596             :                                                objectclass,
    1597             :                                                sd,
    1598             :                                                acl_user_token(module),
    1599             :                                                GUID_DRS_USER_CHANGE_PASSWORD,
    1600             :                                                SEC_ADS_CONTROL_ACCESS,
    1601             :                                                sid);
    1602         522 :                 goto checked;
    1603             :         }
    1604             : 
    1605       16468 :         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
    1606       16468 :         if (c != NULL) {
    1607         310 :                 pav->pwd_reset = true;
    1608             : 
    1609             :                 /*
    1610             :                  * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
    1611             :                  * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
    1612             :                  * have a force password set.
    1613             :                  * This control is used by the SAMR/NETLOGON/LSA password
    1614             :                  * reset mechanisms.
    1615             :                  *
    1616             :                  * This control can't be used by real LDAP clients,
    1617             :                  * the only caller is samdb_set_password_internal(),
    1618             :                  * so we don't have to strict verification of the input.
    1619             :                  */
    1620         310 :                 ret = acl_check_extended_right(tmp_ctx,
    1621             :                                                module,
    1622             :                                                req,
    1623             :                                                objectclass,
    1624             :                                                sd,
    1625             :                                                acl_user_token(module),
    1626             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1627             :                                                SEC_ADS_CONTROL_ACCESS,
    1628             :                                                sid);
    1629         310 :                 goto checked;
    1630             :         }
    1631             : 
    1632       16158 :         el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
    1633       16158 :         if (el != NULL) {
    1634             :                 /*
    1635             :                  * dBCSPwd is only allowed with a control.
    1636             :                  */
    1637           0 :                 talloc_free(tmp_ctx);
    1638           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1639             :         }
    1640             : 
    1641       16158 :         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
    1642       16158 :         if (msg == NULL) {
    1643           0 :                 return ldb_module_oom(module);
    1644             :         }
    1645       64632 :         for (l = passwordAttrs; *l != NULL; l++) {
    1646       48474 :                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
    1647       13366 :                         continue;
    1648             :                 }
    1649             : 
    1650       53350 :                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
    1651       18242 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
    1652        2093 :                                 ++del_attr_cnt;
    1653        2093 :                                 del_val_cnt += el->num_values;
    1654             :                         }
    1655       18242 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
    1656        2057 :                                 ++add_attr_cnt;
    1657        2057 :                                 add_val_cnt += el->num_values;
    1658             :                         }
    1659       18242 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
    1660       14092 :                                 ++rep_attr_cnt;
    1661             :                         }
    1662       18242 :                         ldb_msg_remove_element(msg, el);
    1663             :                 }
    1664             :         }
    1665             : 
    1666             :         /* single deletes will be handled by the "password_hash" LDB module
    1667             :          * later in the stack, so we let it though here */
    1668       16158 :         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
    1669          63 :                 talloc_free(tmp_ctx);
    1670          63 :                 return LDB_SUCCESS;
    1671             :         }
    1672             : 
    1673             : 
    1674       16095 :         if (rep_attr_cnt > 0) {
    1675       14074 :                 pav->pwd_reset = true;
    1676             : 
    1677       14074 :                 ret = acl_check_extended_right(tmp_ctx,
    1678             :                                                module,
    1679             :                                                req,
    1680             :                                                objectclass,
    1681             :                                                sd,
    1682             :                                                acl_user_token(module),
    1683             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1684             :                                                SEC_ADS_CONTROL_ACCESS,
    1685             :                                                sid);
    1686       14074 :                 goto checked;
    1687             :         }
    1688             : 
    1689        2021 :         if (add_attr_cnt != del_attr_cnt) {
    1690          99 :                 pav->pwd_reset = true;
    1691             : 
    1692          99 :                 ret = acl_check_extended_right(tmp_ctx,
    1693             :                                                module,
    1694             :                                                req,
    1695             :                                                objectclass,
    1696             :                                                sd,
    1697             :                                                acl_user_token(module),
    1698             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1699             :                                                SEC_ADS_CONTROL_ACCESS,
    1700             :                                                sid);
    1701          99 :                 goto checked;
    1702             :         }
    1703             : 
    1704        1922 :         if (add_val_cnt == 1 && del_val_cnt == 1) {
    1705        1123 :                 pav->pwd_reset = false;
    1706             : 
    1707        1123 :                 ret = acl_check_extended_right(tmp_ctx,
    1708             :                                                module,
    1709             :                                                req,
    1710             :                                                objectclass,
    1711             :                                                sd,
    1712             :                                                acl_user_token(module),
    1713             :                                                GUID_DRS_USER_CHANGE_PASSWORD,
    1714             :                                                SEC_ADS_CONTROL_ACCESS,
    1715             :                                                sid);
    1716             :                 /* Very strange, but we get constraint violation in this case */
    1717        1123 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1718          18 :                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
    1719             :                 }
    1720        1123 :                 goto checked;
    1721             :         }
    1722             : 
    1723         799 :         if (add_val_cnt == 1 && del_val_cnt == 0) {
    1724         529 :                 pav->pwd_reset = true;
    1725             : 
    1726         529 :                 ret = acl_check_extended_right(tmp_ctx,
    1727             :                                                module,
    1728             :                                                req,
    1729             :                                                objectclass,
    1730             :                                                sd,
    1731             :                                                acl_user_token(module),
    1732             :                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
    1733             :                                                SEC_ADS_CONTROL_ACCESS,
    1734             :                                                sid);
    1735             :                 /* Very strange, but we get constraint violation in this case */
    1736         529 :                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    1737          27 :                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
    1738             :                 }
    1739         529 :                 goto checked;
    1740             :         }
    1741             : 
    1742             :         /*
    1743             :          * Everything else is handled by the password_hash module where it will
    1744             :          * fail, but with the correct error code when the module is again
    1745             :          * checking the attributes. As the change request will lack the
    1746             :          * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
    1747             :          * any modification attempt that went this way will be rejected.
    1748             :          */
    1749             : 
    1750         270 :         talloc_free(tmp_ctx);
    1751         270 :         return LDB_SUCCESS;
    1752             : 
    1753       16657 : checked:
    1754       16657 :         if (ret != LDB_SUCCESS) {
    1755         142 :                 dsdb_acl_debug(sd, acl_user_token(module),
    1756         142 :                                req->op.mod.message->dn,
    1757             :                                true,
    1758             :                                10);
    1759         142 :                 talloc_free(tmp_ctx);
    1760         142 :                 return ret;
    1761             :         }
    1762             : 
    1763       16515 :         ret = ldb_request_add_control(req,
    1764             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
    1765       16515 :         if (ret != LDB_SUCCESS) {
    1766           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
    1767             :                           "Unable to register ACL validation control!\n");
    1768           0 :                 return ret;
    1769             :         }
    1770       16443 :         return LDB_SUCCESS;
    1771             : }
    1772             : 
    1773             : /*
    1774             :  * Context needed by acl_callback
    1775             :  */
    1776             : struct acl_callback_context {
    1777             :         struct ldb_request *request;
    1778             :         struct ldb_module *module;
    1779             : };
    1780             : 
    1781             : /*
    1782             :  * @brief Copy the password validation control to the reply.
    1783             :  *
    1784             :  * Copy the dsdb_control_password_acl_validation control from the request,
    1785             :  * to the reply.  The control is used by the audit_log module to identify
    1786             :  * password rests.
    1787             :  *
    1788             :  * @param req the ldb request.
    1789             :  * @param ares the result, updated with the control.
    1790             :  */
    1791      117967 : static void copy_password_acl_validation_control(
    1792             :         struct ldb_request *req,
    1793             :         struct ldb_reply *ares)
    1794             : {
    1795      117967 :         struct ldb_control *pav_ctrl = NULL;
    1796      117967 :         struct dsdb_control_password_acl_validation *pav = NULL;
    1797             : 
    1798      117967 :         pav_ctrl = ldb_request_get_control(
    1799             :                 discard_const(req),
    1800             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
    1801      117967 :         if (pav_ctrl == NULL) {
    1802       98337 :                 return;
    1803             :         }
    1804             : 
    1805       16515 :         pav = talloc_get_type_abort(
    1806             :                 pav_ctrl->data,
    1807             :                 struct dsdb_control_password_acl_validation);
    1808       16515 :         if (pav == NULL) {
    1809           0 :                 return;
    1810             :         }
    1811       16515 :         ldb_reply_add_control(
    1812             :                 ares,
    1813             :                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
    1814             :                 false,
    1815             :                 pav);
    1816             : }
    1817             : /*
    1818             :  * @brief call back function for acl_modify.
    1819             :  *
    1820             :  * Calls acl_copy to copy the dsdb_control_password_acl_validation from
    1821             :  * the request to the reply.
    1822             :  *
    1823             :  * @param req the ldb_request.
    1824             :  * @param ares the operation result.
    1825             :  *
    1826             :  * @return the LDB_STATUS
    1827             :  */
    1828      117977 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
    1829             : {
    1830      117977 :         struct acl_callback_context *ac = NULL;
    1831             : 
    1832      117977 :         ac = talloc_get_type(req->context, struct acl_callback_context);
    1833             : 
    1834      117977 :         if (!ares) {
    1835           0 :                 return ldb_module_done(
    1836             :                         ac->request,
    1837             :                         NULL,
    1838             :                         NULL,
    1839             :                         LDB_ERR_OPERATIONS_ERROR);
    1840             :         }
    1841             : 
    1842             :         /* pass on to the callback */
    1843      117977 :         switch (ares->type) {
    1844           0 :         case LDB_REPLY_ENTRY:
    1845           0 :                 return ldb_module_send_entry(
    1846             :                         ac->request,
    1847             :                         ares->message,
    1848             :                         ares->controls);
    1849             : 
    1850          10 :         case LDB_REPLY_REFERRAL:
    1851          10 :                 return ldb_module_send_referral(
    1852             :                         ac->request,
    1853             :                         ares->referral);
    1854             : 
    1855      117967 :         case LDB_REPLY_DONE:
    1856             :                 /*
    1857             :                  * Copy the ACL control from the request to the response
    1858             :                  */
    1859      117967 :                 copy_password_acl_validation_control(req, ares);
    1860      117967 :                 return ldb_module_done(
    1861             :                         ac->request,
    1862             :                         ares->controls,
    1863             :                         ares->response,
    1864             :                         ares->error);
    1865             : 
    1866           0 :         default:
    1867             :                 /* Can't happen */
    1868           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1869             :         }
    1870             : }
    1871             : 
    1872      573444 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
    1873             : {
    1874       21578 :         int ret;
    1875      573444 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1876       21578 :         const struct dsdb_schema *schema;
    1877       21578 :         unsigned int i;
    1878       21578 :         const struct dsdb_class *objectclass;
    1879       21578 :         struct ldb_result *acl_res;
    1880       21578 :         struct security_descriptor *sd;
    1881      573444 :         struct dom_sid *sid = NULL;
    1882       21578 :         struct ldb_control *as_system;
    1883       21578 :         struct ldb_control *is_undelete;
    1884      573444 :         struct ldb_control *implicit_validated_write_control = NULL;
    1885       21578 :         bool userPassword;
    1886      573444 :         bool password_rights_checked = false;
    1887       21578 :         TALLOC_CTX *tmp_ctx;
    1888      573444 :         const struct ldb_message *msg = req->op.mod.message;
    1889       21578 :         static const char *acl_attrs[] = {
    1890             :                 "nTSecurityDescriptor",
    1891             :                 "objectClass",
    1892             :                 "objectSid",
    1893             :                 NULL
    1894             :         };
    1895      573444 :         struct acl_callback_context *context = NULL;
    1896      573444 :         struct ldb_request *new_req = NULL;
    1897      573444 :         struct  dsdb_control_password_acl_validation *pav = NULL;
    1898      573444 :         struct ldb_control **controls = NULL;
    1899             : 
    1900      573444 :         if (ldb_dn_is_special(msg->dn)) {
    1901         715 :                 return ldb_next_request(module, req);
    1902             :         }
    1903             : 
    1904      572729 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    1905      572729 :         if (as_system != NULL) {
    1906      252252 :                 as_system->critical = 0;
    1907             :         }
    1908             : 
    1909      572729 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    1910             : 
    1911      572729 :         implicit_validated_write_control = ldb_request_get_control(
    1912             :                 req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
    1913      572729 :         if (implicit_validated_write_control != NULL) {
    1914         147 :                 implicit_validated_write_control->critical = 0;
    1915             :         }
    1916             : 
    1917             :         /* Don't print this debug statement if elements[0].name is going to be NULL */
    1918      572729 :         if (msg->num_elements > 0) {
    1919      572448 :                 DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
    1920             :         }
    1921      572729 :         if (dsdb_module_am_system(module) || as_system) {
    1922      453005 :                 return ldb_next_request(module, req);
    1923             :         }
    1924             : 
    1925      119724 :         tmp_ctx = talloc_new(req);
    1926      119724 :         if (tmp_ctx == NULL) {
    1927           0 :                 return ldb_oom(ldb);
    1928             :         }
    1929             : 
    1930      119724 :         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
    1931             :                                     acl_attrs,
    1932             :                                     DSDB_FLAG_NEXT_MODULE |
    1933             :                                     DSDB_FLAG_AS_SYSTEM |
    1934             :                                     DSDB_SEARCH_SHOW_RECYCLED,
    1935             :                                     req);
    1936             : 
    1937      119724 :         if (ret != LDB_SUCCESS) {
    1938         122 :                 goto fail;
    1939             :         }
    1940             : 
    1941      119602 :         userPassword = dsdb_user_password_support(module, req, req);
    1942             : 
    1943      119602 :         schema = dsdb_get_schema(ldb, tmp_ctx);
    1944      119602 :         if (!schema) {
    1945           0 :                 talloc_free(tmp_ctx);
    1946           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1947             :                                  "acl_modify: Error obtaining schema.");
    1948             :         }
    1949             : 
    1950      119602 :         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
    1951      119602 :         if (ret != LDB_SUCCESS) {
    1952           0 :                 talloc_free(tmp_ctx);
    1953           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1954             :                                  "acl_modify: Error retrieving security descriptor.");
    1955             :         }
    1956             :         /* Theoretically we pass the check if the object has no sd */
    1957      119602 :         if (!sd) {
    1958           0 :                 goto success;
    1959             :         }
    1960             : 
    1961      119602 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    1962      119602 :         if (!objectclass) {
    1963           0 :                 talloc_free(tmp_ctx);
    1964           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    1965             :                                  "acl_modify: Error retrieving object class for GUID.");
    1966             :         }
    1967      119602 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    1968      277865 :         for (i=0; i < msg->num_elements; i++) {
    1969      156706 :                 const struct ldb_message_element *el = &msg->elements[i];
    1970        4863 :                 const struct dsdb_attribute *attr;
    1971             : 
    1972             :                 /*
    1973             :                  * This basic attribute existence check with the right errorcode
    1974             :                  * is needed since this module is the first one which requests
    1975             :                  * schema attribute information.
    1976             :                  * The complete attribute checking is done in the
    1977             :                  * "objectclass_attrs" module behind this one.
    1978             :                  *
    1979             :                  * NOTE: "clearTextPassword" is not defined in the schema.
    1980             :                  */
    1981      156706 :                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
    1982      156706 :                 if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
    1983           4 :                         ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
    1984             :                                                "on entry '%s' was not found in the schema!",
    1985           2 :                                                req->op.mod.message->elements[i].name,
    1986           2 :                                        ldb_dn_get_linearized(req->op.mod.message->dn));
    1987           2 :                         ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
    1988           2 :                         goto fail;
    1989             :                 }
    1990             : 
    1991      156704 :                 if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
    1992       27366 :                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
    1993       27366 :                         uint32_t access_mask = 0;
    1994             : 
    1995          88 :                         bool block_owner_rights;
    1996          88 :                         enum implicit_owner_rights implicit_owner_rights;
    1997             : 
    1998       27366 :                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
    1999       12960 :                                 access_mask |= SEC_STD_WRITE_OWNER;
    2000             :                         }
    2001       27366 :                         if (sd_flags & SECINFO_DACL) {
    2002       27132 :                                 access_mask |= SEC_STD_WRITE_DAC;
    2003             :                         }
    2004       27366 :                         if (sd_flags & SECINFO_SACL) {
    2005       12708 :                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
    2006             :                         }
    2007             : 
    2008       27366 :                         block_owner_rights = !dsdb_module_am_administrator(module);
    2009             : 
    2010       27366 :                         if (block_owner_rights) {
    2011         180 :                                 block_owner_rights = dsdb_block_owner_implicit_rights(module,
    2012             :                                                                                       req,
    2013             :                                                                                       req);
    2014             :                         }
    2015       27366 :                         if (block_owner_rights) {
    2016         162 :                                 block_owner_rights = samdb_find_attribute(ldb,
    2017         162 :                                                                           acl_res->msgs[0],
    2018             :                                                                           "objectclass",
    2019             :                                                                           "computer");
    2020             :                         }
    2021             : 
    2022       27366 :                         implicit_owner_rights = block_owner_rights ?
    2023       27366 :                                 IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
    2024             :                                 IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
    2025             : 
    2026       27366 :                         ret = acl_check_access_on_attribute_implicit_owner(module,
    2027             :                                                                            tmp_ctx,
    2028             :                                                                            sd,
    2029             :                                                                            sid,
    2030             :                                                                            access_mask,
    2031             :                                                                            attr,
    2032             :                                                                            objectclass,
    2033             :                                                                            implicit_owner_rights);
    2034       27366 :                         if (ret != LDB_SUCCESS) {
    2035         108 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2036             :                                                        "Object %s has no write dacl access\n",
    2037         108 :                                                        ldb_dn_get_linearized(msg->dn));
    2038         108 :                                 dsdb_acl_debug(sd,
    2039             :                                                acl_user_token(module),
    2040         108 :                                                msg->dn,
    2041             :                                                true,
    2042             :                                                10);
    2043         108 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2044         108 :                                 goto fail;
    2045             :                         }
    2046      129338 :                 } else if (ldb_attr_cmp("member", el->name) == 0) {
    2047        8015 :                         ret = acl_check_self_membership(tmp_ctx,
    2048             :                                                         module,
    2049             :                                                         req,
    2050             :                                                         sd,
    2051             :                                                         sid,
    2052             :                                                         attr,
    2053             :                                                         objectclass);
    2054        8015 :                         if (ret != LDB_SUCCESS) {
    2055          51 :                                 goto fail;
    2056             :                         }
    2057      121323 :                 } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
    2058             :                         /* this one is not affected by any rights, we should let it through
    2059             :                            so that passwords_hash returns the correct error */
    2060          72 :                         continue;
    2061      121251 :                 } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
    2062        8318 :                            (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
    2063      103815 :                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
    2064             :                         /*
    2065             :                          * Ideally we would do the acl_check_password_rights
    2066             :                          * before we checked the other attributes, i.e. in a
    2067             :                          * loop before the current one.
    2068             :                          * Have not done this as yet in order to limit the size
    2069             :                          * of the change. To limit the possibility of breaking
    2070             :                          * the ACL logic.
    2071             :                          */
    2072       18957 :                         if (password_rights_checked) {
    2073        1967 :                                 continue;
    2074             :                         }
    2075       16990 :                         ret = acl_check_password_rights(tmp_ctx,
    2076             :                                                         module,
    2077             :                                                         req,
    2078             :                                                         sd,
    2079             :                                                         sid,
    2080             :                                                         objectclass,
    2081             :                                                         userPassword,
    2082             :                                                         &pav);
    2083       16990 :                         if (ret != LDB_SUCCESS) {
    2084         142 :                                 goto fail;
    2085             :                         }
    2086       16776 :                         password_rights_checked = true;
    2087      102294 :                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
    2088        2167 :                         ret = acl_check_spn(tmp_ctx,
    2089             :                                             module,
    2090             :                                             req,
    2091             :                                             el,
    2092             :                                             sd,
    2093             :                                             sid,
    2094             :                                             attr,
    2095             :                                             objectclass,
    2096             :                                             implicit_validated_write_control);
    2097        2167 :                         if (ret != LDB_SUCCESS) {
    2098         274 :                                 goto fail;
    2099             :                         }
    2100      100127 :                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
    2101         952 :                         ret = acl_check_dns_host_name(tmp_ctx,
    2102             :                                                       module,
    2103             :                                                       req,
    2104             :                                                       el,
    2105             :                                                       sd,
    2106             :                                                       sid,
    2107             :                                                       attr,
    2108             :                                                       objectclass,
    2109             :                                                       implicit_validated_write_control);
    2110         952 :                         if (ret != LDB_SUCCESS) {
    2111         180 :                                 goto fail;
    2112             :                         }
    2113       99175 :                 } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
    2114             :                         /*
    2115             :                          * in case of undelete op permissions on
    2116             :                          * isDeleted are irrelevant and
    2117             :                          * distinguishedName is removed by the
    2118             :                          * tombstone_reanimate module
    2119             :                          */
    2120         274 :                         continue;
    2121       98901 :                 } else if (implicit_validated_write_control != NULL) {
    2122             :                         /* Allow the update. */
    2123         441 :                         continue;
    2124             :                 } else {
    2125       98460 :                         ret = acl_check_access_on_attribute(module,
    2126             :                                                             tmp_ctx,
    2127             :                                                             sd,
    2128             :                                                             sid,
    2129             :                                                             SEC_ADS_WRITE_PROP,
    2130             :                                                             attr,
    2131             :                                                             objectclass);
    2132       98460 :                         if (ret != LDB_SUCCESS) {
    2133         876 :                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2134             :                                                        "Object %s has no write property access\n",
    2135         876 :                                                        ldb_dn_get_linearized(msg->dn));
    2136         876 :                                 dsdb_acl_debug(sd,
    2137             :                                                acl_user_token(module),
    2138         876 :                                                msg->dn,
    2139             :                                                true,
    2140             :                                                10);
    2141         876 :                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2142         876 :                                 goto fail;
    2143             :                         }
    2144             :                 }
    2145             :         }
    2146             : 
    2147      117969 : success:
    2148      117969 :         talloc_free(tmp_ctx);
    2149      117969 :         context = talloc_zero(req, struct acl_callback_context);
    2150             : 
    2151      117969 :         if (context == NULL) {
    2152           0 :                 return ldb_oom(ldb);
    2153             :         }
    2154      117969 :         context->request = req;
    2155      117969 :         context->module  = module;
    2156      117969 :         ret = ldb_build_mod_req(
    2157             :                 &new_req,
    2158             :                 ldb,
    2159             :                 req,
    2160             :                 req->op.mod.message,
    2161             :                 req->controls,
    2162             :                 context,
    2163             :                 acl_callback,
    2164             :                 req);
    2165      117969 :         if (ret != LDB_SUCCESS) {
    2166           0 :                 return ret;
    2167             :         }
    2168      117969 :         return ldb_next_request(module, new_req);
    2169        1755 : fail:
    2170        1755 :         talloc_free(tmp_ctx);
    2171             :         /*
    2172             :          * We copy the pav into the result, so that the password reset
    2173             :          * logging code in audit_log can log failed password reset attempts.
    2174             :          */
    2175        1755 :         if (pav) {
    2176         142 :                 struct ldb_control *control = NULL;
    2177             : 
    2178         142 :                 controls = talloc_zero_array(req, struct ldb_control *, 2);
    2179         142 :                 if (controls == NULL) {
    2180           0 :                         return ldb_oom(ldb);
    2181             :                 }
    2182             : 
    2183         142 :                 control = talloc(controls, struct ldb_control);
    2184             : 
    2185         142 :                 if (control == NULL) {
    2186           0 :                         return ldb_oom(ldb);
    2187             :                 }
    2188             : 
    2189         142 :                 control->oid= talloc_strdup(
    2190             :                         control,
    2191             :                         DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
    2192         142 :                 if (control->oid == NULL) {
    2193           0 :                         return ldb_oom(ldb);
    2194             :                 }
    2195         142 :                 control->critical    = false;
    2196         142 :                 control->data        = pav;
    2197         142 :                 *controls = control;
    2198             :         }
    2199        1755 :         return ldb_module_done(req, controls, NULL, ret);
    2200             : }
    2201             : 
    2202             : /* similar to the modify for the time being.
    2203             :  * We need to consider the special delete tree case, though - TODO */
    2204       72494 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
    2205             : {
    2206         148 :         int ret;
    2207         148 :         struct ldb_dn *parent;
    2208         148 :         struct ldb_context *ldb;
    2209         148 :         struct ldb_dn *nc_root;
    2210         148 :         struct ldb_control *as_system;
    2211         148 :         const struct dsdb_schema *schema;
    2212         148 :         const struct dsdb_class *objectclass;
    2213       72494 :         struct security_descriptor *sd = NULL;
    2214       72494 :         struct dom_sid *sid = NULL;
    2215         148 :         struct ldb_result *acl_res;
    2216         148 :         static const char *acl_attrs[] = {
    2217             :                 "nTSecurityDescriptor",
    2218             :                 "objectClass",
    2219             :                 "objectSid",
    2220             :                 NULL
    2221             :         };
    2222             : 
    2223       72494 :         if (ldb_dn_is_special(req->op.del.dn)) {
    2224           1 :                 return ldb_next_request(module, req);
    2225             :         }
    2226             : 
    2227       72493 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    2228       72493 :         if (as_system != NULL) {
    2229       29331 :                 as_system->critical = 0;
    2230             :         }
    2231             : 
    2232       72493 :         if (dsdb_module_am_system(module) || as_system) {
    2233       31704 :                 return ldb_next_request(module, req);
    2234             :         }
    2235             : 
    2236       40789 :         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
    2237             : 
    2238       40789 :         ldb = ldb_module_get_ctx(module);
    2239             : 
    2240       40789 :         parent = ldb_dn_get_parent(req, req->op.del.dn);
    2241       40789 :         if (parent == NULL) {
    2242           0 :                 return ldb_oom(ldb);
    2243             :         }
    2244             : 
    2245             :         /* Make sure we aren't deleting a NC */
    2246             : 
    2247       40789 :         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
    2248       40789 :         if (ret != LDB_SUCCESS) {
    2249           0 :                 return ret;
    2250             :         }
    2251       40789 :         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
    2252           0 :                 talloc_free(nc_root);
    2253           0 :                 DEBUG(10,("acl:deleting a NC\n"));
    2254             :                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
    2255           0 :                 return ldb_module_done(req, NULL, NULL,
    2256             :                                        LDB_ERR_UNWILLING_TO_PERFORM);
    2257             :         }
    2258       40789 :         talloc_free(nc_root);
    2259             : 
    2260       40789 :         ret = dsdb_module_search_dn(module, req, &acl_res,
    2261             :                                     req->op.del.dn, acl_attrs,
    2262             :                                     DSDB_FLAG_NEXT_MODULE |
    2263             :                                     DSDB_FLAG_AS_SYSTEM |
    2264             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2265             :         /* we should be able to find the parent */
    2266       40789 :         if (ret != LDB_SUCCESS) {
    2267           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2268             :                           ldb_dn_get_linearized(req->op.rename.olddn)));
    2269           0 :                 return ret;
    2270             :         }
    2271             : 
    2272       40789 :         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
    2273       40789 :         if (ret != LDB_SUCCESS) {
    2274           0 :                 return ldb_operr(ldb);
    2275             :         }
    2276       40789 :         if (!sd) {
    2277           0 :                 return ldb_operr(ldb);
    2278             :         }
    2279             : 
    2280       40789 :         schema = dsdb_get_schema(ldb, req);
    2281       40789 :         if (!schema) {
    2282           0 :                 return ldb_operr(ldb);
    2283             :         }
    2284             : 
    2285       40789 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    2286             : 
    2287       40789 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2288       40789 :         if (!objectclass) {
    2289           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2290             :                                  "acl_modify: Error retrieving object class for GUID.");
    2291             :         }
    2292             : 
    2293       40789 :         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
    2294        2692 :                 ret = acl_check_access_on_objectclass(module, req, sd, sid,
    2295             :                                                       SEC_ADS_DELETE_TREE,
    2296             :                                                       objectclass);
    2297        2692 :                 if (ret != LDB_SUCCESS) {
    2298           0 :                         return ret;
    2299             :                 }
    2300             : 
    2301        2692 :                 return ldb_next_request(module, req);
    2302             :         }
    2303             : 
    2304             :         /* First check if we have delete object right */
    2305       38097 :         ret = acl_check_access_on_objectclass(module, req, sd, sid,
    2306             :                                               SEC_STD_DELETE,
    2307             :                                               objectclass);
    2308       38097 :         if (ret == LDB_SUCCESS) {
    2309       37792 :                 return ldb_next_request(module, req);
    2310             :         }
    2311             : 
    2312             :         /* Nope, we don't have delete object. Lets check if we have delete
    2313             :          * child on the parent */
    2314         305 :         ret = dsdb_module_check_access_on_dn(module, req, parent,
    2315             :                                              SEC_ADS_DELETE_CHILD,
    2316             :                                              &objectclass->schemaIDGUID,
    2317             :                                              req);
    2318         305 :         if (ret != LDB_SUCCESS) {
    2319          10 :                 return ret;
    2320             :         }
    2321             : 
    2322         295 :         return ldb_next_request(module, req);
    2323             : }
    2324         265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
    2325             :                                          struct ldb_module *module,
    2326             :                                          struct ldb_request *req,
    2327             :                                          struct ldb_dn *nc_root)
    2328             : {
    2329           0 :         int ret;
    2330           0 :         struct ldb_result *acl_res;
    2331         265 :         struct security_descriptor *sd = NULL;
    2332         265 :         struct dom_sid *sid = NULL;
    2333         265 :         const struct dsdb_schema *schema = NULL;
    2334         265 :         const struct dsdb_class *objectclass = NULL;
    2335         265 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    2336           0 :         static const char *acl_attrs[] = {
    2337             :                 "nTSecurityDescriptor",
    2338             :                 "objectClass",
    2339             :                 "objectSid",
    2340             :                 NULL
    2341             :         };
    2342             : 
    2343         265 :         ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
    2344             :                                     nc_root, acl_attrs,
    2345             :                                     DSDB_FLAG_NEXT_MODULE |
    2346             :                                     DSDB_FLAG_AS_SYSTEM |
    2347             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2348         265 :         if (ret != LDB_SUCCESS) {
    2349           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2350             :                           ldb_dn_get_linearized(nc_root)));
    2351           0 :                 return ret;
    2352             :         }
    2353             : 
    2354         265 :         ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
    2355         265 :         sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
    2356         265 :         schema = dsdb_get_schema(ldb, req);
    2357         265 :         if (!schema) {
    2358           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    2359             :         }
    2360         265 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2361         265 :         if (ret != LDB_SUCCESS || !sd) {
    2362           0 :                 return ldb_operr(ldb_module_get_ctx(module));
    2363             :         }
    2364         265 :         return acl_check_extended_right(mem_ctx,
    2365             :                                         module,
    2366             :                                         req,
    2367             :                                         objectclass,
    2368             :                                         sd,
    2369             :                                         acl_user_token(module),
    2370             :                                         GUID_DRS_REANIMATE_TOMBSTONE,
    2371             :                                         SEC_ADS_CONTROL_ACCESS, sid);
    2372             : }
    2373             : 
    2374        1533 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
    2375             : {
    2376           5 :         int ret;
    2377           5 :         struct ldb_dn *oldparent;
    2378           5 :         struct ldb_dn *newparent;
    2379           5 :         const struct dsdb_schema *schema;
    2380           5 :         const struct dsdb_class *objectclass;
    2381        1533 :         const struct dsdb_attribute *attr = NULL;
    2382           5 :         struct ldb_context *ldb;
    2383        1533 :         struct security_descriptor *sd = NULL;
    2384        1533 :         struct dom_sid *sid = NULL;
    2385           5 :         struct ldb_result *acl_res;
    2386           5 :         struct ldb_dn *nc_root;
    2387           5 :         struct ldb_control *as_system;
    2388           5 :         struct ldb_control *is_undelete;
    2389           5 :         TALLOC_CTX *tmp_ctx;
    2390           5 :         const char *rdn_name;
    2391           5 :         static const char *acl_attrs[] = {
    2392             :                 "nTSecurityDescriptor",
    2393             :                 "objectClass",
    2394             :                 "objectSid",
    2395             :                 NULL
    2396             :         };
    2397             : 
    2398        1533 :         if (ldb_dn_is_special(req->op.rename.olddn)) {
    2399           0 :                 return ldb_next_request(module, req);
    2400             :         }
    2401             : 
    2402        1533 :         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    2403        1533 :         if (as_system != NULL) {
    2404           0 :                 as_system->critical = 0;
    2405             :         }
    2406             : 
    2407        1533 :         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
    2408        1533 :         if (dsdb_module_am_system(module) || as_system) {
    2409         895 :                 return ldb_next_request(module, req);
    2410             :         }
    2411             : 
    2412         638 :         ldb = ldb_module_get_ctx(module);
    2413             : 
    2414         638 :         tmp_ctx = talloc_new(req);
    2415         638 :         if (tmp_ctx == NULL) {
    2416           0 :                 return ldb_oom(ldb);
    2417             :         }
    2418             : 
    2419         638 :         oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
    2420         638 :         if (oldparent == NULL) {
    2421           0 :                 return ldb_oom(ldb);
    2422             :         }
    2423         638 :         newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
    2424         638 :         if (newparent == NULL) {
    2425           0 :                 return ldb_oom(ldb);
    2426             :         }
    2427             : 
    2428             :         /* Make sure we aren't renaming/moving a NC */
    2429             : 
    2430         638 :         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
    2431         638 :         if (ret != LDB_SUCCESS) {
    2432           0 :                 return ret;
    2433             :         }
    2434         638 :         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
    2435           0 :                 talloc_free(nc_root);
    2436           0 :                 DEBUG(10,("acl:renaming/moving a NC\n"));
    2437             :                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
    2438           0 :                 return ldb_module_done(req, NULL, NULL,
    2439             :                                        LDB_ERR_UNWILLING_TO_PERFORM);
    2440             :         }
    2441             : 
    2442             :         /* special check for undelete operation */
    2443         638 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    2444         638 :         if (is_undelete != NULL) {
    2445         265 :                 is_undelete->critical = 0;
    2446         265 :                 ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
    2447         265 :                 if (ret != LDB_SUCCESS) {
    2448           9 :                         talloc_free(tmp_ctx);
    2449           9 :                         return ret;
    2450             :                 }
    2451             :         }
    2452         629 :         talloc_free(nc_root);
    2453             : 
    2454             :         /* Look for the parent */
    2455             : 
    2456         629 :         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
    2457             :                                     req->op.rename.olddn, acl_attrs,
    2458             :                                     DSDB_FLAG_NEXT_MODULE |
    2459             :                                     DSDB_FLAG_AS_SYSTEM |
    2460             :                                     DSDB_SEARCH_SHOW_RECYCLED, req);
    2461             :         /* we should be able to find the parent */
    2462         629 :         if (ret != LDB_SUCCESS) {
    2463           0 :                 DEBUG(10,("acl: failed to find object %s\n",
    2464             :                           ldb_dn_get_linearized(req->op.rename.olddn)));
    2465           0 :                 talloc_free(tmp_ctx);
    2466           0 :                 return ret;
    2467             :         }
    2468             : 
    2469         629 :         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
    2470         629 :         if (ret != LDB_SUCCESS) {
    2471           0 :                 talloc_free(tmp_ctx);
    2472           0 :                 return ldb_operr(ldb);
    2473             :         }
    2474         629 :         if (!sd) {
    2475           0 :                 talloc_free(tmp_ctx);
    2476           0 :                 return ldb_operr(ldb);
    2477             :         }
    2478             : 
    2479         629 :         schema = dsdb_get_schema(ldb, acl_res);
    2480         629 :         if (!schema) {
    2481           0 :                 talloc_free(tmp_ctx);
    2482           0 :                 return ldb_operr(ldb);
    2483             :         }
    2484             : 
    2485         629 :         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
    2486             : 
    2487         629 :         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
    2488         629 :         if (!objectclass) {
    2489           0 :                 talloc_free(tmp_ctx);
    2490           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2491             :                                  "acl_modify: Error retrieving object class for GUID.");
    2492             :         }
    2493             : 
    2494         629 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
    2495         629 :         if (attr == NULL) {
    2496           0 :                 talloc_free(tmp_ctx);
    2497           0 :                 return ldb_operr(ldb);
    2498             :         }
    2499             : 
    2500         629 :         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
    2501             :                                             SEC_ADS_WRITE_PROP,
    2502             :                                             attr, objectclass);
    2503         629 :         if (ret != LDB_SUCCESS) {
    2504          19 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2505             :                                        "Object %s has no wp on %s\n",
    2506             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    2507          19 :                                        attr->lDAPDisplayName);
    2508          19 :                 dsdb_acl_debug(sd,
    2509             :                           acl_user_token(module),
    2510             :                           req->op.rename.olddn,
    2511             :                           true,
    2512             :                           10);
    2513          19 :                 talloc_free(tmp_ctx);
    2514          19 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2515             :         }
    2516             : 
    2517         610 :         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
    2518         610 :         if (rdn_name == NULL) {
    2519           0 :                 talloc_free(tmp_ctx);
    2520           0 :                 return ldb_operr(ldb);
    2521             :         }
    2522             : 
    2523         610 :         attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
    2524         610 :         if (attr == NULL) {
    2525           0 :                 talloc_free(tmp_ctx);
    2526           0 :                 return ldb_operr(ldb);
    2527             :         }
    2528             : 
    2529         610 :         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
    2530             :                                             SEC_ADS_WRITE_PROP,
    2531             :                                             attr, objectclass);
    2532         610 :         if (ret != LDB_SUCCESS) {
    2533           9 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2534             :                                        "Object %s has no wp on %s\n",
    2535             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    2536           9 :                                        attr->lDAPDisplayName);
    2537           9 :                 dsdb_acl_debug(sd,
    2538             :                           acl_user_token(module),
    2539             :                           req->op.rename.olddn,
    2540             :                           true,
    2541             :                           10);
    2542           9 :                 talloc_free(tmp_ctx);
    2543           9 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2544             :         }
    2545             : 
    2546         601 :         if (ldb_dn_compare(oldparent, newparent) == 0) {
    2547             :                 /* regular rename, not move, nothing more to do */
    2548         232 :                 talloc_free(tmp_ctx);
    2549         232 :                 return ldb_next_request(module, req);
    2550             :         }
    2551             : 
    2552             :         /* new parent should have create child */
    2553         369 :         ret = dsdb_module_check_access_on_dn(module, req, newparent,
    2554             :                                              SEC_ADS_CREATE_CHILD,
    2555             :                                              &objectclass->schemaIDGUID, req);
    2556         369 :         if (ret != LDB_SUCCESS) {
    2557           9 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2558             :                                        "acl:access_denied renaming %s",
    2559             :                                        ldb_dn_get_linearized(req->op.rename.olddn));
    2560           9 :                 talloc_free(tmp_ctx);
    2561           9 :                 return ret;
    2562             :         }
    2563             : 
    2564             :         /* do we have delete object on the object? */
    2565             :         /* this access is not necessary for undelete ops */
    2566         360 :         if (is_undelete == NULL) {
    2567         126 :                 ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
    2568             :                                                       SEC_STD_DELETE,
    2569             :                                                       objectclass);
    2570         126 :                 if (ret == LDB_SUCCESS) {
    2571          99 :                         talloc_free(tmp_ctx);
    2572          99 :                         return ldb_next_request(module, req);
    2573             :                 }
    2574             :                 /* what about delete child on the current parent */
    2575          27 :                 ret = dsdb_module_check_access_on_dn(module, req, oldparent,
    2576             :                                                      SEC_ADS_DELETE_CHILD,
    2577             :                                                      &objectclass->schemaIDGUID,
    2578             :                                                      req);
    2579          27 :                 if (ret != LDB_SUCCESS) {
    2580           9 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
    2581             :                                                "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
    2582           9 :                         talloc_free(tmp_ctx);
    2583           9 :                         return ldb_module_done(req, NULL, NULL, ret);
    2584             :                 }
    2585             :         }
    2586         252 :         talloc_free(tmp_ctx);
    2587             : 
    2588         252 :         return ldb_next_request(module, req);
    2589             : }
    2590             : 
    2591      826336 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
    2592             :                                                 struct acl_private *data)
    2593             : {
    2594       17500 :         struct dsdb_attribute *a;
    2595      826336 :         uint32_t n = 0;
    2596             : 
    2597      826336 :         if (data->acl_search) {
    2598             :                 /*
    2599             :                  * If acl:search is activated, the acl_read module
    2600             :                  * protects confidential attributes.
    2601             :                  */
    2602      808836 :                 return LDB_SUCCESS;
    2603             :         }
    2604             : 
    2605           0 :         if ((ac->schema == data->cached_schema_ptr) &&
    2606           0 :             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
    2607             :         {
    2608           0 :                 return LDB_SUCCESS;
    2609             :         }
    2610             : 
    2611           0 :         data->cached_schema_ptr = NULL;
    2612           0 :         data->cached_schema_loaded_usn = 0;
    2613           0 :         data->cached_schema_metadata_usn = 0;
    2614           0 :         TALLOC_FREE(data->confidential_attrs);
    2615             : 
    2616           0 :         if (ac->schema == NULL) {
    2617           0 :                 return LDB_SUCCESS;
    2618             :         }
    2619             : 
    2620           0 :         for (a = ac->schema->attributes; a; a = a->next) {
    2621           0 :                 const char **attrs = data->confidential_attrs;
    2622             : 
    2623           0 :                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
    2624           0 :                         continue;
    2625             :                 }
    2626             : 
    2627           0 :                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
    2628           0 :                 if (attrs == NULL) {
    2629           0 :                         TALLOC_FREE(data->confidential_attrs);
    2630           0 :                         return ldb_module_oom(ac->module);
    2631             :                 }
    2632             : 
    2633           0 :                 attrs[n] = a->lDAPDisplayName;
    2634           0 :                 attrs[n+1] = NULL;
    2635           0 :                 n++;
    2636             : 
    2637           0 :                 data->confidential_attrs = attrs;
    2638             :         }
    2639             : 
    2640           0 :         data->cached_schema_ptr = ac->schema;
    2641           0 :         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
    2642             : 
    2643           0 :         return LDB_SUCCESS;
    2644             : }
    2645             : 
    2646    46436047 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
    2647             : {
    2648     1503517 :         struct acl_context *ac;
    2649     1503517 :         struct acl_private *data;
    2650     1503517 :         struct ldb_result *acl_res;
    2651     1503517 :         static const char *acl_attrs[] = {
    2652             :                 "objectClass",
    2653             :                 "nTSecurityDescriptor",
    2654             :                 "objectSid",
    2655             :                 NULL
    2656             :         };
    2657     1503517 :         int ret;
    2658     1503517 :         unsigned int i;
    2659             : 
    2660    46436047 :         ac = talloc_get_type(req->context, struct acl_context);
    2661    46436047 :         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
    2662    46436047 :         if (!ares) {
    2663           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    2664             :                                        LDB_ERR_OPERATIONS_ERROR);
    2665             :         }
    2666    46436047 :         if (ares->error != LDB_SUCCESS) {
    2667     1667266 :                 return ldb_module_done(ac->req, ares->controls,
    2668             :                                        ares->response, ares->error);
    2669             :         }
    2670             : 
    2671    44768781 :         switch (ares->type) {
    2672    35365075 :         case LDB_REPLY_ENTRY:
    2673    35365075 :                 if (ac->constructed_attrs) {
    2674         346 :                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
    2675             :                                                     acl_attrs,
    2676             :                                                     DSDB_FLAG_NEXT_MODULE |
    2677             :                                                     DSDB_FLAG_AS_SYSTEM |
    2678             :                                                     DSDB_SEARCH_SHOW_RECYCLED,
    2679             :                                                     req);
    2680         346 :                         if (ret != LDB_SUCCESS) {
    2681           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2682             :                         }
    2683             :                 }
    2684             : 
    2685    35365075 :                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
    2686          22 :                         ret = acl_allowedAttributes(ac->module, ac->schema,
    2687          22 :                                                     acl_res->msgs[0],
    2688             :                                                     ares->message, ac);
    2689          22 :                         if (ret != LDB_SUCCESS) {
    2690           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2691             :                         }
    2692             :                 }
    2693             : 
    2694    35365075 :                 if (ac->allowedChildClasses) {
    2695           0 :                         ret = acl_childClasses(ac->module, ac->schema,
    2696           0 :                                                acl_res->msgs[0],
    2697             :                                                ares->message,
    2698             :                                                "allowedChildClasses");
    2699           0 :                         if (ret != LDB_SUCCESS) {
    2700           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2701             :                         }
    2702             :                 }
    2703             : 
    2704    35365075 :                 if (ac->allowedChildClassesEffective) {
    2705          18 :                         ret = acl_childClassesEffective(ac->module, ac->schema,
    2706          18 :                                                         acl_res->msgs[0],
    2707             :                                                         ares->message, ac);
    2708          18 :                         if (ret != LDB_SUCCESS) {
    2709           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2710             :                         }
    2711             :                 }
    2712             : 
    2713    35365075 :                 if (ac->sDRightsEffective) {
    2714         306 :                         ret = acl_sDRightsEffective(ac->module,
    2715         306 :                                                     acl_res->msgs[0],
    2716             :                                                     ares->message, ac);
    2717         306 :                         if (ret != LDB_SUCCESS) {
    2718           0 :                                 return ldb_module_done(ac->req, NULL, NULL, ret);
    2719             :                         }
    2720             :                 }
    2721             : 
    2722    35365075 :                 if (data == NULL) {
    2723           0 :                         return ldb_module_send_entry(ac->req, ares->message,
    2724             :                                                      ares->controls);
    2725             :                 }
    2726             : 
    2727    35365075 :                 if (ac->am_system) {
    2728           0 :                         return ldb_module_send_entry(ac->req, ares->message,
    2729             :                                                      ares->controls);
    2730             :                 }
    2731             : 
    2732    35365075 :                 if (ac->am_administrator) {
    2733    13792248 :                         return ldb_module_send_entry(ac->req, ares->message,
    2734             :                                                      ares->controls);
    2735             :                 }
    2736             : 
    2737    21572827 :                 if (data->confidential_attrs != NULL) {
    2738           0 :                         for (i = 0; data->confidential_attrs[i]; i++) {
    2739           0 :                                 ldb_msg_remove_attr(ares->message,
    2740           0 :                                                     data->confidential_attrs[i]);
    2741             :                         }
    2742             :                 }
    2743             : 
    2744    21572827 :                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
    2745             : 
    2746      786502 :         case LDB_REPLY_REFERRAL:
    2747      786502 :                 return ldb_module_send_referral(ac->req, ares->referral);
    2748             : 
    2749     8617204 :         case LDB_REPLY_DONE:
    2750     8617204 :                 return ldb_module_done(ac->req, ares->controls,
    2751             :                                        ares->response, LDB_SUCCESS);
    2752             : 
    2753             :         }
    2754           0 :         return LDB_SUCCESS;
    2755             : }
    2756             : 
    2757    32697663 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
    2758             : {
    2759     1778796 :         struct ldb_context *ldb;
    2760     1778796 :         struct acl_context *ac;
    2761    32697663 :         struct ldb_parse_tree *down_tree = req->op.search.tree;
    2762     1778796 :         struct ldb_request *down_req;
    2763     1778796 :         struct acl_private *data;
    2764     1778796 :         int ret;
    2765     1778796 :         unsigned int i;
    2766    32697663 :         bool modify_search = true;
    2767             : 
    2768    32697663 :         if (ldb_dn_is_special(req->op.search.base)) {
    2769     1138656 :                 return ldb_next_request(module, req);
    2770             :         }
    2771             : 
    2772    31559007 :         ldb = ldb_module_get_ctx(module);
    2773             : 
    2774    31559007 :         ac = talloc_zero(req, struct acl_context);
    2775    31559007 :         if (ac == NULL) {
    2776           0 :                 return ldb_oom(ldb);
    2777             :         }
    2778    31559007 :         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
    2779             : 
    2780    31559007 :         ac->module = module;
    2781    31559007 :         ac->req = req;
    2782    31559007 :         ac->am_system = dsdb_module_am_system(module);
    2783    31559007 :         ac->am_administrator = dsdb_module_am_administrator(module);
    2784    31559007 :         ac->constructed_attrs = false;
    2785    31559007 :         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
    2786    31559007 :         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
    2787    31559007 :         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
    2788    31559007 :         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
    2789    31559007 :         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
    2790    31559007 :         ac->schema = dsdb_get_schema(ldb, ac);
    2791             : 
    2792    31559007 :         ac->constructed_attrs |= ac->allowedAttributes;
    2793    31559007 :         ac->constructed_attrs |= ac->allowedChildClasses;
    2794    31559007 :         ac->constructed_attrs |= ac->allowedChildClassesEffective;
    2795    31559007 :         ac->constructed_attrs |= ac->allowedAttributesEffective;
    2796    31559007 :         ac->constructed_attrs |= ac->sDRightsEffective;
    2797             : 
    2798    31559007 :         if (data == NULL) {
    2799           0 :                 modify_search = false;
    2800             :         }
    2801    31559007 :         if (ac->am_system) {
    2802    21273977 :                 modify_search = false;
    2803             :         }
    2804             : 
    2805    31559007 :         if (!ac->constructed_attrs && !modify_search) {
    2806    21273977 :                 talloc_free(ac);
    2807    21273977 :                 return ldb_next_request(module, req);
    2808             :         }
    2809             : 
    2810    10285030 :         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
    2811    10285030 :         if (data == NULL) {
    2812           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
    2813             :                                  "acl_private data is missing");
    2814             :         }
    2815             : 
    2816    10285030 :         if (!ac->am_system && !ac->am_administrator) {
    2817      826336 :                 ret = acl_search_update_confidential_attrs(ac, data);
    2818      826336 :                 if (ret != LDB_SUCCESS) {
    2819           0 :                         return ret;
    2820             :                 }
    2821             : 
    2822      826336 :                 if (data->confidential_attrs != NULL) {
    2823           0 :                         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
    2824           0 :                         if (down_tree == NULL) {
    2825           0 :                                 return ldb_oom(ldb);
    2826             :                         }
    2827             : 
    2828           0 :                         for (i = 0; data->confidential_attrs[i]; i++) {
    2829           0 :                                 ldb_parse_tree_attr_replace(down_tree,
    2830           0 :                                                             data->confidential_attrs[i],
    2831             :                                                             "kludgeACLredactedattribute");
    2832             :                         }
    2833             :                 }
    2834             :         }
    2835             : 
    2836    10285030 :         ret = ldb_build_search_req_ex(&down_req,
    2837             :                                       ldb, ac,
    2838             :                                       req->op.search.base,
    2839             :                                       req->op.search.scope,
    2840             :                                       down_tree,
    2841             :                                       req->op.search.attrs,
    2842             :                                       req->controls,
    2843             :                                       ac, acl_search_callback,
    2844             :                                       req);
    2845    10285030 :         LDB_REQ_SET_LOCATION(down_req);
    2846    10285030 :         if (ret != LDB_SUCCESS) {
    2847           0 :                 return ret;
    2848             :         }
    2849             :         /* perform the search */
    2850    10285030 :         return ldb_next_request(module, down_req);
    2851             : }
    2852             : 
    2853     1280530 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
    2854             : {
    2855     1280530 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    2856     1280530 :         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
    2857             : 
    2858             :         /* allow everybody to read the sequence number */
    2859     1280530 :         if (strcmp(req->op.extended.oid,
    2860             :                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
    2861     1274870 :                 return ldb_next_request(module, req);
    2862             :         }
    2863             : 
    2864        6178 :         if (dsdb_module_am_system(module) ||
    2865         518 :             dsdb_module_am_administrator(module) || as_system) {
    2866        5660 :                 return ldb_next_request(module, req);
    2867             :         } else {
    2868           0 :                 ldb_asprintf_errstring(ldb,
    2869             :                                        "acl_extended: "
    2870             :                                        "attempted database modify not permitted. "
    2871             :                                        "User %s is not SYSTEM or an administrator",
    2872             :                                        acl_user_name(req, module));
    2873           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2874             :         }
    2875             : }
    2876             : 
    2877             : static const struct ldb_module_ops ldb_acl_module_ops = {
    2878             :         .name              = "acl",
    2879             :         .search            = acl_search,
    2880             :         .add               = acl_add,
    2881             :         .modify            = acl_modify,
    2882             :         .del               = acl_delete,
    2883             :         .rename            = acl_rename,
    2884             :         .extended          = acl_extended,
    2885             :         .init_context      = acl_module_init
    2886             : };
    2887             : 
    2888        5903 : int ldb_acl_module_init(const char *version)
    2889             : {
    2890        5903 :         LDB_MODULE_CHECK_VERSION(version);
    2891        5903 :         return ldb_register_module(&ldb_acl_module_ops);
    2892             : }

Generated by: LCOV version 1.14