2008-12-16 11:30:16 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-05-09 15:43:00 +04:00
winbind client common code
Copyright ( C ) Tim Potter 2000
Copyright ( C ) Andrew Tridgell 2000
2002-09-25 19:19:00 +04:00
Copyright ( C ) Andrew Bartlett 2002
2015-01-24 01:35:50 +03:00
Copyright ( C ) Matthew Newton 2015
2008-12-16 11:30:16 +03:00
2000-05-09 15:43:00 +04:00
This library is free software ; you can redistribute it and / or
2007-07-10 08:04:46 +04:00
modify it under the terms of the GNU Lesser General Public
2000-05-09 15:43:00 +04:00
License as published by the Free Software Foundation ; either
2007-07-10 06:31:50 +04:00
version 3 of the License , or ( at your option ) any later version .
2008-12-16 11:30:16 +03:00
2000-05-09 15:43:00 +04:00
This library 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
Library General Public License for more details .
2008-12-16 11:30:16 +03:00
2007-07-10 08:04:46 +04:00
You should have received a copy of the GNU Lesser General Public License
2007-07-10 06:31:50 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-05-09 15:43:00 +04:00
*/
2011-02-18 15:57:35 +03:00
# include "replace.h"
# include "system/select.h"
2002-12-20 04:37:39 +03:00
# include "winbind_client.h"
2023-09-07 16:59:59 +03:00
# include "lib/util/dlinklist.h"
2022-11-06 18:57:27 +03:00
# include <assert.h>
2000-05-09 15:43:00 +04:00
2018-11-20 16:07:39 +03:00
# ifdef HAVE_PTHREAD_H
2018-10-02 14:41:00 +03:00
# include <pthread.h>
# endif
2022-11-06 18:57:27 +03:00
static __thread char client_name [ 32 ] ;
2018-11-02 20:39:26 +03:00
2015-01-24 01:35:50 +03:00
/* Global context */
2000-05-09 15:43:00 +04:00
2015-01-24 01:35:50 +03:00
struct winbindd_context {
2023-09-07 16:59:59 +03:00
struct winbindd_context * prev , * next ;
2015-01-24 01:35:50 +03:00
int winbindd_fd ; /* winbind file descriptor */
bool is_privileged ; /* using the privileged socket? */
pid_t our_pid ; /* calling process pid */
2023-09-07 16:59:59 +03:00
bool autofree ; /* this is a thread global context */
2015-01-24 01:35:50 +03:00
} ;
2022-11-06 18:57:27 +03:00
static struct wb_global_ctx {
2018-11-20 16:07:39 +03:00
# ifdef HAVE_PTHREAD
2022-11-06 18:57:27 +03:00
pthread_once_t control ;
pthread_key_t key ;
2023-09-07 16:59:59 +03:00
bool key_initialized ;
# ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
# define WB_GLOBAL_MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
2022-11-06 18:57:27 +03:00
# else
2023-09-07 16:59:59 +03:00
# define WB_GLOBAL_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
2022-11-06 18:57:27 +03:00
# endif
2023-09-07 16:59:59 +03:00
# define WB_GLOBAL_LIST_LOCK do { \
int __pret = pthread_mutex_lock ( & wb_global_ctx . list_mutex ) ; \
assert ( __pret = = 0 ) ; \
} while ( 0 )
# define WB_GLOBAL_LIST_UNLOCK do { \
int __pret = pthread_mutex_unlock ( & wb_global_ctx . list_mutex ) ; \
assert ( __pret = = 0 ) ; \
} while ( 0 )
pthread_mutex_t list_mutex ;
# else /* => not HAVE_PTHREAD */
# define WB_GLOBAL_LIST_LOCK do { } while(0)
# define WB_GLOBAL_LIST_UNLOCK do { } while(0)
# endif /* not HAVE_PTHREAD */
struct winbindd_context * list ;
2022-11-06 18:57:27 +03:00
} wb_global_ctx = {
# ifdef HAVE_PTHREAD
. control = PTHREAD_ONCE_INIT ,
2023-09-07 16:59:59 +03:00
. list_mutex = WB_GLOBAL_MUTEX_INITIALIZER ,
2018-10-02 14:41:00 +03:00
# endif
2023-09-07 16:59:59 +03:00
. list = NULL ,
2022-11-06 18:57:27 +03:00
} ;
2018-10-02 14:41:00 +03:00
2022-11-06 18:57:27 +03:00
static void winbind_close_sock ( struct winbindd_context * ctx ) ;
2023-09-07 16:59:59 +03:00
static void winbind_ctx_free_locked ( struct winbindd_context * ctx ) ;
static void winbind_cleanup_list ( void ) ;
2022-11-06 18:57:27 +03:00
# ifdef HAVE_PTHREAD
static void wb_thread_ctx_initialize ( void ) ;
2023-09-07 16:59:59 +03:00
static void wb_atfork_prepare ( void )
{
WB_GLOBAL_LIST_LOCK ;
}
static void wb_atfork_parent ( void )
{
WB_GLOBAL_LIST_UNLOCK ;
}
2022-11-06 18:57:27 +03:00
static void wb_atfork_child ( void )
{
2023-09-07 16:59:59 +03:00
wb_global_ctx . list_mutex = ( pthread_mutex_t ) WB_GLOBAL_MUTEX_INITIALIZER ;
2022-11-06 18:57:27 +03:00
2023-09-07 16:59:59 +03:00
if ( wb_global_ctx . key_initialized ) {
int ret ;
2022-11-06 18:57:27 +03:00
2023-09-07 16:59:59 +03:00
/*
* After a fork the child still believes
* it is the same thread as in the parent .
* So pthread_getspecific ( ) would return the
* value of the thread that called fork ( ) .
*
* But we don ' t want that behavior , so
* we just clear the reference and let
* winbind_cleanup_list ( ) below ' autofree '
* the parent threads global context .
*/
ret = pthread_setspecific ( wb_global_ctx . key , NULL ) ;
assert ( ret = = 0 ) ;
}
2022-11-06 18:57:27 +03:00
2023-09-07 16:59:59 +03:00
/*
* But we need to close / cleanup the global state
* of the parents threads .
*/
winbind_cleanup_list ( ) ;
2022-11-06 18:57:27 +03:00
}
static void wb_thread_ctx_destructor ( void * p )
{
struct winbindd_context * ctx = ( struct winbindd_context * ) p ;
2023-09-07 16:59:59 +03:00
winbindd_ctx_free ( ctx ) ;
2022-11-06 18:57:27 +03:00
}
static void wb_thread_ctx_initialize ( void )
{
int ret ;
2023-09-07 16:59:59 +03:00
ret = pthread_atfork ( wb_atfork_prepare ,
wb_atfork_parent ,
2022-11-06 18:57:27 +03:00
wb_atfork_child ) ;
assert ( ret = = 0 ) ;
ret = pthread_key_create ( & wb_global_ctx . key ,
wb_thread_ctx_destructor ) ;
assert ( ret = = 0 ) ;
2023-09-07 16:59:59 +03:00
wb_global_ctx . key_initialized = true ;
2022-11-06 18:57:27 +03:00
}
static struct winbindd_context * get_wb_thread_ctx ( void )
2018-10-02 14:35:16 +03:00
{
2022-11-06 18:57:27 +03:00
struct winbindd_context * ctx = NULL ;
int ret ;
ret = pthread_once ( & wb_global_ctx . control ,
wb_thread_ctx_initialize ) ;
assert ( ret = = 0 ) ;
ctx = ( struct winbindd_context * ) pthread_getspecific (
wb_global_ctx . key ) ;
if ( ctx ! = NULL ) {
return ctx ;
}
ctx = malloc ( sizeof ( struct winbindd_context ) ) ;
if ( ctx = = NULL ) {
return NULL ;
}
* ctx = ( struct winbindd_context ) {
2018-10-02 14:35:16 +03:00
. winbindd_fd = - 1 ,
. is_privileged = false ,
2023-09-07 16:59:59 +03:00
. our_pid = 0 ,
. autofree = true ,
2018-10-02 14:35:16 +03:00
} ;
2023-09-07 16:59:59 +03:00
WB_GLOBAL_LIST_LOCK ;
DLIST_ADD_END ( wb_global_ctx . list , ctx ) ;
WB_GLOBAL_LIST_UNLOCK ;
2022-11-06 18:57:27 +03:00
ret = pthread_setspecific ( wb_global_ctx . key , ctx ) ;
if ( ret ! = 0 ) {
free ( ctx ) ;
return NULL ;
}
return ctx ;
2018-10-02 14:35:16 +03:00
}
2023-09-07 17:02:32 +03:00
# endif /* HAVE_PTHREAD */
2018-10-02 14:35:16 +03:00
2022-11-06 18:57:27 +03:00
static struct winbindd_context * get_wb_global_ctx ( void )
2018-10-02 14:35:16 +03:00
{
2023-01-05 18:25:11 +03:00
struct winbindd_context * ctx = NULL ;
# ifndef HAVE_PTHREAD
static struct winbindd_context _ctx = {
2022-11-06 18:57:27 +03:00
. winbindd_fd = - 1 ,
. is_privileged = false ,
2023-09-07 16:59:59 +03:00
. our_pid = 0 ,
. autofree = false ,
2022-11-06 18:57:27 +03:00
} ;
2018-10-02 14:41:00 +03:00
# endif
2023-01-05 18:25:11 +03:00
# ifdef HAVE_PTHREAD
ctx = get_wb_thread_ctx ( ) ;
# else
ctx = & _ctx ;
2023-09-07 16:59:59 +03:00
if ( ctx - > prev = = NULL & & ctx - > next = = NULL ) {
DLIST_ADD_END ( wb_global_ctx . list , ctx ) ;
}
2023-01-05 18:25:11 +03:00
# endif
return ctx ;
2018-10-02 14:35:16 +03:00
}
2001-07-10 06:28:17 +04:00
2018-11-02 20:57:05 +03:00
void winbind_set_client_name ( const char * name )
{
if ( name = = NULL | | strlen ( name ) = = 0 ) {
return ;
}
( void ) snprintf ( client_name , sizeof ( client_name ) , " %s " , name ) ;
}
2018-11-02 20:39:26 +03:00
static const char * winbind_get_client_name ( void )
{
if ( client_name [ 0 ] = = ' \0 ' ) {
2018-11-12 17:47:46 +03:00
const char * progname = getprogname ( ) ;
2018-11-02 20:39:26 +03:00
int len ;
2018-11-12 17:47:46 +03:00
if ( progname = = NULL ) {
progname = " <unknown> " ;
}
2018-11-02 20:39:26 +03:00
len = snprintf ( client_name ,
sizeof ( client_name ) ,
" %s " ,
2018-11-12 17:47:46 +03:00
progname ) ;
2018-11-02 20:39:26 +03:00
if ( len < = 0 ) {
2018-11-12 17:47:46 +03:00
return progname ;
2018-11-02 20:39:26 +03:00
}
}
return client_name ;
}
2000-07-17 06:37:11 +04:00
/* Initialise a request structure */
2000-05-09 15:43:00 +04:00
2010-01-23 20:06:53 +03:00
static void winbindd_init_request ( struct winbindd_request * request ,
int request_type )
2000-05-09 15:43:00 +04:00
{
2002-01-11 02:45:29 +03:00
request - > length = sizeof ( struct winbindd_request ) ;
2001-08-25 00:32:01 +04:00
request - > cmd = ( enum winbindd_cmd ) request_type ;
2000-07-17 06:37:11 +04:00
request - > pid = getpid ( ) ;
2000-05-09 15:43:00 +04:00
2018-11-02 20:39:26 +03:00
( void ) snprintf ( request - > client_name ,
sizeof ( request - > client_name ) ,
" %s " ,
winbind_get_client_name ( ) ) ;
2000-05-09 15:43:00 +04:00
}
2000-07-17 06:37:11 +04:00
/* Initialise a response structure */
2006-12-20 04:10:04 +03:00
static void init_response ( struct winbindd_response * response )
2000-07-17 06:37:11 +04:00
{
/* Initialise return value */
2001-04-25 09:47:50 +04:00
response - > result = WINBINDD_ERROR ;
2000-07-17 06:37:11 +04:00
}
2000-05-09 15:43:00 +04:00
/* Close established socket */
2015-01-24 01:35:50 +03:00
static void winbind_close_sock ( struct winbindd_context * ctx )
{
if ( ! ctx ) {
return ;
}
if ( ctx - > winbindd_fd ! = - 1 ) {
close ( ctx - > winbindd_fd ) ;
ctx - > winbindd_fd = - 1 ;
}
}
2023-09-07 16:59:59 +03:00
static void winbind_ctx_free_locked ( struct winbindd_context * ctx )
{
winbind_close_sock ( ctx ) ;
DLIST_REMOVE ( wb_global_ctx . list , ctx ) ;
free ( ctx ) ;
}
static void winbind_cleanup_list ( void )
{
struct winbindd_context * ctx = NULL , * next = NULL ;
WB_GLOBAL_LIST_LOCK ;
for ( ctx = wb_global_ctx . list ; ctx ! = NULL ; ctx = next ) {
next = ctx - > next ;
if ( ctx - > autofree ) {
winbind_ctx_free_locked ( ctx ) ;
} else {
winbind_close_sock ( ctx ) ;
}
}
WB_GLOBAL_LIST_UNLOCK ;
}
2015-01-24 01:35:50 +03:00
/* Destructor for global context to ensure fd is closed */
2018-11-20 16:07:39 +03:00
# ifdef HAVE_DESTRUCTOR_ATTRIBUTE
2010-05-10 14:05:01 +04:00
__attribute__ ( ( destructor ) )
2020-10-30 14:59:06 +03:00
# elif defined (HAVE_PRAGMA_FINI)
# pragma fini (winbind_destructor)
2010-05-10 14:05:01 +04:00
# endif
2015-01-24 01:35:50 +03:00
static void winbind_destructor ( void )
2000-05-09 15:43:00 +04:00
{
2023-09-07 16:59:59 +03:00
# ifdef HAVE_PTHREAD
if ( wb_global_ctx . key_initialized ) {
int ret ;
ret = pthread_key_delete ( wb_global_ctx . key ) ;
assert ( ret = = 0 ) ;
wb_global_ctx . key_initialized = false ;
2023-01-05 18:25:11 +03:00
}
2023-09-07 16:59:59 +03:00
wb_global_ctx . control = ( pthread_once_t ) PTHREAD_ONCE_INIT ;
# endif /* HAVE_PTHREAD */
2022-11-06 18:57:27 +03:00
2023-09-07 16:59:59 +03:00
winbind_cleanup_list ( ) ;
2000-05-09 15:43:00 +04:00
}
2004-05-12 02:09:09 +04:00
# define CONNECT_TIMEOUT 30
2002-09-25 19:19:00 +04:00
/* Make sure socket handle isn't stdin, stdout or stderr */
# define RECURSION_LIMIT 3
2008-12-16 11:30:16 +03:00
static int make_nonstd_fd_internals ( int fd , int limit /* Recursion limiter */ )
2002-09-25 19:19:00 +04:00
{
int new_fd ;
if ( fd > = 0 & & fd < = 2 ) {
2008-12-16 11:30:16 +03:00
# ifdef F_DUPFD
2002-09-25 19:19:00 +04:00
if ( ( new_fd = fcntl ( fd , F_DUPFD , 3 ) ) = = - 1 ) {
return - 1 ;
}
2003-10-21 08:38:23 +04:00
/* Paranoia */
2002-09-25 19:19:00 +04:00
if ( new_fd < 3 ) {
close ( new_fd ) ;
return - 1 ;
}
close ( fd ) ;
return new_fd ;
# else
if ( limit < = 0 )
return - 1 ;
2008-12-16 11:30:16 +03:00
2002-09-25 19:19:00 +04:00
new_fd = dup ( fd ) ;
2008-12-16 11:30:16 +03:00
if ( new_fd = = - 1 )
2002-09-25 19:19:00 +04:00
return - 1 ;
/* use the program stack to hold our list of FDs to close */
new_fd = make_nonstd_fd_internals ( new_fd , limit - 1 ) ;
close ( fd ) ;
return new_fd ;
# endif
}
return fd ;
}
2004-05-12 02:09:09 +04:00
/****************************************************************************
Set a fd into blocking / nonblocking mode . Uses POSIX O_NONBLOCK if available ,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
Set close on exec also .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-16 11:30:16 +03:00
static int make_safe_fd ( int fd )
2002-09-25 19:19:00 +04:00
{
int result , flags ;
int new_fd = make_nonstd_fd_internals ( fd , RECURSION_LIMIT ) ;
if ( new_fd = = - 1 ) {
close ( fd ) ;
return - 1 ;
}
2004-05-12 02:09:09 +04:00
/* Socket should be nonblocking. */
# ifdef O_NONBLOCK
# define FLAG_TO_SET O_NONBLOCK
# else
# ifdef SYSV
# define FLAG_TO_SET O_NDELAY
# else /* BSD */
# define FLAG_TO_SET FNDELAY
# endif
# endif
if ( ( flags = fcntl ( new_fd , F_GETFL ) ) = = - 1 ) {
close ( new_fd ) ;
return - 1 ;
}
flags | = FLAG_TO_SET ;
if ( fcntl ( new_fd , F_SETFL , flags ) = = - 1 ) {
close ( new_fd ) ;
return - 1 ;
}
# undef FLAG_TO_SET
2002-09-25 19:19:00 +04:00
/* Socket should be closed on exec() */
# ifdef FD_CLOEXEC
result = flags = fcntl ( new_fd , F_GETFD , 0 ) ;
if ( flags > = 0 ) {
flags | = FD_CLOEXEC ;
result = fcntl ( new_fd , F_SETFD , flags ) ;
}
if ( result < 0 ) {
close ( new_fd ) ;
return - 1 ;
}
# endif
return new_fd ;
}
2013-09-09 18:28:18 +04:00
/**
* @ internal
*
2021-05-06 12:43:51 +03:00
* @ brief Check if we talk to the privileged pipe which should be owned by root .
2013-09-09 18:28:18 +04:00
*
2014-05-16 11:50:42 +04:00
* This checks if we have uid_wrapper running and if this is the case it will
2015-07-27 00:02:57 +03:00
* allow one to connect to the winbind privileged pipe even it is not owned by root .
2013-09-09 18:28:18 +04:00
*
2014-05-16 11:50:42 +04:00
* @ param [ in ] uid The uid to check if we can safely talk to the pipe .
2013-09-09 18:28:18 +04:00
*
* @ return If we have access it returns true , else false .
*/
2014-05-16 11:50:42 +04:00
static bool winbind_privileged_pipe_is_root ( uid_t uid )
2013-09-09 18:28:18 +04:00
{
2014-05-16 11:50:42 +04:00
if ( uid = = 0 ) {
return true ;
2013-09-09 18:28:18 +04:00
}
if ( uid_wrapper_enabled ( ) ) {
2014-05-16 11:50:42 +04:00
return true ;
2013-09-09 18:28:18 +04:00
}
2014-05-16 11:50:42 +04:00
return false ;
2013-09-09 18:28:18 +04:00
}
2000-05-09 15:43:00 +04:00
/* Connect to winbindd socket */
2003-03-24 12:54:13 +03:00
static int winbind_named_pipe_sock ( const char * dir )
2000-05-09 15:43:00 +04:00
{
2000-06-30 10:48:47 +04:00
struct sockaddr_un sunaddr ;
struct stat st ;
2002-09-25 19:19:00 +04:00
int fd ;
2004-05-12 02:09:09 +04:00
int wait_time ;
int slept ;
2015-03-01 14:43:01 +03:00
int ret ;
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Check permissions on unix socket directory */
2007-11-27 04:24:56 +03:00
2003-03-24 12:54:13 +03:00
if ( lstat ( dir , & st ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
2014-05-16 11:50:42 +04:00
/*
* This tells us that the pipe is owned by a privileged
* process , as we will be sending passwords to it .
*/
2007-11-27 04:24:56 +03:00
if ( ! S_ISDIR ( st . st_mode ) | |
2014-05-16 11:50:42 +04:00
! winbind_privileged_pipe_is_root ( st . st_uid ) ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Connect to socket */
2007-11-27 04:24:56 +03:00
2015-03-01 14:43:01 +03:00
sunaddr = ( struct sockaddr_un ) { . sun_family = AF_UNIX } ;
ret = snprintf ( sunaddr . sun_path , sizeof ( sunaddr . sun_path ) ,
" %s/%s " , dir , WINBINDD_SOCKET_NAME ) ;
if ( ( ret = = - 1 ) | | ( ret > = sizeof ( sunaddr . sun_path ) ) ) {
errno = ENAMETOOLONG ;
2007-11-27 04:24:56 +03:00
return - 1 ;
}
2000-06-30 10:48:47 +04:00
/* If socket file doesn't exist, don't bother trying to connect
with retry . This is an attempt to make the system usable when
the winbindd daemon is not running . */
2000-05-09 15:43:00 +04:00
2015-03-01 14:43:01 +03:00
if ( lstat ( sunaddr . sun_path , & st ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Check permissions on unix socket file */
2007-11-27 04:24:56 +03:00
2014-05-16 11:50:42 +04:00
/*
* This tells us that the pipe is owned by a privileged
* process , as we will be sending passwords to it .
*/
2007-11-27 04:24:56 +03:00
if ( ! S_ISSOCK ( st . st_mode ) | |
2014-05-16 11:50:42 +04:00
! winbind_privileged_pipe_is_root ( st . st_uid ) ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2007-11-27 04:24:56 +03:00
2000-06-30 10:48:47 +04:00
/* Connect to socket */
2007-11-27 04:24:56 +03:00
2002-09-25 19:19:00 +04:00
if ( ( fd = socket ( AF_UNIX , SOCK_STREAM , 0 ) ) = = - 1 ) {
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2002-09-25 19:19:00 +04:00
2004-05-12 02:09:09 +04:00
/* Set socket non-blocking and close on exec. */
2003-03-24 12:54:13 +03:00
if ( ( fd = make_safe_fd ( fd ) ) = = - 1 ) {
return fd ;
2002-09-25 19:19:00 +04:00
}
2004-05-12 02:09:09 +04:00
for ( wait_time = 0 ; connect ( fd , ( struct sockaddr * ) & sunaddr , sizeof ( sunaddr ) ) = = - 1 ;
wait_time + = slept ) {
2011-02-18 15:57:35 +03:00
struct pollfd pfd ;
2005-10-18 07:24:00 +04:00
int connect_errno = 0 ;
socklen_t errnosize ;
2004-05-12 02:09:09 +04:00
if ( wait_time > = CONNECT_TIMEOUT )
goto error_out ;
switch ( errno ) {
case EINPROGRESS :
2011-02-18 15:57:35 +03:00
pfd . fd = fd ;
pfd . events = POLLOUT ;
2004-05-12 02:09:09 +04:00
2011-02-18 15:57:35 +03:00
ret = poll ( & pfd , 1 , ( CONNECT_TIMEOUT - wait_time ) * 1000 ) ;
2004-05-12 02:09:09 +04:00
if ( ret > 0 ) {
errnosize = sizeof ( connect_errno ) ;
ret = getsockopt ( fd , SOL_SOCKET ,
SO_ERROR , & connect_errno , & errnosize ) ;
if ( ret > = 0 & & connect_errno = = 0 ) {
/* Connect succeed */
goto out ;
}
}
slept = CONNECT_TIMEOUT ;
break ;
case EAGAIN :
slept = rand ( ) % 3 + 1 ;
sleep ( slept ) ;
break ;
default :
goto error_out ;
}
}
out :
return fd ;
error_out :
close ( fd ) ;
return - 1 ;
2003-03-24 12:54:13 +03:00
}
2007-09-15 22:55:04 +04:00
static const char * winbindd_socket_dir ( void )
{
2014-02-13 18:53:29 +04:00
if ( nss_wrapper_enabled ( ) ) {
const char * env_dir ;
2007-09-15 22:55:04 +04:00
2014-02-20 13:34:49 +04:00
env_dir = getenv ( " SELFTEST_WINBINDD_SOCKET_DIR " ) ;
2014-02-13 18:53:29 +04:00
if ( env_dir ! = NULL ) {
return env_dir ;
}
2007-09-15 22:55:04 +04:00
}
return WINBINDD_SOCKET_DIR ;
}
2003-03-24 12:54:13 +03:00
/* Connect to winbindd socket */
2015-01-24 01:35:50 +03:00
static int winbind_open_pipe_sock ( struct winbindd_context * ctx ,
int recursing , int need_priv )
2003-03-24 12:54:13 +03:00
{
# ifdef HAVE_UNIXSOCKET
struct winbindd_request request ;
struct winbindd_response response ;
2015-01-24 01:35:50 +03:00
2003-03-24 12:54:13 +03:00
ZERO_STRUCT ( request ) ;
ZERO_STRUCT ( response ) ;
2015-01-24 01:35:50 +03:00
if ( ! ctx ) {
return - 1 ;
2003-03-24 12:54:13 +03:00
}
2007-03-23 00:41:36 +03:00
2015-01-24 01:35:50 +03:00
if ( ctx - > our_pid ! = getpid ( ) ) {
winbind_close_sock ( ctx ) ;
ctx - > our_pid = getpid ( ) ;
2007-03-23 00:41:36 +03:00
}
2008-10-28 09:36:36 +03:00
2018-05-04 16:23:18 +03:00
if ( ( need_priv ! = 0 ) & & ! ctx - > is_privileged ) {
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
}
if ( ctx - > winbindd_fd ! = - 1 ) {
return ctx - > winbindd_fd ;
2003-03-24 12:54:13 +03:00
}
2005-09-19 22:49:18 +04:00
if ( recursing ) {
return - 1 ;
}
2015-01-24 01:35:50 +03:00
ctx - > winbindd_fd = winbind_named_pipe_sock ( winbindd_socket_dir ( ) ) ;
if ( ctx - > winbindd_fd = = - 1 ) {
2003-03-24 12:54:13 +03:00
return - 1 ;
}
2018-05-04 16:23:18 +03:00
ctx - > is_privileged = false ;
2007-03-23 00:41:36 +03:00
2003-03-24 12:54:13 +03:00
/* version-check the socket */
2007-08-28 19:16:42 +04:00
request . wb_flags = WBFLAG_RECURSE ;
2015-01-24 01:35:50 +03:00
if ( ( winbindd_request_response ( ctx , WINBINDD_INTERFACE_VERSION , & request ,
& response ) ! = NSS_STATUS_SUCCESS ) | |
( response . data . interface_version ! = WINBIND_INTERFACE_VERSION ) ) {
winbind_close_sock ( ctx ) ;
2003-03-24 12:54:13 +03:00
return - 1 ;
}
2018-04-23 13:13:40 +03:00
if ( need_priv = = 0 ) {
return ctx - > winbindd_fd ;
}
2003-03-24 12:54:13 +03:00
/* try and get priv pipe */
2007-08-28 19:16:42 +04:00
request . wb_flags = WBFLAG_RECURSE ;
2014-05-07 12:00:46 +04:00
/* Note that response needs to be initialized to avoid
* crashing on clean up after WINBINDD_PRIV_PIPE_DIR call failed
* as interface version ( from the first request ) returned as a fstring ,
* thus response . extra_data . data will not be NULL even though
* winbindd response did not write over it due to a failure */
ZERO_STRUCT ( response ) ;
2015-01-24 01:35:50 +03:00
if ( winbindd_request_response ( ctx , WINBINDD_PRIV_PIPE_DIR , & request ,
& response ) = = NSS_STATUS_SUCCESS ) {
2003-03-24 12:54:13 +03:00
int fd ;
2015-01-24 01:35:50 +03:00
fd = winbind_named_pipe_sock ( ( char * ) response . extra_data . data ) ;
if ( fd ! = - 1 ) {
close ( ctx - > winbindd_fd ) ;
ctx - > winbindd_fd = fd ;
2018-05-04 16:23:18 +03:00
ctx - > is_privileged = true ;
2003-03-24 12:54:13 +03:00
}
2018-04-24 11:59:05 +03:00
SAFE_FREE ( response . extra_data . data ) ;
2003-03-24 12:54:13 +03:00
}
2018-05-04 16:23:18 +03:00
if ( ! ctx - > is_privileged ) {
2007-03-23 00:41:36 +03:00
return - 1 ;
}
2015-01-24 01:35:50 +03:00
return ctx - > winbindd_fd ;
2002-09-25 19:19:00 +04:00
# else
return - 1 ;
# endif /* HAVE_UNIXSOCKET */
2000-05-09 15:43:00 +04:00
}
2002-07-15 14:35:28 +04:00
/* Write data to winbindd socket */
2000-05-09 15:43:00 +04:00
2015-01-24 01:35:50 +03:00
static int winbind_write_sock ( struct winbindd_context * ctx , void * buffer ,
int count , int recursing , int need_priv )
2000-05-09 15:43:00 +04:00
{
2011-06-05 18:39:36 +04:00
int fd , result , nwritten ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Open connection to winbind daemon */
2008-12-16 11:30:16 +03:00
2000-05-09 15:43:00 +04:00
restart :
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
fd = winbind_open_pipe_sock ( ctx , recursing , need_priv ) ;
2011-06-05 18:39:36 +04:00
if ( fd = = - 1 ) {
2008-08-20 22:00:40 +04:00
errno = ENOENT ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Write data to socket */
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
nwritten = 0 ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
while ( nwritten < count ) {
2011-02-18 15:57:35 +03:00
struct pollfd pfd ;
int ret ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Catch pipe close on other end by checking if a read()
2011-02-18 15:57:35 +03:00
call would not block by calling poll ( ) . */
2000-06-30 10:48:47 +04:00
2011-06-05 18:39:36 +04:00
pfd . fd = fd ;
2013-10-15 12:23:10 +04:00
pfd . events = POLLIN | POLLOUT | POLLHUP ;
2008-12-16 11:30:16 +03:00
2013-10-15 12:23:10 +04:00
ret = poll ( & pfd , 1 , - 1 ) ;
2011-02-18 15:57:35 +03:00
if ( ret = = - 1 ) {
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
2011-02-18 15:57:35 +03:00
return - 1 ; /* poll error */
2000-06-30 10:48:47 +04:00
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Write should be OK if fd not available for reading */
2008-12-16 11:30:16 +03:00
2011-02-18 15:57:35 +03:00
if ( ( ret = = 1 ) & & ( pfd . revents & ( POLLIN | POLLHUP | POLLERR ) ) ) {
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
/* Pipe has closed on remote end */
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
2011-02-10 16:59:39 +03:00
goto restart ;
}
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
/* Do the write */
2008-12-16 11:30:16 +03:00
2011-06-05 18:39:36 +04:00
result = write ( fd , ( char * ) buffer + nwritten ,
2011-02-10 16:59:39 +03:00
count - nwritten ) ;
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
if ( ( result = = - 1 ) | | ( result = = 0 ) ) {
2008-12-16 11:30:16 +03:00
2011-02-10 16:59:39 +03:00
/* Write failed */
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
2011-02-10 16:59:39 +03:00
return - 1 ;
2000-06-30 10:48:47 +04:00
}
2011-02-10 16:59:39 +03:00
nwritten + = result ;
2000-06-30 10:48:47 +04:00
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
return nwritten ;
2000-05-09 15:43:00 +04:00
}
2002-07-15 14:35:28 +04:00
/* Read data from winbindd socket */
2000-05-09 15:43:00 +04:00
2015-01-24 01:35:50 +03:00
static int winbind_read_sock ( struct winbindd_context * ctx ,
void * buffer , int count )
2000-05-09 15:43:00 +04:00
{
2011-06-05 18:39:36 +04:00
int fd ;
2007-08-22 17:51:44 +04:00
int nread = 0 ;
2011-02-18 15:57:35 +03:00
int total_time = 0 ;
2000-05-09 15:43:00 +04:00
2015-01-24 01:35:50 +03:00
fd = winbind_open_pipe_sock ( ctx , false , false ) ;
2011-06-05 18:39:36 +04:00
if ( fd = = - 1 ) {
2006-03-29 22:55:39 +04:00
return - 1 ;
}
2000-06-30 10:48:47 +04:00
/* Read data from socket */
while ( nread < count ) {
2011-02-18 15:57:35 +03:00
struct pollfd pfd ;
int ret ;
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
/* Catch pipe close on other end by checking if a read()
2011-02-18 15:57:35 +03:00
call would not block by calling poll ( ) . */
2011-06-05 18:39:36 +04:00
pfd . fd = fd ;
2011-02-18 15:57:35 +03:00
pfd . events = POLLIN | POLLHUP ;
2004-05-13 22:37:54 +04:00
/* Wait for 5 seconds for a reply. May need to parameterise this... */
2011-02-18 15:57:35 +03:00
ret = poll ( & pfd , 1 , 5000 ) ;
if ( ret = = - 1 ) {
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
2011-02-18 15:57:35 +03:00
return - 1 ; /* poll error */
2004-05-13 22:37:54 +04:00
}
2008-12-16 11:30:16 +03:00
2011-02-18 15:57:35 +03:00
if ( ret = = 0 ) {
2004-05-13 22:37:54 +04:00
/* Not ready for read yet... */
2015-06-03 00:36:27 +03:00
if ( total_time > = 300 ) {
2004-05-13 22:37:54 +04:00
/* Timeout */
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
2004-05-13 22:37:54 +04:00
return - 1 ;
}
total_time + = 5 ;
continue ;
}
2011-02-18 15:57:35 +03:00
if ( ( ret = = 1 ) & & ( pfd . revents & ( POLLIN | POLLHUP | POLLERR ) ) ) {
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
/* Do the Read */
2008-12-16 11:30:16 +03:00
2011-06-05 18:39:36 +04:00
int result = read ( fd , ( char * ) buffer + nread ,
2004-05-13 22:37:54 +04:00
count - nread ) ;
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
if ( ( result = = - 1 ) | | ( result = = 0 ) ) {
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
/* Read failed. I think the only useful thing we
can do here is just return - 1 and fail since the
transaction has failed half way through . */
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
winbind_close_sock ( ctx ) ;
2004-05-13 22:37:54 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2004-05-13 22:37:54 +04:00
nread + = result ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
}
}
2008-12-16 11:30:16 +03:00
2007-08-22 17:51:44 +04:00
return nread ;
2000-05-09 15:43:00 +04:00
}
/* Read reply */
2015-01-24 01:35:50 +03:00
static int winbindd_read_reply ( struct winbindd_context * ctx ,
struct winbindd_response * response )
2000-05-09 15:43:00 +04:00
{
2000-06-30 10:48:47 +04:00
int result1 , result2 = 0 ;
2000-05-09 15:43:00 +04:00
2000-06-30 10:48:47 +04:00
if ( ! response ) {
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Read fixed length response */
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
result1 = winbind_read_sock ( ctx , response ,
2007-09-14 11:07:59 +04:00
sizeof ( struct winbindd_response ) ) ;
2015-01-08 18:11:15 +03:00
/* We actually send the pointer value of the extra_data field from
the server . This has no meaning in the client ' s address space
so we clear it out . */
response - > extra_data . data = NULL ;
2007-09-14 11:07:59 +04:00
if ( result1 = = - 1 ) {
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2011-03-09 12:58:47 +03:00
if ( response - > length < sizeof ( struct winbindd_response ) ) {
return - 1 ;
}
2000-06-30 10:48:47 +04:00
/* Read variable length response */
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
if ( response - > length > sizeof ( struct winbindd_response ) ) {
2008-12-16 11:30:16 +03:00
int extra_data_len = response - > length -
2000-06-30 10:48:47 +04:00
sizeof ( struct winbindd_response ) ;
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Mallocate memory for extra data */
2008-12-16 11:30:16 +03:00
2007-02-16 23:02:13 +03:00
if ( ! ( response - > extra_data . data = malloc ( extra_data_len ) ) ) {
2000-06-30 10:48:47 +04:00
return - 1 ;
}
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
result2 = winbind_read_sock ( ctx , response - > extra_data . data ,
2007-09-14 11:07:59 +04:00
extra_data_len ) ;
if ( result2 = = - 1 ) {
winbindd_free_response ( response ) ;
2000-06-30 10:48:47 +04:00
return - 1 ;
}
}
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
/* Return total amount of data read */
2008-12-16 11:30:16 +03:00
2000-06-30 10:48:47 +04:00
return result1 + result2 ;
2000-05-09 15:43:00 +04:00
}
2008-12-16 11:30:16 +03:00
/*
* send simple types of requests
2001-12-22 03:51:32 +03:00
*/
2000-06-14 13:58:12 +04:00
2018-05-04 15:40:12 +03:00
static NSS_STATUS winbindd_send_request (
struct winbindd_context * ctx ,
int req_type ,
int need_priv ,
struct winbindd_request * request )
2000-06-14 13:58:12 +04:00
{
struct winbindd_request lrequest ;
2006-10-20 02:34:58 +04:00
2000-06-14 13:58:12 +04:00
/* Check for our tricky environment variable */
2006-10-20 02:34:58 +04:00
if ( winbind_env_set ( ) ) {
return NSS_STATUS_NOTFOUND ;
2000-06-14 13:58:12 +04:00
}
2000-06-30 10:48:47 +04:00
if ( ! request ) {
ZERO_STRUCT ( lrequest ) ;
request = & lrequest ;
}
2008-12-16 11:30:16 +03:00
2000-06-14 13:58:12 +04:00
/* Fill in request and send down pipe */
2000-07-17 06:37:11 +04:00
2007-09-14 11:07:59 +04:00
winbindd_init_request ( request , req_type ) ;
2008-12-16 11:30:16 +03:00
2015-01-24 01:35:50 +03:00
if ( winbind_write_sock ( ctx , request , sizeof ( * request ) ,
2007-09-14 11:07:59 +04:00
request - > wb_flags & WBFLAG_RECURSE ,
2008-12-16 11:30:16 +03:00
need_priv ) = = - 1 )
2008-08-20 22:00:40 +04:00
{
/* Set ENOENT for consistency. Required by some apps */
errno = ENOENT ;
2008-12-16 11:30:16 +03:00
2000-06-14 13:58:12 +04:00
return NSS_STATUS_UNAVAIL ;
}
2005-09-30 21:13:37 +04:00
if ( ( request - > extra_len ! = 0 ) & &
2015-01-24 01:35:50 +03:00
( winbind_write_sock ( ctx , request - > extra_data . data ,
2008-12-16 11:30:16 +03:00
request - > extra_len ,
2007-09-14 11:07:59 +04:00
request - > wb_flags & WBFLAG_RECURSE ,
2008-12-16 11:30:16 +03:00
need_priv ) = = - 1 ) )
2008-08-20 22:00:40 +04:00
{
/* Set ENOENT for consistency. Required by some apps */
errno = ENOENT ;
2005-09-30 21:13:37 +04:00
return NSS_STATUS_UNAVAIL ;
}
2008-12-16 11:30:16 +03:00
2001-12-22 03:51:32 +03:00
return NSS_STATUS_SUCCESS ;
}
/*
* Get results from winbindd request
*/
2018-05-04 15:40:12 +03:00
static NSS_STATUS winbindd_get_response ( struct winbindd_context * ctx ,
struct winbindd_response * response )
2001-12-22 03:51:32 +03:00
{
struct winbindd_response lresponse ;
if ( ! response ) {
ZERO_STRUCT ( lresponse ) ;
response = & lresponse ;
}
init_response ( response ) ;
2000-06-14 13:58:12 +04:00
/* Wait for reply */
2015-01-24 01:35:50 +03:00
if ( winbindd_read_reply ( ctx , response ) = = - 1 ) {
2008-08-20 22:00:40 +04:00
/* Set ENOENT for consistency. Required by some apps */
errno = ENOENT ;
2000-06-14 13:58:12 +04:00
return NSS_STATUS_UNAVAIL ;
}
/* Throw away extra data if client didn't request it */
if ( response = = & lresponse ) {
2007-09-14 11:07:59 +04:00
winbindd_free_response ( response ) ;
2000-06-14 13:58:12 +04:00
}
/* Copy reply data from socket */
if ( response - > result ! = WINBINDD_OK ) {
return NSS_STATUS_NOTFOUND ;
}
2008-12-16 11:30:16 +03:00
2000-06-14 13:58:12 +04:00
return NSS_STATUS_SUCCESS ;
}
2001-12-22 03:51:32 +03:00
/* Handle simple types of requests */
2015-01-24 01:35:50 +03:00
NSS_STATUS winbindd_request_response ( struct winbindd_context * ctx ,
int req_type ,
struct winbindd_request * request ,
struct winbindd_response * response )
2001-12-22 03:51:32 +03:00
{
2005-05-31 22:36:38 +04:00
NSS_STATUS status = NSS_STATUS_UNAVAIL ;
2015-01-24 01:35:50 +03:00
if ( ctx = = NULL ) {
2018-10-02 14:35:16 +03:00
ctx = get_wb_global_ctx ( ) ;
2015-01-24 01:35:50 +03:00
}
2001-12-22 03:51:32 +03:00
2017-07-15 12:54:14 +03:00
status = winbindd_send_request ( ctx , req_type , 0 , request ) ;
2018-10-02 11:58:12 +03:00
if ( status ! = NSS_STATUS_SUCCESS ) {
goto out ;
}
2017-07-15 12:54:14 +03:00
status = winbindd_get_response ( ctx , response ) ;
2007-03-23 00:41:36 +03:00
2018-10-02 11:58:12 +03:00
out :
2007-03-23 00:41:36 +03:00
return status ;
}
2015-01-24 01:35:50 +03:00
NSS_STATUS winbindd_priv_request_response ( struct winbindd_context * ctx ,
int req_type ,
2007-03-23 00:41:36 +03:00
struct winbindd_request * request ,
struct winbindd_response * response )
{
NSS_STATUS status = NSS_STATUS_UNAVAIL ;
2015-01-24 01:35:50 +03:00
if ( ctx = = NULL ) {
2018-10-02 14:35:16 +03:00
ctx = get_wb_global_ctx ( ) ;
2015-01-24 01:35:50 +03:00
}
2007-03-23 00:41:36 +03:00
2017-07-15 12:54:14 +03:00
status = winbindd_send_request ( ctx , req_type , 1 , request ) ;
2018-10-02 11:58:12 +03:00
if ( status ! = NSS_STATUS_SUCCESS ) {
goto out ;
}
2017-07-15 12:54:14 +03:00
status = winbindd_get_response ( ctx , response ) ;
2005-05-31 22:36:38 +04:00
2018-10-02 11:58:12 +03:00
out :
2005-05-31 22:36:38 +04:00
return status ;
2001-12-22 03:51:32 +03:00
}
2015-01-24 01:35:50 +03:00
/* Create and free winbindd context */
struct winbindd_context * winbindd_ctx_create ( void )
{
struct winbindd_context * ctx ;
ctx = calloc ( 1 , sizeof ( struct winbindd_context ) ) ;
if ( ! ctx ) {
return NULL ;
}
ctx - > winbindd_fd = - 1 ;
2023-09-07 16:59:59 +03:00
WB_GLOBAL_LIST_LOCK ;
DLIST_ADD_END ( wb_global_ctx . list , ctx ) ;
WB_GLOBAL_LIST_UNLOCK ;
2015-01-24 01:35:50 +03:00
return ctx ;
}
void winbindd_ctx_free ( struct winbindd_context * ctx )
{
2023-09-07 16:59:59 +03:00
WB_GLOBAL_LIST_LOCK ;
winbind_ctx_free_locked ( ctx ) ;
WB_GLOBAL_LIST_UNLOCK ;
2015-01-24 01:35:50 +03:00
}