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"
# 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"
2009-12-14 20:36:44 -05:00
# include "util.h"
2009-09-14 19:44:41 +03:00
2009-09-19 21:45:07 -07:00
struct descriptor_data {
2009-10-20 13:00:12 +11:00
int _dummy ;
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 ;
struct ldb_reply * search_res ;
struct ldb_reply * search_oc_res ;
struct ldb_val * parentsd_val ;
struct ldb_val * sd_val ;
int ( * step_fn ) ( struct descriptor_context * ) ;
2009-09-14 19:44:41 +03:00
} ;
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 )
{
2009-12-09 15:18:37 +11:00
if ( dsdb_functional_level ( ldb ) > = DS_DOMAIN_FUNCTION_2008 ) {
2009-09-17 18:37:46 +02:00
return dag ;
}
return NULL ;
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 ) ) {
final_sd - > owner_sid = talloc_memdup ( mem_ctx , new_sd - > owner_sid , sizeof ( struct dom_sid ) ) ;
final_sd - > type | = new_sd - > type & SEC_DESC_OWNER_DEFAULTED ;
}
else if ( old_sd ) {
final_sd - > owner_sid = talloc_memdup ( mem_ctx , old_sd - > owner_sid , sizeof ( struct dom_sid ) ) ;
final_sd - > type | = old_sd - > type & SEC_DESC_OWNER_DEFAULTED ;
}
if ( sd_flags & ( SECINFO_GROUP ) ) {
final_sd - > group_sid = talloc_memdup ( mem_ctx , new_sd - > group_sid , sizeof ( struct dom_sid ) ) ;
final_sd - > type | = new_sd - > type & SEC_DESC_GROUP_DEFAULTED ;
}
else if ( old_sd ) {
final_sd - > group_sid = talloc_memdup ( mem_ctx , old_sd - > group_sid , sizeof ( struct dom_sid ) ) ;
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 ) ;
}
else if ( old_sd ) {
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 ) ;
}
else if ( old_sd ) {
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 ;
}
2009-09-14 19:44:41 +03:00
static DATA_BLOB * get_new_descriptor ( struct ldb_module * module ,
struct ldb_dn * dn ,
TALLOC_CTX * mem_ctx ,
const struct dsdb_class * objectclass ,
2009-09-17 18:37:46 +02:00
const struct ldb_val * parent ,
2009-11-20 13:25:13 +02:00
struct ldb_val * object ,
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
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 ;
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
}
2009-09-14 19:44:41 +03:00
ndr_err = ndr_pull_struct_blob ( object , user_descriptor , NULL ,
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 {
2009-09-14 19:44:41 +03:00
user_descriptor = get_sd_unpacked ( module , mem_ctx , objectclass ) ;
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 ;
}
ndr_err = ndr_pull_struct_blob ( old_sd , old_descriptor , NULL ,
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
}
2009-09-14 19:44:41 +03:00
ndr_err = ndr_pull_struct_blob ( parent , parent_descriptor , NULL ,
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
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 ) ;
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 ) ;
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 ;
}
2009-11-20 13:25:13 +02:00
sddl_sd = sddl_encode ( mem_ctx , final_sd , domain_sid ) ;
2009-11-15 22:31:44 +02:00
DEBUG ( 10 , ( " Object %s created with desriptor %s \n \n " , ldb_dn_get_linearized ( dn ) , sddl_sd ) ) ;
2009-09-14 19:44:41 +03:00
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 " ) ) ,
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 ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
old_sd = talloc ( mem_ctx , struct security_descriptor ) ;
if ( ! old_sd ) {
return NULL ;
}
ndr_err = ndr_pull_struct_blob ( sd , old_sd , NULL ,
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 ,
lp_iconv_convenience ( ldb_get_opaque ( ldb , " loadparm " ) ) ,
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 ;
}
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 ) ;
}
2009-09-21 20:08:52 -07:00
ldb_reset_err_string ( ldb ) ;
2009-09-14 19:44:41 +03:00
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
2009-11-15 22:31:44 +02:00
if ( ac - > search_res ! = NULL ) {
2009-09-14 19:44:41 +03:00
ldb_set_errstring ( ldb , " Too many results " ) ;
talloc_free ( ares ) ;
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
2009-11-15 22:31:44 +02:00
}
2009-09-14 19:44:41 +03:00
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 ;
}
2009-11-15 22:31:44 +02:00
static int get_search_oc_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 ) ;
}
ldb_reset_err_string ( ldb ) ;
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
if ( ac - > search_oc_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_oc_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 ;
}
2009-09-14 19:44:41 +03:00
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 ) ;
}
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_control * sd_control ;
struct ldb_val * sd_val = NULL ;
struct ldb_message_element * sd_el ;
DATA_BLOB * show_sd ;
int ret ;
uint32_t sd_flags = 0 ;
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 ) ;
}
sd_control = ldb_request_get_control ( ac - > req , LDB_CONTROL_SD_FLAGS_OID ) ;
2009-11-22 13:36:35 +02:00
if ( sd_control ) {
struct ldb_sd_flags_control * sdctr = ( struct ldb_sd_flags_control * ) sd_control - > data ;
sd_flags = sdctr - > secinfo_flags ;
/* we only care for the last 4 bits */
sd_flags = sd_flags & 0x0000000F ;
2009-12-16 20:39:18 +11:00
if ( sd_flags = = 0 ) {
/* MS-ADTS 3.1.1.3.4.1.11 says that no bits
equals all 4 bits */
sd_flags = 0xF ;
}
2009-11-22 13:36:35 +02:00
}
2009-11-21 18:40:51 +02:00
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
if ( sd_flags ! = 0 ) {
sd_el = ldb_msg_find_element ( ares - > message , " nTSecurityDescriptor " ) ;
if ( sd_el ) {
sd_val = sd_el - > values ;
}
}
if ( sd_val ) {
show_sd = descr_get_descriptor_to_show ( ac - > module , ac - > req ,
sd_val , sd_flags ) ;
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 :
/* ignore referrals */
break ;
case LDB_REPLY_DONE :
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
talloc_free ( ares ) ;
return LDB_SUCCESS ;
fail :
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
2009-11-15 22:31:44 +02:00
static int descriptor_do_mod ( struct descriptor_context * ac )
{
struct ldb_context * ldb ;
const struct dsdb_schema * schema ;
struct ldb_request * mod_req ;
2009-11-20 13:25:13 +02:00
struct ldb_message_element * objectclass_element , * tmp_element , * oldsd_el ;
struct ldb_val * oldsd_val = NULL ;
2009-11-15 22:31:44 +02:00
int ret ;
DATA_BLOB * sd ;
const struct dsdb_class * objectclass ;
struct ldb_message * msg ;
2009-11-20 13:25:13 +02:00
struct ldb_control * sd_control ;
2009-11-27 17:37:14 +03:00
struct ldb_control * sd_control2 ;
2009-11-15 22:31:44 +02:00
int flags = 0 ;
2009-11-20 13:25:13 +02:00
uint32_t sd_flags = 0 ;
2009-11-15 22:31:44 +02:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
2010-03-16 14:52:39 +11:00
schema = dsdb_get_schema ( ldb , ac ) ;
2009-11-15 22:31:44 +02:00
msg = ldb_msg_copy_shallow ( ac , ac - > req - > op . mod . message ) ;
objectclass_element = ldb_msg_find_element ( ac - > search_oc_res - > message , " objectClass " ) ;
objectclass = get_last_structural_class ( schema , objectclass_element ) ;
if ( ! objectclass ) {
ldb_asprintf_errstring ( ldb , " No last structural objectclass found on %s " ,
ldb_dn_get_linearized ( ac - > search_oc_res - > message - > dn ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-11-20 13:25:13 +02:00
sd_control = ldb_request_get_control ( ac - > req , LDB_CONTROL_SD_FLAGS_OID ) ;
2009-11-27 17:37:14 +03:00
sd_control2 = ldb_request_get_control ( ac - > req , LDB_CONTROL_RECALCULATE_SD_OID ) ;
2009-11-20 13:25:13 +02:00
if ( sd_control ) {
struct ldb_sd_flags_control * sdctr = ( struct ldb_sd_flags_control * ) sd_control - > data ;
sd_flags = sdctr - > secinfo_flags ;
/* we only care for the last 4 bits */
sd_flags = sd_flags & 0x0000000F ;
}
if ( sd_flags ! = 0 ) {
oldsd_el = ldb_msg_find_element ( ac - > search_oc_res - > message , " nTSecurityDescriptor " ) ;
if ( oldsd_el ) {
oldsd_val = oldsd_el - > values ;
}
}
2009-11-15 22:31:44 +02:00
sd = get_new_descriptor ( ac - > module , msg - > dn , ac , objectclass ,
2009-11-20 13:25:13 +02:00
ac - > parentsd_val , ac - > sd_val , oldsd_val , sd_flags ) ;
2009-11-15 22:31:44 +02:00
if ( ac - > sd_val ) {
tmp_element = ldb_msg_find_element ( msg , " ntSecurityDescriptor " ) ;
flags = tmp_element - > flags ;
ldb_msg_remove_attr ( msg , " nTSecurityDescriptor " ) ;
}
if ( sd ) {
ret = ldb_msg_add_steal_value ( msg , " nTSecurityDescriptor " , sd ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
tmp_element = ldb_msg_find_element ( msg , " ntSecurityDescriptor " ) ;
2009-11-27 17:37:14 +03:00
if ( sd_control2 ) {
tmp_element - > flags = LDB_FLAG_MOD_REPLACE ;
} else {
tmp_element - > flags = flags ;
}
2009-11-15 22:31:44 +02:00
}
ret = ldb_build_mod_req ( & mod_req , ldb , ac ,
msg ,
ac - > req - > controls ,
ac , descriptor_op_callback ,
ac - > req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-16 20:39:18 +11:00
/* mark it non-critical, so we don't get an error from the
backend , but mark that we ' ve handled it */
2009-11-20 13:25:13 +02:00
if ( sd_control ) {
2009-12-16 20:39:18 +11:00
sd_control - > critical = 0 ;
2009-11-20 13:25:13 +02:00
}
2009-11-15 22:31:44 +02:00
return ldb_next_request ( ac - > module , mod_req ) ;
}
2009-09-14 19:44:41 +03:00
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 ;
DATA_BLOB * sd ;
2009-09-17 18:37:46 +02:00
const struct dsdb_class * objectclass ;
2009-11-20 13:25:13 +02:00
static const char * const attrs [ ] = { " objectClass " , " nTSecurityDescriptor " , NULL } ;
2009-11-15 22:31:44 +02:00
struct ldb_request * search_req ;
2009-09-14 19:44:41 +03:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
2010-03-16 14:52:39 +11:00
schema = dsdb_get_schema ( ldb , ac ) ;
2009-09-14 19:44:41 +03:00
mem_ctx = talloc_new ( ac ) ;
if ( mem_ctx = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-11-15 22:31:44 +02:00
switch ( ac - > req - > operation ) {
case LDB_ADD :
msg = ldb_msg_copy_shallow ( ac , ac - > req - > op . add . message ) ;
objectclass_element = ldb_msg_find_element ( msg , " objectClass " ) ;
objectclass = get_last_structural_class ( schema , objectclass_element ) ;
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
if ( ! objectclass ) {
ldb_asprintf_errstring ( ldb , " No last structural objectclass found on %s " , ldb_dn_get_linearized ( msg - > dn ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
break ;
case LDB_MODIFY :
msg = ldb_msg_copy_shallow ( ac , ac - > req - > op . mod . message ) ;
break ;
default :
2009-09-14 19:44:41 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2009-09-21 20:08:52 -07:00
}
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
/* get the security descriptor values*/
sd_element = ldb_msg_find_element ( msg , " nTSecurityDescriptor " ) ;
if ( sd_element ) {
ac - > sd_val = talloc_memdup ( ac , & sd_element - > values [ 0 ] , sizeof ( struct ldb_val ) ) ;
}
2009-09-14 19:44:41 +03:00
/* NC's have no parent */
if ( ( ldb_dn_compare ( msg - > dn , ( ldb_get_schema_basedn ( ldb ) ) ) = = 0 ) | |
2009-09-21 20:08:52 -07:00
( ldb_dn_compare ( msg - > dn , ( ldb_get_config_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( msg - > dn , ( ldb_get_root_basedn ( ldb ) ) ) = = 0 ) ) {
2009-11-15 22:31:44 +02:00
ac - > parentsd_val = NULL ;
} else if ( ac - > search_res ! = NULL ) {
struct ldb_message_element * parent_element = ldb_msg_find_element ( ac - > search_res - > message , " nTSecurityDescriptor " ) ;
if ( parent_element ) {
ac - > parentsd_val = talloc_memdup ( ac , & parent_element - > values [ 0 ] , sizeof ( struct ldb_val ) ) ;
}
2009-09-21 20:08:52 -07:00
}
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
if ( ac - > req - > operation = = LDB_ADD ) {
2009-09-14 19:44:41 +03:00
/* get the parent descriptor and the one provided. If not provided, get the default.*/
/* convert to security descriptor and calculate */
2009-11-15 22:31:44 +02:00
sd = get_new_descriptor ( ac - > module , msg - > dn , mem_ctx , objectclass ,
2009-11-20 13:25:13 +02:00
ac - > parentsd_val , ac - > sd_val , NULL , 0 ) ;
2009-11-15 22:31:44 +02:00
if ( ac - > sd_val ) {
ldb_msg_remove_attr ( msg , " nTSecurityDescriptor " ) ;
}
2009-09-21 20:08:52 -07:00
2009-11-15 22:31:44 +02:00
if ( sd ) {
ret = ldb_msg_add_steal_value ( msg , " nTSecurityDescriptor " , sd ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-09-21 20:08:52 -07:00
}
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
talloc_free ( mem_ctx ) ;
ret = ldb_msg_sanity_check ( ldb , msg ) ;
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " No last structural objectclass found on %s " ,
ldb_dn_get_linearized ( msg - > dn ) ) ;
return ret ;
}
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
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 ;
}
return ldb_next_request ( ac - > module , add_req ) ;
} else {
ret = ldb_build_search_req ( & search_req , ldb ,
ac , msg - > dn , LDB_SCOPE_BASE ,
" (objectClass=*) " , attrs ,
NULL ,
ac , get_search_oc_callback ,
ac - > req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ac - > step_fn = descriptor_do_mod ;
return ldb_next_request ( ac - > module , search_req ) ;
2009-09-14 19:44:41 +03:00
}
}
2009-11-15 22:31:44 +02:00
static int descriptor_change ( struct ldb_module * module , struct ldb_request * req )
2009-09-14 19:44:41 +03:00
{
struct ldb_context * ldb ;
2009-11-27 17:37:14 +03:00
struct ldb_control * sd_control ;
2009-09-14 19:44:41 +03:00
struct ldb_request * search_req ;
struct descriptor_context * ac ;
2009-11-15 22:31:44 +02:00
struct ldb_dn * parent_dn , * dn ;
struct ldb_message_element * sd_element ;
2009-09-14 19:44:41 +03:00
int ret ;
static const char * const descr_attrs [ ] = { " nTSecurityDescriptor " , NULL } ;
ldb = ldb_module_get_ctx ( module ) ;
2009-11-15 22:31:44 +02:00
switch ( req - > operation ) {
case LDB_ADD :
dn = req - > op . add . message - > dn ;
break ;
case LDB_MODIFY :
dn = req - > op . mod . message - > dn ;
sd_element = ldb_msg_find_element ( req - > op . mod . message , " nTSecurityDescriptor " ) ;
2009-11-27 17:37:14 +03:00
/* This control allow forcing the recalculation of the SD */
sd_control = ldb_request_get_control ( req , LDB_CONTROL_RECALCULATE_SD_OID ) ;
if ( ! sd_element & & ! sd_control ) {
2009-11-15 22:31:44 +02:00
return ldb_next_request ( module , req ) ;
}
break ;
default :
return LDB_ERR_OPERATIONS_ERROR ;
}
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_change: %s \n " , ldb_dn_get_linearized ( dn ) ) ;
2009-09-14 19:44:41 +03:00
2009-11-15 22:31:44 +02:00
if ( ldb_dn_is_special ( dn ) ) {
2009-09-14 19:44:41 +03:00
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 */
2009-11-15 22:31:44 +02:00
if ( ldb_dn_get_comp_num ( dn ) = = 1 ) {
2009-09-14 19:44:41 +03:00
return descriptor_do_add ( ac ) ;
}
/* get copy of parent DN */
2009-11-15 22:31:44 +02:00
parent_dn = ldb_dn_get_parent ( ac , dn ) ;
2009-09-14 19:44:41 +03:00
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 ) ;
}
2009-11-15 22:31:44 +02:00
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_control * sd_control ;
struct ldb_request * down_req ;
struct descriptor_context * ac ;
sd_control = ldb_request_get_control ( req , LDB_CONTROL_SD_FLAGS_OID ) ;
if ( ! sd_control ) {
return ldb_next_request ( module , req ) ;
}
ldb = ldb_module_get_ctx ( module ) ;
ac = descriptor_init_context ( module , req ) ;
if ( ac = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-16 20:39:18 +11:00
/* mark it as handled */
2009-11-21 18:40:51 +02:00
if ( sd_control ) {
2009-12-16 20:39:18 +11:00
sd_control - > critical = 0 ;
2009-11-21 18:40:51 +02:00
}
return ldb_next_request ( ac - > module , down_req ) ;
}
2009-09-14 19:44:41 +03:00
/* TODO */
static int descriptor_rename ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-11-03 11:21:05 +02:00
ldb_debug ( ldb , LDB_DEBUG_TRACE , " descriptor_rename: %s \n " , ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ;
2009-09-14 19:44:41 +03:00
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
int ret = ldb_mod_register_control ( module , LDB_CONTROL_SD_FLAGS_OID ) ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_ERROR ,
" descriptor: Unable to register control with rootdse! \n " ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-09-19 21:45:07 -07:00
return ldb_next_init ( module ) ;
}
2009-09-14 19:44:41 +03:00
_PUBLIC_ const struct ldb_module_ops ldb_descriptor_module_ops = {
2009-11-21 18:40:51 +02:00
. name = " descriptor " ,
. search = descriptor_search ,
2009-11-15 22:31:44 +02:00
. add = descriptor_change ,
. modify = descriptor_change ,
2009-09-14 19:44:41 +03:00
. rename = descriptor_rename ,
2009-09-19 21:45:07 -07:00
. init_context = descriptor_init
2009-09-14 19:44:41 +03:00
} ;