The branch, master has been updated via be938ab44b6095818501b23ca8422c731e14015a (commit) via 4bc9a39eed3e47cd87ea8cd24f9ac4f9e2712f43 (commit) via 0e028fcb7d141d68de2baadeb2c0fae262f2bedc (commit) via f86beaaad96ac2dd7cf6a3a9d57f42c57c2440c2 (commit) from dac0346906b7494f203e1e56b8f2e18c93fc2912 (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit be938ab44b6095818501b23ca8422c731e14015a Author: Matthias Dieter Wallnöfer <mwallnoe...@yahoo.de> Date: Sat Oct 3 11:37:30 2009 +0200 s4:ldap.py - add tests for valid parent and RDN commit 4bc9a39eed3e47cd87ea8cd24f9ac4f9e2712f43 Author: Andrew Bartlett <abart...@samba.org> Date: Thu Sep 24 15:14:49 2009 -0700 s4:dsdb Use possibleInferiors to restrict creation of child objects This also uses systemPossibleInferiors when the 'relax' control is specified, which is done by the provision. Andrew Bartlett commit 0e028fcb7d141d68de2baadeb2c0fae262f2bedc Author: Andrew Bartlett <abart...@samba.org> Date: Thu Sep 24 15:12:49 2009 -0700 s4:dsdb add systemPossibleInferiors to schema code This allows us to figure out what the system can add, which will not be in possibleInferiors due to the systemOnly flag. Andrew Bartlett commit f86beaaad96ac2dd7cf6a3a9d57f42c57c2440c2 Author: Andrew Bartlett <abart...@samba.org> Date: Wed Sep 23 21:16:42 2009 -0700 s4:dsdb Add objectClass and RDN constraints to objectClass module These additional constraints are applied, found by the Microsoft testsuite. - When the parent is not present, we now return 'NO_SUCH_OBJECT'. - Restrict the choice of RDN to the correct one per the schema - Honour the allowedChildClasses attribute from the parent's objectClass. Andrew Bartlett ----------------------------------------------------------------------- Summary of changes: source4/dsdb/samdb/ldb_modules/objectclass.c | 54 ++++++++++++++++++++++---- source4/dsdb/schema/schema.h | 1 + source4/dsdb/schema/schema_inferiors.c | 20 +++++++++ source4/lib/ldb/tests/python/ldap.py | 39 ++++++++++++++++++ 4 files changed, 106 insertions(+), 8 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index b3d5461..51a1ac8 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Simo Sorce 2006-2008 - Copyright (C) Andrew Bartlett <abart...@samba.org> 2005-2007 + Copyright (C) Andrew Bartlett <abart...@samba.org> 2005-2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,6 +42,7 @@ #include "libcli/security/security.h" #include "auth/auth.h" #include "param/param.h" +#include "../libds/common/flags.h" struct oc_context { @@ -381,7 +382,7 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) struct oc_context *ac; struct ldb_dn *parent_dn; int ret; - static const char * const parent_attrs[] = { "objectGUID", NULL }; + static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL }; ldb = ldb_module_get_ctx(module); @@ -465,7 +466,7 @@ static int objectclass_do_add(struct oc_context *ac) ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", ldb_dn_get_linearized(msg->dn)); talloc_free(mem_ctx); - return LDB_ERR_UNWILLING_TO_PERFORM; + return LDB_ERR_NO_SUCH_OBJECT; } } else { const struct ldb_val *parent_guid; @@ -491,9 +492,6 @@ static int objectclass_do_add(struct oc_context *ac) return LDB_ERR_UNWILLING_TO_PERFORM; } - /* TODO: Check this is a valid child to this parent, - * by reading the allowedChildClasses and - * allowedChildClasssesEffective attributes */ ret = ldb_msg_add_steal_value(msg, "parentGUID", discard_const(parent_guid)); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, failed to add parentGUID", @@ -555,12 +553,52 @@ static int objectclass_do_add(struct oc_context *ac) struct ldb_message_element *el; int32_t systemFlags = 0; const char *rdn_name = ldb_dn_get_rdn_name(msg->dn); - if (ldb_attr_cmp(rdn_name, current->objectclass->rDNAttID) != 0) { - ldb_asprintf_errstring(ldb, "RDN %s is not correct for most specific structural objectclass %s, should be %s", + if (current->objectclass->rDNAttID + && ldb_attr_cmp(rdn_name, current->objectclass->rDNAttID) != 0) { + ldb_asprintf_errstring(ldb, + "RDN %s is not correct for most specific structural objectclass %s, should be %s", rdn_name, current->objectclass->lDAPDisplayName, current->objectclass->rDNAttID); return LDB_ERR_NAMING_VIOLATION; } + if (ac->search_res && ac->search_res->message) { + struct ldb_message_element *oc_el + = ldb_msg_find_element(ac->search_res->message, "objectClass"); + + bool allowed_class = false; + int i, j; + for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) { + const struct dsdb_class *sclass; + + sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]); + if (!sclass) { + /* We don't know this class? what is going on? */ + continue; + } + if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) { + for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) { + if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) { + allowed_class = true; + break; + } + } + } else { + for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) { + if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) { + allowed_class = true; + break; + } + } + } + } + + if (!allowed_class) { + ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s", + current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn)); + return LDB_ERR_NAMING_VIOLATION; + } + } + if (current->objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) { ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s", current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn)); diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index 4e7e503..ddd9b37 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -119,6 +119,7 @@ struct dsdb_class { const char **mustContain; const char **mayContain; const char **possibleInferiors; + const char **systemPossibleInferiors; const char *defaultSecurityDescriptor; diff --git a/source4/dsdb/schema/schema_inferiors.c b/source4/dsdb/schema/schema_inferiors.c index b02d557..264e471 100644 --- a/source4/dsdb/schema/schema_inferiors.c +++ b/source4/dsdb/schema/schema_inferiors.c @@ -198,6 +198,25 @@ static void schema_fill_possible_inferiors(struct dsdb_schema *schema, struct ds schema_class->possibleInferiors = str_list_unique(schema_class->possibleInferiors); } +static void schema_fill_system_possible_inferiors(struct dsdb_schema *schema, struct dsdb_class *schema_class) +{ + struct dsdb_class *c2; + + for (c2=schema->classes; c2; c2=c2->next) { + char **superiors = schema_posssuperiors(schema, c2); + if (c2->objectClassCategory != 2 + && c2->objectClassCategory != 3 + && str_list_check(superiors, schema_class->lDAPDisplayName)) { + if (schema_class->possibleInferiors == NULL) { + schema_class->systemPossibleInferiors = str_list_make_empty(schema_class); + } + schema_class->systemPossibleInferiors = str_list_add_const(schema_class->systemPossibleInferiors, + c2->lDAPDisplayName); + } + } + schema_class->systemPossibleInferiors = str_list_unique(schema_class->systemPossibleInferiors); +} + /* fill in a string class name from a governs_ID */ @@ -285,6 +304,7 @@ void schema_fill_constructed(struct dsdb_schema *schema) for (schema_class=schema->classes; schema_class; schema_class=schema_class->next) { schema_fill_possible_inferiors(schema, schema_class); + schema_fill_system_possible_inferiors(schema, schema_class); } /* free up our internal cache elements */ diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 7fa25fb..59bb5d2 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -21,6 +21,7 @@ from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INSUFFICIENT_ACCESS_RIGHTS from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN +from ldb import ERR_NAMING_VIOLATION from ldb import Message, MessageElement, Dn, FLAG_MOD_ADD, FLAG_MOD_REPLACE from samba import Ldb, param, dom_sid_to_rid from samba import UF_NORMAL_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT @@ -118,6 +119,8 @@ class BasicTests(unittest.TestCase): self.delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn) self.delete_force(self.ldb, "cn=testotherusers," + self.base_dn) self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn) + self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn) + self.delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn) def test_system_only(self): """Test systemOnly objects""" @@ -133,6 +136,32 @@ class BasicTests(unittest.TestCase): self.delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn) + def test_invalid_parent(self): + """Test adding an object with invalid parent""" + print "Test adding an object with invalid parent""" + + try: + self.ldb.add({ + "dn": "cn=ldaptestgroup,cn=thisdoesnotexist123," + + self.base_dn, + "objectclass": "group"}) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_NO_SUCH_OBJECT) + + self.delete_force(self.ldb, "cn=ldaptestgroup,cn=thisdoesnotexist123," + + self.base_dn) + + try: + self.ldb.add({ + "dn": "ou=testou,cn=users," + self.base_dn, + "objectclass": "organizationalUnit"}) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_NAMING_VIOLATION) + + self.delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn) + def test_invalid_attribute(self): """Test adding invalid attributes (not in schema)""" print "Test adding invalid attributes (not in schema)""" @@ -188,6 +217,16 @@ class BasicTests(unittest.TestCase): """Tests the RDN""" print "Tests the RDN""" + try: + self.ldb.add({ + "dn": "description=xyz,cn=users," + self.base_dn, + "objectclass": "group"}) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_NAMING_VIOLATION) + + self.delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn) + self.ldb.add({ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn, "objectclass": "group"}) -- Samba Shared Repository