summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/linked_attributes.c92
-rw-r--r--source4/lib/ldb-samba/ldif_handlers.c78
-rwxr-xr-xsource4/lib/ldb/tests/python/ldap.py91
-rw-r--r--source4/scripting/python/samba/provision.py3
4 files changed, 213 insertions, 51 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
index c21fda5135..c204571133 100644
--- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c
+++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
@@ -1,4 +1,4 @@
-/*
+/*
ldb database library
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
@@ -8,12 +8,12 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -93,8 +93,8 @@ static struct la_context *linked_attributes_init(struct ldb_module *module,
*/
static int la_guid_from_dn(struct la_context *ac, struct ldb_dn *dn, struct GUID *guid)
{
- int ret;
NTSTATUS status;
+ int ret;
status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
if (NT_STATUS_IS_OK(status)) {
@@ -131,7 +131,7 @@ static int la_store_op(struct la_context *ac,
op_dn = ldb_dn_from_ldb_val(ac, ldb, dn);
if (!op_dn) {
- ldb_asprintf_errstring(ldb,
+ ldb_asprintf_errstring(ldb,
"could not parse attribute as a DN");
return LDB_ERR_INVALID_DN_SYNTAX;
}
@@ -191,8 +191,8 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
struct la_context *ac;
const char *attr_name;
struct ldb_control *ctrl;
+ unsigned int i, j;
int ret;
- int i, j;
ldb = ldb_module_get_ctx(module);
@@ -224,9 +224,9 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
const struct dsdb_attribute *schema_attr
= dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
+ ldb_asprintf_errstring(ldb,
"attribute %s is not a valid attribute in schema", el->name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
/* We have a valid attribute, now find out if it is a forward link */
if ((schema_attr->linkID == 0)) {
@@ -235,11 +235,11 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
if ((schema_attr->linkID & 1) == 1) {
unsigned int functional_level;
-
+
functional_level = dsdb_functional_level(ldb);
SMB_ASSERT(functional_level > DS_DOMAIN_FUNCTION_2000);
}
-
+
/* Even link IDs are for the originating attribute */
target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
if (!target_attr) {
@@ -289,7 +289,7 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are
struct replace_context *rc;
struct la_context *ac;
const char *attr_name;
- int i, j;
+ unsigned int i, j;
int ret = LDB_SUCCESS;
ac = talloc_get_type(req->context, struct la_context);
@@ -310,8 +310,8 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are
case LDB_REPLY_ENTRY:
if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
- ldb_asprintf_errstring(ldb,
- "linked_attributes: %s is not the DN we were looking for",
+ ldb_asprintf_errstring(ldb,
+ "linked_attributes: %s is not the DN we were looking for",
ldb_dn_get_linearized(ares->message->dn));
/* Guh? We only asked for this DN */
talloc_free(ares);
@@ -412,12 +412,11 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
/* Apply the modify to the linked entry */
struct ldb_context *ldb;
- int i, j;
+ unsigned int i, j;
struct la_context *ac;
struct ldb_request *search_req;
const char **attrs;
struct ldb_control *ctrl;
-
int ret;
ldb = ldb_module_get_ctx(module);
@@ -457,9 +456,9 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
const struct dsdb_attribute *schema_attr
= dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
+ ldb_asprintf_errstring(ldb,
"attribute %s is not a valid attribute in schema", el->name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
/* We have a valid attribute, now find out if it is a forward link
(Even link IDs are for the originating attribute) */
@@ -469,7 +468,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
if ((schema_attr->linkID & 1) == 1) {
unsigned int functional_level;
-
+
functional_level = dsdb_functional_level(ldb);
SMB_ASSERT(functional_level > DS_DOMAIN_FUNCTION_2000);
}
@@ -487,7 +486,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
}
attr_name = target_attr->lDAPDisplayName;
-
+
switch (el->flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_REPLACE:
/* treat as just a normal add the delete part is handled by the callback */
@@ -546,11 +545,11 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
ac->rc->num_elements++;
}
}
-
+
if (ac->ops || ac->rc->el) {
/* both replace and delete without values are handled in the callback
* after the search on the entry to be modified is performed */
-
+
attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
if (!attrs) {
ldb_oom(ldb);
@@ -560,7 +559,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
attrs[i] = ac->rc->el[i].name;
}
attrs[i] = NULL;
-
+
/* The callback does all the hard work here */
ret = ldb_build_search_req(&search_req, ldb, ac,
req->op.mod.message->dn,
@@ -578,7 +577,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
}
if (ret == LDB_SUCCESS) {
talloc_steal(search_req, attrs);
-
+
ret = ldb_next_request(module, search_req);
}
@@ -596,11 +595,12 @@ static int linked_attributes_fix_links(struct ldb_module *module,
struct ldb_message_element *el, struct dsdb_schema *schema,
const struct dsdb_attribute *schema_attr)
{
- unsigned int i;
+ unsigned int i, j;
TALLOC_CTX *tmp_ctx = talloc_new(module);
struct ldb_context *ldb = ldb_module_get_ctx(module);
const struct dsdb_attribute *target;
const char *attrs[2];
+ int ret;
target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
if (target == NULL) {
@@ -613,8 +613,6 @@ static int linked_attributes_fix_links(struct ldb_module *module,
for (i=0; i<el->num_values; i++) {
struct dsdb_dn *dsdb_dn;
- unsigned int j;
- int ret;
struct ldb_result *res;
struct ldb_message *msg;
struct ldb_message_element *el2;
@@ -645,7 +643,7 @@ static int linked_attributes_fix_links(struct ldb_module *module,
/* Forward link without backlink remaining - nothing to do here */
continue;
} else if (msg->num_elements != 1) {
- ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
+ ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
msg->num_elements, ldb_dn_get_linearized(msg->dn));
talloc_free(tmp_ctx);
return LDB_ERR_OPERATIONS_ERROR;
@@ -709,9 +707,9 @@ static int linked_attributes_rename(struct ldb_module *module, struct ldb_reques
struct ldb_result *res;
struct ldb_message *msg;
unsigned int i;
- int ret;
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct dsdb_schema *schema;
+ int ret;
/*
- load the current msg
- find any linked attributes
@@ -757,7 +755,7 @@ static int linked_attributes_rename(struct ldb_module *module, struct ldb_reques
structure */
static int la_queue_mod_request(struct la_context *ac)
{
- struct la_private *la_private =
+ struct la_private *la_private =
talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
if (la_private == NULL) {
@@ -775,9 +773,9 @@ static int la_queue_mod_request(struct la_context *ac)
/* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- int ret;
struct la_context *ac;
struct ldb_context *ldb;
+ int ret;
ac = talloc_get_type(req->context, struct la_context);
ldb = ldb_module_get_ctx(ac->module);
@@ -798,13 +796,13 @@ static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
return ldb_module_done(ac->req, NULL, NULL,
LDB_ERR_OPERATIONS_ERROR);
}
-
+
ac->op_controls = talloc_steal(ac, ares->controls);
ac->op_response = talloc_steal(ac, ares->response);
/* If we have modfies to make, this is the time to do them for modify and delete */
ret = la_queue_mod_request(ac);
-
+
if (ret != LDB_SUCCESS) {
return ldb_module_done(ac->req, NULL, NULL, ret);
}
@@ -821,9 +819,9 @@ static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
*/
static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- int ret;
struct la_context *ac;
struct ldb_context *ldb;
+ int ret;
ac = talloc_get_type(req->context, struct la_context);
ldb = ldb_module_get_ctx(ac->module);
@@ -844,11 +842,11 @@ static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
return ldb_module_done(ac->req, NULL, NULL,
LDB_ERR_OPERATIONS_ERROR);
}
-
+
if (ac->ops) {
struct ldb_request *search_req;
static const char *attrs[] = { NULL };
-
+
/* The callback does all the hard work here - we need
* the objectGUID and SID of the added record */
ret = ldb_build_search_req(&search_req, ldb, ac,
@@ -858,7 +856,7 @@ static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
NULL,
ac, la_mod_search_callback,
ac->req);
-
+
if (ret == LDB_SUCCESS) {
ret = ldb_request_add_control(search_req,
LDB_CONTROL_EXTENDED_DN_OID,
@@ -873,7 +871,7 @@ static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
ac->op_response = talloc_steal(ac, ares->response);
return ldb_next_request(ac->module, search_req);
-
+
} else {
return ldb_module_done(ac->req, ares->controls,
ares->response, ares->error);
@@ -884,8 +882,8 @@ static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
static int la_down_req(struct la_context *ac)
{
struct ldb_request *down_req;
- int ret;
struct ldb_context *ldb;
+ int ret;
ldb = ldb_module_get_ctx(ac->module);
@@ -918,7 +916,7 @@ static int la_down_req(struct la_context *ac)
use the GUID part of an extended DN to find the target DN, in case
it has moved
*/
-static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
+static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
struct GUID *guid, struct ldb_dn **dn)
{
return dsdb_find_dn_by_guid(ldb_module_get_ctx(ac->module), ac, guid, dn);
@@ -970,10 +968,10 @@ static int la_do_op_request(struct ldb_module *module, struct la_context *ac, st
#if 0
ldb_debug(ldb, LDB_DEBUG_WARNING,
- "link on %s %s: %s %s\n",
- ldb_dn_get_linearized(new_msg->dn), ret_el->name,
+ "link on %s %s: %s %s\n",
+ ldb_dn_get_linearized(new_msg->dn), ret_el->name,
ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
-#endif
+#endif
if (DEBUGLVL(4)) {
DEBUG(4,("Applying linked attribute change:\n%s\n",
@@ -1009,7 +1007,7 @@ static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
/*
- we hook into the transaction operations to allow us to
+ we hook into the transaction operations to allow us to
perform the linked attribute updates at the end of the whole
transaction. This allows a forward linked attribute to be created
before the target is created, as long as the target is created
@@ -1036,7 +1034,7 @@ static int linked_attributes_start_transaction(struct ldb_module *module)
*/
static int linked_attributes_prepare_commit(struct ldb_module *module)
{
- struct la_private *la_private =
+ struct la_private *la_private =
talloc_get_type(ldb_module_get_private(module), struct la_private);
struct la_context *ac;
@@ -1060,20 +1058,20 @@ static int linked_attributes_prepare_commit(struct ldb_module *module)
if (ret != LDB_SUCCESS) {
DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
talloc_free(la_private);
- ldb_module_set_private(module, NULL);
+ ldb_module_set_private(module, NULL);
return ret;
}
}
talloc_free(la_private);
- ldb_module_set_private(module, NULL);
+ ldb_module_set_private(module, NULL);
return ldb_next_prepare_commit(module);
}
static int linked_attributes_del_transaction(struct ldb_module *module)
{
- struct la_private *la_private =
+ struct la_private *la_private =
talloc_get_type(ldb_module_get_private(module), struct la_private);
talloc_free(la_private);
ldb_module_set_private(module, NULL);
diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c
index 480335f411..2ce1055d0d 100644
--- a/source4/lib/ldb-samba/ldif_handlers.c
+++ b/source4/lib/ldb-samba/ldif_handlers.c
@@ -878,6 +878,78 @@ static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
return 0;
}
+/*
+ compare two dns
+*/
+static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *v1, const struct ldb_val *v2)
+{
+ struct ldb_dn *dn1 = NULL, *dn2 = NULL;
+ int ret;
+
+ if (dsdb_dn_is_deleted_val(v1)) {
+ /* If the DN is deleted, then we can't search for it */
+ return -1;
+ }
+
+ if (dsdb_dn_is_deleted_val(v2)) {
+ /* If the DN is deleted, then we can't search for it */
+ return -1;
+ }
+
+ dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
+ if ( ! ldb_dn_validate(dn1)) return -1;
+
+ dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
+ if ( ! ldb_dn_validate(dn2)) {
+ talloc_free(dn1);
+ return -1;
+ }
+
+ ret = ldb_dn_compare(dn1, dn2);
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+ return ret;
+}
+
+static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx,
+ const struct ldb_val *in, struct ldb_val *out)
+{
+ struct ldb_dn *dn;
+ int ret = -1;
+
+ out->length = 0;
+ out->data = NULL;
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
+ if ( ! ldb_dn_validate(dn)) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ /* By including the RMD_FLAGS of a deleted DN, we ensure it
+ * does not casually match a not deleted DN */
+ if (dsdb_dn_is_deleted_val(in)) {
+ out->data = talloc_asprintf(mem_ctx, "<RMD_FLAGS=%u>%s",
+ dsdb_dn_val_rmd_flags(in),
+ ldb_dn_get_casefold(dn));
+ } else {
+ out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
+ }
+
+ if (out->data == NULL) {
+ goto done;
+ }
+ out->length = strlen((char *)out->data);
+
+ ret = 0;
+
+done:
+ talloc_free(dn);
+
+ return ret;
+}
+
/*
write a 64 bit 2-part range
@@ -1010,6 +1082,12 @@ static const struct ldb_schema_syntax samba_syntaxes[] = {
.canonicalise_fn = dsdb_dn_string_canonicalise,
.comparison_fn = dsdb_dn_string_comparison
},{
+ .name = LDB_SYNTAX_DN,
+ .ldif_read_fn = ldb_handler_copy,
+ .ldif_write_fn = ldb_handler_copy,
+ .canonicalise_fn = samba_ldb_dn_link_canonicalise,
+ .comparison_fn = samba_ldb_dn_link_comparison,
+ },{
.name = LDB_SYNTAX_SAMBA_RANGE64,
.ldif_read_fn = ldif_read_range64,
.ldif_write_fn = ldif_write_range64,
diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py
index ddf0254c21..40cbb9feb3 100755
--- a/source4/lib/ldb/tests/python/ldap.py
+++ b/source4/lib/ldb/tests/python/ldap.py
@@ -969,6 +969,95 @@ objectClass: container
self.assertEquals(res1[0]["groupType"][0], "-2147483643")
+ def test_linked_attributes(self):
+ """This tests the linked attribute behaviour"""
+ print "Testing linked attribute behaviour\n"
+
+ ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group"})
+
+ # This should not work since "memberOf" is linked to "member"
+ try:
+ ldb.add({
+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+ "objectclass": ["user", "person"],
+ "memberOf": "cn=ldaptestgroup,cn=users," + self.base_dn})
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+
+ ldb.add({
+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+ "objectclass": ["user", "person"]})
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
+ FLAG_MOD_ADD, "memberOf")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
+ FLAG_MOD_ADD, "member")
+ ldb.modify(m)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
+ FLAG_MOD_REPLACE, "memberOf")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
+ FLAG_MOD_DELETE, "memberOf")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
+ FLAG_MOD_DELETE, "member")
+ ldb.modify(m)
+
+ # This should yield no results since the member attribute for
+ # "ldaptestuser" should have been deleted
+ res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
+ scope=SCOPE_BASE,
+ expression="(member=cn=ldaptestuser,cn=users," + self.base_dn + ")",
+ attrs=[])
+ self.assertTrue(len(res1) == 0)
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group",
+ "member": "cn=ldaptestuser,cn=users," + self.base_dn})
+
+ self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+
+ # Make sure that the "member" attribute for "ldaptestuser" has been
+ # removed
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["member"])
+ self.assertTrue(len(res) == 1)
+ self.assertFalse("member" in res[0])
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
def test_groups(self):
"""This tests the group behaviour (setting, changing) of a user account"""
print "Testing group behaviour\n"
@@ -2072,7 +2161,7 @@ member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """
self.assertTrue(("<GUID=" + ldb.schema_format_value("objectGUID", ldaptestuser2_guid) + ">;<SID=" + ldb.schema_format_value("objectSid", ldaptestuser2_sid) + ">;CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
- print "Testing Linked attribute behaviours"
+ print "Quicktest for linked attributes"
ldb.modify_ldif("""
dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
changetype: modify
diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py
index 8b07f892e9..7fa5dbbdd7 100644
--- a/source4/scripting/python/samba/provision.py
+++ b/source4/scripting/python/samba/provision.py
@@ -856,9 +856,6 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, names,
if dom_for_fun_level is None:
dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
- if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003:
- logger.warning("Running SAMBA 4 on a domain and forest function level"
- " lower than Windows 2003 (Native) is not recommended.")
if dom_for_fun_level > domainControllerFunctionality:
raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008). This won't work!")