mirror of
https://github.com/samba-team/samba.git
synced 2025-02-05 21:57:51 +03:00
s4:objectclass LDB module - multiple "objectClass" change elements are unfortunately still allowed
The test message has been compressed - therefore I've now used "modify_ldif".
This commit is contained in:
parent
b9cfe10945
commit
113a9c1806
@ -921,7 +921,7 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
TALLOC_CTX *mem_ctx;
|
||||
struct class_list *sorted, *current;
|
||||
const struct dsdb_class *objectclass;
|
||||
unsigned int i, j;
|
||||
unsigned int i, j, k;
|
||||
bool found, replace = false;
|
||||
int ret;
|
||||
|
||||
@ -939,13 +939,6 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
return ldb_operr(ldb);
|
||||
}
|
||||
|
||||
oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
|
||||
"objectClass");
|
||||
if (oc_el_change == NULL) {
|
||||
/* we should have an objectclass change operation */
|
||||
return ldb_operr(ldb);
|
||||
}
|
||||
|
||||
/* use a new message structure */
|
||||
msg = ldb_msg_new(ac);
|
||||
if (msg == NULL) {
|
||||
@ -959,20 +952,32 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
return ldb_oom(ldb);
|
||||
}
|
||||
|
||||
/* We've to walk over all "objectClass" message elements */
|
||||
for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
|
||||
if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
|
||||
"objectClass") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
oc_el_change = &ac->req->op.mod.message->elements[k];
|
||||
|
||||
switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
|
||||
case LDB_FLAG_MOD_ADD:
|
||||
/* Merge the two message elements */
|
||||
for (i = 0; i < oc_el_change->num_values; i++) {
|
||||
for (j = 0; j < oc_el_entry->num_values; j++) {
|
||||
if (strcasecmp((char *)oc_el_change->values[i].data,
|
||||
if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
|
||||
(char *)oc_el_entry->values[j].data) == 0) {
|
||||
/* we cannot add an already existing object class */
|
||||
ldb_asprintf_errstring(ldb,
|
||||
"objectclass: cannot re-add an existing objectclass: '%.*s'!",
|
||||
(int)oc_el_change->values[i].length,
|
||||
(const char *)oc_el_change->values[i].data);
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
|
||||
}
|
||||
}
|
||||
/* append the new object class value - code was copied
|
||||
* from "ldb_msg_add_value" */
|
||||
/* append the new object class value - code was
|
||||
* copied from "ldb_msg_add_value" */
|
||||
vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
|
||||
struct ldb_val,
|
||||
oc_el_entry->num_values + 1);
|
||||
@ -989,7 +994,9 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
objectclass = get_last_structural_class(ac->schema,
|
||||
oc_el_change);
|
||||
if (objectclass != NULL) {
|
||||
/* we cannot add a new structural object class */
|
||||
ldb_asprintf_errstring(ldb,
|
||||
"objectclass: cannot add a new top-most structural objectclass '%s'!",
|
||||
objectclass->lDAPDisplayName);
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_OBJECT_CLASS_VIOLATION;
|
||||
}
|
||||
@ -1031,11 +1038,11 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
for (i = 0; i < oc_el_change->num_values; i++) {
|
||||
found = false;
|
||||
for (j = 0; j < oc_el_entry->num_values; j++) {
|
||||
if (strcasecmp((char *)oc_el_change->values[i].data,
|
||||
if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
|
||||
(char *)oc_el_entry->values[j].data) == 0) {
|
||||
found = true;
|
||||
/* delete the object class value -
|
||||
* code was copied from
|
||||
/* delete the object class value
|
||||
* - code was copied from
|
||||
* "ldb_msg_remove_element" */
|
||||
if (j != oc_el_entry->num_values - 1) {
|
||||
memmove(&oc_el_entry->values[j],
|
||||
@ -1047,30 +1054,35 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
/* we cannot delete a not existing object class */
|
||||
ldb_asprintf_errstring(ldb, "Cannot delete this %.*s ",
|
||||
(int)oc_el_change->values[i].length, (const char *)oc_el_change->values[i].data);
|
||||
|
||||
/* we cannot delete a not existing
|
||||
* object class */
|
||||
ldb_asprintf_errstring(ldb,
|
||||
"objectclass: cannot delete this objectclass: '%.*s'!",
|
||||
(int)oc_el_change->values[i].length,
|
||||
(const char *)oc_el_change->values[i].data);
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_NO_SUCH_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that the top-most structural objectclass wasn't
|
||||
* deleted */
|
||||
/* Make sure that the top-most structural object class
|
||||
* hasn't been deleted */
|
||||
found = false;
|
||||
for (i = 0; i < oc_el_entry->num_values; i++) {
|
||||
if (strcasecmp(objectclass->lDAPDisplayName,
|
||||
if (ldb_attr_cmp(objectclass->lDAPDisplayName,
|
||||
(char *)oc_el_entry->values[i].data) == 0) {
|
||||
found = true; break;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ldb_asprintf_errstring(ldb,
|
||||
"objectclass: cannot delete the top-most structural objectclass '%s'!",
|
||||
objectclass->lDAPDisplayName);
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_OBJECT_CLASS_VIOLATION;
|
||||
}
|
||||
|
||||
|
||||
/* Now do the sorting */
|
||||
ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
|
||||
oc_el_entry, &sorted);
|
||||
@ -1082,21 +1094,9 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only one "objectclass" attribute change element per modify request
|
||||
* allowed! */
|
||||
for (i = 0; i < ac->req->op.mod.message->num_elements; i++) {
|
||||
if (ldb_attr_cmp(ac->req->op.mod.message->elements[i].name,
|
||||
"objectClass") != 0) continue;
|
||||
|
||||
if (ldb_msg_element_compare(&ac->req->op.mod.message->elements[i],
|
||||
oc_el_change) != 0) {
|
||||
ldb_set_errstring(ldb,
|
||||
"objectclass: only one 'objectClass' attribute change per modify request allowed!");
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
|
||||
}
|
||||
}
|
||||
|
||||
/* (Re)-add an empty "objectClass" attribute on the object
|
||||
* classes change message "msg". */
|
||||
ldb_msg_remove_attr(msg, "objectClass");
|
||||
ret = ldb_msg_add_empty(msg, "objectClass",
|
||||
LDB_FLAG_MOD_REPLACE, &oc_el_change);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
@ -1114,41 +1114,49 @@ static int objectclass_do_mod(struct oc_context *ac)
|
||||
}
|
||||
ret = ldb_msg_add_string(msg, "objectClass", value);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
|
||||
ldb_set_errstring(ldb,
|
||||
"objectclass: could not re-add sorted objectclasses!");
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
if (replace) {
|
||||
/* Well, on replace we are nearly done: we have to test if
|
||||
* the change and entry message element are identically. We
|
||||
* can use "ldb_msg_element_compare" since now the specified
|
||||
* objectclasses match for sure in case. */
|
||||
ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
|
||||
/* Well, on replace we are nearly done: we have to test
|
||||
* if the change and entry message element are identical
|
||||
* ly. We can use "ldb_msg_element_compare" since now
|
||||
* the specified objectclasses match for sure in case.
|
||||
*/
|
||||
ret = ldb_msg_element_compare(oc_el_entry,
|
||||
oc_el_change);
|
||||
if (ret == 0) {
|
||||
ret = ldb_msg_element_compare(oc_el_change,
|
||||
oc_el_entry);
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* they are the same so we are done in this case */
|
||||
/* they are the same so we are done in this
|
||||
* case */
|
||||
talloc_free(mem_ctx);
|
||||
return ldb_module_done(ac->req, NULL, NULL,
|
||||
LDB_SUCCESS);
|
||||
} else {
|
||||
/* they're not exactly the same */
|
||||
ldb_set_errstring(ldb,
|
||||
"objectclass: the specified objectclasses are not exactly the same as on the entry!");
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_OBJECT_CLASS_VIOLATION;
|
||||
}
|
||||
}
|
||||
|
||||
/* in the other cases we have the real change left to do */
|
||||
|
||||
ret = ldb_msg_sanity_check(ldb, msg);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
/* Now we've applied all changes from "oc_el_change" to
|
||||
* "oc_el_entry" therefore the new "oc_el_entry" will be
|
||||
* "oc_el_change". */
|
||||
oc_el_entry = oc_el_change;
|
||||
}
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
/* Now we have the real and definitive change left to do */
|
||||
|
||||
ret = ldb_build_mod_req(&mod_req, ldb, ac,
|
||||
msg,
|
||||
ac->req->controls,
|
||||
|
@ -310,18 +310,15 @@ class BasicTests(unittest.TestCase):
|
||||
except LdbError, (num, _):
|
||||
self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
|
||||
|
||||
# More than one change operation is not allowed
|
||||
m = Message()
|
||||
m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
|
||||
m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
|
||||
"objectClass")
|
||||
m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_ADD,
|
||||
"objectClass")
|
||||
try:
|
||||
ldb.modify(m)
|
||||
self.fail()
|
||||
except LdbError, (num, _):
|
||||
self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
|
||||
# More than one change operation is allowed
|
||||
ldb.modify_ldif("""
|
||||
dn: cn=ldaptestuser,cn=users, """ + self.base_dn + """
|
||||
changetype: modify
|
||||
delete: objectClass
|
||||
objectClass: bootableDevice
|
||||
add: objectClass
|
||||
objectClass: bootableDevice
|
||||
""")
|
||||
|
||||
# We cannot remove all object classes by an empty replace
|
||||
m = Message()
|
||||
|
Loading…
x
Reference in New Issue
Block a user