2010-06-18 21:13:39 +02:00
/*
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
2011-05-22 23:41:56 +04:00
Copyright ( C ) Matthieu Patou < mat @ matws . net > 2011
2010-06-18 21:13:39 +02:00
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 .
2010-06-18 21:13:39 +02:00
2005-11-29 08:50:52 +00: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 .
2010-06-18 21:13:39 +02:00
2005-11-29 08:50:52 +00:00
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"
2011-02-10 14:12:51 +11:00
# include <ldb.h>
# 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"
2010-04-09 17:22:35 +10:00
# include "auth/auth.h"
2010-08-26 11:09:58 +03:00
# include "param/param.h"
# include "lib/messaging/irpc.h"
2010-09-09 16:16:05 +10:00
# include "librpc/gen_ndr/ndr_irpc_c.h"
2013-10-27 06:55:48 +01:00
# include "lib/tsocket/tsocket.h"
# include "cldap_server/cldap_server.h"
2014-04-17 15:39:56 +12:00
# include "lib/events/events.h"
2005-11-29 08:50:52 +00:00
2014-04-17 15:38:14 +12:00
struct rootdse_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 ;
2010-11-25 16:13:17 +11:00
bool block_anonymous ;
2014-04-17 15:39:56 +12:00
struct tevent_context * saved_ev ;
struct tevent_context * private_ev ;
2006-01-06 04:01:23 +00:00
} ;
2013-11-01 06:55:41 +01:00
struct rootdse_context {
struct ldb_module * module ;
struct ldb_request * req ;
2013-10-27 06:55:48 +01:00
struct ldb_val netlogon ;
2013-11-01 06:55:41 +01: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 ;
2011-05-13 13:31:13 +04:00
unsigned int i ;
struct ldb_message_element * el ;
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 ;
}
2011-05-13 13:31:13 +04:00
el = ldb_msg_find_element ( msg , attrname ) ;
if ( ! el | | el - > num_values = = 0 ) {
2010-06-11 10:19:19 +02:00
return LDB_SUCCESS ;
2009-09-20 18:24:23 -07:00
}
2011-05-13 13:31:13 +04:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
v = & el - > values [ i ] ;
if ( v = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
dn_string = talloc_strndup ( tmp_ctx , ( const char * ) v - > data , v - > length ) ;
if ( dn_string = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_operr ( ldb ) ;
}
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( res = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_operr ( ldb ) ;
}
dn = ldb_dn_new ( tmp_ctx , ldb , dn_string ) ;
if ( dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_operr ( ldb ) ;
}
ret = ldb_build_search_req ( & req2 , ldb , tmp_ctx ,
dn ,
LDB_SCOPE_BASE ,
NULL ,
no_attrs ,
NULL ,
res , ldb_search_default_callback ,
req ) ;
LDB_REQ_SET_LOCATION ( req2 ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2014-11-20 14:21:06 +01:00
ret = dsdb_request_add_controls ( req2 , DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_EXTENDED_DN ) ;
2011-05-13 13:31:13 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ldb_error ( ldb , ret , " Failed to add control " ) ;
}
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_operr ( ldb ) ;
}
dn2 = res - > msgs [ 0 ] - > dn ;
v - > data = ( uint8_t * ) ldb_dn_get_extended_linearized ( msg - > elements , dn2 , edn_type ) ;
if ( v - > data = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_operr ( ldb ) ;
}
v - > length = strlen ( ( char * ) v - > data ) ;
2009-09-20 18:24:23 -07:00
}
talloc_free ( tmp_ctx ) ;
2010-06-11 10:19:19 +02:00
return LDB_SUCCESS ;
2010-06-18 21:13:39 +02:00
}
2011-08-11 15:40:53 +10:00
/*
see if we are master for a FSMO role
*/
static int dsdb_module_we_are_master ( struct ldb_module * module , struct ldb_dn * dn , bool * master ,
struct ldb_request * parent )
{
const char * attrs [ ] = { " fSMORoleOwner " , NULL } ;
TALLOC_CTX * tmp_ctx = talloc_new ( parent ) ;
struct ldb_result * res ;
int ret ;
struct ldb_dn * owner_dn ;
ret = dsdb_module_search_dn ( module , tmp_ctx , & res ,
2012-11-12 14:19:34 +01:00
dn , attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_EXTENDED_DN ,
parent ) ;
2011-08-11 15:40:53 +10:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
owner_dn = ldb_msg_find_attr_as_dn ( ldb_module_get_ctx ( module ) ,
tmp_ctx , res - > msgs [ 0 ] , " fSMORoleOwner " ) ;
if ( ! owner_dn ) {
* master = false ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2012-08-14 19:48:32 +10:00
ret = samdb_dn_is_our_ntdsa ( ldb_module_get_ctx ( module ) , dn , master ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) , " Failed to confirm if our ntdsDsa is %s: %s " ,
ldb_dn_get_linearized ( owner_dn ) , ldb_errstring ( ldb_module_get_ctx ( module ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2016-10-26 09:19:13 +13:00
2011-08-11 15:40:53 +10:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-20 18:24:23 -07:00
2005-11-29 08:50:52 +00:00
/*
add dynamically generated attributes to rootDSE result
*/
2013-11-01 06:55:41 +01:00
static int rootdse_add_dynamic ( struct rootdse_context * ac , struct ldb_message * msg )
2005-11-29 08:50:52 +00:00
{
2009-01-30 16:31:19 -05:00
struct ldb_context * ldb ;
2014-04-17 15:38:14 +12:00
struct rootdse_private_data * priv = talloc_get_type ( ldb_module_get_private ( ac - > module ) , struct rootdse_private_data ) ;
2013-11-01 06:55:41 +01:00
const char * const * attrs = ac - > req - > op . search . attrs ;
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 " ,
" rootDomainNamingContext " ,
" schemaNamingContext " ,
" serverName " ,
2011-08-11 15:40:53 +10:00
" validFSMOs " ,
2012-05-09 08:51:57 -07:00
" namingContexts " ,
2009-09-20 18:24:23 -07:00
NULL
} ;
2011-08-11 15:44:32 +10:00
const char * guid_attrs [ ] = {
" dsServiceName " ,
NULL
} ;
unsigned int i ;
2007-01-18 00:49:52 +00:00
2013-11-01 06:55:41 +01:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
2010-03-16 14:52:39 +11:00
schema = dsdb_get_schema ( ldb , NULL ) ;
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
2010-09-19 09:40:13 +02:00
/* don't return the distinguishedName, 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
2010-09-15 18:36:03 +02:00
if ( do_attribute ( attrs , " serverName " ) ) {
if ( ldb_msg_add_linearized_dn ( msg , " serverName " ,
samdb_server_dn ( ldb , msg ) ) ! = LDB_SUCCESS ) {
goto failed ;
}
}
2010-09-18 20:50:25 +02:00
if ( do_attribute ( attrs , " dnsHostName " ) ) {
2011-01-14 15:46:32 +11:00
struct ldb_result * res ;
int ret ;
const char * dns_attrs [ ] = { " dNSHostName " , NULL } ;
2013-11-01 06:55:41 +01:00
ret = dsdb_module_search_dn ( ac - > module , msg , & res , samdb_server_dn ( ldb , msg ) ,
2012-11-12 14:19:34 +01:00
dns_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
2013-11-01 06:55:41 +01:00
ac - > req ) ;
2011-01-14 15:46:32 +11:00
if ( ret = = LDB_SUCCESS ) {
const char * hostname = ldb_msg_find_attr_as_string ( res - > msgs [ 0 ] , " dNSHostName " , NULL ) ;
if ( hostname ! = NULL ) {
2013-09-25 00:49:19 +02:00
if ( ldb_msg_add_string ( msg , " dnsHostName " , hostname ) ) {
2011-01-14 15:46:32 +11:00
goto failed ;
}
}
2010-09-18 20:50:25 +02:00
}
}
2010-09-18 21:44:26 +02:00
if ( do_attribute ( attrs , " ldapServiceName " ) ) {
struct loadparm_context * lp_ctx
= talloc_get_type ( ldb_get_opaque ( ldb , " loadparm " ) ,
struct loadparm_context ) ;
char * ldap_service_name , * hostname ;
2011-05-03 12:16:16 +10:00
hostname = strlower_talloc ( msg , lpcfg_netbios_name ( lp_ctx ) ) ;
2010-09-18 21:44:26 +02:00
if ( hostname = = NULL ) {
goto failed ;
}
ldap_service_name = talloc_asprintf ( msg , " %s:%s$@%s " ,
samdb_forest_name ( ldb , msg ) ,
hostname , lpcfg_realm ( lp_ctx ) ) ;
if ( ldap_service_name = = NULL ) {
goto failed ;
}
if ( ldb_msg_add_string ( msg , " ldapServiceName " ,
ldap_service_name ) ! = LDB_SUCCESS ) {
goto failed ;
}
}
2006-03-14 17:34:00 +00:00
if ( do_attribute ( attrs , " currentTime " ) ) {
2010-06-18 21:13:39 +02:00
if ( ldb_msg_add_steal_string ( msg , " currentTime " ,
2010-09-15 18:21:43 +02:00
ldb_timestring ( msg , time ( NULL ) ) ) ! = LDB_SUCCESS ) {
2005-11-29 08:50:52 +00:00
goto failed ;
}
}
2009-07-14 08:15:50 +10:00
if ( priv & & do_attribute ( attrs , " supportedControl " ) ) {
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 " ,
2010-09-15 18:21:43 +02:00
control ) ! = LDB_SUCCESS ) {
2006-01-06 04:01:23 +00:00
goto failed ;
}
}
}
2009-07-14 08:15:50 +10:00
if ( priv & & do_attribute ( attrs , " namingContexts " ) ) {
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 " ,
2010-09-15 18:21:43 +02:00
ldb_dn_alloc_linearized ( msg , dn ) ) ! = 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
goto failed ;
}
}
}
2010-06-30 13:47:29 +10:00
server_sasl = talloc_get_type ( ldb_get_opaque ( ldb , " supportedSASLMechanisms " ) ,
2006-11-01 03:21:04 +00:00
char * ) ;
if ( server_sasl & & do_attribute ( attrs , " supportedSASLMechanisms " ) ) {
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 " ,
2010-09-15 18:21:43 +02:00
sasl_name ) ! = LDB_SUCCESS ) {
2006-11-01 03:21:04 +00:00
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 ) {
2010-10-14 17:01:39 +02:00
if ( samdb_msg_add_uint64 ( ldb , msg , msg ,
" highestCommittedUSN " ,
seq_num ) ! = LDB_SUCCESS ) {
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 + + ;
}
2010-10-14 17:01:39 +02:00
if ( samdb_msg_add_uint ( ldb , msg , msg , " dsSchemaAttrCount " ,
n ) ! = LDB_SUCCESS ) {
2007-01-18 00:49:52 +00:00
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 + + ;
}
2010-10-14 17:01:39 +02:00
if ( samdb_msg_add_uint ( ldb , msg , msg , " dsSchemaClassCount " ,
n ) ! = LDB_SUCCESS ) {
2007-01-18 00:49:52 +00:00
goto failed ;
}
}
if ( schema & & do_attribute_explicit ( attrs , " dsSchemaPrefixCount " ) ) {
2010-10-14 17:01:39 +02:00
if ( samdb_msg_add_uint ( ldb , msg , msg , " dsSchemaPrefixCount " ,
schema - > prefixmap - > length ) ! = LDB_SUCCESS ) {
2007-01-18 00:49:52 +00:00
goto failed ;
}
}
2007-01-18 01:31:09 +00:00
if ( do_attribute_explicit ( attrs , " validFSMOs " ) ) {
2011-08-11 15:40:53 +10:00
struct ldb_dn * dns [ 3 ] ;
2007-01-18 01:31:09 +00:00
2011-08-11 15:40:53 +10:00
dns [ 0 ] = ldb_get_schema_basedn ( ldb ) ;
dns [ 1 ] = samdb_partitions_dn ( ldb , msg ) ;
dns [ 2 ] = ldb_get_default_basedn ( ldb ) ;
2007-01-18 01:31:09 +00:00
2011-08-11 15:40:53 +10:00
for ( i = 0 ; i < 3 ; i + + ) {
bool master ;
2013-11-01 06:55:41 +01:00
int ret = dsdb_module_we_are_master ( ac - > module , dns [ i ] , & master , ac - > req ) ;
2011-08-11 15:40:53 +10:00
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
if ( master & & ldb_msg_add_fmt ( msg , " validFSMOs " , " %s " ,
ldb_dn_get_linearized ( dns [ i ] ) ) ! = LDB_SUCCESS ) {
goto failed ;
2007-01-18 01:31:09 +00:00
}
}
}
2009-07-14 08:15:50 +10:00
if ( do_attribute_explicit ( attrs , " vendorVersion " ) ) {
2010-06-18 21:13:39 +02:00
if ( ldb_msg_add_fmt ( msg , " vendorVersion " ,
2010-09-15 18:21:43 +02:00
" %s " , SAMBA_VERSION_STRING ) ! = LDB_SUCCESS ) {
2008-04-04 12:25:19 +11:00
goto failed ;
}
}
2010-09-16 14:37:11 +02:00
if ( do_attribute ( attrs , " domainFunctionality " ) ) {
2010-10-24 19:30:12 +02:00
if ( samdb_msg_add_int ( ldb , msg , msg , " domainFunctionality " ,
dsdb_functional_level ( ldb ) ) ! = LDB_SUCCESS ) {
2009-07-14 08:15:50 +10:00
goto failed ;
}
}
2010-09-17 08:49:07 +02:00
if ( do_attribute ( attrs , " forestFunctionality " ) ) {
2010-10-24 19:30:12 +02:00
if ( samdb_msg_add_int ( ldb , msg , msg , " forestFunctionality " ,
dsdb_forest_functional_level ( ldb ) ) ! = LDB_SUCCESS ) {
2009-07-14 08:15:50 +10:00
goto failed ;
}
}
2010-09-16 14:37:11 +02:00
if ( do_attribute ( attrs , " domainControllerFunctionality " )
2009-07-14 08:15:50 +10:00
& & ( val = talloc_get_type ( ldb_get_opaque ( ldb , " domainControllerFunctionality " ) , int ) ) ) {
2010-10-24 19:30:12 +02:00
if ( samdb_msg_add_int ( ldb , msg , msg ,
" domainControllerFunctionality " ,
* val ) ! = LDB_SUCCESS ) {
2009-07-14 08:15:50 +10:00
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 " ,
2010-09-15 18:21:43 +02:00
" %s " , samdb_is_gc ( ldb ) ? " TRUE " : " FALSE " ) ! = LDB_SUCCESS ) {
2010-01-15 19:13:26 +11:00
goto failed ;
}
}
2009-09-20 18:24:23 -07:00
2010-04-15 19:01:17 +02:00
if ( do_attribute_explicit ( attrs , " tokenGroups " ) ) {
2010-04-09 17:22:35 +10:00
/* Obtain the user's session_info */
struct auth_session_info * session_info
2018-05-31 15:12:46 +12:00
= ( struct auth_session_info * ) ldb_get_opaque (
ldb ,
DSDB_SESSION_INFO ) ;
2010-04-09 17:22:35 +10:00
if ( session_info & & session_info - > security_token ) {
/* The list of groups this user is in */
for ( i = 0 ; i < session_info - > security_token - > num_sids ; i + + ) {
if ( samdb_msg_add_dom_sid ( ldb , msg , msg ,
" tokenGroups " ,
2010-09-15 18:21:43 +02:00
& session_info - > security_token - > sids [ i ] ) ! = LDB_SUCCESS ) {
2010-04-09 17:22:35 +10:00
goto failed ;
}
}
}
}
2013-10-27 06:55:48 +01:00
if ( ac - > netlogon . length > 0 ) {
if ( ldb_msg_add_steal_value ( msg , " netlogon " , & ac - > netlogon ) ! = LDB_SUCCESS ) {
goto failed ;
}
}
2005-11-29 08:50:52 +00:00
/* TODO: lots more dynamic attributes should be added here */
2013-11-01 06:55:41 +01:00
edn_control = ldb_request_get_control ( ac - > req , LDB_CONTROL_EXTENDED_DN_OID ) ;
2010-09-15 18:24:53 +02:00
2011-08-11 15:44:32 +10:00
/* convert any GUID attributes to be in the right form */
for ( i = 0 ; guid_attrs [ i ] ; i + + ) {
struct ldb_result * res ;
struct ldb_message_element * el ;
struct ldb_dn * attr_dn ;
const char * no_attrs [ ] = { NULL } ;
int ret ;
if ( ! do_attribute ( attrs , guid_attrs [ i ] ) ) continue ;
2013-11-01 06:55:41 +01:00
attr_dn = ldb_msg_find_attr_as_dn ( ldb , ac - > req , msg , guid_attrs [ i ] ) ;
2011-08-11 15:44:32 +10:00
if ( attr_dn = = NULL ) {
continue ;
}
2013-11-01 06:55:41 +01:00
ret = dsdb_module_search_dn ( ac - > module , ac - > req , & res ,
2011-08-11 15:44:32 +10:00
attr_dn , no_attrs ,
2012-11-12 14:19:34 +01:00
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM |
DSDB_SEARCH_SHOW_EXTENDED_DN ,
2013-11-01 06:55:41 +01:00
ac - > req ) ;
2011-08-11 15:44:32 +10:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_operr ( ldb ) ;
}
el = ldb_msg_find_element ( msg , guid_attrs [ i ] ) ;
if ( el = = NULL ) {
return ldb_operr ( ldb ) ;
}
talloc_steal ( el - > values , res - > msgs [ 0 ] - > dn ) ;
if ( edn_control ) {
struct ldb_extended_dn_control * edn ;
int edn_type = 0 ;
edn = talloc_get_type ( edn_control - > data , struct ldb_extended_dn_control ) ;
if ( edn ! = NULL ) {
edn_type = edn - > type ;
}
el - > values [ 0 ] . data = ( uint8_t * ) ldb_dn_get_extended_linearized ( el - > values ,
res - > msgs [ 0 ] - > dn ,
edn_type ) ;
} else {
el - > values [ 0 ] . data = ( uint8_t * ) talloc_strdup ( el - > values ,
ldb_dn_get_linearized ( res - > msgs [ 0 ] - > dn ) ) ;
}
if ( el - > values [ 0 ] . data = = NULL ) {
return ldb_oom ( ldb ) ;
}
el - > values [ 0 ] . length = strlen ( ( const char * ) el - > values [ 0 ] . data ) ;
}
2010-09-15 18:24:53 +02:00
/* 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 ) {
int ret ;
for ( i = 0 ; dn_attrs [ i ] ; i + + ) {
if ( ! do_attribute ( attrs , dn_attrs [ i ] ) ) continue ;
2013-11-01 06:55:41 +01:00
ret = expand_dn_in_message ( ac - > module , msg , dn_attrs [ i ] ,
edn_control , ac - > req ) ;
2010-09-15 18:24:53 +02:00
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to expand DN in rootDSE for %s \n " ,
dn_attrs [ i ] ) ) ;
goto failed ;
}
}
}
2006-03-14 17:34:00 +00:00
return LDB_SUCCESS ;
2005-11-29 08:50:52 +00:00
failed :
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2005-11-29 08:50:52 +00:00
}
/*
handle search requests
*/
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-03-14 17:34:00 +00:00
/* for each record returned post-process to add any dynamic
attributes that have been asked for */
2013-11-01 06:55:41 +01:00
ret = rootdse_add_dynamic ( ac , ares - > message ) ;
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
}
2010-09-19 16:11:57 -07:00
/*
2010-10-19 11:21:45 +11:00
filter from controls from clients in several ways
1 ) mark our registered controls as non - critical in the request
This is needed as clients may mark controls as critical even if
they are not needed at all in a request . For example , the centrify
client sets the SD_FLAGS control as critical on ldap modify
requests which are setting the dNSHostName attribute on the
machine account . That request doesn ' t need SD_FLAGS at all , but
centrify adds it on all ldap requests .
2 ) if this request is untrusted then remove any non - registered
controls that are non - critical
This is used on ldap : // connections to prevent remote users from
setting an internal control that may be dangerous
3 ) if this request is untrusted then fail any request that includes
a critical non - registered control
2010-09-19 16:11:57 -07:00
*/
2010-10-19 11:21:45 +11:00
static int rootdse_filter_controls ( struct ldb_module * module , struct ldb_request * req )
2010-09-19 16:11:57 -07:00
{
2010-09-20 09:23:37 +02:00
unsigned int i , j ;
2014-04-17 15:38:14 +12:00
struct rootdse_private_data * priv = talloc_get_type ( ldb_module_get_private ( module ) , struct rootdse_private_data ) ;
2010-10-19 11:21:45 +11:00
bool is_untrusted ;
2010-09-19 16:11:57 -07:00
2010-10-19 11:21:45 +11:00
if ( ! req - > controls ) {
return LDB_SUCCESS ;
}
is_untrusted = ldb_req_is_untrusted ( req ) ;
2010-09-19 16:11:57 -07:00
2010-10-19 11:21:45 +11:00
for ( i = 0 ; req - > controls [ i ] ; i + + ) {
bool is_registered = false ;
bool is_critical = ( req - > controls [ i ] - > critical ! = 0 ) ;
if ( req - > controls [ i ] - > oid = = NULL ) {
2010-09-19 16:11:57 -07:00
continue ;
}
2010-10-19 11:21:45 +11:00
if ( is_untrusted | | is_critical ) {
for ( j = 0 ; j < priv - > num_controls ; j + + ) {
if ( strcasecmp ( priv - > controls [ j ] , req - > controls [ i ] - > oid ) = = 0 ) {
is_registered = true ;
break ;
}
2010-09-19 16:11:57 -07:00
}
}
2010-10-19 11:21:45 +11:00
if ( is_untrusted & & ! is_registered ) {
if ( ! is_critical ) {
/* remove it by marking the oid NULL */
req - > controls [ i ] - > oid = NULL ;
req - > controls [ i ] - > data = NULL ;
req - > controls [ i ] - > critical = 0 ;
continue ;
}
/* its a critical unregistered control - give
an error */
ldb_asprintf_errstring ( ldb_module_get_ctx ( module ) ,
" Attempt to use critical non-registered control '%s' " ,
req - > controls [ i ] - > oid ) ;
return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION ;
}
if ( ! is_critical ) {
continue ;
}
2016-03-10 15:25:44 +13:00
/*
* If the control is DIRSYNC , SORT or VLV then we keep the
* critical flag as the modules will need to act upon it .
*
* These modules have to unset the critical flag after the
* request has been seen by the correct module .
2011-02-07 09:58:17 +03:00
*/
2016-03-10 15:25:44 +13:00
if ( is_registered & &
strcmp ( req - > controls [ i ] - > oid ,
LDB_CONTROL_DIRSYNC_OID ) ! = 0 & &
strcmp ( req - > controls [ i ] - > oid ,
LDB_CONTROL_VLV_REQ_OID ) ! = 0 & &
strcmp ( req - > controls [ i ] - > oid ,
LDB_CONTROL_SERVER_SORT_OID ) ! = 0 ) {
2010-10-19 11:21:45 +11:00
req - > controls [ i ] - > critical = 0 ;
}
2010-09-19 16:11:57 -07:00
}
2010-10-19 11:21:45 +11:00
return LDB_SUCCESS ;
2010-09-19 16:11:57 -07:00
}
2010-11-25 16:13:17 +11:00
/* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
static int rootdse_filter_operations ( struct ldb_module * module , struct ldb_request * req )
{
struct auth_session_info * session_info ;
2014-04-17 15:38:14 +12:00
struct rootdse_private_data * priv = talloc_get_type ( ldb_module_get_private ( module ) , struct rootdse_private_data ) ;
2010-11-25 16:13:17 +11:00
bool is_untrusted = ldb_req_is_untrusted ( req ) ;
bool is_anonymous = true ;
if ( is_untrusted = = false ) {
return LDB_SUCCESS ;
}
2018-05-31 15:12:46 +12:00
session_info = ( struct auth_session_info * ) ldb_get_opaque (
ldb_module_get_ctx ( module ) ,
DSDB_SESSION_INFO ) ;
2010-11-25 16:13:17 +11:00
if ( session_info ) {
is_anonymous = security_token_is_anonymous ( session_info - > security_token ) ;
}
2016-10-26 09:19:13 +13:00
2010-11-25 16:13:17 +11:00
if ( is_anonymous = = false | | ( priv & & priv - > block_anonymous = = false ) ) {
return LDB_SUCCESS ;
}
2016-10-26 09:19:13 +13:00
2010-11-25 16:13:17 +11:00
if ( req - > operation = = LDB_SEARCH ) {
if ( req - > op . search . scope = = LDB_SCOPE_BASE & & ldb_dn_is_null ( req - > op . search . base ) ) {
return LDB_SUCCESS ;
}
}
ldb_set_errstring ( ldb_module_get_ctx ( module ) , " Operation unavailable without authentication " ) ;
2010-12-15 21:28:12 +02:00
return LDB_ERR_OPERATIONS_ERROR ;
2010-11-25 16:13:17 +11:00
}
2010-10-19 11:21:45 +11:00
2013-10-27 06:55:48 +01:00
static int rootdse_handle_netlogon ( struct rootdse_context * ac )
{
struct ldb_context * ldb ;
struct ldb_parse_tree * tree ;
struct loadparm_context * lp_ctx ;
struct tsocket_address * src_addr ;
TALLOC_CTX * tmp_ctx = talloc_new ( ac - > req ) ;
const char * domain , * host , * user , * domain_guid ;
char * src_addr_s = NULL ;
struct dom_sid * domain_sid ;
int acct_control = - 1 ;
int version = - 1 ;
NTSTATUS status ;
struct netlogon_samlogon_response netlogon ;
int ret = LDB_ERR_OPERATIONS_ERROR ;
ldb = ldb_module_get_ctx ( ac - > module ) ;
tree = ac - > req - > op . search . tree ;
lp_ctx = talloc_get_type ( ldb_get_opaque ( ldb , " loadparm " ) ,
struct loadparm_context ) ;
src_addr = talloc_get_type ( ldb_get_opaque ( ldb , " remoteAddress " ) ,
struct tsocket_address ) ;
if ( src_addr ) {
src_addr_s = tsocket_address_inet_addr_string ( src_addr ,
tmp_ctx ) ;
}
status = parse_netlogon_request ( tree , lp_ctx , tmp_ctx ,
& domain , & host , & user , & domain_guid ,
& domain_sid , & acct_control , & version ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
status = fill_netlogon_samlogon_response ( ldb , tmp_ctx ,
domain , NULL , domain_sid ,
domain_guid ,
user , acct_control ,
src_addr_s ,
version , lp_ctx ,
& netlogon , false ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
status = push_netlogon_samlogon_response ( & ac - > netlogon , ac , & netlogon ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
ret = LDB_SUCCESS ;
failed :
talloc_free ( tmp_ctx ) ;
return ret ;
}
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 ;
2010-11-25 16:13:17 +11:00
ret = rootdse_filter_operations ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-10-19 11:21:45 +11:00
ret = rootdse_filter_controls ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-09-19 16:11:57 -07:00
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 ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2006-03-14 17:34:00 +00:00
}
2013-10-27 06:55:48 +01:00
if ( do_attribute_explicit ( req - > op . search . attrs , " netlogon " ) ) {
ret = rootdse_handle_netlogon ( ac ) ;
2015-07-26 23:02:57 +02:00
/* We have to return an empty result, so don't forward `ret' */
2013-10-27 06:55:48 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , LDB_SUCCESS ) ;
}
}
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 ) ;
2010-09-24 12:50:13 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2008-09-11 18:36:28 -04:00
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
}
2018-04-10 07:58:07 +12:00
static struct rootdse_private_data * rootdse_get_private_data ( struct ldb_module * module )
{
void * priv = ldb_module_get_private ( module ) ;
struct rootdse_private_data * data = NULL ;
2018-04-10 07:54:20 +12:00
struct ldb_context * ldb
= ldb_module_get_ctx ( module ) ;
2018-04-10 07:58:07 +12:00
if ( priv ! = NULL ) {
data = talloc_get_type_abort ( priv ,
struct rootdse_private_data ) ;
}
if ( data ! = NULL ) {
return data ;
}
data = talloc_zero ( module , struct rootdse_private_data ) ;
if ( data = = NULL ) {
return NULL ;
}
data - > num_controls = 0 ;
data - > controls = NULL ;
data - > num_partitions = 0 ;
data - > partitions = NULL ;
data - > block_anonymous = true ;
ldb_module_set_private ( module , data ) ;
2018-04-10 07:54:20 +12:00
ldb_set_default_dns ( ldb ) ;
2018-04-10 07:58:07 +12:00
return data ;
}
2006-01-06 04:01:23 +00:00
static int rootdse_register_control ( struct ldb_module * module , struct ldb_request * req )
{
2018-04-10 07:58:07 +12:00
struct rootdse_private_data * priv =
rootdse_get_private_data ( module ) ;
2006-01-06 04:01:23 +00:00
char * * list ;
2018-04-10 07:58:07 +12:00
if ( priv = = NULL ) {
return ldb_module_oom ( module ) ;
}
2006-01-06 04:01:23 +00:00
list = talloc_realloc ( priv , priv - > controls , char * , priv - > num_controls + 1 ) ;
if ( ! list ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb_module_get_ctx ( module ) ) ;
2006-01-06 04:01:23 +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
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 ] ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb_module_get_ctx ( module ) ) ;
2006-01-06 04:01:23 +00:00
}
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 )
{
2018-04-10 07:58:07 +12:00
struct rootdse_private_data * priv =
rootdse_get_private_data ( module ) ;
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 ;
2018-04-10 07:58:07 +12:00
if ( priv = = NULL ) {
return ldb_module_oom ( module ) ;
}
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 = talloc_realloc ( priv , priv - > partitions , struct ldb_dn * , priv - > num_partitions + 1 ) ;
if ( ! list ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb_module_get_ctx ( module ) ) ;
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
}
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 ] ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb_module_get_ctx ( module ) ) ;
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
}
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 ;
struct ldb_result * res ;
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
2018-04-10 07:58:07 +12:00
struct ldb_context * ldb
= ldb_module_get_ctx ( module ) ;
struct rootdse_private_data * data
= rootdse_get_private_data ( module ) ;
2009-01-30 16:31:19 -05:00
2006-01-06 04:01:23 +00:00
if ( data = = NULL ) {
2018-04-10 07:58:07 +12:00
return ldb_module_oom ( module ) ;
2006-01-06 04:01:23 +00:00
}
2009-07-14 08:15:50 +10:00
ret = ldb_next_init ( module ) ;
2010-06-11 10:19:19 +02:00
if ( ret ! = LDB_SUCCESS ) {
2009-07-14 08:15:50 +10:00
return ret ;
}
mem_ctx = talloc_new ( data ) ;
if ( ! mem_ctx ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-07-14 08:15:50 +10:00
}
/* Now that the partitions are set up, do a search for:
- domainControllerFunctionality
- domainFunctionality
- forestFunctionality
Then stuff these values into an opaque
*/
2011-01-17 13:39:46 +11:00
ret = dsdb_module_search ( module , mem_ctx , & res ,
ldb_get_default_basedn ( ldb ) ,
2012-11-12 14:19:34 +01:00
LDB_SCOPE_BASE , attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
NULL , NULL ) ;
2009-07-14 08:15:50 +10:00
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
int domain_behaviour_version
2010-06-18 21:13:39 +02:00
= ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] ,
2009-07-14 08:15:50 +10:00
" msDS-Behavior-Version " , - 1 ) ;
if ( domain_behaviour_version ! = - 1 ) {
int * val = talloc ( ldb , int ) ;
if ( ! val ) {
talloc_free ( mem_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-07-14 08:15:50 +10:00
}
* val = domain_behaviour_version ;
ret = ldb_set_opaque ( ldb , " domainFunctionality " , val ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
}
2011-01-17 13:39:46 +11:00
ret = dsdb_module_search ( module , mem_ctx , & res ,
samdb_partitions_dn ( ldb , mem_ctx ) ,
2012-11-12 14:19:34 +01:00
LDB_SCOPE_BASE , attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
NULL , NULL ) ;
2009-07-14 08:15:50 +10:00
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
int forest_behaviour_version
2010-06-18 21:13:39 +02:00
= ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] ,
2009-07-14 08:15:50 +10:00
" msDS-Behavior-Version " , - 1 ) ;
if ( forest_behaviour_version ! = - 1 ) {
int * val = talloc ( ldb , int ) ;
if ( ! val ) {
talloc_free ( mem_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-07-14 08:15:50 +10:00
}
* val = forest_behaviour_version ;
ret = ldb_set_opaque ( ldb , " forestFunctionality " , val ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
}
2011-02-02 14:01:35 +11:00
/* For now, our own server's location in the DB is recorded in
* the @ ROOTDSE record */
2011-01-17 13:39:46 +11:00
ret = dsdb_module_search ( module , mem_ctx , & res ,
2011-02-02 14:01:35 +11:00
ldb_dn_new ( mem_ctx , ldb , " @ROOTDSE " ) ,
2012-11-12 14:19:34 +01:00
LDB_SCOPE_BASE , ds_attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
NULL , NULL ) ;
2009-07-14 08:15:50 +10:00
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
struct ldb_dn * ds_dn
2010-06-18 21:13:39 +02:00
= ldb_msg_find_attr_as_dn ( ldb , mem_ctx , res - > msgs [ 0 ] ,
2009-07-14 08:15:50 +10:00
" dsServiceName " ) ;
if ( ds_dn ) {
2011-01-17 13:39:46 +11:00
ret = dsdb_module_search ( module , mem_ctx , & res , ds_dn ,
2012-11-12 14:19:34 +01:00
LDB_SCOPE_BASE , attrs ,
DSDB_FLAG_NEXT_MODULE |
DSDB_FLAG_AS_SYSTEM ,
NULL , NULL ) ;
2009-07-14 08:15:50 +10:00
if ( ret = = LDB_SUCCESS & & res - > count = = 1 ) {
int domain_controller_behaviour_version
2010-06-18 21:13:39 +02:00
= ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] ,
2009-07-14 08:15:50 +10:00
" msDS-Behavior-Version " , - 1 ) ;
if ( domain_controller_behaviour_version ! = - 1 ) {
int * val = talloc ( ldb , int ) ;
if ( ! val ) {
talloc_free ( mem_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-07-14 08:15:50 +10:00
}
* val = domain_controller_behaviour_version ;
2010-06-18 21:13:39 +02:00
ret = ldb_set_opaque ( ldb ,
2009-07-14 08:15:50 +10:00
" domainControllerFunctionality " , val ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
}
}
}
2011-01-17 13:12:15 +11:00
data - > block_anonymous = dsdb_block_anonymous_ops ( module , NULL ) ;
2010-11-25 16:13:17 +11:00
2009-07-14 08:15:50 +10:00
talloc_free ( mem_ctx ) ;
2010-06-18 21:13:39 +02:00
2009-07-14 08:15:50 +10:00
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 ) {
2010-06-18 20:52:33 +02:00
ldb_set_errstring ( ldb ,
" rootdse: unable to find 'enableOptionalFeature'! " ) ;
2010-02-12 14:18:27 -02:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
guid = strchr ( ldb_val_str , ' : ' ) ;
if ( ! guid ) {
2010-06-18 20:52:33 +02:00
ldb_set_errstring ( ldb ,
" rootdse: unable to find GUID in 'enableOptionalFeature'! " ) ;
2010-02-12 14:18:27 -02:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
status = GUID_from_string ( guid + 1 , op_feature_guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-06-18 20:52:33 +02:00
ldb_set_errstring ( ldb ,
" rootdse: bad GUID in 'enableOptionalFeature'! " ) ;
2010-02-12 14:18:27 -02:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
dn = talloc_strndup ( tmp_ctx , ldb_val_str , guid - ldb_val_str ) ;
if ( ! dn ) {
2010-06-18 20:52:33 +02:00
ldb_set_errstring ( ldb ,
" rootdse: bad DN in 'enableOptionalFeature'! " ) ;
2010-02-12 14:18:27 -02:00
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 ,
2011-01-17 13:12:15 +11:00
TALLOC_CTX * mem_ctx , struct GUID op_feature_guid , struct ldb_message * * msg ,
struct ldb_request * parent )
2010-02-12 14:18:27 -02:00
{
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 ,
2011-01-17 13:12:15 +11:00
NULL ,
DSDB_FLAG_NEXT_MODULE |
2012-11-12 14:19:34 +01:00
DSDB_FLAG_AS_SYSTEM |
2011-01-17 13:12:15 +11:00
DSDB_SEARCH_SEARCH_ALL_PARTITIONS ,
parent ,
2010-02-12 14:18:27 -02:00
" (&(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 ,
2010-06-18 20:52:33 +02:00
" More than one object found matching optional feature GUID %s \n " ,
GUID_string ( tmp_ctx , & op_feature_guid ) ) ;
2010-02-12 14:18:27 -02:00
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 ,
2011-01-17 13:12:15 +11:00
TALLOC_CTX * mem_ctx , struct ldb_dn * op_feature_scope_dn ,
struct ldb_message * op_feature_msg , struct ldb_request * parent )
2010-02-12 14:18:27 -02:00
{
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 ,
2010-06-18 20:52:33 +02:00
" rootdse_enable_recycle_bin: Domain functional level must be at least %d \n " ,
ret ) ;
2010-02-12 14:18:27 -02:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
tmp_ctx = talloc_new ( mem_ctx ) ;
2012-08-14 16:08:47 +10:00
ntds_settings_dn = samdb_ntds_settings_dn ( ldb , tmp_ctx ) ;
2010-02-12 14:18:27 -02:00
if ( ! ntds_settings_dn ) {
talloc_free ( tmp_ctx ) ;
2011-03-18 15:02:35 +11:00
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR , " Failed to find NTDS settings DN " ) ;
2010-02-12 14:18:27 -02:00
}
ntds_settings_dn = ldb_dn_copy ( tmp_ctx , ntds_settings_dn ) ;
if ( ! ntds_settings_dn ) {
talloc_free ( tmp_ctx ) ;
2011-03-18 15:02:35 +11:00
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR , " Failed to copy NTDS settings DN " ) ;
2010-02-12 14:18:27 -02:00
}
msg = ldb_msg_new ( tmp_ctx ) ;
2015-06-23 14:46:12 +02:00
if ( msg = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_module_oom ( module ) ;
}
2010-02-12 14:18:27 -02:00
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 ;
2011-01-17 13:12:15 +11:00
ret = dsdb_module_modify ( module , msg , DSDB_FLAG_NEXT_MODULE , parent ) ;
2010-02-12 14:18:27 -02:00
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb ,
2010-06-18 20:52:33 +02:00
" rootdse_enable_recycle_bin: Failed to modify object %s - %s " ,
ldb_dn_get_linearized ( ntds_settings_dn ) ,
ldb_errstring ( ldb ) ) ;
2010-02-12 14:18:27 -02:00
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 ;
2011-01-17 13:12:15 +11:00
ret = dsdb_module_modify ( module , msg , DSDB_FLAG_NEXT_MODULE , parent ) ;
2010-02-12 14:18:27 -02:00
if ( ret ! = LDB_SUCCESS ) {
2010-06-18 20:52:33 +02:00
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 ) ) ;
2010-02-12 14:18:27 -02:00
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 =
2018-05-31 15:12:46 +12:00
( struct auth_session_info * ) ldb_get_opaque (
ldb ,
DSDB_SESSION_INFO ) ;
2010-02-12 14:18:27 -02:00
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
int ret ;
const char * guid_string ;
2010-04-22 16:48:01 +10:00
if ( security_session_user_level ( session_info , NULL ) ! = SECURITY_SYSTEM ) {
2010-06-18 20:52:33 +02:00
ldb_set_errstring ( ldb , " rootdse: Insufficient rights for enableoptionalfeature " ) ;
2010-02-12 14:18:27 -02:00
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 ) {
2010-06-18 20:52:33 +02:00
ldb_set_errstring ( ldb , " rootdse: bad optional feature GUID " ) ;
2010-02-12 14:18:27 -02:00
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
2011-01-17 13:12:15 +11:00
ret = dsdb_find_optional_feature ( module , ldb , tmp_ctx , op_feature_guid , & op_feature_msg , req ) ;
2010-02-12 14:18:27 -02:00
if ( ret ! = LDB_SUCCESS ) {
2010-06-18 20:52:33 +02:00
ldb_asprintf_errstring ( ldb ,
" rootdse: unable to find optional feature for %s - %s " ,
guid_string , ldb_errstring ( ldb ) ) ;
2010-02-12 14:18:27 -02:00
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 ,
2011-01-17 13:12:15 +11:00
op_feature_msg , req ) ;
2010-02-12 14:18:27 -02:00
} else {
2010-06-18 20:52:33 +02:00
ldb_asprintf_errstring ( ldb ,
" rootdse: unknown optional feature %s " ,
2010-02-12 14:18:27 -02:00
guid_string ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
if ( ret ! = LDB_SUCCESS ) {
2010-06-18 20:52:33 +02:00
ldb_asprintf_errstring ( ldb ,
" rootdse: failed to set optional feature for %s - %s " ,
2010-02-12 14:18:27 -02:00
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 ;
2010-04-13 08:41:10 +02:00
schema_dn = ldb_get_schema_basedn ( 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 ) ;
}
2017-08-18 13:59:30 +12:00
/*
* schemaUpdateNow has been requested . Allow this to refresh the schema
* even if we ' re currently in the middle of a transaction
*/
ret = ldb_set_opaque ( ldb , " dsdb_schema_refresh_expected " , ( void * ) 1 ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_operr ( ldb ) ;
}
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 ) {
2017-08-18 13:59:30 +12:00
ldb_set_opaque ( ldb , " dsdb_schema_refresh_expected " , ( void * ) 0 ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2008-07-23 09:59:17 +03:00
}
2010-02-12 14:18:27 -02:00
2008-07-23 09:59:17 +03:00
talloc_free ( ext_res ) ;
2017-08-18 13:59:30 +12:00
ret = ldb_set_opaque ( ldb , " dsdb_schema_refresh_expected " , ( void * ) 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_operr ( ldb ) ;
}
2009-10-26 08:38:03 +11:00
return ldb_module_done ( req , NULL , NULL , ret ) ;
2008-07-23 09:59:17 +03:00
}
2012-04-06 02:20:37 +02:00
static int rootdse_schemaupgradeinprogress ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
int ret = LDB_SUCCESS ;
struct ldb_dn * schema_dn ;
schema_dn = ldb_get_schema_basedn ( ldb ) ;
if ( ! schema_dn ) {
ldb_reset_err_string ( ldb ) ;
ldb_debug ( ldb , LDB_DEBUG_WARNING ,
" rootdse_modify: no schema dn present: (skip ldb_extended call) \n " ) ;
return ldb_next_request ( module , req ) ;
}
/* FIXME we have to do something in order to relax constraints for DRS
* setting schemaUpgradeInProgress cause the fschemaUpgradeInProgress
* in all LDAP connection ( 2 K3 / 2 K3R2 ) or in the current connection ( 2 K8 and + )
* to be set to true .
*/
/* from 5.113 LDAPConnections in DRSR.pdf
* fschemaUpgradeInProgress : A Boolean that specifies certain constraint
* validations are skipped when adding , updating , or removing directory
* objects on the opened connection . The skipped constraint validations
* are documented in the applicable constraint sections in [ MS - ADTS ] .
*/
return ldb_module_done ( req , NULL , NULL , ret ) ;
}
2010-06-18 21:10:19 +02:00
static int rootdse_add ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2010-10-19 11:21:45 +11:00
int ret ;
2010-06-18 21:10:19 +02:00
2010-11-25 16:13:17 +11:00
ret = rootdse_filter_operations ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-10-19 11:21:45 +11:00
ret = rootdse_filter_controls ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-09-19 16:11:57 -07:00
2010-06-18 21:10:19 +02:00
/*
If dn is not " " we should let it pass through
*/
if ( ! ldb_dn_is_null ( req - > op . add . message - > dn ) ) {
return ldb_next_request ( module , req ) ;
}
ldb_set_errstring ( ldb , " rootdse_add: you cannot add a new rootdse entry! " ) ;
return LDB_ERR_NAMING_VIOLATION ;
}
2014-04-17 15:39:56 +12:00
static int rootdse_start_trans ( struct ldb_module * module )
{
int ret ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct rootdse_private_data * data = talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct rootdse_private_data ) ;
ret = ldb_next_start_trans ( module ) ;
if ( ret = = LDB_SUCCESS ) {
if ( data - > private_ev ! = NULL ) {
return ldb_operr ( ldb ) ;
}
data - > private_ev = s4_event_context_init ( data ) ;
if ( data - > private_ev = = NULL ) {
return ldb_operr ( ldb ) ;
}
data - > saved_ev = ldb_get_event_context ( ldb ) ;
ldb_set_event_context ( ldb , data - > private_ev ) ;
}
return ret ;
}
static int rootdse_end_trans ( struct ldb_module * module )
{
int ret ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct rootdse_private_data * data = talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct rootdse_private_data ) ;
ret = ldb_next_end_trans ( module ) ;
if ( data - > saved_ev = = NULL ) {
return ldb_operr ( ldb ) ;
}
if ( data - > private_ev ! = ldb_get_event_context ( ldb ) ) {
return ldb_operr ( ldb ) ;
}
ldb_set_event_context ( ldb , data - > saved_ev ) ;
data - > saved_ev = NULL ;
TALLOC_FREE ( data - > private_ev ) ;
return ret ;
}
static int rootdse_del_trans ( struct ldb_module * module )
{
int ret ;
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct rootdse_private_data * data = talloc_get_type_abort ( ldb_module_get_private ( module ) ,
struct rootdse_private_data ) ;
ret = ldb_next_del_trans ( module ) ;
if ( data - > saved_ev = = NULL ) {
return ldb_operr ( ldb ) ;
}
if ( data - > private_ev ! = ldb_get_event_context ( ldb ) ) {
return ldb_operr ( ldb ) ;
}
ldb_set_event_context ( ldb , data - > saved_ev ) ;
data - > saved_ev = NULL ;
TALLOC_FREE ( data - > private_ev ) ;
return ret ;
}
2011-03-28 16:20:47 +11:00
struct fsmo_transfer_state {
struct ldb_context * ldb ;
struct ldb_request * req ;
2013-01-15 09:56:46 +11:00
struct ldb_module * module ;
2011-03-28 16:20:47 +11:00
} ;
/*
called when a FSMO transfer operation has completed
*/
static void rootdse_fsmo_transfer_callback ( struct tevent_req * treq )
{
struct fsmo_transfer_state * fsmo = tevent_req_callback_data ( treq , struct fsmo_transfer_state ) ;
NTSTATUS status ;
WERROR werr ;
2013-01-15 09:56:46 +11:00
int ret ;
2011-03-28 16:20:47 +11:00
struct ldb_request * req = fsmo - > req ;
struct ldb_context * ldb = fsmo - > ldb ;
2013-11-12 14:09:56 +01:00
struct ldb_module * module = fsmo - > module ;
2011-03-28 16:20:47 +11:00
status = dcerpc_drepl_takeFSMORole_recv ( treq , fsmo , & werr ) ;
talloc_free ( fsmo ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldb_asprintf_errstring ( ldb , " Failed FSMO transfer: %s " , nt_errstr ( status ) ) ;
2013-01-15 09:56:46 +11:00
/*
* Now that it is failed , start the transaction up
* again so the wrappers can close it without additional error
*/
2014-04-17 15:39:56 +12:00
rootdse_start_trans ( module ) ;
2011-03-28 16:20:47 +11:00
ldb_module_done ( req , NULL , NULL , LDB_ERR_UNAVAILABLE ) ;
return ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
ldb_asprintf_errstring ( ldb , " Failed FSMO transfer: %s " , win_errstr ( werr ) ) ;
2013-01-15 09:56:46 +11:00
/*
* Now that it is failed , start the transaction up
* again so the wrappers can close it without additional error
*/
2014-04-17 15:39:56 +12:00
rootdse_start_trans ( module ) ;
2011-03-28 16:20:47 +11:00
ldb_module_done ( req , NULL , NULL , LDB_ERR_UNAVAILABLE ) ;
return ;
}
2013-01-15 09:56:46 +11:00
/*
* Now that it is done , start the transaction up again so the
* wrappers can close it without error
*/
2014-04-17 15:39:56 +12:00
ret = rootdse_start_trans ( module ) ;
2013-01-15 09:56:46 +11:00
ldb_module_done ( req , NULL , NULL , ret ) ;
2011-03-28 16:20:47 +11:00
}
2010-08-26 11:09:58 +03:00
static int rootdse_become_master ( struct ldb_module * module ,
struct ldb_request * req ,
2010-11-27 14:40:53 +01:00
enum drepl_role_master role )
2010-08-26 11:09:58 +03:00
{
2011-05-03 10:40:33 +10:00
struct imessaging_context * msg ;
2010-08-26 11:09:58 +03:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
TALLOC_CTX * tmp_ctx = talloc_new ( req ) ;
struct loadparm_context * lp_ctx = ldb_get_opaque ( ldb , " loadparm " ) ;
2010-09-28 19:35:56 -07:00
bool am_rodc ;
2010-09-09 16:16:05 +10:00
struct dcerpc_binding_handle * irpc_handle ;
2010-09-28 19:35:56 -07:00
int ret ;
2011-03-28 14:41:36 +11:00
struct auth_session_info * session_info ;
enum security_user_level level ;
2011-03-28 16:20:47 +11:00
struct fsmo_transfer_state * fsmo ;
struct tevent_req * treq ;
2011-03-28 14:41:36 +11:00
2018-05-31 15:12:46 +12:00
session_info = ( struct auth_session_info * ) ldb_get_opaque (
ldb_module_get_ctx ( module ) ,
DSDB_SESSION_INFO ) ;
2011-03-28 14:41:36 +11:00
level = security_session_user_level ( session_info , NULL ) ;
if ( level < SECURITY_ADMINISTRATOR ) {
return ldb_error ( ldb , LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS , " Denied rootDSE modify for non-administrator " ) ;
}
2010-09-28 19:35:56 -07:00
ret = samdb_rodc ( ldb , & am_rodc ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_error ( ldb , ret , " Could not determine if server is RODC. " ) ;
}
if ( am_rodc ) {
return ldb_error ( ldb , LDB_ERR_UNWILLING_TO_PERFORM ,
" RODC cannot become a role master. " ) ;
}
2010-08-26 11:09:58 +03:00
2013-01-15 09:56:46 +11:00
/*
* We always delete the transaction , not commit it , because
2016-10-20 16:20:49 +13:00
* this gives the least surprise to this surprising action ( as
2013-01-15 09:56:46 +11:00
* we will never record anything done to this point
*/
2014-04-17 15:39:56 +12:00
rootdse_del_trans ( module ) ;
2013-01-15 09:56:46 +11:00
2017-05-12 01:55:45 +02:00
/*
* We must use the global event loop to run this IRPC in
* single process mode
*/
ldb_handle_use_global_event_context ( req - > handle ) ;
2011-10-13 20:01:56 +11:00
msg = imessaging_client_init ( tmp_ctx , lp_ctx ,
2010-08-26 11:09:58 +03:00
ldb_get_event_context ( ldb ) ) ;
2010-09-27 14:43:33 +10:00
if ( ! msg ) {
2011-05-03 10:40:33 +10:00
ldb_asprintf_errstring ( ldb , " Failed to generate client messaging context in %s " , lpcfg_imessaging_path ( tmp_ctx , lp_ctx ) ) ;
2010-09-27 14:43:33 +10:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2010-09-09 16:16:05 +10:00
irpc_handle = irpc_binding_handle_by_name ( tmp_ctx , msg ,
" dreplsrv " ,
& ndr_table_irpc ) ;
if ( irpc_handle = = NULL ) {
return ldb_oom ( ldb ) ;
}
2011-03-28 16:20:47 +11:00
fsmo = talloc_zero ( req , struct fsmo_transfer_state ) ;
if ( fsmo = = NULL ) {
return ldb_oom ( ldb ) ;
2010-08-26 11:09:58 +03:00
}
2011-03-28 16:20:47 +11:00
fsmo - > ldb = ldb ;
fsmo - > req = req ;
2013-01-15 09:56:46 +11:00
fsmo - > module = module ;
2011-03-28 16:20:47 +11:00
2012-11-20 14:59:17 +11:00
/*
* we send the call asynchronously , as the ldap client is
2011-03-28 16:20:47 +11:00
* expecting to get an error back if the role transfer fails
2012-11-20 14:59:17 +11:00
*
* We need more than the default 10 seconds IRPC allows , so
* set a longer timeout ( default ldb timeout is 300 seconds ) .
* We send an async reply when we are done .
*
* We are the first module , so don ' t bother working out how
* long we have spent so far .
2011-03-28 16:20:47 +11:00
*/
2012-11-20 14:59:17 +11:00
dcerpc_binding_handle_set_timeout ( irpc_handle , req - > timeout ) ;
2011-03-28 16:20:47 +11:00
treq = dcerpc_drepl_takeFSMORole_send ( req , ldb_get_event_context ( ldb ) , irpc_handle , role ) ;
if ( treq = = NULL ) {
return ldb_oom ( ldb ) ;
2010-08-26 11:09:58 +03:00
}
2011-03-28 16:20:47 +11:00
tevent_req_set_callback ( treq , rootdse_fsmo_transfer_callback , fsmo ) ;
return LDB_SUCCESS ;
2010-08-26 11:09:58 +03:00
}
2010-02-12 14:18:27 -02:00
static int rootdse_modify ( struct ldb_module * module , struct ldb_request * req )
{
2010-06-18 21:10:19 +02:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2010-10-19 11:21:45 +11:00
int ret ;
2010-02-12 14:18:27 -02:00
2010-11-25 16:13:17 +11:00
ret = rootdse_filter_operations ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-10-19 11:21:45 +11:00
ret = rootdse_filter_controls ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-09-19 16:11:57 -07:00
2010-02-12 14:18:27 -02:00
/*
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 ) ;
}
/*
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 ) ;
}
2010-08-26 11:09:58 +03:00
if ( ldb_msg_find_element ( req - > op . mod . message , " becomeDomainMaster " ) ) {
return rootdse_become_master ( module , req , DREPL_NAMING_MASTER ) ;
}
if ( ldb_msg_find_element ( req - > op . mod . message , " becomeInfrastructureMaster " ) ) {
return rootdse_become_master ( module , req , DREPL_INFRASTRUCTURE_MASTER ) ;
}
if ( ldb_msg_find_element ( req - > op . mod . message , " becomeRidMaster " ) ) {
return rootdse_become_master ( module , req , DREPL_RID_MASTER ) ;
}
if ( ldb_msg_find_element ( req - > op . mod . message , " becomeSchemaMaster " ) ) {
return rootdse_become_master ( module , req , DREPL_SCHEMA_MASTER ) ;
}
if ( ldb_msg_find_element ( req - > op . mod . message , " becomePdc " ) ) {
return rootdse_become_master ( module , req , DREPL_PDC_MASTER ) ;
}
2010-02-12 14:18:27 -02:00
if ( ldb_msg_find_element ( req - > op . mod . message , " enableOptionalFeature " ) ) {
return rootdse_enableoptionalfeature ( module , req ) ;
}
2012-04-06 02:20:37 +02:00
if ( ldb_msg_find_element ( req - > op . mod . message , " schemaUpgradeInProgress " ) ) {
return rootdse_schemaupgradeinprogress ( module , req ) ;
}
2010-02-12 14:18:27 -02:00
2010-06-18 20:53:25 +02:00
ldb_set_errstring ( ldb , " rootdse_modify: unknown attribute to change! " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
2010-02-12 14:18:27 -02:00
}
2010-11-25 16:13:17 +11:00
static int rootdse_rename ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
int ret ;
ret = rootdse_filter_operations ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = rootdse_filter_controls ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
/*
If dn is not " " we should let it pass through
*/
if ( ! ldb_dn_is_null ( req - > op . rename . olddn ) ) {
return ldb_next_request ( module , req ) ;
}
ldb_set_errstring ( ldb , " rootdse_remove: you cannot rename the rootdse entry! " ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2010-06-18 21:10:19 +02:00
static int rootdse_delete ( struct ldb_module * module , struct ldb_request * req )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2010-10-19 11:21:45 +11:00
int ret ;
2010-06-18 21:10:19 +02:00
2010-11-25 16:13:17 +11:00
ret = rootdse_filter_operations ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-10-19 11:21:45 +11:00
ret = rootdse_filter_controls ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-09-19 16:11:57 -07:00
2010-06-18 21:10:19 +02:00
/*
If dn is not " " we should let it pass through
*/
if ( ! ldb_dn_is_null ( req - > op . del . dn ) ) {
return ldb_next_request ( module , req ) ;
}
ldb_set_errstring ( ldb , " rootdse_remove: you cannot delete the rootdse entry! " ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2010-11-25 16:13:17 +11:00
static int rootdse_extended ( struct ldb_module * module , struct ldb_request * req )
{
int ret ;
ret = rootdse_filter_operations ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = rootdse_filter_controls ( module , req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return ldb_next_request ( module , req ) ;
}
2010-11-01 15:28:02 +11:00
static const struct ldb_module_ops ldb_rootdse_module_ops = {
2014-04-17 15:39:56 +12:00
. name = " rootdse " ,
. init_context = rootdse_init ,
. search = rootdse_search ,
. request = rootdse_request ,
. add = rootdse_add ,
. modify = rootdse_modify ,
. rename = rootdse_rename ,
. extended = rootdse_extended ,
. del = rootdse_delete ,
. start_transaction = rootdse_start_trans ,
. end_transaction = rootdse_end_trans ,
. del_transaction = rootdse_del_trans
2006-03-02 16:32:53 +00:00
} ;
2010-11-01 15:28:02 +11:00
int ldb_rootdse_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_rootdse_module_ops ) ;
}