LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - objectclass.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 595 703 84.6 %
Date: 2024-04-21 15:09:00 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /*
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Simo Sorce  2006-2008
       5             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
       6             :    Copyright (C) Matthias Dieter Wallnöfer 2010-2011
       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: objectClass sorting and constraint checking module
      26             :  *
      27             :  *  Description:
      28             :  *  - sort the objectClass attribute into the class
      29             :  *    hierarchy and perform constraint checks (correct RDN name,
      30             :  *    valid parent),
      31             :  *  - fix DNs into 'standard' case
      32             :  *  - Add objectCategory and some other attribute defaults
      33             :  *
      34             :  *  Author: Andrew Bartlett
      35             :  */
      36             : 
      37             : 
      38             : #include "includes.h"
      39             : #include "ldb_module.h"
      40             : #include "dsdb/samdb/samdb.h"
      41             : #include "librpc/ndr/libndr.h"
      42             : #include "librpc/gen_ndr/ndr_security.h"
      43             : #include "libcli/security/security.h"
      44             : #include "auth/auth.h"
      45             : #include "param/param.h"
      46             : #include "../libds/common/flags.h"
      47             : #include "dsdb/samdb/ldb_modules/util.h"
      48             : 
      49             : #undef strcasecmp
      50             : 
      51             : struct oc_context {
      52             : 
      53             :         struct ldb_module *module;
      54             :         struct ldb_request *req;
      55             :         const struct dsdb_schema *schema;
      56             : 
      57             :         struct ldb_reply *search_res;
      58             :         struct ldb_reply *search_res2;
      59             : 
      60             :         int (*step_fn)(struct oc_context *);
      61             : };
      62             : 
      63      975603 : static struct oc_context *oc_init_context(struct ldb_module *module,
      64             :                                           struct ldb_request *req)
      65             : {
      66      100910 :         struct ldb_context *ldb;
      67      100910 :         struct oc_context *ac;
      68             : 
      69      975603 :         ldb = ldb_module_get_ctx(module);
      70             : 
      71      975603 :         ac = talloc_zero(req, struct oc_context);
      72      975603 :         if (ac == NULL) {
      73           0 :                 ldb_oom(ldb);
      74           0 :                 return NULL;
      75             :         }
      76             : 
      77      975603 :         ac->module = module;
      78      975603 :         ac->req = req;
      79      975603 :         ac->schema = dsdb_get_schema(ldb, ac);
      80             : 
      81      975603 :         return ac;
      82             : }
      83             : 
      84             : static int objectclass_do_add(struct oc_context *ac);
      85             : 
      86             : /*
      87             :  * This checks if we have unrelated object classes in our entry's "objectClass"
      88             :  * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
      89             :  * or two or more disjunct structural ones.
      90             :  * If one of these conditions are true, blame.
      91             :  */
      92      543324 : static int check_unrelated_objectclasses(struct ldb_module *module,
      93             :                                         const struct dsdb_schema *schema,
      94             :                                         const struct dsdb_class *struct_objectclass,
      95             :                                         struct ldb_message_element *objectclass_element)
      96             : {
      97      543324 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
      98       83617 :         unsigned int i;
      99       83617 :         bool found;
     100             : 
     101      543324 :         if (schema == NULL) {
     102           0 :                 return LDB_SUCCESS;
     103             :         }
     104             : 
     105     1703686 :         for (i = 0; i < objectclass_element->num_values; i++) {
     106     1329331 :                 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
     107     1160367 :                                                                                            &objectclass_element->values[i]);
     108     1160367 :                 const struct dsdb_class *tmp_class2 = struct_objectclass;
     109             : 
     110             :                 /* Pointer comparison can be used due to the same schema str. */
     111     1327607 :                 if (tmp_class == NULL ||
     112      700665 :                     tmp_class == struct_objectclass ||
     113      617048 :                     tmp_class->objectClassCategory > 2 ||
     114      616937 :                     ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
     115     1086754 :                         continue;
     116             :                 }
     117             : 
     118       71889 :                 found = false;
     119      187530 :                 while (!found &&
     120      113922 :                        ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
     121      116051 :                         tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
     122      113917 :                                                                    tmp_class2->subClassOf);
     123      113917 :                         if (tmp_class2 == tmp_class) {
     124       73608 :                                 found = true;
     125             :                         }
     126             :                 }
     127       73613 :                 if (found) {
     128       73608 :                         continue;
     129             :                 }
     130             : 
     131           5 :                 ldb_asprintf_errstring(ldb,
     132             :                                        "objectclass: the objectclass '%s' seems to be unrelated to %s!",
     133           5 :                                        tmp_class->lDAPDisplayName,
     134           5 :                                        struct_objectclass->lDAPDisplayName);
     135           5 :                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
     136             :         }
     137             : 
     138      459702 :         return LDB_SUCCESS;
     139             : }
     140             : 
     141     1275491 : static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
     142             : {
     143      167521 :         struct ldb_context *ldb;
     144      167521 :         struct oc_context *ac;
     145      167521 :         int ret;
     146             : 
     147     1275491 :         ac = talloc_get_type(req->context, struct oc_context);
     148     1275491 :         ldb = ldb_module_get_ctx(ac->module);
     149             : 
     150     1275491 :         if (!ares) {
     151           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     152             :                                         LDB_ERR_OPERATIONS_ERROR);
     153             :         }
     154     1275491 :         if (ares->error != LDB_SUCCESS &&
     155       37852 :             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
     156           2 :                 return ldb_module_done(ac->req, ares->controls,
     157             :                                         ares->response, ares->error);
     158             :         }
     159             : 
     160     1275489 :         ldb_reset_err_string(ldb);
     161             : 
     162     1275489 :         switch (ares->type) {
     163      618803 :         case LDB_REPLY_ENTRY:
     164      618803 :                 if (ac->search_res != NULL) {
     165           0 :                         ldb_set_errstring(ldb, "Too many results");
     166           0 :                         talloc_free(ares);
     167           0 :                         return ldb_module_done(ac->req, NULL, NULL,
     168             :                                                 LDB_ERR_OPERATIONS_ERROR);
     169             :                 }
     170             : 
     171      618803 :                 ac->search_res = talloc_steal(ac, ares);
     172      618803 :                 break;
     173             : 
     174           0 :         case LDB_REPLY_REFERRAL:
     175             :                 /* ignore */
     176           0 :                 talloc_free(ares);
     177           0 :                 break;
     178             : 
     179      656686 :         case LDB_REPLY_DONE:
     180      656686 :                 talloc_free(ares);
     181      656686 :                 ret = ac->step_fn(ac);
     182      656686 :                 if (ret != LDB_SUCCESS) {
     183       38831 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
     184             :                 }
     185      534090 :                 break;
     186             :         }
     187             : 
     188     1069149 :         return LDB_SUCCESS;
     189             : }
     190             : 
     191             : /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
     192             : 
     193             :    This should mean that if the parent is:
     194             :     CN=Users,DC=samba,DC=example,DC=com
     195             :    and a proposed child is
     196             :     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
     197             : 
     198             :    The resulting DN should be:
     199             : 
     200             :     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
     201             : 
     202             :  */
     203      544353 : static int fix_dn(struct ldb_context *ldb,
     204             :                   TALLOC_CTX *mem_ctx,
     205             :                   struct ldb_dn *newdn, struct ldb_dn *parent_dn,
     206             :                   struct ldb_dn **fixed_dn)
     207             : {
     208       83594 :         char *upper_rdn_attr;
     209       83594 :         const struct ldb_val *rdn_val;
     210             : 
     211             :         /* Fix up the DN to be in the standard form, taking particular care to
     212             :          * match the parent DN */
     213      544353 :         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
     214      544353 :         if (*fixed_dn == NULL) {
     215           0 :                 return ldb_oom(ldb);
     216             :         }
     217             : 
     218             :         /* We need the attribute name in upper case */
     219      544353 :         upper_rdn_attr = strupper_talloc(*fixed_dn,
     220             :                                          ldb_dn_get_rdn_name(newdn));
     221      544353 :         if (upper_rdn_attr == NULL) {
     222           0 :                 return ldb_oom(ldb);
     223             :         }
     224             : 
     225             :         /* Create a new child */
     226      544353 :         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
     227           0 :                 return ldb_operr(ldb);
     228             :         }
     229             : 
     230      544353 :         rdn_val = ldb_dn_get_rdn_val(newdn);
     231      544353 :         if (rdn_val == NULL) {
     232           0 :                 return ldb_operr(ldb);
     233             :         }
     234             : 
     235             : #if 0
     236             :         /* the rules for rDN length constraints are more complex than
     237             :         this. Until we understand them we need to leave this
     238             :         constraint out. Otherwise we break replication, as windows
     239             :         does sometimes send us rDNs longer than 64 */
     240             :         if (!rdn_val || rdn_val->length > 64) {
     241             :                 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
     242             :         }
     243             : #endif
     244             : 
     245             : 
     246             :         /* And replace it with CN=foo (we need the attribute in upper case) */
     247      544353 :         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
     248             : }
     249             : 
     250             : 
     251      543753 : static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
     252             : {
     253       83679 :         struct ldb_context *ldb;
     254       83679 :         struct ldb_request *search_req;
     255       83679 :         struct oc_context *ac;
     256       83679 :         struct ldb_dn *parent_dn;
     257       83679 :         const struct ldb_val *val;
     258       83679 :         int ret;
     259       83679 :         static const char * const parent_attrs[] = { "objectClass", NULL };
     260             : 
     261      543753 :         ldb = ldb_module_get_ctx(module);
     262             : 
     263      543753 :         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
     264             : 
     265             :         /* do not manipulate our control entries */
     266      543753 :         if (ldb_dn_is_special(req->op.add.message->dn)) {
     267         538 :                 return ldb_next_request(module, req);
     268             :         }
     269             : 
     270             :         /* An add operation on the basedn without "NC-add" operation isn't
     271             :          * allowed. */
     272      543215 :         if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
     273          22 :                 unsigned int instanceType;
     274             : 
     275         128 :                 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
     276             :                                                          "instanceType", 0);
     277         128 :                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
     278           0 :                         char *referral_uri;
     279             :                         /* When we are trying to readd the root basedn then
     280             :                          * this is denied, but with an interesting mechanism:
     281             :                          * there is generated a referral with the last
     282             :                          * component value as hostname. */
     283           1 :                         val = ldb_dn_get_component_val(req->op.add.message->dn,
     284           1 :                                                        ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
     285           1 :                         if (val == NULL) {
     286           0 :                                 return ldb_operr(ldb);
     287             :                         }
     288           1 :                         referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
     289           1 :                                                        ldb_dn_get_linearized(req->op.add.message->dn));
     290           1 :                         if (referral_uri == NULL) {
     291           0 :                                 return ldb_module_oom(module);
     292             :                         }
     293             : 
     294           1 :                         return ldb_module_send_referral(req, referral_uri);
     295             :                 }
     296             :         }
     297             : 
     298      543214 :         ac = oc_init_context(module, req);
     299      543214 :         if (ac == NULL) {
     300           0 :                 return ldb_operr(ldb);
     301             :         }
     302             : 
     303             :         /* If there isn't a parent, just go on to the add processing */
     304      543214 :         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
     305           9 :                 return objectclass_do_add(ac);
     306             :         }
     307             : 
     308             :         /* get copy of parent DN */
     309      543205 :         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
     310      543205 :         if (parent_dn == NULL) {
     311           0 :                 return ldb_operr(ldb);
     312             :         }
     313             : 
     314      543205 :         ret = ldb_build_search_req(&search_req, ldb,
     315             :                                    ac, parent_dn, LDB_SCOPE_BASE,
     316             :                                    "(objectClass=*)", parent_attrs,
     317             :                                    NULL,
     318             :                                    ac, get_search_callback,
     319             :                                    req);
     320      543205 :         LDB_REQ_SET_LOCATION(search_req);
     321      543205 :         if (ret != LDB_SUCCESS) {
     322           0 :                 return ret;
     323             :         }
     324             : 
     325      543205 :         ret = dsdb_request_add_controls(search_req,
     326             :                                         DSDB_FLAG_AS_SYSTEM |
     327             :                                         DSDB_SEARCH_SHOW_RECYCLED);
     328      543205 :         if (ret != LDB_SUCCESS) {
     329           0 :                 return ret;
     330             :         }
     331             : 
     332      543205 :         ac->step_fn = objectclass_do_add;
     333             : 
     334      543205 :         return ldb_next_request(ac->module, search_req);
     335             : }
     336             : 
     337             : 
     338             : /*
     339             :   check if this is a special RODC nTDSDSA add
     340             :  */
     341          93 : static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
     342             :                                    const struct dsdb_class *objectclass)
     343             : {
     344           0 :         struct ldb_control *rodc_control;
     345             : 
     346          93 :         if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
     347           1 :                 return false;
     348             :         }
     349          92 :         rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
     350          92 :         if (!rodc_control) {
     351           0 :                 return false;
     352             :         }
     353             : 
     354          92 :         rodc_control->critical = false;
     355          92 :         return true;
     356             : }
     357             : 
     358      543214 : static int objectclass_do_add(struct oc_context *ac)
     359             : {
     360      543214 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     361       83611 :         struct ldb_request *add_req;
     362       83611 :         struct ldb_message_element *objectclass_element, *el;
     363       83611 :         struct ldb_message *msg;
     364      543214 :         const char *rdn_name = NULL;
     365       83611 :         char *value;
     366       83611 :         const struct dsdb_class *objectclass;
     367       83611 :         struct ldb_dn *objectcategory;
     368      543214 :         int32_t systemFlags = 0;
     369       83611 :         unsigned int i, j;
     370       83611 :         bool found;
     371       83611 :         int ret;
     372             : 
     373      543214 :         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
     374      543214 :         if (msg == NULL) {
     375           0 :                 return ldb_module_oom(ac->module);
     376             :         }
     377             : 
     378             :         /* Check if we have a valid parent - this check is needed since
     379             :          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
     380      543214 :         if (ac->search_res == NULL) {
     381          22 :                 unsigned int instanceType;
     382             : 
     383             :                 /* An add operation on partition DNs without "NC-add" operation
     384             :                  * isn't allowed. */
     385         128 :                 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
     386             :                                                          0);
     387         128 :                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
     388           1 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
     389             :                                                ldb_dn_get_linearized(msg->dn));
     390           1 :                         return LDB_ERR_NO_SUCH_OBJECT;
     391             :                 }
     392             : 
     393             :                 /* Don't keep any error messages - we've to add a partition */
     394         127 :                 ldb_set_errstring(ldb, NULL);
     395             :         } else {
     396             :                 /* Fix up the DN to be in the standard form, taking
     397             :                  * particular care to match the parent DN */
     398      626675 :                 ret = fix_dn(ldb, msg,
     399      543086 :                              ac->req->op.add.message->dn,
     400      543086 :                              ac->search_res->message->dn,
     401             :                              &msg->dn);
     402      543086 :                 if (ret != LDB_SUCCESS) {
     403           0 :                         ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
     404           0 :                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
     405           0 :                         return ret;
     406             :                 }
     407             :         }
     408             : 
     409      543213 :         if (ac->schema != NULL) {
     410      543213 :                 unsigned int linkID = 0;
     411             :                 /*
     412             :                  * Notice: by the normalization function call in "ldb_request()"
     413             :                  * case "LDB_ADD" we have always only *one* "objectClass"
     414             :                  * attribute at this stage!
     415             :                  */
     416             : 
     417      543213 :                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
     418      543213 :                 if (!objectclass_element) {
     419           1 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
     420             :                                                ldb_dn_get_linearized(msg->dn));
     421           1 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
     422             :                 }
     423      543212 :                 if (objectclass_element->num_values == 0) {
     424           1 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
     425             :                                                ldb_dn_get_linearized(msg->dn));
     426           1 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     427             :                 }
     428             : 
     429             :                 /* Now do the sorting */
     430      543211 :                 ret = dsdb_sort_objectClass_attr(ldb, ac->schema,
     431             :                                                  objectclass_element, msg,
     432             :                                                  objectclass_element);
     433      543211 :                 if (ret != LDB_SUCCESS) {
     434           1 :                         return ret;
     435             :                 }
     436             : 
     437             :                 /*
     438             :                  * Get the new top-most structural object class and check for
     439             :                  * unrelated structural classes
     440             :                  */
     441      543210 :                 objectclass = dsdb_get_last_structural_class(ac->schema,
     442             :                                                              objectclass_element);
     443      543210 :                 if (objectclass == NULL) {
     444           1 :                         ldb_asprintf_errstring(ldb,
     445             :                                                "Failed to find a structural class for %s",
     446             :                                                ldb_dn_get_linearized(msg->dn));
     447           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     448             :                 }
     449             : 
     450      543209 :                 ret = check_unrelated_objectclasses(ac->module, ac->schema,
     451             :                                                     objectclass,
     452             :                                                     objectclass_element);
     453      543209 :                 if (ret != LDB_SUCCESS) {
     454           2 :                         return ret;
     455             :                 }
     456             : 
     457      543207 :                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
     458      543207 :                 if (rdn_name == NULL) {
     459           0 :                         return ldb_operr(ldb);
     460             :                 }
     461      459596 :                 found = false;
     462     1129672 :                 for (i = 0; (!found) && (i < objectclass_element->num_values);
     463      586465 :                      i++) {
     464       84978 :                         const struct dsdb_class *tmp_class =
     465      671443 :                                 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
     466      586465 :                                                                       &objectclass_element->values[i]);
     467             : 
     468      586465 :                         if (tmp_class == NULL) continue;
     469             : 
     470      586465 :                         if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
     471      543206 :                                 found = true;
     472             :                 }
     473      543207 :                 if (!found) {
     474           1 :                         ldb_asprintf_errstring(ldb,
     475             :                                                "objectclass: Invalid RDN '%s' for objectclass '%s'!",
     476           1 :                                                rdn_name, objectclass->lDAPDisplayName);
     477           1 :                         return LDB_ERR_NAMING_VIOLATION;
     478             :                 }
     479             : 
     480      544881 :                 if (objectclass->systemOnly &&
     481        1675 :                     !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
     482          93 :                     !check_rodc_ntdsdsa_add(ac, objectclass)) {
     483           1 :                         ldb_asprintf_errstring(ldb,
     484             :                                                "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
     485           1 :                                                objectclass->lDAPDisplayName,
     486             :                                                ldb_dn_get_linearized(msg->dn));
     487           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     488             :                 }
     489             : 
     490      543205 :                 if (ac->search_res && ac->search_res->message) {
     491       83589 :                         struct ldb_message_element *oc_el
     492      543078 :                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
     493             : 
     494      543078 :                         bool allowed_class = false;
     495     1721960 :                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
     496      167698 :                                 const struct dsdb_class *sclass;
     497             : 
     498     1262991 :                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
     499     1095293 :                                                                                &oc_el->values[i]);
     500     1095293 :                                 if (!sclass) {
     501             :                                         /* We don't know this class?  what is going on? */
     502           0 :                                         continue;
     503             :                                 }
     504    11264486 :                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
     505    10712268 :                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
     506      459486 :                                                 allowed_class = true;
     507      459486 :                                                 break;
     508             :                                         }
     509             :                                 }
     510             :                         }
     511             : 
     512      543078 :                         if (!allowed_class) {
     513           6 :                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
     514           3 :                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
     515           3 :                                 return LDB_ERR_NAMING_VIOLATION;
     516             :                         }
     517             :                 }
     518             : 
     519      543202 :                 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
     520             :                                                          "objectCategory");
     521      543202 :                 if (objectcategory == NULL) {
     522       83611 :                         struct dsdb_extended_dn_store_format *dn_format =
     523      542671 :                                         talloc_get_type(ldb_module_get_private(ac->module),
     524             :                                                         struct dsdb_extended_dn_store_format);
     525      542671 :                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
     526             :                                 /* Strip off extended components */
     527           0 :                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
     528           0 :                                                                objectclass->defaultObjectCategory);
     529           0 :                                 value = ldb_dn_alloc_linearized(msg, dn);
     530           0 :                                 talloc_free(dn);
     531             :                         } else {
     532      542671 :                                 value = talloc_strdup(msg,
     533      542671 :                                                       objectclass->defaultObjectCategory);
     534             :                         }
     535      542671 :                         if (value == NULL) {
     536           0 :                                 return ldb_module_oom(ac->module);
     537             :                         }
     538             : 
     539      542671 :                         ret = ldb_msg_add_string(msg, "objectCategory", value);
     540      542671 :                         if (ret != LDB_SUCCESS) {
     541           0 :                                 return ret;
     542             :                         }
     543             :                 } else {
     544           0 :                         const struct dsdb_class *ocClass =
     545         531 :                                         dsdb_class_by_cn_ldb_val(ac->schema,
     546             :                                                                  ldb_dn_get_rdn_val(objectcategory));
     547         531 :                         if (ocClass != NULL) {
     548         530 :                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
     549         530 :                                                                ocClass->defaultObjectCategory);
     550         530 :                                 if (ldb_dn_compare(objectcategory, dn) != 0) {
     551           0 :                                         ocClass = NULL;
     552             :                                 }
     553             :                         }
     554         531 :                         talloc_free(objectcategory);
     555         531 :                         if (ocClass == NULL) {
     556           1 :                                 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
     557             :                                                        ldb_dn_get_linearized(msg->dn));
     558           1 :                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
     559             :                         }
     560             :                 }
     561             : 
     562      543201 :                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
     563      254205 :                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
     564             :                                                 "TRUE");
     565             :                 }
     566             : 
     567             :                 /* There are very special rules for systemFlags, see MS-ADTS
     568             :                  * MS-ADTS 3.1.1.5.2.4 */
     569             : 
     570      543201 :                 el = ldb_msg_find_element(msg, "systemFlags");
     571      543201 :                 if ((el != NULL) && (el->num_values > 1)) {
     572           1 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
     573             :                                                ldb_dn_get_linearized(msg->dn));
     574           1 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     575             :                 }
     576             : 
     577      543200 :                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
     578             : 
     579      543200 :                 ldb_msg_remove_attr(msg, "systemFlags");
     580             : 
     581             :                 /* Only the following flags may be set by a client */
     582      543200 :                 if (ldb_request_get_control(ac->req,
     583             :                                             LDB_CONTROL_RELAX_OID) == NULL) {
     584      271331 :                         systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
     585             :                                        | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
     586             :                                        | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
     587             :                                        | SYSTEM_FLAG_ATTR_IS_RDN );
     588             :                 }
     589             : 
     590             :                 /* But the last one ("ATTR_IS_RDN") is only allowed on
     591             :                  * "attributeSchema" objects. So truncate if it does not fit. */
     592      543200 :                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
     593      358800 :                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
     594             :                 }
     595             : 
     596      543200 :                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
     597         633 :                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
     598      542567 :                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
     599      542369 :                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
     600      542171 :                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
     601         747 :                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
     602         198 :                                 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
     603         747 :                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
     604      541820 :                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
     605      541675 :                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
     606      541466 :                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
     607      541466 :                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
     608         462 :                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
     609             :                 }
     610             :                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
     611             : 
     612      543200 :                 linkID = ldb_msg_find_attr_as_int(msg, "linkID", 0);
     613      543200 :                 if (linkID > 0 && linkID % 2 == 1) {
     614        6575 :                         systemFlags |= DS_FLAG_ATTR_NOT_REPLICATED;
     615             :                 }
     616             : 
     617      543200 :                 if (el || systemFlags != 0) {
     618      206716 :                         ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
     619             :                                                 systemFlags);
     620      206716 :                         if (ret != LDB_SUCCESS) {
     621           0 :                                 return ret;
     622             :                         }
     623             :                 }
     624             : 
     625             :                 /* make sure that "isCriticalSystemObject" is not specified! */
     626      543200 :                 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
     627      556192 :                 if ((el != NULL) &&
     628       12992 :                     !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
     629           1 :                         ldb_set_errstring(ldb,
     630             :                                           "objectclass: 'isCriticalSystemObject' must not be specified!");
     631           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     632             :                 }
     633             :         }
     634             : 
     635      543199 :         ret = ldb_build_add_req(&add_req, ldb, ac,
     636             :                                 msg,
     637      459588 :                                 ac->req->controls,
     638      459588 :                                 ac->req, dsdb_next_callback,
     639             :                                 ac->req);
     640      543199 :         LDB_REQ_SET_LOCATION(add_req);
     641      543199 :         if (ret != LDB_SUCCESS) {
     642           0 :                 return ret;
     643             :         }
     644             : 
     645             :         /* perform the add */
     646      543199 :         return ldb_next_request(ac->module, add_req);
     647             : }
     648             : 
     649             : static int oc_modify_callback(struct ldb_request *req,
     650             :                                 struct ldb_reply *ares);
     651             : static int objectclass_do_mod(struct oc_context *ac);
     652             : 
     653      321259 : static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
     654             : {
     655      321259 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     656       17201 :         struct ldb_message_element *objectclass_element;
     657       17201 :         struct ldb_message *msg;
     658       17201 :         struct ldb_request *down_req;
     659       17201 :         struct oc_context *ac;
     660      321259 :         bool oc_changes = false;
     661       17201 :         int ret;
     662             : 
     663      321259 :         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
     664             : 
     665             :         /* do not manipulate our control entries */
     666      321259 :         if (ldb_dn_is_special(req->op.mod.message->dn)) {
     667         715 :                 return ldb_next_request(module, req);
     668             :         }
     669             : 
     670             :         /* As with the "real" AD we don't accept empty messages */
     671      320544 :         if (req->op.mod.message->num_elements == 0) {
     672           6 :                 ldb_set_errstring(ldb, "objectclass: modify message must have "
     673             :                                        "elements/attributes!");
     674           6 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     675             :         }
     676             : 
     677      320538 :         ac = oc_init_context(module, req);
     678      320538 :         if (ac == NULL) {
     679           0 :                 return ldb_operr(ldb);
     680             :         }
     681             : 
     682             :         /* Without schema, there isn't much to do here */
     683      320538 :         if (ac->schema == NULL) {
     684           0 :                 talloc_free(ac);
     685           0 :                 return ldb_next_request(module, req);
     686             :         }
     687             : 
     688      320538 :         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
     689      320538 :         if (msg == NULL) {
     690           0 :                 return ldb_module_oom(ac->module);
     691             :         }
     692             : 
     693             :         /* For now change everything except the objectclasses */
     694             : 
     695      320538 :         objectclass_element = ldb_msg_find_element(msg, "objectClass");
     696      320538 :         if (objectclass_element != NULL) {
     697         476 :                 ldb_msg_remove_attr(msg, "objectClass");
     698         476 :                 oc_changes = true;
     699             :         }
     700             : 
     701             :         /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
     702             :          * only on application NCs - not on the default ones */
     703      303871 :         if (oc_changes &&
     704         476 :             (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
     705           0 :                 struct ldb_dn *nc_root;
     706             : 
     707           0 :                 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
     708             :                                         &nc_root);
     709           0 :                 if (ret != LDB_SUCCESS) {
     710           0 :                         return ret;
     711             :                 }
     712             : 
     713           0 :                 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
     714           0 :                     (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
     715           0 :                     (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
     716           0 :                         ldb_set_errstring(ldb,
     717             :                                           "objectclass: object class changes on objects under the standard name contexts not allowed!");
     718           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     719             :                 }
     720             : 
     721           0 :                 talloc_free(nc_root);
     722             :         }
     723             : 
     724      320538 :         if (oc_changes) {
     725         476 :                 ret = ldb_build_mod_req(&down_req, ldb, ac,
     726             :                                         msg,
     727             :                                         req->controls, ac,
     728             :                                         oc_modify_callback,
     729             :                                         req);
     730             :         } else {
     731      320062 :                 ret = ldb_build_mod_req(&down_req, ldb, ac,
     732             :                                         msg,
     733             :                                         req->controls, req,
     734             :                                         dsdb_next_callback,
     735             :                                         req);
     736             :         }
     737      320538 :         LDB_REQ_SET_LOCATION(down_req);
     738      320538 :         if (ret != LDB_SUCCESS) {
     739           0 :                 return ret;
     740             :         }
     741             : 
     742      320538 :         return ldb_next_request(module, down_req);
     743             : }
     744             : 
     745         476 : static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
     746             : {
     747           6 :         static const char * const attrs[] = { "objectClass", NULL };
     748           6 :         struct ldb_context *ldb;
     749           6 :         struct ldb_request *search_req;
     750           6 :         struct oc_context *ac;
     751           6 :         int ret;
     752             : 
     753         476 :         ac = talloc_get_type(req->context, struct oc_context);
     754         476 :         ldb = ldb_module_get_ctx(ac->module);
     755             : 
     756         476 :         if (!ares) {
     757           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     758             :                                         LDB_ERR_OPERATIONS_ERROR);
     759             :         }
     760             : 
     761         476 :         if (ares->type == LDB_REPLY_REFERRAL) {
     762           0 :                 return ldb_module_send_referral(ac->req, ares->referral);
     763             :         }
     764             : 
     765         476 :         if (ares->error != LDB_SUCCESS) {
     766         120 :                 return ldb_module_done(ac->req, ares->controls,
     767             :                                         ares->response, ares->error);
     768             :         }
     769             : 
     770         356 :         if (ares->type != LDB_REPLY_DONE) {
     771           0 :                 talloc_free(ares);
     772           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     773             :                                         LDB_ERR_OPERATIONS_ERROR);
     774             :         }
     775             : 
     776         356 :         talloc_free(ares);
     777             : 
     778             :         /* this looks up the real existing object for fetching some important
     779             :          * information (objectclasses) */
     780         362 :         ret = ldb_build_search_req(&search_req, ldb,
     781         356 :                                    ac, ac->req->op.mod.message->dn,
     782             :                                    LDB_SCOPE_BASE,
     783             :                                    "(objectClass=*)",
     784             :                                    attrs, NULL,
     785             :                                    ac, get_search_callback,
     786             :                                    ac->req);
     787         356 :         LDB_REQ_SET_LOCATION(search_req);
     788         356 :         if (ret != LDB_SUCCESS) {
     789           0 :                 return ldb_module_done(ac->req, NULL, NULL, ret);
     790             :         }
     791             : 
     792         356 :         ret = dsdb_request_add_controls(search_req,
     793             :                                         DSDB_FLAG_AS_SYSTEM |
     794             :                                         DSDB_SEARCH_SHOW_RECYCLED);
     795         356 :         if (ret != LDB_SUCCESS) {
     796           0 :                 return ldb_module_done(ac->req, NULL, NULL, ret);
     797             :         }
     798             : 
     799         356 :         ac->step_fn = objectclass_do_mod;
     800             : 
     801         356 :         ret = ldb_next_request(ac->module, search_req);
     802         356 :         if (ret != LDB_SUCCESS) {
     803           0 :                 return ldb_module_done(ac->req, NULL, NULL, ret);
     804             :         }
     805             : 
     806         350 :         return LDB_SUCCESS;
     807             : }
     808             : 
     809         356 : static int objectclass_do_mod(struct oc_context *ac)
     810             : {
     811           6 :         struct ldb_context *ldb;
     812           6 :         struct ldb_request *mod_req;
     813           6 :         struct ldb_message_element *oc_el_entry, *oc_el_change;
     814           6 :         struct ldb_val *vals;
     815           6 :         struct ldb_message *msg;
     816           6 :         const struct dsdb_class *current_structural_objectclass;
     817           6 :         const struct dsdb_class *objectclass;
     818           6 :         unsigned int i, j, k;
     819           6 :         bool found;
     820           6 :         int ret;
     821             : 
     822         356 :         ldb = ldb_module_get_ctx(ac->module);
     823             : 
     824             :         /* we should always have a valid entry when we enter here */
     825         356 :         if (ac->search_res == NULL) {
     826           0 :                 return ldb_operr(ldb);
     827             :         }
     828             : 
     829         356 :         oc_el_entry = ldb_msg_find_element(ac->search_res->message,
     830             :                                            "objectClass");
     831         356 :         if (oc_el_entry == NULL) {
     832             :                 /* existing entry without a valid object class? */
     833           0 :                 return ldb_operr(ldb);
     834             :         }
     835             : 
     836             :         /*
     837             :          * Get the current new top-most structural object class
     838             :          *
     839             :          * We must not allow this to change
     840             :          */
     841             : 
     842           6 :         current_structural_objectclass
     843         356 :                 = dsdb_get_last_structural_class(ac->schema,
     844             :                                                  oc_el_entry);
     845         356 :         if (current_structural_objectclass == NULL) {
     846           0 :                 ldb_asprintf_errstring(ldb,
     847             :                                        "objectclass: cannot find current structural objectclass on %s!",
     848           0 :                                        ldb_dn_get_linearized(ac->search_res->message->dn));
     849           0 :                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
     850             :         }
     851             : 
     852             :         /* use a new message structure */
     853         356 :         msg = ldb_msg_new(ac);
     854         356 :         if (msg == NULL) {
     855           0 :                 return ldb_module_oom(ac->module);
     856             :         }
     857             : 
     858         356 :         msg->dn = ac->req->op.mod.message->dn;
     859             : 
     860             :         /* We've to walk over all "objectClass" message elements */
     861         610 :         for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
     862         499 :                 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
     863             :                                  "objectClass") != 0) {
     864         142 :                         continue;
     865             :                 }
     866             : 
     867         357 :                 oc_el_change = &ac->req->op.mod.message->elements[k];
     868             : 
     869         357 :                 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
     870         107 :                 case LDB_FLAG_MOD_ADD:
     871             :                         /* Merge the two message elements */
     872         177 :                         for (i = 0; i < oc_el_change->num_values; i++) {
     873         497 :                                 for (j = 0; j < oc_el_entry->num_values; j++) {
     874         433 :                                         if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
     875             :                                                          (char *)oc_el_entry->values[j].data) == 0) {
     876          49 :                                                 ldb_asprintf_errstring(ldb,
     877             :                                                                        "objectclass: cannot re-add an existing objectclass: '%.*s'!",
     878          49 :                                                                        (int)oc_el_change->values[i].length,
     879          49 :                                                                        (const char *)oc_el_change->values[i].data);
     880          49 :                                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
     881             :                                         }
     882             :                                 }
     883             :                                 /* append the new object class value - code was
     884             :                                  * copied from "ldb_msg_add_value" */
     885          64 :                                 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
     886             :                                                       struct ldb_val,
     887             :                                                       oc_el_entry->num_values + 1);
     888          64 :                                 if (vals == NULL) {
     889           0 :                                         return ldb_module_oom(ac->module);
     890             :                                 }
     891          64 :                                 oc_el_entry->values = vals;
     892          64 :                                 oc_el_entry->values[oc_el_entry->num_values] =
     893          64 :                                                         oc_el_change->values[i];
     894          64 :                                 ++(oc_el_entry->num_values);
     895             :                         }
     896             : 
     897          58 :                         break;
     898             : 
     899         179 :                 case LDB_FLAG_MOD_REPLACE:
     900             :                         /*
     901             :                          * In this case the new "oc_el_entry" is simply
     902             :                          * "oc_el_change"
     903             :                          */
     904         179 :                         oc_el_entry = oc_el_change;
     905             : 
     906         179 :                         break;
     907             : 
     908          65 :                 case LDB_FLAG_MOD_DELETE:
     909             :                         /* Merge the two message elements */
     910         129 :                         for (i = 0; i < oc_el_change->num_values; i++) {
     911          65 :                                 found = false;
     912         140 :                                 for (j = 0; j < oc_el_entry->num_values; j++) {
     913         139 :                                         if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
     914             :                                                          (char *)oc_el_entry->values[j].data) == 0) {
     915          64 :                                                 found = true;
     916             :                                                 /* delete the object class value
     917             :                                                  * - code was copied from
     918             :                                                  * "ldb_msg_remove_element" */
     919          64 :                                                 if (j != oc_el_entry->num_values - 1) {
     920          58 :                                                         memmove(&oc_el_entry->values[j],
     921          58 :                                                                 &oc_el_entry->values[j+1],
     922          58 :                                                                 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
     923             :                                                 }
     924          64 :                                                 --(oc_el_entry->num_values);
     925          64 :                                                 break;
     926             :                                         }
     927             :                                 }
     928          65 :                                 if (!found) {
     929             :                                         /* we cannot delete a not existing
     930             :                                          * object class */
     931           1 :                                         ldb_asprintf_errstring(ldb,
     932             :                                                                "objectclass: cannot delete this objectclass: '%.*s'!",
     933           1 :                                                                (int)oc_el_change->values[i].length,
     934           1 :                                                                (const char *)oc_el_change->values[i].data);
     935           1 :                                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
     936             :                                 }
     937             :                         }
     938             : 
     939          64 :                         break;
     940             :                 }
     941             : 
     942             :                 /* Now do the sorting */
     943         307 :                 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
     944             :                                                  msg, oc_el_entry);
     945         307 :                 if (ret != LDB_SUCCESS) {
     946           1 :                         return ret;
     947             :                 }
     948             : 
     949             :                 /*
     950             :                  * Get the new top-most structural object class and check for
     951             :                  * unrelated structural classes
     952             :                  */
     953         306 :                 objectclass = dsdb_get_last_structural_class(ac->schema,
     954             :                                                              oc_el_entry);
     955         306 :                 if (objectclass == NULL) {
     956           2 :                         ldb_set_errstring(ldb,
     957             :                                           "objectclass: cannot delete all structural objectclasses!");
     958           2 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
     959             :                 }
     960             : 
     961             :                 /*
     962             :                  * Has (so far, we re-check for each and every
     963             :                  * "objectclass" in the message) the structural
     964             :                  * objectclass changed?
     965             :                  */
     966             : 
     967         304 :                 if (objectclass != current_structural_objectclass) {
     968           0 :                         const char *dn
     969         189 :                                 = ldb_dn_get_linearized(ac->search_res->message->dn);
     970         189 :                         ldb_asprintf_errstring(ldb,
     971             :                                                "objectclass: not permitted "
     972             :                                                "to change the structural "
     973             :                                                "objectClass on %s [%s] => [%s]!",
     974             :                                                dn,
     975         189 :                                                current_structural_objectclass->lDAPDisplayName,
     976         189 :                                                objectclass->lDAPDisplayName);
     977         189 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
     978             :                 }
     979             : 
     980             :                 /* Check for unrelated objectclasses */
     981         115 :                 ret = check_unrelated_objectclasses(ac->module, ac->schema,
     982             :                                                     objectclass,
     983             :                                                     oc_el_entry);
     984         115 :                 if (ret != LDB_SUCCESS) {
     985           3 :                         return ret;
     986             :                 }
     987             :         }
     988             : 
     989             :         /* Now add the new object class attribute to the change message */
     990         111 :         ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
     991         111 :         if (ret != LDB_SUCCESS) {
     992           0 :                 ldb_module_oom(ac->module);
     993           0 :                 return ret;
     994             :         }
     995             : 
     996             :         /* Now we have the real and definitive change left to do */
     997             : 
     998         111 :         ret = ldb_build_mod_req(&mod_req, ldb, ac,
     999             :                                 msg,
    1000         105 :                                 ac->req->controls,
    1001         105 :                                 ac->req, dsdb_next_callback,
    1002             :                                 ac->req);
    1003         111 :         LDB_REQ_SET_LOCATION(mod_req);
    1004         111 :         if (ret != LDB_SUCCESS) {
    1005           0 :                 return ret;
    1006             :         }
    1007             : 
    1008         111 :         return ldb_next_request(ac->module, mod_req);
    1009             : }
    1010             : 
    1011             : static int objectclass_do_rename(struct oc_context *ac);
    1012             : 
    1013        1280 : static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
    1014             : {
    1015           5 :         static const char * const attrs[] = { "objectClass", NULL };
    1016           5 :         struct ldb_context *ldb;
    1017           5 :         struct ldb_request *search_req;
    1018           5 :         struct oc_context *ac;
    1019           5 :         struct ldb_dn *parent_dn;
    1020           5 :         int ret;
    1021             : 
    1022        1280 :         ldb = ldb_module_get_ctx(module);
    1023             : 
    1024        1280 :         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
    1025             : 
    1026             :         /* do not manipulate our control entries */
    1027        1280 :         if (ldb_dn_is_special(req->op.rename.olddn)) {
    1028           0 :                 return ldb_next_request(module, req);
    1029             :         }
    1030             : 
    1031             :         /*
    1032             :          * Bypass the constraint checks when we do have the "DBCHECK" control
    1033             :          * set, so we can force objects under the deleted objects container.
    1034             :          */
    1035        1280 :         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK) != NULL) {
    1036           1 :                 return ldb_next_request(module, req);
    1037             :         }
    1038             : 
    1039        1279 :         ac = oc_init_context(module, req);
    1040        1279 :         if (ac == NULL) {
    1041           0 :                 return ldb_operr(ldb);
    1042             :         }
    1043             : 
    1044        1279 :         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
    1045        1279 :         if (parent_dn == NULL) {
    1046           0 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
    1047             :                                        ldb_dn_get_linearized(req->op.rename.olddn));
    1048           0 :                 return LDB_ERR_NO_SUCH_OBJECT;
    1049             :         }
    1050             : 
    1051             :         /* this looks up the parent object for fetching some important
    1052             :          * information (objectclasses, DN normalisation...) */
    1053        1279 :         ret = ldb_build_search_req(&search_req, ldb,
    1054             :                                    ac, parent_dn, LDB_SCOPE_BASE,
    1055             :                                    "(objectClass=*)",
    1056             :                                    attrs, NULL,
    1057             :                                    ac, get_search_callback,
    1058             :                                    req);
    1059        1279 :         LDB_REQ_SET_LOCATION(search_req);
    1060        1279 :         if (ret != LDB_SUCCESS) {
    1061           0 :                 return ret;
    1062             :         }
    1063             : 
    1064             :         /* we have to add the show recycled control, as otherwise DRS
    1065             :            deletes will be refused as we will think the target parent
    1066             :            does not exist */
    1067        1279 :         ret = dsdb_request_add_controls(search_req,
    1068             :                                         DSDB_FLAG_AS_SYSTEM |
    1069             :                                         DSDB_SEARCH_SHOW_RECYCLED);
    1070        1279 :         if (ret != LDB_SUCCESS) {
    1071           0 :                 return ret;
    1072             :         }
    1073             : 
    1074        1279 :         ac->step_fn = objectclass_do_rename;
    1075             : 
    1076        1279 :         return ldb_next_request(ac->module, search_req);
    1077             : }
    1078             : 
    1079             : static int objectclass_do_rename2(struct oc_context *ac);
    1080             : 
    1081        1279 : static int objectclass_do_rename(struct oc_context *ac)
    1082             : {
    1083           5 :         static const char * const attrs[] = { "objectClass", NULL };
    1084           5 :         struct ldb_context *ldb;
    1085           5 :         struct ldb_request *search_req;
    1086           5 :         int ret;
    1087             : 
    1088        1279 :         ldb = ldb_module_get_ctx(ac->module);
    1089             : 
    1090             :         /* Check if we have a valid parent - this check is needed since
    1091             :          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
    1092        1279 :         if (ac->search_res == NULL) {
    1093           3 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
    1094           3 :                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
    1095           3 :                 return LDB_ERR_OTHER;
    1096             :         }
    1097             : 
    1098             :         /* now assign "search_res2" to the parent entry to have "search_res"
    1099             :          * free for another lookup */
    1100        1276 :         ac->search_res2 = ac->search_res;
    1101        1276 :         ac->search_res = NULL;
    1102             : 
    1103             :         /* this looks up the real existing object for fetching some important
    1104             :          * information (objectclasses) */
    1105        1276 :         ret = ldb_build_search_req(&search_req, ldb,
    1106        1271 :                                    ac, ac->req->op.rename.olddn,
    1107             :                                    LDB_SCOPE_BASE,
    1108             :                                    "(objectClass=*)",
    1109             :                                    attrs, NULL,
    1110             :                                    ac, get_search_callback,
    1111             :                                    ac->req);
    1112        1276 :         LDB_REQ_SET_LOCATION(search_req);
    1113        1276 :         if (ret != LDB_SUCCESS) {
    1114           0 :                 return ret;
    1115             :         }
    1116             : 
    1117        1276 :         ret = dsdb_request_add_controls(search_req,
    1118             :                                         DSDB_FLAG_AS_SYSTEM |
    1119             :                                         DSDB_SEARCH_SHOW_RECYCLED);
    1120        1276 :         if (ret != LDB_SUCCESS) {
    1121           0 :                 return ret;
    1122             :         }
    1123             : 
    1124        1276 :         ac->step_fn = objectclass_do_rename2;
    1125             : 
    1126        1276 :         return ldb_next_request(ac->module, search_req);
    1127             : }
    1128             : 
    1129        1275 : static int objectclass_do_rename2(struct oc_context *ac)
    1130             : {
    1131           5 :         struct ldb_context *ldb;
    1132           5 :         struct ldb_request *rename_req;
    1133           5 :         struct ldb_dn *fixed_dn;
    1134           5 :         int ret;
    1135             : 
    1136        1275 :         ldb = ldb_module_get_ctx(ac->module);
    1137             : 
    1138             :         /* Check if we have a valid entry - this check is needed since
    1139             :          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
    1140        1275 :         if (ac->search_res == NULL) {
    1141           2 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
    1142           2 :                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
    1143           2 :                 return LDB_ERR_NO_SUCH_OBJECT;
    1144             :         }
    1145             : 
    1146        1273 :         if (ac->schema != NULL) {
    1147           5 :                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
    1148           5 :                 const struct dsdb_class *objectclass;
    1149           5 :                 const char *rdn_name;
    1150        1273 :                 bool allowed_class = false;
    1151           5 :                 unsigned int i, j;
    1152           5 :                 bool found;
    1153             : 
    1154        1273 :                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
    1155             :                                                    "objectClass");
    1156        1273 :                 if (oc_el_entry == NULL) {
    1157             :                         /* existing entry without a valid object class? */
    1158           0 :                         return ldb_operr(ldb);
    1159             :                 }
    1160        1273 :                 objectclass = dsdb_get_last_structural_class(ac->schema,
    1161             :                                                              oc_el_entry);
    1162        1273 :                 if (objectclass == NULL) {
    1163             :                         /* existing entry without a valid object class? */
    1164           0 :                         return ldb_operr(ldb);
    1165             :                 }
    1166             : 
    1167        1273 :                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
    1168        1273 :                 if (rdn_name == NULL) {
    1169           0 :                         return ldb_operr(ldb);
    1170             :                 }
    1171        1268 :                 found = false;
    1172        2656 :                 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
    1173           5 :                         const struct dsdb_class *tmp_class =
    1174        1388 :                                 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
    1175        1383 :                                                                       &oc_el_entry->values[i]);
    1176             : 
    1177        1383 :                         if (tmp_class == NULL) continue;
    1178             : 
    1179        1383 :                         if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
    1180        1271 :                                 found = true;
    1181             :                 }
    1182        1273 :                 if (!found) {
    1183           2 :                         ldb_asprintf_errstring(ldb,
    1184             :                                                "objectclass: Invalid RDN '%s' for objectclass '%s'!",
    1185           2 :                                                rdn_name, objectclass->lDAPDisplayName);
    1186           2 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1187             :                 }
    1188             : 
    1189        1271 :                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
    1190             :                                                     "objectClass");
    1191        1271 :                 if (oc_el_parent == NULL) {
    1192             :                         /* existing entry without a valid object class? */
    1193           0 :                         return ldb_operr(ldb);
    1194             :                 }
    1195             : 
    1196        3858 :                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
    1197          10 :                         const struct dsdb_class *sclass;
    1198             : 
    1199        2597 :                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
    1200        2587 :                                                                        &oc_el_parent->values[i]);
    1201        2587 :                         if (!sclass) {
    1202             :                                 /* We don't know this class?  what is going on? */
    1203           0 :                                 continue;
    1204             :                         }
    1205      130416 :                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
    1206      129098 :                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
    1207        1264 :                                         allowed_class = true;
    1208        1264 :                                         break;
    1209             :                                 }
    1210             :                         }
    1211             :                 }
    1212             : 
    1213        1271 :                 if (!allowed_class) {
    1214           4 :                         ldb_asprintf_errstring(ldb,
    1215             :                                                "objectclass: structural objectClass %s is not a valid child class for %s",
    1216           2 :                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
    1217           2 :                         return LDB_ERR_NAMING_VIOLATION;
    1218             :                 }
    1219             :         }
    1220             : 
    1221             :         /* Ensure we are not trying to rename it to be a child of itself */
    1222        1269 :         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
    1223        1277 :                                  ac->req->op.rename.newdn) == 0)  &&
    1224           8 :             (ldb_dn_compare(ac->req->op.rename.olddn,
    1225           8 :                             ac->req->op.rename.newdn) != 0)) {
    1226           2 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
    1227           2 :                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
    1228           2 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1229             :         }
    1230             : 
    1231             :         /* Fix up the DN to be in the standard form, taking
    1232             :          * particular care to match the parent DN */
    1233        1272 :         ret = fix_dn(ldb, ac,
    1234        1267 :                      ac->req->op.rename.newdn,
    1235        1267 :                      ac->search_res2->message->dn,
    1236             :                      &fixed_dn);
    1237        1267 :         if (ret != LDB_SUCCESS) {
    1238           0 :                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
    1239           0 :                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
    1240           0 :                 return ret;
    1241             : 
    1242             :         }
    1243             : 
    1244        1267 :         ret = ldb_build_rename_req(&rename_req, ldb, ac,
    1245        1262 :                                    ac->req->op.rename.olddn, fixed_dn,
    1246        1262 :                                    ac->req->controls,
    1247        1262 :                                    ac->req, dsdb_next_callback,
    1248             :                                    ac->req);
    1249        1267 :         LDB_REQ_SET_LOCATION(rename_req);
    1250        1267 :         if (ret != LDB_SUCCESS) {
    1251           0 :                 return ret;
    1252             :         }
    1253             : 
    1254             :         /* perform the rename */
    1255        1267 :         return ldb_next_request(ac->module, rename_req);
    1256             : }
    1257             : 
    1258             : static int objectclass_do_delete(struct oc_context *ac);
    1259             : 
    1260      110598 : static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
    1261             : {
    1262         160 :         static const char * const attrs[] = { "nCName", "objectClass",
    1263             :                                               "systemFlags",
    1264             :                                               "isDeleted",
    1265             :                                               "isCriticalSystemObject", NULL };
    1266         160 :         struct ldb_context *ldb;
    1267         160 :         struct ldb_request *search_req;
    1268         160 :         struct oc_context *ac;
    1269         160 :         int ret;
    1270             : 
    1271      110598 :         ldb = ldb_module_get_ctx(module);
    1272             : 
    1273      110598 :         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
    1274             : 
    1275             :         /* do not manipulate our control entries */
    1276      110598 :         if (ldb_dn_is_special(req->op.del.dn)) {
    1277           1 :                 return ldb_next_request(module, req);
    1278             :         }
    1279             : 
    1280             :         /* Bypass the constraint checks when we do have the "RELAX" control
    1281             :          * set. */
    1282      110597 :         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
    1283          25 :                 return ldb_next_request(module, req);
    1284             :         }
    1285             : 
    1286      110572 :         ac = oc_init_context(module, req);
    1287      110572 :         if (ac == NULL) {
    1288           0 :                 return ldb_operr(ldb);
    1289             :         }
    1290             : 
    1291             :         /* this looks up the entry object for fetching some important
    1292             :          * information (object classes, system flags...) */
    1293      110572 :         ret = ldb_build_search_req(&search_req, ldb,
    1294             :                                    ac, req->op.del.dn, LDB_SCOPE_BASE,
    1295             :                                    "(objectClass=*)",
    1296             :                                    attrs, NULL,
    1297             :                                    ac, get_search_callback,
    1298             :                                    req);
    1299      110572 :         LDB_REQ_SET_LOCATION(search_req);
    1300      110572 :         if (ret != LDB_SUCCESS) {
    1301           0 :                 return ret;
    1302             :         }
    1303             : 
    1304      110572 :         ret = dsdb_request_add_controls(search_req,
    1305             :                                         DSDB_FLAG_AS_SYSTEM |
    1306             :                                         DSDB_SEARCH_SHOW_RECYCLED);
    1307      110572 :         if (ret != LDB_SUCCESS) {
    1308           0 :                 return ret;
    1309             :         }
    1310             : 
    1311      110572 :         ac->step_fn = objectclass_do_delete;
    1312             : 
    1313      110572 :         return ldb_next_request(ac->module, search_req);
    1314             : }
    1315             : 
    1316      110571 : static int objectclass_do_delete(struct oc_context *ac)
    1317             : {
    1318         151 :         struct ldb_context *ldb;
    1319         151 :         struct ldb_dn *dn;
    1320         151 :         int32_t systemFlags;
    1321         151 :         bool isCriticalSystemObject;
    1322         151 :         int ret;
    1323             : 
    1324      110571 :         ldb = ldb_module_get_ctx(ac->module);
    1325             : 
    1326             :         /* Check if we have a valid entry - this check is needed since
    1327             :          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
    1328      110571 :         if (ac->search_res == NULL) {
    1329       37771 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
    1330       37759 :                                        ldb_dn_get_linearized(ac->req->op.del.dn));
    1331       37759 :                 return LDB_ERR_NO_SUCH_OBJECT;
    1332             :         }
    1333             : 
    1334             :         /* DC's ntDSDSA object */
    1335       72812 :         if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
    1336           2 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
    1337           2 :                                        ldb_dn_get_linearized(ac->req->op.del.dn));
    1338           2 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1339             :         }
    1340             : 
    1341             :         /* DC's rIDSet object */
    1342             :         /* Perform this check only when it does exist - this is needed in order
    1343             :          * to don't let existing provisions break, and to delete . */
    1344       72810 :         ret = samdb_rid_set_dn(ldb, ac, &dn);
    1345       72810 :         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_ATTRIBUTE)
    1346           0 :             && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
    1347           0 :                 ldb_asprintf_errstring(ldb, "objectclass: Unable to determine if %s, is this DC's rIDSet object: %s ",
    1348           0 :                                        ldb_dn_get_linearized(ac->req->op.del.dn),
    1349             :                                        ldb_errstring(ldb));
    1350           0 :                 return ret;
    1351             :         }
    1352       72810 :         if (ret == LDB_SUCCESS) {
    1353       72809 :                 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
    1354           4 :                         talloc_free(dn);
    1355           4 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
    1356           4 :                                                ldb_dn_get_linearized(ac->req->op.del.dn));
    1357           4 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1358             :                 }
    1359       72805 :                 talloc_free(dn);
    1360             :         }
    1361             : 
    1362             :         /* Only trusted request from system account are allowed to delete
    1363             :          * deleted objects.
    1364             :          */
    1365       72806 :         if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
    1366           0 :                         (ldb_req_is_untrusted(ac->req) ||
    1367           0 :                                 !dsdb_module_am_system(ac->module))) {
    1368           0 :                 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
    1369           0 :                                                 ldb_dn_get_linearized(ac->req->op.del.dn));
    1370           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1371             :         }
    1372             : 
    1373             :         /* crossRef objects regarding config, schema and default domain NCs */
    1374       72806 :         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
    1375             :                                  "crossRef") != NULL) {
    1376          12 :                 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
    1377             :                                              "nCName");
    1378          20 :                 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
    1379           8 :                     (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
    1380           8 :                         talloc_free(dn);
    1381             : 
    1382           8 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
    1383           8 :                                                ldb_dn_get_linearized(ac->req->op.del.dn));
    1384           8 :                         return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
    1385             :                 }
    1386           4 :                 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
    1387           4 :                         talloc_free(dn);
    1388             : 
    1389           4 :                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
    1390           4 :                                                ldb_dn_get_linearized(ac->req->op.del.dn));
    1391           4 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1392             :                 }
    1393           0 :                 talloc_free(dn);
    1394             :         }
    1395             : 
    1396             :         /* systemFlags */
    1397             : 
    1398       72794 :         systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
    1399             :                                                "systemFlags", 0);
    1400       72794 :         if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
    1401           5 :                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
    1402           5 :                                        ldb_dn_get_linearized(ac->req->op.del.dn));
    1403           5 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1404             :         }
    1405             : 
    1406             :         /* isCriticalSystemObject - but this only applies on tree delete
    1407             :          * operations - MS-ADTS 3.1.1.5.5.7.2 */
    1408       72789 :         if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
    1409       32320 :                 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
    1410             :                                                                    "isCriticalSystemObject", false);
    1411       32320 :                 if (isCriticalSystemObject) {
    1412             :                         /*
    1413             :                          * Following the explanation from Microsoft
    1414             :                          * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
    1415             :                          * "I finished the investigation on this behavior.
    1416             :                          * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
    1417             :                          * every object in the tree will be checked to see if it has isCriticalSystemObject
    1418             :                          * set to TRUE, including the root node on which the delete operation is performed
    1419             :                          * But there is an exception  if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
    1420             :                          * Its deletion is done through SAM manager and isCriticalSystemObject attribute is not checked
    1421             :                          * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
    1422             :                          * which is a SAM object  with  user class.  Therefore the tree deletion is performed without any error
    1423             :                          */
    1424             : 
    1425         638 :                         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
    1426         638 :                             samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
    1427         638 :                             samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
    1428         319 :                             samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
    1429           0 :                                         ldb_asprintf_errstring(ldb,
    1430             :                                                "objectclass: Cannot tree-delete %s, it's a critical system object!",
    1431           0 :                                                ldb_dn_get_linearized(ac->req->op.del.dn));
    1432           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1433             :                         }
    1434             :                 }
    1435             :         }
    1436             : 
    1437       72789 :         return ldb_next_request(ac->module, ac->req);
    1438             : }
    1439             : 
    1440      182004 : static int objectclass_init(struct ldb_module *module)
    1441             : {
    1442      182004 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1443        6016 :         int ret;
    1444             : 
    1445             :         /* Init everything else */
    1446      182004 :         ret = ldb_next_init(module);
    1447      182004 :         if (ret != LDB_SUCCESS) {
    1448           0 :                 return ret;
    1449             :         }
    1450             : 
    1451             :         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
    1452      182004 :         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
    1453             : 
    1454      182004 :         ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
    1455      182004 :         if (ret != LDB_SUCCESS) {
    1456           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
    1457             :                           "objectclass_init: Unable to register control DCPROMO with rootdse\n");
    1458           0 :                 return ldb_operr(ldb);
    1459             :         }
    1460             : 
    1461      175988 :         return ret;
    1462             : }
    1463             : 
    1464             : static const struct ldb_module_ops ldb_objectclass_module_ops = {
    1465             :         .name           = "objectclass",
    1466             :         .add            = objectclass_add,
    1467             :         .modify         = objectclass_modify,
    1468             :         .rename         = objectclass_rename,
    1469             :         .del            = objectclass_delete,
    1470             :         .init_context   = objectclass_init
    1471             : };
    1472             : 
    1473        6040 : int ldb_objectclass_module_init(const char *version)
    1474             : {
    1475        6040 :         LDB_MODULE_CHECK_VERSION(version);
    1476        6040 :         return ldb_register_module(&ldb_objectclass_module_ops);
    1477             : }

Generated by: LCOV version 1.14