2009-09-17 18:17:55 +02:00
/*
2009-09-14 19:44:41 +03:00
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"
2010-06-15 00:55:03 +02:00
# include <ldb_module.h>
# include "util/dlinklist.h"
2009-09-14 19:44:41 +03:00
# 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"
2011-09-20 14:26:36 -07:00
# include "dsdb/samdb/ldb_modules/util.h"
2022-02-10 14:36:28 +01:00
# include "lib/util/util_tdb.h"
# include "lib/dbwrap/dbwrap.h"
# include "lib/dbwrap/dbwrap_rbt.h"
2012-11-23 15:55:24 +01:00
struct descriptor_changes {
struct descriptor_changes * prev , * next ;
struct ldb_dn * nc_root ;
2019-12-12 14:44:57 +13:00
struct GUID guid ;
2022-02-10 15:08:47 +01:00
struct GUID parent_guid ;
2012-11-23 15:55:24 +01:00
bool force_self ;
bool force_children ;
struct ldb_dn * stopped_dn ;
2022-02-10 14:36:28 +01:00
size_t ref_count ;
2022-02-10 17:19:31 +01:00
size_t sort_count ;
2012-11-23 15:55:24 +01:00
} ;
2009-09-14 19:44:41 +03:00
2022-02-10 14:33:15 +01:00
struct descriptor_transaction {
TALLOC_CTX * mem ;
struct {
2022-02-10 14:36:28 +01:00
/*
* We used to have a list of changes , appended with each
* DSDB_EXTENDED_SEC_DESC_PROPAGATION_OID operation .
*
* But the main problem was that a replication
* cycle ( mainly the initial replication ) calls
* DSDB_EXTENDED_SEC_DESC_PROPAGATION_OID for the
* same object [ GUID ] more than once . With
* DRSUAPI_DRS_GET_TGT we ' ll get the naming
* context head object and other top level
* containers , every often .
*
* It means we ' ll process objects more
* than once and waste a lot of time
* doing the same work again and again .
*
* We use an objectGUID based map in order to
* avoid registering objects more than once .
* In an domain with 22000 object it can
* reduce the work from 4 hours down to ~ 3.5 minutes .
*/
2022-02-10 14:33:15 +01:00
struct descriptor_changes * list ;
2022-02-10 14:36:28 +01:00
struct db_context * map ;
size_t num_registrations ;
2022-02-10 16:20:51 +01:00
size_t num_registered ;
2022-02-10 17:19:31 +01:00
size_t num_toplevel ;
2022-02-10 16:20:51 +01:00
size_t num_processed ;
2022-02-10 14:33:15 +01:00
} changes ;
2022-02-10 16:20:51 +01:00
struct {
2022-02-10 12:46:10 +01:00
struct db_context * map ;
2022-02-10 16:20:51 +01:00
size_t num_processed ;
2022-02-10 12:46:10 +01:00
size_t num_skipped ;
2022-02-10 16:20:51 +01:00
} objects ;
2022-02-10 14:33:15 +01:00
} ;
2009-09-19 21:45:07 -07:00
struct descriptor_data {
2022-02-10 14:33:15 +01:00
struct descriptor_transaction transaction ;
2009-09-19 21:45:07 -07:00
} ;
2009-09-14 19:44:41 +03:00
struct descriptor_context {
2009-11-15 22:31:44 +02:00
struct ldb_module * module ;
struct ldb_request * req ;
2010-11-06 23:04:55 +01:00
struct ldb_message * msg ;
2009-11-15 22:31:44 +02:00
struct ldb_reply * search_res ;
struct ldb_reply * search_oc_res ;
struct ldb_val * parentsd_val ;
2010-11-01 17:51:36 +01:00
struct ldb_message_element * sd_element ;
2009-11-15 22:31:44 +02:00
struct ldb_val * sd_val ;
2012-11-21 13:05:31 +01:00
uint32_t sd_flags ;
2009-11-15 22:31:44 +02:00
int ( * step_fn ) ( struct descriptor_context * ) ;
2009-09-14 19:44:41 +03:00
} ;
2011-03-19 00:43:26 +01:00
static struct dom_sid * get_default_ag ( TALLOC_CTX * mem_ctx ,
2009-09-14 19:44:41 +03:00
struct ldb_dn * dn ,
2022-05-05 17:21:42 +12:00
const struct security_token * token ,
2009-09-14 19:44:41 +03:00
struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
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 ;
2010-11-16 13:17:32 +01:00
struct ldb_dn * nc_root ;
int ret ;
2009-09-14 19:44:41 +03:00
2010-11-16 13:17:32 +01:00
ret = dsdb_find_nc_root ( ldb , tmp_ctx , dn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
2010-04-13 09:18:33 +02:00
2010-11-16 13:17:32 +01:00
if ( ldb_dn_compare ( nc_root , ldb_get_schema_basedn ( ldb ) ) = = 0 ) {
2011-02-22 06:28:19 +02:00
if ( security_token_has_sid ( token , sa_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , sa_sid ) ;
2011-02-22 06:28:19 +02:00
} else if ( security_token_has_sid ( token , ea_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , ea_sid ) ;
2011-02-22 06:28:19 +02:00
} else if ( security_token_has_sid ( token , da_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , da_sid ) ;
2012-11-22 14:07:04 +01:00
} else if ( security_token_is_system ( token ) ) {
dag_sid = dom_sid_dup ( mem_ctx , sa_sid ) ;
2011-02-22 06:28:19 +02:00
} else {
2009-09-14 19:44:41 +03:00
dag_sid = NULL ;
2011-02-22 06:28:19 +02:00
}
2010-11-16 13:17:32 +01:00
} else if ( ldb_dn_compare ( nc_root , ldb_get_config_basedn ( ldb ) ) = = 0 ) {
2011-02-22 06:28:19 +02:00
if ( security_token_has_sid ( token , ea_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , ea_sid ) ;
2011-02-22 06:28:19 +02:00
} else if ( security_token_has_sid ( token , da_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , da_sid ) ;
2012-11-22 14:07:04 +01:00
} else if ( security_token_is_system ( token ) ) {
dag_sid = dom_sid_dup ( mem_ctx , ea_sid ) ;
2011-02-22 06:28:19 +02:00
} else {
2009-09-14 19:44:41 +03:00
dag_sid = NULL ;
2011-02-22 06:28:19 +02:00
}
2010-11-16 13:17:32 +01:00
} else if ( ldb_dn_compare ( nc_root , ldb_get_default_basedn ( ldb ) ) = = 0 ) {
2011-02-22 06:28:19 +02:00
if ( security_token_has_sid ( token , da_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , da_sid ) ;
2011-02-22 06:28:19 +02:00
} else if ( security_token_has_sid ( token , ea_sid ) ) {
2009-09-14 19:44:41 +03:00
dag_sid = dom_sid_dup ( mem_ctx , ea_sid ) ;
2012-11-22 14:07:04 +01:00
} else if ( security_token_is_system ( token ) ) {
dag_sid = dom_sid_dup ( mem_ctx , da_sid ) ;
2011-02-22 06:28:19 +02:00
} else {
2009-09-14 19:44:41 +03:00
dag_sid = NULL ;
2011-02-22 06:28:19 +02:00
}
2010-11-16 13:17:32 +01:00
} else {
2009-09-14 19:44:41 +03:00
dag_sid = NULL ;
2010-11-16 13:17:32 +01:00
}
2009-09-14 19:44:41 +03:00
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 )
{
2013-01-24 22:59:26 +01:00
/*
* This depends on the function level of the DC
* which is 2008 R2 in our case . Which means it is
* higher than 2003 and we should use the
* " default administrator group " also as owning group .
*
* This matches dcpromo for a 2003 domain
* on a Windows 2008 R2 DC .
*/
return dag ;
2009-09-14 19:44:41 +03:00
}
2009-11-20 13:25:13 +02:00
static struct security_descriptor * descr_handle_sd_flags ( TALLOC_CTX * mem_ctx ,
struct security_descriptor * new_sd ,
struct security_descriptor * old_sd ,
uint32_t sd_flags )
{
struct security_descriptor * final_sd ;
2009-11-21 18:40:51 +02:00
/* if there is no control or control == 0 modify everything */
2009-11-20 13:25:13 +02:00
if ( ! sd_flags ) {
return new_sd ;
}
final_sd = talloc_zero ( mem_ctx , struct security_descriptor ) ;
final_sd - > revision = SECURITY_DESCRIPTOR_REVISION_1 ;
final_sd - > type = SEC_DESC_SELF_RELATIVE ;
if ( sd_flags & ( SECINFO_OWNER ) ) {
2013-02-11 14:46:43 +11:00
if ( new_sd - > owner_sid ) {
final_sd - > owner_sid = talloc_memdup ( mem_ctx , new_sd - > owner_sid , sizeof ( struct dom_sid ) ) ;
}
2009-11-20 13:25:13 +02:00
final_sd - > type | = new_sd - > type & SEC_DESC_OWNER_DEFAULTED ;
}
else if ( old_sd ) {
2013-02-11 14:46:43 +11:00
if ( old_sd - > owner_sid ) {
final_sd - > owner_sid = talloc_memdup ( mem_ctx , old_sd - > owner_sid , sizeof ( struct dom_sid ) ) ;
}
2009-11-20 13:25:13 +02:00
final_sd - > type | = old_sd - > type & SEC_DESC_OWNER_DEFAULTED ;
}
if ( sd_flags & ( SECINFO_GROUP ) ) {
2013-02-11 14:46:43 +11:00
if ( new_sd - > group_sid ) {
final_sd - > group_sid = talloc_memdup ( mem_ctx , new_sd - > group_sid , sizeof ( struct dom_sid ) ) ;
}
2009-11-20 13:25:13 +02:00
final_sd - > type | = new_sd - > type & SEC_DESC_GROUP_DEFAULTED ;
}
else if ( old_sd ) {
2013-02-11 14:46:43 +11:00
if ( old_sd - > group_sid ) {
final_sd - > group_sid = talloc_memdup ( mem_ctx , old_sd - > group_sid , sizeof ( struct dom_sid ) ) ;
}
2009-11-20 13:25:13 +02:00
final_sd - > type | = old_sd - > type & SEC_DESC_GROUP_DEFAULTED ;
}
if ( sd_flags & ( SECINFO_SACL ) ) {
final_sd - > sacl = security_acl_dup ( mem_ctx , new_sd - > sacl ) ;
final_sd - > type | = new_sd - > type & ( SEC_DESC_SACL_PRESENT |
SEC_DESC_SACL_DEFAULTED | SEC_DESC_SACL_AUTO_INHERIT_REQ |
SEC_DESC_SACL_AUTO_INHERITED | SEC_DESC_SACL_PROTECTED |
SEC_DESC_SERVER_SECURITY ) ;
}
2010-06-01 15:05:02 +03:00
else if ( old_sd & & old_sd - > sacl ) {
2009-11-20 13:25:13 +02:00
final_sd - > sacl = security_acl_dup ( mem_ctx , old_sd - > sacl ) ;
final_sd - > type | = old_sd - > type & ( SEC_DESC_SACL_PRESENT |
SEC_DESC_SACL_DEFAULTED | SEC_DESC_SACL_AUTO_INHERIT_REQ |
SEC_DESC_SACL_AUTO_INHERITED | SEC_DESC_SACL_PROTECTED |
SEC_DESC_SERVER_SECURITY ) ;
}
if ( sd_flags & ( SECINFO_DACL ) ) {
final_sd - > dacl = security_acl_dup ( mem_ctx , new_sd - > dacl ) ;
final_sd - > type | = new_sd - > type & ( SEC_DESC_DACL_PRESENT |
SEC_DESC_DACL_DEFAULTED | SEC_DESC_DACL_AUTO_INHERIT_REQ |
SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_PROTECTED |
SEC_DESC_DACL_TRUSTED ) ;
}
2010-06-01 15:05:02 +03:00
else if ( old_sd & & old_sd - > dacl ) {
2009-11-20 13:25:13 +02:00
final_sd - > dacl = security_acl_dup ( mem_ctx , old_sd - > dacl ) ;
final_sd - > type | = old_sd - > type & ( SEC_DESC_DACL_PRESENT |
SEC_DESC_DACL_DEFAULTED | SEC_DESC_DACL_AUTO_INHERIT_REQ |
SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_PROTECTED |
SEC_DESC_DACL_TRUSTED ) ;
}
/* not so sure about this */
final_sd - > type | = new_sd - > type & SEC_DESC_RM_CONTROL_VALID ;
return final_sd ;
}
2021-10-25 13:10:56 +03:00
static struct security_descriptor * get_new_descriptor_nonlinear ( struct ldb_module * module ,
struct ldb_dn * dn ,
TALLOC_CTX * mem_ctx ,
const struct dsdb_class * objectclass ,
const struct ldb_val * parent ,
const struct ldb_val * object ,
const struct ldb_val * old_sd ,
uint32_t sd_flags )
2009-09-14 19:44:41 +03:00
{
struct security_descriptor * user_descriptor = NULL , * parent_descriptor = NULL ;
2009-11-20 13:25:13 +02:00
struct security_descriptor * old_descriptor = NULL ;
struct security_descriptor * new_sd , * final_sd ;
2009-09-14 19:44:41 +03:00
enum ndr_err_code ndr_err ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct auth_session_info * session_info
2018-05-31 15:12:46 +12:00
= ldb_get_opaque ( ldb , DSDB_SESSION_INFO ) ;
2009-09-14 19:44:41 +03:00
const struct dom_sid * domain_sid = samdb_domain_sid ( ldb ) ;
struct dom_sid * default_owner ;
struct dom_sid * default_group ;
2012-11-22 15:53:14 +01:00
struct security_descriptor * default_descriptor = NULL ;
2012-12-11 02:01:12 +01:00
struct GUID * object_list = NULL ;
2012-11-22 15:53:14 +01:00
if ( objectclass ! = NULL ) {
default_descriptor = get_sd_unpacked ( module , mem_ctx , objectclass ) ;
2012-12-11 02:01:12 +01:00
object_list = talloc_zero_array ( mem_ctx , struct GUID , 2 ) ;
if ( object_list = = NULL ) {
return NULL ;
}
object_list [ 0 ] = objectclass - > schemaIDGUID ;
2012-11-22 15:53:14 +01:00
}
2009-09-14 19:44:41 +03:00
2009-09-21 20:08:52 -07:00
if ( object ) {
2009-09-14 19:44:41 +03:00
user_descriptor = talloc ( mem_ctx , struct security_descriptor ) ;
2009-11-20 13:25:13 +02:00
if ( ! user_descriptor ) {
2009-09-14 19:44:41 +03:00
return NULL ;
2009-11-20 13:25:13 +02:00
}
2010-05-09 17:20:01 +02:00
ndr_err = ndr_pull_struct_blob ( object , user_descriptor ,
2009-09-14 19:44:41 +03:00
user_descriptor ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
2009-11-20 13:25:13 +02:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2009-09-14 19:44:41 +03:00
talloc_free ( user_descriptor ) ;
return NULL ;
}
2009-09-21 20:08:52 -07:00
} else {
2012-11-22 15:53:14 +01:00
user_descriptor = default_descriptor ;
2009-09-21 20:08:52 -07:00
}
2009-09-14 19:44:41 +03:00
2009-11-20 13:25:13 +02:00
if ( old_sd ) {
old_descriptor = talloc ( mem_ctx , struct security_descriptor ) ;
if ( ! old_descriptor ) {
return NULL ;
}
2010-05-09 17:20:01 +02:00
ndr_err = ndr_pull_struct_blob ( old_sd , old_descriptor ,
2009-11-20 13:25:13 +02:00
old_descriptor ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( old_descriptor ) ;
return NULL ;
}
}
if ( parent ) {
2009-09-14 19:44:41 +03:00
parent_descriptor = talloc ( mem_ctx , struct security_descriptor ) ;
2009-11-20 13:25:13 +02:00
if ( ! parent_descriptor ) {
2009-09-14 19:44:41 +03:00
return NULL ;
2009-11-20 13:25:13 +02:00
}
2010-05-09 17:20:01 +02:00
ndr_err = ndr_pull_struct_blob ( parent , parent_descriptor ,
2009-09-14 19:44:41 +03:00
parent_descriptor ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
2009-11-20 13:25:13 +02:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2009-09-14 19:44:41 +03:00
talloc_free ( parent_descriptor ) ;
return NULL ;
}
}
2009-11-20 13:25:13 +02:00
2012-11-22 15:53:14 +01:00
if ( user_descriptor & & default_descriptor & &
( user_descriptor - > dacl = = NULL ) )
{
user_descriptor - > dacl = default_descriptor - > dacl ;
user_descriptor - > type | = default_descriptor - > type & (
SEC_DESC_DACL_PRESENT |
SEC_DESC_DACL_DEFAULTED | SEC_DESC_DACL_AUTO_INHERIT_REQ |
SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_PROTECTED |
SEC_DESC_DACL_TRUSTED ) ;
}
if ( user_descriptor & & default_descriptor & &
( user_descriptor - > sacl = = NULL ) )
{
user_descriptor - > sacl = default_descriptor - > sacl ;
user_descriptor - > type | = default_descriptor - > type & (
SEC_DESC_SACL_PRESENT |
SEC_DESC_SACL_DEFAULTED | SEC_DESC_SACL_AUTO_INHERIT_REQ |
SEC_DESC_SACL_AUTO_INHERITED | SEC_DESC_SACL_PROTECTED |
SEC_DESC_SERVER_SECURITY ) ;
}
2012-12-01 15:10:38 +01:00
if ( ! ( sd_flags & SECINFO_OWNER ) & & user_descriptor ) {
user_descriptor - > owner_sid = NULL ;
/*
* We need the correct owner sid
* when calculating the DACL or SACL
*/
if ( old_descriptor ) {
user_descriptor - > owner_sid = old_descriptor - > owner_sid ;
}
}
if ( ! ( sd_flags & SECINFO_GROUP ) & & user_descriptor ) {
user_descriptor - > group_sid = NULL ;
/*
* We need the correct group sid
* when calculating the DACL or SACL
*/
if ( old_descriptor ) {
user_descriptor - > group_sid = old_descriptor - > group_sid ;
}
}
if ( ! ( sd_flags & SECINFO_DACL ) & & user_descriptor ) {
user_descriptor - > dacl = NULL ;
/*
* We add SEC_DESC_DACL_PROTECTED so that
* create_security_descriptor ( ) skips
* the unused inheritance calculation
*/
user_descriptor - > type | = SEC_DESC_DACL_PROTECTED ;
}
if ( ! ( sd_flags & SECINFO_SACL ) & & user_descriptor ) {
user_descriptor - > sacl = NULL ;
/*
* We add SEC_DESC_SACL_PROTECTED so that
* create_security_descriptor ( ) skips
* the unused inheritance calculation
*/
user_descriptor - > type | = SEC_DESC_SACL_PROTECTED ;
}
2009-09-14 19:44:41 +03:00
default_owner = get_default_ag ( mem_ctx , dn ,
session_info - > security_token , ldb ) ;
default_group = get_default_group ( mem_ctx , ldb , default_owner ) ;
2012-12-11 02:01:12 +01:00
new_sd = create_security_descriptor ( mem_ctx ,
parent_descriptor ,
user_descriptor ,
true ,
object_list ,
SEC_DACL_AUTO_INHERIT |
SEC_SACL_AUTO_INHERIT ,
2009-09-14 19:44:41 +03:00
session_info - > security_token ,
default_owner , default_group ,
map_generic_rights_ds ) ;
2009-11-20 13:25:13 +02:00
if ( ! new_sd ) {
2009-09-14 19:44:41 +03:00
return NULL ;
2009-11-20 13:25:13 +02:00
}
final_sd = descr_handle_sd_flags ( mem_ctx , new_sd , old_descriptor , sd_flags ) ;
2009-09-14 19:44:41 +03:00
2009-11-20 13:25:13 +02:00
if ( ! final_sd ) {
return NULL ;
}
2010-01-02 16:53:20 +11:00
if ( final_sd - > dacl ) {
final_sd - > dacl - > revision = SECURITY_ACL_REVISION_ADS ;
}
if ( final_sd - > sacl ) {
final_sd - > sacl - > revision = SECURITY_ACL_REVISION_ADS ;
}
2021-04-14 16:30:16 +02:00
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
DBG_DEBUG ( " Object %s created with descriptor %s \n \n " ,
ldb_dn_get_linearized ( dn ) ,
sddl_encode ( tmp_ctx , final_sd , domain_sid ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
}
2009-09-14 19:44:41 +03:00
2021-10-25 13:10:56 +03:00
return final_sd ;
}
static DATA_BLOB * get_new_descriptor ( struct ldb_module * module ,
struct ldb_dn * dn ,
TALLOC_CTX * mem_ctx ,
const struct dsdb_class * objectclass ,
const struct ldb_val * parent ,
const struct ldb_val * object ,
const struct ldb_val * old_sd ,
uint32_t sd_flags )
{
struct security_descriptor * final_sd = NULL ;
enum ndr_err_code ndr_err ;
DATA_BLOB * linear_sd = talloc ( mem_ctx , DATA_BLOB ) ;
2009-09-14 19:44:41 +03:00
if ( ! linear_sd ) {
return NULL ;
}
2021-10-25 13:10:56 +03:00
final_sd = get_new_descriptor_nonlinear ( module ,
dn ,
mem_ctx ,
objectclass ,
parent ,
object ,
old_sd ,
sd_flags ) ;
if ( final_sd = = NULL ) {
return NULL ;
}
2009-09-14 19:44:41 +03:00
ndr_err = ndr_push_struct_blob ( linear_sd , mem_ctx ,
2009-11-20 13:25:13 +02:00
final_sd ,
2009-09-14 19:44:41 +03:00
( ndr_push_flags_fn_t ) ndr_push_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return NULL ;
}
return linear_sd ;
}
2009-11-21 18:40:51 +02:00
static DATA_BLOB * descr_get_descriptor_to_show ( struct ldb_module * module ,
TALLOC_CTX * mem_ctx ,
struct ldb_val * sd ,
uint32_t sd_flags )
{
struct security_descriptor * old_sd , * final_sd ;
DATA_BLOB * linear_sd ;
enum ndr_err_code ndr_err ;
old_sd = talloc ( mem_ctx , struct security_descriptor ) ;
if ( ! old_sd ) {
return NULL ;
}
2010-05-09 17:20:01 +02:00
ndr_err = ndr_pull_struct_blob ( sd , old_sd ,
2009-11-21 18:40:51 +02:00
old_sd ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( old_sd ) ;
return NULL ;
}
final_sd = descr_handle_sd_flags ( mem_ctx , old_sd , NULL , sd_flags ) ;
if ( ! final_sd ) {
return NULL ;
}
linear_sd = talloc ( mem_ctx , DATA_BLOB ) ;
if ( ! linear_sd ) {
return NULL ;
}
ndr_err = ndr_push_struct_blob ( linear_sd , mem_ctx ,
final_sd ,
( ndr_push_flags_fn_t ) ndr_push_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return NULL ;
}
return linear_sd ;
}
2009-09-14 19:44:41 +03:00
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 ;
}
2009-11-21 18:40:51 +02:00
static int descriptor_search_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
struct descriptor_context * ac ;
struct ldb_val * sd_val = NULL ;
struct ldb_message_element * sd_el ;
DATA_BLOB * show_sd ;
2013-12-10 17:52:29 +01:00
int ret = LDB_SUCCESS ;
2009-11-21 18:40:51 +02:00
ac = talloc_get_type ( req - > context , struct descriptor_context ) ;
if ( ! ares ) {
ret = LDB_ERR_OPERATIONS_ERROR ;
goto fail ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
2012-11-21 13:05:31 +01:00
sd_el = ldb_msg_find_element ( ares - > message , " nTSecurityDescriptor " ) ;
if ( sd_el ) {
sd_val = sd_el - > values ;
2009-11-21 18:40:51 +02:00
}
2012-11-21 13:05:31 +01:00
2009-11-21 18:40:51 +02:00
if ( sd_val ) {
show_sd = descr_get_descriptor_to_show ( ac - > module , ac - > req ,
2012-11-21 13:05:31 +01:00
sd_val , ac - > sd_flags ) ;
2009-11-21 18:40:51 +02:00
if ( ! show_sd ) {
ret = LDB_ERR_OPERATIONS_ERROR ;
goto fail ;
}
ldb_msg_remove_attr ( ares - > message , " nTSecurityDescriptor " ) ;
ret = ldb_msg_add_steal_value ( ares - > message , " nTSecurityDescriptor " , show_sd ) ;
if ( ret ! = LDB_SUCCESS ) {
goto fail ;
}
}
return ldb_module_send_entry ( ac - > req , ares - > message , ares - > controls ) ;
case LDB_REPLY_REFERRAL :
2010-11-06 22:27:13 +01:00
return ldb_module_send_referral ( ac - > req , ares - > referral ) ;
2009-11-21 18:40:51 +02:00
case LDB_REPLY_DONE :
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
fail :
2010-12-17 08:43:33 +11:00
talloc_free ( ares ) ;
2009-11-21 18:40:51 +02:00
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
2022-05-05 17:21:42 +12:00
static bool can_write_owner ( TALLOC_CTX * mem_ctx ,
struct ldb_context * ldb ,
struct ldb_dn * dn ,
const struct security_token * security_token ,
const struct dom_sid * owner_sid )
{
const struct dom_sid * default_owner = NULL ;
/* If the user possesses SE_RESTORE_PRIVILEGE, the write is allowed. */
bool ok = security_token_has_privilege ( security_token , SEC_PRIV_RESTORE ) ;
if ( ok ) {
return true ;
}
/* The user can write their own SID to a security descriptor. */
ok = security_token_is_sid ( security_token , owner_sid ) ;
if ( ok ) {
return true ;
}
/*
* The user can write the SID of the " default administrators group " that
* they are a member of .
*/
default_owner = get_default_ag ( mem_ctx , dn ,
security_token , ldb ) ;
if ( default_owner ! = NULL ) {
ok = security_token_is_sid ( security_token , owner_sid ) ;
}
return ok ;
}
2011-02-21 17:04:27 +02:00
static int descriptor_add ( struct ldb_module * module , struct ldb_request * req )
{
2012-11-23 07:18:35 +01:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2011-02-21 17:04:27 +02:00
struct ldb_request * add_req ;
struct ldb_message * msg ;
struct ldb_result * parent_res ;
const struct ldb_val * parent_sd = NULL ;
2021-10-25 13:10:56 +03:00
const struct ldb_val * user_sd = NULL ;
2012-11-23 07:18:35 +01:00
struct ldb_dn * dn = req - > op . add . message - > dn ;
struct ldb_dn * parent_dn , * nc_root ;
2011-02-21 17:04:27 +02:00
struct ldb_message_element * objectclass_element , * sd_element ;
int ret ;
const struct dsdb_schema * schema ;
DATA_BLOB * sd ;
const struct dsdb_class * objectclass ;
static const char * const parent_attrs [ ] = { " nTSecurityDescriptor " , NULL } ;
2011-11-16 00:56:28 +01:00
uint32_t instanceType ;
bool isNC = false ;
2021-10-25 13:10:56 +03:00
enum ndr_err_code ndr_err ;
struct dsdb_control_calculated_default_sd * control_sd = NULL ;
2012-11-21 13:05:31 +01:00
uint32_t sd_flags = dsdb_request_sd_flags ( req , NULL ) ;
2021-10-25 13:10:56 +03:00
struct security_descriptor * user_descriptor = NULL ;
2011-02-21 17:04:27 +02:00
2012-11-23 07:18:35 +01:00
/* do not manipulate our control entries */
if ( ldb_dn_is_special ( dn ) ) {
return ldb_next_request ( module , req ) ;
}
2011-02-21 17:04:27 +02:00
user_sd = ldb_msg_find_ldb_val ( req - > op . add . message , " nTSecurityDescriptor " ) ;
sd_element = ldb_msg_find_element ( req - > op . add . message , " nTSecurityDescriptor " ) ;
/* nTSecurityDescriptor without a value is an error, letting through so it is handled */
if ( user_sd = = NULL & & sd_element ) {
return ldb_next_request ( module , req ) ;
}
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_add: %s \n " , ldb_dn_get_linearized ( dn ) ) ;
2011-11-16 00:56:28 +01:00
instanceType = ldb_msg_find_attr_as_uint ( req - > op . add . message , " instanceType " , 0 ) ;
if ( instanceType & INSTANCE_TYPE_IS_NC_HEAD ) {
isNC = true ;
2011-02-21 17:04:27 +02:00
}
2011-11-16 00:56:28 +01:00
if ( ! isNC ) {
ret = dsdb_find_nc_root ( ldb , req , dn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_add: Could not find NC root for %s \n " ,
ldb_dn_get_linearized ( dn ) ) ;
return ret ;
}
if ( ldb_dn_compare ( dn , nc_root ) = = 0 ) {
DEBUG ( 0 , ( " Found DN %s being a NC by the old method \n " , ldb_dn_get_linearized ( dn ) ) ) ;
isNC = true ;
}
2011-02-21 17:04:27 +02:00
}
2011-11-16 00:56:28 +01:00
if ( isNC ) {
DEBUG ( 2 , ( " DN: %s is a NC \n " , ldb_dn_get_linearized ( dn ) ) ) ;
}
if ( ! isNC ) {
/* if the object has a parent, retrieve its SD to
* use for calculation . Unfortunately we do not yet have
* instanceType , so we use dsdb_find_nc_root . */
parent_dn = ldb_dn_get_parent ( req , dn ) ;
if ( parent_dn = = NULL ) {
return ldb_oom ( ldb ) ;
}
2011-02-21 17:04:27 +02:00
/* we aren't any NC */
ret = dsdb_module_search_dn ( module , req , & parent_res , parent_dn ,
parent_attrs ,
2012-11-21 10:15:58 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED ,
2011-02-21 17:04:27 +02:00
req ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_add: Could not find SD for %s \n " ,
ldb_dn_get_linearized ( parent_dn ) ) ;
return ret ;
}
if ( parent_res - > count ! = 1 ) {
return ldb_operr ( ldb ) ;
}
parent_sd = ldb_msg_find_ldb_val ( parent_res - > msgs [ 0 ] , " nTSecurityDescriptor " ) ;
}
schema = dsdb_get_schema ( ldb , req ) ;
objectclass_element = ldb_msg_find_element ( req - > op . add . message , " objectClass " ) ;
if ( objectclass_element = = NULL ) {
return ldb_operr ( ldb ) ;
}
2012-04-04 22:24:16 +02:00
objectclass = dsdb_get_last_structural_class ( schema ,
objectclass_element ) ;
2011-02-21 17:04:27 +02:00
if ( objectclass = = NULL ) {
return ldb_operr ( ldb ) ;
}
2012-11-21 14:13:17 +01:00
/*
* The SD_FLAG control is ignored on add
* and we default to all bits set .
*/
2013-02-11 14:45:57 +11:00
sd_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL ;
2012-11-21 14:13:17 +01:00
2021-10-25 13:10:56 +03:00
control_sd = talloc ( req , struct dsdb_control_calculated_default_sd ) ;
if ( control_sd = = NULL ) {
return ldb_operr ( ldb ) ;
}
control_sd - > specified_sd = false ;
control_sd - > specified_sacl = false ;
if ( user_sd ! = NULL ) {
user_descriptor = talloc ( req , struct security_descriptor ) ;
if ( user_descriptor = = NULL ) {
return ldb_operr ( ldb ) ;
}
ndr_err = ndr_pull_struct_blob ( user_sd , user_descriptor ,
user_descriptor ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( user_descriptor ) ;
return ldb_operr ( ldb ) ;
}
/*
* calculate the permissions needed , since in acl we no longer have
* access to the original user descriptor
*/
control_sd - > specified_sd = true ;
control_sd - > specified_sacl = user_descriptor - > sacl ! = NULL ;
2022-05-05 17:21:42 +12:00
if ( user_descriptor - > owner_sid ! = NULL ) {
/* Verify the owner of the security descriptor. */
const struct auth_session_info * session_info
= ldb_get_opaque ( ldb , DSDB_SESSION_INFO ) ;
bool ok = can_write_owner ( req ,
ldb ,
dn ,
session_info - > security_token ,
user_descriptor - > owner_sid ) ;
talloc_free ( user_descriptor ) ;
if ( ! ok ) {
return dsdb_module_werror ( module ,
LDB_ERR_CONSTRAINT_VIOLATION ,
WERR_INVALID_OWNER ,
" invalid addition of owner SID " ) ;
}
}
2021-10-25 13:10:56 +03:00
}
2011-02-21 17:04:27 +02:00
sd = get_new_descriptor ( module , dn , req ,
objectclass , parent_sd ,
2012-11-21 14:13:17 +01:00
user_sd , NULL , sd_flags ) ;
2012-11-23 09:19:11 +01:00
if ( sd = = NULL ) {
return ldb_operr ( ldb ) ;
}
2021-10-25 13:10:56 +03:00
control_sd - > default_sd = get_new_descriptor_nonlinear ( module ,
dn ,
req ,
objectclass ,
parent_sd ,
NULL ,
NULL ,
sd_flags ) ;
if ( control_sd - > default_sd = = NULL ) {
return ldb_operr ( ldb ) ;
}
2011-02-21 17:04:27 +02:00
msg = ldb_msg_copy_shallow ( req , req - > op . add . message ) ;
2012-11-23 09:19:11 +01:00
if ( msg = = NULL ) {
return ldb_oom ( ldb ) ;
}
2012-11-23 09:20:50 +01:00
if ( sd_element ! = NULL ) {
sd_element - > values [ 0 ] = * sd ;
} else {
ret = ldb_msg_add_steal_value ( msg ,
" nTSecurityDescriptor " ,
sd ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
2011-02-21 17:04:27 +02:00
}
}
ret = ldb_build_add_req ( & add_req , ldb , req ,
msg ,
req - > controls ,
req , dsdb_next_callback ,
req ) ;
2021-10-25 13:10:56 +03:00
2011-02-21 17:04:27 +02:00
LDB_REQ_SET_LOCATION ( add_req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_error ( ldb , ret ,
" descriptor_add: Error creating new add request. " ) ;
}
2021-10-25 13:10:56 +03:00
dom_sid_parse ( " S-1-0-0 " , control_sd - > default_sd - > owner_sid ) ;
ret = ldb_request_add_control ( add_req ,
DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID ,
false , ( void * ) control_sd ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_operr ( module ) ;
}
2011-02-21 17:04:27 +02:00
return ldb_next_request ( module , add_req ) ;
}
2011-02-21 17:08:44 +02:00
static int descriptor_modify ( struct ldb_module * module , struct ldb_request * req )
{
2012-11-23 07:18:35 +01:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2011-02-21 17:08:44 +02:00
struct ldb_request * mod_req ;
struct ldb_message * msg ;
struct ldb_result * current_res , * parent_res ;
const struct ldb_val * old_sd = NULL ;
const struct ldb_val * parent_sd = NULL ;
2021-10-25 13:10:56 +03:00
const struct ldb_val * user_sd = NULL ;
2012-11-23 07:18:35 +01:00
struct ldb_dn * dn = req - > op . mod . message - > dn ;
struct ldb_dn * parent_dn ;
2012-11-23 09:31:05 +01:00
struct ldb_message_element * objectclass_element , * sd_element ;
2011-02-21 17:08:44 +02:00
int ret ;
2012-11-21 13:05:31 +01:00
uint32_t instanceType ;
2012-11-23 10:45:02 +01:00
bool explicit_sd_flags = false ;
uint32_t sd_flags = dsdb_request_sd_flags ( req , & explicit_sd_flags ) ;
2011-02-21 17:08:44 +02:00
const struct dsdb_schema * schema ;
DATA_BLOB * sd ;
const struct dsdb_class * objectclass ;
static const char * const parent_attrs [ ] = { " nTSecurityDescriptor " , NULL } ;
static const char * const current_attrs [ ] = { " nTSecurityDescriptor " ,
" instanceType " ,
" objectClass " , NULL } ;
2022-02-10 15:08:47 +01:00
struct GUID parent_guid = { . time_low = 0 } ;
2012-11-23 10:45:02 +01:00
struct ldb_control * sd_propagation_control ;
2012-11-16 12:49:16 +01:00
int cmp_ret = - 1 ;
2012-11-23 07:18:35 +01:00
/* do not manipulate our control entries */
if ( ldb_dn_is_special ( dn ) ) {
return ldb_next_request ( module , req ) ;
}
2012-11-23 10:45:02 +01:00
sd_propagation_control = ldb_request_get_control ( req ,
DSDB_CONTROL_SEC_DESC_PROPAGATION_OID ) ;
if ( sd_propagation_control ! = NULL ) {
if ( sd_propagation_control - > data ! = module ) {
return ldb_operr ( ldb ) ;
}
if ( req - > op . mod . message - > num_elements ! = 0 ) {
return ldb_operr ( ldb ) ;
}
if ( explicit_sd_flags ) {
return ldb_operr ( ldb ) ;
}
if ( sd_flags ! = 0xF ) {
return ldb_operr ( ldb ) ;
}
if ( sd_propagation_control - > critical = = 0 ) {
return ldb_operr ( ldb ) ;
}
sd_propagation_control - > critical = 0 ;
}
2012-11-23 09:31:05 +01:00
sd_element = ldb_msg_find_element ( req - > op . mod . message , " nTSecurityDescriptor " ) ;
2012-11-23 10:45:02 +01:00
if ( sd_propagation_control = = NULL & & sd_element = = NULL ) {
2012-11-23 09:31:05 +01:00
return ldb_next_request ( module , req ) ;
}
2012-11-23 09:55:17 +01:00
/*
* nTSecurityDescriptor with DELETE is not supported yet .
* TODO : handle this correctly .
*/
2012-11-23 10:45:02 +01:00
if ( sd_propagation_control = = NULL & &
LDB_FLAG_MOD_TYPE ( sd_element - > flags ) = = LDB_FLAG_MOD_DELETE )
{
2012-11-23 09:55:17 +01:00
return ldb_module_error ( module ,
LDB_ERR_UNWILLING_TO_PERFORM ,
" MOD_DELETE for nTSecurityDescriptor "
" not supported yet " ) ;
}
2011-02-21 17:08:44 +02:00
user_sd = ldb_msg_find_ldb_val ( req - > op . mod . message , " nTSecurityDescriptor " ) ;
2012-11-23 09:31:05 +01:00
/* nTSecurityDescriptor without a value is an error, letting through so it is handled */
2012-11-23 10:45:02 +01:00
if ( sd_propagation_control = = NULL & & user_sd = = NULL ) {
2011-02-21 17:08:44 +02:00
return ldb_next_request ( module , req ) ;
}
2022-05-05 17:21:42 +12:00
if ( sd_flags & SECINFO_OWNER & & user_sd ! = NULL ) {
/* Verify the new owner of the security descriptor. */
struct security_descriptor * user_descriptor = NULL ;
enum ndr_err_code ndr_err ;
const struct auth_session_info * session_info ;
bool ok ;
user_descriptor = talloc ( req , struct security_descriptor ) ;
if ( user_descriptor = = NULL ) {
return ldb_operr ( ldb ) ;
}
ndr_err = ndr_pull_struct_blob ( user_sd , user_descriptor ,
user_descriptor ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( user_descriptor ) ;
return ldb_operr ( ldb ) ;
}
session_info = ldb_get_opaque ( ldb , DSDB_SESSION_INFO ) ;
ok = can_write_owner ( req ,
ldb ,
dn ,
session_info - > security_token ,
user_descriptor - > owner_sid ) ;
talloc_free ( user_descriptor ) ;
if ( ! ok ) {
return dsdb_module_werror ( module ,
LDB_ERR_CONSTRAINT_VIOLATION ,
WERR_INVALID_OWNER ,
" invalid modification of owner SID " ) ;
}
}
2011-02-21 17:08:44 +02:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_modify: %s \n " , ldb_dn_get_linearized ( dn ) ) ;
ret = dsdb_module_search_dn ( module , req , & current_res , dn ,
current_attrs ,
2012-11-21 10:15:58 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
2019-12-12 14:44:57 +13:00
DSDB_SEARCH_SHOW_RECYCLED |
DSDB_SEARCH_SHOW_EXTENDED_DN ,
2011-02-21 17:08:44 +02:00
req ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_ERROR , " descriptor_modify: Could not find %s \n " ,
ldb_dn_get_linearized ( dn ) ) ;
return ret ;
}
instanceType = ldb_msg_find_attr_as_uint ( current_res - > msgs [ 0 ] ,
" instanceType " , 0 ) ;
/* if the object has a parent, retrieve its SD to
* use for calculation */
if ( ! ldb_dn_is_null ( current_res - > msgs [ 0 ] - > dn ) & &
! ( instanceType & INSTANCE_TYPE_IS_NC_HEAD ) ) {
2022-02-10 15:08:47 +01:00
NTSTATUS status ;
2011-02-21 17:08:44 +02:00
parent_dn = ldb_dn_get_parent ( req , dn ) ;
if ( parent_dn = = NULL ) {
return ldb_oom ( ldb ) ;
}
ret = dsdb_module_search_dn ( module , req , & parent_res , parent_dn ,
parent_attrs ,
2012-11-21 10:15:58 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
2022-02-10 15:08:47 +01:00
DSDB_SEARCH_SHOW_RECYCLED |
DSDB_SEARCH_SHOW_EXTENDED_DN ,
2011-02-21 17:08:44 +02:00
req ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_ERROR , " descriptor_modify: Could not find SD for %s \n " ,
ldb_dn_get_linearized ( parent_dn ) ) ;
return ret ;
}
if ( parent_res - > count ! = 1 ) {
return ldb_operr ( ldb ) ;
}
parent_sd = ldb_msg_find_ldb_val ( parent_res - > msgs [ 0 ] , " nTSecurityDescriptor " ) ;
2022-02-10 15:08:47 +01:00
status = dsdb_get_extended_dn_guid ( parent_res - > msgs [ 0 ] - > dn ,
& parent_guid ,
" GUID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ldb_operr ( ldb ) ;
}
2011-02-21 17:08:44 +02:00
}
schema = dsdb_get_schema ( ldb , req ) ;
objectclass_element = ldb_msg_find_element ( current_res - > msgs [ 0 ] , " objectClass " ) ;
if ( objectclass_element = = NULL ) {
return ldb_operr ( ldb ) ;
}
2012-04-04 22:24:16 +02:00
objectclass = dsdb_get_last_structural_class ( schema ,
objectclass_element ) ;
2011-02-21 17:08:44 +02:00
if ( objectclass = = NULL ) {
return ldb_operr ( ldb ) ;
}
2012-11-21 13:05:31 +01:00
old_sd = ldb_msg_find_ldb_val ( current_res - > msgs [ 0 ] , " nTSecurityDescriptor " ) ;
2012-11-23 10:58:49 +01:00
if ( old_sd = = NULL ) {
return ldb_operr ( ldb ) ;
}
2011-02-21 17:08:44 +02:00
2012-11-23 10:45:02 +01:00
if ( sd_propagation_control ! = NULL ) {
/*
* This just triggers a recalculation of the
* inherited aces .
*/
user_sd = old_sd ;
}
2019-12-12 14:44:57 +13:00
sd = get_new_descriptor ( module , current_res - > msgs [ 0 ] - > dn , req ,
2011-02-21 17:08:44 +02:00
objectclass , parent_sd ,
user_sd , old_sd , sd_flags ) ;
2012-11-23 09:19:11 +01:00
if ( sd = = NULL ) {
return ldb_operr ( ldb ) ;
}
2011-02-21 17:08:44 +02:00
msg = ldb_msg_copy_shallow ( req , req - > op . mod . message ) ;
2012-11-23 09:19:11 +01:00
if ( msg = = NULL ) {
return ldb_oom ( ldb ) ;
}
2012-11-16 12:49:16 +01:00
cmp_ret = data_blob_cmp ( old_sd , sd ) ;
2012-11-23 10:45:02 +01:00
if ( sd_propagation_control ! = NULL ) {
2012-11-16 12:49:16 +01:00
if ( cmp_ret = = 0 ) {
2012-11-23 10:45:02 +01:00
/*
* The nTSecurityDescriptor is unchanged ,
* which means we can stop the processing .
*
* We mark the control as critical again ,
* as we have not processed it , so the caller
* can tell that the descriptor was unchanged .
*/
sd_propagation_control - > critical = 1 ;
return ldb_module_done ( req , NULL , NULL , LDB_SUCCESS ) ;
}
2022-02-21 16:27:37 +13:00
ret = ldb_msg_append_value ( msg , " nTSecurityDescriptor " ,
sd , LDB_FLAG_MOD_REPLACE ) ;
2012-11-23 10:45:02 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_oom ( ldb ) ;
}
2012-11-16 12:49:16 +01:00
} else if ( cmp_ret ! = 0 ) {
2019-12-12 14:44:57 +13:00
struct GUID guid ;
2012-11-16 12:49:16 +01:00
struct ldb_dn * nc_root ;
2019-12-12 14:44:57 +13:00
NTSTATUS status ;
2012-11-16 12:49:16 +01:00
2019-12-12 14:44:57 +13:00
ret = dsdb_find_nc_root ( ldb ,
msg ,
current_res - > msgs [ 0 ] - > dn ,
& nc_root ) ;
2012-11-16 12:49:16 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_oom ( ldb ) ;
}
2019-12-12 14:44:57 +13:00
status = dsdb_get_extended_dn_guid ( current_res - > msgs [ 0 ] - > dn ,
& guid ,
" GUID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ldb_operr ( ldb ) ;
}
2019-11-26 16:17:32 +13:00
/*
* Force SD propagation on children of this record
*/
2019-12-12 14:44:57 +13:00
ret = dsdb_module_schedule_sd_propagation ( module ,
nc_root ,
guid ,
2022-02-10 15:08:47 +01:00
parent_guid ,
2019-12-12 14:44:57 +13:00
false ) ;
2012-11-16 12:49:16 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_operr ( ldb ) ;
}
sd_element - > values [ 0 ] = * sd ;
2012-11-23 10:45:02 +01:00
} else {
sd_element - > values [ 0 ] = * sd ;
}
2011-02-21 17:08:44 +02:00
ret = ldb_build_mod_req ( & mod_req , ldb , req ,
msg ,
req - > controls ,
req ,
dsdb_next_callback ,
req ) ;
LDB_REQ_SET_LOCATION ( mod_req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return ldb_next_request ( module , mod_req ) ;
}
2009-11-21 18:40:51 +02:00
static int descriptor_search ( struct ldb_module * module , struct ldb_request * req )
{
int ret ;
struct ldb_context * ldb ;
struct ldb_request * down_req ;
struct descriptor_context * ac ;
2012-11-21 13:05:31 +01:00
bool explicit_sd_flags = false ;
uint32_t sd_flags = dsdb_request_sd_flags ( req , & explicit_sd_flags ) ;
bool show_sd = explicit_sd_flags ;
2012-11-21 15:24:46 +01:00
if ( ! show_sd & &
ldb_attr_in_list ( req - > op . search . attrs , " nTSecurityDescriptor " ) )
{
show_sd = true ;
}
if ( ! show_sd ) {
2009-11-21 18:40:51 +02:00
return ldb_next_request ( module , req ) ;
}
ldb = ldb_module_get_ctx ( module ) ;
ac = descriptor_init_context ( module , req ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-11-21 18:40:51 +02:00
}
2012-11-21 13:05:31 +01:00
ac - > sd_flags = sd_flags ;
2009-11-21 18:40:51 +02:00
ret = ldb_build_search_req_ex ( & down_req , ldb , ac ,
req - > op . search . base ,
req - > op . search . scope ,
req - > op . search . tree ,
req - > op . search . attrs ,
req - > controls ,
ac , descriptor_search_callback ,
ac - > req ) ;
2010-09-24 12:09:26 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2009-11-21 18:40:51 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return ldb_next_request ( ac - > module , down_req ) ;
}
2012-11-16 12:49:16 +01:00
2023-01-26 09:44:01 +13:00
static int descriptor_rename_callback ( struct ldb_request * req ,
struct ldb_reply * ares )
{
struct descriptor_context * ac = NULL ;
struct ldb_context * ldb = NULL ;
struct ldb_dn * newdn = req - > op . rename . newdn ;
struct GUID guid ;
struct ldb_dn * nc_root ;
struct GUID parent_guid = { . time_low = 0 } ;
int ret ;
ac = talloc_get_type_abort ( 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 ) {
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
if ( ares - > type ! = LDB_REPLY_DONE ) {
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
ret = dsdb_module_guid_by_dn ( ac - > module ,
newdn ,
& guid ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL ,
ret ) ;
}
ret = dsdb_find_nc_root ( ldb , req , newdn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL ,
ret ) ;
}
/*
* After a successful rename , force SD propagation on this
* record ( get a new inherited SD from the potentially new
* parent
*
* We don ' t know the parent guid here ( it is filled in as
* all - zero in the initialiser above ) , but we ' re not in a hot
* code path here , as the " descriptor " module is located above
* the " repl_meta_data " , only originating changes are handled
* here .
*
* If it turns out to be a problem we may search for the new
* parent guid .
*/
ret = dsdb_module_schedule_sd_propagation ( ac - > module ,
nc_root ,
guid ,
parent_guid ,
true ) ;
if ( ret ! = LDB_SUCCESS ) {
ret = ldb_operr ( ldb ) ;
return ldb_module_done ( ac - > req , NULL , NULL ,
ret ) ;
}
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
2009-09-14 19:44:41 +03:00
static int descriptor_rename ( struct ldb_module * module , struct ldb_request * req )
{
2023-01-26 09:44:01 +13:00
struct descriptor_context * ac = NULL ;
2009-09-14 19:44:41 +03:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2012-11-23 07:18:35 +01:00
struct ldb_dn * olddn = req - > op . rename . olddn ;
2012-11-16 12:49:16 +01:00
struct ldb_dn * newdn = req - > op . rename . newdn ;
2023-01-26 09:44:01 +13:00
struct ldb_request * down_req ;
2012-11-16 12:49:16 +01:00
int ret ;
2010-11-16 13:25:34 +01:00
/* do not manipulate our control entries */
if ( ldb_dn_is_special ( req - > op . rename . olddn ) ) {
return ldb_next_request ( module , req ) ;
}
2012-11-23 07:18:35 +01:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_rename: %s \n " ,
ldb_dn_get_linearized ( olddn ) ) ;
2023-01-26 09:44:01 +13:00
if ( ldb_dn_compare ( olddn , newdn ) = = 0 ) {
/* No special work required for a case-only rename */
return ldb_next_request ( module , req ) ;
}
2012-11-16 12:49:16 +01:00
2023-01-26 09:44:01 +13:00
ac = descriptor_init_context ( module , req ) ;
if ( ac = = NULL ) {
return ldb_operr ( ldb ) ;
}
2022-02-10 15:08:47 +01:00
2023-01-26 09:44:01 +13:00
ret = ldb_build_rename_req ( & down_req , ldb , ac ,
req - > op . rename . olddn ,
req - > op . rename . newdn ,
req - > controls ,
ac , descriptor_rename_callback ,
req ) ;
LDB_REQ_SET_LOCATION ( down_req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
2012-11-16 12:49:16 +01:00
}
2023-01-26 09:44:01 +13:00
return ldb_next_request ( module , down_req ) ;
2009-09-14 19:44:41 +03:00
}
2022-02-10 14:36:28 +01:00
static void descriptor_changes_parser ( TDB_DATA key , TDB_DATA data , void * private_data )
{
struct descriptor_changes * * c_ptr = ( struct descriptor_changes * * ) private_data ;
uintptr_t ptr = 0 ;
SMB_ASSERT ( data . dsize = = sizeof ( ptr ) ) ;
memcpy ( & ptr , data . dptr , data . dsize ) ;
* c_ptr = talloc_get_type_abort ( ( void * ) ptr , struct descriptor_changes ) ;
}
2022-02-10 12:46:10 +01:00
static void descriptor_object_parser ( TDB_DATA key , TDB_DATA data , void * private_data )
{
SMB_ASSERT ( data . dsize = = 0 ) ;
}
2012-11-23 15:55:24 +01:00
static int descriptor_extended_sec_desc_propagation ( struct ldb_module * module ,
struct ldb_request * req )
{
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
2022-02-10 14:33:15 +01:00
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2012-11-23 15:55:24 +01:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct dsdb_extended_sec_desc_propagation_op * op ;
2022-02-10 14:36:28 +01:00
struct descriptor_changes * c = NULL ;
TDB_DATA key ;
NTSTATUS status ;
2012-11-23 15:55:24 +01:00
op = talloc_get_type ( req - > op . extended . data ,
struct dsdb_extended_sec_desc_propagation_op ) ;
if ( op = = NULL ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" descriptor_extended_sec_desc_propagation: "
" invalid extended data \n " ) ;
return LDB_ERR_PROTOCOL_ERROR ;
}
2022-02-10 14:33:15 +01:00
if ( t - > mem = = NULL ) {
2012-11-23 15:55:24 +01:00
return ldb_module_operr ( module ) ;
}
2022-02-10 15:08:47 +01:00
if ( GUID_equal ( & op - > parent_guid , & op - > guid ) ) {
/*
* This is an unexpected situation ,
* it should never happen !
*/
DBG_ERR ( " ERROR: Object %s is its own parent (nc_root=%s) \n " ,
GUID_string ( t - > mem , & op - > guid ) ,
ldb_dn_get_extended_linearized ( t - > mem , op - > nc_root , 1 ) ) ;
return ldb_module_operr ( module ) ;
}
2022-02-10 14:36:28 +01:00
/*
* First we check if we already have an registration
* for the given object .
*/
key = make_tdb_data ( ( const void * ) & op - > guid , sizeof ( op - > guid ) ) ;
status = dbwrap_parse_record ( t - > changes . map , key ,
descriptor_changes_parser , & c ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
c = NULL ;
status = NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" dbwrap_parse_record() - %s \n " ,
nt_errstr ( status ) ) ;
return ldb_module_operr ( module ) ;
}
2012-11-23 15:55:24 +01:00
if ( c = = NULL ) {
2022-02-10 14:36:28 +01:00
/*
* Create a new structure if we
* don ' t know about the object yet .
*/
c = talloc_zero ( t - > mem , struct descriptor_changes ) ;
if ( c = = NULL ) {
return ldb_module_oom ( module ) ;
}
c - > nc_root = ldb_dn_copy ( c , op - > nc_root ) ;
if ( c - > nc_root = = NULL ) {
return ldb_module_oom ( module ) ;
}
c - > guid = op - > guid ;
2012-11-23 15:55:24 +01:00
}
2022-02-10 14:36:28 +01:00
if ( ldb_dn_compare ( c - > nc_root , op - > nc_root ) ! = 0 ) {
/*
* This is an unexpected situation ,
* we don ' t expect the nc root to change
* during a replication cycle .
*/
DBG_ERR ( " ERROR: Object %s nc_root changed %s => %s \n " ,
GUID_string ( c , & c - > guid ) ,
ldb_dn_get_extended_linearized ( c , c - > nc_root , 1 ) ,
ldb_dn_get_extended_linearized ( c , op - > nc_root , 1 ) ) ;
return ldb_module_operr ( module ) ;
2012-11-23 15:55:24 +01:00
}
2022-02-10 14:36:28 +01:00
c - > ref_count + = 1 ;
2022-02-10 15:08:47 +01:00
/*
* always use the last known parent_guid .
*/
c - > parent_guid = op - > parent_guid ;
2022-02-10 14:36:28 +01:00
/*
* Note that we only set , but don ' t clear values here ,
* it means c - > force_self and c - > force_children can
* both be true in the end .
*/
2012-11-23 15:55:24 +01:00
if ( op - > include_self ) {
c - > force_self = true ;
} else {
c - > force_children = true ;
}
2022-02-10 14:36:28 +01:00
if ( c - > ref_count = = 1 ) {
struct TDB_DATA val = make_tdb_data ( ( const void * ) & c , sizeof ( c ) ) ;
/*
* Remember the change by objectGUID in order
* to avoid processing it more than once .
*/
status = dbwrap_store ( t - > changes . map , key , val , TDB_INSERT ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" dbwrap_parse_record() - %s \n " ,
nt_errstr ( status ) ) ;
return ldb_module_operr ( module ) ;
}
DLIST_ADD_END ( t - > changes . list , c ) ;
t - > changes . num_registered + = 1 ;
}
t - > changes . num_registrations + = 1 ;
2012-11-23 15:55:24 +01:00
return ldb_module_done ( req , NULL , NULL , LDB_SUCCESS ) ;
}
static int descriptor_extended ( struct ldb_module * module , struct ldb_request * req )
{
if ( strcmp ( req - > op . extended . oid , DSDB_EXTENDED_SEC_DESC_PROPAGATION_OID ) = = 0 ) {
return descriptor_extended_sec_desc_propagation ( module , req ) ;
}
return ldb_next_request ( module , req ) ;
}
2009-09-19 21:45:07 -07:00
static int descriptor_init ( struct ldb_module * module )
{
2009-11-21 18:40:51 +02:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2012-11-23 15:55:24 +01:00
int ret ;
struct descriptor_data * descriptor_private ;
ret = ldb_mod_register_control ( module , LDB_CONTROL_SD_FLAGS_OID ) ;
2009-11-21 18:40:51 +02:00
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_ERROR ,
" descriptor: Unable to register control with rootdse! \n " ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-11-21 18:40:51 +02:00
}
2012-11-23 15:55:24 +01:00
descriptor_private = talloc_zero ( module , struct descriptor_data ) ;
if ( descriptor_private = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ldb_module_set_private ( module , descriptor_private ) ;
2009-09-19 21:45:07 -07:00
return ldb_next_init ( module ) ;
}
2012-11-23 15:55:24 +01:00
static int descriptor_sd_propagation_object ( struct ldb_module * module ,
struct ldb_message * msg ,
bool * stop )
{
2022-02-10 16:20:51 +01:00
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2012-11-23 15:55:24 +01:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_request * sub_req ;
struct ldb_result * mod_res ;
struct ldb_control * sd_propagation_control ;
2022-02-10 17:19:31 +01:00
struct GUID guid ;
2012-11-23 15:55:24 +01:00
int ret ;
2022-02-10 17:19:31 +01:00
TDB_DATA key ;
2022-02-10 12:46:10 +01:00
TDB_DATA empty_val = { . dsize = 0 , } ;
2022-02-10 17:19:31 +01:00
NTSTATUS status ;
struct descriptor_changes * c = NULL ;
2012-11-23 15:55:24 +01:00
* stop = false ;
2022-02-10 17:19:31 +01:00
/*
* We get the GUID of the object
2022-02-10 12:46:10 +01:00
* in order to have the cache key
* for the object .
2022-02-10 17:19:31 +01:00
*/
status = dsdb_get_extended_dn_guid ( msg - > dn , & guid , " GUID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ldb_operr ( ldb ) ;
}
key = make_tdb_data ( ( const void * ) & guid , sizeof ( guid ) ) ;
2022-02-10 12:46:10 +01:00
/*
* Check if we already processed this object .
*/
status = dbwrap_parse_record ( t - > objects . map , key ,
descriptor_object_parser , NULL ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
/*
* All work is already one
*/
t - > objects . num_skipped + = 1 ;
* stop = true ;
return LDB_SUCCESS ;
}
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" dbwrap_parse_record() - %s \n " ,
nt_errstr ( status ) ) ;
return ldb_module_operr ( module ) ;
}
t - > objects . num_processed + = 1 ;
/*
* Remember that we ' re processing this object .
*/
status = dbwrap_store ( t - > objects . map , key , empty_val , TDB_INSERT ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" dbwrap_parse_record() - %s \n " ,
nt_errstr ( status ) ) ;
return ldb_module_operr ( module ) ;
}
/*
* Check that if there ' s a descriptor_change in our list ,
* which we may be able to remove from the pending list
* when we processed the object .
*/
2022-02-10 17:19:31 +01:00
status = dbwrap_parse_record ( t - > changes . map , key , descriptor_changes_parser , & c ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
c = NULL ;
status = NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" dbwrap_parse_record() - %s \n " ,
nt_errstr ( status ) ) ;
return ldb_module_operr ( module ) ;
}
2012-11-23 15:55:24 +01:00
mod_res = talloc_zero ( msg , struct ldb_result ) ;
if ( mod_res = = NULL ) {
return ldb_module_oom ( module ) ;
}
ret = ldb_build_mod_req ( & sub_req , ldb , mod_res ,
msg ,
NULL ,
mod_res ,
ldb_modify_default_callback ,
NULL ) ;
LDB_REQ_SET_LOCATION ( sub_req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_operr ( module ) ;
}
ldb_req_mark_trusted ( sub_req ) ;
ret = ldb_request_add_control ( sub_req ,
DSDB_CONTROL_SEC_DESC_PROPAGATION_OID ,
true , module ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_operr ( module ) ;
}
sd_propagation_control = ldb_request_get_control ( sub_req ,
DSDB_CONTROL_SEC_DESC_PROPAGATION_OID ) ;
if ( sd_propagation_control = = NULL ) {
return ldb_module_operr ( module ) ;
}
ret = dsdb_request_add_controls ( sub_req ,
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_operr ( module ) ;
}
ret = descriptor_modify ( module , sub_req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( sub_req - > handle , LDB_WAIT_ALL ) ;
}
if ( ret ! = LDB_SUCCESS ) {
2016-07-11 16:05:49 +12:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" descriptor_modify on %s failed: %s " ,
ldb_dn_get_linearized ( msg - > dn ) ,
ldb_errstring ( ldb_module_get_ctx ( module ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2012-11-23 15:55:24 +01:00
}
if ( sd_propagation_control - > critical ! = 0 ) {
2022-02-10 17:19:31 +01:00
if ( c = = NULL ) {
/*
* If we don ' t have a
* descriptor_changes structure
* we ' re done .
*/
* stop = true ;
} else if ( ! c - > force_children ) {
/*
* If we don ' t need to
* propagate to children ,
* we ' re done .
*/
* stop = true ;
}
}
if ( c ! = NULL & & ! c - > force_children ) {
/*
* Remove the pending change ,
* we already done all required work ,
* there ' s no need to do it again .
*
* Note DLIST_REMOVE ( ) is a noop
* if the element is not part of
* the list .
*/
DLIST_REMOVE ( t - > changes . list , c ) ;
2012-11-23 15:55:24 +01:00
}
talloc_free ( mod_res ) ;
return LDB_SUCCESS ;
}
static int descriptor_sd_propagation_msg_sort ( struct ldb_message * * m1 ,
struct ldb_message * * m2 )
{
struct ldb_dn * dn1 = ( * m1 ) - > dn ;
struct ldb_dn * dn2 = ( * m2 ) - > dn ;
/*
* This sorts in tree order , parents first
*/
return ldb_dn_compare ( dn2 , dn1 ) ;
}
static int descriptor_sd_propagation_recursive ( struct ldb_module * module ,
struct descriptor_changes * change )
{
2022-02-10 16:20:51 +01:00
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2019-12-12 14:44:57 +13:00
struct ldb_result * guid_res = NULL ;
2012-11-23 15:55:24 +01:00
struct ldb_result * res = NULL ;
unsigned int i ;
const char * const no_attrs [ ] = { " @__NONE__ " , NULL } ;
2019-12-12 14:44:57 +13:00
struct ldb_dn * stopped_dn = NULL ;
struct GUID_txt_buf guid_buf ;
2012-11-23 15:55:24 +01:00
int ret ;
2019-12-12 14:44:57 +13:00
bool stop = false ;
2012-11-23 15:55:24 +01:00
2022-02-10 16:20:51 +01:00
t - > changes . num_processed + = 1 ;
2013-06-23 19:47:35 +10:00
/*
2019-12-12 14:44:57 +13:00
* First confirm this object has children , or exists
* ( depending on change - > force_self )
2013-06-23 19:47:35 +10:00
*
* LDB_SCOPE_SUBTREE searches are expensive .
*
2019-11-26 15:44:32 +13:00
* We know this is safe against a rename race as we are in the
* prepare_commit ( ) , so must be in a transaction .
2013-06-23 19:47:35 +10:00
*/
2019-12-12 14:44:57 +13:00
/* Find the DN by GUID, as this is stable under rename */
ret = dsdb_module_search ( module ,
change ,
& guid_res ,
change - > nc_root ,
LDB_SCOPE_SUBTREE ,
no_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_DELETED |
2022-02-10 17:19:31 +01:00
DSDB_SEARCH_SHOW_RECYCLED |
DSDB_SEARCH_SHOW_EXTENDED_DN ,
2019-12-12 14:44:57 +13:00
NULL , /* parent_req */
" (objectGUID=%s) " ,
GUID_buf_string ( & change - > guid ,
& guid_buf ) ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( guid_res - > count ! = 1 ) {
/*
* We were just given this GUID during the same
* transaction , if it is missing this is a big
* problem .
*
* Cleanup of tombstones does not trigger this module
* as it just does a delete .
*/
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" failed to find GUID %s under %s "
" for transaction-end SD inheritance: %d results " ,
GUID_buf_string ( & change - > guid ,
& guid_buf ) ,
ldb_dn_get_linearized ( change - > nc_root ) ,
guid_res - > count ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
/*
* OK , so there was a parent , are there children ? Note : that
* this time we do not search for deleted / recycled objects
*/
2013-06-23 19:47:35 +10:00
ret = dsdb_module_search ( module ,
change ,
& res ,
2019-12-12 14:44:57 +13:00
guid_res - > msgs [ 0 ] - > dn ,
2013-06-23 19:47:35 +10:00
LDB_SCOPE_ONELEVEL ,
no_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
NULL , /* parent_req */
" (objectClass=*) " ) ;
if ( ret ! = LDB_SUCCESS ) {
2019-12-12 14:44:57 +13:00
/*
* LDB_ERR_NO_SUCH_OBJECT , say if the DN was a deleted
* object , is ignored by the caller
*/
2013-06-23 19:47:35 +10:00
return ret ;
}
if ( res - > count = = 0 & & ! change - > force_self ) {
2019-12-12 14:44:57 +13:00
/* All done, no children */
2013-06-23 19:47:35 +10:00
TALLOC_FREE ( res ) ;
return LDB_SUCCESS ;
}
2012-11-23 15:55:24 +01:00
/*
2019-12-12 14:44:57 +13:00
* First , if we are in force_self mode ( eg renamed under new
* parent ) then apply the SD to the top object
*/
if ( change - > force_self ) {
ret = descriptor_sd_propagation_object ( module ,
guid_res - > msgs [ 0 ] ,
& stop ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( guid_res ) ;
return ret ;
}
if ( stop = = true & & ! change - > force_children ) {
/* There was no change, nothing more to do */
TALLOC_FREE ( guid_res ) ;
return LDB_SUCCESS ;
}
if ( res - > count = = 0 ) {
/* All done! */
TALLOC_FREE ( guid_res ) ;
return LDB_SUCCESS ;
}
}
/*
* Look for children
*
2012-11-23 15:55:24 +01:00
* Note : that we do not search for deleted / recycled objects
*/
ret = dsdb_module_search ( module ,
change ,
& res ,
2019-12-12 14:44:57 +13:00
guid_res - > msgs [ 0 ] - > dn ,
LDB_SCOPE_SUBTREE ,
2012-11-23 15:55:24 +01:00
no_attrs ,
DSDB_FLAG_NEXT_MODULE |
2022-02-10 17:19:31 +01:00
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_EXTENDED_DN ,
2012-11-23 15:55:24 +01:00
NULL , /* parent_req */
" (objectClass=*) " ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
TYPESAFE_QSORT ( res - > msgs , res - > count ,
descriptor_sd_propagation_msg_sort ) ;
2019-12-12 14:44:57 +13:00
/* We start from 1, the top object has been done */
for ( i = 1 ; i < res - > count ; i + + ) {
/*
* ldb_dn_compare_base ( ) does not match for NULL but
* this is clearer
*/
if ( stopped_dn ! = NULL ) {
ret = ldb_dn_compare_base ( stopped_dn ,
res - > msgs [ i ] - > dn ) ;
2019-12-06 17:54:23 +13:00
/*
2019-12-12 14:44:57 +13:00
* Skip further processing of this
* sub - subtree
2019-12-06 17:54:23 +13:00
*/
2012-11-23 15:55:24 +01:00
if ( ret = = 0 ) {
continue ;
}
}
2019-12-12 14:44:57 +13:00
ret = descriptor_sd_propagation_object ( module ,
res - > msgs [ i ] ,
2012-11-23 15:55:24 +01:00
& stop ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( stop ) {
2019-12-12 14:44:57 +13:00
/*
* If this child didn ' t change , then nothing
* under it needs to change
*
* res has been sorted into tree order so the
* next few entries can be skipped
*/
stopped_dn = res - > msgs [ i ] - > dn ;
2012-11-23 15:55:24 +01:00
}
}
TALLOC_FREE ( res ) ;
return LDB_SUCCESS ;
}
static int descriptor_start_transaction ( struct ldb_module * module )
{
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
2022-02-10 14:33:15 +01:00
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2012-11-23 15:55:24 +01:00
2022-02-10 14:33:15 +01:00
if ( t - > mem ! = NULL ) {
2012-11-23 15:55:24 +01:00
return ldb_module_operr ( module ) ;
}
2022-02-10 14:33:15 +01:00
* t = ( struct descriptor_transaction ) { . mem = NULL , } ;
t - > mem = talloc_new ( descriptor_private ) ;
if ( t - > mem = = NULL ) {
2012-11-23 15:55:24 +01:00
return ldb_module_oom ( module ) ;
}
2022-02-10 14:36:28 +01:00
t - > changes . map = db_open_rbt ( t - > mem ) ;
if ( t - > changes . map = = NULL ) {
TALLOC_FREE ( t - > mem ) ;
* t = ( struct descriptor_transaction ) { . mem = NULL , } ;
return ldb_module_oom ( module ) ;
}
2022-02-10 12:46:10 +01:00
t - > objects . map = db_open_rbt ( t - > mem ) ;
if ( t - > objects . map = = NULL ) {
TALLOC_FREE ( t - > mem ) ;
* t = ( struct descriptor_transaction ) { . mem = NULL , } ;
return ldb_module_oom ( module ) ;
}
2012-11-23 15:55:24 +01:00
return ldb_next_start_trans ( module ) ;
}
static int descriptor_prepare_commit ( struct ldb_module * module )
{
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
2022-02-10 14:33:15 +01:00
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2022-02-10 17:19:31 +01:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2012-11-23 15:55:24 +01:00
struct descriptor_changes * c , * n ;
int ret ;
2022-02-10 14:36:28 +01:00
DBG_NOTICE ( " changes: num_registrations=%zu \n " ,
t - > changes . num_registrations ) ;
2022-02-10 16:20:51 +01:00
DBG_NOTICE ( " changes: num_registered=%zu \n " ,
t - > changes . num_registered ) ;
2022-02-10 17:19:31 +01:00
/*
* The security descriptor propagation
* needs to apply the inheritance from
* an object to itself and / or all it ' s
* children .
*
* In the initial replication during
* a join , we have every object in our
* list .
*
* In order to avoid useless work it ' s
* better to start with toplevel objects and
* move down to the leaf object from there .
*
* So if the parent_guid is also in our list ,
* we better move the object behind its parent .
*
* It allows that the recursive processing of
* the parent already does the work needed
* for the child .
*
* If we have a list for this directory tree :
*
* A
* - > B
* - > C
* - > D
* - > E
*
* The initial list would have the order D , E , B , A , C
*
* By still processing from the front , we ensure that ,
* when D is found to be below C , that E follows because
* we keep peeling items off the front for checking and
* move them behind their parent .
*
* So we would go :
*
* E B A C D
*
* B A C D E
*
* A B C D E
*/
2022-02-10 14:33:15 +01:00
for ( c = t - > changes . list ; c ; c = n ) {
2022-02-10 17:19:31 +01:00
struct descriptor_changes * pc = NULL ;
2012-11-23 15:55:24 +01:00
n = c - > next ;
2022-02-10 14:33:15 +01:00
2022-02-10 17:19:31 +01:00
if ( c - > sort_count > = t - > changes . num_registered ) {
/*
* This should never happen , but it ' s
* a sanity check in order to avoid
* endless loops . Just stop sorting .
*/
break ;
}
/*
* Check if we have the parent also in the list .
*/
if ( ! GUID_all_zero ( ( const void * ) & c - > parent_guid ) ) {
TDB_DATA pkey ;
NTSTATUS status ;
pkey = make_tdb_data ( ( const void * ) & c - > parent_guid ,
sizeof ( c - > parent_guid ) ) ;
status = dbwrap_parse_record ( t - > changes . map , pkey ,
descriptor_changes_parser , & pc ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
pc = NULL ;
status = NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_debug ( ldb , LDB_DEBUG_FATAL ,
" dbwrap_parse_record() - %s \n " ,
nt_errstr ( status ) ) ;
return ldb_module_operr ( module ) ;
}
}
if ( pc = = NULL ) {
/*
* There is no parent in the list
*/
t - > changes . num_toplevel + = 1 ;
continue ;
}
/*
* Move the child after the parent
*
* Note that we do that multiple times
* in case the parent already moved itself .
*
* See the comment above the loop .
*/
DLIST_REMOVE ( t - > changes . list , c ) ;
DLIST_ADD_AFTER ( t - > changes . list , c , pc ) ;
/*
* Remember how often we moved the object
* in order to avoid endless loops .
*/
c - > sort_count + = 1 ;
}
DBG_NOTICE ( " changes: num_toplevel=%zu \n " , t - > changes . num_toplevel ) ;
while ( t - > changes . list ! = NULL ) {
c = t - > changes . list ;
2022-02-10 14:33:15 +01:00
DLIST_REMOVE ( t - > changes . list , c ) ;
2012-11-23 15:55:24 +01:00
2022-02-10 17:19:31 +01:00
/*
* Note that descriptor_sd_propagation_recursive ( )
* may also remove other elements of the list ,
* so we can ' t use a next pointer
*/
2012-11-23 15:55:24 +01:00
ret = descriptor_sd_propagation_recursive ( module , c ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
continue ;
}
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2022-02-10 16:20:51 +01:00
DBG_NOTICE ( " changes: num_processed=%zu \n " , t - > changes . num_processed ) ;
DBG_NOTICE ( " objects: num_processed=%zu \n " , t - > objects . num_processed ) ;
2022-02-10 12:46:10 +01:00
DBG_NOTICE ( " objects: num_skipped=%zu \n " , t - > objects . num_skipped ) ;
2022-02-10 16:20:51 +01:00
2012-11-23 15:55:24 +01:00
return ldb_next_prepare_commit ( module ) ;
}
static int descriptor_end_transaction ( struct ldb_module * module )
{
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
2022-02-10 14:33:15 +01:00
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2012-11-23 15:55:24 +01:00
2022-02-10 14:33:15 +01:00
TALLOC_FREE ( t - > mem ) ;
* t = ( struct descriptor_transaction ) { . mem = NULL , } ;
2012-11-23 15:55:24 +01:00
return ldb_next_end_trans ( module ) ;
}
static int descriptor_del_transaction ( struct ldb_module * module )
{
struct descriptor_data * descriptor_private =
talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct descriptor_data ) ;
2022-02-10 14:33:15 +01:00
struct descriptor_transaction * t = & descriptor_private - > transaction ;
2012-11-23 15:55:24 +01:00
2022-02-10 14:33:15 +01:00
TALLOC_FREE ( t - > mem ) ;
* t = ( struct descriptor_transaction ) { . mem = NULL , } ;
2012-11-23 15:55:24 +01:00
return ldb_next_del_trans ( module ) ;
}
2009-09-19 21:45:07 -07:00
2010-11-01 15:28:02 +11:00
static const struct ldb_module_ops ldb_descriptor_module_ops = {
2012-11-23 15:55:24 +01:00
. name = " descriptor " ,
. search = descriptor_search ,
. add = descriptor_add ,
. modify = descriptor_modify ,
. rename = descriptor_rename ,
. init_context = descriptor_init ,
. extended = descriptor_extended ,
. start_transaction = descriptor_start_transaction ,
. prepare_commit = descriptor_prepare_commit ,
. end_transaction = descriptor_end_transaction ,
. del_transaction = descriptor_del_transaction ,
2009-09-14 19:44:41 +03:00
} ;
2010-11-01 15:28:02 +11:00
int ldb_descriptor_module_init ( const char * version )
{
2010-11-01 22:30:45 +11:00
LDB_MODULE_CHECK_VERSION ( version ) ;
2010-11-01 15:28:02 +11:00
return ldb_register_module ( & ldb_descriptor_module_ops ) ;
}