LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - acl.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 714 947 75.4 %
Date: 2021-09-23 10:06:22 Functions: 21 23 91.3 %

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

Generated by: LCOV version 1.13