2011-09-09 15:24:49 +04:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright ( C ) Jelmer Vernooij 2002 - 2003 , 2005 - 2007
Copyright ( C ) Stefan ( metze ) Metzmacher 2003
Copyright ( C ) Andrew Bartlett 2011
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/>.
*/
# include "includes.h"
# include "dynconfig/dynconfig.h"
2011-12-03 10:03:35 +04:00
# include "lib/util/samba_modules.h"
2017-06-22 17:10:52 +03:00
# include "lib/util/util_paths.h"
2011-09-09 15:24:49 +04:00
# include "system/filesys.h"
# include "system/dir.h"
/**
* Obtain the init function from a shared library file
*/
2011-12-03 10:03:35 +04:00
init_module_fn load_module ( const char * path , bool is_probe , void * * handle_out )
2011-09-09 15:24:49 +04:00
{
void * handle ;
void * init_fn ;
2011-09-09 16:41:28 +04:00
char * error ;
2011-09-09 15:24:49 +04:00
2011-09-09 16:41:28 +04:00
/* This should be a WAF build, where modules should be built
* with no undefined symbols and are already linked against
* the libraries that they are loaded by */
2011-09-09 15:24:49 +04:00
handle = dlopen ( path , RTLD_NOW ) ;
2011-09-09 16:41:28 +04:00
/* This call should reset any possible non-fatal errors that
2017-02-17 22:46:28 +03:00
occurred since last call to dl * functions */
2011-09-09 16:41:28 +04:00
error = dlerror ( ) ;
2011-09-09 15:24:49 +04:00
if ( handle = = NULL ) {
2011-09-09 16:41:28 +04:00
int level = is_probe ? 5 : 0 ;
DEBUG ( level , ( " Error loading module '%s': %s \n " , path , error ? error : " " ) ) ;
2011-09-09 15:24:49 +04:00
return NULL ;
}
2011-12-03 10:03:35 +04:00
init_fn = ( init_module_fn ) dlsym ( handle , SAMBA_INIT_MODULE ) ;
2011-09-09 16:41:28 +04:00
/* we could check dlerror() to determine if it worked, because
dlsym ( ) can validly return NULL , but what would we do with
a NULL pointer as a module init function ? */
2011-09-09 15:24:49 +04:00
if ( init_fn = = NULL ) {
DEBUG ( 0 , ( " Unable to find %s() in %s: %s \n " ,
2011-12-03 10:03:35 +04:00
SAMBA_INIT_MODULE , path , dlerror ( ) ) ) ;
2011-09-09 15:24:49 +04:00
DEBUG ( 1 , ( " Loading module '%s' failed \n " , path ) ) ;
dlclose ( handle ) ;
return NULL ;
}
2011-09-09 16:41:28 +04:00
if ( handle_out ) {
* handle_out = handle ;
}
2011-12-03 10:03:35 +04:00
return ( init_module_fn ) init_fn ;
2011-09-09 15:24:49 +04:00
}
/**
* Obtain list of init functions from the modules in the specified
* directory
*/
2011-12-03 10:03:35 +04:00
static init_module_fn * load_modules ( TALLOC_CTX * mem_ctx , const char * path )
2011-09-09 15:24:49 +04:00
{
DIR * dir ;
struct dirent * entry ;
char * filename ;
int success = 0 ;
2011-12-03 10:03:35 +04:00
init_module_fn * ret = talloc_array ( mem_ctx , init_module_fn , 2 ) ;
2011-09-09 15:24:49 +04:00
ret [ 0 ] = NULL ;
dir = opendir ( path ) ;
if ( dir = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
while ( ( entry = readdir ( dir ) ) ) {
if ( ISDOT ( entry - > d_name ) | | ISDOTDOT ( entry - > d_name ) )
continue ;
filename = talloc_asprintf ( mem_ctx , " %s/%s " , path , entry - > d_name ) ;
2011-09-09 16:41:28 +04:00
ret [ success ] = load_module ( filename , true , NULL ) ;
2011-09-09 15:24:49 +04:00
if ( ret [ success ] ) {
2011-12-03 10:03:35 +04:00
ret = talloc_realloc ( mem_ctx , ret , init_module_fn , success + 2 ) ;
2011-09-09 15:24:49 +04:00
success + + ;
ret [ success ] = NULL ;
}
talloc_free ( filename ) ;
}
closedir ( dir ) ;
return ret ;
}
2011-12-03 10:03:35 +04:00
/**
* Run the specified init functions .
*
* @ return true if all functions ran successfully , false otherwise
*/
2017-04-20 22:24:43 +03:00
bool run_init_functions ( TALLOC_CTX * ctx , init_module_fn * fns )
2011-12-03 10:03:35 +04:00
{
int i ;
bool ret = true ;
if ( fns = = NULL )
return true ;
2017-04-20 22:24:43 +03:00
for ( i = 0 ; fns [ i ] ; i + + ) { ret & = ( bool ) NT_STATUS_IS_OK ( fns [ i ] ( ctx ) ) ; }
2011-12-03 10:03:35 +04:00
return ret ;
}
/**
* Load the initialization functions from DSO files for a specific subsystem .
*
* Will return an array of function pointers to initialization functions
*/
init_module_fn * load_samba_modules ( TALLOC_CTX * mem_ctx , const char * subsystem )
{
char * path = modules_path ( mem_ctx , subsystem ) ;
init_module_fn * ret ;
ret = load_modules ( mem_ctx , path ) ;
talloc_free ( path ) ;
return ret ;
}
2017-05-15 10:06:51 +03:00
static NTSTATUS load_module_absolute_path ( const char * module_path ,
bool is_probe )
{
void * handle ;
init_module_fn init ;
NTSTATUS status ;
DBG_INFO ( " %s module '%s' \n " ,
is_probe ? " Probing " : " Loading " ,
module_path ) ;
init = load_module ( module_path , is_probe , & handle ) ;
if ( init = = NULL ) {
return NT_STATUS_UNSUCCESSFUL ;
}
DBG_NOTICE ( " Module '%s' loaded \n " , module_path ) ;
status = init ( NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " Module '%s' initialization failed: %s \n " ,
module_path ,
get_friendly_nt_error_msg ( status ) ) ;
dlclose ( handle ) ;
return status ;
}
return NT_STATUS_OK ;
}
2011-09-09 15:24:49 +04:00
/* Load all modules in list and return number of
* modules that has been successfully loaded */
2017-05-15 11:49:07 +03:00
int smb_load_all_modules_absoute_path ( const char * * modules )
2011-09-09 15:24:49 +04:00
{
int i ;
int success = 0 ;
2017-05-15 10:06:51 +03:00
for ( i = 0 ; modules [ i ] ! = NULL ; i + + ) {
const char * module = modules [ i ] ;
NTSTATUS status ;
if ( module [ 0 ] ! = ' / ' ) {
continue ;
}
status = load_module_absolute_path ( module , false ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2011-09-09 15:24:49 +04:00
success + + ;
}
}
DEBUG ( 2 , ( " %d modules successfully loaded \n " , success ) ) ;
return success ;
}
2017-05-15 12:05:59 +03:00
/**
* @ brief Check if a module exist and load it .
*
* @ param [ in ] subsystem The name of the subsystem the module belongs too .
*
* @ param [ in ] module The name of the module
*
* @ return A NTSTATUS code
*/
2011-09-09 15:24:49 +04:00
NTSTATUS smb_probe_module ( const char * subsystem , const char * module )
{
2017-05-15 12:05:59 +03:00
NTSTATUS status ;
char * module_path = NULL ;
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
if ( subsystem = = NULL ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
if ( module = = NULL ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
if ( strchr ( module , ' / ' ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
module_path = talloc_asprintf ( tmp_ctx ,
" %s/%s.%s " ,
modules_path ( tmp_ctx , subsystem ) ,
module ,
shlib_ext ( ) ) ;
if ( module_path = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
status = load_module_absolute_path ( module_path , true ) ;
done :
TALLOC_FREE ( tmp_ctx ) ;
return status ;
}
/**
* @ brief Check if a module exist and load it .
*
* Warning : Using this function can have security implecations !
*
* @ param [ in ] subsystem The name of the subsystem the module belongs too .
*
* @ param [ in ] module Load a module using an abolute path .
*
* @ return A NTSTATUS code
*/
NTSTATUS smb_probe_module_absolute_path ( const char * module )
{
if ( module = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( module [ 0 ] ! = ' / ' ) {
return NT_STATUS_INVALID_PARAMETER ;
}
return load_module_absolute_path ( module , true ) ;
2012-04-03 07:22:41 +04:00
}
2011-09-09 15:24:49 +04:00
2017-05-15 12:08:19 +03:00
/**
* @ brief Load a module .
*
* @ param [ in ] subsystem The name of the subsystem the module belongs too .
*
* @ param [ in ] module Check if a module exists and load it .
*
* @ return A NTSTATUS code
*/
2012-04-03 07:22:41 +04:00
NTSTATUS smb_load_module ( const char * subsystem , const char * module )
{
2017-05-15 12:08:19 +03:00
NTSTATUS status ;
char * module_path = NULL ;
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
if ( subsystem = = NULL ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
if ( module = = NULL ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
if ( strchr ( module , ' / ' ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
module_path = talloc_asprintf ( tmp_ctx ,
" %s/%s.%s " ,
modules_path ( tmp_ctx , subsystem ) ,
module ,
shlib_ext ( ) ) ;
if ( module_path = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
status = load_module_absolute_path ( module_path , false ) ;
done :
TALLOC_FREE ( tmp_ctx ) ;
return status ;
2011-09-09 15:24:49 +04:00
}