Skip to content

Commit

Permalink
repl_meta_data: Correctly use msDS-IntId for custom schema, not the p…
Browse files Browse the repository at this point in the history
…refixMap value

We must, when dealing with custom schema, respect the msDC-IntId value recorded
in the schema.  If we do not, then we will create multiple replPropertyMetaData
records for the one attribute.  This may cause confusion during replication.

This fixes the issue by always calling dsdb_attribute_get_attid() to obtain
the correct local (32 bit integer) attribute ID

Signed-off-by: Andrew Bartlett <[email protected]>
Reviewed-by: Garming Sam <[email protected]>
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11443
  • Loading branch information
abartlet committed Mar 8, 2016
1 parent 90bf114 commit ecf0dd4
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 14 deletions.
55 changes: 45 additions & 10 deletions source4/dsdb/samdb/ldb_modules/repl_meta_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
bool allow_add_guid = false;
bool remove_current_guid = false;
bool is_urgent = false;
bool is_schema_nc = false;
struct ldb_message_element *objectclass_el;
struct replmd_private *replmd_private =
talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
Expand Down Expand Up @@ -1007,6 +1008,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_OPERATIONS_ERROR;
}

is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;

for (i=0; i < msg->num_elements; i++) {
struct ldb_message_element *e = &msg->elements[i];
struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
Expand Down Expand Up @@ -1041,8 +1044,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
continue;
}

m->attid = sa->attributeID_id;
m->version = 1;
m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
m->version = 1;
if (m->attid == 0x20030) {
const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
const char* rdn;
Expand Down Expand Up @@ -1209,12 +1212,14 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
uint64_t *seq_num,
const struct GUID *our_invocation_id,
NTTIME now,
bool is_schema_nc,
struct ldb_request *req)
{
uint32_t i;
const struct dsdb_attribute *a;
struct replPropertyMetaData1 *md1;
bool may_skip = false;
uint32_t attid;

a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
if (a == NULL) {
Expand All @@ -1229,6 +1234,8 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
return LDB_ERR_OPERATIONS_ERROR;
}

attid = dsdb_attribute_get_attid(a, is_schema_nc);

if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
return LDB_SUCCESS;
}
Expand Down Expand Up @@ -1272,7 +1279,22 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
}

for (i=0; i<omd->ctr.ctr1.count; i++) {
if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
/*
* First check if we find it under the msDS-IntID,
* then check if we find it under the OID and
* prefixMap ID.
*
* This allows the administrator to simply re-write
* the attributes and so restore replication, which is
* likely what they will try to do.
*/
if (attid == omd->ctr.ctr1.array[i].attid) {
break;
}

if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
break;
}
}

if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
Expand Down Expand Up @@ -1311,7 +1333,7 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,

md1 = &omd->ctr.ctr1.array[i];
md1->version++;
md1->attid = a->attributeID_id;
md1->attid = attid;
if (md1->attid == 0x20030) {
const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
const char* rdn;
Expand Down Expand Up @@ -1365,7 +1387,7 @@ static int replmd_update_rpmd(struct ldb_module *module,
struct ldb_request *req,
const char * const *rename_attrs,
struct ldb_message *msg, uint64_t *seq_num,
time_t t,
time_t t, bool is_schema_nc,
bool *is_urgent, bool *rodc)
{
const struct ldb_val *omd_value;
Expand Down Expand Up @@ -1524,7 +1546,9 @@ static int replmd_update_rpmd(struct ldb_module *module,
struct ldb_message_element *old_el;
old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
our_invocation_id, now, req);
our_invocation_id,
now, is_schema_nc,
req);
if (ret != LDB_SUCCESS) {
return ret;
}
Expand Down Expand Up @@ -2486,6 +2510,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
time_t t = time(NULL);
int ret;
bool is_urgent = false, rodc = false;
bool is_schema_nc = false;
unsigned int functional_level;
const struct ldb_message_element *guid_el = NULL;
struct ldb_control *sd_propagation_control;
Expand Down Expand Up @@ -2541,8 +2566,11 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
ldb_msg_remove_attr(msg, "whenChanged");
ldb_msg_remove_attr(msg, "uSNChanged");

is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;

ret = replmd_update_rpmd(module, ac->schema, req, NULL,
msg, &ac->seq_num, t, &is_urgent, &rodc);
msg, &ac->seq_num, t, is_schema_nc,
&is_urgent, &rodc);
if (rodc && (ret == LDB_ERR_REFERRAL)) {
struct loadparm_context *lp_ctx;
char *referral;
Expand Down Expand Up @@ -2690,7 +2718,6 @@ static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct ldb_context *ldb;
struct replmd_replicated_request *ac;
struct ldb_request *down_req;
struct ldb_message *msg;
const struct dsdb_attribute *rdn_attr;
Expand All @@ -2700,8 +2727,13 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
time_t t = time(NULL);
int ret;
bool is_urgent = false, rodc = false;
bool is_schema_nc;
struct replmd_replicated_request *ac =
talloc_get_type(req->context, struct replmd_replicated_request);
struct replmd_private *replmd_private =
talloc_get_type(ldb_module_get_private(ac->module),
struct replmd_private);

ac = talloc_get_type(req->context, struct replmd_replicated_request);
ldb = ldb_module_get_ctx(ac->module);

if (ares->error != LDB_SUCCESS) {
Expand Down Expand Up @@ -2729,6 +2761,8 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are

msg->dn = ac->req->op.rename.newdn;

is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;

rdn_name = ldb_dn_get_rdn_name(msg->dn);
if (rdn_name == NULL) {
talloc_free(ares);
Expand Down Expand Up @@ -2814,7 +2848,8 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
attrs[4] = NULL;

ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
msg, &ac->seq_num, t, &is_urgent, &rodc);
msg, &ac->seq_num, t,
is_schema_nc, &is_urgent, &rodc);
if (rodc && (ret == LDB_ERR_REFERRAL)) {
struct ldb_dn *olddn = ac->req->op.rename.olddn;
struct loadparm_context *lp_ctx;
Expand Down
31 changes: 27 additions & 4 deletions source4/dsdb/tests/python/ldap_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
from samba.samdb import SamDB
from samba.dsdb import DS_DOMAIN_FUNCTION_2003
from samba.tests import delete_force
from samba.ndr import ndr_unpack
from samba.dcerpc import drsblobs

parser = optparse.OptionParser("ldap_schema.py [options] <host>")
sambaopts = options.SambaOptions(parser)
Expand Down Expand Up @@ -124,10 +126,16 @@ def test_schemaUpdateNow(self):
# Search for created attribute
res = []
res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE,
attrs=["lDAPDisplayName","schemaIDGUID"])
attrs=["lDAPDisplayName","schemaIDGUID", "msDS-IntID"])
self.assertEquals(len(res), 1)
self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
self.assertTrue("schemaIDGUID" in res[0])
if "msDS-IntId" in res[0]:
msDS_IntId = int(res[0]["msDS-IntId"][0])
if msDS_IntId < 0:
msDS_IntId += (1 << 32)
else:
msDS_IntId = None

class_name = "test-Class" + time.strftime("%s", time.gmtime())
class_ldap_display_name = class_name.replace("-", "")
Expand Down Expand Up @@ -211,9 +219,24 @@ def test_schemaUpdateNow(self):
self.ldb.add_ldif(ldif)

# Search for created object
res = []
res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
self.assertEquals(len(res), 1)
obj_res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["replPropertyMetaData"])

self.assertEquals(len(obj_res), 1)
self.assertTrue("replPropertyMetaData" in obj_res[0])
val = obj_res[0]["replPropertyMetaData"][0]
repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
obj = repl.ctr

# Windows 2000 functional level won't have this. It is too
# hard to work it out from the prefixmap however, so we skip
# this test in that case.
if msDS_IntId is not None:
found = False
for o in repl.ctr.array:
if o.attid == msDS_IntId:
found = True
break
self.assertTrue(found, "Did not find 0x%08x in replPropertyMetaData" % msDS_IntId)
# Delete the object
delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))

Expand Down

0 comments on commit ecf0dd4

Please sign in to comment.