2005-11-29 08:50:52 +00:00
/*
Unix SMB / CIFS implementation .
rootDSE ldb module
Copyright ( C ) Andrew Tridgell 2005
2008-09-11 18:36:28 -04:00
Copyright ( C ) Simo Sorce 2005 - 2008
2005-11-29 08:50:52 +00: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
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-11-29 08:50:52 +00:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-11-29 08:50:52 +00:00
*/
# include "includes.h"
2009-06-30 15:30:13 +10:00
# include "lib/ldb/include/ldb.h"
# include "lib/ldb/include/ldb_module.h"
2006-01-11 15:01:21 +00:00
# include "system/time.h"
2007-01-18 00:49:52 +00:00
# include "dsdb/samdb/samdb.h"
2008-04-04 12:25:19 +11:00
# include "version.h"
2010-02-12 14:18:27 -02:00
# include "dsdb/samdb/ldb_modules/util.h"
# include "libcli/security/security.h"
# include "librpc/ndr/libndr.h"
2005-11-29 08:50:52 +00:00
2006-01-06 04:01:23 +00:00
struct private_data {
2010-03-07 19:11:03 +01:00
unsigned int num_controls ;
2006-01-06 04:01:23 +00:00
char * * controls ;
2010-03-07 19:11:03 +01:00
unsigned int num_partitions ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
struct ldb_dn * * partitions ;
2006-01-06 04:01:23 +00:00
} ;
2005-11-29 08:50:52 +00:00
/*
return 1 if a specific attribute has been requested
*/
static int do_attribute ( const char * const * attrs , const char * name )
{
return attrs = = NULL | |
ldb_attr_in_list ( attrs , name ) | |
ldb_attr_in_list ( attrs , " * " ) ;
}
2007-01-18 00:49:52 +00:00
static int do_attribute_explicit ( const char * const * attrs , const char * name )
{
return attrs ! = NULL & & ldb_attr_in_list ( attrs , name ) ;
}
2006-02-27 00:39:26 +00:00
2009-09-20 18:24:23 -07:00
/*
expand a DN attribute to include extended DN information if requested
*/
static int expand_dn_in_message ( struct ldb_module * module , struct ldb_message * msg ,
const char * attrname , struct ldb_control * edn_control ,
struct ldb_request * req )
{
struct ldb_dn * dn , * dn2 ;
struct ldb_val * v ;
int ret ;
struct ldb_request * req2 ;
char * dn_string ;
const char * no_attrs [ ] = { NULL } ;
struct ldb_result * res ;
struct ldb_extended_dn_control * edn ;
TALLOC_CTX * tmp_ctx = talloc_new ( req ) ;
struct ldb_context * ldb ;
2009-09-20 18:58:18 -07:00
int edn_type = 0 ;
2009-09-20 18:24:23 -07:00
ldb = ldb_module_get_ctx ( module ) ;
edn = talloc_get_type ( edn_control - > data , struct ldb_extended_dn_control ) ;
if ( edn ) {
edn_type = edn - > type ;
}
v = discard_const_p ( struct ldb_val , ldb_msg_find_ldb_val ( msg , attrname ) ) ;
if ( v = = NULL ) {
talloc_free ( tmp_ctx ) ;
return 0 ;
}
dn_string = talloc_strndup ( tmp_ctx , ( const char * ) v - > data , v - > length ) ;
if ( dn_string = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( res = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
dn = ldb_dn_new ( tmp_ctx , ldb , dn_string ) ;
if ( ! ldb_dn_validate ( dn ) ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_build_search_req ( & req2 , ldb , tmp_ctx ,
dn ,
LDB_SCOPE_BASE ,
NULL ,
no_attrs ,
NULL ,
res , ldb_search_default_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_request_add_control ( req2 ,
LDB_CONTROL_EXTENDED_DN_OID ,
edn_control - > critical , edn ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_next_request ( module , req2 ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req2 - > handle , LDB_WAIT_ALL ) ;
}
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( ! res | | res - > count ! = 1 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
dn2 = res - > msgs [ 0 ] - > dn ;
v - > data = ( uint8_t * ) ldb_dn_get_extended_linearized ( msg - > elements , dn2 , edn_type ) ;
v - > length = strlen ( ( char * ) v - > data ) ;
if ( v - > data = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2005-11-29 08:50:52 +00:00
/*
add dynamically generated attributes to rootDSE result
*/
2009-09-20 18:24:23 -07:00
static int rootdse_add_dynamic ( struct ldb_module * module , struct ldb_message * msg ,
const char * const * attrs , struct ldb_request * req )
2005-11-29 08:50:52 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
struct private_data * priv = talloc_get_type ( ldb_module_get_private ( module ) , struct private_data ) ;
2006-11-01 03:21:04 +00:00
char * * server_sasl ;
2007-01-18 00:49:52 +00:00
const struct dsdb_schema * schema ;
2009-07-14 08:15:50 +10:00
int * val ;
2009-09-20 18:24:23 -07:00
struct ldb_control * edn_control ;
const char * dn_attrs [ ] = {
" configurationNamingContext " ,
" defaultNamingContext " ,
" dsServiceName " ,
" rootDomainNamingContext " ,
" schemaNamingContext " ,
" serverName " ,
NULL
} ;
2007-01-18 00:49:52 +00:00
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
schema = dsdb_get_schema ( ldb ) ;
2005-11-29 08:50:52 +00:00
2009-01-30 16:31:19 -05:00
msg - > dn = ldb_dn_new ( msg , ldb , NULL ) ;
2005-11-29 08:50:52 +00:00
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
/* don't return the distinduishedName, cn and name attributes */
2006-03-14 17:39:02 +00:00
ldb_msg_remove_attr ( msg , " distinguishedName " ) ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
ldb_msg_remove_attr ( msg , " cn " ) ;
ldb_msg_remove_attr ( msg , " name " ) ;
2006-03-14 17:39:02 +00:00
2006-03-14 17:34:00 +00:00
if ( do_attribute ( attrs , " currentTime " ) ) {
2006-02-22 09:28:58 +00:00
if ( ldb_msg_add_steal_string ( msg , " currentTime " ,
ldb_timestring ( msg , time ( NULL ) ) ) ! = 0 ) {
2005-11-29 08:50:52 +00:00
goto failed ;
}
}
2009-07-14 08:15:50 +10:00
if ( priv & & do_attribute ( attrs , " supportedControl " ) ) {
2010-03-07 19:11:03 +01:00
unsigned int i ;
2006-01-06 04:01:23 +00:00
for ( i = 0 ; i < priv - > num_controls ; i + + ) {
2006-02-22 00:26:56 +00:00
char * control = talloc_strdup ( msg , priv - > controls [ i ] ) ;
if ( ! control ) {
goto failed ;
}
2006-02-22 09:28:58 +00:00
if ( ldb_msg_add_steal_string ( msg , " supportedControl " ,
control ) ! = 0 ) {
2006-01-06 04:01:23 +00:00
goto failed ;
}
}
}
2009-07-14 08:15:50 +10:00
if ( priv & & do_attribute ( attrs , " namingContexts " ) ) {
2010-03-07 19:11:03 +01:00
unsigned int i ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
for ( i = 0 ; i < priv - > num_partitions ; i + + ) {
struct ldb_dn * dn = priv - > partitions [ i ] ;
if ( ldb_msg_add_steal_string ( msg , " namingContexts " ,
2006-11-22 02:05:19 +00:00
ldb_dn_alloc_linearized ( msg , dn ) ) ! = 0 ) {
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
goto failed ;
}
}
}
2009-01-30 16:31:19 -05:00
server_sasl = talloc_get_type ( ldb_get_opaque ( ldb , " supportedSASLMechanims " ) ,
2006-11-01 03:21:04 +00:00
char * ) ;
if ( server_sasl & & do_attribute ( attrs , " supportedSASLMechanisms " ) ) {
2010-03-07 19:11:03 +01:00
unsigned int i ;
2006-11-01 03:21:04 +00:00
for ( i = 0 ; server_sasl & & server_sasl [ i ] ; i + + ) {
char * sasl_name = talloc_strdup ( msg , server_sasl [ i ] ) ;
if ( ! sasl_name ) {
goto failed ;
}
if ( ldb_msg_add_steal_string ( msg , " supportedSASLMechanisms " ,
sasl_name ) ! = 0 ) {
goto failed ;
2006-01-03 04:25:12 +00:00
}
}
}
2006-02-27 00:39:26 +00:00
2006-03-14 17:34:00 +00:00
if ( do_attribute ( attrs , " highestCommittedUSN " ) ) {
2006-06-07 21:03:38 +00:00
uint64_t seq_num ;
2009-01-30 16:31:19 -05:00
int ret = ldb_sequence_number ( ldb , LDB_SEQ_HIGHEST_SEQ , & seq_num ) ;
2006-06-07 21:03:38 +00:00
if ( ret = = LDB_SUCCESS ) {
if ( ldb_msg_add_fmt ( msg , " highestCommittedUSN " ,
2006-09-09 10:05:58 +00:00
" %llu " , ( unsigned long long ) seq_num ) ! = 0 ) {
2006-06-07 21:03:38 +00:00
goto failed ;
}
2006-02-27 00:39:26 +00:00
}
}
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
2007-01-18 00:49:52 +00:00
if ( schema & & do_attribute_explicit ( attrs , " dsSchemaAttrCount " ) ) {
struct dsdb_attribute * cur ;
2010-03-07 19:11:03 +01:00
unsigned int n = 0 ;
2007-01-18 00:49:52 +00:00
for ( cur = schema - > attributes ; cur ; cur = cur - > next ) {
n + + ;
}
if ( ldb_msg_add_fmt ( msg , " dsSchemaAttrCount " ,
" %u " , n ) ! = 0 ) {
goto failed ;
}
}
if ( schema & & do_attribute_explicit ( attrs , " dsSchemaClassCount " ) ) {
struct dsdb_class * cur ;
2010-03-07 19:11:03 +01:00
unsigned int n = 0 ;
2007-01-18 00:49:52 +00:00
for ( cur = schema - > classes ; cur ; cur = cur - > next ) {
n + + ;
}
if ( ldb_msg_add_fmt ( msg , " dsSchemaClassCount " ,
" %u " , n ) ! = 0 ) {
goto failed ;
}
}
if ( schema & & do_attribute_explicit ( attrs , " dsSchemaPrefixCount " ) ) {
if ( ldb_msg_add_fmt ( msg , " dsSchemaPrefixCount " ,
2009-10-29 16:24:00 +02:00
" %u " , schema - > prefixmap - > length ) ! = 0 ) {
2007-01-18 00:49:52 +00:00
goto failed ;
}
}
2007-01-18 01:31:09 +00:00
if ( do_attribute_explicit ( attrs , " validFSMOs " ) ) {
const struct dsdb_naming_fsmo * naming_fsmo ;
const struct dsdb_pdc_fsmo * pdc_fsmo ;
const char * dn_str ;
2008-07-01 16:35:13 +02:00
if ( schema & & schema - > fsmo . we_are_master ) {
2009-01-30 16:31:19 -05:00
dn_str = ldb_dn_get_linearized ( samdb_schema_dn ( ldb ) ) ;
2007-01-18 01:31:09 +00:00
if ( dn_str & & dn_str [ 0 ] ) {
if ( ldb_msg_add_fmt ( msg , " validFSMOs " , " %s " , dn_str ) ! = 0 ) {
goto failed ;
}
}
}
2009-01-30 16:31:19 -05:00
naming_fsmo = talloc_get_type ( ldb_get_opaque ( ldb , " dsdb_naming_fsmo " ) ,
2007-01-18 01:31:09 +00:00
struct dsdb_naming_fsmo ) ;
if ( naming_fsmo & & naming_fsmo - > we_are_master ) {
2009-01-30 16:31:19 -05:00
dn_str = ldb_dn_get_linearized ( samdb_partitions_dn ( ldb , msg ) ) ;
2007-01-18 01:31:09 +00:00
if ( dn_str & & dn_str [ 0 ] ) {
if ( ldb_msg_add_fmt ( msg , " validFSMOs " , " %s " , dn_str ) ! = 0 ) {
goto failed ;
}
}
}
2009-01-30 16:31:19 -05:00
pdc_fsmo = talloc_get_type ( ldb_get_opaque ( ldb , " dsdb_pdc_fsmo " ) ,
2007-01-18 01:31:09 +00:00
struct dsdb_pdc_fsmo ) ;
if ( pdc_fsmo & & pdc_fsmo - > we_are_master ) {
2009-01-30 16:31:19 -05:00
dn_str = ldb_dn_get_linearized ( samdb_base_dn ( ldb ) ) ;
2007-01-18 01:31:09 +00:00
if ( dn_str & & dn_str [ 0 ] ) {
if ( ldb_msg_add_fmt ( msg , " validFSMOs " , " %s " , dn_str ) ! = 0 ) {
goto failed ;
}
}
}
}
2009-07-14 08:15:50 +10:00
if ( do_attribute_explicit ( attrs , " vendorVersion " ) ) {
2008-04-04 12:25:19 +11:00
if ( ldb_msg_add_fmt ( msg , " vendorVersion " ,
" %s " , SAMBA_VERSION_STRING ) ! = 0 ) {
goto failed ;
}
}
2009-12-09 15:18:37 +11:00
if ( priv & & do_attribute ( attrs , " domainFunctionality " ) ) {
2009-07-14 08:15:50 +10:00
if ( ldb_msg_add_fmt ( msg , " domainFunctionality " ,
2009-12-09 15:18:37 +11:00
" %d " , dsdb_functional_level ( ldb ) ) ! = 0 ) {
2009-07-14 08:15:50 +10:00
goto failed ;
}
}
if ( priv & & do_attribute ( attrs , " forestFunctionality " )
& & ( val = talloc_get_type ( ldb_get_opaque ( ldb , " forestFunctionality " ) , int ) ) ) {
if ( ldb_msg_add_fmt ( msg , " forestFunctionality " ,
" %d " , * val ) ! = 0 ) {
goto failed ;
}
}
if ( priv & & do_attribute ( attrs , " domainControllerFunctionality " )
& & ( val = talloc_get_type ( ldb_get_opaque ( ldb , " domainControllerFunctionality " ) , int ) ) ) {
if ( ldb_msg_add_fmt ( msg , " domainControllerFunctionality " ,
" %d " , * val ) ! = 0 ) {
goto failed ;
}
}
2009-09-20 18:24:23 -07:00
edn_control = ldb_request_get_control ( req , LDB_CONTROL_EXTENDED_DN_OID ) ;
/* if the client sent us the EXTENDED_DN control then we need
to expand the DNs to have GUID and SID . W2K8 join relies on
this */
if ( edn_control ) {
2010-03-07 19:11:03 +01:00
unsigned int i ;
int ret ;
2009-09-20 18:24:23 -07:00
for ( i = 0 ; dn_attrs [ i ] ; i + + ) {
if ( ! do_attribute ( attrs , dn_attrs [ i ] ) ) continue ;
ret = expand_dn_in_message ( module , msg , dn_attrs [ i ] ,
edn_control , req ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to expand DN in rootDSE for %s \n " ,
dn_attrs [ i ] ) ) ;
goto failed ;
}
}
}
2010-01-17 06:48:09 +11:00
if ( do_attribute ( attrs , " isGlobalCatalogReady " ) ) {
2010-01-15 19:13:26 +11:00
/* MS-ADTS 3.1.1.3.2.10
Note , we should only return true here is we have
completed at least one synchronisation . As both
provision and vampire do a full sync , this means we
can return true is the gc bit is set in the NTDSDSA
options */
if ( ldb_msg_add_fmt ( msg , " isGlobalCatalogReady " ,
" %s " , samdb_is_gc ( ldb ) ? " TRUE " : " FALSE " ) ! = 0 ) {
goto failed ;
}
}
2009-09-20 18:24:23 -07:00
2005-11-29 08:50:52 +00:00
/* TODO: lots more dynamic attributes should be added here */
2006-03-14 17:34:00 +00:00
return LDB_SUCCESS ;
2005-11-29 08:50:52 +00:00
failed :
return LDB_ERR_OPERATIONS_ERROR ;
}
/*
handle search requests
*/
2006-07-22 17:21:59 +00:00
struct rootdse_context {
2006-03-14 17:34:00 +00:00
struct ldb_module * module ;
2008-09-11 18:36:28 -04:00
struct ldb_request * req ;
2006-03-14 17:34:00 +00:00
} ;
2008-09-11 18:36:28 -04:00
static struct rootdse_context * rootdse_init_context ( struct ldb_module * module ,
struct ldb_request * req )
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct rootdse_context * ac ;
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-09-11 18:36:28 -04:00
ac = talloc_zero ( req , struct rootdse_context ) ;
if ( ac = = NULL ) {
2009-01-30 16:31:19 -05:00
ldb_set_errstring ( ldb , " Out of Memory " ) ;
2008-09-11 18:36:28 -04:00
return NULL ;
}
ac - > module = module ;
ac - > req = req ;
return ac ;
}
static int rootdse_callback ( struct ldb_request * req , struct ldb_reply * ares )
2006-03-14 17:34:00 +00:00
{
2006-07-22 17:21:59 +00:00
struct rootdse_context * ac ;
2008-09-11 18:36:28 -04:00
int ret ;
2006-03-14 17:34:00 +00:00
2008-09-11 18:36:28 -04:00
ac = talloc_get_type ( req - > context , struct rootdse_context ) ;
2006-03-14 17:34:00 +00:00
2008-09-11 18:36:28 -04:00
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 :
2006-11-15 17:35:24 +00:00
/*
* if the client explicit asks for the ' netlogon ' attribute
* the reply_entry needs to be skipped
*/
2008-09-11 18:36:28 -04:00
if ( ac - > req - > op . search . attrs & &
ldb_attr_in_list ( ac - > req - > op . search . attrs , " netlogon " ) ) {
2006-11-15 17:35:24 +00:00
talloc_free ( ares ) ;
return LDB_SUCCESS ;
}
2006-03-14 17:34:00 +00:00
/* for each record returned post-process to add any dynamic
attributes that have been asked for */
2008-09-11 18:36:28 -04:00
ret = rootdse_add_dynamic ( ac - > module , ares - > message ,
2009-09-20 18:24:23 -07:00
ac - > req - > op . search . attrs , ac - > req ) ;
2008-09-11 18:36:28 -04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( ares ) ;
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
2006-03-14 17:34:00 +00:00
}
2008-12-16 08:59:05 +01:00
return ldb_module_send_entry ( ac - > req , ares - > message , ares - > controls ) ;
2008-09-11 18:36:28 -04:00
case LDB_REPLY_REFERRAL :
/* should we allow the backend to return referrals in this case
* ? ? */
break ;
case LDB_REPLY_DONE :
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
2006-03-14 17:34:00 +00:00
talloc_free ( ares ) ;
2008-09-11 18:36:28 -04:00
return LDB_SUCCESS ;
2006-03-14 17:34:00 +00:00
}
2006-05-29 23:46:43 +00:00
static int rootdse_search ( struct ldb_module * module , struct ldb_request * req )
2006-03-14 17:34:00 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2006-07-22 17:21:59 +00:00
struct rootdse_context * ac ;
2006-03-14 17:34:00 +00:00
struct ldb_request * down_req ;
int ret ;
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-07-25 08:44:00 +10:00
/* see if its for the rootDSE - only a base search on the "" DN qualifies */
2008-12-16 09:01:35 +01:00
if ( ! ( req - > op . search . scope = = LDB_SCOPE_BASE & & ldb_dn_is_null ( req - > op . search . base ) ) ) {
2008-07-25 08:44:00 +10:00
/* Otherwise, pass down to the rest of the stack */
2006-03-14 17:34:00 +00:00
return ldb_next_request ( module , req ) ;
}
2008-09-11 18:36:28 -04:00
ac = rootdse_init_context ( module , req ) ;
2006-03-14 17:34:00 +00:00
if ( ac = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2007-10-30 21:01:07 +01:00
/* in our db we store the rootDSE with a DN of @ROOTDSE */
2009-01-30 16:31:19 -05:00
ret = ldb_build_search_req ( & down_req , ldb , ac ,
ldb_dn_new ( ac , ldb , " @ROOTDSE " ) ,
2008-09-11 18:36:28 -04:00
LDB_SCOPE_BASE ,
NULL ,
req - > op . search . attrs ,
2008-10-02 11:20:10 +02:00
NULL , /* for now skip the controls from the client */
2008-09-11 18:36:28 -04:00
ac , rootdse_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
2006-03-14 17:34:00 +00:00
}
2008-09-11 18:36:28 -04:00
return ldb_next_request ( module , down_req ) ;
2006-03-14 17:34:00 +00:00
}
2006-01-06 04:01:23 +00:00
static int rootdse_register_control ( struct ldb_module * module , struct ldb_request * req )
{
2009-01-30 16:31:19 -05:00
struct private_data * priv = talloc_get_type ( ldb_module_get_private ( module ) , struct private_data ) ;
2006-01-06 04:01:23 +00:00
char * * list ;
list = talloc_realloc ( priv , priv - > controls , char * , priv - > num_controls + 1 ) ;
if ( ! list ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
list [ priv - > num_controls ] = talloc_strdup ( list , req - > op . reg_control . oid ) ;
2006-01-06 04:01:23 +00:00
if ( ! list [ priv - > num_controls ] ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
priv - > num_controls + = 1 ;
priv - > controls = list ;
2008-09-11 18:36:28 -04:00
return ldb_module_done ( req , NULL , NULL , LDB_SUCCESS ) ;
2006-01-06 04:01:23 +00:00
}
2008-09-11 18:36:28 -04:00
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
static int rootdse_register_partition ( struct ldb_module * module , struct ldb_request * req )
{
2009-01-30 16:31:19 -05:00
struct private_data * priv = talloc_get_type ( ldb_module_get_private ( module ) , struct private_data ) ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
struct ldb_dn * * list ;
list = talloc_realloc ( priv , priv - > partitions , struct ldb_dn * , priv - > num_partitions + 1 ) ;
if ( ! list ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2006-09-09 10:05:58 +00:00
list [ priv - > num_partitions ] = ldb_dn_copy ( list , req - > op . reg_partition . dn ) ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
if ( ! list [ priv - > num_partitions ] ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
priv - > num_partitions + = 1 ;
priv - > partitions = list ;
2008-09-11 18:36:28 -04:00
return ldb_module_done ( req , NULL , NULL , LDB_SUCCESS ) ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
}
2008-09-11 18:36:28 -04:00
2005-11-29 08:50:52 +00:00
static int rootdse_request ( struct ldb_module * module , struct ldb_request * req )
{
switch ( req - > operation ) {
2006-03-14 17:34:00 +00:00
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
case LDB_REQ_REGISTER_CONTROL :
2006-01-06 04:01:23 +00:00
return rootdse_register_control ( module , req ) ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
case LDB_REQ_REGISTER_PARTITION :
return rootdse_register_partition ( module , req ) ;
2006-03-14 17:34:00 +00:00
2005-11-29 08:50:52 +00:00
default :
break ;
}
return ldb_next_request ( module , req ) ;
}
2006-03-02 16:32:53 +00:00
static int rootdse_init ( struct ldb_module * module )
2005-11-29 08:50:52 +00:00
{
2009-07-14 08:15:50 +10:00
int ret ;
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2009-07-14 08:15:50 +10:00
struct ldb_result * res ;
2006-01-06 04:01:23 +00:00
struct private_data * data ;
2009-07-14 08:15:50 +10:00
const char * attrs [ ] = { " msDS-Behavior-Version " , NULL } ;
const char * ds_attrs [ ] = { " dsServiceName " , NULL } ;
TALLOC_CTX * mem_ctx ;
2006-01-06 04:01:23 +00:00
2009-01-30 16:31:19 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2009-07-14 08:15:50 +10:00
data = talloc_zero ( module , struct private_data ) ;
2006-01-06 04:01:23 +00:00
if ( data = = NULL ) {
2006-03-02 16:32:53 +00:00
return - 1 ;
2006-01-06 04:01:23 +00:00
}
data - > num_controls = 0 ;
data - > controls = NULL ;
r16264: Add, but do not yet enable, the partitions module.
This required changes to the rootDSE module, to allow registration of
partitions. In doing so I renamed the 'register' operation to
'register_control' and 'register_partition', which changed a few more
modules.
Due to the behaviour of certain LDAP servers, we create the baseDN
entry in two parts: Firstly, we allow the admin to export a simple
LDIF file to add to their server. Then we perform a modify to add the
remaining attributes.
To delete all users in partitions, we must now search and delete all
objects in the partition, rather than a simple search from the root.
Against LDAP, this might not delete all objects, so we allow this to
fail.
In testing, we found that the 'Domain Controllers' container was
misnamed, and should be 'CN=', rather than 'OU='.
To avoid the Templates being found in default searches, they have been
moved to CN=Templates from CN=Templates,${BASEDN}.
Andrew Bartlett
(This used to be commit b49a4fbb57f10726bd288fdc9fc95c0cbbe9094a)
2006-06-15 18:04:24 +00:00
data - > num_partitions = 0 ;
data - > partitions = NULL ;
2009-01-30 16:31:19 -05:00
ldb_module_set_private ( module , data ) ;
2006-01-06 04:01:23 +00:00
2009-01-30 16:31:19 -05:00
ldb_set_default_dns ( ldb ) ;
2007-01-14 13:45:18 +00:00
2009-07-14 08:15:50 +10:00
ret = ldb_next_init ( module ) ;
if ( ret ) {
return ret ;
}
mem_ctx = talloc_new ( data ) ;
if ( ! mem_ctx ) {
ldb_oom ( ldb ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
/* Now that the partitions are set up, do a search for:
- domainControllerFunctionality
- domainFunctionality
- forestFunctionality
Then stuff these values into an opaque
*/
ret = ldb_search ( ldb , mem_ctx , & res ,
ldb_get_default_basedn ( ldb ) ,
LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
int domain_behaviour_version
= ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] ,
" msDS-Behavior-Version " , - 1 ) ;
if ( domain_behaviour_version ! = - 1 ) {
int * val = talloc ( ldb , int ) ;
if ( ! val ) {
ldb_oom ( ldb ) ;
talloc_free ( mem_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
* val = domain_behaviour_version ;
ret = ldb_set_opaque ( ldb , " domainFunctionality " , val ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
}
ret = ldb_search ( ldb , mem_ctx , & res ,
samdb_partitions_dn ( ldb , mem_ctx ) ,
LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
int forest_behaviour_version
= ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] ,
" msDS-Behavior-Version " , - 1 ) ;
if ( forest_behaviour_version ! = - 1 ) {
int * val = talloc ( ldb , int ) ;
if ( ! val ) {
ldb_oom ( ldb ) ;
talloc_free ( mem_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
* val = forest_behaviour_version ;
ret = ldb_set_opaque ( ldb , " forestFunctionality " , val ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
}
ret = ldb_search ( ldb , mem_ctx , & res ,
ldb_dn_new ( mem_ctx , ldb , " " ) ,
LDB_SCOPE_BASE , ds_attrs , NULL ) ;
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
struct ldb_dn * ds_dn
= ldb_msg_find_attr_as_dn ( ldb , mem_ctx , res - > msgs [ 0 ] ,
" dsServiceName " ) ;
if ( ds_dn ) {
ret = ldb_search ( ldb , mem_ctx , & res , ds_dn ,
LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
int domain_controller_behaviour_version
= ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] ,
" msDS-Behavior-Version " , - 1 ) ;
if ( domain_controller_behaviour_version ! = - 1 ) {
int * val = talloc ( ldb , int ) ;
if ( ! val ) {
ldb_oom ( ldb ) ;
talloc_free ( mem_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
* val = domain_controller_behaviour_version ;
ret = ldb_set_opaque ( ldb ,
" domainControllerFunctionality " , val ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
}
}
}
talloc_free ( mem_ctx ) ;
return LDB_SUCCESS ;
2006-03-02 16:32:53 +00:00
}
2005-11-29 08:50:52 +00:00
2010-02-12 14:18:27 -02:00
/*
* This function gets the string SCOPE_DN : OPTIONAL_FEATURE_GUID and parse it
* to a DN and a GUID object
*/
static int get_optional_feature_dn_guid ( struct ldb_request * req , struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * * op_feature_scope_dn ,
struct GUID * op_feature_guid )
2008-07-23 09:59:17 +03:00
{
2010-02-12 14:18:27 -02:00
const struct ldb_message * msg = req - > op . mod . message ;
const char * ldb_val_str ;
char * dn , * guid ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
NTSTATUS status ;
ldb_val_str = ldb_msg_find_attr_as_string ( msg , " enableOptionalFeature " , NULL ) ;
if ( ! ldb_val_str ) {
ldb_asprintf_errstring ( ldb ,
" rootdse: unable to find enableOptionalFeature \n " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
guid = strchr ( ldb_val_str , ' : ' ) ;
if ( ! guid ) {
ldb_asprintf_errstring ( ldb ,
" rootdse: unable to find GUID in enableOptionalFeature \n " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
status = GUID_from_string ( guid + 1 , op_feature_guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_asprintf_errstring ( ldb ,
" rootdse: bad GUID in enableOptionalFeature \n " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
dn = talloc_strndup ( tmp_ctx , ldb_val_str , guid - ldb_val_str ) ;
if ( ! dn ) {
ldb_asprintf_errstring ( ldb ,
" rootdse: bad DN in enableOptionalFeature \n " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
* op_feature_scope_dn = ldb_dn_new ( mem_ctx , ldb , dn ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
/*
* This function gets the OPTIONAL_FEATURE_GUID and looks for the optional feature
* ldb_message object .
*/
static int dsdb_find_optional_feature ( struct ldb_module * module , struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx , struct GUID op_feature_guid , struct ldb_message * * msg )
{
struct ldb_result * res ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
2008-07-23 09:59:17 +03:00
int ret ;
2010-02-12 14:18:27 -02:00
ret = dsdb_module_search ( module , tmp_ctx , & res , NULL , LDB_SCOPE_SUBTREE ,
NULL ,
DSDB_SEARCH_SEARCH_ALL_PARTITIONS ,
" (&(objectClass=msDS-OptionalFeature) "
" (msDS-OptionalFeatureGUID=%s)) " , GUID_string ( tmp_ctx , & op_feature_guid ) ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( res - > count = = 0 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
if ( res - > count ! = 1 ) {
ldb_asprintf_errstring ( ldb ,
" More than one object found matching optional feature GUID %s \n " ,
GUID_string ( tmp_ctx , & op_feature_guid ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2008-07-23 09:59:17 +03:00
}
2009-01-30 16:31:19 -05:00
2010-02-12 14:18:27 -02:00
* msg = talloc_steal ( mem_ctx , res - > msgs [ 0 ] ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
static int rootdse_enable_recycle_bin ( struct ldb_module * module , struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx , struct ldb_dn * op_feature_scope_dn ,
struct ldb_message * op_feature_msg )
{
int ret ;
const int domain_func_level = dsdb_functional_level ( ldb ) ;
struct ldb_dn * ntds_settings_dn ;
TALLOC_CTX * tmp_ctx ;
2010-03-07 19:11:03 +01:00
unsigned int el_count = 0 ;
2010-02-12 14:18:27 -02:00
struct ldb_message * msg ;
ret = ldb_msg_find_attr_as_int ( op_feature_msg , " msDS-RequiredForestBehaviorVersion " , 0 ) ;
if ( domain_func_level < ret ) {
ldb_asprintf_errstring ( ldb ,
" rootdse: Domain functional level must be at least %d \n " ,
ret ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
tmp_ctx = talloc_new ( mem_ctx ) ;
ntds_settings_dn = samdb_ntds_settings_dn ( ldb ) ;
if ( ! ntds_settings_dn ) {
ldb_asprintf_errstring ( ldb ,
__location__ " : Failed to find NTDS settings DN \n " ) ;
ret = LDB_ERR_OPERATIONS_ERROR ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
ntds_settings_dn = ldb_dn_copy ( tmp_ctx , ntds_settings_dn ) ;
if ( ! ntds_settings_dn ) {
DEBUG ( 0 , ( __location__ " : Failed to copy NTDS settings DN \n " ) ) ;
ret = LDB_ERR_OPERATIONS_ERROR ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
msg = ldb_msg_new ( tmp_ctx ) ;
msg - > dn = ntds_settings_dn ;
ldb_msg_add_linearized_dn ( msg , " msDS-EnabledFeature " , op_feature_msg - > dn ) ;
msg - > elements [ el_count + + ] . flags = LDB_FLAG_MOD_ADD ;
2010-02-15 23:49:26 +11:00
ret = dsdb_module_modify ( module , msg , 0 ) ;
2010-02-12 14:18:27 -02:00
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb ,
" rootdse_enable_recycle_bin: Failed to modify object %s - %s " ,
ldb_dn_get_linearized ( ntds_settings_dn ) , ldb_errstring ( ldb ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-01-30 16:31:19 -05:00
2010-02-12 14:18:27 -02:00
msg - > dn = op_feature_scope_dn ;
2010-02-15 23:49:26 +11:00
ret = dsdb_module_modify ( module , msg , 0 ) ;
2010-02-12 14:18:27 -02:00
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " rootdse_enable_recycle_bin: Failed to modify object %s - %s " ,
ldb_dn_get_linearized ( op_feature_scope_dn ) , ldb_errstring ( ldb ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
return LDB_SUCCESS ;
}
static int rootdse_enableoptionalfeature ( struct ldb_module * module , struct ldb_request * req )
{
2008-07-23 09:59:17 +03:00
/*
2010-02-12 14:18:27 -02:00
steps :
- check for system ( only system can enable features )
- extract GUID from the request
- find the feature object
- check functional level , must be at least msDS - RequiredForestBehaviorVersion
- check if it is already enabled ( if enabled return LDAP_ATTRIBUTE_OR_VALUE_EXISTS ) - probably not needed , just return error from the add / modify
- add / modify objects ( see ntdsconnection code for an example )
*/
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct GUID op_feature_guid ;
struct ldb_dn * op_feature_scope_dn ;
struct ldb_message * op_feature_msg ;
struct auth_session_info * session_info =
( struct auth_session_info * ) ldb_get_opaque ( ldb , " sessionInfo " ) ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
int ret ;
const char * guid_string ;
if ( security_session_user_level ( session_info ) ! = SECURITY_SYSTEM ) {
ldb_asprintf_errstring ( ldb , " rootdse: Insufficient rights for enableoptionalfeature " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
ret = get_optional_feature_dn_guid ( req , ldb , tmp_ctx , & op_feature_scope_dn , & op_feature_guid ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
2008-07-23 09:59:17 +03:00
}
2010-02-12 14:18:27 -02:00
guid_string = GUID_string ( tmp_ctx , & op_feature_guid ) ;
if ( ! guid_string ) {
ldb_asprintf_errstring ( ldb , " rootdse: bad optional feature GUID " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
ret = dsdb_find_optional_feature ( module , ldb , tmp_ctx , op_feature_guid , & op_feature_msg ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " rootdse: unable to find optional feature for %s - %s " ,
guid_string , ldb_errstring ( ldb ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( strcasecmp ( DS_GUID_FEATURE_RECYCLE_BIN , guid_string ) = = 0 ) {
ret = rootdse_enable_recycle_bin ( module , ldb ,
tmp_ctx , op_feature_scope_dn ,
op_feature_msg ) ;
} else {
ldb_asprintf_errstring ( ldb , " rootdse: unknown optional feature %s " ,
guid_string ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb , " rootdse: failed to set optional feature for %s - %s " ,
guid_string , ldb_errstring ( ldb ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
talloc_free ( tmp_ctx ) ;
return ldb_module_done ( req , NULL , NULL , LDB_SUCCESS ) ; ;
}
static int rootdse_schemaupdatenow ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct ldb_result * ext_res ;
int ret ;
struct ldb_dn * schema_dn ;
2009-01-30 16:31:19 -05:00
schema_dn = samdb_schema_dn ( ldb ) ;
2008-07-23 09:59:17 +03:00
if ( ! schema_dn ) {
2009-01-30 16:31:19 -05:00
ldb_reset_err_string ( ldb ) ;
ldb_debug ( ldb , LDB_DEBUG_WARNING ,
2008-07-23 09:59:17 +03:00
" rootdse_modify: no schema dn present: (skip ldb_extended call) \n " ) ;
return ldb_next_request ( module , req ) ;
}
2009-01-30 16:31:19 -05:00
ret = ldb_extended ( ldb , DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID , schema_dn , & ext_res ) ;
2008-07-23 09:59:17 +03:00
if ( ret ! = LDB_SUCCESS ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2010-02-12 14:18:27 -02:00
2008-07-23 09:59:17 +03:00
talloc_free ( ext_res ) ;
2009-10-26 08:38:03 +11:00
return ldb_module_done ( req , NULL , NULL , ret ) ;
2008-07-23 09:59:17 +03:00
}
2010-02-12 14:18:27 -02:00
static int rootdse_modify ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb ;
/*
If dn is not " " we should let it pass through
*/
if ( ! ldb_dn_is_null ( req - > op . mod . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
}
ldb = ldb_module_get_ctx ( module ) ;
/*
dn is empty so check for schemaUpdateNow attribute
" The type of modification and values specified in the LDAP modify operation do not matter. " MSDN
*/
if ( ldb_msg_find_element ( req - > op . mod . message , " schemaUpdateNow " ) ) {
return rootdse_schemaupdatenow ( module , req ) ;
}
if ( ldb_msg_find_element ( req - > op . mod . message , " enableOptionalFeature " ) ) {
return rootdse_enableoptionalfeature ( module , req ) ;
}
return LDB_ERR_OPERATIONS_ERROR ;
}
2008-02-20 04:33:43 +01:00
_PUBLIC_ const struct ldb_module_ops ldb_rootdse_module_ops = {
2009-10-06 19:26:15 +02:00
. name = " rootdse " ,
2008-07-23 09:59:17 +03:00
. init_context = rootdse_init ,
. search = rootdse_search ,
2009-10-06 19:26:15 +02:00
. request = rootdse_request ,
2008-07-23 09:59:17 +03:00
. modify = rootdse_modify
2006-03-02 16:32:53 +00:00
} ;