2009-08-05 10:50:03 +10:00
/*
2014-01-17 14:43:01 +01:00
* Copyright ( c ) 2009 Andrew Tridgell
* Copyright ( c ) 2011 - 2013 Andreas Schneider < asn @ samba . org >
*
* 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/>.
2009-08-05 10:50:03 +10:00
*/
2014-01-17 14:43:01 +01:00
# include "config.h"
2010-01-30 14:25:51 +01:00
2014-01-17 14:43:01 +01:00
# include <errno.h>
# include <stdarg.h>
# include <stdbool.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <sys/types.h>
# include <unistd.h>
# include <grp.h>
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
# ifdef HAVE_SYSCALL_H
# include <syscall.h>
# endif
# include <dlfcn.h>
# include <pthread.h>
# ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
# define UWRAP_THREAD __thread
# else
# define UWRAP_THREAD
# endif
2015-01-23 14:00:49 +01:00
# define UWRAP_LOCK(m) do { \
pthread_mutex_lock ( & ( m # # _mutex ) ) ; \
} while ( 0 )
# define UWRAP_UNLOCK(m) do { \
pthread_mutex_unlock ( & ( m # # _mutex ) ) ; \
} while ( 0 )
2015-01-23 15:29:35 +01:00
/* Add new global locks here please */
# define UWRAP_LOCK_ALL \
UWRAP_LOCK ( uwrap_id ) ; \
UWRAP_LOCK ( libc_symbol_binding ) ; \
2015-01-23 15:30:03 +01:00
UWRAP_LOCK ( libpthread_symbol_binding )
2015-01-23 15:29:35 +01:00
# define UWRAP_UNLOCK_ALL \
2015-01-23 15:30:03 +01:00
UWRAP_UNLOCK ( libpthread_symbol_binding ) ; \
2015-01-23 15:29:35 +01:00
UWRAP_UNLOCK ( libc_symbol_binding ) ; \
UWRAP_UNLOCK ( uwrap_id )
2015-01-23 15:10:02 +01:00
# ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
# define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
# else
# define CONSTRUCTOR_ATTRIBUTE
# endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
2014-01-17 14:43:01 +01:00
# ifdef HAVE_DESTRUCTOR_ATTRIBUTE
# define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
# else
# define DESTRUCTOR_ATTRIBUTE
# endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
2015-01-23 15:22:18 +01:00
# ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
# define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
# else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
# define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
# endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
2014-07-31 10:18:13 +02:00
/* GCC have printf type attribute check. */
# ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
# define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
# else
# define PRINTF_ATTRIBUTE(a,b)
# endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
2014-01-17 14:43:01 +01:00
# define UWRAP_DLIST_ADD(list,item) do { \
if ( ! ( list ) ) { \
( item ) - > prev = NULL ; \
( item ) - > next = NULL ; \
( list ) = ( item ) ; \
} else { \
( item ) - > prev = NULL ; \
( item ) - > next = ( list ) ; \
( list ) - > prev = ( item ) ; \
( list ) = ( item ) ; \
} \
} while ( 0 )
2010-01-30 14:25:51 +01:00
2014-01-17 14:43:01 +01:00
# define UWRAP_DLIST_REMOVE(list,item) do { \
if ( ( list ) = = ( item ) ) { \
( list ) = ( item ) - > next ; \
if ( list ) { \
( list ) - > prev = NULL ; \
} \
} else { \
if ( ( item ) - > prev ) { \
( item ) - > prev - > next = ( item ) - > next ; \
} \
if ( ( item ) - > next ) { \
( item ) - > next - > prev = ( item ) - > prev ; \
} \
} \
( item ) - > prev = NULL ; \
( item ) - > next = NULL ; \
} while ( 0 )
# ifndef SAFE_FREE
# define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
# endif
2010-01-30 14:25:51 +01:00
2014-07-31 10:18:59 +02:00
/*****************
* LOGGING
* * * * * * * * * * * * * * * * */
enum uwrap_dbglvl_e {
UWRAP_LOG_ERROR = 0 ,
UWRAP_LOG_WARN ,
UWRAP_LOG_DEBUG ,
UWRAP_LOG_TRACE
} ;
# ifdef NDEBUG
# define UWRAP_LOG(...)
# else /* NDEBUG */
2015-10-30 13:36:39 +01:00
static void uwrap_log ( enum uwrap_dbglvl_e dbglvl , const char * function , const char * format , . . . ) PRINTF_ATTRIBUTE ( 3 , 4 ) ;
# define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
2014-07-31 10:18:59 +02:00
2015-10-30 13:36:39 +01:00
static void uwrap_log ( enum uwrap_dbglvl_e dbglvl , const char * function , const char * format , . . . )
2014-07-31 10:18:59 +02:00
{
char buffer [ 1024 ] ;
va_list va ;
const char * d ;
unsigned int lvl = 0 ;
d = getenv ( " UID_WRAPPER_DEBUGLEVEL " ) ;
if ( d ! = NULL ) {
lvl = atoi ( d ) ;
}
va_start ( va , format ) ;
vsnprintf ( buffer , sizeof ( buffer ) , format , va ) ;
va_end ( va ) ;
if ( lvl > = dbglvl ) {
2015-10-30 13:36:39 +01:00
const char * prefix ;
2014-07-31 10:18:59 +02:00
switch ( dbglvl ) {
case UWRAP_LOG_ERROR :
2015-10-30 13:36:39 +01:00
prefix = " UWRAP_ERROR " ;
2014-07-31 10:18:59 +02:00
break ;
case UWRAP_LOG_WARN :
2015-10-30 13:36:39 +01:00
prefix = " UWRAP_WARN " ;
2014-07-31 10:18:59 +02:00
break ;
case UWRAP_LOG_DEBUG :
2015-10-30 13:36:39 +01:00
prefix = " UWRAP_DEBUG " ;
2014-07-31 10:18:59 +02:00
break ;
case UWRAP_LOG_TRACE :
2015-10-30 13:36:39 +01:00
prefix = " UWRAP_TRACE " ;
2014-07-31 10:18:59 +02:00
break ;
}
2015-10-30 13:36:39 +01:00
fprintf ( stderr ,
" %s(%d) - %s: %s \n " ,
prefix ,
( int ) getpid ( ) ,
function ,
buffer ) ;
2014-07-31 10:18:59 +02:00
}
}
# endif /* NDEBUG */
/*****************
* LIBC
* * * * * * * * * * * * * * * * */
2014-01-17 14:43:01 +01:00
# define LIBC_NAME "libc.so"
2010-01-30 14:25:51 +01:00
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setuid ) ( uid_t uid ) ;
typedef uid_t ( * __libc_getuid ) ( void ) ;
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETEUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_seteuid ) ( uid_t euid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETREUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setreuid ) ( uid_t ruid , uid_t euid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETRESUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setresuid ) ( uid_t ruid , uid_t euid , uid_t suid ) ;
2015-01-23 15:27:25 +01:00
# endif
2015-01-23 15:28:37 +01:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_getresuid ) ( uid_t * ruid , uid_t * euid , uid_t * suid ) ;
2010-01-30 14:25:51 +01:00
# endif
2009-08-05 10:50:03 +10:00
2015-01-23 15:28:37 +01:00
typedef uid_t ( * __libc_geteuid ) ( void ) ;
typedef int ( * __libc_setgid ) ( gid_t gid ) ;
typedef gid_t ( * __libc_getgid ) ( void ) ;
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETEGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setegid ) ( uid_t egid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETREGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setregid ) ( uid_t rgid , uid_t egid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETRESGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setresgid ) ( uid_t rgid , uid_t egid , uid_t sgid ) ;
2015-01-23 15:27:25 +01:00
# endif
2015-01-23 15:28:37 +01:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_getresgid ) ( gid_t * rgid , gid_t * egid , gid_t * sgid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
typedef gid_t ( * __libc_getegid ) ( void ) ;
typedef int ( * __libc_getgroups ) ( int size , gid_t list [ ] ) ;
typedef int ( * __libc_setgroups ) ( size_t size , const gid_t * list ) ;
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SYSCALL
2015-01-23 15:28:37 +01:00
typedef long int ( * __libc_syscall ) ( long int sysno , . . . ) ;
# endif
# define UWRAP_SYMBOL_ENTRY(i) \
union { \
__libc_ # # i f ; \
void * obj ; \
} _libc_ # # i
struct uwrap_libc_symbols {
UWRAP_SYMBOL_ENTRY ( setuid ) ;
UWRAP_SYMBOL_ENTRY ( getuid ) ;
# ifdef HAVE_SETEUID
UWRAP_SYMBOL_ENTRY ( seteuid ) ;
# endif
# ifdef HAVE_SETREUID
UWRAP_SYMBOL_ENTRY ( setreuid ) ;
# endif
# ifdef HAVE_SETRESUID
UWRAP_SYMBOL_ENTRY ( setresuid ) ;
# endif
# ifdef HAVE_GETRESUID
UWRAP_SYMBOL_ENTRY ( getresuid ) ;
# endif
UWRAP_SYMBOL_ENTRY ( geteuid ) ;
UWRAP_SYMBOL_ENTRY ( setgid ) ;
UWRAP_SYMBOL_ENTRY ( getgid ) ;
# ifdef HAVE_SETEGID
UWRAP_SYMBOL_ENTRY ( setegid ) ;
# endif
# ifdef HAVE_SETREGID
UWRAP_SYMBOL_ENTRY ( setregid ) ;
# endif
# ifdef HAVE_SETRESGID
UWRAP_SYMBOL_ENTRY ( setresgid ) ;
# endif
# ifdef HAVE_GETRESGID
UWRAP_SYMBOL_ENTRY ( getresgid ) ;
# endif
UWRAP_SYMBOL_ENTRY ( getegid ) ;
UWRAP_SYMBOL_ENTRY ( getgroups ) ;
UWRAP_SYMBOL_ENTRY ( setgroups ) ;
# ifdef HAVE_SYSCALL
UWRAP_SYMBOL_ENTRY ( syscall ) ;
2009-08-05 10:50:03 +10:00
# endif
2014-01-17 14:43:01 +01:00
} ;
2015-01-23 15:30:03 +01:00
# undef UWRAP_SYMBOL_ENTRY
/*****************
* LIBPTHREAD
* * * * * * * * * * * * * * * * */
/* Yeah... I'm pig. I overloading macro here... So what? */
# define UWRAP_SYMBOL_ENTRY(i) \
union { \
__libpthread_ # # i f ; \
void * obj ; \
} _libpthread_ # # i
typedef int ( * __libpthread_pthread_create ) ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg ) ;
typedef void ( * __libpthread_pthread_exit ) ( void * retval ) ;
struct uwrap_libpthread_symbols {
UWRAP_SYMBOL_ENTRY ( pthread_create ) ;
UWRAP_SYMBOL_ENTRY ( pthread_exit ) ;
} ;
# undef UWRAP_SYMBOL_ENTRY
2009-08-05 10:50:03 +10:00
/*
2014-01-17 14:43:01 +01:00
* We keep the virtualised euid / egid / groups information here
2009-08-05 10:50:03 +10:00
*/
2014-01-17 14:43:01 +01:00
struct uwrap_thread {
2015-01-23 15:30:30 +01:00
bool enabled ;
2014-01-17 14:43:01 +01:00
uid_t ruid ;
uid_t euid ;
uid_t suid ;
gid_t rgid ;
gid_t egid ;
gid_t sgid ;
int ngroups ;
2015-01-23 15:25:16 +01:00
gid_t * groups ;
2014-01-17 14:43:01 +01:00
struct uwrap_thread * next ;
struct uwrap_thread * prev ;
} ;
struct uwrap {
struct {
void * handle ;
2015-01-23 15:28:37 +01:00
struct uwrap_libc_symbols symbols ;
2014-01-17 14:43:01 +01:00
} libc ;
2015-01-23 15:30:03 +01:00
struct {
void * handle ;
struct uwrap_libpthread_symbols symbols ;
} libpthread ;
2009-08-05 10:50:03 +10:00
bool initialised ;
2015-01-23 15:25:16 +01:00
2015-01-23 15:16:34 +01:00
/* Real uid and gid of user who run uid wrapper */
2011-10-07 18:58:58 +02:00
uid_t myuid ;
2015-01-23 15:16:34 +01:00
gid_t mygid ;
2014-01-17 14:43:01 +01:00
struct uwrap_thread * ids ;
} ;
static struct uwrap uwrap ;
/* Shortcut to the list item */
static UWRAP_THREAD struct uwrap_thread * uwrap_tls_id ;
/* The mutex or accessing the id */
static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER ;
2015-01-23 15:28:37 +01:00
/* The mutex for accessing the global libc.symbols */
2015-01-23 15:12:02 +01:00
static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER ;
2015-01-23 15:30:03 +01:00
/* The mutex for accessing the global libpthread.symbols */
static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER ;
2014-01-17 14:43:01 +01:00
/*********************************************************
* UWRAP PROTOTYPES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool uid_wrapper_enabled ( void ) ;
2015-01-23 15:10:02 +01:00
void uwrap_constructor ( void ) CONSTRUCTOR_ATTRIBUTE ;
2014-01-17 14:43:01 +01:00
void uwrap_destructor ( void ) DESTRUCTOR_ATTRIBUTE ;
/*********************************************************
* UWRAP LIBC LOADER FUNCTIONS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum uwrap_lib {
UWRAP_LIBC ,
UWRAP_LIBNSL ,
UWRAP_LIBSOCKET ,
2015-01-23 15:30:03 +01:00
UWRAP_LIBPTHREAD ,
2014-01-17 14:43:01 +01:00
} ;
static void * uwrap_load_lib_handle ( enum uwrap_lib lib )
{
int flags = RTLD_LAZY ;
void * handle = NULL ;
int i ;
# ifdef RTLD_DEEPBIND
flags | = RTLD_DEEPBIND ;
# endif
switch ( lib ) {
case UWRAP_LIBNSL :
/* FALL TROUGH */
case UWRAP_LIBSOCKET :
/* FALL TROUGH */
case UWRAP_LIBC :
handle = uwrap . libc . handle ;
if ( handle = = NULL ) {
2015-01-23 13:59:14 +01:00
for ( i = 10 ; i > = 0 ; i - - ) {
2014-01-17 14:43:01 +01:00
char soname [ 256 ] = { 0 } ;
snprintf ( soname , sizeof ( soname ) , " libc.so.%d " , i ) ;
handle = dlopen ( soname , flags ) ;
2015-01-23 13:59:14 +01:00
if ( handle ! = NULL ) {
break ;
}
2014-01-17 14:43:01 +01:00
}
uwrap . libc . handle = handle ;
}
break ;
2015-01-23 15:30:03 +01:00
case UWRAP_LIBPTHREAD :
handle = uwrap . libpthread . handle ;
if ( handle = = NULL ) {
handle = dlopen ( " libpthread.so.0 " , flags ) ;
if ( handle ! = NULL ) {
break ;
}
}
break ;
2014-01-17 14:43:01 +01:00
}
if ( handle = = NULL ) {
2014-07-31 10:13:40 +02:00
# ifdef RTLD_NEXT
handle = uwrap . libc . handle = RTLD_NEXT ;
# else
2014-01-17 14:43:01 +01:00
fprintf ( stderr ,
" Failed to dlopen library: %s \n " ,
dlerror ( ) ) ;
exit ( - 1 ) ;
2014-07-31 10:13:40 +02:00
# endif
2014-01-17 14:43:01 +01:00
}
return handle ;
}
2015-01-23 15:28:37 +01:00
static void * _uwrap_bind_symbol ( enum uwrap_lib lib , const char * fn_name )
2014-01-17 14:43:01 +01:00
{
void * handle ;
void * func ;
handle = uwrap_load_lib_handle ( lib ) ;
func = dlsym ( handle , fn_name ) ;
if ( func = = NULL ) {
fprintf ( stderr ,
" Failed to find %s: %s \n " ,
fn_name , dlerror ( ) ) ;
exit ( - 1 ) ;
}
return func ;
}
2015-01-23 15:30:03 +01:00
# define uwrap_bind_symbol_libc(sym_name) \
2015-01-23 15:12:02 +01:00
UWRAP_LOCK ( libc_symbol_binding ) ; \
2015-01-23 15:28:37 +01:00
if ( uwrap . libc . symbols . _libc_ # # sym_name . obj = = NULL ) { \
uwrap . libc . symbols . _libc_ # # sym_name . obj = \
2015-01-23 15:30:03 +01:00
_uwrap_bind_symbol ( UWRAP_LIBC , # sym_name ) ; \
2015-01-23 15:12:02 +01:00
} \
UWRAP_UNLOCK ( libc_symbol_binding )
2014-01-17 14:43:01 +01:00
2015-01-23 15:30:03 +01:00
# define uwrap_bind_symbol_libpthread(sym_name) \
UWRAP_LOCK ( libpthread_symbol_binding ) ; \
if ( uwrap . libpthread . symbols . _libpthread_ # # sym_name . obj = = NULL ) { \
uwrap . libpthread . symbols . _libpthread_ # # sym_name . obj = \
_uwrap_bind_symbol ( UWRAP_LIBPTHREAD , # sym_name ) ; \
} \
UWRAP_UNLOCK ( libpthread_symbol_binding )
2014-01-17 14:43:01 +01:00
/*
* IMPORTANT
*
* Functions expeciall from libc need to be loaded individually , you can ' t load
* all at once or gdb will segfault at startup . The same applies to valgrind and
* has probably something todo with with the linker .
* So we need load each function at the point it is called the first time .
*/
static int libc_setuid ( uid_t uid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setuid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setuid . f ( uid ) ;
2014-01-17 14:43:01 +01:00
}
static uid_t libc_getuid ( void )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( getuid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getuid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SETEUID
static int libc_seteuid ( uid_t euid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( seteuid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_seteuid . f ( euid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETREUID
static int libc_setreuid ( uid_t ruid , uid_t euid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setreuid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setreuid . f ( ruid , euid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETRESUID
static int libc_setresuid ( uid_t ruid , uid_t euid , uid_t suid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setresuid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setresuid . f ( ruid , euid , suid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
static int libc_getresuid ( uid_t * ruid , uid_t * euid , uid_t * suid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( getresuid ) ;
2015-01-23 15:27:25 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getresuid . f ( ruid , euid , suid ) ;
2015-01-23 15:27:25 +01:00
}
# endif
2014-01-17 14:43:01 +01:00
static uid_t libc_geteuid ( void )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( geteuid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_geteuid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
static int libc_setgid ( gid_t gid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setgid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setgid . f ( gid ) ;
2014-01-17 14:43:01 +01:00
}
static gid_t libc_getgid ( void )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( getgid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getgid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SETEGID
static int libc_setegid ( gid_t egid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setegid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setegid . f ( egid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETREGID
static int libc_setregid ( gid_t rgid , gid_t egid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setregid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setregid . f ( rgid , egid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETRESGID
static int libc_setresgid ( gid_t rgid , gid_t egid , gid_t sgid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setresgid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setresgid . f ( rgid , egid , sgid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
static int libc_getresgid ( gid_t * rgid , gid_t * egid , gid_t * sgid )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setresgid ) ;
2015-01-23 15:27:25 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getresgid . f ( rgid , egid , sgid ) ;
2015-01-23 15:27:25 +01:00
}
# endif
2014-01-17 14:43:01 +01:00
static gid_t libc_getegid ( void )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( getegid ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getegid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
static int libc_getgroups ( int size , gid_t list [ ] )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( getgroups ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getgroups . f ( size , list ) ;
2014-01-17 14:43:01 +01:00
}
static int libc_setgroups ( size_t size , const gid_t * list )
{
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( setgroups ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setgroups . f ( size , list ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SYSCALL
2015-01-23 15:22:18 +01:00
DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
2014-01-17 14:43:01 +01:00
static long int libc_vsyscall ( long int sysno , va_list va )
{
long int args [ 8 ] ;
long int rc ;
int i ;
2015-01-23 15:30:03 +01:00
uwrap_bind_symbol_libc ( syscall ) ;
2014-01-17 14:43:01 +01:00
for ( i = 0 ; i < 8 ; i + + ) {
args [ i ] = va_arg ( va , long int ) ;
}
2015-01-23 15:28:37 +01:00
rc = uwrap . libc . symbols . _libc_syscall . f ( sysno ,
2014-01-17 14:43:01 +01:00
args [ 0 ] ,
args [ 1 ] ,
args [ 2 ] ,
args [ 3 ] ,
args [ 4 ] ,
args [ 5 ] ,
args [ 6 ] ,
args [ 7 ] ) ;
return rc ;
}
# endif
2015-01-23 15:30:03 +01:00
/*
* This part is " optimistic " .
* Thread can ends without pthread_exit call .
*/
static void libpthread_pthread_exit ( void * retval )
{
uwrap_bind_symbol_libpthread ( pthread_exit ) ;
uwrap . libpthread . symbols . _libpthread_pthread_exit . f ( retval ) ;
}
static void uwrap_pthread_exit ( void * retval )
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Cleanup thread " ) ;
UWRAP_LOCK ( uwrap_id ) ;
if ( id = = NULL ) {
UWRAP_UNLOCK ( uwrap_id ) ;
libpthread_pthread_exit ( retval ) ;
2015-01-23 15:31:17 +01:00
return ;
2015-01-23 15:30:30 +01:00
}
UWRAP_DLIST_REMOVE ( uwrap . ids , id ) ;
SAFE_FREE ( id - > groups ) ;
SAFE_FREE ( id ) ;
uwrap_tls_id = NULL ;
UWRAP_UNLOCK ( uwrap_id ) ;
2015-01-23 15:30:03 +01:00
libpthread_pthread_exit ( retval ) ;
}
void pthread_exit ( void * retval )
{
if ( ! uid_wrapper_enabled ( ) ) {
libpthread_pthread_exit ( retval ) ;
} ;
uwrap_pthread_exit ( retval ) ;
/* Calm down gcc warning. */
exit ( 666 ) ;
}
static int libpthread_pthread_create ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg )
{
uwrap_bind_symbol_libpthread ( pthread_create ) ;
return uwrap . libpthread . symbols . _libpthread_pthread_create . f ( thread ,
attr ,
start_routine ,
arg ) ;
}
2015-01-23 15:30:30 +01:00
struct uwrap_pthread_create_args {
struct uwrap_thread * id ;
void * ( * start_routine ) ( void * ) ;
void * arg ;
} ;
static void * uwrap_pthread_create_start ( void * _a )
{
struct uwrap_pthread_create_args * a =
( struct uwrap_pthread_create_args * ) _a ;
void * ( * start_routine ) ( void * ) = a - > start_routine ;
void * arg = a - > arg ;
struct uwrap_thread * id = a - > id ;
SAFE_FREE ( a ) ;
uwrap_tls_id = id ;
return start_routine ( arg ) ;
}
2015-01-23 15:30:03 +01:00
static int uwrap_pthread_create ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg )
{
2015-01-23 15:30:30 +01:00
struct uwrap_pthread_create_args * args ;
struct uwrap_thread * src_id = uwrap_tls_id ;
int ret ;
args = malloc ( sizeof ( struct uwrap_pthread_create_args ) ) ;
if ( args = = NULL ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" uwrap_pthread_create: Unable to allocate memory " ) ;
errno = ENOMEM ;
return - 1 ;
}
args - > start_routine = start_routine ;
args - > arg = arg ;
args - > id = calloc ( 1 , sizeof ( struct uwrap_thread ) ) ;
if ( args - > id = = NULL ) {
SAFE_FREE ( args ) ;
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" uwrap_pthread_create: Unable to allocate memory " ) ;
errno = ENOMEM ;
return - 1 ;
}
UWRAP_LOCK ( uwrap_id ) ;
args - > id - > groups = malloc ( sizeof ( gid_t ) * src_id - > ngroups ) ;
if ( args - > id - > groups = = NULL ) {
UWRAP_UNLOCK ( uwrap_id ) ;
SAFE_FREE ( args - > id ) ;
SAFE_FREE ( args ) ;
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" uwrap_pthread_create: Unable to allocate memory again " ) ;
errno = ENOMEM ;
return - 1 ;
}
args - > id - > ruid = src_id - > ruid ;
args - > id - > euid = src_id - > euid ;
args - > id - > suid = src_id - > suid ;
args - > id - > rgid = src_id - > rgid ;
args - > id - > egid = src_id - > egid ;
args - > id - > sgid = src_id - > sgid ;
args - > id - > enabled = src_id - > enabled ;
args - > id - > ngroups = src_id - > ngroups ;
if ( src_id - > groups ! = NULL ) {
memcpy ( args - > id - > groups , src_id - > groups ,
sizeof ( gid_t ) * src_id - > ngroups ) ;
} else {
SAFE_FREE ( args - > id - > groups ) ;
}
UWRAP_DLIST_ADD ( uwrap . ids , args - > id ) ;
UWRAP_UNLOCK ( uwrap_id ) ;
ret = libpthread_pthread_create ( thread , attr ,
uwrap_pthread_create_start ,
args ) ;
if ( ret ! = 0 ) {
return ret ;
}
return ret ;
2015-01-23 15:30:03 +01:00
}
int pthread_create ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libpthread_pthread_create ( thread ,
attr ,
start_routine ,
arg ) ;
} ;
return uwrap_pthread_create ( thread ,
attr ,
start_routine ,
arg ) ;
}
2014-01-17 14:43:01 +01:00
/*********************************************************
* UWRAP ID HANDLING
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-01-23 15:30:30 +01:00
static void uwrap_thread_prepare ( void )
2014-01-17 14:43:01 +01:00
{
struct uwrap_thread * id = uwrap_tls_id ;
2015-10-30 13:37:11 +01:00
/* uid_wrapper is loaded but not enabled */
if ( id = = NULL ) {
return ;
}
2015-01-23 15:29:35 +01:00
UWRAP_LOCK_ALL ;
2014-01-17 14:43:01 +01:00
/*
* What happens if another atfork prepare functions calls a uwrap
* function ? So disable it in case another atfork prepare function
2015-01-23 15:30:30 +01:00
* calls a ( s ) uid function . We disable uid_wrapper only for thread
* ( process ) which called fork .
2014-01-17 14:43:01 +01:00
*/
2015-01-23 15:30:30 +01:00
id - > enabled = false ;
2014-01-17 14:43:01 +01:00
}
static void uwrap_thread_parent ( void )
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
2015-10-30 13:37:11 +01:00
/* uid_wrapper is loaded but not enabled */
if ( id = = NULL ) {
return ;
}
2015-01-23 15:30:30 +01:00
id - > enabled = true ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:29:35 +01:00
UWRAP_UNLOCK_ALL ;
2014-01-17 14:43:01 +01:00
}
static void uwrap_thread_child ( void )
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
struct uwrap_thread * u = uwrap . ids ;
2015-10-30 13:37:11 +01:00
/* uid_wrapper is loaded but not enabled */
if ( id = = NULL ) {
return ;
}
2015-01-23 15:30:30 +01:00
/*
* " Garbage collector " - Inspired by DESTRUCTOR .
* All threads ( except one which called fork ( ) ) are dead now . . Dave
* That ' s what posix said . . .
*/
while ( u ! = NULL ) {
if ( u = = id ) {
/* Skip this item. */
u = uwrap . ids - > next ;
continue ;
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:30:30 +01:00
UWRAP_DLIST_REMOVE ( uwrap . ids , u ) ;
2015-01-23 15:24:39 +01:00
2015-01-23 15:30:30 +01:00
SAFE_FREE ( u - > groups ) ;
SAFE_FREE ( u ) ;
u = uwrap . ids ;
}
id - > enabled = true ;
UWRAP_UNLOCK_ALL ;
2014-01-17 14:43:01 +01:00
}
2009-08-05 10:50:03 +10:00
static void uwrap_init ( void )
{
2015-01-23 15:15:42 +01:00
const char * env ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:12:43 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
if ( uwrap . initialised ) {
struct uwrap_thread * id = uwrap_tls_id ;
2015-01-23 15:30:30 +01:00
if ( uwrap . ids = = NULL ) {
2015-01-23 15:12:43 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return ;
}
if ( id = = NULL ) {
2015-01-23 15:30:30 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Invalid id for thread " ) ;
exit ( - 1 ) ;
2014-01-17 14:43:01 +01:00
}
2015-01-23 15:30:30 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return ;
}
2014-07-31 10:19:58 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Initialize uid_wrapper " ) ;
2009-08-05 10:50:03 +10:00
uwrap . initialised = true ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:42 +01:00
env = getenv ( " UID_WRAPPER " ) ;
2014-01-17 14:43:01 +01:00
if ( env ! = NULL & & env [ 0 ] = = ' 1 ' ) {
const char * root = getenv ( " UID_WRAPPER_ROOT " ) ;
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id ;
id = calloc ( 1 , sizeof ( struct uwrap_thread ) ) ;
if ( id = = NULL ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to allocate memory for main id " ) ;
exit ( - 1 ) ;
}
UWRAP_DLIST_ADD ( uwrap . ids , id ) ;
uwrap_tls_id = id ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:16:34 +01:00
uwrap . myuid = libc_geteuid ( ) ;
uwrap . mygid = libc_getegid ( ) ;
2015-01-23 15:30:30 +01:00
2009-08-05 13:31:06 +10:00
/* put us in one group */
2014-01-17 14:43:01 +01:00
if ( root ! = NULL & & root [ 0 ] = = ' 1 ' ) {
2015-01-23 15:30:30 +01:00
id - > ruid = id - > euid = id - > suid = 0 ;
id - > rgid = id - > egid = id - > sgid = 0 ;
2015-01-23 15:25:16 +01:00
2015-01-23 15:30:30 +01:00
id - > groups = malloc ( sizeof ( gid_t ) * 1 ) ;
if ( id - > groups = = NULL ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to allocate memory " ) ;
exit ( - 1 ) ;
}
2015-01-23 15:30:30 +01:00
id - > ngroups = 1 ;
id - > groups [ 0 ] = 0 ;
2015-01-23 15:25:16 +01:00
2014-01-17 14:43:01 +01:00
} else {
2015-01-23 15:30:30 +01:00
id - > ruid = id - > euid = id - > suid = uwrap . myuid ;
id - > rgid = id - > egid = id - > sgid = uwrap . mygid ;
2015-01-23 15:25:16 +01:00
2015-01-23 15:30:30 +01:00
id - > ngroups = libc_getgroups ( 0 , NULL ) ;
if ( id - > ngroups = = - 1 ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to call libc_getgroups in uwrap_init. " ) ;
exit ( - 1 ) ;
}
2015-01-23 15:30:30 +01:00
id - > groups = malloc ( sizeof ( gid_t ) * id - > ngroups ) ;
if ( id - > groups = = NULL ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR , " Unable to allocate memory " ) ;
exit ( - 1 ) ;
}
2015-01-23 15:30:30 +01:00
if ( libc_getgroups ( id - > ngroups , id - > groups ) = = - 1 ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to call libc_getgroups again in uwrap_init. " ) ;
2015-01-23 15:30:30 +01:00
id - > groups = 0 ;
2015-01-23 15:25:16 +01:00
/*
* Deallocation of uwrap . groups is handled by
* library destructor .
*/
exit ( - 1 ) ;
}
2014-01-17 14:43:01 +01:00
}
2015-01-23 15:30:30 +01:00
id - > enabled = true ;
2014-07-31 10:19:58 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG ,
2015-10-30 13:36:04 +01:00
" Enabled uid_wrapper as %s (real uid=%u) " ,
id - > ruid = = 0 ? " root " : " user " ,
( unsigned int ) uwrap . myuid ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-07-31 10:19:58 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Succeccfully initialized uid_wrapper " ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
bool uid_wrapper_enabled ( void )
2009-08-05 11:21:06 +10:00
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
bool enabled ;
if ( id = = NULL ) {
return false ;
}
UWRAP_LOCK ( uwrap_id ) ;
enabled = id - > enabled ;
UWRAP_UNLOCK ( uwrap_id ) ;
2015-01-23 15:15:04 +01:00
return enabled ;
2009-08-05 11:21:06 +10:00
}
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
static int uwrap_getresuid ( uid_t * ruid , uid_t * euid , uid_t * suid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOCK ( uwrap_id ) ;
* ruid = id - > ruid ;
* euid = id - > euid ;
* suid = id - > suid ;
UWRAP_UNLOCK ( uwrap_id ) ;
return 0 ;
}
# endif
2014-01-17 14:43:01 +01:00
static int uwrap_setresuid_thread ( uid_t ruid , uid_t euid , uid_t suid )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
if ( ruid = = ( uid_t ) - 1 & & euid = = ( uid_t ) - 1 & & suid = = ( uid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
if ( ruid ! = ( uid_t ) - 1 ) {
id - > ruid = ruid ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
if ( euid ! = ( uid_t ) - 1 ) {
id - > euid = euid ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
if ( suid ! = ( uid_t ) - 1 ) {
id - > suid = suid ;
}
2015-01-23 15:24:39 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2009-08-05 10:50:03 +10:00
return 0 ;
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
static int uwrap_getresgid ( gid_t * rgid , gid_t * egid , gid_t * sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOCK ( uwrap_id ) ;
* rgid = id - > rgid ;
* egid = id - > egid ;
* sgid = id - > sgid ;
UWRAP_UNLOCK ( uwrap_id ) ;
return 0 ;
}
# endif
2014-01-17 14:43:01 +01:00
static int uwrap_setresuid ( uid_t ruid , uid_t euid , uid_t suid )
{
struct uwrap_thread * id ;
if ( ruid = = ( uid_t ) - 1 & & euid = = ( uid_t ) - 1 & & suid = = ( uid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
for ( id = uwrap . ids ; id ; id = id - > next ) {
if ( ruid ! = ( uid_t ) - 1 ) {
id - > ruid = ruid ;
}
if ( euid ! = ( uid_t ) - 1 ) {
id - > euid = euid ;
}
if ( suid ! = ( uid_t ) - 1 ) {
id - > suid = suid ;
}
}
2015-01-23 15:16:34 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return 0 ;
}
/*
* SETUID
*/
int setuid ( uid_t uid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setuid ( uid ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresuid ( uid , - 1 , - 1 ) ;
}
# ifdef HAVE_SETEUID
int seteuid ( uid_t euid )
{
if ( euid = = ( uid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
if ( ! uid_wrapper_enabled ( ) ) {
return libc_seteuid ( euid ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresuid ( - 1 , euid , - 1 ) ;
}
2011-10-08 10:08:37 +02:00
# endif
2009-08-05 10:50:03 +10:00
2011-10-08 10:08:37 +02:00
# ifdef HAVE_SETREUID
2014-01-17 14:43:01 +01:00
int setreuid ( uid_t ruid , uid_t euid )
2011-10-06 16:25:32 +02:00
{
2014-01-17 14:43:01 +01:00
if ( ruid = = ( uid_t ) - 1 & & euid = = ( uid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
2011-10-06 16:25:32 +02:00
}
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setreuid ( ruid , euid ) ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresuid ( ruid , euid , - 1 ) ;
2011-10-06 16:25:32 +02:00
}
2011-10-08 10:08:37 +02:00
# endif
2011-10-06 16:25:32 +02:00
2011-10-08 10:08:37 +02:00
# ifdef HAVE_SETRESUID
2014-01-17 14:43:01 +01:00
int setresuid ( uid_t ruid , uid_t euid , uid_t suid )
2011-10-07 10:30:23 +02:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setresuid ( ruid , euid , suid ) ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresuid ( ruid , euid , suid ) ;
2011-10-07 10:30:23 +02:00
}
2011-10-08 10:08:37 +02:00
# endif
2011-10-07 10:30:23 +02:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
int getresuid ( uid_t * ruid , uid_t * euid , uid_t * suid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getresuid ( ruid , euid , suid ) ;
}
uwrap_init ( ) ;
return uwrap_getresuid ( ruid , euid , suid ) ;
}
# endif
2014-01-17 14:43:01 +01:00
/*
* GETUID
*/
static uid_t uwrap_getuid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
uid_t uid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
uid = id - > ruid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return uid ;
}
uid_t getuid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getuid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getuid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
/*
* GETEUID
*/
static uid_t uwrap_geteuid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
const char * env = getenv ( " UID_WRAPPER_MYUID " ) ;
struct uwrap_thread * id = uwrap_tls_id ;
uid_t uid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
uid = id - > euid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
/* Disable root and return myuid */
if ( env ! = NULL & & env [ 0 ] = = ' 1 ' ) {
uid = uwrap . myuid ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
return uid ;
}
uid_t geteuid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_geteuid ( ) ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_geteuid ( ) ;
}
static int uwrap_setresgid_thread ( gid_t rgid , gid_t egid , gid_t sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
if ( rgid = = ( gid_t ) - 1 & & egid = = ( gid_t ) - 1 & & sgid = = ( gid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
if ( rgid ! = ( gid_t ) - 1 ) {
id - > rgid = rgid ;
}
if ( egid ! = ( gid_t ) - 1 ) {
id - > egid = egid ;
}
if ( sgid ! = ( gid_t ) - 1 ) {
id - > sgid = sgid ;
}
2015-01-23 15:24:39 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2009-08-05 10:50:03 +10:00
return 0 ;
}
2014-01-17 14:43:01 +01:00
static int uwrap_setresgid ( gid_t rgid , gid_t egid , gid_t sgid )
2011-10-06 16:52:03 +02:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id ;
if ( rgid = = ( gid_t ) - 1 & & egid = = ( gid_t ) - 1 & & sgid = = ( gid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
2011-10-06 16:52:03 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
for ( id = uwrap . ids ; id ; id = id - > next ) {
if ( rgid ! = ( gid_t ) - 1 ) {
id - > rgid = rgid ;
}
if ( egid ! = ( gid_t ) - 1 ) {
id - > egid = egid ;
}
if ( sgid ! = ( gid_t ) - 1 ) {
id - > sgid = sgid ;
}
2011-10-07 18:58:58 +02:00
}
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2011-10-06 16:52:03 +02:00
return 0 ;
}
2014-01-17 14:43:01 +01:00
/*
* SETGID
*/
int setgid ( gid_t gid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setgid ( gid ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresgid ( gid , - 1 , - 1 ) ;
}
# ifdef HAVE_SETEGID
int setegid ( gid_t egid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setegid ( egid ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresgid ( - 1 , egid , - 1 ) ;
}
2011-10-08 10:08:37 +02:00
# endif
2011-10-06 16:52:03 +02:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETREGID
int setregid ( gid_t rgid , gid_t egid )
2011-10-08 10:52:02 +02:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setregid ( rgid , egid ) ;
2011-10-08 10:52:02 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresgid ( rgid , egid , - 1 ) ;
}
# endif
# ifdef HAVE_SETRESGID
int setresgid ( gid_t rgid , gid_t egid , gid_t sgid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setresgid ( rgid , egid , sgid ) ;
2011-10-08 10:52:02 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresgid ( rgid , egid , sgid ) ;
2011-10-08 10:52:02 +02:00
}
# endif
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
int getresgid ( gid_t * rgid , gid_t * egid , gid_t * sgid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getresgid ( rgid , egid , sgid ) ;
}
uwrap_init ( ) ;
return uwrap_getresgid ( rgid , egid , sgid ) ;
}
# endif
2014-01-17 14:43:01 +01:00
/*
* GETGID
*/
static gid_t uwrap_getgid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
gid_t gid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
gid = id - > rgid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return gid ;
}
gid_t getgid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getgid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getgid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
/*
* GETEGID
*/
static uid_t uwrap_getegid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
gid_t gid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
gid = id - > egid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return gid ;
}
uid_t getegid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getegid ( ) ;
2009-08-05 10:50:03 +10:00
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getegid ( ) ;
}
static int uwrap_setgroups_thread ( size_t size , const gid_t * list )
{
struct uwrap_thread * id = uwrap_tls_id ;
int rc = - 1 ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2014-07-31 10:20:40 +02:00
if ( size = = 0 ) {
2015-01-23 15:25:16 +01:00
SAFE_FREE ( id - > groups ) ;
2014-07-31 10:20:40 +02:00
id - > ngroups = 0 ;
} else if ( size > 0 ) {
2014-01-17 14:43:01 +01:00
gid_t * tmp ;
2009-08-05 13:31:06 +10:00
2014-01-17 14:43:01 +01:00
tmp = realloc ( id - > groups , sizeof ( gid_t ) * size ) ;
if ( tmp = = NULL ) {
2009-08-05 13:31:06 +10:00
errno = ENOMEM ;
2014-01-17 14:43:01 +01:00
goto out ;
2009-08-05 13:31:06 +10:00
}
2014-01-17 14:43:01 +01:00
id - > groups = tmp ;
id - > ngroups = size ;
memcpy ( id - > groups , list , size * sizeof ( gid_t ) ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
rc = 0 ;
out :
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return rc ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
static int uwrap_setgroups ( size_t size , const gid_t * list )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id ;
int rc = - 1 ;
2011-02-19 23:21:07 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2014-07-31 10:20:40 +02:00
if ( size = = 0 ) {
for ( id = uwrap . ids ; id ; id = id - > next ) {
2015-01-23 15:25:16 +01:00
SAFE_FREE ( id - > groups ) ;
2014-07-31 10:20:40 +02:00
id - > ngroups = 0 ;
2015-01-23 15:25:16 +01:00
2014-07-31 10:20:40 +02:00
}
} else if ( size > 0 ) {
2015-01-23 15:25:16 +01:00
gid_t * tmp ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:25:16 +01:00
for ( id = uwrap . ids ; id ; id = id - > next ) {
2014-01-17 14:43:01 +01:00
tmp = realloc ( id - > groups , sizeof ( gid_t ) * size ) ;
if ( tmp = = NULL ) {
errno = ENOMEM ;
goto out ;
}
id - > groups = tmp ;
id - > ngroups = size ;
memcpy ( id - > groups , list , size * sizeof ( gid_t ) ) ;
}
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
rc = 0 ;
out :
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return rc ;
}
# ifdef HAVE_SETGROUPS_INT
int setgroups ( int size , const gid_t * list )
# else
int setgroups ( size_t size , const gid_t * list )
# endif
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setgroups ( size , list ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setgroups ( size , list ) ;
}
static int uwrap_getgroups ( int size , gid_t * list )
{
struct uwrap_thread * id = uwrap_tls_id ;
int ngroups ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
ngroups = id - > ngroups ;
2011-02-19 23:21:07 +01:00
if ( size > ngroups ) {
size = ngroups ;
2009-08-05 10:50:03 +10:00
}
if ( size = = 0 ) {
2014-01-17 14:43:01 +01:00
goto out ;
2009-08-05 10:50:03 +10:00
}
2011-02-19 23:21:07 +01:00
if ( size < ngroups ) {
2009-08-05 10:50:03 +10:00
errno = EINVAL ;
2014-01-17 14:43:01 +01:00
ngroups = - 1 ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
memcpy ( list , id - > groups , size * sizeof ( gid_t ) ) ;
out :
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2011-02-19 23:21:07 +01:00
return ngroups ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
int getgroups ( int size , gid_t * list )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getgroups ( size , list ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getgroups ( size , list ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
# if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
& & ( defined ( SYS_setreuid ) | | defined ( SYS_setreuid32 ) )
static long int uwrap_syscall ( long int sysno , va_list vp )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
long int rc ;
switch ( sysno ) {
/* gid */
case SYS_getgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getgid32 :
# endif
{
rc = uwrap_getgid ( ) ;
}
break ;
# ifdef SYS_getegid
case SYS_getegid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getegid32 :
# endif
{
rc = uwrap_getegid ( ) ;
}
break ;
# endif /* SYS_getegid */
case SYS_setgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setgid32 :
# endif
{
2015-01-23 15:28:00 +01:00
gid_t gid = ( gid_t ) va_arg ( vp , gid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresgid_thread ( gid , - 1 , - 1 ) ;
}
break ;
case SYS_setregid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setregid32 :
# endif
{
2015-01-23 15:28:00 +01:00
gid_t rgid = ( gid_t ) va_arg ( vp , gid_t ) ;
gid_t egid = ( gid_t ) va_arg ( vp , gid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresgid_thread ( rgid , egid , - 1 ) ;
}
break ;
# ifdef SYS_setresgid
case SYS_setresgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setresgid32 :
# endif
{
2015-01-23 15:28:00 +01:00
gid_t rgid = ( gid_t ) va_arg ( vp , gid_t ) ;
gid_t egid = ( gid_t ) va_arg ( vp , gid_t ) ;
gid_t sgid = ( gid_t ) va_arg ( vp , gid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresgid_thread ( rgid , egid , sgid ) ;
}
break ;
# endif /* SYS_setresgid */
2015-08-21 11:04:49 +02:00
# if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2015-01-23 15:27:25 +01:00
case SYS_getresgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresgid32 :
# endif
{
gid_t * rgid = ( gid_t * ) va_arg ( vp , gid_t * ) ;
gid_t * egid = ( gid_t * ) va_arg ( vp , gid_t * ) ;
gid_t * sgid = ( gid_t * ) va_arg ( vp , gid_t * ) ;
rc = uwrap_getresgid ( rgid , egid , sgid ) ;
}
break ;
2015-08-21 11:04:49 +02:00
# endif /* SYS_getresgid && HAVE_GETRESGID */
2014-01-17 14:43:01 +01:00
/* uid */
case SYS_getuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getuid32 :
# endif
{
rc = uwrap_getuid ( ) ;
}
break ;
# ifdef SYS_geteuid
case SYS_geteuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_geteuid32 :
# endif
{
rc = uwrap_geteuid ( ) ;
}
break ;
# endif /* SYS_geteuid */
case SYS_setuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setuid32 :
# endif
{
2015-01-23 15:28:00 +01:00
uid_t uid = ( uid_t ) va_arg ( vp , uid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresuid_thread ( uid , - 1 , - 1 ) ;
}
break ;
case SYS_setreuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setreuid32 :
# endif
{
2015-01-23 15:28:00 +01:00
uid_t ruid = ( uid_t ) va_arg ( vp , uid_t ) ;
uid_t euid = ( uid_t ) va_arg ( vp , uid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresuid_thread ( ruid , euid , - 1 ) ;
}
break ;
# ifdef SYS_setresuid
case SYS_setresuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setresuid32 :
# endif
{
2015-01-23 15:28:00 +01:00
uid_t ruid = ( uid_t ) va_arg ( vp , uid_t ) ;
uid_t euid = ( uid_t ) va_arg ( vp , uid_t ) ;
uid_t suid = ( uid_t ) va_arg ( vp , uid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresuid_thread ( ruid , euid , suid ) ;
}
break ;
# endif /* SYS_setresuid */
2015-08-21 11:04:49 +02:00
# if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2015-01-23 15:27:25 +01:00
case SYS_getresuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresuid32 :
# endif
{
uid_t * ruid = ( uid_t * ) va_arg ( vp , uid_t * ) ;
uid_t * euid = ( uid_t * ) va_arg ( vp , uid_t * ) ;
uid_t * suid = ( uid_t * ) va_arg ( vp , uid_t * ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:27:25 +01:00
rc = uwrap_getresuid ( ruid , euid , suid ) ;
}
break ;
2015-08-21 11:04:49 +02:00
# endif /* SYS_getresuid && HAVE_GETRESUID*/
2014-01-17 14:43:01 +01:00
/* groups */
case SYS_setgroups :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setgroups32 :
# endif
{
size_t size = ( size_t ) va_arg ( vp , size_t ) ;
gid_t * list = ( gid_t * ) va_arg ( vp , int * ) ;
rc = uwrap_setgroups_thread ( size , list ) ;
}
break ;
default :
2014-07-31 10:18:59 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG ,
2015-08-21 11:05:24 +02:00
" UID_WRAPPER calling non-wrapped syscall %lu " ,
2014-07-31 10:18:59 +02:00
sysno ) ;
2014-01-17 14:43:01 +01:00
rc = libc_vsyscall ( sysno , vp ) ;
break ;
}
return rc ;
}
# ifdef HAVE_SYSCALL
# ifdef HAVE_SYSCALL_INT
int syscall ( int sysno , . . . )
# else
long int syscall ( long int sysno , . . . )
# endif
{
# ifdef HAVE_SYSCALL_INT
int rc ;
# else
long int rc ;
# endif
va_list va ;
va_start ( va , sysno ) ;
if ( ! uid_wrapper_enabled ( ) ) {
rc = libc_vsyscall ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_syscall ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
# endif /* HAVE_SYSCALL */
# endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2015-01-23 15:10:02 +01:00
/****************************
* CONSTRUCTOR
* * * * * * * * * * * * * * * * * * * * * * * * * * */
void uwrap_constructor ( void )
{
/*
* If we hold a lock and the application forks , then the child
* is not able to unlock the mutex and we are in a deadlock .
* This should prevent such deadlocks .
*/
pthread_atfork ( & uwrap_thread_prepare ,
& uwrap_thread_parent ,
& uwrap_thread_child ) ;
2015-01-23 15:15:04 +01:00
/* Here is safe place to call uwrap_init() and initialize data
* for main process .
*/
uwrap_init ( ) ;
2015-01-23 15:10:02 +01:00
}
2014-01-17 14:43:01 +01:00
/****************************
* DESTRUCTOR
* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* This function is called when the library is unloaded and makes sure that
* resources are freed .
*/
void uwrap_destructor ( void )
{
struct uwrap_thread * u = uwrap . ids ;
2015-01-23 15:29:35 +01:00
UWRAP_LOCK_ALL ;
2015-01-23 15:12:02 +01:00
2014-01-17 14:43:01 +01:00
while ( u ! = NULL ) {
UWRAP_DLIST_REMOVE ( uwrap . ids , u ) ;
SAFE_FREE ( u - > groups ) ;
SAFE_FREE ( u ) ;
u = uwrap . ids ;
}
2015-01-23 15:25:16 +01:00
2014-01-17 14:43:01 +01:00
if ( uwrap . libc . handle ! = NULL ) {
dlclose ( uwrap . libc . handle ) ;
2009-08-05 10:50:03 +10:00
}
2015-01-23 15:12:02 +01:00
2015-01-23 15:30:03 +01:00
if ( uwrap . libpthread . handle ! = NULL ) {
dlclose ( uwrap . libpthread . handle ) ;
}
2015-01-23 15:29:35 +01:00
UWRAP_UNLOCK_ALL ;
2009-08-05 10:50:03 +10:00
}