@ -20,35 +20,42 @@
# include <errno.h>
# include <fcntl.h>
# include <dlfcn.h>
# include <errno.h>
# include <stdlib.h>
# include <libintl .h>
# include <string .h>
# include <bits/libc-lock.h>
# include "dummy-db.h"
# include "nsswitch.h"
# include "nss_db.h"
/* This file contains the functions used to open and close the databases
read by the rest of libnss_db . They are not thread safe ; the caller
must handl e locking .
read by the rest of libnss_db . Not all of them are thread safe ;
make sure the caller does the appropriat e locking .
We dynamically load the database library , so that it does not have
to be present when glibc is compiled . Once loaded , libdb is never
unloaded again unless this library is unloaded ( from the free_mem
routine in nsswitch . c ) - we catch the unload by providing a shlib
destructor . ( XXX Does it work ? ) */
to be present when glibc is compiled . Once loaded , the database
library is never never unloaded again until the libnss_db module is
unloaded ( from the free_mem routine in nsswitch . c ) - - we catch the
unload by providing a shlib destructor . ( XXX Does that actually
work ? ) */
/* Handle for the shared Berkeley DB library. If non-null, the
database library is completely loaded and ready to be used by
multithreaded code . */
static void * libdb_handle ;
/* The version of the Berkeley DB library we are using. */
enum {
nodb ,
db24 ,
db27 ,
db30
} libdb_version ;
/* Pointer to the db_open function. For use with DB 2.x. */
static int ( * libdb_db_open ) ( const char * , int ,
uint32_t , int , void * , void * , void * * ) ;
/* Pointer to the db_create function. For use with DB 3.x. */
static int ( * libdb_db_create ) ( void * , void * , uint32_t ) ;
/* Constants which vary from version to version are actually variables
@ -65,13 +72,17 @@ int db_notfound;
/* Locks the static variables in this file. */
__libc_lock_define_initialized ( static , lock )
/* Dynamically load the database library.
/* Dynamically load the database library. Return zero if successful,
non - zero if no suitable version of the library could be loaded .
Must be called with the above lock held if it might run in a
multithreaded context .
We try currently :
- libdb . so .3 : the name used by glibc 2.1
- libdb - 3.0 . so : the name used by db - 3.0 . x
and maybe others in the future . */
int
enum nss_status
load_db ( void )
{
static const char * libnames [ ] = { " libdb.so.3 " , " libdb-3.0.so " } ;
@ -83,11 +94,11 @@ load_db (void)
if ( libdb_handle = = NULL )
continue ;
/* db 3.0 has db_create instead of db_open. */
/* DB 3.0 has db_create instead of db_open. */
libdb_db_create = dlsym ( libdb_handle , " db_create " ) ;
if ( libdb_db_create = = NULL )
/* db 2.x uses db_open. */
/* DB 2.x uses db_open. */
libdb_db_open = dlsym ( libdb_handle , " db_open " ) ;
if ( libdb_db_open ! = NULL | | libdb_db_create ! = NULL )
@ -129,6 +140,7 @@ load_db (void)
db_rdonly = DB2x_RDONLY ;
}
break ;
case 3 :
/* Sanity check: Do we have db_create? */
if ( libdb_db_create ! = NULL )
@ -141,12 +153,14 @@ load_db (void)
db_rdonly = DB30_RDONLY ;
}
break ;
default :
break ;
}
}
if ( libdb_version ! = nodb )
return 0 ;
return NSS_STATUS_SUCCESS ;
/* Clear variables. */
libdb_db_open = NULL ;
@ -157,7 +171,22 @@ load_db (void)
}
( void ) dlerror ( ) ;
return 1 ;
return NSS_STATUS_UNAVAIL ;
}
/* Set the `FD_CLOEXEC' flag of FD. Return 0 on success, or -1 on
error with ` errno ' set . */
static int
set_cloexec_flag ( int fd )
{
int oldflags = fcntl ( fd , F_GETFD , 0 ) ;
if ( oldflags < 0 )
return oldflags ;
oldflags | = FD_CLOEXEC ;
return fcntl ( fd , F_SETFD , oldflags ) ;
}
/* Make sure we don't use the library anymore once we are shutting down. */
@ -173,6 +202,9 @@ unload_db (void)
}
}
/* Open the database stored in FILE. If succesful, store the database
handle in * DBP and return NSS_STATUS_SUCCESS . On failure , return
the appropriate lookup status . */
enum nss_status
internal_setent ( const char * file , NSS_DB * * dbp )
{
@ -184,26 +216,26 @@ internal_setent (const char *file, NSS_DB **dbp)
{
__libc_lock_lock ( lock ) ;
status = load_db ( ) ;
if ( libdb_db_open = = NULL & & libdb_db_create = = NULL )
status = load_db ( ) ;
__libc_lock_unlock ( lock ) ;
if ( status ! = 0 )
return status ;
}
status = dbopen ( file , db_rdonly , 0 , dbp ) ;
if ( status = = NSS_STATUS_SUCCESS )
status = dbopen ( file , db_rdonly , 0 , dbp ) ;
}
return status ;
}
/* Close the database file . */
/* Close the database *DBP . */
void
internal_endent ( NSS_DB * * dbp )
{
NSS_DB * db = * dbp ;
if ( db ! = NULL )
{
DL_CALL_FCT ( db - > close , ( db - > db , 0 ) ) ;
@ -211,188 +243,147 @@ internal_endent (NSS_DB **dbp)
}
}
/* Allocate a cursor for database DB and transaction TXN. On success,
store the cursor in * DBCP and return zero . Otherwise return an
error value . */
int
db_cursor ( void * db , void * txn , NSS_DBC * * dbcp )
{
void * ptr ;
NSS_DBC * dbc = NULL ;
NSS_DBC * dbc ;
int ret ;
dbc = ( NSS_DBC * ) malloc ( sizeof ( NSS_DBC ) ) ;
if ( dbc = = NULL )
return ENOMEM ;
switch ( libdb_version )
{
case db24 :
ret = ( ( struct db24 * ) db ) - > cursor ( db , txn , & ptr ) ;
ret = ( ( struct db24 * ) db ) - > cursor ( db , txn , & dbc - > cursor ) ;
if ( ret = = 0 )
dbc - > c_get = ( ( struct dbc24 * ) dbc - > cursor ) - > c_get ;
break ;
case db27 :
ret = ( ( struct db27 * ) db ) - > cursor ( db , txn , & ptr , 0 ) ;
ret = ( ( struct db27 * ) db ) - > cursor ( db , txn , & dbc - > cursor , 0 ) ;
if ( ret = = 0 )
dbc - > c_get = ( ( struct dbc27 * ) dbc - > cursor ) - > c_get ;
break ;
case db30 :
ret = ( ( struct db30 * ) db ) - > cursor ( db , txn , & ptr , 0 ) ;
ret = ( ( struct db30 * ) db ) - > cursor ( db , txn , & dbc - > cursor , 0 ) ;
if ( ret = = 0 )
dbc - > c_get = ( ( struct dbc30 * ) dbc - > cursor ) - > c_get ;
break ;
default :
abort ( ) ;
}
if ( ret = = 0 )
if ( ret ! = 0 )
{
dbc = ( NSS_DBC * ) malloc ( sizeof ( NSS_DBC ) ) ;
if ( dbc = = NULL )
return 1 ;
dbc - > cursor = ptr ;
switch ( libdb_version )
{
case db24 :
dbc - > c_get =
( int ( * ) ( void * , void * , void * , uint32_t ) )
( ( struct dbc24 * ) ptr ) - > c_get ;
break ;
case db27 :
dbc - > c_get =
( int ( * ) ( void * , void * , void * , uint32_t ) )
( ( struct dbc27 * ) ptr ) - > c_get ;
break ;
case db30 :
dbc - > c_get =
( int ( * ) ( void * , void * , void * , uint32_t ) )
( ( struct dbc30 * ) ptr ) - > c_get ;
default :
abort ( ) ;
}
free ( dbc ) ;
return ret ;
}
* dbcp = dbc ;
return ret ;
return 0 ;
}
/* Open the database in FNAME, for access specified by FLAGS. If
opening the database causes the file FNAME to be created , it is
created with MODE . If succesful , store the database handle in * DBP
and return NSS_STATUS_SUCCESS . On failure , return the appropriate
lookup status . */
int
dbopen ( const char * fname , int oper , int mode , NSS_DB * * dbp )
{
int err ;
int result ;
int fd ;
void * odb ;
enum nss_status status = NSS_STATUS_SUCCESS ;
NSS_DB * db ;
/* Construct the object we pass up. */
db = ( NSS_DB * ) calloc ( 1 , sizeof ( NSS_DB ) ) ;
if ( db = = NULL )
return NSS_STATUS_UNAVAIL ;
/* Initialize the object. */
db - > cursor = db_cursor ;
/* Actually open the database. */
switch ( libdb_version )
{
case db24 :
case db27 :
err = DL_CALL_FCT ( libdb_db_open ,
( fname , DB_BTREE , oper , mode , NULL , NULL , & odb ) ) ;
( fname , DB_BTREE , oper , mode , NULL , NULL , & db - > db ) ) ;
if ( err ! = 0 )
goto fail ;
if ( libdb_version )
{
__set_errno ( err ) ;
* dbp = NULL ;
return err = = EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL ;
db - > close = ( ( struct db24 * ) db - > db ) - > close ;
db - > fd = ( ( struct db24 * ) db - > db ) - > fd ;
db - > get = ( ( struct db24 * ) db - > db ) - > get ;
db - > put = ( ( struct db24 * ) db - > db ) - > put ;
}
else
{
db - > close = ( ( struct db27 * ) db - > db ) - > close ;
db - > fd = ( ( struct db27 * ) db - > db ) - > fd ;
db - > get = ( ( struct db27 * ) db - > db ) - > get ;
db - > put = ( ( struct db27 * ) db - > db ) - > put ;
}
break ;
case db30 :
err = DL_CALL_FCT ( libdb_db_create , ( & odb , NULL , 0 ) ) ;
err = DL_CALL_FCT ( libdb_db_create , ( db - > db , NULL , 0 ) ) ;
if ( err ! = 0 )
{
__set_errno ( err ) ;
* dbp = NULL ;
return err = = EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL ;
}
err = ( ( struct db30 * ) odb ) - > open ( odb , fname , NULL , DB_BTREE ,
oper , mode ) ;
goto fail ;
db - > close = ( ( struct db30 * ) db - > db ) - > close ;
db - > fd = ( ( struct db30 * ) db - > db ) - > fd ;
db - > get = ( ( struct db30 * ) db - > db ) - > get ;
db - > put = ( ( struct db30 * ) db - > db ) - > put ;
err = ( ( struct db30 * ) db - > db ) - > open ( db - > db , fname , NULL , DB_BTREE ,
oper , mode ) ;
if ( err ! = 0 )
{
__set_errno ( err ) ;
/* Free all resources. */
( ( struct db30 * ) odb ) - > close ( odb , 0 ) ;
* dbp = NULL ;
return NSS_STATUS_UNAVAIL ;
}
goto fail ;
break ;
default :
abort ( ) ;
}
/* Construct the object we pass up. */
db = ( NSS_DB * ) malloc ( sizeof ( NSS_DB ) ) ;
if ( db ! = NULL )
{
db - > db = odb ;
/* The functions are at different positions for the different
versions . Sigh . */
switch ( libdb_version )
{
case db24 :
db - > close =
( int ( * ) ( void * , uint32_t ) ) ( ( struct db24 * ) odb ) - > close ;
db - > fd =
( int ( * ) ( void * , int * ) ) ( ( struct db24 * ) odb ) - > fd ;
db - > get =
( int ( * ) ( void * , void * , void * , void * , uint32_t ) )
( ( struct db24 * ) odb ) - > get ;
db - > put =
( int ( * ) ( void * , void * , void * , void * , uint32_t ) )
( ( struct db24 * ) odb ) - > put ;
break ;
case db27 :
db - > close =
( int ( * ) ( void * , uint32_t ) ) ( ( struct db27 * ) odb ) - > close ;
db - > fd =
( int ( * ) ( void * , int * ) ) ( ( struct db27 * ) odb ) - > fd ;
db - > get =
( int ( * ) ( void * , void * , void * , void * , uint32_t ) )
( ( struct db27 * ) odb ) - > get ;
db - > put =
( int ( * ) ( void * , void * , void * , void * , uint32_t ) )
( ( struct db27 * ) odb ) - > put ;
break ;
case db30 :
db - > close =
( int ( * ) ( void * , uint32_t ) ) ( ( struct db30 * ) odb ) - > close ;
db - > fd =
( int ( * ) ( void * , int * ) ) ( ( struct db30 * ) odb ) - > fd ;
db - > get =
( int ( * ) ( void * , void * , void * , void * , uint32_t ) )
( ( struct db30 * ) odb ) - > get ;
db - > put =
( int ( * ) ( void * , void * , void * , void * , uint32_t ) )
( ( struct db30 * ) odb ) - > put ;
break ;
default :
abort ( ) ;
}
db - > cursor = db_cursor ;
/* We have to make sure the file is `closed on exec'. */
err = DL_CALL_FCT ( db - > fd , ( db - > db , & fd ) ) ;
if ( err ! = 0 )
goto fail ;
if ( set_cloexec_flag ( fd ) < 0 )
goto fail ;
/* We have to make sure the file is `closed on exec'. */
err = DL_CALL_FCT ( db - > fd , ( odb , & fd ) ) ;
if ( err ! = 0 )
{
__set_errno ( err ) ;
result = - 1 ;
}
else
{
int flags = result = fcntl ( fd , F_GETFD , 0 ) ;
* dbp = db ;
if ( result > = 0 )
{
flags | = FD_CLOEXEC ;
result = fcntl ( fd , F_SETFD , flags ) ;
}
}
if ( result < 0 )
{
/* Something went wrong. Close the stream and return a
failure . */
DL_CALL_FCT ( db - > close , ( odb , 0 ) ) ;
free ( db ) ;
status = NSS_STATUS_UNAVAIL ;
db = NULL ;
}
return NSS_STATUS_UNAVAIL ;
fail :
/* Something went wrong. Close the database if necessary. */
if ( db )
{
if ( db - > db & & db - > close )
DL_CALL_FCT ( db - > close , ( db - > db , 0 ) ) ;
free ( db ) ;
}
* dbp = db ;
return status ;
/* Make sure `errno' is set. */
if ( err )
__set_errno ( err ) ;
return err = = EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL ;
}