2010-10-17 12:23:41 +04:00
/*
2007-11-29 17:08:27 +03:00
Unix SMB / CIFS implementation .
LDB wrap functions
2009-10-23 07:27:00 +04:00
Copyright ( C ) Andrew Tridgell 2004 - 2009
2010-10-17 12:23:41 +04:00
2007-11-29 17:08:27 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2010-10-17 12:23:41 +04:00
2007-11-29 17:08:27 +03: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-10-17 12:23:41 +04:00
2007-11-29 17:08:27 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
the stupidity of the unix fcntl locking design forces us to never
allow a database file to be opened twice in the same process . These
wrappers provide convenient access to a tdb or ldb , taking advantage
of talloc destructors to ensure that only a single open is done
*/
# include "includes.h"
# include "lib/events/events.h"
2011-02-10 06:12:51 +03:00
# include <ldb.h>
# include <ldb_errors.h>
2007-11-29 17:08:27 +03:00
# include "lib/ldb-samba/ldif_handlers.h"
# include "ldb_wrap.h"
# include "dsdb/samdb/samdb.h"
# include "param/param.h"
2009-12-20 20:05:38 +03:00
# include "../lib/util/dlinklist.h"
2011-02-27 20:45:53 +03:00
# include <tdb.h>
2007-11-29 17:08:27 +03:00
/*
this is used to catch debug messages from ldb
*/
2010-10-17 12:23:41 +04:00
static void ldb_wrap_debug ( void * context , enum ldb_debug_level level ,
2007-11-29 17:08:27 +03:00
const char * fmt , va_list ap ) PRINTF_ATTRIBUTE ( 3 , 0 ) ;
2010-10-17 12:23:41 +04:00
static void ldb_wrap_debug ( void * context , enum ldb_debug_level level ,
2007-11-29 17:08:27 +03:00
const char * fmt , va_list ap )
{
2008-05-15 20:09:56 +04:00
int samba_level = - 1 ;
2007-11-29 17:08:27 +03:00
char * s = NULL ;
switch ( level ) {
case LDB_DEBUG_FATAL :
samba_level = 0 ;
break ;
case LDB_DEBUG_ERROR :
samba_level = 1 ;
break ;
case LDB_DEBUG_WARNING :
samba_level = 2 ;
break ;
case LDB_DEBUG_TRACE :
samba_level = 5 ;
break ;
2010-10-10 18:56:55 +04:00
2007-11-29 17:08:27 +03:00
} ;
vasprintf ( & s , fmt , ap ) ;
if ( ! s ) return ;
2008-03-06 09:03:18 +03:00
DEBUG ( samba_level , ( " ldb: %s \n " , s ) ) ;
2007-11-29 17:08:27 +03:00
free ( s ) ;
}
2009-10-23 07:27:00 +04:00
/*
connecting to a ldb can be a relatively expensive operation because
of the schema and partition loads . We keep a list of open ldb
2010-10-17 12:23:41 +04:00
contexts here , and try to re - use when possible .
2009-10-23 07:27:00 +04:00
This means callers of ldb_wrap_connect ( ) must use talloc_unlink ( ) or
the free of a parent to destroy the context
*/
static struct ldb_wrap {
struct ldb_wrap * next , * prev ;
struct ldb_wrap_context {
/* the context is what we use to tell if two ldb
2010-10-17 12:23:41 +04:00
* connections are exactly equivalent
*/
2009-10-23 07:27:00 +04:00
const char * url ;
struct tevent_context * ev ;
struct loadparm_context * lp_ctx ;
struct auth_session_info * session_info ;
struct cli_credentials * credentials ;
unsigned int flags ;
} context ;
struct ldb_context * ldb ;
} * ldb_wrap_list ;
2010-10-17 12:23:41 +04:00
/*
2009-10-23 07:27:00 +04:00
free a ldb_wrap structure
*/
static int ldb_wrap_destructor ( struct ldb_wrap * w )
{
DLIST_REMOVE ( ldb_wrap_list , w ) ;
2008-09-25 01:59:59 +04:00
return 0 ;
2009-10-23 07:27:00 +04:00
}
2007-11-29 17:08:27 +03:00
2010-10-17 12:20:40 +04:00
/*
* The casefolder for s4 ' s LDB databases - Unicode - safe
*/
char * wrap_casefold ( void * context , void * mem_ctx , const char * s , size_t n )
{
return strupper_talloc_n ( mem_ctx , s , n ) ;
}
2010-10-10 19:34:21 +04:00
struct ldb_context * samba_ldb_init ( TALLOC_CTX * mem_ctx ,
2010-10-17 12:23:41 +04:00
struct tevent_context * ev ,
struct loadparm_context * lp_ctx ,
struct auth_session_info * session_info ,
struct cli_credentials * credentials )
2007-11-29 17:08:27 +03:00
{
2010-10-10 19:34:21 +04:00
struct ldb_context * ldb ;
int ret ;
2008-06-14 19:24:17 +04:00
ldb = ldb_init ( mem_ctx , ev ) ;
if ( ldb = = NULL ) {
2008-04-22 01:58:23 +04:00
return NULL ;
2008-04-17 14:23:44 +04:00
}
2007-11-29 17:08:27 +03:00
2008-06-14 19:24:17 +04:00
ldb_set_modules_dir ( ldb ,
talloc_asprintf ( ldb ,
" %s/ldb " ,
2010-07-16 08:32:42 +04:00
lpcfg_modulesdir ( lp_ctx ) ) ) ;
2008-06-14 19:24:17 +04:00
2010-10-10 19:15:11 +04:00
ldb_set_debug ( ldb , ldb_wrap_debug , NULL ) ;
ldb_set_utf8_fns ( ldb , NULL , wrap_casefold ) ;
2010-06-23 15:15:43 +04:00
if ( session_info ) {
if ( ldb_set_opaque ( ldb , " sessionInfo " , session_info ) ) {
talloc_free ( ldb ) ;
return NULL ;
}
2007-11-29 17:08:27 +03:00
}
2010-06-23 15:15:43 +04:00
if ( credentials ) {
if ( ldb_set_opaque ( ldb , " credentials " , credentials ) ) {
talloc_free ( ldb ) ;
return NULL ;
}
2007-11-29 17:08:27 +03:00
}
2007-12-02 21:04:33 +03:00
if ( ldb_set_opaque ( ldb , " loadparm " , lp_ctx ) ) {
talloc_free ( ldb ) ;
return NULL ;
}
2007-11-29 17:08:27 +03:00
2008-08-21 11:29:47 +04:00
/* This must be done before we load the schema, as these
* handlers for objectSid and objectGUID etc must take
* precedence over the ' binary attribute ' declaration in the
* schema */
2007-11-29 17:08:27 +03:00
ret = ldb_register_samba_handlers ( ldb ) ;
2010-09-11 19:41:38 +04:00
if ( ret ! = LDB_SUCCESS ) {
2007-11-29 17:08:27 +03:00
talloc_free ( ldb ) ;
return NULL ;
}
/* we usually want Samba databases to be private. If we later
find we need one public , we will need to add a parameter to
ldb_wrap_connect ( ) */
ldb_set_create_perms ( ldb , 0600 ) ;
2010-10-10 19:15:11 +04:00
return ldb ;
}
2010-10-10 19:34:21 +04:00
struct ldb_context * ldb_wrap_find ( const char * url ,
2010-10-17 12:23:41 +04:00
struct tevent_context * ev ,
struct loadparm_context * lp_ctx ,
struct auth_session_info * session_info ,
struct cli_credentials * credentials ,
int flags )
2010-10-10 19:34:21 +04:00
{
struct ldb_wrap * w ;
/* see if we can re-use an existing ldb */
for ( w = ldb_wrap_list ; w ; w = w - > next ) {
if ( w - > context . ev = = ev & &
w - > context . lp_ctx = = lp_ctx & &
w - > context . session_info = = session_info & &
w - > context . credentials = = credentials & &
w - > context . flags = = flags & &
( w - > context . url = = url | | strcmp ( w - > context . url , url ) = = 0 ) )
return w - > ldb ;
}
return NULL ;
}
2010-10-17 12:23:41 +04:00
int samba_ldb_connect ( struct ldb_context * ldb , struct loadparm_context * lp_ctx ,
const char * url , int flags )
2010-10-10 19:15:11 +04:00
{
int ret ;
char * real_url = NULL ;
2010-10-11 01:25:38 +04:00
/* allow admins to force non-sync ldb for all databases */
if ( lpcfg_parm_bool ( lp_ctx , NULL , " ldb " , " nosync " , false ) ) {
flags | = LDB_FLG_NOSYNC ;
}
2010-10-10 19:15:11 +04:00
2010-10-11 01:25:38 +04:00
if ( DEBUGLVL ( 10 ) ) {
flags | = LDB_FLG_ENABLE_TRACING ;
2010-10-10 19:15:11 +04:00
}
real_url = private_path ( ldb , lp_ctx , url ) ;
if ( real_url = = NULL ) {
2010-10-11 01:25:38 +04:00
return LDB_ERR_OPERATIONS_ERROR ;
2010-10-10 19:15:11 +04:00
}
2009-10-23 07:27:00 +04:00
ret = ldb_connect ( ldb , real_url , flags , NULL ) ;
2010-10-11 01:25:38 +04:00
2007-11-29 17:08:27 +03:00
if ( ret ! = LDB_SUCCESS ) {
2010-10-11 01:25:38 +04:00
return ret ;
2007-11-29 17:08:27 +03:00
}
/* setup for leak detection */
ldb_set_opaque ( ldb , " wrap_url " , real_url ) ;
2010-10-11 01:25:38 +04:00
return LDB_SUCCESS ;
}
bool ldb_wrap_add ( const char * url , struct tevent_context * ev ,
2010-10-17 12:23:41 +04:00
struct loadparm_context * lp_ctx ,
struct auth_session_info * session_info ,
struct cli_credentials * credentials ,
int flags ,
struct ldb_context * ldb )
2010-10-11 01:25:38 +04:00
{
struct ldb_wrap * w ;
struct ldb_wrap_context c ;
2009-10-23 07:27:00 +04:00
/* add to the list of open ldb contexts */
w = talloc ( ldb , struct ldb_wrap ) ;
if ( w = = NULL ) {
2010-10-11 01:25:38 +04:00
return false ;
2009-10-23 07:27:00 +04:00
}
2010-10-10 19:34:21 +04:00
c . url = url ;
c . ev = ev ;
c . lp_ctx = lp_ctx ;
c . session_info = session_info ;
c . credentials = credentials ;
c . flags = flags ;
2009-10-23 07:27:00 +04:00
w - > context = c ;
w - > context . url = talloc_strdup ( w , url ) ;
if ( w - > context . url = = NULL ) {
2010-10-11 01:25:38 +04:00
return false ;
2009-10-23 07:27:00 +04:00
}
2010-08-17 12:29:42 +04:00
if ( session_info ) {
/* take a reference to the session_info, as it is
* possible for the ldb to live longer than the
* session_info . This happens when a DRS DsBind call
* reuses a handle , but the original connection is
* shutdown . The token for the new connection is still
* valid , so we need the session_info to remain valid for
* ldb modules to use
*/
if ( talloc_reference ( w , session_info ) = = NULL ) {
2010-10-11 01:25:38 +04:00
return false ;
2010-08-17 12:29:42 +04:00
}
}
2009-10-23 07:27:00 +04:00
w - > ldb = ldb ;
DLIST_ADD ( ldb_wrap_list , w ) ;
talloc_set_destructor ( w , ldb_wrap_destructor ) ;
2007-11-29 17:08:27 +03:00
2010-10-11 01:25:38 +04:00
return true ;
}
/*
wrapped connection to a ldb database
to close just talloc_free ( ) the returned ldb_context
TODO : We need an error_string parameter
*/
struct ldb_context * ldb_wrap_connect ( TALLOC_CTX * mem_ctx ,
2010-10-17 12:23:41 +04:00
struct tevent_context * ev ,
struct loadparm_context * lp_ctx ,
const char * url ,
struct auth_session_info * session_info ,
struct cli_credentials * credentials ,
unsigned int flags )
2010-10-11 01:25:38 +04:00
{
struct ldb_context * ldb ;
int ret ;
ldb = ldb_wrap_find ( url , ev , lp_ctx , session_info , credentials , flags ) ;
if ( ldb ! = NULL )
return talloc_reference ( mem_ctx , ldb ) ;
ldb = samba_ldb_init ( mem_ctx , ev , lp_ctx , session_info , credentials ) ;
if ( ldb = = NULL )
return NULL ;
ret = samba_ldb_connect ( ldb , lp_ctx , url , flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( ldb ) ;
return NULL ;
}
if ( ! ldb_wrap_add ( url , ev , lp_ctx , session_info , credentials , flags , ldb ) ) {
talloc_free ( ldb ) ;
return NULL ;
}
DEBUG ( 3 , ( " ldb_wrap open of %s \n " , url ) ) ;
2007-11-29 17:08:27 +03:00
return ldb ;
}
2009-10-23 07:27:00 +04:00
/*
when we fork ( ) we need to make sure that any open ldb contexts have
any open transactions cancelled
*/
2010-06-16 15:43:38 +04:00
void ldb_wrap_fork_hook ( void )
2009-10-23 07:27:00 +04:00
{
2009-10-23 07:46:34 +04:00
struct ldb_wrap * w ;
for ( w = ldb_wrap_list ; w ; w = w - > next ) {
2009-10-23 07:50:56 +04:00
if ( ldb_transaction_cancel_noerr ( w - > ldb ) ! = LDB_SUCCESS ) {
smb_panic ( " Failed to cancel child transactions \n " ) ;
}
2010-10-17 12:23:41 +04:00
}
2009-10-23 07:50:56 +04:00
if ( tdb_reopen_all ( 1 ) = = - 1 ) {
smb_panic ( " tdb_reopen_all failed \n " ) ;
}
2009-10-23 07:27:00 +04:00
}
2010-10-11 01:45:23 +04:00
char * ldb_relative_path ( struct ldb_context * ldb ,
2010-10-17 12:23:41 +04:00
TALLOC_CTX * mem_ctx ,
const char * name )
2010-10-11 01:45:23 +04:00
{
2010-10-17 12:23:41 +04:00
const char * base_url =
2010-10-11 01:45:23 +04:00
( const char * ) ldb_get_opaque ( ldb , " ldb_url " ) ;
char * path , * p , * full_name ;
if ( name = = NULL ) {
return NULL ;
}
if ( strncmp ( " tdb:// " , base_url , 6 ) = = 0 ) {
base_url = base_url + 6 ;
}
path = talloc_strdup ( mem_ctx , base_url ) ;
if ( path = = NULL ) {
return NULL ;
}
if ( ( p = strrchr ( path , ' / ' ) ) ! = NULL ) {
p [ 0 ] = ' \0 ' ;
full_name = talloc_asprintf ( mem_ctx , " %s/%s " , path , name ) ;
} else {
full_name = talloc_asprintf ( mem_ctx , " ./%s " , name ) ;
}
talloc_free ( path ) ;
return full_name ;
}