mirror of
https://github.com/samba-team/samba.git
synced 2025-08-04 08:22:08 +03:00
Owner and group defaulting.
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
committed by
Andrew Bartlett
parent
fec33db90e
commit
d70e171719
@ -50,7 +50,7 @@ struct security_descriptor *security_descriptor_initialise(TALLOC_CTX *mem_ctx)
|
|||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
|
struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
|
||||||
const struct security_acl *oacl)
|
const struct security_acl *oacl)
|
||||||
{
|
{
|
||||||
struct security_acl *nacl;
|
struct security_acl *nacl;
|
||||||
|
@ -61,4 +61,7 @@ struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
|
|||||||
uint32_t access_mask,
|
uint32_t access_mask,
|
||||||
uint8_t flags);
|
uint8_t flags);
|
||||||
|
|
||||||
|
struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
|
||||||
|
const struct security_acl *oacl);
|
||||||
|
|
||||||
#endif /* __SECURITY_DESCRIPTOR_H__ */
|
#endif /* __SECURITY_DESCRIPTOR_H__ */
|
||||||
|
@ -159,6 +159,32 @@ interface security
|
|||||||
SEC_STD_WRITE_DAC |
|
SEC_STD_WRITE_DAC |
|
||||||
SEC_STD_WRITE_OWNER); /* 0x000f0000 */
|
SEC_STD_WRITE_OWNER); /* 0x000f0000 */
|
||||||
|
|
||||||
|
/* generic->specific mappings for Directory Service objects */
|
||||||
|
/* directory specific part of GENERIC_ALL */
|
||||||
|
const int SEC_ADS_GENERIC_ALL_DS =
|
||||||
|
(SEC_STD_DELETE |
|
||||||
|
SEC_STD_WRITE_DAC |
|
||||||
|
SEC_STD_WRITE_OWNER |
|
||||||
|
SEC_ADS_CREATE_CHILD |
|
||||||
|
SEC_ADS_DELETE_CHILD |
|
||||||
|
SEC_ADS_DELETE_TREE |
|
||||||
|
SEC_ADS_CONTROL_ACCESS);
|
||||||
|
const int SEC_ADS_GENERIC_EXECUTE = SEC_STD_READ_CONTROL | SEC_ADS_LIST;
|
||||||
|
const int SEC_ADS_GENERIC_WRITE =
|
||||||
|
(SEC_STD_READ_CONTROL |
|
||||||
|
SEC_ADS_SELF_WRITE |
|
||||||
|
SEC_ADS_WRITE_PROP);
|
||||||
|
const int SEC_ADS_GENERIC_READ =
|
||||||
|
(SEC_STD_READ_CONTROL |
|
||||||
|
SEC_ADS_LIST |
|
||||||
|
SEC_ADS_READ_PROP |
|
||||||
|
SEC_ADS_LIST_OBJECT);
|
||||||
|
const int SEC_ADS_GENERIC_ALL =
|
||||||
|
(SEC_ADS_GENERIC_EXECUTE |
|
||||||
|
SEC_ADS_GENERIC_WRITE |
|
||||||
|
SEC_ADS_GENERIC_READ |
|
||||||
|
SEC_ADS_GENERIC_ALL_DS);
|
||||||
|
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
/* WELL KNOWN SIDS */
|
/* WELL KNOWN SIDS */
|
||||||
|
|
||||||
@ -397,6 +423,7 @@ interface security
|
|||||||
uint32 num_sids;
|
uint32 num_sids;
|
||||||
[size_is(num_sids)] dom_sid *sids[*];
|
[size_is(num_sids)] dom_sid *sids[*];
|
||||||
udlong privilege_mask;
|
udlong privilege_mask;
|
||||||
|
security_acl *default_dacl;
|
||||||
} security_token;
|
} security_token;
|
||||||
|
|
||||||
/* bits that determine which parts of a security descriptor
|
/* bits that determine which parts of a security descriptor
|
||||||
@ -420,4 +447,11 @@ interface security
|
|||||||
KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010
|
KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010
|
||||||
} kerb_EncTypes;
|
} kerb_EncTypes;
|
||||||
|
|
||||||
|
typedef [public,bitmap32bit] bitmap {
|
||||||
|
SEC_DACL_AUTO_INHERIT = 0x00000001,
|
||||||
|
SEC_SACL_AUTO_INHERIT = 0x00000002,
|
||||||
|
SEC_DEFAULT_DESCRIPTOR = 0x00000004,
|
||||||
|
SEC_OWNER_FROM_PARENT = 0x00000008,
|
||||||
|
SEC_GROUP_FROM_PARENT = 0x00000010
|
||||||
|
} security_autoinherit;
|
||||||
}
|
}
|
||||||
|
@ -334,3 +334,15 @@ INIT_FUNCTION = LDB_MODULE(operational)
|
|||||||
################################################
|
################################################
|
||||||
|
|
||||||
ldb_operational_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/operational.o
|
ldb_operational_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/operational.o
|
||||||
|
|
||||||
|
################################################
|
||||||
|
# Start MODULE ldb_descriptor
|
||||||
|
[MODULE::ldb_descriptor]
|
||||||
|
INIT_FUNCTION = LDB_MODULE(descriptor)
|
||||||
|
CFLAGS = -Ilib/ldb/include
|
||||||
|
PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB
|
||||||
|
SUBSYSTEM = LIBLDB
|
||||||
|
# End MODULE ldb_descriptor
|
||||||
|
################################################
|
||||||
|
|
||||||
|
ldb_descriptor_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/descriptor.o
|
||||||
|
459
source4/dsdb/samdb/ldb_modules/descriptor.c
Normal file
459
source4/dsdb/samdb/ldb_modules/descriptor.c
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
/*
|
||||||
|
ldb database library
|
||||||
|
|
||||||
|
Copyright (C) Simo Sorce 2006-2008
|
||||||
|
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
|
||||||
|
Copyright (C) Nadezhda Ivanova 2009
|
||||||
|
|
||||||
|
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: DS Security descriptor module
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* - Calculate the security descriptor of a newly created object
|
||||||
|
* - Perform sd recalculation on a move operation
|
||||||
|
* - Handle sd modification invariants
|
||||||
|
*
|
||||||
|
* Author: Nadezhda Ivanova
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
#include "ldb_module.h"
|
||||||
|
#include "dlinklist.h"
|
||||||
|
#include "dsdb/samdb/samdb.h"
|
||||||
|
#include "librpc/ndr/libndr.h"
|
||||||
|
#include "librpc/gen_ndr/ndr_security.h"
|
||||||
|
#include "libcli/security/security.h"
|
||||||
|
#include "auth/auth.h"
|
||||||
|
#include "param/param.h"
|
||||||
|
|
||||||
|
struct descriptor_context {
|
||||||
|
struct ldb_module *module;
|
||||||
|
struct ldb_request *req;
|
||||||
|
struct ldb_reply *search_res;
|
||||||
|
int (*step_fn)(struct descriptor_context *);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema, struct ldb_message_element *element)
|
||||||
|
{
|
||||||
|
struct dsdb_class *last_class = NULL;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < element->num_values; i++){
|
||||||
|
if (!last_class)
|
||||||
|
last_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
|
||||||
|
else {
|
||||||
|
struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
|
||||||
|
if (tmp_class->subClass_order > last_class->subClass_order)
|
||||||
|
last_class = tmp_class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return last_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dom_sid *get_default_ag(TALLOC_CTX *mem_ctx,
|
||||||
|
struct ldb_dn *dn,
|
||||||
|
struct security_token *token,
|
||||||
|
struct ldb_context *ldb)
|
||||||
|
{
|
||||||
|
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
|
||||||
|
struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb);
|
||||||
|
struct ldb_dn *schema_base_dn = ldb_get_schema_basedn(ldb);
|
||||||
|
struct ldb_dn *config_base_dn = ldb_get_config_basedn(ldb);
|
||||||
|
const struct dom_sid *domain_sid = samdb_domain_sid(ldb);
|
||||||
|
struct dom_sid *da_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ADMINS);
|
||||||
|
struct dom_sid *ea_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ENTERPRISE_ADMINS);
|
||||||
|
struct dom_sid *sa_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_SCHEMA_ADMINS);
|
||||||
|
struct dom_sid *dag_sid;
|
||||||
|
|
||||||
|
if (ldb_dn_compare_base(schema_base_dn, dn) == 0){
|
||||||
|
if (security_token_has_sid(token, sa_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, sa_sid);
|
||||||
|
else if (security_token_has_sid(token, ea_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, ea_sid);
|
||||||
|
else if (security_token_has_sid(token, da_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, da_sid);
|
||||||
|
else
|
||||||
|
dag_sid = NULL;
|
||||||
|
}
|
||||||
|
else if (ldb_dn_compare_base(config_base_dn, dn) == 0){
|
||||||
|
if (security_token_has_sid(token, ea_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, ea_sid);
|
||||||
|
else if (security_token_has_sid(token, da_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, da_sid);
|
||||||
|
else
|
||||||
|
dag_sid = NULL;
|
||||||
|
}
|
||||||
|
else if (ldb_dn_compare_base(root_base_dn, dn) == 0){
|
||||||
|
if (security_token_has_sid(token, da_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, da_sid);
|
||||||
|
else if (security_token_has_sid(token, ea_sid))
|
||||||
|
dag_sid = dom_sid_dup(mem_ctx, ea_sid);
|
||||||
|
else
|
||||||
|
dag_sid = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dag_sid = NULL;
|
||||||
|
|
||||||
|
talloc_free(tmp_ctx);
|
||||||
|
return dag_sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct security_descriptor *get_sd_unpacked(struct ldb_module *module, TALLOC_CTX *mem_ctx,
|
||||||
|
const struct dsdb_class *objectclass)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb = ldb_module_get_ctx(module);
|
||||||
|
struct security_descriptor *sd;
|
||||||
|
const struct dom_sid *domain_sid = samdb_domain_sid(ldb);
|
||||||
|
|
||||||
|
if (!objectclass->defaultSecurityDescriptor || !domain_sid) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd = sddl_decode(mem_ctx,
|
||||||
|
objectclass->defaultSecurityDescriptor,
|
||||||
|
domain_sid);
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dom_sid *get_default_group(TALLOC_CTX *mem_ctx,
|
||||||
|
struct ldb_context *ldb,
|
||||||
|
struct dom_sid *dag)
|
||||||
|
{
|
||||||
|
int *domainFunctionality;
|
||||||
|
|
||||||
|
domainFunctionality = talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
|
||||||
|
|
||||||
|
if (*domainFunctionality && (*domainFunctionality >= DS_BEHAVIOR_WIN2008)){
|
||||||
|
return dag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DATA_BLOB *get_new_descriptor(struct ldb_module *module,
|
||||||
|
struct ldb_dn *dn,
|
||||||
|
TALLOC_CTX *mem_ctx,
|
||||||
|
const struct dsdb_class *objectclass,
|
||||||
|
struct ldb_val *parent,
|
||||||
|
struct ldb_val *object)
|
||||||
|
{
|
||||||
|
struct security_descriptor *user_descriptor = NULL, *parent_descriptor = NULL;
|
||||||
|
struct security_descriptor *new_sd;
|
||||||
|
DATA_BLOB *linear_sd;
|
||||||
|
enum ndr_err_code ndr_err;
|
||||||
|
struct ldb_context *ldb = ldb_module_get_ctx(module);
|
||||||
|
struct auth_session_info *session_info
|
||||||
|
= ldb_get_opaque(ldb, "sessionInfo");
|
||||||
|
const struct dom_sid *domain_sid = samdb_domain_sid(ldb);
|
||||||
|
char *sddl_sd;
|
||||||
|
struct dom_sid *default_owner;
|
||||||
|
struct dom_sid *default_group;
|
||||||
|
|
||||||
|
if (object){
|
||||||
|
user_descriptor = talloc(mem_ctx, struct security_descriptor);
|
||||||
|
if(!user_descriptor)
|
||||||
|
return NULL;
|
||||||
|
ndr_err = ndr_pull_struct_blob(object, user_descriptor, NULL,
|
||||||
|
user_descriptor,
|
||||||
|
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
|
||||||
|
|
||||||
|
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)){
|
||||||
|
talloc_free(user_descriptor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
user_descriptor = get_sd_unpacked(module, mem_ctx, objectclass);
|
||||||
|
|
||||||
|
if (parent){
|
||||||
|
parent_descriptor = talloc(mem_ctx, struct security_descriptor);
|
||||||
|
if(!parent_descriptor)
|
||||||
|
return NULL;
|
||||||
|
ndr_err = ndr_pull_struct_blob(parent, parent_descriptor, NULL,
|
||||||
|
parent_descriptor,
|
||||||
|
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
|
||||||
|
|
||||||
|
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)){
|
||||||
|
talloc_free(parent_descriptor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default_owner = get_default_ag(mem_ctx, dn,
|
||||||
|
session_info->security_token, ldb);
|
||||||
|
default_group = get_default_group(mem_ctx, ldb, default_owner);
|
||||||
|
new_sd = create_security_descriptor(mem_ctx, parent_descriptor, user_descriptor, true,
|
||||||
|
NULL, SEC_DACL_AUTO_INHERIT|SEC_SACL_AUTO_INHERIT,
|
||||||
|
session_info->security_token,
|
||||||
|
default_owner, default_group,
|
||||||
|
map_generic_rights_ds);
|
||||||
|
if (!new_sd)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
sddl_sd = sddl_encode(mem_ctx, new_sd, domain_sid);
|
||||||
|
DEBUG(10, ("Object %s created with desriptor %s", ldb_dn_get_linearized(dn), sddl_sd));
|
||||||
|
|
||||||
|
linear_sd = talloc(mem_ctx, DATA_BLOB);
|
||||||
|
if (!linear_sd) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx,
|
||||||
|
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
|
||||||
|
new_sd,
|
||||||
|
(ndr_push_flags_fn_t)ndr_push_security_descriptor);
|
||||||
|
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return linear_sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct descriptor_context *descriptor_init_context(struct ldb_module *module,
|
||||||
|
struct ldb_request *req)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb;
|
||||||
|
struct descriptor_context *ac;
|
||||||
|
|
||||||
|
ldb = ldb_module_get_ctx(module);
|
||||||
|
|
||||||
|
ac = talloc_zero(req, struct descriptor_context);
|
||||||
|
if (ac == NULL) {
|
||||||
|
ldb_set_errstring(ldb, "Out of Memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ac->module = module;
|
||||||
|
ac->req = req;
|
||||||
|
return ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb;
|
||||||
|
struct descriptor_context *ac;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ac = talloc_get_type(req->context, struct descriptor_context);
|
||||||
|
ldb = ldb_module_get_ctx(ac->module);
|
||||||
|
|
||||||
|
if (!ares) {
|
||||||
|
return ldb_module_done(ac->req, NULL, NULL,
|
||||||
|
LDB_ERR_OPERATIONS_ERROR);
|
||||||
|
}
|
||||||
|
if (ares->error != LDB_SUCCESS &&
|
||||||
|
ares->error != LDB_ERR_NO_SUCH_OBJECT) {
|
||||||
|
return ldb_module_done(ac->req, ares->controls,
|
||||||
|
ares->response, ares->error);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ares->type) {
|
||||||
|
case LDB_REPLY_ENTRY:
|
||||||
|
if (ac->search_res != NULL) {
|
||||||
|
ldb_set_errstring(ldb, "Too many results");
|
||||||
|
talloc_free(ares);
|
||||||
|
return ldb_module_done(ac->req, NULL, NULL,
|
||||||
|
LDB_ERR_OPERATIONS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
ac->search_res = talloc_steal(ac, ares);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LDB_REPLY_REFERRAL:
|
||||||
|
/* ignore */
|
||||||
|
talloc_free(ares);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LDB_REPLY_DONE:
|
||||||
|
talloc_free(ares);
|
||||||
|
ret = ac->step_fn(ac);
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
return ldb_module_done(ac->req, NULL, NULL, ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LDB_SUCCESS;
|
||||||
|
}
|
||||||
|
static int descriptor_op_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||||||
|
{
|
||||||
|
struct descriptor_context *ac;
|
||||||
|
|
||||||
|
ac = talloc_get_type(req->context, struct descriptor_context);
|
||||||
|
|
||||||
|
if (!ares) {
|
||||||
|
return ldb_module_done(ac->req, NULL, NULL,
|
||||||
|
LDB_ERR_OPERATIONS_ERROR);
|
||||||
|
}
|
||||||
|
if (ares->error != LDB_SUCCESS) {
|
||||||
|
return ldb_module_done(ac->req, ares->controls,
|
||||||
|
ares->response, ares->error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ares->type != LDB_REPLY_DONE) {
|
||||||
|
talloc_free(ares);
|
||||||
|
return ldb_module_done(ac->req, NULL, NULL,
|
||||||
|
LDB_ERR_OPERATIONS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ldb_module_done(ac->req, ares->controls,
|
||||||
|
ares->response, ares->error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int descriptor_do_add(struct descriptor_context *ac)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb;
|
||||||
|
const struct dsdb_schema *schema;
|
||||||
|
struct ldb_request *add_req;
|
||||||
|
struct ldb_message_element *objectclass_element, *sd_element = NULL;
|
||||||
|
struct ldb_message *msg;
|
||||||
|
TALLOC_CTX *mem_ctx;
|
||||||
|
int ret;
|
||||||
|
struct ldb_val *sd_val = NULL, *parentsd_val = NULL;
|
||||||
|
DATA_BLOB *sd;
|
||||||
|
struct dsdb_class *objectclass;
|
||||||
|
|
||||||
|
ldb = ldb_module_get_ctx(ac->module);
|
||||||
|
schema = dsdb_get_schema(ldb);
|
||||||
|
|
||||||
|
mem_ctx = talloc_new(ac);
|
||||||
|
if (mem_ctx == NULL) {
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
|
||||||
|
|
||||||
|
/* get the security descriptor values*/
|
||||||
|
sd_element = ldb_msg_find_element(msg, "nTSecurityDescriptor");
|
||||||
|
objectclass_element = ldb_msg_find_element(msg, "objectClass");
|
||||||
|
objectclass = get_last_structural_class(schema, objectclass_element);
|
||||||
|
|
||||||
|
if (!objectclass)
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
|
||||||
|
if (sd_element)
|
||||||
|
sd_val = &sd_element->values[0];
|
||||||
|
/* NC's have no parent */
|
||||||
|
if ((ldb_dn_compare(msg->dn, (ldb_get_schema_basedn(ldb))) == 0) ||
|
||||||
|
(ldb_dn_compare(msg->dn, (ldb_get_config_basedn(ldb))) == 0) ||
|
||||||
|
(ldb_dn_compare(msg->dn, (ldb_get_root_basedn(ldb))) == 0))
|
||||||
|
parentsd_val = NULL;
|
||||||
|
else if (ac->search_res != NULL)
|
||||||
|
parentsd_val = ldb_msg_find_ldb_val(ac->search_res->message, "nTSecurityDescriptor");
|
||||||
|
|
||||||
|
|
||||||
|
/* get the parent descriptor and the one provided. If not provided, get the default.*/
|
||||||
|
/* convert to security descriptor and calculate */
|
||||||
|
sd = get_new_descriptor(ac->module, msg->dn, mem_ctx, objectclass,
|
||||||
|
parentsd_val, sd_val);
|
||||||
|
if (sd) {
|
||||||
|
ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
talloc_free(mem_ctx);
|
||||||
|
ret = ldb_msg_sanity_check(ldb, msg);
|
||||||
|
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ldb_build_add_req(&add_req, ldb, ac,
|
||||||
|
msg,
|
||||||
|
ac->req->controls,
|
||||||
|
ac, descriptor_op_callback,
|
||||||
|
ac->req);
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform the add */
|
||||||
|
return ldb_next_request(ac->module, add_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int descriptor_add(struct ldb_module *module, struct ldb_request *req)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb;
|
||||||
|
struct ldb_request *search_req;
|
||||||
|
struct descriptor_context *ac;
|
||||||
|
struct ldb_dn *parent_dn;
|
||||||
|
int ret;
|
||||||
|
static const char * const descr_attrs[] = { "nTSecurityDescriptor", NULL };
|
||||||
|
|
||||||
|
ldb = ldb_module_get_ctx(module);
|
||||||
|
|
||||||
|
ldb_debug(ldb, LDB_DEBUG_TRACE, "descriptor_add\n");
|
||||||
|
|
||||||
|
if (ldb_dn_is_special(req->op.add.message->dn)) {
|
||||||
|
return ldb_next_request(module, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
ac = descriptor_init_context(module, req);
|
||||||
|
if (ac == NULL) {
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there isn't a parent, just go on to the add processing */
|
||||||
|
if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
|
||||||
|
return descriptor_do_add(ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get copy of parent DN */
|
||||||
|
parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
|
||||||
|
if (parent_dn == NULL) {
|
||||||
|
ldb_oom(ldb);
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ldb_build_search_req(&search_req, ldb,
|
||||||
|
ac, parent_dn, LDB_SCOPE_BASE,
|
||||||
|
"(objectClass=*)", descr_attrs,
|
||||||
|
NULL,
|
||||||
|
ac, get_search_callback,
|
||||||
|
req);
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
talloc_steal(search_req, parent_dn);
|
||||||
|
|
||||||
|
ac->step_fn = descriptor_do_add;
|
||||||
|
|
||||||
|
return ldb_next_request(ac->module, search_req);
|
||||||
|
}
|
||||||
|
/* TODO */
|
||||||
|
static int descriptor_modify(struct ldb_module *module, struct ldb_request *req)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb = ldb_module_get_ctx(module);
|
||||||
|
ldb_debug(ldb, LDB_DEBUG_TRACE, "descriptor_modify\n");
|
||||||
|
return ldb_next_request(module, req);
|
||||||
|
}
|
||||||
|
/* TODO */
|
||||||
|
static int descriptor_rename(struct ldb_module *module, struct ldb_request *req)
|
||||||
|
{
|
||||||
|
struct ldb_context *ldb = ldb_module_get_ctx(module);
|
||||||
|
ldb_debug(ldb, LDB_DEBUG_TRACE, "descriptor_rename\n");
|
||||||
|
return ldb_next_request(module, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
_PUBLIC_ const struct ldb_module_ops ldb_descriptor_module_ops = {
|
||||||
|
.name = "descriptor",
|
||||||
|
.add = descriptor_add,
|
||||||
|
.modify = descriptor_modify,
|
||||||
|
.rename = descriptor_rename,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -231,49 +231,6 @@ static int objectclass_sort(struct ldb_module *module,
|
|||||||
return LDB_ERR_OBJECT_CLASS_VIOLATION;
|
return LDB_ERR_OBJECT_CLASS_VIOLATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx,
|
|
||||||
const struct dsdb_class *objectclass)
|
|
||||||
{
|
|
||||||
struct ldb_context *ldb = ldb_module_get_ctx(module);
|
|
||||||
enum ndr_err_code ndr_err;
|
|
||||||
DATA_BLOB *linear_sd;
|
|
||||||
struct auth_session_info *session_info
|
|
||||||
= ldb_get_opaque(ldb, "sessionInfo");
|
|
||||||
struct security_descriptor *sd;
|
|
||||||
const struct dom_sid *domain_sid = samdb_domain_sid(ldb);
|
|
||||||
|
|
||||||
if (!objectclass->defaultSecurityDescriptor || !domain_sid) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd = sddl_decode(mem_ctx,
|
|
||||||
objectclass->defaultSecurityDescriptor,
|
|
||||||
domain_sid);
|
|
||||||
|
|
||||||
if (!sd || !session_info || !session_info->security_token) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd->owner_sid = session_info->security_token->user_sid;
|
|
||||||
sd->group_sid = session_info->security_token->group_sid;
|
|
||||||
|
|
||||||
linear_sd = talloc(mem_ctx, DATA_BLOB);
|
|
||||||
if (!linear_sd) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx,
|
|
||||||
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
|
|
||||||
sd,
|
|
||||||
(ndr_push_flags_fn_t)ndr_push_security_descriptor);
|
|
||||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return linear_sd;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
|
static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
|
||||||
{
|
{
|
||||||
struct ldb_context *ldb;
|
struct ldb_context *ldb;
|
||||||
@ -536,7 +493,6 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
return LDB_ERR_UNWILLING_TO_PERFORM;
|
return LDB_ERR_UNWILLING_TO_PERFORM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema) {
|
if (schema) {
|
||||||
ret = fix_attributes(ldb, schema, msg);
|
ret = fix_attributes(ldb, schema, msg);
|
||||||
if (ret != LDB_SUCCESS) {
|
if (ret != LDB_SUCCESS) {
|
||||||
@ -546,7 +502,7 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
|
|
||||||
/* This is now the objectClass list from the database */
|
/* This is now the objectClass list from the database */
|
||||||
objectclass_element = ldb_msg_find_element(msg, "objectClass");
|
objectclass_element = ldb_msg_find_element(msg, "objectClass");
|
||||||
|
|
||||||
if (!objectclass_element) {
|
if (!objectclass_element) {
|
||||||
/* Where did it go? bail now... */
|
/* Where did it go? bail now... */
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
@ -565,10 +521,10 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We must completely replace the existing objectClass entry,
|
/* We must completely replace the existing objectClass entry,
|
||||||
* because we need it sorted */
|
* because we need it sorted */
|
||||||
|
|
||||||
/* Move from the linked list back into an ldb msg */
|
/* Move from the linked list back into an ldb msg */
|
||||||
for (current = sorted; current; current = current->next) {
|
for (current = sorted; current; current = current->next) {
|
||||||
value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
|
value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
|
||||||
@ -579,7 +535,7 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
}
|
}
|
||||||
ret = ldb_msg_add_string(msg, "objectClass", value);
|
ret = ldb_msg_add_string(msg, "objectClass", value);
|
||||||
if (ret != LDB_SUCCESS) {
|
if (ret != LDB_SUCCESS) {
|
||||||
ldb_set_errstring(ldb,
|
ldb_set_errstring(ldb,
|
||||||
"objectclass: could not re-add sorted "
|
"objectclass: could not re-add sorted "
|
||||||
"objectclass to modify msg");
|
"objectclass to modify msg");
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
@ -589,6 +545,7 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
if (!current->next) {
|
if (!current->next) {
|
||||||
struct ldb_message_element *el;
|
struct ldb_message_element *el;
|
||||||
int32_t systemFlags = 0;
|
int32_t systemFlags = 0;
|
||||||
|
DATA_BLOB *sd;
|
||||||
if (!ldb_msg_find_element(msg, "objectCategory")) {
|
if (!ldb_msg_find_element(msg, "objectCategory")) {
|
||||||
value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
|
value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
@ -599,15 +556,9 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
ldb_msg_add_string(msg, "objectCategory", value);
|
ldb_msg_add_string(msg, "objectCategory", value);
|
||||||
}
|
}
|
||||||
if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
|
if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
|
||||||
ldb_msg_add_string(msg, "showInAdvancedViewOnly",
|
ldb_msg_add_string(msg, "showInAdvancedViewOnly",
|
||||||
"TRUE");
|
"TRUE");
|
||||||
}
|
}
|
||||||
if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) {
|
|
||||||
DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass);
|
|
||||||
if (sd) {
|
|
||||||
ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
|
/* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
|
||||||
el = ldb_msg_find_element(msg, "systemFlags");
|
el = ldb_msg_find_element(msg, "systemFlags");
|
||||||
@ -619,7 +570,7 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
/* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
|
/* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
|
||||||
ldb_msg_remove_element(msg, el);
|
ldb_msg_remove_element(msg, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This flag is only allowed on attributeSchema objects */
|
/* This flag is only allowed on attributeSchema objects */
|
||||||
if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) {
|
if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) {
|
||||||
systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
|
systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
|
||||||
@ -632,7 +583,7 @@ static int objectclass_do_add(struct oc_context *ac)
|
|||||||
|| ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
|
|| ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
|
||||||
systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
|
systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
|
||||||
|
|
||||||
} else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0
|
} else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0
|
||||||
|| ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0
|
|| ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0
|
||||||
|| ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
|
|| ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
|
||||||
systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
|
systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
PUBLIC_DEPENDENCIES = LIBNDR LIBSECURITY_COMMON
|
PUBLIC_DEPENDENCIES = LIBNDR LIBSECURITY_COMMON
|
||||||
|
|
||||||
LIBSECURITY_OBJ_FILES = $(addprefix $(libclisrcdir)/security/, \
|
LIBSECURITY_OBJ_FILES = $(addprefix $(libclisrcdir)/security/, \
|
||||||
security_token.o access_check.o privilege.o sddl.o) \
|
security_token.o access_check.o privilege.o sddl.o create_descriptor.o) \
|
||||||
|
|
||||||
$(eval $(call proto_header_template,$(libclisrcdir)/security/proto.h,$(LIBSECURITY_OBJ_FILES:.o=.c)))
|
$(eval $(call proto_header_template,$(libclisrcdir)/security/proto.h,$(LIBSECURITY_OBJ_FILES:.o=.c)))
|
||||||
|
117
source4/libcli/security/create_descriptor.c
Normal file
117
source4/libcli/security/create_descriptor.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) Nadezhda Ivanova 2009
|
||||||
|
|
||||||
|
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: create_descriptor
|
||||||
|
*
|
||||||
|
* Component: routines for calculating and creating security descriptors
|
||||||
|
* as described in MS-DTYP 2.5.2.2
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Author: Nadezhda Ivanova
|
||||||
|
*/
|
||||||
|
#include "includes.h"
|
||||||
|
#include "libcli/security/security.h"
|
||||||
|
|
||||||
|
/* the mapping function for generic rights for DS.(GA,GR,GW,GX)
|
||||||
|
* The mapping function is passed as an argument to the
|
||||||
|
* descriptor calculating routine and depends on the security
|
||||||
|
* manager that calls the calculating routine.
|
||||||
|
* TODO: need similar mappings for the file system and
|
||||||
|
* registry security managers in order to make this code
|
||||||
|
* generic for all security managers
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t map_generic_rights_ds(uint32_t access_mask)
|
||||||
|
{
|
||||||
|
if (access_mask & SEC_GENERIC_ALL){
|
||||||
|
access_mask |= SEC_ADS_GENERIC_ALL;
|
||||||
|
access_mask = ~SEC_GENERIC_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access_mask & SEC_GENERIC_EXECUTE){
|
||||||
|
access_mask |= SEC_ADS_GENERIC_EXECUTE;
|
||||||
|
access_mask = ~SEC_GENERIC_EXECUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access_mask & SEC_GENERIC_WRITE){
|
||||||
|
access_mask |= SEC_ADS_GENERIC_WRITE;
|
||||||
|
access_mask &= ~SEC_GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access_mask & SEC_GENERIC_READ){
|
||||||
|
access_mask |= SEC_ADS_GENERIC_READ;
|
||||||
|
access_mask &= ~SEC_GENERIC_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return access_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
|
||||||
|
struct security_descriptor *parent_sd,
|
||||||
|
struct security_descriptor *creator_sd,
|
||||||
|
bool is_container,
|
||||||
|
struct GUID *object_list,
|
||||||
|
uint32_t inherit_flags,
|
||||||
|
struct security_token *token,
|
||||||
|
struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */
|
||||||
|
struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
|
||||||
|
uint32_t (*generic_map)(uint32_t access_mask))
|
||||||
|
{
|
||||||
|
struct security_descriptor *new_sd;
|
||||||
|
struct dom_sid *new_owner = NULL;
|
||||||
|
struct dom_sid *new_group = NULL;
|
||||||
|
|
||||||
|
new_sd = security_descriptor_initialise(mem_ctx);
|
||||||
|
if (!new_sd)
|
||||||
|
return NULL;
|
||||||
|
if (!creator_sd || !creator_sd->owner_sid){
|
||||||
|
if (inherit_flags & SEC_OWNER_FROM_PARENT)
|
||||||
|
new_owner = parent_sd->owner_sid;
|
||||||
|
else if (!default_owner)
|
||||||
|
new_owner = token->user_sid;
|
||||||
|
else
|
||||||
|
new_owner = default_owner;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new_owner = creator_sd->owner_sid;
|
||||||
|
|
||||||
|
if (!creator_sd || !creator_sd->group_sid){
|
||||||
|
if (inherit_flags & SEC_GROUP_FROM_PARENT && parent_sd)
|
||||||
|
new_group = parent_sd->group_sid;
|
||||||
|
else if (!default_group)
|
||||||
|
new_group = token->group_sid;
|
||||||
|
else new_group = default_group;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new_group = creator_sd->group_sid;
|
||||||
|
|
||||||
|
new_sd->owner_sid = talloc_memdup(new_sd, new_owner, sizeof(struct dom_sid));
|
||||||
|
new_sd->group_sid = talloc_memdup(new_sd, new_group, sizeof(struct dom_sid));
|
||||||
|
if (!new_sd->owner_sid || !new_sd->group_sid){
|
||||||
|
talloc_free(new_sd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Todo remove */
|
||||||
|
if (creator_sd && creator_sd->type & SEC_DESC_DACL_PRESENT){
|
||||||
|
new_sd->dacl = security_acl_dup(new_sd, creator_sd->dacl);
|
||||||
|
new_sd->type |= SEC_DESC_DACL_PRESENT;
|
||||||
|
}
|
||||||
|
return new_sd;
|
||||||
|
}
|
@ -584,6 +584,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
|
|||||||
"extended_dn_in",
|
"extended_dn_in",
|
||||||
"rdn_name",
|
"rdn_name",
|
||||||
"objectclass",
|
"objectclass",
|
||||||
|
"descriptor",
|
||||||
"samldb",
|
"samldb",
|
||||||
"password_hash",
|
"password_hash",
|
||||||
"operational",
|
"operational",
|
||||||
|
Reference in New Issue
Block a user