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"
2010-12-22 12:27:15 +02:00
# include "system/kerberos.h"
# include "auth/kerberos/kerberos.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 {
2012-11-21 12:12:41 +01:00
bool acl_search ;
2009-12-10 15:49:53 +02:00
const char * * password_attrs ;
2012-11-09 17:05:44 +01:00
void * cached_schema_ptr ;
uint64_t cached_schema_metadata_usn ;
uint64_t cached_schema_loaded_usn ;
const char * * confidential_attrs ;
2016-02-12 15:53:37 +13:00
bool userPassword_support ;
2009-12-10 15:49:53 +02:00
} ;
struct acl_context {
struct ldb_module * module ;
struct ldb_request * req ;
2010-01-08 09:30:31 +11:00
bool am_system ;
2012-11-09 17:05:44 +01:00
bool am_administrator ;
2012-11-09 11:23:47 +01:00
bool modify_search ;
bool constructed_attrs ;
2009-12-10 15:49:53 +02:00
bool allowedAttributes ;
bool allowedAttributesEffective ;
bool allowedChildClasses ;
bool allowedChildClassesEffective ;
bool sDRightsEffective ;
2010-11-09 14:39:30 +01:00
bool userPassword ;
2009-12-10 15:49:53 +02:00
const char * const * attrs ;
2010-03-16 14:43:33 +11:00
struct dsdb_schema * schema ;
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 ;
2010-11-20 10:42:01 +01:00
int ret ;
2012-11-24 09:15:24 +01:00
unsigned int i , n , j ;
2010-07-07 18:01:34 +02:00
TALLOC_CTX * mem_ctx ;
2012-11-24 09:15:24 +01:00
static const char * const attrs [ ] = { " passwordAttribute " , NULL } ;
static const char * const secret_attrs [ ] = {
DSDB_SECRET_ATTRIBUTES
} ;
2009-12-10 15:49:53 +02:00
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 " ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-09-21 17:27:50 -07:00
}
2012-11-09 11:23:47 +01:00
data = talloc_zero ( module , struct acl_private ) ;
2009-12-10 15:49:53 +02:00
if ( data = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-12-10 15:49:53 +02:00
}
2012-11-21 12:12:41 +01:00
data - > acl_search = lpcfg_parm_bool ( ldb_get_opaque ( ldb , " loadparm " ) ,
2012-11-18 18:57:03 +01:00
NULL , " acl " , " search " , true ) ;
2009-11-05 17:34:12 +02:00
ldb_module_set_private ( module , data ) ;
2009-09-21 17:27:50 -07:00
2016-02-12 15:53:37 +13:00
data - > userPassword_support = dsdb_user_password_support ( module , module , NULL ) ;
2010-07-07 18:01:34 +02:00
mem_ctx = talloc_new ( module ) ;
2009-12-10 15:49:53 +02:00
if ( ! mem_ctx ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-12-10 15:49:53 +02:00
}
2010-03-12 02:21:16 +02:00
ret = dsdb_module_search_dn ( module , mem_ctx , & res ,
ldb_dn_new ( mem_ctx , ldb , " @KLUDGEACL " ) ,
2010-07-06 03:26:03 +03:00
attrs ,
2012-11-21 07:14:31 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
NULL ) ;
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 ;
}
2012-11-24 09:15:24 +01:00
data - > password_attrs = talloc_array ( data , const char * ,
password_attributes - > num_values +
ARRAY_SIZE ( secret_attrs ) + 1 ) ;
2009-12-10 15:49:53 +02:00
if ( ! data - > password_attrs ) {
talloc_free ( mem_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-12-10 15:49:53 +02:00
}
2012-11-24 09:15:24 +01:00
n = 0 ;
2009-12-10 15:49:53 +02:00
for ( i = 0 ; i < password_attributes - > num_values ; i + + ) {
2012-11-24 09:15:24 +01:00
data - > password_attrs [ n ] = ( const char * ) password_attributes - > values [ i ] . data ;
2009-12-10 15:49:53 +02:00
talloc_steal ( data - > password_attrs , password_attributes - > values [ i ] . data ) ;
2012-11-24 09:15:24 +01:00
n + + ;
}
for ( i = 0 ; i < ARRAY_SIZE ( secret_attrs ) ; i + + ) {
bool found = false ;
for ( j = 0 ; j < n ; j + + ) {
if ( strcasecmp ( data - > password_attrs [ j ] , secret_attrs [ i ] ) = = 0 ) {
found = true ;
break ;
}
}
if ( found ) {
continue ;
}
data - > password_attrs [ n ] = talloc_strdup ( data - > password_attrs ,
secret_attrs [ i ] ) ;
if ( data - > password_attrs [ n ] = = NULL ) {
talloc_free ( mem_ctx ) ;
return ldb_oom ( ldb ) ;
}
n + + ;
2009-12-10 15:49:53 +02:00
}
2012-11-24 09:15:24 +01:00
data - > password_attrs [ n ] = NULL ;
2009-12-10 15:49:53 +02:00
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 int acl_allowedAttributes ( struct ldb_module * module ,
2010-03-16 14:43:33 +11:00
const struct dsdb_schema * schema ,
2009-12-10 15:49:53 +02:00
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 ) ;
TALLOC_CTX * mem_ctx ;
const char * * attr_list ;
int i , ret ;
2013-01-02 15:01:00 +11:00
const struct dsdb_class * objectclass ;
2009-12-10 15:49:53 +02:00
/* If we don't have a schema yet, we can't do anything... */
if ( schema = = NULL ) {
2010-03-16 14:43:33 +11:00
ldb_asprintf_errstring ( ldb , " cannot add allowedAttributes to %s because no schema is loaded " , ldb_dn_get_linearized ( msg - > dn ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2009-12-10 15:49:53 +02:00
}
/* Must remove any existing attribute */
if ( ac - > allowedAttributes ) {
ldb_msg_remove_attr ( msg , " allowedAttributes " ) ;
}
mem_ctx = talloc_new ( msg ) ;
if ( ! mem_ctx ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-12-10 15:49:53 +02:00
}
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 ;
}
2013-01-02 15:01:00 +11:00
/*
* Get the top - most structural object class for the ACL check
*/
objectclass = dsdb_get_last_structural_class ( ac - > schema ,
oc_el ) ;
if ( objectclass = = NULL ) {
ldb_asprintf_errstring ( ldb , " acl_read: Failed to find a structural class for %s " ,
ldb_dn_get_linearized ( sd_msg - > dn ) ) ;
talloc_free ( mem_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-12-10 15:49:53 +02:00
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-07-06 13:21:54 +10:00
ret = dsdb_get_sd_from_ldb_message ( ldb_module_get_ctx ( module ) , 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-04-16 14:28:09 +03:00
sid = samdb_result_dom_sid ( mem_ctx , sd_msg , " objectSid " ) ;
2009-12-10 15:49:53 +02:00
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 ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-12-10 15:49:53 +02:00
}
/* 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 ,
2013-01-02 15:01:00 +11:00
attr ,
objectclass ) ;
2009-12-10 15:49:53 +02:00
if ( ret = = LDB_SUCCESS ) {
ldb_msg_add_string ( msg , " allowedAttributesEffective " , attr_list [ i ] ) ;
}
}
}
return LDB_SUCCESS ;
}
static int acl_childClasses ( struct ldb_module * module ,
2010-03-16 14:43:33 +11:00
const struct dsdb_schema * schema ,
2009-12-10 15:49:53 +02:00
struct ldb_message * sd_msg ,
struct ldb_message * msg ,
const char * attrName )
{
struct ldb_message_element * oc_el ;
struct ldb_message_element * allowedClasses ;
const struct dsdb_class * sclass ;
2010-06-05 20:08:45 +02:00
unsigned int i , j ;
int ret ;
2009-12-10 15:49:53 +02:00
/* If we don't have a schema yet, we can't do anything... */
if ( schema = = NULL ) {
2010-03-16 14:43:33 +11:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) , " cannot add childClassesEffective to %s because no schema is loaded " , ldb_dn_get_linearized ( msg - > dn ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2009-12-10 15:49:53 +02:00
}
/* 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 ,
2010-03-16 14:43:33 +11:00
const struct dsdb_schema * schema ,
2009-12-10 15:49:53 +02:00
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 ;
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 ;
2010-06-05 20:08:45 +02:00
unsigned int i , j ;
int ret ;
2009-12-10 15:49:53 +02: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 ( ac - > am_system | | as_system ) {
2010-03-16 14:43:33 +11:00
return acl_childClasses ( module , schema , sd_msg , msg , " allowedChildClassesEffective " ) ;
2009-12-10 15:49:53 +02:00
}
/* If we don't have a schema yet, we can't do anything... */
if ( schema = = NULL ) {
2010-03-16 14:43:33 +11:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) , " cannot add allowedChildClassesEffective to %s because no schema is loaded " , ldb_dn_get_linearized ( msg - > dn ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2009-12-10 15:49:53 +02:00
}
/* 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-07-06 13:21:54 +10:00
ret = dsdb_get_sd_from_ldb_message ( ldb_module_get_ctx ( module ) , msg , sd_msg , & sd ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-04-16 14:28:09 +03:00
sid = samdb_result_dom_sid ( msg , sd_msg , " objectSid " ) ;
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 + + ) {
2013-01-16 16:35:33 +01:00
const struct dsdb_class * sc ;
sc = dsdb_class_by_lDAPDisplayName ( schema ,
sclass - > possibleInferiors [ j ] ) ;
if ( ! sc ) {
/* We don't know this class? what is going on? */
continue ;
}
ret = acl_check_access_on_objectclass ( module , ac ,
sd , sid ,
SEC_ADS_CREATE_CHILD ,
sc ) ;
2009-12-10 15:49:53 +02:00
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 )
{
2013-01-08 15:54:47 +01:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-12-10 15:49:53 +02:00
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 ;
2013-01-02 15:01:00 +11:00
} else {
const struct dsdb_class * objectclass ;
2013-01-08 15:55:36 +01:00
const struct dsdb_attribute * attr ;
2013-01-02 15:01:00 +11:00
objectclass = dsdb_get_structural_oc_from_msg ( ac - > schema , sd_msg ) ;
if ( objectclass = = NULL ) {
return ldb_operr ( ldb ) ;
}
2013-01-08 15:55:36 +01:00
attr = dsdb_attribute_by_lDAPDisplayName ( ac - > schema ,
" nTSecurityDescriptor " ) ;
if ( attr = = NULL ) {
return ldb_operr ( ldb ) ;
}
2009-12-10 15:49:53 +02:00
/* Get the security descriptor from the message */
2013-01-08 15:54:47 +01:00
ret = dsdb_get_sd_from_ldb_message ( ldb , msg , sd_msg , & sd ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-04-16 14:28:09 +03:00
sid = samdb_result_dom_sid ( msg , sd_msg , " objectSid " ) ;
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 ,
2013-01-02 15:01:00 +11:00
attr ,
objectclass ) ;
2009-12-10 15:49:53 +02:00
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 ,
2013-01-02 15:01:00 +11:00
attr ,
objectclass ) ;
2009-12-10 15:49:53 +02:00
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 ,
2013-01-02 15:01:00 +11:00
attr ,
objectclass ) ;
2009-12-10 15:49:53 +02:00
if ( ret = = LDB_SUCCESS ) {
flags | = SECINFO_SACL ;
}
}
2010-10-14 17:01:39 +02:00
return samdb_msg_add_uint ( ldb_module_get_ctx ( module ) , msg , msg ,
" sDRightsEffective " , flags ) ;
2009-12-10 15:49:53 +02:00
}
2010-12-22 12:27:15 +02:00
static int acl_validate_spn_value ( TALLOC_CTX * mem_ctx ,
struct ldb_context * ldb ,
const char * spn_value ,
2011-02-11 15:10:04 +01:00
uint32_t userAccountControl ,
2010-12-22 12:27:15 +02:00
const char * samAccountName ,
const char * dnsHostName ,
const char * netbios_name ,
const char * ntds_guid )
{
2016-05-24 15:07:00 +02:00
int ret , princ_size ;
2010-12-22 12:27:15 +02:00
krb5_context krb_ctx ;
krb5_error_code kerr ;
krb5_principal principal ;
char * instanceName ;
char * serviceType ;
char * serviceName ;
const char * forest_name = samdb_forest_name ( ldb , mem_ctx ) ;
const char * base_domain = samdb_default_domain_name ( ldb , mem_ctx ) ;
struct loadparm_context * lp_ctx = talloc_get_type ( ldb_get_opaque ( ldb , " loadparm " ) ,
struct loadparm_context ) ;
bool is_dc = ( userAccountControl & UF_SERVER_TRUST_ACCOUNT ) | |
( userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT ) ;
2011-06-30 14:20:22 +10:00
if ( strcasecmp_m ( spn_value , samAccountName ) = = 0 ) {
/* MacOS X sets this value, and setting an SPN of your
* own samAccountName is both pointless and safe */
return LDB_SUCCESS ;
}
2010-12-22 12:27:15 +02:00
kerr = smb_krb5_init_context_basic ( mem_ctx ,
lp_ctx ,
& krb_ctx ) ;
if ( kerr ! = 0 ) {
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
" Could not initialize kerberos context. " ) ;
}
ret = krb5_parse_name ( krb_ctx , spn_value , & principal ) ;
if ( ret ) {
krb5_free_context ( krb_ctx ) ;
return LDB_ERR_CONSTRAINT_VIOLATION ;
}
2016-05-24 15:07:00 +02:00
princ_size = krb5_princ_size ( krb_ctx , principal ) ;
if ( princ_size < 2 ) {
DBG_WARNING ( " princ_size=%d \n " , princ_size ) ;
2011-06-30 14:21:51 +10:00
goto fail ;
}
2014-04-30 10:26:17 +02:00
instanceName = smb_krb5_principal_get_comp_string ( mem_ctx , krb_ctx ,
principal , 1 ) ;
serviceType = smb_krb5_principal_get_comp_string ( mem_ctx , krb_ctx ,
principal , 0 ) ;
if ( krb5_princ_size ( krb_ctx , principal ) = = 3 ) {
serviceName = smb_krb5_principal_get_comp_string ( mem_ctx , krb_ctx ,
principal , 2 ) ;
2010-12-22 12:27:15 +02:00
} else {
serviceName = NULL ;
}
if ( serviceName ) {
if ( ! is_dc ) {
2016-05-24 15:07:00 +02:00
DBG_WARNING ( " is_dc=false, serviceName=%s, "
" serviceType=%s \n " , serviceName ,
serviceType ) ;
2010-12-22 12:27:15 +02:00
goto fail ;
}
if ( strcasecmp ( serviceType , " ldap " ) = = 0 ) {
if ( strcasecmp ( serviceName , netbios_name ) ! = 0 & &
strcasecmp ( serviceName , forest_name ) ! = 0 ) {
2016-05-24 15:07:00 +02:00
DBG_WARNING ( " serviceName=%s \n " , serviceName ) ;
2010-12-22 12:27:15 +02:00
goto fail ;
}
} else if ( strcasecmp ( serviceType , " gc " ) = = 0 ) {
if ( strcasecmp ( serviceName , forest_name ) ! = 0 ) {
2016-05-24 15:07:00 +02:00
DBG_WARNING ( " serviceName=%s \n " , serviceName ) ;
2010-12-22 12:27:15 +02:00
goto fail ;
}
} else {
if ( strcasecmp ( serviceName , base_domain ) ! = 0 & &
strcasecmp ( serviceName , netbios_name ) ! = 0 ) {
2016-05-24 15:07:00 +02:00
DBG_WARNING ( " serviceType=%s, "
" serviceName=%s \n " ,
serviceType , serviceName ) ;
2010-12-22 12:27:15 +02:00
goto fail ;
}
}
}
/* instanceName can be samAccountName without $ or dnsHostName
* or " ntds_guid._msdcs.forest_domain for DC objects */
2011-06-30 14:21:51 +10:00
if ( strlen ( instanceName ) = = ( strlen ( samAccountName ) - 1 )
2016-05-27 10:40:55 +02:00
& & strncasecmp ( instanceName , samAccountName ,
strlen ( samAccountName ) - 1 ) = = 0 ) {
2010-12-22 12:27:15 +02:00
goto success ;
2016-05-27 10:40:55 +02:00
}
if ( ( dnsHostName ! = NULL ) & &
( strcasecmp ( instanceName , dnsHostName ) = = 0 ) ) {
2010-12-22 12:27:15 +02:00
goto success ;
2016-05-27 10:40:55 +02:00
}
if ( is_dc ) {
2011-02-14 11:41:19 +02:00
const char * guid_str ;
guid_str = talloc_asprintf ( mem_ctx , " %s._msdcs.%s " ,
ntds_guid ,
forest_name ) ;
2010-12-22 12:27:15 +02:00
if ( strcasecmp ( instanceName , guid_str ) = = 0 ) {
goto success ;
}
}
2011-02-14 11:41:19 +02:00
2010-12-22 12:27:15 +02:00
fail :
krb5_free_principal ( krb_ctx , principal ) ;
krb5_free_context ( krb_ctx ) ;
2016-05-24 15:07:00 +02:00
ldb_debug_set ( ldb , LDB_DEBUG_WARNING ,
" acl: spn validation failed for "
" spn[%s] uac[0x%x] account[%s] hostname[%s] "
" nbname[%s] ntds[%s] forest[%s] domain[%s] \n " ,
spn_value , ( unsigned ) userAccountControl ,
samAccountName , dnsHostName ,
netbios_name , ntds_guid ,
forest_name , base_domain ) ;
2010-12-22 12:27:15 +02:00
return LDB_ERR_CONSTRAINT_VIOLATION ;
success :
krb5_free_principal ( krb_ctx , principal ) ;
krb5_free_context ( krb_ctx ) ;
return LDB_SUCCESS ;
}
static int acl_check_spn ( TALLOC_CTX * mem_ctx ,
struct ldb_module * module ,
struct ldb_request * req ,
struct security_descriptor * sd ,
struct dom_sid * sid ,
2013-01-02 15:01:00 +11:00
const struct dsdb_attribute * attr ,
const struct dsdb_class * objectclass )
2010-12-22 12:27:15 +02:00
{
int ret ;
unsigned int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_result * acl_res ;
struct ldb_result * netbios_res ;
struct ldb_message_element * el ;
struct ldb_dn * partitions_dn = samdb_partitions_dn ( ldb , tmp_ctx ) ;
2011-02-11 15:10:04 +01:00
uint32_t userAccountControl ;
2010-12-22 12:27:15 +02:00
const char * samAccountName ;
const char * dnsHostName ;
const char * netbios_name ;
2011-02-14 11:35:48 +02:00
struct GUID ntds ;
char * ntds_guid = NULL ;
2010-12-22 12:27:15 +02:00
static const char * acl_attrs [ ] = {
" samAccountName " ,
" dnsHostName " ,
" userAccountControl " ,
NULL
} ;
static const char * netbios_attrs [ ] = {
" nETBIOSName " ,
NULL
} ;
2011-02-14 11:35:48 +02:00
2010-12-22 12:27:15 +02:00
/* if we have wp, we can do whatever we like */
if ( acl_check_access_on_attribute ( module ,
tmp_ctx ,
sd ,
sid ,
SEC_ADS_WRITE_PROP ,
2013-01-02 15:01:00 +11:00
attr , objectclass ) = = LDB_SUCCESS ) {
2010-12-22 12:27:15 +02:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
ret = acl_check_extended_right ( tmp_ctx , sd , acl_user_token ( module ) ,
GUID_DRS_VALIDATE_SPN ,
SEC_ADS_SELF_WRITE ,
sid ) ;
if ( ret = = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ) {
dsdb_acl_debug ( sd , acl_user_token ( module ) ,
req - > op . mod . message - > dn ,
true ,
10 ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = dsdb_module_search_dn ( module , tmp_ctx ,
& acl_res , req - > op . mod . message - > dn ,
acl_attrs ,
DSDB_FLAG_NEXT_MODULE |
2012-11-21 07:14:31 +01:00
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED ,
req ) ;
2010-12-22 12:27:15 +02:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2011-02-11 15:10:04 +01:00
userAccountControl = ldb_msg_find_attr_as_uint ( acl_res - > msgs [ 0 ] , " userAccountControl " , 0 ) ;
2010-12-22 12:27:15 +02:00
dnsHostName = ldb_msg_find_attr_as_string ( acl_res - > msgs [ 0 ] , " dnsHostName " , NULL ) ;
samAccountName = ldb_msg_find_attr_as_string ( acl_res - > msgs [ 0 ] , " samAccountName " , NULL ) ;
ret = dsdb_module_search ( module , tmp_ctx ,
& netbios_res , partitions_dn ,
LDB_SCOPE_ONELEVEL ,
netbios_attrs ,
2012-11-21 07:14:31 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
2011-01-17 13:12:15 +11:00
req ,
2010-12-22 12:27:15 +02:00
" (ncName=%s) " ,
ldb_dn_get_linearized ( ldb_get_default_basedn ( ldb ) ) ) ;
netbios_name = ldb_msg_find_attr_as_string ( netbios_res - > msgs [ 0 ] , " nETBIOSName " , NULL ) ;
el = ldb_msg_find_element ( req - > op . mod . message , " servicePrincipalName " ) ;
if ( ! el ) {
2010-12-23 20:54:08 +01:00
talloc_free ( tmp_ctx ) ;
2010-12-22 12:27:15 +02:00
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
" Error finding element for servicePrincipalName. " ) ;
}
2011-02-14 11:35:48 +02:00
/* NTDSDSA objectGuid of object we are checking SPN for */
if ( userAccountControl & ( UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT ) ) {
ret = dsdb_module_find_ntdsguid_for_computer ( module , tmp_ctx ,
req - > op . mod . message - > dn , & ntds , req ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " Failed to find NTDSDSA objectGuid for %s: %s " ,
ldb_dn_get_linearized ( req - > op . mod . message - > dn ) ,
ldb_strerror ( ret ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ntds_guid = GUID_string ( tmp_ctx , & ntds ) ;
}
2010-12-22 12:27:15 +02:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
ret = acl_validate_spn_value ( tmp_ctx ,
ldb ,
( char * ) el - > values [ i ] . data ,
userAccountControl ,
samAccountName ,
dnsHostName ,
netbios_name ,
ntds_guid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
talloc_free ( tmp_ctx ) ;
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 ;
2013-01-17 08:51:23 +01:00
struct ldb_dn * parent ;
2009-11-05 17:34:12 +02:00
struct ldb_context * ldb ;
2010-03-16 14:43:33 +11:00
const struct dsdb_schema * schema ;
2013-01-02 09:26:15 +11:00
const struct dsdb_class * objectclass ;
2013-01-17 08:51:23 +01:00
struct ldb_control * as_system ;
2013-09-06 15:48:29 +12:00
struct ldb_message_element * el ;
unsigned int instanceType = 0 ;
2009-09-21 17:27:50 -07:00
2013-01-17 08:51:23 +01:00
if ( ldb_dn_is_special ( req - > op . add . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
}
as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
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
}
2010-11-16 14:22:27 +01:00
2009-11-05 17:34:12 +02:00
ldb = ldb_module_get_ctx ( module ) ;
2010-11-16 14:22:27 +01:00
2013-01-17 08:51:23 +01:00
parent = ldb_dn_get_parent ( req , req - > op . add . message - > dn ) ;
if ( parent = = NULL ) {
return ldb_oom ( ldb ) ;
}
2010-03-16 14:43:33 +11:00
schema = dsdb_get_schema ( ldb , req ) ;
if ( ! schema ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-03-16 14:43:33 +11:00
}
2013-01-02 09:26:15 +11:00
objectclass = dsdb_get_structural_oc_from_msg ( schema , req - > op . add . message ) ;
if ( ! objectclass ) {
2011-08-25 19:20:28 +10:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
2013-09-06 15:48:29 +12:00
" acl: unable to find or validate structural objectClass on %s \n " ,
2011-08-25 19:20:28 +10:00
ldb_dn_get_linearized ( req - > op . add . message - > dn ) ) ;
2009-11-05 17:34:12 +02:00
return ldb_module_done ( req , NULL , NULL , LDB_ERR_OPERATIONS_ERROR ) ;
2009-09-21 17:27:50 -07:00
}
2013-09-06 15:48:29 +12:00
el = ldb_msg_find_element ( req - > op . add . message , " instanceType " ) ;
if ( ( el ! = NULL ) & & ( el - > num_values ! = 1 ) ) {
ldb_set_errstring ( ldb , " acl: the 'instanceType' attribute is single-valued! " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
instanceType = ldb_msg_find_attr_as_uint ( req - > op . add . message ,
" instanceType " , 0 ) ;
if ( instanceType & INSTANCE_TYPE_IS_NC_HEAD ) {
static const char * no_attrs [ ] = { NULL } ;
struct ldb_result * partition_res ;
struct ldb_dn * partitions_dn ;
partitions_dn = samdb_partitions_dn ( ldb , req ) ;
if ( ! partitions_dn ) {
ldb_set_errstring ( ldb , " acl: CN=partitions dn could not be generated! " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
ret = dsdb_module_search ( module , req , & partition_res ,
partitions_dn , LDB_SCOPE_ONELEVEL ,
no_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_ONE_ONLY |
DSDB_SEARCH_SHOW_RECYCLED ,
req ,
" (&(nCName=%s)(objectClass=crossRef)) " ,
ldb_dn_get_linearized ( req - > op . add . message - > dn ) ) ;
if ( ret = = LDB_SUCCESS ) {
/* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
ret = dsdb_module_check_access_on_dn ( module , req , partition_res - > msgs [ 0 ] - > dn ,
SEC_ADS_WRITE_PROP ,
& objectclass - > schemaIDGUID , req ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" acl: ACL check failed on crossRef object %s: %s \n " ,
ldb_dn_get_linearized ( partition_res - > msgs [ 0 ] - > dn ) ,
ldb_errstring ( ldb ) ) ;
return ret ;
}
/*
* TODO : Remaining checks , like if we are
* the naming master etc need to be handled
* in the instanceType module
*/
return ldb_next_request ( module , req ) ;
}
/* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
ret = dsdb_module_check_access_on_dn ( module , req , partitions_dn ,
SEC_ADS_CREATE_CHILD ,
& objectclass - > schemaIDGUID , req ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT & &
ldb_request_get_control ( req , LDB_CONTROL_RELAX_OID ) )
{
/* Allow provision bootstrap */
ret = LDB_SUCCESS ;
}
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" acl: ACL check failed on CN=Partitions crossRef container %s: %s \n " ,
ldb_dn_get_linearized ( partitions_dn ) , ldb_errstring ( ldb ) ) ;
return ret ;
}
/*
* TODO : Remaining checks , like if we are the naming
* master and adding the crossRef object need to be
* handled in the instanceType module
*/
return ldb_next_request ( module , req ) ;
}
2013-01-02 09:26:15 +11:00
ret = dsdb_module_check_access_on_dn ( module , req , parent ,
SEC_ADS_CREATE_CHILD ,
& objectclass - > schemaIDGUID , req ) ;
2009-09-21 17:27:50 -07:00
if ( ret ! = LDB_SUCCESS ) {
2013-09-06 15:48:29 +12:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
2016-01-13 12:53:26 -08:00
" acl: unable to get access to %s \n " ,
2013-09-06 15:48:29 +12:00
ldb_dn_get_linearized ( req - > op . add . message - > dn ) ) ;
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
}
2010-06-28 10:34:14 +03:00
/* ckecks if modifications are allowed on "Member" attribute */
2010-07-05 00:17:38 +03:00
static int acl_check_self_membership ( TALLOC_CTX * mem_ctx ,
struct ldb_module * module ,
2010-06-28 10:34:14 +03:00
struct ldb_request * req ,
struct security_descriptor * sd ,
struct dom_sid * sid ,
2013-01-02 15:01:00 +11:00
const struct dsdb_attribute * attr ,
const struct dsdb_class * objectclass )
2010-06-28 10:34:14 +03:00
{
2010-06-28 11:25:43 +02:00
int ret ;
unsigned int i ;
2010-06-28 10:34:14 +03:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_dn * user_dn ;
struct ldb_message_element * member_el ;
/* if we have wp, we can do whatever we like */
if ( acl_check_access_on_attribute ( module ,
2010-07-05 00:17:38 +03:00
mem_ctx ,
2010-06-28 10:34:14 +03:00
sd ,
sid ,
SEC_ADS_WRITE_PROP ,
2013-01-02 15:01:00 +11:00
attr , objectclass ) = = LDB_SUCCESS ) {
2010-06-28 10:34:14 +03:00
return LDB_SUCCESS ;
}
/* if we are adding/deleting ourselves, check for self membership */
2010-08-14 13:30:51 +10:00
ret = dsdb_find_dn_by_sid ( ldb , mem_ctx ,
2010-08-20 12:15:15 +10:00
& acl_user_token ( module ) - > sids [ PRIMARY_USER_SID_INDEX ] ,
2010-08-14 13:30:51 +10:00
& user_dn ) ;
2010-06-28 10:34:14 +03:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-06-29 11:46:22 +03:00
member_el = ldb_msg_find_element ( req - > op . mod . message , " member " ) ;
2010-06-28 10:34:14 +03:00
if ( ! member_el ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-06-28 10:34:14 +03:00
}
/* user can only remove oneself */
if ( member_el - > num_values = = 0 ) {
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
for ( i = 0 ; i < member_el - > num_values ; i + + ) {
if ( strcasecmp ( ( const char * ) member_el - > values [ i ] . data ,
2010-07-05 00:17:38 +03:00
ldb_dn_get_extended_linearized ( mem_ctx , user_dn , 1 ) ) ! = 0 ) {
2010-06-28 10:34:14 +03:00
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
}
2010-07-05 00:17:38 +03:00
ret = acl_check_extended_right ( mem_ctx , sd , acl_user_token ( module ) ,
GUID_DRS_SELF_MEMBERSHIP ,
SEC_ADS_SELF_WRITE ,
sid ) ;
if ( ret = = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ) {
dsdb_acl_debug ( sd , acl_user_token ( module ) ,
req - > op . mod . message - > dn ,
true ,
10 ) ;
}
return ret ;
}
static int acl_check_password_rights ( TALLOC_CTX * mem_ctx ,
struct ldb_module * module ,
struct ldb_request * req ,
struct security_descriptor * sd ,
struct dom_sid * sid ,
2013-01-02 15:01:00 +11:00
const struct dsdb_class * objectclass ,
2010-11-09 14:39:30 +01:00
bool userPassword )
2010-07-05 00:17:38 +03:00
{
int ret = LDB_SUCCESS ;
unsigned int del_attr_cnt = 0 , add_attr_cnt = 0 , rep_attr_cnt = 0 ;
struct ldb_message_element * el ;
struct ldb_message * msg ;
2010-07-08 14:51:49 +02:00
const char * passwordAttrs [ ] = { " userPassword " , " clearTextPassword " ,
" unicodePwd " , " dBCSPwd " , NULL } , * * l ;
2010-07-05 00:17:38 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
msg = ldb_msg_copy_shallow ( tmp_ctx , req - > op . mod . message ) ;
if ( msg = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_module_oom ( module ) ;
2010-07-05 00:17:38 +03:00
}
for ( l = passwordAttrs ; * l ! = NULL ; l + + ) {
2010-11-09 14:39:30 +01:00
if ( ( ! userPassword ) & & ( ldb_attr_cmp ( * l , " userPassword " ) = = 0 ) ) {
continue ;
}
2010-07-05 00:17:38 +03:00
while ( ( el = ldb_msg_find_element ( msg , * l ) ) ! = NULL ) {
2010-08-17 11:21:11 +10:00
if ( LDB_FLAG_MOD_TYPE ( el - > flags ) = = LDB_FLAG_MOD_DELETE ) {
2010-07-05 00:17:38 +03:00
+ + del_attr_cnt ;
}
2010-08-17 11:21:11 +10:00
if ( LDB_FLAG_MOD_TYPE ( el - > flags ) = = LDB_FLAG_MOD_ADD ) {
2010-07-05 00:17:38 +03:00
+ + add_attr_cnt ;
}
2010-08-17 11:21:11 +10:00
if ( LDB_FLAG_MOD_TYPE ( el - > flags ) = = LDB_FLAG_MOD_REPLACE ) {
2010-07-05 00:17:38 +03:00
+ + rep_attr_cnt ;
}
ldb_msg_remove_element ( msg , el ) ;
}
}
2010-11-07 22:37:39 +01:00
/* single deletes will be handled by the "password_hash" LDB module
* later in the stack , so we let it though here */
if ( ( del_attr_cnt > 0 ) & & ( add_attr_cnt = = 0 ) & & ( rep_attr_cnt = = 0 ) ) {
2010-07-05 00:17:38 +03:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-07-08 16:00:19 +02:00
if ( ldb_request_get_control ( req ,
DSDB_CONTROL_PASSWORD_CHANGE_OID ) ! = NULL ) {
/* The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
* have a user password change and not a set as the message
* looks like . In it ' s value blob it contains the NT and / or LM
* hash of the old password specified by the user .
* This control is used by the SAMR and " kpasswd " password
* change mechanisms . */
ret = acl_check_extended_right ( tmp_ctx , sd , acl_user_token ( module ) ,
GUID_DRS_USER_CHANGE_PASSWORD ,
SEC_ADS_CONTROL_ACCESS ,
sid ) ;
}
else if ( rep_attr_cnt > 0 | | ( add_attr_cnt ! = del_attr_cnt ) ) {
2010-07-05 00:17:38 +03:00
ret = acl_check_extended_right ( tmp_ctx , sd , acl_user_token ( module ) ,
GUID_DRS_FORCE_CHANGE_PASSWORD ,
SEC_ADS_CONTROL_ACCESS ,
sid ) ;
}
else if ( add_attr_cnt = = 1 & & del_attr_cnt = = 1 ) {
ret = acl_check_extended_right ( tmp_ctx , sd , acl_user_token ( module ) ,
GUID_DRS_USER_CHANGE_PASSWORD ,
SEC_ADS_CONTROL_ACCESS ,
sid ) ;
/* Very strange, but we get constraint violation in this case */
if ( ret = = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ) {
ret = LDB_ERR_CONSTRAINT_VIOLATION ;
}
}
if ( ret ! = LDB_SUCCESS ) {
dsdb_acl_debug ( sd , acl_user_token ( module ) ,
req - > op . mod . message - > dn ,
true ,
10 ) ;
}
2010-06-28 10:34:14 +03:00
talloc_free ( tmp_ctx ) ;
2010-07-05 00:17:38 +03:00
return ret ;
2010-06-28 10:34:14 +03:00
}
2012-04-04 21:58:04 +02: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 ) ;
2010-03-16 14:43:33 +11:00
const struct dsdb_schema * schema ;
2010-03-07 19:16:24 +01:00
unsigned int i ;
2013-01-02 14:53:02 +11:00
const struct dsdb_class * objectclass ;
2009-11-05 17:34:12 +02:00
struct ldb_result * acl_res ;
struct security_descriptor * sd ;
2009-12-17 17:25:11 +02:00
struct dom_sid * sid = NULL ;
2013-01-17 08:51:23 +01:00
struct ldb_control * as_system ;
2014-11-04 20:21:57 +02:00
struct ldb_control * is_undelete ;
2013-01-17 08:37:12 +01:00
bool userPassword ;
2013-01-17 08:51:23 +01:00
TALLOC_CTX * tmp_ctx ;
2013-01-18 09:17:25 +01:00
const struct ldb_message * msg = req - > op . mod . message ;
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
} ;
2013-01-18 09:17:25 +01:00
if ( ldb_dn_is_special ( msg - > dn ) ) {
2013-01-17 08:51:23 +01:00
return ldb_next_request ( module , req ) ;
}
as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
2010-02-04 09:22:39 +01:00
if ( as_system ! = NULL ) {
as_system - > critical = 0 ;
}
2014-11-04 20:21:57 +02:00
is_undelete = ldb_request_get_control ( req , DSDB_CONTROL_RESTORE_TOMBSTONE_OID ) ;
2009-12-14 20:32:28 -05:00
/* Don't print this debug statement if elements[0].name is going to be NULL */
2013-01-18 09:17:25 +01:00
if ( msg - > num_elements > 0 ) {
DEBUG ( 10 , ( " ldb:acl_modify: %s \n " , msg - > elements [ 0 ] . name ) ) ;
2009-12-14 20:32:28 -05:00
}
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 ) ;
}
2013-01-17 08:51:23 +01:00
tmp_ctx = talloc_new ( req ) ;
if ( tmp_ctx = = NULL ) {
return ldb_oom ( ldb ) ;
2009-09-21 17:27:50 -07:00
}
2013-01-17 08:51:23 +01:00
2013-01-18 09:17:25 +01:00
ret = dsdb_module_search_dn ( module , tmp_ctx , & acl_res , msg - > dn ,
2010-07-06 03:26:03 +03:00
acl_attrs ,
2012-11-21 07:14:31 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED ,
2011-07-13 10:28:07 +10:00
req ) ;
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
2010-07-05 00:17:38 +03:00
goto fail ;
2009-11-05 17:34:12 +02:00
}
2009-09-21 17:27:50 -07:00
2013-01-17 08:37:12 +01:00
userPassword = dsdb_user_password_support ( module , req , req ) ;
2010-07-05 00:17:38 +03:00
schema = dsdb_get_schema ( ldb , tmp_ctx ) ;
2010-03-16 14:43:33 +11:00
if ( ! schema ) {
2013-01-03 21:31:22 +11:00
talloc_free ( tmp_ctx ) ;
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
" acl_modify: Error obtaining schema. " ) ;
2010-03-16 14:43:33 +11:00
}
2010-07-06 13:21:54 +10:00
ret = dsdb_get_sd_from_ldb_message ( ldb , tmp_ctx , acl_res - > msgs [ 0 ] , & sd ) ;
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
2011-01-28 11:58:14 +02:00
talloc_free ( tmp_ctx ) ;
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
" acl_modify: Error retrieving security descriptor. " ) ;
2009-11-05 17:34:12 +02:00
}
/* Theoretically we pass the check if the object has no sd */
if ( ! sd ) {
2010-07-05 00:17:38 +03:00
goto success ;
2009-11-05 17:34:12 +02:00
}
2009-09-21 17:27:50 -07:00
2013-01-02 14:53:02 +11:00
objectclass = dsdb_get_structural_oc_from_msg ( schema , acl_res - > msgs [ 0 ] ) ;
if ( ! objectclass ) {
2011-01-28 11:58:14 +02:00
talloc_free ( tmp_ctx ) ;
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
2013-01-02 14:53:02 +11:00
" acl_modify: Error retrieving object class for GUID. " ) ;
2009-11-05 17:34:12 +02:00
}
2010-04-16 14:28:09 +03:00
sid = samdb_result_dom_sid ( req , acl_res - > msgs [ 0 ] , " objectSid " ) ;
2013-01-18 09:17:25 +01:00
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
2013-01-18 09:17:25 +01:00
const struct ldb_message_element * el = & msg - > elements [ i ] ;
2009-11-05 17:34:12 +02:00
const struct dsdb_attribute * attr ;
2013-01-18 09:17:25 +01:00
2013-01-16 16:39:35 +01:00
/*
* This basic attribute existence check with the right errorcode
* is needed since this module is the first one which requests
* schema attribute information .
* The complete attribute checking is done in the
* " objectclass_attrs " module behind this one .
*
* NOTE : " clearTextPassword " is not defined in the schema .
*/
attr = dsdb_attribute_by_lDAPDisplayName ( schema , el - > name ) ;
if ( ! attr & & ldb_attr_cmp ( " clearTextPassword " , el - > name ) ! = 0 ) {
ldb_asprintf_errstring ( ldb , " acl_modify: attribute '%s' "
" on entry '%s' was not found in the schema! " ,
req - > op . mod . message - > elements [ i ] . name ,
ldb_dn_get_linearized ( req - > op . mod . message - > dn ) ) ;
ret = LDB_ERR_NO_SUCH_ATTRIBUTE ;
goto fail ;
}
2010-06-05 20:19:31 +02:00
2013-01-18 09:17:25 +01:00
if ( ldb_attr_cmp ( " nTSecurityDescriptor " , el - > name ) = = 0 ) {
2012-11-21 14:10:43 +01:00
uint32_t sd_flags = dsdb_request_sd_flags ( req , NULL ) ;
uint32_t access_mask = 0 ;
if ( sd_flags & ( SECINFO_OWNER | SECINFO_GROUP ) ) {
access_mask | = SEC_STD_WRITE_OWNER ;
}
if ( sd_flags & SECINFO_DACL ) {
access_mask | = SEC_STD_WRITE_DAC ;
}
if ( sd_flags & SECINFO_SACL ) {
access_mask | = SEC_FLAG_SYSTEM_SECURITY ;
}
2013-01-16 16:41:51 +01:00
ret = acl_check_access_on_attribute ( module ,
tmp_ctx ,
sd ,
sid ,
access_mask ,
attr ,
objectclass ) ;
if ( ret ! = LDB_SUCCESS ) {
2011-08-25 19:20:28 +10:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" Object %s has no write dacl access \n " ,
2013-01-18 09:17:25 +01:00
ldb_dn_get_linearized ( msg - > dn ) ) ;
2010-07-05 00:17:38 +03:00
dsdb_acl_debug ( sd ,
acl_user_token ( module ) ,
2013-01-18 09:17:25 +01:00
msg - > dn ,
2010-07-05 00:17:38 +03:00
true ,
10 ) ;
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
goto fail ;
}
2013-01-18 09:17:25 +01:00
} else if ( ldb_attr_cmp ( " member " , el - > name ) = = 0 ) {
2010-07-05 00:17:38 +03:00
ret = acl_check_self_membership ( tmp_ctx ,
module ,
2010-06-28 10:34:14 +03:00
req ,
sd ,
sid ,
2013-01-02 15:01:00 +11:00
attr ,
objectclass ) ;
2010-06-28 10:34:14 +03:00
if ( ret ! = LDB_SUCCESS ) {
2010-07-05 00:17:38 +03:00
goto fail ;
}
2013-01-18 09:17:25 +01:00
} else if ( ldb_attr_cmp ( " dBCSPwd " , el - > name ) = = 0 ) {
2010-07-05 00:17:38 +03:00
/* this one is not affected by any rights, we should let it through
so that passwords_hash returns the correct error */
continue ;
2013-01-18 09:17:25 +01:00
} else if ( ldb_attr_cmp ( " unicodePwd " , el - > name ) = = 0 | |
( userPassword & & ldb_attr_cmp ( " userPassword " , el - > name ) = = 0 ) | |
ldb_attr_cmp ( " clearTextPassword " , el - > name ) = = 0 ) {
2010-07-05 00:17:38 +03:00
ret = acl_check_password_rights ( tmp_ctx ,
module ,
req ,
sd ,
sid ,
2013-01-02 15:01:00 +11:00
objectclass ,
2010-11-09 14:39:30 +01:00
userPassword ) ;
2010-07-05 00:17:38 +03:00
if ( ret ! = LDB_SUCCESS ) {
goto fail ;
2010-06-28 10:34:14 +03:00
}
2013-01-18 09:17:25 +01:00
} else if ( ldb_attr_cmp ( " servicePrincipalName " , el - > name ) = = 0 ) {
2010-12-22 12:27:15 +02:00
ret = acl_check_spn ( tmp_ctx ,
module ,
req ,
sd ,
sid ,
2013-01-02 15:01:00 +11:00
attr ,
objectclass ) ;
2010-12-22 12:27:15 +02:00
if ( ret ! = LDB_SUCCESS ) {
goto fail ;
}
2014-11-04 20:21:57 +02:00
} else if ( is_undelete ! = NULL & & ( ldb_attr_cmp ( " isDeleted " , el - > name ) = = 0 ) ) {
/*
* in case of undelete op permissions on
* isDeleted are irrelevant and
* distinguishedName is removed by the
* tombstone_reanimate module
*/
continue ;
2009-11-15 22:31:44 +02:00
} else {
2013-01-16 16:41:51 +01:00
ret = acl_check_access_on_attribute ( module ,
tmp_ctx ,
sd ,
sid ,
SEC_ADS_WRITE_PROP ,
attr ,
objectclass ) ;
if ( ret ! = LDB_SUCCESS ) {
2013-01-09 16:59:18 +11:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" Object %s has no write property access \n " ,
2013-01-18 09:17:25 +01:00
ldb_dn_get_linearized ( msg - > dn ) ) ;
2013-01-09 16:59:18 +11:00
dsdb_acl_debug ( sd ,
acl_user_token ( module ) ,
2013-01-18 09:17:25 +01:00
msg - > dn ,
2013-01-09 16:59:18 +11:00
true ,
10 ) ;
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
goto fail ;
}
2009-11-15 22:31:44 +02:00
}
2009-11-05 17:34:12 +02:00
}
2010-07-05 00:17:38 +03:00
success :
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 ) ;
2010-07-05 00:17:38 +03:00
return ret ;
2009-09-21 17:27:50 -07:00
}
/* similar to the modify for the time being.
2010-11-16 14:22:27 +01:00
* We need to consider the special delete tree case , though - TODO */
2009-09-21 17:27:50 -07:00
static int acl_delete ( struct ldb_module * module , struct ldb_request * req )
{
int ret ;
2013-01-17 08:51:23 +01:00
struct ldb_dn * parent ;
2009-09-21 17:27:50 -07:00
struct ldb_context * ldb ;
2010-11-16 14:22:27 +01:00
struct ldb_dn * nc_root ;
2013-01-17 08:51:23 +01:00
struct ldb_control * as_system ;
2013-01-17 16:21:10 +01:00
const struct dsdb_schema * schema ;
const struct dsdb_class * objectclass ;
struct security_descriptor * sd = NULL ;
struct dom_sid * sid = NULL ;
struct ldb_result * acl_res ;
static const char * acl_attrs [ ] = {
" nTSecurityDescriptor " ,
" objectClass " ,
" objectSid " ,
NULL
} ;
2013-01-17 08:51:23 +01:00
if ( ldb_dn_is_special ( req - > op . del . dn ) ) {
return ldb_next_request ( module , req ) ;
}
2009-09-21 17:27:50 -07:00
2013-01-17 08:51:23 +01:00
as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
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-09-21 17:27:50 -07:00
return ldb_next_request ( module , req ) ;
}
2013-01-17 08:51:23 +01:00
DEBUG ( 10 , ( " ldb:acl_delete: %s \n " , ldb_dn_get_linearized ( req - > op . del . dn ) ) ) ;
2010-11-16 14:22:27 +01:00
2009-09-21 17:27:50 -07:00
ldb = ldb_module_get_ctx ( module ) ;
2010-11-16 14:22:27 +01:00
2013-01-17 08:51:23 +01:00
parent = ldb_dn_get_parent ( req , req - > op . del . dn ) ;
if ( parent = = NULL ) {
return ldb_oom ( ldb ) ;
}
2010-11-16 14:22:27 +01:00
/* Make sure we aren't deleting a NC */
ret = dsdb_find_nc_root ( ldb , req , req - > op . del . dn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
2009-09-21 17:27:50 -07:00
}
2010-11-16 14:22:27 +01:00
if ( ldb_dn_compare ( nc_root , req - > op . del . dn ) = = 0 ) {
talloc_free ( nc_root ) ;
DEBUG ( 10 , ( " acl:deleting a NC \n " ) ) ;
/* Windows returns "ERR_UNWILLING_TO_PERFORM */
return ldb_module_done ( req , NULL , NULL ,
LDB_ERR_UNWILLING_TO_PERFORM ) ;
}
talloc_free ( nc_root ) ;
2009-09-21 17:27:50 -07:00
2013-01-17 16:21:10 +01:00
ret = dsdb_module_search_dn ( module , req , & acl_res ,
req - > op . del . dn , acl_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED , req ) ;
/* 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 ;
}
ret = dsdb_get_sd_from_ldb_message ( ldb , req , acl_res - > msgs [ 0 ] , & sd ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_operr ( ldb ) ;
}
if ( ! sd ) {
return ldb_operr ( ldb ) ;
}
schema = dsdb_get_schema ( ldb , req ) ;
if ( ! schema ) {
return ldb_operr ( ldb ) ;
}
sid = samdb_result_dom_sid ( req , acl_res - > msgs [ 0 ] , " objectSid " ) ;
objectclass = dsdb_get_structural_oc_from_msg ( schema , acl_res - > msgs [ 0 ] ) ;
if ( ! objectclass ) {
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
" acl_modify: Error retrieving object class for GUID. " ) ;
}
2012-11-24 10:06:13 +01:00
if ( ldb_request_get_control ( req , LDB_CONTROL_TREE_DELETE_OID ) ) {
2013-01-17 16:21:10 +01:00
ret = acl_check_access_on_objectclass ( module , req , sd , sid ,
SEC_ADS_DELETE_TREE ,
objectclass ) ;
2012-11-24 10:06:13 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return ldb_next_request ( module , req ) ;
}
2010-11-16 14:22:27 +01:00
/* First check if we have delete object right */
2013-01-17 16:21:10 +01:00
ret = acl_check_access_on_objectclass ( module , req , sd , sid ,
SEC_STD_DELETE ,
objectclass ) ;
2010-11-16 14:22:27 +01:00
if ( ret = = LDB_SUCCESS ) {
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2010-11-16 14:22:27 +01:00
/* Nope, we don't have delete object. Lets check if we have delete
* child on the parent */
ret = dsdb_module_check_access_on_dn ( module , req , parent ,
2013-01-17 16:22:09 +01:00
SEC_ADS_DELETE_CHILD ,
& objectclass - > schemaIDGUID ,
req ) ;
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
}
2010-11-16 14:22:27 +01:00
2009-11-05 17:34:12 +02:00
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2014-11-04 20:21:57 +02:00
static int acl_check_reanimate_tombstone ( TALLOC_CTX * mem_ctx ,
struct ldb_module * module ,
struct ldb_request * req ,
struct ldb_dn * nc_root )
{
int ret ;
struct ldb_result * acl_res ;
struct security_descriptor * sd = NULL ;
struct dom_sid * sid = NULL ;
static const char * acl_attrs [ ] = {
" nTSecurityDescriptor " ,
" objectClass " ,
" objectSid " ,
NULL
} ;
ret = dsdb_module_search_dn ( module , mem_ctx , & acl_res ,
nc_root , acl_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED , req ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 10 , ( " acl: failed to find object %s \n " ,
ldb_dn_get_linearized ( nc_root ) ) ) ;
return ret ;
}
ret = dsdb_get_sd_from_ldb_message ( mem_ctx , req , acl_res - > msgs [ 0 ] , & sd ) ;
sid = samdb_result_dom_sid ( mem_ctx , acl_res - > msgs [ 0 ] , " objectSid " ) ;
if ( ret ! = LDB_SUCCESS | | ! sd ) {
return ldb_operr ( ldb_module_get_ctx ( module ) ) ;
}
return acl_check_extended_right ( mem_ctx , sd , acl_user_token ( module ) ,
GUID_DRS_REANIMATE_TOMBSTONE ,
SEC_ADS_CONTROL_ACCESS , sid ) ;
}
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 ;
2013-01-17 08:51:23 +01:00
struct ldb_dn * oldparent ;
struct ldb_dn * newparent ;
2010-03-16 14:43:33 +11:00
const struct dsdb_schema * schema ;
2013-01-02 14:54:20 +11:00
const struct dsdb_class * objectclass ;
2013-01-16 16:43:14 +01:00
const struct dsdb_attribute * attr = NULL ;
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 ;
2010-11-16 14:22:27 +01:00
struct ldb_dn * nc_root ;
2013-01-17 08:51:23 +01:00
struct ldb_control * as_system ;
2014-11-04 20:21:57 +02:00
struct ldb_control * is_undelete ;
2013-01-17 08:51:23 +01:00
TALLOC_CTX * tmp_ctx ;
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
} ;
2013-01-17 08:51:23 +01:00
if ( ldb_dn_is_special ( req - > op . rename . olddn ) ) {
return ldb_next_request ( module , req ) ;
}
as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
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
}
2010-11-16 14:22:27 +01:00
2009-11-05 17:34:12 +02:00
ldb = ldb_module_get_ctx ( module ) ;
2009-09-21 17:27:50 -07:00
2013-01-17 08:51:23 +01:00
tmp_ctx = talloc_new ( req ) ;
if ( tmp_ctx = = NULL ) {
return ldb_oom ( ldb ) ;
}
oldparent = ldb_dn_get_parent ( tmp_ctx , req - > op . rename . olddn ) ;
if ( oldparent = = NULL ) {
return ldb_oom ( ldb ) ;
}
newparent = ldb_dn_get_parent ( tmp_ctx , req - > op . rename . newdn ) ;
if ( newparent = = NULL ) {
return ldb_oom ( ldb ) ;
}
2010-11-16 14:22:27 +01:00
/* Make sure we aren't renaming/moving a NC */
ret = dsdb_find_nc_root ( ldb , req , req - > op . rename . olddn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( ldb_dn_compare ( nc_root , req - > op . rename . olddn ) = = 0 ) {
talloc_free ( nc_root ) ;
DEBUG ( 10 , ( " acl:renaming/moving a NC \n " ) ) ;
/* Windows returns "ERR_UNWILLING_TO_PERFORM */
return ldb_module_done ( req , NULL , NULL ,
LDB_ERR_UNWILLING_TO_PERFORM ) ;
}
2014-11-04 20:21:57 +02:00
/* special check for undelete operation */
is_undelete = ldb_request_get_control ( req , DSDB_CONTROL_RESTORE_TOMBSTONE_OID ) ;
if ( is_undelete ! = NULL ) {
is_undelete - > critical = 0 ;
ret = acl_check_reanimate_tombstone ( tmp_ctx , module , req , nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
}
2010-11-16 14:22:27 +01:00
talloc_free ( nc_root ) ;
/* Look for the parent */
2010-12-23 21:56:52 +01:00
ret = dsdb_module_search_dn ( module , tmp_ctx , & acl_res ,
req - > op . rename . olddn , acl_attrs ,
2010-07-06 03:26:03 +03:00
DSDB_FLAG_NEXT_MODULE |
2012-11-21 07:14:31 +01:00
DSDB_FLAG_AS_SYSTEM |
2011-01-17 13:12:15 +11:00
DSDB_SEARCH_SHOW_RECYCLED , req ) ;
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 ) ) ) ;
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2009-11-05 17:34:12 +02:00
return ret ;
2009-09-21 17:27:50 -07:00
}
2013-01-16 16:43:14 +01:00
ret = dsdb_get_sd_from_ldb_message ( ldb , req , acl_res - > msgs [ 0 ] , & sd ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ldb_operr ( ldb ) ;
}
if ( ! sd ) {
talloc_free ( tmp_ctx ) ;
return ldb_operr ( ldb ) ;
}
2010-03-16 14:43:33 +11:00
schema = dsdb_get_schema ( ldb , acl_res ) ;
if ( ! schema ) {
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-03-16 14:43:33 +11:00
}
2013-01-16 16:43:14 +01:00
sid = samdb_result_dom_sid ( req , acl_res - > msgs [ 0 ] , " objectSid " ) ;
2013-01-02 14:54:20 +11:00
objectclass = dsdb_get_structural_oc_from_msg ( schema , acl_res - > msgs [ 0 ] ) ;
if ( ! objectclass ) {
talloc_free ( tmp_ctx ) ;
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR ,
" acl_modify: Error retrieving object class for GUID. " ) ;
}
2013-01-16 16:43:14 +01:00
attr = dsdb_attribute_by_lDAPDisplayName ( schema , " name " ) ;
if ( attr = = NULL ) {
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2013-01-02 14:54:20 +11:00
}
2009-09-21 17:27:50 -07:00
2013-01-16 16:43:14 +01:00
ret = acl_check_access_on_attribute ( module , tmp_ctx , sd , sid ,
SEC_ADS_WRITE_PROP ,
attr , objectclass ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" Object %s has no wp on %s \n " ,
ldb_dn_get_linearized ( req - > op . rename . olddn ) ,
attr - > lDAPDisplayName ) ;
dsdb_acl_debug ( sd ,
acl_user_token ( module ) ,
req - > op . rename . olddn ,
true ,
10 ) ;
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2013-01-16 16:43:14 +01:00
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
2013-01-02 14:54:20 +11:00
}
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 ) {
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-03-07 21:42:53 +02:00
}
2009-09-21 17:27:50 -07:00
2013-01-16 16:43:14 +01:00
attr = dsdb_attribute_by_lDAPDisplayName ( schema , rdn_name ) ;
if ( attr = = NULL ) {
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-11-05 17:34:12 +02:00
}
2013-01-16 16:43:14 +01:00
ret = acl_check_access_on_attribute ( module , tmp_ctx , sd , sid ,
SEC_ADS_WRITE_PROP ,
attr , objectclass ) ;
if ( ret ! = LDB_SUCCESS ) {
2011-08-25 19:20:28 +10:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
2013-01-16 16:43:14 +01:00
" Object %s has no wp on %s \n " ,
ldb_dn_get_linearized ( req - > op . rename . olddn ) ,
attr - > lDAPDisplayName ) ;
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 ) ;
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2009-11-05 17:34:12 +02:00
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 */
2010-12-23 21:56:52 +01: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
}
2009-09-21 17:27:50 -07:00
2009-11-05 17:34:12 +02:00
/* new parent should have create child */
2013-01-02 14:54:20 +11:00
ret = dsdb_module_check_access_on_dn ( module , req , newparent ,
SEC_ADS_CREATE_CHILD ,
& objectclass - > schemaIDGUID , req ) ;
2009-11-05 17:34:12 +02:00
if ( ret ! = LDB_SUCCESS ) {
2011-08-25 19:20:28 +10:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" acl:access_denied renaming %s " ,
ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ;
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2009-11-05 17:34:12 +02:00
return ret ;
}
2009-09-21 17:27:50 -07:00
2013-01-16 16:43:14 +01:00
/* do we have delete object on the object? */
2014-11-04 20:21:57 +02:00
/* this access is not necessary for undelete ops */
if ( is_undelete = = NULL ) {
ret = acl_check_access_on_objectclass ( module , tmp_ctx , sd , sid ,
SEC_STD_DELETE ,
objectclass ) ;
if ( ret = = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ldb_next_request ( module , req ) ;
}
/* what about delete child on the current parent */
ret = dsdb_module_check_access_on_dn ( module , req , oldparent ,
SEC_ADS_DELETE_CHILD ,
& objectclass - > schemaIDGUID ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" acl:access_denied renaming %s " , ldb_dn_get_linearized ( req - > op . rename . olddn ) ) ;
talloc_free ( tmp_ctx ) ;
return ldb_module_done ( req , NULL , NULL , ret ) ;
}
2009-09-21 17:27:50 -07:00
}
2010-12-23 21:56:52 +01:00
talloc_free ( tmp_ctx ) ;
2009-11-05 17:34:12 +02:00
return ldb_next_request ( module , req ) ;
2009-09-21 17:27:50 -07:00
}
2012-11-09 17:05:44 +01:00
static int acl_search_update_confidential_attrs ( struct acl_context * ac ,
struct acl_private * data )
{
struct dsdb_attribute * a ;
uint32_t n = 0 ;
2012-11-21 12:12:41 +01:00
if ( data - > acl_search ) {
/*
* If acl : search is activated , the acl_read module
* protects confidential attributes .
*/
return LDB_SUCCESS ;
}
2012-11-09 17:05:44 +01:00
if ( ( ac - > schema = = data - > cached_schema_ptr ) & &
( ac - > schema - > metadata_usn = = data - > cached_schema_metadata_usn ) )
{
return LDB_SUCCESS ;
}
data - > cached_schema_ptr = NULL ;
data - > cached_schema_loaded_usn = 0 ;
data - > cached_schema_metadata_usn = 0 ;
TALLOC_FREE ( data - > confidential_attrs ) ;
if ( ac - > schema = = NULL ) {
return LDB_SUCCESS ;
}
for ( a = ac - > schema - > attributes ; a ; a = a - > next ) {
const char * * attrs = data - > confidential_attrs ;
if ( ! ( a - > searchFlags & SEARCH_FLAG_CONFIDENTIAL ) ) {
continue ;
}
attrs = talloc_realloc ( data , attrs , const char * , n + 2 ) ;
if ( attrs = = NULL ) {
TALLOC_FREE ( data - > confidential_attrs ) ;
return ldb_module_oom ( ac - > module ) ;
}
attrs [ n ] = a - > lDAPDisplayName ;
attrs [ n + 1 ] = NULL ;
n + + ;
data - > confidential_attrs = attrs ;
}
data - > cached_schema_ptr = ac - > schema ;
data - > cached_schema_metadata_usn = ac - > schema - > metadata_usn ;
return LDB_SUCCESS ;
}
2009-12-10 15:49:53 +02:00
static int acl_search_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
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
} ;
2010-11-20 10:42:01 +01:00
int ret ;
unsigned int i ;
2009-12-10 15:49:53 +02:00
ac = talloc_get_type ( req - > context , struct acl_context ) ;
data = talloc_get_type ( ldb_module_get_private ( ac - > module ) , struct acl_private ) ;
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 :
2012-11-09 11:23:47 +01:00
if ( ac - > constructed_attrs ) {
2010-03-12 02:21:16 +02:00
ret = dsdb_module_search_dn ( ac - > module , ac , & acl_res , ares - > message - > dn ,
2010-07-06 03:26:03 +03:00
acl_attrs ,
2011-07-13 10:28:07 +10:00
DSDB_FLAG_NEXT_MODULE |
2012-11-21 07:14:31 +01:00
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_RECYCLED ,
req ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
2012-11-09 11:23:47 +01:00
}
if ( ac - > allowedAttributes | | ac - > allowedAttributesEffective ) {
ret = acl_allowedAttributes ( ac - > module , ac - > schema ,
acl_res - > msgs [ 0 ] ,
ares - > message , ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
2009-12-10 15:49:53 +02:00
}
2012-11-09 11:23:47 +01:00
}
if ( ac - > allowedChildClasses ) {
ret = acl_childClasses ( ac - > module , ac - > schema ,
acl_res - > msgs [ 0 ] ,
ares - > message ,
" allowedChildClasses " ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
2009-12-10 15:49:53 +02:00
}
2012-11-09 11:23:47 +01:00
}
if ( ac - > allowedChildClassesEffective ) {
ret = acl_childClassesEffective ( ac - > module , ac - > schema ,
acl_res - > msgs [ 0 ] ,
ares - > message , ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
2009-12-10 15:49:53 +02:00
}
2012-11-09 11:23:47 +01:00
}
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 ) ;
2009-12-10 15:49:53 +02:00
}
}
2010-11-09 14:39:30 +01:00
2012-11-09 11:23:47 +01:00
if ( data = = NULL ) {
return ldb_module_send_entry ( ac - > req , ares - > message ,
ares - > controls ) ;
}
if ( ac - > am_system ) {
return ldb_module_send_entry ( ac - > req , ares - > message ,
ares - > controls ) ;
}
if ( data - > password_attrs ! = NULL ) {
for ( i = 0 ; data - > password_attrs [ i ] ; i + + ) {
if ( ( ! ac - > userPassword ) & &
( ldb_attr_cmp ( data - > password_attrs [ i ] ,
" userPassword " ) = = 0 ) )
{
continue ;
2009-12-10 15:49:53 +02:00
}
2012-11-09 11:23:47 +01:00
ldb_msg_remove_attr ( ares - > message , data - > password_attrs [ i ] ) ;
2009-12-10 15:49:53 +02:00
}
}
2012-11-09 17:05:44 +01:00
if ( ac - > am_administrator ) {
return ldb_module_send_entry ( ac - > req , ares - > message ,
ares - > controls ) ;
}
ret = acl_search_update_confidential_attrs ( ac , data ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( data - > confidential_attrs ! = NULL ) {
for ( i = 0 ; data - > confidential_attrs [ i ] ; i + + ) {
ldb_msg_remove_attr ( ares - > message ,
data - > confidential_attrs [ i ] ) ;
}
}
2009-12-10 15:49:53 +02:00
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 ;
2012-11-09 11:23:47 +01:00
struct ldb_parse_tree * down_tree ;
2009-12-10 15:49:53 +02:00
struct ldb_request * down_req ;
struct acl_private * data ;
2010-11-20 10:42:01 +01:00
int ret ;
unsigned int i ;
2009-12-10 15:49:53 +02:00
2012-12-30 02:27:25 -08:00
if ( ldb_dn_is_special ( req - > op . search . base ) ) {
return ldb_next_request ( module , req ) ;
}
2009-12-10 15:49:53 +02:00
ldb = ldb_module_get_ctx ( module ) ;
ac = talloc_zero ( req , struct acl_context ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-12-10 15:49:53 +02:00
}
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 ) ;
2012-11-09 17:05:44 +01:00
ac - > am_administrator = dsdb_module_am_administrator ( module ) ;
2012-11-09 11:23:47 +01:00
ac - > constructed_attrs = false ;
ac - > modify_search = true ;
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 " ) ;
2013-01-17 08:37:12 +01:00
ac - > userPassword = true ;
2010-03-16 14:43:33 +11:00
ac - > schema = dsdb_get_schema ( ldb , ac ) ;
2009-12-10 15:49:53 +02:00
2012-11-09 11:23:47 +01:00
ac - > constructed_attrs | = ac - > allowedAttributes ;
ac - > constructed_attrs | = ac - > allowedChildClasses ;
ac - > constructed_attrs | = ac - > allowedChildClassesEffective ;
ac - > constructed_attrs | = ac - > allowedAttributesEffective ;
ac - > constructed_attrs | = ac - > sDRightsEffective ;
2010-11-09 14:39:30 +01:00
2012-11-09 11:23:47 +01:00
if ( data = = NULL ) {
ac - > modify_search = false ;
}
if ( ac - > am_system ) {
ac - > modify_search = false ;
}
if ( ! ac - > constructed_attrs & & ! ac - > modify_search ) {
2013-01-17 08:37:58 +01:00
talloc_free ( ac ) ;
2012-11-09 11:23:47 +01:00
return ldb_next_request ( module , req ) ;
}
2016-02-12 15:53:37 +13:00
data = talloc_get_type ( ldb_module_get_private ( ac - > module ) , struct acl_private ) ;
if ( data ! = NULL ) {
ac - > userPassword = data - > userPassword_support ;
2013-01-17 08:37:12 +01:00
}
2012-11-09 17:05:44 +01:00
ret = acl_search_update_confidential_attrs ( ac , data ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2012-11-09 11:23:47 +01:00
down_tree = ldb_parse_tree_copy_shallow ( ac , req - > op . search . tree ) ;
if ( down_tree = = NULL ) {
return ldb_oom ( ldb ) ;
}
if ( ! ac - > am_system & & data - > password_attrs ) {
for ( i = 0 ; data - > password_attrs [ i ] ; i + + ) {
if ( ( ! ac - > userPassword ) & &
( ldb_attr_cmp ( data - > password_attrs [ i ] ,
" userPassword " ) = = 0 ) )
{
continue ;
2009-12-10 15:49:53 +02:00
}
2012-11-09 11:23:47 +01:00
ldb_parse_tree_attr_replace ( down_tree ,
data - > password_attrs [ i ] ,
" kludgeACLredactedattribute " ) ;
2009-12-10 15:49:53 +02:00
}
}
2012-11-09 17:05:44 +01:00
if ( ! ac - > am_system & & ! ac - > am_administrator & & data - > confidential_attrs ) {
for ( i = 0 ; data - > confidential_attrs [ i ] ; i + + ) {
ldb_parse_tree_attr_replace ( down_tree ,
data - > confidential_attrs [ i ] ,
" kludgeACLredactedattribute " ) ;
}
}
2009-12-10 15:49:53 +02:00
ret = ldb_build_search_req_ex ( & down_req ,
ldb , ac ,
req - > op . search . base ,
req - > op . search . scope ,
2012-11-09 11:23:47 +01:00
down_tree ,
2009-12-10 15:49:53 +02:00
req - > op . search . attrs ,
req - > controls ,
ac , acl_search_callback ,
req ) ;
2010-09-24 12:09:26 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2009-12-10 15:49:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
/* perform the search */
return ldb_next_request ( module , down_req ) ;
}
2010-08-04 15:22:17 +03:00
static int acl_extended ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_control * as_system = ldb_request_get_control ( req , LDB_CONTROL_AS_SYSTEM_OID ) ;
/* allow everybody to read the sequence number */
if ( strcmp ( req - > op . extended . oid ,
LDB_EXTENDED_SEQUENCE_NUMBER ) = = 0 ) {
return ldb_next_request ( module , req ) ;
}
if ( dsdb_module_am_system ( module ) | |
dsdb_module_am_administrator ( module ) | | as_system ) {
return ldb_next_request ( module , req ) ;
} else {
ldb_asprintf_errstring ( ldb ,
" acl_extended: "
" attempted database modify not permitted. "
" User %s is not SYSTEM or an administrator " ,
acl_user_name ( req , module ) ) ;
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ;
}
}
2010-11-01 15:28:02 +11:00
static const struct ldb_module_ops ldb_acl_module_ops = {
2009-09-21 17:27:50 -07:00
. 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 ,
2010-08-04 15:22:17 +03:00
. extended = acl_extended ,
2009-09-21 17:27:50 -07:00
. init_context = acl_module_init
} ;
2010-11-01 15:28:02 +11:00
int ldb_acl_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_acl_module_ops ) ;
}