2009-09-21 17:27:50 -07:00
/*
2009-12-10 15:49:53 +02:00
ldb database library
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
Copyright ( C ) Simo Sorce 2006 - 2008
Copyright ( C ) Nadezhda Ivanova 2009
Copyright ( C ) Anatoliy Atanasov 2009
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
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 .
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
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 .
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-09-21 17:27:50 -07:00
*/
/*
* Name : ldb
*
* Component : ldb ACL module
*
* Description : Module that performs authorisation access checks based on the
* account ' s security context and the DACL of the object being polled .
* Only DACL checks implemented at this point
*
* Authors : Nadezhda Ivanova , Anatoliy Atanasov
*/
# include "includes.h"
# include "ldb_module.h"
# include "auth/auth.h"
# include "libcli/security/security.h"
# include "dsdb/samdb/samdb.h"
# include "librpc/gen_ndr/ndr_security.h"
# include "param/param.h"
2010-01-08 09:30:59 +11:00
# include "dsdb/samdb/ldb_modules/util.h"
2010-02-13 12:59:43 +11:00
# include "lib/util/tsort.h"
2009-09-21 17:27:50 -07:00
struct extended_access_check_attribute {
const char * oa_name ;
const uint32_t requires_rights ;
} ;
2009-12-10 15:49:53 +02:00
struct acl_private {
bool acl_perform ;
const char * * password_attrs ;
} ;
struct acl_context {
struct ldb_module * module ;
struct ldb_request * req ;
2010-01-08 09:30:31 +11:00
bool am_system ;
2009-12-10 15:49:53 +02:00
bool allowedAttributes ;
bool allowedAttributesEffective ;
bool allowedChildClasses ;
bool allowedChildClassesEffective ;
bool sDRightsEffective ;
const char * const * attrs ;
2009-09-21 17:27:50 -07:00
} ;
bool is_root_base_dn ( struct ldb_context * ldb , struct ldb_dn * dn_to_check )
{
int result ;
struct ldb_dn * root_base_dn = ldb_get_root_basedn ( ldb ) ;
result = ldb_dn_compare ( root_base_dn , dn_to_check ) ;
return ( result = = 0 ) ;
}
2009-11-05 17:34:12 +02:00
static struct security_token * acl_user_token ( struct ldb_module * module )
2009-09-21 17:27:50 -07:00
{
2009-11-05 17:34:12 +02:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct auth_session_info * session_info
= ( struct auth_session_info * ) ldb_get_opaque ( ldb , " sessionInfo " ) ;
if ( ! session_info ) {
return NULL ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
return session_info - > security_token ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
static int acl_module_init ( struct ldb_module * module )
2009-09-21 17:27:50 -07:00
{
2009-11-05 17:34:12 +02:00
struct ldb_context * ldb ;
struct acl_private * data ;
2009-12-10 15:49:53 +02:00
int ret , i ;
TALLOC_CTX * mem_ctx = talloc_new ( module ) ;
static const char * attrs [ ] = { " passwordAttribute " , NULL } ;
struct ldb_result * res ;
struct ldb_message * msg ;
struct ldb_message_element * password_attributes ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
ldb = ldb_module_get_ctx ( module ) ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
ret = ldb_mod_register_control ( module , LDB_CONTROL_SD_FLAGS_OID ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_debug ( ldb , LDB_DEBUG_ERROR ,
" acl_module_init: Unable to register control with rootdse! \n " ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
data = talloc ( module , struct acl_private ) ;
2009-12-10 15:49:53 +02:00
if ( data = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
data - > password_attrs = NULL ;
data - > acl_perform = lp_parm_bool ( ldb_get_opaque ( ldb , " loadparm " ) ,
NULL , " acl " , " perform " , false ) ;
2009-11-05 17:34:12 +02:00
ldb_module_set_private ( module , data ) ;
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
if ( ! mem_ctx ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2010-03-12 02:21:16 +02:00
ret = dsdb_module_search_dn ( module , mem_ctx , & res ,
ldb_dn_new ( mem_ctx , ldb , " @KLUDGEACL " ) ,
attrs , 0 ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
goto done ;
}
if ( res - > count = = 0 ) {
goto done ;
}
if ( res - > count > 1 ) {
talloc_free ( mem_ctx ) ;
return LDB_ERR_CONSTRAINT_VIOLATION ;
}
msg = res - > msgs [ 0 ] ;
password_attributes = ldb_msg_find_element ( msg , " passwordAttribute " ) ;
if ( ! password_attributes ) {
goto done ;
}
data - > password_attrs = talloc_array ( data , const char * , password_attributes - > num_values + 1 ) ;
if ( ! data - > password_attrs ) {
talloc_free ( mem_ctx ) ;
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
for ( i = 0 ; i < password_attributes - > num_values ; i + + ) {
data - > password_attrs [ i ] = ( const char * ) password_attributes - > values [ i ] . data ;
talloc_steal ( data - > password_attrs , password_attributes - > values [ i ] . data ) ;
}
data - > password_attrs [ i ] = NULL ;
done :
talloc_free ( mem_ctx ) ;
2009-11-05 17:34:12 +02:00
return ldb_next_init ( module ) ;
2009-09-21 17:27:50 -07:00
}
2009-12-10 15:49:53 +02:00
static const struct GUID * get_oc_guid_from_message ( struct ldb_module * module ,
struct ldb_message * msg )
2009-09-21 17:27:50 -07:00
{
2009-11-05 17:34:12 +02:00
struct ldb_message_element * oc_el ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
oc_el = ldb_msg_find_element ( msg , " objectClass " ) ;
2009-11-05 17:34:12 +02:00
if ( ! oc_el ) {
return NULL ;
}
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
return class_schemaid_guid_by_lDAPDisplayName ( dsdb_get_schema ( ldb ) ,
( char * ) oc_el - > values [ oc_el - > num_values - 1 ] . data ) ;
2009-09-21 17:27:50 -07:00
}
2009-12-10 15:49:53 +02:00
static int acl_check_access_on_attribute ( struct ldb_module * module ,
TALLOC_CTX * mem_ctx ,
struct security_descriptor * sd ,
2009-12-17 17:25:11 +02:00
struct dom_sid * rp_sid ,
2009-12-10 15:49:53 +02:00
uint32_t access ,
2010-01-08 09:30:59 +11:00
const struct dsdb_attribute * attr )
2009-12-10 15:49:53 +02:00
{
int ret ;
NTSTATUS status ;
uint32_t access_granted ;
struct object_tree * root = NULL ;
struct object_tree * new_node = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct security_token * token = acl_user_token ( module ) ;
if ( attr ) {
if ( ! GUID_all_zero ( & attr - > attributeSecurityGUID ) ) {
if ( ! insert_in_object_tree ( tmp_ctx ,
& attr - > attributeSecurityGUID , access ,
& root , & new_node ) ) {
DEBUG ( 10 , ( " acl_search: cannot add to object tree securityGUID \n " ) ) ;
goto fail ;
}
if ( ! insert_in_object_tree ( tmp_ctx ,
& attr - > schemaIDGUID , access , & new_node , & new_node ) ) {
DEBUG ( 10 , ( " acl_search: cannot add to object tree attributeGUID \n " ) ) ;
goto fail ;
}
}
else {
if ( ! insert_in_object_tree ( tmp_ctx ,
& attr - > schemaIDGUID , access , & root , & new_node ) ) {
DEBUG ( 10 , ( " acl_search: cannot add to object tree attributeGUID \n " ) ) ;
goto fail ;
}
}
}
status = sec_access_check_ds ( sd , token ,
access ,
& access_granted ,
2009-12-17 17:25:11 +02:00
root ,
rp_sid ) ;
2009-12-10 15:49:53 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
else {
ret = LDB_SUCCESS ;
}
return ret ;
fail :
return LDB_ERR_OPERATIONS_ERROR ;
}
static int acl_check_access_on_class ( struct ldb_module * module ,
TALLOC_CTX * mem_ctx ,
struct security_descriptor * sd ,
2009-12-17 17:25:11 +02:00
struct dom_sid * rp_sid ,
2009-12-10 15:49:53 +02:00
uint32_t access ,
const char * class_name )
{
int ret ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
NTSTATUS status ;
uint32_t access_granted ;
struct object_tree * root = NULL ;
struct object_tree * new_node = NULL ;
2010-01-08 09:30:59 +11:00
const struct GUID * guid ;
2009-12-10 15:49:53 +02:00
const struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct security_token * token = acl_user_token ( module ) ;
if ( class_name ) {
guid = class_schemaid_guid_by_lDAPDisplayName ( schema , class_name ) ;
if ( ! guid ) {
DEBUG ( 10 , ( " acl_search: cannot find class %s \n " ,
class_name ) ) ;
goto fail ;
}
if ( ! insert_in_object_tree ( tmp_ctx ,
guid , access ,
& root , & new_node ) ) {
DEBUG ( 10 , ( " acl_search: cannot add to object tree guid \n " ) ) ;
goto fail ;
}
}
status = sec_access_check_ds ( sd , token ,
access ,
& access_granted ,
2009-12-17 17:25:11 +02:00
root ,
rp_sid ) ;
2009-12-10 15:49:53 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
else {
ret = LDB_SUCCESS ;
}
return ret ;
fail :
return LDB_ERR_OPERATIONS_ERROR ;
}
static int acl_allowedAttributes ( struct ldb_module * module ,
struct ldb_message * sd_msg ,
struct ldb_message * msg ,
struct acl_context * ac )
{
struct ldb_message_element * oc_el ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
const struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
TALLOC_CTX * mem_ctx ;
const char * * attr_list ;
int i , ret ;
/* If we don't have a schema yet, we can't do anything... */
if ( schema = = NULL ) {
return LDB_SUCCESS ;
}
/* Must remove any existing attribute */
if ( ac - > allowedAttributes ) {
ldb_msg_remove_attr ( msg , " allowedAttributes " ) ;
}
mem_ctx = talloc_new ( msg ) ;
if ( ! mem_ctx ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
oc_el = ldb_msg_find_element ( sd_msg , " objectClass " ) ;
attr_list = dsdb_full_attribute_list ( mem_ctx , schema , oc_el , DSDB_SCHEMA_ALL ) ;
if ( ! attr_list ) {
ldb_asprintf_errstring ( ldb , " acl: Failed to get list of attributes " ) ;
talloc_free ( mem_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
if ( ac - > allowedAttributes ) {
for ( i = 0 ; attr_list & & attr_list [ i ] ; i + + ) {
ldb_msg_add_string ( msg , " allowedAttributes " , attr_list [ i ] ) ;
}
}
if ( ac - > allowedAttributesEffective ) {
struct security_descriptor * sd ;
2009-12-17 17:25:11 +02:00
struct dom_sid * sid = NULL ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( ac - > req ,
LDB_CONTROL_AS_SYSTEM_OID ) ;
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2009-12-10 15:49:53 +02:00
ldb_msg_remove_attr ( msg , " allowedAttributesEffective " ) ;
2010-01-08 09:30:31 +11:00
if ( ac - > am_system | | as_system ) {
2009-12-10 15:49:53 +02:00
for ( i = 0 ; attr_list & & attr_list [ i ] ; i + + ) {
ldb_msg_add_string ( msg , " allowedAttributesEffective " , attr_list [ i ] ) ;
}
return LDB_SUCCESS ;
}
2010-03-11 23:10:38 +02:00
ret = dsdb_get_sd_from_ldb_message ( mem_ctx , sd_msg , & sd ) ;
2009-12-10 15:49:53 +02:00
2009-12-17 17:25:11 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-03-11 23:10:38 +02:00
ret = dsdb_get_dom_sid_from_ldb_message ( mem_ctx , sd_msg , & sid ) ;
2009-12-17 17:25:11 +02:00
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
for ( i = 0 ; attr_list & & attr_list [ i ] ; i + + ) {
2010-01-08 09:30:59 +11:00
const struct dsdb_attribute * attr = dsdb_attribute_by_lDAPDisplayName ( schema ,
2009-12-10 15:49:53 +02:00
attr_list [ i ] ) ;
if ( ! attr ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
/* remove constructed attributes */
2009-12-15 12:02:20 +02:00
if ( attr - > systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
| | attr - > systemOnly
| | ( attr - > linkID ! = 0 & & attr - > linkID % 2 ! = 0 ) ) {
2009-12-10 15:49:53 +02:00
continue ;
}
ret = acl_check_access_on_attribute ( module ,
msg ,
sd ,
2009-12-17 17:25:11 +02:00
sid ,
2009-12-10 15:49:53 +02:00
SEC_ADS_WRITE_PROP ,
attr ) ;
if ( ret = = LDB_SUCCESS ) {
ldb_msg_add_string ( msg , " allowedAttributesEffective " , attr_list [ i ] ) ;
}
}
}
return LDB_SUCCESS ;
}
static int acl_childClasses ( struct ldb_module * module ,
struct ldb_message * sd_msg ,
struct ldb_message * msg ,
const char * attrName )
{
struct ldb_message_element * oc_el ;
struct ldb_message_element * allowedClasses ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
const struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
const struct dsdb_class * sclass ;
int i , j , ret ;
/* If we don't have a schema yet, we can't do anything... */
if ( schema = = NULL ) {
return LDB_SUCCESS ;
}
/* Must remove any existing attribute, or else confusion reins */
ldb_msg_remove_attr ( msg , attrName ) ;
ret = ldb_msg_add_empty ( msg , attrName , 0 , & allowedClasses ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
oc_el = ldb_msg_find_element ( sd_msg , " objectClass " ) ;
for ( i = 0 ; oc_el & & i < oc_el - > num_values ; i + + ) {
sclass = dsdb_class_by_lDAPDisplayName_ldb_val ( schema , & oc_el - > values [ i ] ) ;
if ( ! sclass ) {
/* We don't know this class? what is going on? */
continue ;
}
for ( j = 0 ; sclass - > possibleInferiors & & sclass - > possibleInferiors [ j ] ; j + + ) {
ldb_msg_add_string ( msg , attrName , sclass - > possibleInferiors [ j ] ) ;
}
}
if ( allowedClasses - > num_values > 1 ) {
2010-02-13 12:59:43 +11:00
TYPESAFE_QSORT ( allowedClasses - > values , allowedClasses - > num_values , data_blob_cmp ) ;
2009-12-10 15:49:53 +02:00
for ( i = 1 ; i < allowedClasses - > num_values ; i + + ) {
struct ldb_val * val1 = & allowedClasses - > values [ i - 1 ] ;
struct ldb_val * val2 = & allowedClasses - > values [ i ] ;
if ( data_blob_cmp ( val1 , val2 ) = = 0 ) {
memmove ( val1 , val2 , ( allowedClasses - > num_values - i ) * sizeof ( struct ldb_val ) ) ;
allowedClasses - > num_values - - ;
i - - ;
}
}
}
return LDB_SUCCESS ;
}
static int acl_childClassesEffective ( struct ldb_module * module ,
struct ldb_message * sd_msg ,
struct ldb_message * msg ,
struct acl_context * ac )
{
struct ldb_message_element * oc_el ;
struct ldb_message_element * allowedClasses = NULL ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
const struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
const struct dsdb_class * sclass ;
struct security_descriptor * sd ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( ac - > req ,
LDB_CONTROL_AS_SYSTEM_OID ) ;
2009-12-17 17:25:11 +02:00
struct dom_sid * sid = NULL ;
2009-12-10 15:49:53 +02:00
int i , j , ret ;
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2010-01-08 09:30:31 +11:00
if ( ac - > am_system | | as_system ) {
2009-12-10 15:49:53 +02:00
return acl_childClasses ( module , sd_msg , msg , " allowedChildClassesEffective " ) ;
}
/* If we don't have a schema yet, we can't do anything... */
if ( schema = = NULL ) {
return LDB_SUCCESS ;
}
/* Must remove any existing attribute, or else confusion reins */
ldb_msg_remove_attr ( msg , " allowedChildClassesEffective " ) ;
oc_el = ldb_msg_find_element ( sd_msg , " objectClass " ) ;
2010-03-11 23:10:38 +02:00
ret = dsdb_get_sd_from_ldb_message ( msg , sd_msg , & sd ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-03-11 23:10:38 +02:00
ret = dsdb_get_dom_sid_from_ldb_message ( msg , sd_msg , & sid ) ;
2009-12-10 15:49:53 +02:00
2009-12-17 17:25:11 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-10 15:49:53 +02:00
for ( i = 0 ; oc_el & & i < oc_el - > num_values ; i + + ) {
sclass = dsdb_class_by_lDAPDisplayName_ldb_val ( schema , & oc_el - > values [ i ] ) ;
if ( ! sclass ) {
/* We don't know this class? what is going on? */
continue ;
}
for ( j = 0 ; sclass - > possibleInferiors & & sclass - > possibleInferiors [ j ] ; j + + ) {
ret = acl_check_access_on_class ( module ,
msg ,
sd ,
2009-12-17 17:25:11 +02:00
sid ,
2009-12-10 15:49:53 +02:00
SEC_ADS_CREATE_CHILD ,
sclass - > possibleInferiors [ j ] ) ;
if ( ret = = LDB_SUCCESS ) {
ldb_msg_add_string ( msg , " allowedChildClassesEffective " ,
sclass - > possibleInferiors [ j ] ) ;
}
}
}
allowedClasses = ldb_msg_find_element ( msg , " allowedChildClassesEffective " ) ;
if ( ! allowedClasses ) {
return LDB_SUCCESS ;
}
if ( allowedClasses - > num_values > 1 ) {
2010-02-13 12:59:43 +11:00
TYPESAFE_QSORT ( allowedClasses - > values , allowedClasses - > num_values , data_blob_cmp ) ;
2009-12-10 15:49:53 +02:00
for ( i = 1 ; i < allowedClasses - > num_values ; i + + ) {
struct ldb_val * val1 = & allowedClasses - > values [ i - 1 ] ;
struct ldb_val * val2 = & allowedClasses - > values [ i ] ;
if ( data_blob_cmp ( val1 , val2 ) = = 0 ) {
memmove ( val1 , val2 , ( allowedClasses - > num_values - i ) * sizeof ( struct ldb_val ) ) ;
allowedClasses - > num_values - - ;
i - - ;
}
}
}
return LDB_SUCCESS ;
}
static int acl_sDRightsEffective ( struct ldb_module * module ,
struct ldb_message * sd_msg ,
struct ldb_message * msg ,
struct acl_context * ac )
{
struct ldb_message_element * rightsEffective ;
int ret ;
struct security_descriptor * sd ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( ac - > req ,
LDB_CONTROL_AS_SYSTEM_OID ) ;
2009-12-17 17:25:11 +02:00
struct dom_sid * sid = NULL ;
2009-12-10 15:49:53 +02:00
uint32_t flags = 0 ;
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2009-12-10 15:49:53 +02:00
/* Must remove any existing attribute, or else confusion reins */
ldb_msg_remove_attr ( msg , " sDRightsEffective " ) ;
ret = ldb_msg_add_empty ( msg , " sDRightsEffective " , 0 , & rightsEffective ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-01-08 09:30:31 +11:00
if ( ac - > am_system | | as_system ) {
2009-12-10 15:49:53 +02:00
flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL ;
}
else {
/* Get the security descriptor from the message */
2010-03-11 23:10:38 +02:00
ret = dsdb_get_sd_from_ldb_message ( msg , sd_msg , & sd ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-03-11 23:10:38 +02:00
ret = dsdb_get_dom_sid_from_ldb_message ( msg , sd_msg , & sid ) ;
2009-12-10 15:49:53 +02:00
2009-12-17 17:25:11 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-10 15:49:53 +02:00
ret = acl_check_access_on_attribute ( module ,
msg ,
sd ,
2009-12-17 17:25:11 +02:00
sid ,
2009-12-10 15:49:53 +02:00
SEC_STD_WRITE_OWNER ,
NULL ) ;
if ( ret = = LDB_SUCCESS ) {
flags | = SECINFO_OWNER | SECINFO_GROUP ;
}
ret = acl_check_access_on_attribute ( module ,
msg ,
sd ,
2009-12-17 17:25:11 +02:00
sid ,
2009-12-10 15:49:53 +02:00
SEC_STD_WRITE_DAC ,
NULL ) ;
if ( ret = = LDB_SUCCESS ) {
flags | = SECINFO_DACL ;
}
ret = acl_check_access_on_attribute ( module ,
msg ,
sd ,
2009-12-17 17:25:11 +02:00
sid ,
2009-12-10 15:49:53 +02:00
SEC_FLAG_SYSTEM_SECURITY ,
NULL ) ;
if ( ret = = LDB_SUCCESS ) {
flags | = SECINFO_SACL ;
}
}
ldb_msg_add_fmt ( msg , " sDRightsEffective " , " %u " , flags ) ;
return LDB_SUCCESS ;
}
2009-11-05 17:34:12 +02:00
static int acl_add ( struct ldb_module * module , struct ldb_request * req )
2009-09-21 17:27:50 -07:00
{
2009-11-05 17:34:12 +02:00
int ret ;
struct ldb_dn * parent = ldb_dn_get_parent ( req , req - > op . add . message - > dn ) ;
struct ldb_context * ldb ;
struct ldb_message_element * oc_el ;
const struct GUID * guid ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
2009-09-21 17:27:50 -07:00
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2010-01-08 09:30:31 +11:00
if ( dsdb_module_am_system ( module ) | | as_system ) {
2009-11-05 17:34:12 +02:00
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
if ( ldb_dn_is_special ( req - > op . add . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
ldb = ldb_module_get_ctx ( module ) ;
/* Creating an NC. There is probably something we should do here,
* but we will establish that later */
if ( ( ldb_dn_compare ( req - > op . add . message - > dn , ( ldb_get_schema_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( req - > op . add . message - > dn , ( ldb_get_config_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( req - > op . add . message - > dn , ( ldb_get_root_basedn ( ldb ) ) ) = = 0 ) ) {
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
oc_el = ldb_msg_find_element ( req - > op . add . message , " objectClass " ) ;
if ( ! oc_el | | oc_el - > num_values = = 0 ) {
DEBUG ( 10 , ( " acl:operation error %s \n " , ldb_dn_get_linearized ( req - > op . add . message - > dn ) ) ) ;
return ldb_module_done ( req , NULL , NULL , LDB_ERR_OPERATIONS_ERROR ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
guid = class_schemaid_guid_by_lDAPDisplayName ( dsdb_get_schema ( ldb ) ,
( char * ) oc_el - > values [ oc_el - > num_values - 1 ] . data ) ;
2010-03-11 23:10:38 +02:00
ret = dsdb_check_access_on_dn ( ldb , req , parent , SEC_ADS_CREATE_CHILD , guid ) ;
2009-09-21 17:27:50 -07:00
if ( ret ! = LDB_SUCCESS ) {
2009-11-05 17:34:12 +02:00
return ret ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
static int acl_modify ( struct ldb_module * module , struct ldb_request * req )
2009-09-21 17:27:50 -07:00
{
int ret ;
2009-11-05 17:34:12 +02:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
const struct dsdb_schema * schema = dsdb_get_schema ( ldb ) ;
2010-03-07 19:16:24 +01:00
unsigned int i ;
2009-11-15 22:31:44 +02:00
bool modify_sd = false ;
2009-11-05 17:34:12 +02:00
const struct GUID * guid ;
uint32_t access_granted ;
struct object_tree * root = NULL ;
struct object_tree * new_node = NULL ;
NTSTATUS status ;
struct ldb_result * acl_res ;
struct security_descriptor * sd ;
2009-12-17 17:25:11 +02:00
struct dom_sid * sid = NULL ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
2009-11-05 17:34:12 +02:00
TALLOC_CTX * tmp_ctx = talloc_new ( req ) ;
static const char * acl_attrs [ ] = {
" nTSecurityDescriptor " ,
" objectClass " ,
2009-12-17 17:25:11 +02:00
" objectSid " ,
2009-11-05 17:34:12 +02:00
NULL
} ;
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2009-12-14 20:32:28 -05:00
/* Don't print this debug statement if elements[0].name is going to be NULL */
if ( req - > op . mod . message - > num_elements > 0 )
{
DEBUG ( 10 , ( " ldb:acl_modify: %s \n " , req - > op . mod . message - > elements [ 0 ] . name ) ) ;
}
2010-01-08 09:30:31 +11:00
if ( dsdb_module_am_system ( module ) | | as_system ) {
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
2009-11-05 17:34:12 +02:00
if ( ldb_dn_is_special ( req - > op . mod . message - > dn ) ) {
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
2010-03-12 02:21:16 +02:00
ret = dsdb_module_search_dn ( module , req , & acl_res , req - > op . mod . message - > dn ,
acl_attrs , 0 ) ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-09-21 17:27:50 -07:00
2010-03-11 23:10:38 +02:00
ret = dsdb_get_sd_from_ldb_message ( req , acl_res - > msgs [ 0 ] , & sd ) ;
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 10 , ( " acl_modify: cannot get descriptor \n " ) ) ;
return ret ;
}
/* Theoretically we pass the check if the object has no sd */
if ( ! sd ) {
return LDB_SUCCESS ;
}
2009-09-21 17:27:50 -07:00
2009-12-10 15:49:53 +02:00
guid = get_oc_guid_from_message ( module , acl_res - > msgs [ 0 ] ) ;
2009-11-05 17:34:12 +02:00
if ( ! guid ) {
DEBUG ( 10 , ( " acl_modify: cannot get guid \n " ) ) ;
goto fail ;
}
2009-09-21 17:27:50 -07:00
2010-03-11 23:10:38 +02:00
ret = dsdb_get_dom_sid_from_ldb_message ( req , acl_res - > msgs [ 0 ] , & sid ) ;
2009-12-17 17:25:11 +02:00
if ( ret ! = LDB_SUCCESS ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-11-05 17:34:12 +02:00
if ( ! insert_in_object_tree ( tmp_ctx , guid , SEC_ADS_WRITE_PROP ,
2009-12-10 15:49:53 +02:00
& root , & new_node ) ) {
2009-11-05 17:34:12 +02:00
DEBUG ( 10 , ( " acl_modify: cannot add to object tree \n " ) ) ;
goto fail ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
for ( i = 0 ; i < req - > op . mod . message - > num_elements ; i + + ) {
const struct dsdb_attribute * attr ;
/* clearTextPassword is not in schema */
if ( strcmp ( " clearTextPassword " , req - > op . mod . message - > elements [ i ] . name ) = = 0 ) {
attr = dsdb_attribute_by_lDAPDisplayName ( schema , " unicodePwd " ) ;
} else {
attr = dsdb_attribute_by_lDAPDisplayName ( schema ,
req - > op . mod . message - > elements [ i ] . name ) ;
}
2009-11-15 22:31:44 +02:00
if ( strcmp ( " nTSecurityDescriptor " , req - > op . mod . message - > elements [ i ] . name ) = = 0 ) {
modify_sd = true ;
} else {
2009-09-21 17:27:50 -07:00
2009-11-15 22:31:44 +02:00
if ( ! attr ) {
DEBUG ( 10 , ( " acl_modify: cannot find attribute %s \n " ,
req - > op . mod . message - > elements [ i ] . name ) ) ;
goto fail ;
}
if ( ! insert_in_object_tree ( tmp_ctx ,
& attr - > attributeSecurityGUID , SEC_ADS_WRITE_PROP ,
& new_node , & new_node ) ) {
DEBUG ( 10 , ( " acl_modify: cannot add to object tree securityGUID \n " ) ) ;
goto fail ;
}
if ( ! insert_in_object_tree ( tmp_ctx ,
& attr - > schemaIDGUID , SEC_ADS_WRITE_PROP , & new_node , & new_node ) ) {
DEBUG ( 10 , ( " acl_modify: cannot add to object tree attributeGUID \n " ) ) ;
goto fail ;
}
2009-11-05 17:34:12 +02:00
}
2009-11-15 22:31:44 +02:00
}
2009-09-21 17:27:50 -07:00
2009-11-15 22:31:44 +02:00
if ( root - > num_of_children > 0 ) {
status = sec_access_check_ds ( sd , acl_user_token ( module ) ,
SEC_ADS_WRITE_PROP ,
& access_granted ,
2009-12-17 17:25:11 +02:00
root ,
sid ) ;
2009-11-15 22:31:44 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Object %s nas no write property access \n " ,
2009-12-10 15:49:53 +02:00
ldb_dn_get_linearized ( req - > op . mod . message - > dn ) ) ) ;
2010-03-11 23:10:38 +02:00
dsdb_acl_debug ( sd ,
2009-11-15 22:31:44 +02:00
acl_user_token ( module ) ,
req - > op . mod . message - > dn ,
true ,
10 ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
2009-09-21 17:27:50 -07:00
}
}
2009-11-15 22:31:44 +02:00
if ( modify_sd ) {
status = sec_access_check_ds ( sd , acl_user_token ( module ) ,
2009-12-10 15:49:53 +02:00
SEC_STD_WRITE_DAC ,
& access_granted ,
2009-12-17 17:25:11 +02:00
NULL ,
sid ) ;
2009-11-15 22:31:44 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Object %s nas no write dacl access \n " ,
ldb_dn_get_linearized ( req - > op . mod . message - > dn ) ) ) ;
2010-03-11 23:10:38 +02:00
dsdb_acl_debug ( sd ,
2009-11-15 22:31:44 +02:00
acl_user_token ( module ) ,
req - > op . mod . message - > dn ,
true ,
10 ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
2009-11-05 17:34:12 +02:00
}
talloc_free ( tmp_ctx ) ;
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
2009-11-05 17:34:12 +02:00
fail :
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2009-09-21 17:27:50 -07:00
}
/* similar to the modify for the time being.
* We need to concider the special delete tree case , though - TODO */
static int acl_delete ( struct ldb_module * module , struct ldb_request * req )
{
int ret ;
2009-11-05 17:34:12 +02:00
struct ldb_dn * parent = ldb_dn_get_parent ( req , req - > op . del . dn ) ;
2009-09-21 17:27:50 -07:00
struct ldb_context * ldb ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
2009-09-21 17:27:50 -07:00
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2009-11-05 17:34:12 +02:00
DEBUG ( 10 , ( " ldb:acl_delete: %s \n " , ldb_dn_get_linearized ( req - > op . del . dn ) ) ) ;
2010-01-08 09:30:31 +11:00
if ( dsdb_module_am_system ( module ) | | as_system ) {
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
2009-11-05 17:34:12 +02:00
if ( ldb_dn_is_special ( req - > op . del . dn ) ) {
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
ldb = ldb_module_get_ctx ( module ) ;
2009-11-05 17:34:12 +02:00
/* first check if we have delete object right */
2010-03-11 23:10:38 +02:00
ret = dsdb_check_access_on_dn ( ldb , req , req - > op . del . dn , SEC_STD_DELETE , NULL ) ;
2009-11-05 17:34:12 +02:00
if ( ret = = LDB_SUCCESS ) {
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
2009-11-05 17:34:12 +02:00
/* Nope, we don't have delete object. Lets check if we have delete child on the parent */
/* No parent, so check fails */
if ( ( ldb_dn_compare ( req - > op . del . dn , ( ldb_get_schema_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( req - > op . del . dn , ( ldb_get_config_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( req - > op . del . dn , ( ldb_get_root_basedn ( ldb ) ) ) = = 0 ) ) {
DEBUG ( 10 , ( " acl:deleting an NC \n " ) ) ;
return ldb_module_done ( req , NULL , NULL , LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ) ;
2009-09-21 17:27:50 -07:00
}
2010-03-11 23:10:38 +02:00
ret = dsdb_check_access_on_dn ( ldb , req , parent , SEC_ADS_DELETE_CHILD , NULL ) ;
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
2009-09-21 17:27:50 -07:00
return ret ;
2009-11-05 17:34:12 +02:00
}
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
static int acl_rename ( struct ldb_module * module , struct ldb_request * req )
2009-09-21 17:27:50 -07:00
{
2009-11-05 17:34:12 +02:00
int ret ;
struct ldb_dn * oldparent = ldb_dn_get_parent ( req , req - > op . rename . olddn ) ;
struct ldb_dn * newparent = ldb_dn_get_parent ( req , req - > op . rename . newdn ) ;
2009-09-21 17:27:50 -07:00
struct ldb_context * ldb ;
2009-11-05 17:34:12 +02:00
struct security_descriptor * sd = NULL ;
2009-12-17 17:25:11 +02:00
struct dom_sid * sid = NULL ;
2009-11-05 17:34:12 +02:00
struct ldb_result * acl_res ;
const struct GUID * guid ;
struct object_tree * root = NULL ;
struct object_tree * new_node = NULL ;
2009-12-18 18:00:15 +02:00
struct ldb_control * as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
2009-11-05 17:34:12 +02:00
TALLOC_CTX * tmp_ctx = talloc_new ( req ) ;
2009-09-21 17:27:50 -07:00
NTSTATUS status ;
2009-11-05 17:34:12 +02:00
uint32_t access_granted ;
2010-03-07 21:42:53 +02:00
const char * rdn_name ;
2009-11-05 17:34:12 +02:00
static const char * acl_attrs [ ] = {
" nTSecurityDescriptor " ,
" objectClass " ,
2009-12-17 17:25:11 +02:00
" objectSid " ,
2009-11-05 17:34:12 +02:00
NULL
} ;
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2009-11-05 17:34:12 +02:00
DEBUG ( 10 , ( " ldb:acl_rename: %s \n " , ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ) ;
2010-01-08 09:30:31 +11:00
if ( dsdb_module_am_system ( module ) | | as_system ) {
2009-11-05 17:34:12 +02:00
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
if ( ldb_dn_is_special ( req - > op . rename . olddn ) ) {
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
ldb = ldb_module_get_ctx ( module ) ;
2009-09-21 17:27:50 -07:00
2010-03-12 02:21:16 +02:00
ret = dsdb_module_search_dn ( module , req , & acl_res , req - > op . rename . olddn ,
acl_attrs , DSDB_SEARCH_SHOW_DELETED ) ;
2009-11-05 17:34:12 +02:00
/* we sould be able to find the parent */
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 10 , ( " acl: failed to find object %s \n " ,
ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ) ;
return ret ;
2009-09-21 17:27:50 -07:00
}
2009-12-10 15:49:53 +02:00
guid = get_oc_guid_from_message ( module , acl_res - > msgs [ 0 ] ) ;
2009-11-05 17:34:12 +02:00
if ( ! insert_in_object_tree ( tmp_ctx , guid , SEC_ADS_WRITE_PROP ,
& root , & new_node ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
} ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
guid = attribute_schemaid_guid_by_lDAPDisplayName ( dsdb_get_schema ( ldb ) ,
" name " ) ;
if ( ! insert_in_object_tree ( tmp_ctx , guid , SEC_ADS_WRITE_PROP ,
& new_node , & new_node ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
} ;
2009-09-21 17:27:50 -07:00
2010-03-07 21:42:53 +02:00
rdn_name = ldb_dn_get_rdn_name ( req - > op . rename . olddn ) ;
if ( rdn_name = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
guid = attribute_schemaid_guid_by_lDAPDisplayName ( dsdb_get_schema ( ldb ) ,
rdn_name ) ;
if ( ! insert_in_object_tree ( tmp_ctx , guid , SEC_ADS_WRITE_PROP ,
& new_node , & new_node ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
} ;
2010-03-11 23:10:38 +02:00
ret = dsdb_get_sd_from_ldb_message ( req , acl_res - > msgs [ 0 ] , & sd ) ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
/* Theoretically we pass the check if the object has no sd */
if ( ! sd ) {
return LDB_SUCCESS ;
}
2010-03-11 23:10:38 +02:00
ret = dsdb_get_dom_sid_from_ldb_message ( req , acl_res - > msgs [ 0 ] , & sid ) ;
2009-12-17 17:25:11 +02:00
if ( ret ! = LDB_SUCCESS ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-11-05 17:34:12 +02:00
status = sec_access_check_ds ( sd , acl_user_token ( module ) ,
SEC_ADS_WRITE_PROP ,
& access_granted ,
2009-12-17 17:25:11 +02:00
root ,
sid ) ;
2009-11-05 17:34:12 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Object %s nas no wp on name \n " ,
ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ) ;
2010-03-11 23:10:38 +02:00
dsdb_acl_debug ( sd ,
2009-11-05 17:34:12 +02:00
acl_user_token ( module ) ,
req - > op . rename . olddn ,
true ,
10 ) ;
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
if ( ldb_dn_compare ( oldparent , newparent ) = = 0 ) {
/* regular rename, not move, nothing more to do */
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
2009-11-05 17:34:12 +02:00
}
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
/* What exactly to do in this case? It would fail anyway.. */
if ( ( ldb_dn_compare ( req - > op . rename . newdn , ( ldb_get_schema_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( req - > op . rename . newdn , ( ldb_get_config_basedn ( ldb ) ) ) = = 0 ) | |
( ldb_dn_compare ( req - > op . rename . newdn , ( ldb_get_root_basedn ( ldb ) ) ) = = 0 ) ) {
DEBUG ( 10 , ( " acl:moving as an NC \n " ) ) ;
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
2009-12-10 15:49:53 +02:00
}
2009-11-05 17:34:12 +02:00
/* new parent should have create child */
talloc_free ( tmp_ctx ) ;
tmp_ctx = talloc_new ( req ) ;
root = NULL ;
new_node = NULL ;
2009-12-10 15:49:53 +02:00
guid = get_oc_guid_from_message ( module , acl_res - > msgs [ 0 ] ) ;
2009-11-05 17:34:12 +02:00
if ( ! guid ) {
DEBUG ( 10 , ( " acl:renamed object has no object class \n " ) ) ;
return ldb_module_done ( req , NULL , NULL , LDB_ERR_OPERATIONS_ERROR ) ;
}
2010-03-11 23:10:38 +02:00
ret = dsdb_check_access_on_dn ( ldb , req , newparent , SEC_ADS_CREATE_CHILD , guid ) ;
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 10 , ( " acl:access_denied renaming %s " , ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ) ;
return ret ;
}
/* do we have delete object on the object? */
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
status = sec_access_check_ds ( sd , acl_user_token ( module ) ,
SEC_STD_DELETE ,
& access_granted ,
2009-12-17 17:25:11 +02:00
NULL ,
sid ) ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
if ( NT_STATUS_IS_OK ( status ) ) {
2009-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
2009-11-05 17:34:12 +02:00
/* what about delete child on the current parent */
2010-03-11 23:10:38 +02:00
ret = dsdb_check_access_on_dn ( ldb , req , oldparent , SEC_ADS_DELETE_CHILD , NULL ) ;
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 10 , ( " acl:access_denied renaming %s " , ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ) ;
return ldb_module_done ( req , NULL , NULL , ret ) ;
2009-09-21 17:27:50 -07:00
}
2009-11-05 17:34:12 +02:00
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2009-12-10 15:49:53 +02:00
static int acl_search_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
struct ldb_context * ldb ;
struct acl_context * ac ;
struct acl_private * data ;
struct ldb_result * acl_res ;
static const char * acl_attrs [ ] = {
" objectClass " ,
" nTSecurityDescriptor " ,
2009-12-17 17:25:11 +02:00
" objectSid " ,
2009-12-10 15:49:53 +02:00
NULL
} ;
int ret , i ;
ac = talloc_get_type ( req - > context , struct acl_context ) ;
data = talloc_get_type ( ldb_module_get_private ( ac - > module ) , struct acl_private ) ;
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 ) ;
}
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
if ( ac - > allowedAttributes
| | ac - > allowedChildClasses
| | ac - > allowedChildClassesEffective
| | ac - > allowedAttributesEffective
| | ac - > sDRightsEffective ) {
2010-03-12 02:21:16 +02:00
ret = dsdb_module_search_dn ( ac - > module , ac , & acl_res , ares - > message - > dn ,
acl_attrs , 0 ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
if ( ac - > allowedAttributes | | ac - > allowedAttributesEffective ) {
ret = acl_allowedAttributes ( ac - > module , acl_res - > msgs [ 0 ] , ares - > message , ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
if ( ac - > allowedChildClasses ) {
ret = acl_childClasses ( ac - > module , acl_res - > msgs [ 0 ] ,
ares - > message , " allowedChildClasses " ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
if ( ac - > allowedChildClassesEffective ) {
ret = acl_childClassesEffective ( ac - > module ,
acl_res - > msgs [ 0 ] , ares - > message , ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
if ( ac - > sDRightsEffective ) {
ret = acl_sDRightsEffective ( ac - > module ,
acl_res - > msgs [ 0 ] , ares - > message , ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
}
if ( data & & data - > password_attrs ) {
2010-01-08 09:30:31 +11:00
if ( ! ac - > am_system ) {
2009-12-10 15:49:53 +02:00
for ( i = 0 ; data - > password_attrs [ i ] ; i + + ) {
ldb_msg_remove_attr ( ares - > message , data - > password_attrs [ i ] ) ;
}
}
}
return ldb_module_send_entry ( ac - > req , ares - > message , ares - > controls ) ;
case LDB_REPLY_REFERRAL :
return ldb_module_send_referral ( ac - > req , ares - > referral ) ;
case LDB_REPLY_DONE :
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , LDB_SUCCESS ) ;
}
return LDB_SUCCESS ;
}
static int acl_search ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb ;
struct acl_context * ac ;
struct ldb_request * down_req ;
struct acl_private * data ;
int ret , i ;
ldb = ldb_module_get_ctx ( module ) ;
ac = talloc_zero ( req , struct acl_context ) ;
if ( ac = = NULL ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
data = talloc_get_type ( ldb_module_get_private ( module ) , struct acl_private ) ;
ac - > module = module ;
ac - > req = req ;
2010-01-08 09:30:31 +11:00
ac - > am_system = dsdb_module_am_system ( module ) ;
2009-12-10 15:49:53 +02:00
ac - > allowedAttributes = ldb_attr_in_list ( req - > op . search . attrs , " allowedAttributes " ) ;
ac - > allowedAttributesEffective = ldb_attr_in_list ( req - > op . search . attrs , " allowedAttributesEffective " ) ;
ac - > allowedChildClasses = ldb_attr_in_list ( req - > op . search . attrs , " allowedChildClasses " ) ;
ac - > allowedChildClassesEffective = ldb_attr_in_list ( req - > op . search . attrs , " allowedChildClassesEffective " ) ;
ac - > sDRightsEffective = ldb_attr_in_list ( req - > op . search . attrs , " sDRightsEffective " ) ;
/* replace any attributes in the parse tree that are private,
so we don ' t allow a search for ' userPassword = penguin ' ,
just as we would not allow that attribute to be returned */
2010-01-08 09:30:31 +11:00
if ( ac - > am_system ) {
2009-12-10 15:49:53 +02:00
/* FIXME: We should copy the tree and keep the original unmodified. */
/* remove password attributes */
if ( data & & data - > password_attrs ) {
for ( i = 0 ; data - > password_attrs [ i ] ; i + + ) {
ldb_parse_tree_attr_replace ( req - > op . search . tree ,
data - > password_attrs [ i ] ,
" kludgeACLredactedattribute " ) ;
}
}
}
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 , acl_search_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
/* perform the search */
return ldb_next_request ( module , down_req ) ;
}
2009-09-21 17:27:50 -07:00
_PUBLIC_ const struct ldb_module_ops ldb_acl_module_ops = {
. name = " acl " ,
2009-12-10 15:49:53 +02:00
. search = acl_search ,
2009-09-21 17:27:50 -07:00
. add = acl_add ,
. modify = acl_modify ,
. del = acl_delete ,
. rename = acl_rename ,
. init_context = acl_module_init
} ;