diff options
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules')
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/acl.c | 38 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/config.mk | 23 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/instancetype.c | 3 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/lazy_commit.c | 13 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/partition.c | 12 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/pdc_fsmo.c | 4 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 12 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/ridalloc.c | 646 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samba3sid.c | 197 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 77 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samldb.c | 684 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema_data.c | 5 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema_load.c | 8 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/show_deleted.c | 4 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/tests/samba3sam.py | 17 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/util.c | 192 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/util.h | 5 |
17 files changed, 1212 insertions, 728 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index a3298362f3..a779821107 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -35,10 +35,10 @@ #include "ldb_module.h" #include "auth/auth.h" #include "libcli/security/security.h" -#include "librpc/gen_ndr/ndr_security.h" #include "dsdb/samdb/samdb.h" #include "librpc/gen_ndr/ndr_security.h" #include "param/param.h" +#include "dsdb/samdb/ldb_modules/util.h" struct extended_access_check_attribute { const char *oa_name; @@ -53,7 +53,7 @@ struct acl_private { struct acl_context { struct ldb_module *module; struct ldb_request *req; - enum security_user_level user_type; + bool am_system; bool allowedAttributes; bool allowedAttributesEffective; bool allowedChildClasses; @@ -70,14 +70,6 @@ bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check) return (result==0); } -static enum security_user_level what_is_user(struct ldb_module *module) -{ - struct ldb_context *ldb = ldb_module_get_ctx(module); - struct auth_session_info *session_info - = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); - return security_session_user_level(session_info); -} - static struct security_token *acl_user_token(struct ldb_module *module) { struct ldb_context *ldb = ldb_module_get_ctx(module); @@ -309,7 +301,7 @@ static int acl_check_access_on_attribute(struct ldb_module *module, struct security_descriptor *sd, struct dom_sid *rp_sid, uint32_t access, - struct dsdb_attribute *attr) + const struct dsdb_attribute *attr) { int ret; NTSTATUS status; @@ -370,7 +362,7 @@ static int acl_check_access_on_class(struct ldb_module *module, uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; - struct GUID *guid; + const struct GUID *guid; const struct dsdb_schema *schema = dsdb_get_schema(ldb); TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); struct security_token *token = acl_user_token(module); @@ -450,7 +442,7 @@ static int acl_allowedAttributes(struct ldb_module *module, struct ldb_control *as_system = ldb_request_get_control(ac->req, LDB_CONTROL_AS_SYSTEM_OID); ldb_msg_remove_attr(msg, "allowedAttributesEffective"); - if (ac->user_type == SECURITY_SYSTEM || as_system) { + if (ac->am_system || as_system) { for (i=0; attr_list && attr_list[i]; i++) { ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]); } @@ -468,7 +460,7 @@ static int acl_allowedAttributes(struct ldb_module *module, return ret; } for (i=0; attr_list && attr_list[i]; i++) { - struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, + const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, attr_list[i]); if (!attr) { return LDB_ERR_OPERATIONS_ERROR; @@ -566,7 +558,7 @@ static int acl_childClassesEffective(struct ldb_module *module, struct dom_sid *sid = NULL; int i, j, ret; - if (ac->user_type == SECURITY_SYSTEM || as_system) { + if (ac->am_system || as_system) { return acl_childClasses(module, sd_msg, msg, "allowedChildClassesEffective"); } @@ -650,7 +642,7 @@ static int acl_sDRightsEffective(struct ldb_module *module, if (ret != LDB_SUCCESS) { return ret; } - if (ac->user_type == SECURITY_SYSTEM || as_system) { + if (ac->am_system || as_system) { flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL; } else { @@ -707,7 +699,7 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) struct object_tree *new_node = NULL; struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); - if (what_is_user(module) == SECURITY_SYSTEM || as_system) { + if (dsdb_module_am_system(module) || as_system) { return ldb_next_request(module, req); } @@ -773,7 +765,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } - if (what_is_user(module) == SECURITY_SYSTEM || as_system) { + if (dsdb_module_am_system(module) || as_system) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -901,7 +893,7 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req) struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn))); - if (what_is_user(module) == SECURITY_SYSTEM || as_system) { + if (dsdb_module_am_system(module) || as_system) { return ldb_next_request(module, req); } @@ -955,7 +947,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); - if (what_is_user(module) == SECURITY_SYSTEM || as_system) { + if (dsdb_module_am_system(module) || as_system) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { @@ -1135,7 +1127,7 @@ static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares) } } if (data && data->password_attrs) { - if (ac->user_type != SECURITY_SYSTEM) { + if (!ac->am_system) { for (i = 0; data->password_attrs[i]; i++) { ldb_msg_remove_attr(ares->message, data->password_attrs[i]); } @@ -1173,7 +1165,7 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req) ac->module = module; ac->req = req; - ac->user_type = what_is_user(module); + ac->am_system = dsdb_module_am_system(module); ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes"); ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective"); ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses"); @@ -1183,7 +1175,7 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req) /* replace any attributes in the parse tree that are private, so we don't allow a search for 'userPassword=penguin', just as we would not allow that attribute to be returned */ - if (ac->user_type != SECURITY_SYSTEM) { + if (ac->am_system) { /* FIXME: We should copy the tree and keep the original unmodified. */ /* remove password attributes */ if (data && data->password_attrs) { diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 6128dc9d65..f9f1714358 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -1,9 +1,11 @@ ################################################ # Start SUBSYSTEM DSDB_MODULE_HELPERS [SUBSYSTEM::DSDB_MODULE_HELPERS] -PRIVATE_DEPENDENCIES = LIBLDB LIBNDR SAMDB_SCHEMA +PRIVATE_DEPENDENCIES = LIBLDB LIBNDR SAMDB_SCHEMA MESSAGING -DSDB_MODULE_HELPERS_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/util.o +DSDB_MODULE_HELPERS_OBJ_FILES = \ + $(dsdbsrcdir)/samdb/ldb_modules/util.o \ + $(dsdbsrcdir)/samdb/ldb_modules/ridalloc.o $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/ldb_modules/util_proto.h,$(DSDB_MODULE_HELPERS_OBJ_FILES:.o=.c))) @@ -135,13 +137,26 @@ SUBSYSTEM = LIBLDB INIT_FUNCTION = LDB_MODULE(samba3sam) PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBLDB SMBPASSWD \ NSS_WRAPPER LIBSECURITY NDR_SECURITY -# End MODULE ldb_samldb +# End MODULE ldb_samba3sam ################################################ ldb_samba3sam_OBJ_FILES = \ $(dsdbsrcdir)/samdb/ldb_modules/samba3sam.o ################################################ +# Start MODULE ldb_samba3sid +[MODULE::ldb_samba3sid] +SUBSYSTEM = LIBLDB +INIT_FUNCTION = LDB_MODULE(samba3sid) +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBLDB SMBPASSWD \ + NSS_WRAPPER LIBSECURITY NDR_SECURITY +# End MODULE ldb_samba3sid +################################################ + +ldb_samba3sid_OBJ_FILES = \ + $(dsdbsrcdir)/samdb/ldb_modules/samba3sid.o + +################################################ # Start MODULE ldb_simple_ldap_map [MODULE::ldb_simple_ldap_map] SUBSYSTEM = LIBLDB @@ -337,7 +352,7 @@ ldb_subtree_delete_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/subtree_delete.o [MODULE::ldb_linked_attributes] INIT_FUNCTION = LDB_MODULE(linked_attributes) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS SAMDB DSDB_MODULE_HELPERS SUBSYSTEM = LIBLDB # End MODULE ldb_linked_attributes ################################################ diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c index b17f40e82a..0a297d587a 100644 --- a/source4/dsdb/samdb/ldb_modules/instancetype.c +++ b/source4/dsdb/samdb/ldb_modules/instancetype.c @@ -36,6 +36,7 @@ #include "librpc/gen_ndr/ndr_misc.h" #include "dsdb/samdb/samdb.h" #include "../libds/common/flags.h" +#include "dsdb/samdb/ldb_modules/util.h" struct it_context { struct ldb_module *module; @@ -143,7 +144,7 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) ret = ldb_build_add_req(&down_req, ldb, req, msg, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); if (ret != LDB_SUCCESS) { return ret; diff --git a/source4/dsdb/samdb/ldb_modules/lazy_commit.c b/source4/dsdb/samdb/ldb_modules/lazy_commit.c index 0502b2efa1..b4eaf50d51 100644 --- a/source4/dsdb/samdb/ldb_modules/lazy_commit.c +++ b/source4/dsdb/samdb/ldb_modules/lazy_commit.c @@ -28,6 +28,7 @@ */ #include "ldb_module.h" +#include "dsdb/samdb/ldb_modules/util.h" static int unlazy_op(struct ldb_module *module, struct ldb_request *req) { @@ -47,28 +48,28 @@ static int unlazy_op(struct ldb_module *module, struct ldb_request *req) req->op.search.tree, req->op.search.attrs, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); break; case LDB_ADD: ret = ldb_build_add_req(&new_req, ldb_module_get_ctx(module), req, req->op.add.message, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); break; case LDB_MODIFY: ret = ldb_build_mod_req(&new_req, ldb_module_get_ctx(module), req, req->op.mod.message, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); break; case LDB_DELETE: ret = ldb_build_del_req(&new_req, ldb_module_get_ctx(module), req, req->op.del.dn, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); break; case LDB_RENAME: @@ -76,7 +77,7 @@ static int unlazy_op(struct ldb_module *module, struct ldb_request *req) req->op.rename.olddn, req->op.rename.newdn, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); break; case LDB_EXTENDED: @@ -85,7 +86,7 @@ static int unlazy_op(struct ldb_module *module, struct ldb_request *req) req->op.extended.oid, req->op.extended.data, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); break; default: diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 01ae0a10a7..59e7fab393 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -39,7 +39,6 @@ struct part_request { struct partition_context { struct ldb_module *module; struct ldb_request *req; - bool got_success; struct part_request *part_req; int num_requests; @@ -160,7 +159,7 @@ static int partition_req_callback(struct ldb_request *req, } } - if (ares->error != LDB_SUCCESS && !ac->got_success) { + if (ares->error != LDB_SUCCESS) { return ldb_module_done(ac->req, ares->controls, ares->response, ares->error); } @@ -182,9 +181,6 @@ static int partition_req_callback(struct ldb_request *req, return ldb_module_send_entry(ac->req, ares->message, ares->controls); case LDB_REPLY_DONE: - if (ares->error == LDB_SUCCESS) { - ac->got_success = true; - } if (ac->req->operation == LDB_EXTENDED) { /* FIXME: check for ares->response, replmd does not fill it ! */ if (ares->response) { @@ -205,7 +201,7 @@ static int partition_req_callback(struct ldb_request *req, /* this was the last one, call callback */ return ldb_module_done(ac->req, ares->controls, ares->response, - ac->got_success?LDB_SUCCESS:ares->error); + ares->error); } /* not the last, now call the next one */ @@ -528,9 +524,7 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req) */ if (ldb_dn_compare(data->partitions[i]->ctrl->dn, req->op.search.base) == 0) { match = true; - if (req->op.search.scope == LDB_SCOPE_BASE) { - stop = true; - } + stop = true; } if (!match && (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->ctrl->dn) == 0 && diff --git a/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c b/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c index 796ecaf7bc..00d9a30fd3 100644 --- a/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c +++ b/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c @@ -75,8 +75,8 @@ static int pdc_fsmo_init(struct ldb_module *module) return ldb_next_init(module); } else if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "pdc_fsmo_init: failed to search the domain object: %d:%s", - ret, ldb_strerror(ret)); + "pdc_fsmo_init: failed to search the domain object: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); talloc_free(mem_ctx); return ret; } diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 890eb91d6d..b4caac4c8d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -672,7 +672,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); if (control) { - allow_add_guid = 1; + allow_add_guid = true; } /* do not manipulate our control entries */ @@ -2667,10 +2667,12 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) break; } - DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n", - msg->elements[i-removed_attrs].name, - ldb_dn_get_linearized(msg->dn), - GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id))); + if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) { + DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n", + msg->elements[i-removed_attrs].name, + ldb_dn_get_linearized(msg->dn), + GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id))); + } /* we don't want to apply this change so remove the attribute */ ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]); diff --git a/source4/dsdb/samdb/ldb_modules/ridalloc.c b/source4/dsdb/samdb/ldb_modules/ridalloc.c new file mode 100644 index 0000000000..a64062fcdc --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/ridalloc.c @@ -0,0 +1,646 @@ +/* + RID allocation helper functions + + Copyright (C) Andrew Bartlett 2010 + Copyright (C) Andrew Tridgell 2010 + + 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 + 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/>. +*/ + +/* + * Name: ldb + * + * Component: RID allocation logic + * + * Description: manage RID Set and RID Manager objects + * + */ + +#include "includes.h" +#include "ldb_module.h" +#include "dsdb/samdb/samdb.h" +#include "dsdb/samdb/ldb_modules/util.h" +#include "lib/messaging/irpc.h" +#include "param/param.h" +#include "librpc/gen_ndr/ndr_misc.h" + +/* + Note: the RID allocation attributes in AD are very badly named. Here + is what we think they really do: + + in RID Set object: + - rIDPreviousAllocationPool: the pool which a DC is currently + pulling RIDs from. Managed by client DC + + - rIDAllocationPool: the pool that the DC will switch to next, + when rIDPreviousAllocationPool is exhausted. Managed by RID Manager. + + - rIDNextRID: the last RID allocated by this DC. Managed by client DC + + in RID Manager object: + - rIDAvailablePool: the pool where the RID Manager gets new rID + pools from when it gets a EXOP_RID_ALLOC getncchanges call (or + locally when the DC is the RID Manager) + */ + + +/* + make a IRPC call to the drepl task to ask it to get the RID + Manager to give us another RID pool. + + This function just sends the message to the drepl task then + returns immediately. It should be called well before we + completely run out of RIDs + */ +static void ridalloc_poke_rid_manager(struct ldb_module *module) +{ + struct messaging_context *msg; + struct server_id *server; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm"); + TALLOC_CTX *tmp_ctx = talloc_new(module); + + msg = messaging_client_init(tmp_ctx, lp_messaging_path(tmp_ctx, lp_ctx), + lp_iconv_convenience(lp_ctx), + ldb_get_event_context(ldb)); + if (!msg) { + DEBUG(3,(__location__ ": Failed to create messaging context\n")); + talloc_free(tmp_ctx); + return; + } + + server = irpc_servers_byname(msg, msg, "dreplsrv"); + if (!server) { + /* this means the drepl service is not running */ + talloc_free(tmp_ctx); + return; + } + + messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL); + + /* we don't care if the message got through */ + talloc_free(tmp_ctx); +} + + +/* + allocate a new range of RIDs in the RID Manager object + */ +static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool) +{ + int ret; + TALLOC_CTX *tmp_ctx = talloc_new(module); + const char *attrs[] = { "rIDAvailablePool", NULL }; + uint64_t rid_pool, new_rid_pool, dc_pool; + uint32_t rid_pool_lo, rid_pool_hi; + struct ldb_result *res; + struct ldb_context *ldb = ldb_module_get_ctx(module); + const unsigned alloc_size = 500; + + ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn, attrs, 0); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s", + ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0); + rid_pool_lo = rid_pool & 0xFFFFFFFF; + rid_pool_hi = rid_pool >> 32; + if (rid_pool_lo >= rid_pool_hi) { + ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u", + rid_pool_lo, rid_pool_hi); + talloc_free(tmp_ctx); + return ret; + } + + /* lower part of new pool is the low part of the rIDAvailablePool */ + dc_pool = rid_pool_lo; + + /* allocate 500 RIDs to this DC */ + rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size); + + /* work out upper part of new pool */ + dc_pool |= (((uint64_t)rid_pool_lo-1)<<32); + + /* and new rIDAvailablePool value */ + new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32); + + ret = dsdb_module_constrainted_update_integer(module, rid_manager_dn, "rIDAvailablePool", + rid_pool, new_rid_pool); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + (*new_pool) = dc_pool; + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + +/* + create a RID Set object for the specified DC + */ +static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx, + struct ldb_dn *rid_manager_dn, + struct ldb_dn *ntds_dn, struct ldb_dn **dn) +{ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_dn *server_dn, *machine_dn, *rid_set_dn; + int ret; + uint64_t dc_pool; + struct ldb_message *msg; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + /* + steps: + + find the machine object for the DC + construct the RID Set DN + load rIDAvailablePool to find next available set + modify RID Manager object to update rIDAvailablePool + add the RID Set object + link to the RID Set object in machine object + */ + + server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn); + if (!server_dn) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s", + ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn); + if (rid_set_dn == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* grab a pool from the RID Manager object */ + ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &dc_pool); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + /* create the RID Set object */ + msg = ldb_msg_new(tmp_ctx); + msg->dn = rid_set_dn; + + ret = ldb_msg_add_string(msg, "objectClass", "rIDSet"); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + ret = ldb_msg_add_fmt(msg, "rIDAllocationPool", "%llu", (unsigned long long)dc_pool); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + /* w2k8-r2 sets these to zero when first created */ + ret = ldb_msg_add_fmt(msg, "rIDPreviousAllocationPool", "0"); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + ret = ldb_msg_add_fmt(msg, "rIDUsedPool", "0"); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + ret = ldb_msg_add_fmt(msg, "rIDNextRID", "0"); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + /* we need this to go all the way to the top of the module + * stack, as we need all the extra attributes added (including + * complex ones like ntsecuritydescriptor) */ + ret = dsdb_module_add(module, msg, DSDB_FLAG_TOP_MODULE | DSDB_MODIFY_RELAX); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s", + ldb_dn_get_linearized(msg->dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + /* add the rIDSetReferences link */ + msg = ldb_msg_new(tmp_ctx); + msg->dn = machine_dn; + + ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_linearized(rid_set_dn)); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + msg->elements[0].flags = LDB_FLAG_MOD_ADD; + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s", + ldb_dn_get_linearized(msg->dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + (*dn) = talloc_steal(mem_ctx, rid_set_dn); + + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + +/* + create a RID Set object for this DC + */ +static int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx, + struct ldb_dn **dn) +{ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_dn *rid_manager_dn, *fsmo_role_dn; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + /* work out who is the RID Manager */ + ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + /* find the DN of the RID Manager */ + ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) { + ridalloc_poke_rid_manager(module); + ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh"); + talloc_free(tmp_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn); + talloc_free(tmp_ctx); + return ret; +} + +/* + refresh a RID Set object for the specified DC + also returns the first RID for the new pool + */ +static int ridalloc_refresh_rid_set_ntds(struct ldb_module *module, + struct ldb_dn *rid_manager_dn, + struct ldb_dn *ntds_dn, uint64_t *new_pool) +{ + TALLOC_CTX *tmp_ctx = talloc_new(module); + struct ldb_dn *server_dn, *machine_dn, *rid_set_dn; + struct ldb_context *ldb = ldb_module_get_ctx(module); + int ret; + + /* grab a pool from the RID Manager object */ + ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn); + if (!server_dn) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s", + ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s", + ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_set_integer(module, rid_set_dn, "rIDAllocationPool", *new_pool); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s", + ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + +/* + get a new RID pool for ourselves + also returns the first rid for the new pool + */ +static int ridalloc_refresh_own_pool(struct ldb_module *module, uint64_t *new_pool) +{ + TALLOC_CTX *tmp_ctx = talloc_new(module); + struct ldb_dn *rid_manager_dn, *fsmo_role_dn; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + /* work out who is the RID Manager */ + ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + /* find the DN of the RID Manager */ + ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) { + ridalloc_poke_rid_manager(module); + ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh"); + talloc_free(tmp_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, fsmo_role_dn, new_pool); + talloc_free(tmp_ctx); + return ret; +} + + +/* allocate a RID using our RID Set + If we run out of RIDs then allocate a new pool + either locally or by contacting the RID Manager +*/ +int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid) +{ + struct ldb_context *ldb; + static const char * const attrs[] = { "rIDAllocationPool", "rIDPreviousAllocationPool", + "rIDNextRID" , "rIDUsedPool", NULL }; + int ret; + struct ldb_dn *rid_set_dn; + struct ldb_result *res; + uint64_t alloc_pool, prev_alloc_pool; + uint32_t prev_alloc_pool_lo, prev_alloc_pool_hi; + uint32_t rid_used_pool; + int prev_rid; + TALLOC_CTX *tmp_ctx = talloc_new(module); + + (*rid) = 0; + ldb = ldb_module_get_ctx(module); + + ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn); + if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { + ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn); + } + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s", + ldb_dn_get_linearized(rid_set_dn)); + talloc_free(tmp_ctx); + return ret; + } + + prev_alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0); + alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0); + prev_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", 0); + rid_used_pool = ldb_msg_find_attr_as_int(res->msgs[0], "rIDUsedPool", 0); + if (alloc_pool == 0) { + ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s", + ldb_dn_get_linearized(rid_set_dn)); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF; + prev_alloc_pool_hi = prev_alloc_pool >> 32; + if (prev_rid >= prev_alloc_pool_hi) { + if (prev_alloc_pool == 0) { + ret = dsdb_module_set_integer(module, rid_set_dn, "rIDPreviousAllocationPool", alloc_pool); + } else { + ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool", + prev_alloc_pool, alloc_pool); + } + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s", + ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + prev_alloc_pool = alloc_pool; + prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF; + prev_alloc_pool_hi = prev_alloc_pool >> 32; + + /* update the rIDUsedPool attribute */ + ret = dsdb_module_set_integer(module, rid_set_dn, "rIDUsedPool", rid_used_pool+1); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDUsedPool on %s - %s", + ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + (*rid) = prev_alloc_pool_lo; + } + + /* see if we are still out of RIDs, and if so then ask + the RID Manager to give us more */ + if (prev_rid >= prev_alloc_pool_hi) { + uint64_t new_pool; + ret = ridalloc_refresh_own_pool(module, &new_pool); + if (ret != LDB_SUCCESS) { + return ret; + } + ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool", + prev_alloc_pool, new_pool); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s", + ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + prev_alloc_pool = new_pool; + prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF; + prev_alloc_pool_hi = prev_alloc_pool >> 32; + (*rid) = prev_alloc_pool_lo; + } else { + /* despite the name, rIDNextRID is the value of the last user + * added by this DC, not the next available RID */ + if (*rid == 0) { + (*rid) = prev_rid + 1; + } + } + + if (*rid < prev_alloc_pool_lo || *rid > prev_alloc_pool_hi) { + ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u", + (unsigned)*rid, (unsigned)prev_alloc_pool_lo, + (unsigned)prev_alloc_pool_hi); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* now modify the RID Set to use up this RID using a + * constrained delete/add if possible */ + if (prev_rid == 0) { + ret = dsdb_module_set_integer(module, rid_set_dn, "rIDNextRID", *rid); + } else { + ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDNextRID", prev_rid, *rid); + } + + /* if we are half-exhausted then ask the repl task to start + * getting another one */ + if (*rid > (prev_alloc_pool_hi + prev_alloc_pool_lo)/2) { + ridalloc_poke_rid_manager(module); + } + + talloc_free(tmp_ctx); + + return ret; +} + + +/* + called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb + */ +int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop) +{ + struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn; + struct ldb_dn *rid_manager_dn; + TALLOC_CTX *tmp_ctx = talloc_new(module); + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + uint64_t new_pool; + + ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n", + GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn); + if (!server_dn) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s", + ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + + ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn); + if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { + ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn); + talloc_free(tmp_ctx); + return ret; + } + + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s", + ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + if (exop->fsmo_info != 0) { + const char *attrs[] = { "rIDAllocationPool", NULL }; + struct ldb_result *res; + uint64_t alloc_pool; + + ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s", + ldb_dn_get_linearized(rid_set_dn)); + talloc_free(tmp_ctx); + return ret; + } + + alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0); + if (alloc_pool != exop->fsmo_info) { + /* it has already been updated */ + DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n", + (unsigned long long)exop->fsmo_info, + (unsigned long long)alloc_pool)); + talloc_free(tmp_ctx); + return LDB_SUCCESS; + } + } + + ret = ridalloc_refresh_rid_set_ntds(module, rid_manager_dn, ntds_dn, &new_pool); + talloc_free(tmp_ctx); + return ret; +} diff --git a/source4/dsdb/samdb/ldb_modules/samba3sid.c b/source4/dsdb/samdb/ldb_modules/samba3sid.c new file mode 100644 index 0000000000..76848eb258 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/samba3sid.c @@ -0,0 +1,197 @@ +/* + samba3sid module + + Copyright (C) Andrew Bartlett 2010 + Copyright (C) Andrew Tridgell 2010 + + 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 + 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/>. +*/ + +/* + add objectSID to users and groups using samba3 nextRid method + */ + +#include "includes.h" +#include "libcli/ldap/ldap_ndr.h" +#include "ldb_module.h" +#include "dsdb/samdb/samdb.h" +#include "dsdb/samdb/ldb_modules/util.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "../lib/util/util_ldb.h" +#include "ldb_wrap.h" +#include "param/param.h" + +/* + RID algorithm from pdb_ldap.c in source3/passdb/ + (loosely based on Volkers code) + */ +static int samba3sid_next_sid(struct ldb_module *module, + TALLOC_CTX *mem_ctx, char **sid) +{ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_result *res; + const char *attrs[] = { "sambaNextRid", "sambaNextUserRid", + "sambaNextGroupRid", "sambaSID", NULL }; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + int sambaNextRid, sambaNextGroupRid, sambaNextUserRid; + struct ldb_message *msg; + int rid; + const char *sambaSID; + + ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, + attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, + "(&(objectClass=sambaDomain)(sambaDomainName=%s))", + lp_sam_name(ldb_get_opaque(ldb, "loadparm"))); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + __location__ + ": Failed to find domain object - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + if (res->count != 1) { + ldb_asprintf_errstring(ldb, + __location__ + ": Expected exactly 1 domain object - got %u", + res->count); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + msg = res->msgs[0]; + + sambaNextRid = ldb_msg_find_attr_as_uint(msg, "sambaNextRid", -1); + sambaNextUserRid = ldb_msg_find_attr_as_uint(msg, "sambaNextUserRid", -1); + sambaNextGroupRid = ldb_msg_find_attr_as_uint(msg, "sambaNextGroupRid", -1); + sambaSID = ldb_msg_find_attr_as_string(msg, "sambaSID", NULL); + + if (sambaSID == NULL) { + ldb_asprintf_errstring(ldb, + __location__ + ": No sambaSID in %s", + ldb_dn_get_linearized(msg->dn)); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* choose the highest of the 3 - see pdb_ldap.c for an + * explanation */ + rid = sambaNextRid; + if (sambaNextUserRid > rid) { + rid = sambaNextUserRid; + } + if (sambaNextGroupRid > rid) { + rid = sambaNextGroupRid; + } + if (rid == -1) { + ldb_asprintf_errstring(ldb, + __location__ + ": No sambaNextRid in %s", + ldb_dn_get_linearized(msg->dn)); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* sambaNextRid is actually the previous RID .... */ + rid += 1; + + (*sid) = talloc_asprintf(tmp_ctx, "%s-%d", sambaSID, rid); + if (!*sid) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_module_constrainted_update_integer(module, msg->dn, + "sambaNextRid", + sambaNextRid, rid); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + __location__ + ": Failed to update sambaNextRid - %s", + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + talloc_steal(mem_ctx, *sid); + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + + +/* add */ +static int samba3sid_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb; + int ret; + const struct ldb_message *msg = req->op.add.message; + struct ldb_message *new_msg; + char *sid; + struct ldb_request *new_req; + + ldb = ldb_module_get_ctx(module); + + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.add.message->dn)) { + return ldb_next_request(module, req); + } + + if (!samdb_find_attribute(ldb, msg, "objectclass", "posixAccount") && + !samdb_find_attribute(ldb, msg, "objectclass", "posixGroup")) { + /* its not a user or a group */ + return ldb_next_request(module, req); + } + + if (ldb_msg_find_element(msg, "sambaSID")) { + /* a SID was supplied */ + return ldb_next_request(module, req); + } + + new_msg = ldb_msg_copy_shallow(req, req->op.add.message); + if (!new_msg) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = samba3sid_next_sid(module, new_msg, &sid); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_msg_add_steal_string(new_msg, "sambaSID", sid); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_add_req(&new_req, ldb, req, + new_msg, + req->controls, + req, dsdb_next_callback, + req); + if (ret != LDB_SUCCESS) { + return ret; + } + + return ldb_next_request(module, new_req); +} + +_PUBLIC_ const struct ldb_module_ops ldb_samba3sid_module_ops = { + .name = "samba3sid", + .add = samba3sid_add, +}; + diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c index a461a94806..44526128f1 100644 --- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c +++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c @@ -138,53 +138,6 @@ static int prepare_modules_line(struct ldb_context *ldb, -/* - initialise the invocationID for a standalone server - */ -static int initialise_invocation_id(struct ldb_module *module, struct GUID *guid) -{ - struct ldb_message *msg; - struct ldb_context *ldb = ldb_module_get_ctx(module); - int ret; - - *guid = GUID_random(); - - msg = ldb_msg_new(module); - if (msg == NULL) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - msg->dn = ldb_dn_new(msg, ldb, "@SAMBA_DSDB"); - if (!msg->dn) { - ldb_module_oom(module); - talloc_free(msg); - return LDB_ERR_OPERATIONS_ERROR; - } - ret = dsdb_msg_add_guid(msg, guid, "invocationID"); - if (ret != LDB_SUCCESS) { - ldb_module_oom(module); - talloc_free(msg); - return ret; - } - msg->elements[0].flags = LDB_FLAG_MOD_ADD; - - ret = ldb_modify(ldb, msg); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, "Failed to setup standalone invocationID - %s", - ldb_errstring(ldb)); - talloc_free(msg); - return ret; - } - - DEBUG(1,("Initialised standalone invocationID to %s\n", - GUID_string(msg, guid))); - - talloc_free(msg); - - return LDB_SUCCESS; -} - - static int samba_dsdb_init(struct ldb_module *module) { struct ldb_context *ldb = ldb_module_get_ctx(module); @@ -258,7 +211,7 @@ static int samba_dsdb_init(struct ldb_module *module) static const char *openldap_backend_modules[] = { "entryuuid", "paged_searches", NULL }; - static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", "invocationID", NULL }; + static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", NULL }; const char *backendType, *serverRole; if (!tmp_ctx) { @@ -293,34 +246,6 @@ static int samba_dsdb_init(struct ldb_module *module) return ret; } - if (strcmp(serverRole, "standalone") == 0 || - strcmp(serverRole, "member server") == 0) { - struct GUID *guid; - - guid = talloc(module, struct GUID); - if (!guid) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - - *guid = samdb_result_guid(res->msgs[0], "invocationID"); - if (GUID_all_zero(guid)) { - ret = initialise_invocation_id(module, guid); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - } - - /* cache the domain_sid in the ldb. See the matching - * code in samdb_ntds_invocation_id() */ - ret = ldb_set_opaque(ldb, "cache.invocation_id", guid); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - } - backend_modules = NULL; if (strcasecmp(backendType, "ldb") == 0) { extended_dn_module = extended_dn_module_ldb; diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 17a99c74c7..ccf76aaef2 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -59,12 +59,6 @@ struct samldb_ctx { /* the resulting message */ struct ldb_message *msg; - /* used to find parent domain */ - struct ldb_dn *check_dn; - struct ldb_dn *domain_dn; - struct dom_sid *domain_sid; - uint32_t next_rid; - /* holds the entry SID */ struct dom_sid *sid; @@ -175,139 +169,6 @@ static int samldb_next_step(struct samldb_ctx *ac) } } -/* - * samldb_get_parent_domain (async) - */ - -static int samldb_get_parent_domain(struct samldb_ctx *ac); - -static int samldb_get_parent_domain_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct ldb_context *ldb; - struct samldb_ctx *ac; - const char *nextRid; - int ret; - - ac = talloc_get_type(req->context, struct samldb_ctx); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - switch (ares->type) { - case LDB_REPLY_ENTRY: - /* save entry */ - if ((ac->domain_dn != NULL) || (ac->domain_sid != NULL)) { - /* one too many! */ - ldb_set_errstring(ldb, - "Invalid number of results while searching " - "for domain object!"); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - nextRid = ldb_msg_find_attr_as_string(ares->message, - "nextRid", NULL); - if (nextRid == NULL) { - ldb_asprintf_errstring(ldb, - "While looking for domain above %s attribute nextRid not found in %s!", - ldb_dn_get_linearized( - ac->req->op.add.message->dn), - ldb_dn_get_linearized(ares->message->dn)); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - ac->next_rid = strtol(nextRid, NULL, 0); - - ac->domain_sid = samdb_result_dom_sid(ac, ares->message, - "objectSid"); - if (ac->domain_sid == NULL) { - ldb_set_errstring(ldb, - "Unable to get the parent domain SID!"); - ret = LDB_ERR_CONSTRAINT_VIOLATION; - break; - } - ac->domain_dn = ldb_dn_copy(ac, ares->message->dn); - - talloc_free(ares); - ret = LDB_SUCCESS; - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - talloc_free(ares); - ret = LDB_SUCCESS; - break; - - case LDB_REPLY_DONE: - talloc_free(ares); - if ((ac->domain_dn == NULL) || (ac->domain_sid == NULL)) { - /* not found -> retry */ - ret = samldb_get_parent_domain(ac); - } else { - /* found, go on */ - ret = samldb_next_step(ac); - } - break; - } - -done: - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - - return LDB_SUCCESS; -} - -/* Find a domain object in the parents of a particular DN. */ -static int samldb_get_parent_domain(struct samldb_ctx *ac) -{ - struct ldb_context *ldb; - static const char * const attrs[] = { "objectSid", "nextRid", NULL }; - struct ldb_request *req; - struct ldb_dn *dn; - int ret; - - ldb = ldb_module_get_ctx(ac->module); - - if (ac->check_dn == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - dn = ldb_dn_get_parent(ac, ac->check_dn); - if (dn == NULL) { - ldb_set_errstring(ldb, - "Unable to find parent domain object!"); - return LDB_ERR_CONSTRAINT_VIOLATION; - } - - ac->check_dn = dn; - - ret = ldb_build_search_req(&req, ldb, ac, - dn, LDB_SCOPE_BASE, - "(|(objectClass=domain)" - "(objectClass=builtinDomain))", - attrs, - NULL, - ac, samldb_get_parent_domain_callback, - ac->req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - return ldb_next_request(ac->module, req); -} - - static int samldb_generate_samAccountName(struct ldb_message *msg) { char *name; @@ -395,7 +256,7 @@ static int samldb_check_samAccountName(struct samldb_ctx *ac) } ret = ldb_build_search_req(&req, ldb, ac, - ac->domain_dn, LDB_SCOPE_SUBTREE, + samdb_base_dn(ldb), LDB_SCOPE_SUBTREE, filter, NULL, NULL, ac, samldb_check_samAccountName_callback, @@ -464,134 +325,45 @@ static int samldb_check_samAccountType(struct samldb_ctx *ac) return samldb_next_step(ac); } - -/* - * samldb_get_sid_domain (async) - */ - -static int samldb_get_sid_domain_callback(struct ldb_request *req, - struct ldb_reply *ares) +static bool samldb_msg_add_sid(struct ldb_message *msg, + const char *name, + const struct dom_sid *sid) { - struct ldb_context *ldb; - struct samldb_ctx *ac; - const char *nextRid; - int ret; - - ac = talloc_get_type(req->context, struct samldb_ctx); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - switch (ares->type) { - case LDB_REPLY_ENTRY: - /* save entry */ - if (ac->next_rid != 0) { - /* one too many! */ - ldb_set_errstring(ldb, - "Invalid number of results while searching " - "for domain object!"); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - nextRid = ldb_msg_find_attr_as_string(ares->message, - "nextRid", NULL); - if (nextRid == NULL) { - ldb_asprintf_errstring(ldb, - "Attribute nextRid not found in %s!", - ldb_dn_get_linearized(ares->message->dn)); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - ac->next_rid = strtol(nextRid, NULL, 0); - - ac->domain_dn = ldb_dn_copy(ac, ares->message->dn); - - talloc_free(ares); - ret = LDB_SUCCESS; - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - talloc_free(ares); - ret = LDB_SUCCESS; - break; - - case LDB_REPLY_DONE: - talloc_free(ares); - if (ac->next_rid == 0) { - ldb_asprintf_errstring(ldb, - "Unable to get nextRid from domain entry!"); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - /* found, go on */ - ret = samldb_next_step(ac); - break; - } + struct ldb_val v; + enum ndr_err_code ndr_err; -done: - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); + ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid, + (ndr_push_flags_fn_t)ndr_push_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return false; } - - return LDB_SUCCESS; + return (ldb_msg_add_value(msg, name, &v, NULL) == 0); } -/* Find a domain object in the parents of a particular DN. */ -static int samldb_get_sid_domain(struct samldb_ctx *ac) + +/* allocate a SID using our RID Set */ +static int samldb_allocate_sid(struct samldb_ctx *ac) { - struct ldb_context *ldb; - static const char * const attrs[] = { "nextRid", NULL }; - struct ldb_request *req; - char *filter; + uint32_t rid; int ret; + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); - ldb = ldb_module_get_ctx(ac->module); - - if (ac->sid == NULL) { - return LDB_ERR_OPERATIONS_ERROR; + ret = ridalloc_allocate_rid(ac->module, &rid); + if (ret != LDB_SUCCESS) { + return ret; } - ac->domain_sid = dom_sid_dup(ac, ac->sid); - if (!ac->domain_sid) { + ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid); + if (ac->sid == NULL) { + ldb_module_oom(ac->module); return LDB_ERR_OPERATIONS_ERROR; } - /* get the domain component part of the provided SID */ - ac->domain_sid->num_auths--; - filter = talloc_asprintf(ac, - "(&(objectSid=%s)" - "(|(objectClass=domain)" - "(objectClass=builtinDomain)))", - ldap_encode_ndr_dom_sid(ac, ac->domain_sid)); - if (filter == NULL) { + if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) { return LDB_ERR_OPERATIONS_ERROR; } - ret = ldb_build_search_req(&req, ldb, ac, - ldb_get_default_basedn(ldb), - LDB_SCOPE_SUBTREE, - filter, attrs, - NULL, - ac, samldb_get_sid_domain_callback, - ac->req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - ac->next_rid = 0; - return ldb_next_request(ac->module, req); + return samldb_next_step(ac); } /* @@ -722,161 +494,6 @@ static int samldb_check_primaryGroupID_2(struct samldb_ctx *ac) } -static bool samldb_msg_add_sid(struct ldb_message *msg, - const char *name, - const struct dom_sid *sid) -{ - struct ldb_val v; - enum ndr_err_code ndr_err; - - ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid, - (ndr_push_flags_fn_t)ndr_push_dom_sid); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return false; - } - return (ldb_msg_add_value(msg, name, &v, NULL) == 0); -} - -static int samldb_new_sid(struct samldb_ctx *ac) -{ - - if (ac->domain_sid == NULL || ac->next_rid == 0) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1); - if (ac->sid == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - return samldb_next_step(ac); -} - -/* - * samldb_notice_sid_callback (async) - */ - -static int samldb_notice_sid_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct ldb_context *ldb; - struct samldb_ctx *ac; - int ret; - - ac = talloc_get_type(req->context, struct samldb_ctx); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "Invalid reply type!"); - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; - } - - ret = samldb_next_step(ac); - -done: - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - - return LDB_SUCCESS; -} - -/* If we are adding new users/groups, we need to update the nextRid - * attribute to be 'above' the new/incoming RID. Attempt to do it - * atomically. */ -static int samldb_notice_sid(struct samldb_ctx *ac) -{ - struct ldb_context *ldb; - uint32_t old_id, new_id; - struct ldb_request *req; - struct ldb_message *msg; - struct ldb_message_element *els; - struct ldb_val *vals; - int ret; - - ldb = ldb_module_get_ctx(ac->module); - old_id = ac->next_rid; - new_id = ac->sid->sub_auths[ac->sid->num_auths - 1]; - - if (old_id >= new_id) { - /* no need to update the domain nextRid attribute */ - return samldb_next_step(ac); - } - - /* we do a delete and add as a single operation. That prevents - a race, in case we are not actually on a transaction db */ - msg = ldb_msg_new(ac); - if (msg == NULL) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - els = talloc_array(msg, struct ldb_message_element, 2); - if (els == NULL) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - vals = talloc_array(msg, struct ldb_val, 2); - if (vals == NULL) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - msg->dn = ac->domain_dn; - msg->num_elements = 2; - msg->elements = els; - - els[0].num_values = 1; - els[0].values = &vals[0]; - els[0].flags = LDB_FLAG_MOD_DELETE; - els[0].name = talloc_strdup(msg, "nextRid"); - if (!els[0].name) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - els[1].num_values = 1; - els[1].values = &vals[1]; - els[1].flags = LDB_FLAG_MOD_ADD; - els[1].name = els[0].name; - - vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id); - if (!vals[0].data) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - vals[0].length = strlen((char *)vals[0].data); - - vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id); - if (!vals[1].data) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - vals[1].length = strlen((char *)vals[1].data); - - ret = ldb_build_mod_req(&req, ldb, ac, - msg, NULL, - ac, samldb_notice_sid_callback, - ac->req); - if (ret != LDB_SUCCESS) { - return ret; - } - - return ldb_next_request(ac->module, req); -} - /* * samldb_set_defaultObjectCategory_callback (async) */ @@ -1142,11 +759,6 @@ static int samldb_fill_object(struct samldb_ctx *ac, const char *type) ldb = ldb_module_get_ctx(ac->module); - /* search for a parent domain objet */ - ac->check_dn = ac->req->op.add.message->dn; - ret = samldb_add_step(ac, samldb_get_parent_domain); - if (ret != LDB_SUCCESS) return ret; - /* Add informations for the different account types */ ac->type = type; if (strcmp(ac->type, "user") == 0) { @@ -1174,9 +786,11 @@ static int samldb_fill_object(struct samldb_ctx *ac, const char *type) ret = samdb_find_or_add_attribute(ldb, ac->msg, "pwdLastSet", "0"); if (ret != LDB_SUCCESS) return ret; - ret = samdb_find_or_add_attribute(ldb, ac->msg, - "primaryGroupID", "513"); - if (ret != LDB_SUCCESS) return ret; + if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) { + ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, + "primaryGroupID", DOMAIN_RID_USERS); + if (ret != LDB_SUCCESS) return ret; + } ret = samdb_find_or_add_attribute(ldb, ac->msg, "accountExpires", "9223372036854775807"); if (ret != LDB_SUCCESS) return ret; @@ -1287,20 +901,21 @@ static int samldb_fill_object(struct samldb_ctx *ac, const char *type) lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context); - sid_generator = lp_sid_generator(lp_ctx); - if (sid_generator == SID_GENERATOR_INTERNAL) { - /* check if we have a valid SID */ - ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid"); - if ( ! ac->sid) { - ret = samldb_add_step(ac, samldb_new_sid); - if (ret != LDB_SUCCESS) return ret; - } else { - ret = samldb_add_step(ac, samldb_get_sid_domain); + /* don't allow objectSID to be specified without the RELAX control */ + ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid"); + if (ac->sid && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) && + !dsdb_module_am_system(ac->module)) { + ldb_asprintf_errstring(ldb, "No SID may be specified in user/group creation for %s", + ldb_dn_get_linearized(ac->msg->dn)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + if ( ! ac->sid) { + sid_generator = lp_sid_generator(lp_ctx); + if (sid_generator == SID_GENERATOR_INTERNAL) { + ret = samldb_add_step(ac, samldb_allocate_sid); if (ret != LDB_SUCCESS) return ret; } - - ret = samldb_add_step(ac, samldb_notice_sid); - if (ret != LDB_SUCCESS) return ret; } /* finally proceed with adding the entry */ @@ -1310,144 +925,6 @@ static int samldb_fill_object(struct samldb_ctx *ac, const char *type) return samldb_first_step(ac); } -/* - * samldb_foreign_notice_sid (async) - */ - -static int samldb_foreign_notice_sid_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct ldb_context *ldb; - struct samldb_ctx *ac; - const char *nextRid; - const char *name; - int ret; - - ac = talloc_get_type(req->context, struct samldb_ctx); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - switch (ares->type) { - case LDB_REPLY_ENTRY: - /* save entry */ - if (ac->next_rid != 0) { - /* one too many! */ - ldb_set_errstring(ldb, - "Invalid number of results while searching " - "for domain object!"); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - nextRid = ldb_msg_find_attr_as_string(ares->message, - "nextRid", NULL); - if (nextRid == NULL) { - ldb_asprintf_errstring(ldb, - "While looking for foreign SID %s attribute nextRid not found in %s", - dom_sid_string(ares, ac->sid), - ldb_dn_get_linearized(ares->message->dn)); - ret = LDB_ERR_OPERATIONS_ERROR; - break; - } - - ac->next_rid = strtol(nextRid, NULL, 0); - - ac->domain_dn = ldb_dn_copy(ac, ares->message->dn); - - name = samdb_result_string(ares->message, "name", NULL); - ldb_debug(ldb, LDB_DEBUG_TRACE, - "NOTE (strange but valid): Adding foreign SID " - "record with SID %s, but this domain (%s) is " - "not foreign in the database\n", - dom_sid_string(ares, ac->sid), name); - - talloc_free(ares); - ret = LDB_SUCCESS; - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - talloc_free(ares); - ret = LDB_SUCCESS; - break; - - case LDB_REPLY_DONE: - talloc_free(ares); - - /* if this is a fake foreign SID, notice the SID */ - if (ac->domain_dn) { - ret = samldb_notice_sid(ac); - break; - } - - /* found, go on */ - ret = samldb_next_step(ac); - break; - } - -done: - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - - return LDB_SUCCESS; -} - -/* Find a domain object in the parents of a particular DN. */ -static int samldb_foreign_notice_sid(struct samldb_ctx *ac) -{ - struct ldb_context *ldb; - static const char * const attrs[3] = { "nextRid", "name", NULL }; - struct ldb_request *req; - NTSTATUS status; - char *filter; - int ret; - - ldb = ldb_module_get_ctx(ac->module); - - if (ac->sid == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL); - if (!NT_STATUS_IS_OK(status)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - - filter = talloc_asprintf(ac, - "(&(objectSid=%s)" - "(|(objectClass=domain)" - "(objectClass=builtinDomain)))", - ldap_encode_ndr_dom_sid(ac, ac->domain_sid)); - if (filter == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_build_search_req(&req, ldb, ac, - ldb_get_default_basedn(ldb), - LDB_SCOPE_SUBTREE, - filter, attrs, - NULL, - ac, samldb_foreign_notice_sid_callback, - ac->req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - return ldb_next_request(ac->module, req); -} - - static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac) { struct ldb_context *ldb; @@ -1455,8 +932,6 @@ static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac) ldb = ldb_module_get_ctx(ac->module); - ac->next_rid = 0; - ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid"); if (ac->sid == NULL) { ac->sid = dom_sid_parse_talloc(ac->msg, @@ -1474,10 +949,6 @@ static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac) } } - /* check if we need to notice this SID */ - ret = samldb_add_step(ac, samldb_foreign_notice_sid); - if (ret != LDB_SUCCESS) return ret; - /* finally proceed with adding the entry */ ret = samldb_add_step(ac, samldb_add_entry); if (ret != LDB_SUCCESS) return ret; @@ -2313,6 +1784,20 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) el2->flags = LDB_FLAG_MOD_REPLACE; } + el = ldb_msg_find_element(req->op.mod.message, "primaryGroupID"); + if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) { + struct samldb_ctx *ac; + + ac = samldb_ctx_init(module, req); + if (ac == NULL) + return LDB_ERR_OPERATIONS_ERROR; + + req->op.mod.message = ac->msg = ldb_msg_copy_shallow(req, + req->op.mod.message); + + return samldb_prim_group_change(ac); + } + el = ldb_msg_find_element(req->op.mod.message, "userAccountControl"); if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) { uint32_t user_account_control; @@ -2340,21 +1825,18 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) } el2 = ldb_msg_find_element(msg, "isCriticalSystemObject"); el2->flags = LDB_FLAG_MOD_REPLACE; - } - } - - el = ldb_msg_find_element(req->op.mod.message, "primaryGroupID"); - if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) { - struct samldb_ctx *ac; - ac = samldb_ctx_init(module, req); - if (ac == NULL) - return LDB_ERR_OPERATIONS_ERROR; - - req->op.mod.message = ac->msg = ldb_msg_copy_shallow(req, - req->op.mod.message); - - return samldb_prim_group_change(ac); + /* DCs have primaryGroupID of DOMAIN_RID_DCS */ + if (!ldb_msg_find_element(msg, "primaryGroupID")) { + ret = samdb_msg_add_uint(ldb, msg, msg, + "primaryGroupID", DOMAIN_RID_DCS); + if (ret != LDB_SUCCESS) { + return ret; + } + el2 = ldb_msg_find_element(msg, "primaryGroupID"); + el2->flags = LDB_FLAG_MOD_REPLACE; + } + } } el = ldb_msg_find_element(req->op.mod.message, "member"); @@ -2392,17 +1874,41 @@ static int samldb_delete(struct ldb_module *module, struct ldb_request *req) return samldb_prim_group_users_check(ac); } +static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_fsmo_extended_op *exop; + int ret; + + exop = talloc_get_type(req->op.extended.data, struct dsdb_fsmo_extended_op); + if (!exop) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "samldb_extended_allocate_rid_pool: invalid extended data\n"); + return LDB_ERR_PROTOCOL_ERROR; + } + + ret = ridalloc_allocate_rid_pool_fsmo(module, exop); + if (ret != LDB_SUCCESS) { + return ret; + } + + return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); +} -static int samldb_init(struct ldb_module *module) +static int samldb_extended(struct ldb_module *module, struct ldb_request *req) { - return ldb_next_init(module); + if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) { + return samldb_extended_allocate_rid_pool(module, req); + } + + return ldb_next_request(module, req); } + _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = { .name = "samldb", - .init_context = samldb_init, .add = samldb_add, .modify = samldb_modify, - .del = samldb_delete + .del = samldb_delete, + .extended = samldb_extended }; diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index 2e99113953..8125a46cbb 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -290,6 +290,11 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) } } + /* bypass further processing if CONTROL_RELAX is set */ + if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) { + return ldb_next_request(module, req); + } + /* generate and add msDS-IntId attr value */ if (attributeID && (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2003) diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c index c72911fe89..6c11df21ce 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_load.c +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -181,8 +181,8 @@ static int schema_load_init(struct ldb_module *module) ret = dsdb_set_schema(ldb, schema); if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "schema_load_init: dsdb_set_schema() failed: %d:%s", - ret, ldb_strerror(ret)); + "schema_load_init: dsdb_set_schema() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); talloc_free(mem_ctx); return ret; } @@ -240,8 +240,8 @@ static int schema_load_extended(struct ldb_module *module, struct ldb_request *r ret = dsdb_set_schema(ldb, schema); if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "schema_load_extended: dsdb_set_schema() failed: %d:%s", - ret, ldb_strerror(ret)); + "schema_load_extended: dsdb_set_schema() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); talloc_free(mem_ctx); return ret; } diff --git a/source4/dsdb/samdb/ldb_modules/show_deleted.c b/source4/dsdb/samdb/ldb_modules/show_deleted.c index 666d28053c..93463ae95f 100644 --- a/source4/dsdb/samdb/ldb_modules/show_deleted.c +++ b/source4/dsdb/samdb/ldb_modules/show_deleted.c @@ -32,7 +32,7 @@ #include "includes.h" #include "ldb/include/ldb_module.h" #include "dsdb/samdb/samdb.h" - +#include "dsdb/samdb/ldb_modules/util.h" static int show_deleted_search(struct ldb_module *module, struct ldb_request *req) { @@ -83,7 +83,7 @@ static int show_deleted_search(struct ldb_module *module, struct ldb_request *re new_tree, req->op.search.attrs, req->controls, - req->context, req->callback, + req, dsdb_next_callback, req); if (ret != LDB_SUCCESS) { return ret; diff --git a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py index 2478043eb4..cc1a86ed4a 100644 --- a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py +++ b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py @@ -29,6 +29,8 @@ from samba import Ldb, substitute_var from samba.tests import LdbTestCase, TestCaseInTempDir, cmdline_loadparm import samba.dcerpc.security import samba.ndr +from samba.auth import system_session +from samba import param datadir = os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3") @@ -49,7 +51,7 @@ class MapBaseTestCase(TestCaseInTempDir): "@TO": "sambaDomainName=TESTS," + s3.basedn}) ldb.add({"dn": "@MODULES", - "@LIST": "rootdse,paged_results,server_sort,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,partition"}) + "@LIST": "rootdse,paged_results,server_sort,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,samba3sid,partition"}) ldb.add({"dn": "@PARTITION", "partition": ["%s" % (s4.basedn_casefold), @@ -58,6 +60,9 @@ class MapBaseTestCase(TestCaseInTempDir): "modules": "*:"}) def setUp(self): + cmdline_loadparm.set("sid generator", "backend") + cmdline_loadparm.set("workgroup", "TESTS") + cmdline_loadparm.set("netbios name", "TESTS") super(MapBaseTestCase, self).setUp() def make_dn(basedn, rdn): @@ -75,7 +80,7 @@ class MapBaseTestCase(TestCaseInTempDir): """Simple helper class that contains data for a specific SAM connection.""" def __init__(self, basedn, dn): - self.db = Ldb(lp=cmdline_loadparm) + self.db = Ldb(lp=cmdline_loadparm, session_info=system_session()) self.basedn = basedn self.basedn_casefold = ldb.Dn(self.db, basedn).get_casefold() self.substvars = {"BASEDN": self.basedn} @@ -124,13 +129,13 @@ class Samba3SamTestCase(MapBaseTestCase): def setUp(self): super(Samba3SamTestCase, self).setUp() - ldb = Ldb(self.ldburl, lp=cmdline_loadparm) + ldb = Ldb(self.ldburl, lp=cmdline_loadparm, session_info=system_session()) self.samba3.setup_data("samba3.ldif") ldif = read_datafile("provision_samba3sam.ldif") ldb.add_ldif(self.samba4.subst(ldif)) self.setup_modules(ldb, self.samba3, self.samba4) del ldb - self.ldb = Ldb(self.ldburl, lp=cmdline_loadparm) + self.ldb = Ldb(self.ldburl, lp=cmdline_loadparm, session_info=system_session()) def test_search_non_mapped(self): """Looking up by non-mapped attribute""" @@ -291,12 +296,12 @@ class MapTestCase(MapBaseTestCase): def setUp(self): super(MapTestCase, self).setUp() - ldb = Ldb(self.ldburl, lp=cmdline_loadparm) + ldb = Ldb(self.ldburl, lp=cmdline_loadparm, session_info=system_session()) ldif = read_datafile("provision_samba3sam.ldif") ldb.add_ldif(self.samba4.subst(ldif)) self.setup_modules(ldb, self.samba3, self.samba4) del ldb - self.ldb = Ldb(self.ldburl, lp=cmdline_loadparm) + self.ldb = Ldb(self.ldburl, lp=cmdline_loadparm, session_info=system_session()) def test_map_search(self): """Running search tests on mapped data.""" diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index 32b79a6701..46252cb279 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -26,6 +26,7 @@ #include "dsdb/samdb/ldb_modules/util.h" #include "dsdb/samdb/samdb.h" #include "util.h" +#include "libcli/security/security.h" /* add a set of controls to a ldb_request structure based on a set of @@ -214,6 +215,8 @@ int dsdb_module_search(struct ldb_module *module, if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { const struct ldb_module_ops *ops = ldb_module_get_ops(module); ret = ops->search(module, req); + } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { + ret = ldb_request(ldb_module_get_ctx(module), req); } else { ret = ldb_next_request(module, req); } @@ -332,6 +335,8 @@ int dsdb_module_modify(struct ldb_module *module, if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { const struct ldb_module_ops *ops = ldb_module_get_ops(module); ret = ops->modify(module, mod_req); + } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { + ret = ldb_request(ldb_module_get_ctx(module), mod_req); } else { ret = ldb_next_request(module, mod_req); } @@ -380,6 +385,8 @@ int dsdb_module_rename(struct ldb_module *module, if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { const struct ldb_module_ops *ops = ldb_module_get_ops(module); ret = ops->rename(module, req); + } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { + ret = ldb_request(ldb_module_get_ctx(module), req); } else { ret = ldb_next_request(module, req); } @@ -391,6 +398,54 @@ int dsdb_module_rename(struct ldb_module *module, return ret; } +/* + a ldb_add request operating on modules below the + current module + */ +int dsdb_module_add(struct ldb_module *module, + const struct ldb_message *message, + uint32_t dsdb_flags) +{ + struct ldb_request *req; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + TALLOC_CTX *tmp_ctx = talloc_new(module); + + ret = ldb_build_add_req(&req, ldb, tmp_ctx, + message, + NULL, + NULL, + ldb_op_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_request_add_controls(module, req, dsdb_flags); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + /* Run the new request */ + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->add(module, req); + } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { + ret = ldb_request(ldb_module_get_ctx(module), req); + } else { + ret = ldb_next_request(module, req); + } + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(tmp_ctx); + return ret; +} + + const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element) { const struct dsdb_class *last_class = NULL; @@ -446,3 +501,140 @@ int dsdb_check_single_valued_link(const struct dsdb_attribute *attr, return LDB_SUCCESS; } + + +/* + find a 'reference' DN that points at another object + (eg. serverReference, rIDManagerReference etc) + */ +int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base, + const char *attribute, struct ldb_dn **dn) +{ + const char *attrs[2]; + struct ldb_result *res; + int ret; + + attrs[0] = attribute; + attrs[1] = NULL; + + ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + + *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module), + mem_ctx, res->msgs[0], attribute); + if (!*dn) { + talloc_free(res); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + + talloc_free(res); + return LDB_SUCCESS; +} + +/* + find the RID Manager$ DN via the rIDManagerReference attribute in the + base DN + */ +int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn) +{ + return dsdb_module_reference_dn(module, mem_ctx, + samdb_base_dn(ldb_module_get_ctx(module)), + "rIDManagerReference", dn); +} + + +/* + update an integer attribute safely via a constrained delete/add + */ +int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn, + const char *attr, uint64_t old_val, uint64_t new_val) +{ + struct ldb_message *msg; + struct ldb_message_element *el; + struct ldb_val v1, v2; + int ret; + char *vstring; + + msg = ldb_msg_new(module); + msg->dn = dn; + + ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el); + if (ret != LDB_SUCCESS) { + talloc_free(msg); + return ret; + } + el->num_values = 1; + el->values = &v1; + vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val); + if (!vstring) { + ldb_module_oom(module); + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + v1 = data_blob_string_const(vstring); + + ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el); + if (ret != LDB_SUCCESS) { + talloc_free(msg); + return ret; + } + el->num_values = 1; + el->values = &v2; + vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val); + if (!vstring) { + ldb_module_oom(module); + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + v2 = data_blob_string_const(vstring); + + ret = dsdb_module_modify(module, msg, 0); + talloc_free(msg); + return ret; +} + +/* + used to chain to the callers callback + */ +int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request); + + talloc_steal(up_req, req); + return up_req->callback(up_req, ares); +} + + +/* + set an integer attribute + */ +int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn, + const char *attr, uint64_t new_val) +{ + struct ldb_message *msg; + int ret; + + msg = ldb_msg_new(module); + msg->dn = dn; + + ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val); + if (ret != LDB_SUCCESS) { + talloc_free(msg); + return ret; + } + msg->elements[0].flags = LDB_FLAG_MOD_REPLACE; + + ret = dsdb_module_modify(module, msg, 0); + talloc_free(msg); + return ret; +} + +bool dsdb_module_am_system(struct ldb_module *module) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct auth_session_info *session_info + = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); + return security_session_user_level(session_info) == SECURITY_SYSTEM; +} diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index add39e110a..53ed9bd48e 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -19,9 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -struct dsdb_schema; /* predeclare schema struct */ +/* predeclare some structures used by utility functions */ +struct dsdb_schema; struct GUID; struct dsdb_attribute; +struct dsdb_fsmo_extended_op; #include "dsdb/samdb/ldb_modules/util_proto.h" @@ -32,3 +34,4 @@ struct dsdb_attribute; #define DSDB_SEARCH_SHOW_EXTENDED_DN 0x0010 #define DSDB_MODIFY_RELAX 0x0020 #define DSDB_FLAG_OWN_MODULE 0x0040 +#define DSDB_FLAG_TOP_MODULE 0x0080 |