mirror of
https://github.com/samba-team/samba.git
synced 2024-12-29 11:21:54 +03:00
samldb: Allow automatic generation of linkIDs and prevent duplicates
As per MS-ADTS 3.1.1.2.3.1, this allows specifying the OID 1.2.840.113556.1.2.50 as the linkID of a new linked attribute in the schema in order to automatically assign it an unused even linkID. Specifying the attributeID or ldapDisplayName of an existing forward link will now also add the new linked attribute as the backlink of that existing link. This also prevents adding duplicate linkIDs. Previously, we could run into issues when trying to delete backlinks with duplicate linkIDs. Signed-off-by: Bob Campbell <bobcampbell@catalyst.net.nz> Reviewed-by: Garming Sam <garming@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139
This commit is contained in:
parent
85d5b43392
commit
35be7ee8a4
@ -5,6 +5,7 @@
|
||||
Copyright (C) Simo Sorce 2004-2008
|
||||
Copyright (C) Matthias Dieter Wallnöfer 2009-2011
|
||||
Copyright (C) Matthieu Patou 2012
|
||||
Copyright (C) Catalyst.Net Ltd 2017
|
||||
|
||||
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
|
||||
@ -272,6 +273,171 @@ static int samldb_schema_ldapdisplayname_valid_check(struct samldb_ctx *ac)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int samldb_check_linkid_used(struct samldb_ctx *ac,
|
||||
struct dsdb_schema *schema,
|
||||
struct ldb_dn *schema_dn,
|
||||
struct ldb_context *ldb,
|
||||
int32_t linkID,
|
||||
bool *found)
|
||||
{
|
||||
int ret;
|
||||
struct ldb_result *ldb_res;
|
||||
|
||||
if (dsdb_attribute_by_linkID(schema, linkID)) {
|
||||
*found = true;
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
|
||||
ret = dsdb_module_search(ac->module, ac,
|
||||
&ldb_res,
|
||||
schema_dn, LDB_SCOPE_ONELEVEL, NULL,
|
||||
DSDB_FLAG_NEXT_MODULE,
|
||||
ac->req,
|
||||
"(linkID=%d)", linkID);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
ldb_debug_set(ldb, LDB_DEBUG_ERROR,
|
||||
__location__": Searching for linkID=%d failed - %s\n",
|
||||
linkID,
|
||||
ldb_errstring(ldb));
|
||||
return ldb_operr(ldb);
|
||||
}
|
||||
|
||||
*found = (ldb_res->count != 0);
|
||||
talloc_free(ldb_res);
|
||||
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
|
||||
/* Find the next open forward linkID in the schema. */
|
||||
static int samldb_generate_next_linkid(struct samldb_ctx *ac,
|
||||
struct dsdb_schema *schema,
|
||||
int32_t *next_linkID)
|
||||
{
|
||||
int ret;
|
||||
struct ldb_context *ldb;
|
||||
struct ldb_dn *schema_dn;
|
||||
bool linkID_used = true;
|
||||
|
||||
/*
|
||||
* Windows starts at about 0xB0000000 in order to stop potential
|
||||
* collisions with future additions to the schema. We pass this
|
||||
* around as a signed int sometimes, but this should be sufficient.
|
||||
*/
|
||||
*next_linkID = 0x40000000;
|
||||
|
||||
ldb = ldb_module_get_ctx(ac->module);
|
||||
schema_dn = ldb_get_schema_basedn(ldb);
|
||||
|
||||
while (linkID_used) {
|
||||
*next_linkID += 2;
|
||||
ret = samldb_check_linkid_used(ac, schema,
|
||||
schema_dn, ldb,
|
||||
*next_linkID, &linkID_used);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
|
||||
static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
|
||||
{
|
||||
int ret;
|
||||
bool ok, found;
|
||||
struct ldb_message_element *el;
|
||||
const char *enc_str;
|
||||
const struct dsdb_attribute *attr;
|
||||
struct ldb_context *ldb;
|
||||
struct ldb_dn *schema_dn;
|
||||
struct dsdb_schema *schema;
|
||||
int32_t new_linkID = 0;
|
||||
|
||||
ldb = ldb_module_get_ctx(ac->module);
|
||||
schema = dsdb_get_schema(ldb, ac);
|
||||
schema_dn = ldb_get_schema_basedn(ldb);
|
||||
|
||||
el = dsdb_get_single_valued_attr(ac->msg, "linkID",
|
||||
ac->req->operation);
|
||||
if (el == NULL) {
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
|
||||
enc_str = ldb_binary_encode(ac, el->values[0]);
|
||||
if (enc_str == NULL) {
|
||||
return ldb_module_oom(ac->module);
|
||||
}
|
||||
|
||||
ok = (strcmp(enc_str, "0") == 0);
|
||||
if (ok) {
|
||||
return LDB_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This OID indicates that the caller wants the linkID
|
||||
* to be automatically generated. We therefore assign
|
||||
* it the next open linkID.
|
||||
*/
|
||||
ok = (strcmp(enc_str, "1.2.840.113556.1.2.50") == 0);
|
||||
if (ok) {
|
||||
ret = samldb_generate_next_linkid(ac, schema, &new_linkID);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ldb_msg_remove_element(ac->msg, el);
|
||||
ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
|
||||
new_linkID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using either the attributeID or lDAPDisplayName of
|
||||
* another attribute in the linkID field indicates that
|
||||
* we should make this the backlink of that attribute.
|
||||
*/
|
||||
attr = dsdb_attribute_by_attributeID_oid(schema, enc_str);
|
||||
if (attr == NULL) {
|
||||
attr = dsdb_attribute_by_lDAPDisplayName(schema, enc_str);
|
||||
}
|
||||
|
||||
if (attr != NULL) {
|
||||
/*
|
||||
* The attribute we're adding this as a backlink of must
|
||||
* be a forward link.
|
||||
*/
|
||||
if (attr->linkID % 2 != 0) {
|
||||
return LDB_ERR_UNWILLING_TO_PERFORM;
|
||||
}
|
||||
|
||||
new_linkID = attr->linkID + 1;
|
||||
|
||||
/* Make sure that this backlink doesn't already exist. */
|
||||
ret = samldb_check_linkid_used(ac, schema,
|
||||
schema_dn, ldb,
|
||||
new_linkID, &found);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return LDB_ERR_UNWILLING_TO_PERFORM;
|
||||
}
|
||||
|
||||
ldb_msg_remove_element(ac->msg, el);
|
||||
ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
|
||||
new_linkID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
|
||||
ret = samldb_unique_attr_check(ac, "linkID", NULL, schema_dn);
|
||||
if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
|
||||
return LDB_ERR_UNWILLING_TO_PERFORM;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* sAMAccountName handling */
|
||||
|
||||
@ -3227,6 +3393,11 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req)
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = samldb_schema_add_handle_linkid(ac);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = samldb_schema_ldapdisplayname_valid_check(ac);
|
||||
|
Loading…
Reference in New Issue
Block a user