CVE-2020-25722 Ensure the structural objectclass cannot be changed
[samba.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
index 17cb34f4befb7e1fc8514b629bb93313a1a0e604..5b97c9dec024ad1b6a509f8bb56e3675f03d4a0e 100644 (file)
@@ -813,6 +813,7 @@ static int objectclass_do_mod(struct oc_context *ac)
        struct ldb_message_element *oc_el_entry, *oc_el_change;
        struct ldb_val *vals;
        struct ldb_message *msg;
+       const struct dsdb_class *current_structural_objectclass;
        const struct dsdb_class *objectclass;
        unsigned int i, j, k;
        bool found;
@@ -832,6 +833,22 @@ static int objectclass_do_mod(struct oc_context *ac)
                return ldb_operr(ldb);
        }
 
+       /*
+        * Get the current new top-most structural object class
+        *
+        * We must not allow this to change
+        */
+
+       current_structural_objectclass
+               = dsdb_get_last_structural_class(ac->schema,
+                                                oc_el_entry);
+       if (current_structural_objectclass == NULL) {
+               ldb_asprintf_errstring(ldb,
+                                      "objectclass: cannot find current structural objectclass on %s!",
+                                      ldb_dn_get_linearized(ac->search_res->message->dn));
+               return LDB_ERR_OBJECT_CLASS_VIOLATION;
+       }
+
        /* use a new message structure */
        msg = ldb_msg_new(ac);
        if (msg == NULL) {
@@ -941,6 +958,25 @@ static int objectclass_do_mod(struct oc_context *ac)
                        return LDB_ERR_OBJECT_CLASS_VIOLATION;
                }
 
+               /*
+                * Has (so far, we re-check for each and every
+                * "objectclass" in the message) the structural
+                * objectclass changed?
+                */
+
+               if (objectclass != current_structural_objectclass) {
+                       const char *dn
+                               = ldb_dn_get_linearized(ac->search_res->message->dn);
+                       ldb_asprintf_errstring(ldb,
+                                              "objectclass: not permitted "
+                                              "to change the structural "
+                                              "objectClass on %s [%s] => [%s]!",
+                                              dn,
+                                              current_structural_objectclass->lDAPDisplayName,
+                                              objectclass->lDAPDisplayName);
+                       return LDB_ERR_OBJECT_CLASS_VIOLATION;
+               }
+
                /* Check for unrelated objectclasses */
                ret = check_unrelated_objectclasses(ac->module, ac->schema,
                                                    objectclass,