summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/objectclass_attrs.c43
-rw-r--r--source4/dsdb/samdb/ldb_modules/samldb.c81
-rwxr-xr-xsource4/dsdb/tests/python/ldap.py163
-rwxr-xr-xsource4/dsdb/tests/python/sam.py156
4 files changed, 245 insertions, 198 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
index 26eaaeaae5..67d11b302d 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
@@ -158,49 +158,6 @@ static int attr_handler(struct oc_context *ac)
}
}
- /* "description" on AD is very special: it's nearly single-
- * valued (only on add operations it isn't). */
- if ((ac->req->operation == LDB_MODIFY) &&
- (ldb_attr_cmp(attr->lDAPDisplayName, "description") == 0)) {
- /* Multi-valued add or replace operations are always
- * denied */
- if ((LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
- != LDB_FLAG_MOD_DELETE) &&
- (msg->elements[i].num_values > 1)) {
- ldb_asprintf_errstring(ldb,
- "objectclass_attrs: attribute '%s' on entry '%s' is changed using a multi-valued add or replace operation!",
- msg->elements[i].name,
- ldb_dn_get_linearized(msg->dn));
- return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- }
-
- /* Add operations are only allowed if no value exists */
- if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
- == LDB_FLAG_MOD_ADD) {
- const char *attrs[] = { attr->lDAPDisplayName,
- NULL };
- struct ldb_result *res;
- struct ldb_message_element *el;
-
- ret = ldb_search(ldb, ac, &res, msg->dn,
- LDB_SCOPE_BASE, attrs, NULL);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- el = ldb_msg_find_element(res->msgs[0],
- attr->lDAPDisplayName);
- if (el != NULL) {
- ldb_asprintf_errstring(ldb,
- "objectclass_attrs: attribute '%s' on entry '%s' is changed using an add operation, but there a value already exists!",
- msg->elements[i].name,
- ldb_dn_get_linearized(msg->dn));
- return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- }
- talloc_free(res);
- }
- }
-
/* "dSHeuristics" syntax check */
if (ldb_attr_cmp(attr->lDAPDisplayName, "dSHeuristics") == 0) {
ret = oc_validate_dsheuristics(&(msg->elements[i]));
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index 0cd8bc9bcc..4b8a303753 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -1496,6 +1496,79 @@ static int samldb_member_check(struct samldb_ctx *ac)
}
}
+ talloc_free(res);
+
+ return LDB_SUCCESS;
+}
+
+/* SAM objects have special rules regarding the "description" attribute on
+ * modify operations. */
+static int samldb_description_check(struct samldb_ctx *ac)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ const char * const attrs[] = { "objectClass", "description", NULL };
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ unsigned int i;
+ int ret;
+
+ /* Fetch informations from the existing object */
+
+ ret = ldb_search(ldb, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (res->count != 1) {
+ return ldb_operr(ldb);
+ }
+
+ /* if it's not a SAM object then please skip the constraints */
+ if ((samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+ "group") == NULL) &&
+ (samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+ "samDomain") == NULL) &&
+ (samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+ "samServer") == NULL) &&
+ (samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+ "user") == NULL)) {
+ talloc_free(res);
+ return LDB_SUCCESS;
+ }
+
+ /* We've to walk over all modification entries and consider the
+ * "description" ones. */
+ for (i = 0; i < ac->msg->num_elements; i++) {
+ if (ldb_attr_cmp(ac->msg->elements[i].name,
+ "description") != 0) {
+ continue;
+ }
+
+ el = &ac->msg->elements[i];
+
+ /* Multi-valued add or replace operations are always denied */
+ if ((LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_DELETE) &&
+ (el->num_values > 1)) {
+ ldb_asprintf_errstring(ldb,
+ "samldb: Description on SAM entry '%s' is changed using a multi-valued add or replace operation!",
+ ldb_dn_get_linearized(ac->msg->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+
+ /* Add operations are only allowed if no value exists */
+ if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
+ if (ldb_msg_find_element(res->msgs[0], "description")
+ != NULL) {
+ ldb_asprintf_errstring(ldb,
+ "samldb: Description on SAM entry '%s' is changed using an add operation while a value already exists!",
+ ldb_dn_get_linearized(ac->msg->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ }
+ }
+
+ talloc_free(res);
+
return LDB_SUCCESS;
}
@@ -1894,6 +1967,14 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
}
}
+ el = ldb_msg_find_element(ac->msg, "description");
+ if (el != NULL) {
+ ret = samldb_description_check(ac);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
el = ldb_msg_find_element(ac->msg, "dNSHostName");
el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
if ((el != NULL) || (el2 != NULL)) {
diff --git a/source4/dsdb/tests/python/ldap.py b/source4/dsdb/tests/python/ldap.py
index 833e141b7d..26a0d720c5 100755
--- a/source4/dsdb/tests/python/ldap.py
+++ b/source4/dsdb/tests/python/ldap.py
@@ -618,160 +618,6 @@ class BasicTests(unittest.TestCase):
self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- def test_description_attribute(self):
- """Test description attribute"""
- print "Test description attribute"""
-
- self.ldb.add({
- "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
- "description": "desc2",
- "objectclass": "group",
- "description": "desc1"})
-
- res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
- scope=SCOPE_BASE, attrs=["description"])
- self.assertTrue(len(res) == 1)
- self.assertTrue("description" in res[0])
- self.assertTrue(len(res[0]["description"]) == 1)
- self.assertEquals(res[0]["description"][0], "desc1")
-
- self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-
- self.ldb.add({
- "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
- "objectclass": "group",
- "description": ["desc1", "desc2"]})
-
- res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
- scope=SCOPE_BASE, attrs=["description"])
- self.assertTrue(len(res) == 1)
- self.assertTrue("description" in res[0])
- self.assertTrue(len(res[0]["description"]) == 2)
- self.assertTrue(res[0]["description"][0] == "desc1" or
- res[0]["description"][1] == "desc1")
- self.assertTrue(res[0]["description"][0] == "desc2" or
- res[0]["description"][1] == "desc2")
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
- "description")
- try:
- ldb.modify(m)
- self.fail()
- except LdbError, (num, _):
- self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
- "description")
- ldb.modify(m)
-
- self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-
- self.ldb.add({
- "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
- "objectclass": "group" })
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
- "description")
- ldb.modify(m)
-
- res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
- scope=SCOPE_BASE, attrs=["description"])
- self.assertTrue(len(res) == 1)
- self.assertTrue("description" in res[0])
- self.assertTrue(len(res[0]["description"]) == 1)
- self.assertEquals(res[0]["description"][0], "desc1")
-
- self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-
- self.ldb.add({
- "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
- "objectclass": "group",
- "description": ["desc1", "desc2"]})
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
- "description")
- ldb.modify(m)
-
- res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
- scope=SCOPE_BASE, attrs=["description"])
- self.assertTrue(len(res) == 1)
- self.assertTrue("description" in res[0])
- self.assertTrue(len(res[0]["description"]) == 1)
- self.assertEquals(res[0]["description"][0], "desc1")
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
- "description")
- try:
- ldb.modify(m)
- self.fail()
- except LdbError, (num, _):
- self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
- "description")
- try:
- ldb.modify(m)
- self.fail()
- except LdbError, (num, _):
- self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
- "description")
- ldb.modify(m)
- res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
- scope=SCOPE_BASE, attrs=["description"])
- self.assertTrue(len(res) == 1)
- self.assertFalse("description" in res[0])
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
- "description")
- try:
- ldb.modify(m)
- self.fail()
- except LdbError, (num, _):
- self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
- "description")
- try:
- ldb.modify(m)
- self.fail()
- except LdbError, (num, _):
- self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
- "description")
- ldb.modify(m)
-
- res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
- scope=SCOPE_BASE, attrs=["description"])
- self.assertTrue(len(res) == 1)
- self.assertTrue("description" in res[0])
- self.assertTrue(len(res[0]["description"]) == 1)
- self.assertEquals(res[0]["description"][0], "desc1")
-
- self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-
def test_attribute_ranges(self):
"""Test attribute ranges"""
print "Test attribute ranges"""
@@ -1943,6 +1789,15 @@ servicePrincipalName: host/ldaptest2computer29
"objectClass": "user",
"cn": "LDAPtestUSER4"})
+ # Here we don't enforce these hard "description" constraints
+ ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+replace: description
+description: desc1
+description: desc2
+""")
+
ldb.modify_ldif("""
dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
changetype: modify
diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py
index 245d051659..b64cce1c3f 100755
--- a/source4/dsdb/tests/python/sam.py
+++ b/source4/dsdb/tests/python/sam.py
@@ -17,7 +17,7 @@ from samba.auth import system_session
from ldb import SCOPE_BASE, LdbError
from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
-from ldb import ERR_OTHER
+from ldb import ERR_OTHER, ERR_NO_SUCH_ATTRIBUTE
from ldb import ERR_OBJECT_CLASS_VIOLATION
from ldb import ERR_CONSTRAINT_VIOLATION
from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
@@ -2251,6 +2251,160 @@ class SamTests(unittest.TestCase):
self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_sam_description_attribute(self):
+ """Test SAM description attribute"""
+ print "Test SAM description attribute"""
+
+ self.ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "description": "desc2",
+ "objectclass": "group",
+ "description": "desc1"})
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ self.ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group",
+ "description": ["desc1", "desc2"]})
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 2)
+ self.assertTrue(res[0]["description"][0] == "desc1" or
+ res[0]["description"][1] == "desc1")
+ self.assertTrue(res[0]["description"][0] == "desc2" or
+ res[0]["description"][1] == "desc2")
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
+ "description")
+ ldb.modify(m)
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ self.ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group" })
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
+ "description")
+ ldb.modify(m)
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ self.ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group",
+ "description": ["desc1", "desc2"]})
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
+ "description")
+ ldb.modify(m)
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
+ "description")
+ ldb.modify(m)
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertFalse("description" in res[0])
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
+ "description")
+ ldb.modify(m)
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
if not "://" in host:
if os.path.isfile(host):