1
0
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:
Bob Campbell 2017-02-01 11:54:40 +13:00 committed by Andrew Bartlett
parent 85d5b43392
commit 35be7ee8a4

View File

@ -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);