2009-11-23 20:30:35 +11:00
/*
Samba4 module loading module
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2009
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
* Name : ldb
*
* Component : Samba4 module loading module
*
* Description : Implement a single ' module ' in the ldb database ,
* which loads the remaining modules based on ' choice of configuration ' attributes
*
* This is to avoid forcing a reprovision of the ldb databases when we change the internal structure of the code
*
* Author : Andrew Bartlett
*/
# include "includes.h"
2011-02-10 14:12:51 +11:00
# include <ldb.h>
# include <ldb_errors.h>
# include <ldb_module.h>
2009-11-23 20:30:35 +11:00
# include "dsdb/samdb/ldb_modules/util.h"
# include "dsdb/samdb/samdb.h"
2009-12-18 13:47:46 +11:00
# include "librpc/ndr/libndr.h"
2009-11-23 20:30:35 +11:00
static int read_at_rootdse_record ( struct ldb_context * ldb , struct ldb_module * module , TALLOC_CTX * mem_ctx ,
2011-01-17 13:12:15 +11:00
struct ldb_message * * msg , struct ldb_request * parent )
2009-11-23 20:30:35 +11:00
{
int ret ;
static const char * rootdse_attrs [ ] = { " defaultNamingContext " , " configurationNamingContext " , " schemaNamingContext " , NULL } ;
struct ldb_result * rootdse_res ;
struct ldb_dn * rootdse_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
rootdse_dn = ldb_dn_new ( tmp_ctx , ldb , " @ROOTDSE " ) ;
if ( ! rootdse_dn ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
2010-07-06 03:23:21 +03:00
ret = dsdb_module_search_dn ( module , tmp_ctx , & rootdse_res , rootdse_dn ,
2011-01-17 13:12:15 +11:00
rootdse_attrs , DSDB_FLAG_NEXT_MODULE , parent ) ;
2009-11-23 20:30:35 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
talloc_steal ( mem_ctx , rootdse_res - > msgs ) ;
* msg = rootdse_res - > msgs [ 0 ] ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
static int prepare_modules_line ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
const struct ldb_message * rootdse_msg ,
struct ldb_message * msg , const char * backend_attr ,
const char * backend_mod , const char * * backend_mod_list )
{
int ret ;
const char * * backend_full_list ;
const char * backend_dn ;
char * mod_list_string ;
char * full_string ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
if ( backend_attr ) {
backend_dn = ldb_msg_find_attr_as_string ( rootdse_msg , backend_attr , NULL ) ;
if ( ! backend_dn ) {
ldb_asprintf_errstring ( ldb ,
" samba_dsdb_init: "
" unable to read %s from %s:%s " ,
backend_attr , ldb_dn_get_linearized ( rootdse_msg - > dn ) ,
ldb_errstring ( ldb ) ) ;
return LDB_ERR_CONSTRAINT_VIOLATION ;
}
} else {
backend_dn = " * " ;
}
if ( backend_mod ) {
backend_full_list = ( const char * * ) str_list_make_single ( tmp_ctx , backend_mod ) ;
} else {
backend_full_list = ( const char * * ) str_list_make_empty ( tmp_ctx ) ;
}
if ( ! backend_full_list ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
backend_full_list = str_list_append_const ( backend_full_list , backend_mod_list ) ;
if ( ! backend_full_list ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
mod_list_string = str_list_join ( tmp_ctx , backend_full_list , ' , ' ) ;
if ( ! mod_list_string ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
full_string = talloc_asprintf ( tmp_ctx , " %s:%s " , backend_dn , mod_list_string ) ;
ret = ldb_msg_add_steal_string ( msg , " modules " , full_string ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-12-18 13:47:46 +11:00
2009-11-23 20:30:35 +11:00
static int samba_dsdb_init ( struct ldb_module * module )
{
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
int ret , len , i ;
TALLOC_CTX * tmp_ctx = talloc_new ( module ) ;
struct ldb_result * res ;
struct ldb_message * rootdse_msg , * partition_msg ;
struct ldb_dn * samba_dsdb_dn ;
struct ldb_module * backend_module , * module_chain ;
const char * * final_module_list , * * reverse_module_list ;
/*
Add modules to the list to activate them by default
beware often order is important
Some Known ordering constraints :
- rootdse must be first , as it makes redirects from " " - > cn = rootdse
- extended_dn_in must be before objectclass . c , as it resolves the DN
2010-06-07 14:58:30 +02:00
- objectclass must be before password_hash and samldb since these LDB
modules require the expanded " objectClass " list
- objectclass_attrs must be behind operational in order to see all
2010-06-07 15:02:38 +02:00
attributes ( the operational module protects and therefore
suppresses per default some important ones )
2009-11-23 20:30:35 +11:00
- partition must be last
- each partition has its own module list then
The list is presented here as a set of declarations to show the
stack visually - the code below then handles the creation of the list
based on the parameters loaded from the database .
*/
static const char * modules_list [ ] = { " resolve_oids " ,
" rootdse " ,
" lazy_commit " ,
" paged_results " ,
" ranged_results " ,
" anr " ,
" server_sort " ,
" asq " ,
" extended_dn_store " ,
" extended_dn_in " ,
" objectclass " ,
" descriptor " ,
" acl " ,
2010-12-06 13:53:06 +02:00
" aclread " ,
2009-11-23 20:30:35 +11:00
" samldb " ,
" password_hash " ,
" operational " ,
" schema_load " ,
" instancetype " ,
2010-06-10 11:05:43 +02:00
" objectclass_attrs " ,
2009-11-23 20:30:35 +11:00
NULL } ;
const char * * link_modules ;
2010-04-20 15:35:51 +10:00
static const char * fedora_ds_modules [ ] = {
" rdn_name " , NULL } ;
static const char * openldap_modules [ ] = {
NULL } ;
2009-11-23 20:30:35 +11:00
static const char * tdb_modules_list [ ] = {
2010-04-20 15:35:51 +10:00
" rdn_name " ,
2009-11-23 20:30:35 +11:00
" subtree_delete " ,
2009-12-16 17:14:26 +11:00
" repl_meta_data " ,
" subtree_rename " ,
2009-11-23 20:30:35 +11:00
" linked_attributes " ,
NULL } ;
const char * extended_dn_module ;
const char * extended_dn_module_ldb = " extended_dn_out_ldb " ;
2009-11-24 11:36:34 +11:00
const char * extended_dn_module_fds = " extended_dn_out_fds " ;
const char * extended_dn_module_openldap = " extended_dn_out_openldap " ;
2009-11-23 20:30:35 +11:00
static const char * modules_list2 [ ] = { " show_deleted " ,
" new_partition " ,
" partition " ,
NULL } ;
const char * * backend_modules ;
static const char * fedora_ds_backend_modules [ ] = {
2010-10-19 22:29:04 +11:00
" nsuniqueid " , " paged_searches " , " simple_dn " , NULL } ;
2009-11-23 20:30:35 +11:00
static const char * openldap_backend_modules [ ] = {
2010-10-19 22:29:04 +11:00
" entryuuid " , " paged_searches " , " simple_dn " , NULL } ;
2009-11-23 20:30:35 +11:00
2010-01-07 17:32:13 +11:00
static const char * samba_dsdb_attrs [ ] = { " backendType " , " serverRole " , NULL } ;
2009-11-23 20:30:35 +11:00
const char * backendType , * serverRole ;
if ( ! tmp_ctx ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
2010-12-08 08:22:21 +11:00
ret = ldb_register_samba_handlers ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-11-23 20:30:35 +11:00
samba_dsdb_dn = ldb_dn_new ( tmp_ctx , ldb , " @SAMBA_DSDB " ) ;
if ( ! samba_dsdb_dn ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
# define CHECK_LDB_RET(check_ret) \
do { \
if ( check_ret ! = LDB_SUCCESS ) { \
talloc_free ( tmp_ctx ) ; \
return check_ret ; \
} \
} while ( 0 )
2010-07-06 03:23:21 +03:00
ret = dsdb_module_search_dn ( module , tmp_ctx , & res , samba_dsdb_dn ,
2011-01-17 13:12:15 +11:00
samba_dsdb_attrs , DSDB_FLAG_NEXT_MODULE , NULL ) ;
2009-11-25 18:49:42 +11:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
backendType = " ldb " ;
serverRole = " domain controller " ;
} else if ( ret = = LDB_SUCCESS ) {
backendType = ldb_msg_find_attr_as_string ( res - > msgs [ 0 ] , " backendType " , " ldb " ) ;
serverRole = ldb_msg_find_attr_as_string ( res - > msgs [ 0 ] , " serverRole " , " domain controller " ) ;
} else {
2009-11-23 20:30:35 +11:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
backend_modules = NULL ;
if ( strcasecmp ( backendType , " ldb " ) = = 0 ) {
extended_dn_module = extended_dn_module_ldb ;
link_modules = tdb_modules_list ;
} else {
2009-11-24 11:36:34 +11:00
if ( strcasecmp ( backendType , " fedora-ds " ) = = 0 ) {
2010-04-20 15:35:51 +10:00
link_modules = fedora_ds_modules ;
2009-11-23 20:30:35 +11:00
backend_modules = fedora_ds_backend_modules ;
extended_dn_module = extended_dn_module_fds ;
2009-11-24 11:36:34 +11:00
} else if ( strcasecmp ( backendType , " openldap " ) = = 0 ) {
2010-04-20 15:35:51 +10:00
link_modules = openldap_modules ;
2009-11-23 20:30:35 +11:00
backend_modules = openldap_backend_modules ;
extended_dn_module = extended_dn_module_openldap ;
2010-09-10 20:16:29 +10:00
} else {
return ldb_error ( ldb , LDB_ERR_OPERATIONS_ERROR , " invalid backend type " ) ;
2009-11-23 20:30:35 +11:00
}
2010-07-11 23:07:06 +10:00
ret = ldb_set_opaque ( ldb , " readOnlySchema " , ( void * ) 1 ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_set_errstring ( ldb , " Failed to set readOnlySchema opaque " ) ;
}
2009-11-23 20:30:35 +11:00
}
# define CHECK_MODULE_LIST \
do { \
if ( ! final_module_list ) { \
talloc_free ( tmp_ctx ) ; \
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ; \
2009-11-23 20:30:35 +11:00
} \
} while ( 0 )
final_module_list = str_list_copy_const ( tmp_ctx , modules_list ) ;
CHECK_MODULE_LIST ;
final_module_list = str_list_append_const ( final_module_list , link_modules ) ;
CHECK_MODULE_LIST ;
final_module_list = str_list_add_const ( final_module_list , extended_dn_module ) ;
CHECK_MODULE_LIST ;
final_module_list = str_list_append_const ( final_module_list , modules_list2 ) ;
CHECK_MODULE_LIST ;
2011-01-17 13:12:15 +11:00
ret = read_at_rootdse_record ( ldb , module , tmp_ctx , & rootdse_msg , NULL ) ;
2009-11-23 20:30:35 +11:00
CHECK_LDB_RET ( ret ) ;
partition_msg = ldb_msg_new ( tmp_ctx ) ;
partition_msg - > dn = ldb_dn_new ( partition_msg , ldb , " @ " DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME ) ;
ret = prepare_modules_line ( ldb , tmp_ctx ,
rootdse_msg ,
partition_msg , " defaultNamingContext " ,
" pdc_fsmo " , backend_modules ) ;
CHECK_LDB_RET ( ret ) ;
ret = prepare_modules_line ( ldb , tmp_ctx ,
rootdse_msg ,
partition_msg , " configurationNamingContext " ,
" naming_fsmo " , backend_modules ) ;
CHECK_LDB_RET ( ret ) ;
ret = prepare_modules_line ( ldb , tmp_ctx ,
rootdse_msg ,
partition_msg , " schemaNamingContext " ,
" schema_data " , backend_modules ) ;
CHECK_LDB_RET ( ret ) ;
ret = prepare_modules_line ( ldb , tmp_ctx ,
rootdse_msg ,
partition_msg , NULL ,
NULL , backend_modules ) ;
CHECK_LDB_RET ( ret ) ;
ret = ldb_set_opaque ( ldb , DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME , partition_msg ) ;
CHECK_LDB_RET ( ret ) ;
talloc_steal ( ldb , partition_msg ) ;
/* Now prepare the module chain. Oddly, we must give it to ldb_load_modules_list in REVERSE */
for ( len = 0 ; final_module_list [ len ] ; len + + ) { /* noop */ } ;
reverse_module_list = talloc_array ( tmp_ctx , const char * , len + 1 ) ;
if ( ! reverse_module_list ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-11-23 20:30:35 +11:00
}
for ( i = 0 ; i < len ; i + + ) {
reverse_module_list [ i ] = final_module_list [ ( len - 1 ) - i ] ;
}
reverse_module_list [ i ] = NULL ;
/* The backend (at least until the partitions module
* reconfigures things ) is the next module in the currently
* loaded chain */
2010-11-02 10:41:28 +11:00
backend_module = ldb_module_next ( module ) ;
ret = ldb_module_load_list ( ldb , reverse_module_list , backend_module , & module_chain ) ;
2009-11-23 20:30:35 +11:00
CHECK_LDB_RET ( ret ) ;
talloc_free ( tmp_ctx ) ;
/* Set this as the 'next' module, so that we effectivly append it to module chain */
2010-11-02 10:41:28 +11:00
ldb_module_set_next ( module , module_chain ) ;
2009-11-23 20:30:35 +11:00
return ldb_next_init ( module ) ;
}
2010-11-01 15:28:02 +11:00
static const struct ldb_module_ops ldb_samba_dsdb_module_ops = {
2009-11-23 20:30:35 +11:00
. name = " samba_dsdb " ,
. init_context = samba_dsdb_init ,
} ;
2010-11-01 15:28:02 +11:00
int ldb_samba_dsdb_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_samba_dsdb_module_ops ) ;
}