2008-12-27 20:43:03 +03:00
/*
Unix SMB / CIFS implementation .
Infrastructure for async winbind requests
Copyright ( C ) Volker Lendecke 2008
2009-05-29 16:15:51 +04:00
* * NOTE ! The following LGPL license applies to the wbclient
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
2008-12-27 20:43:03 +03:00
2009-05-29 16:15:51 +04:00
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
2008-12-27 20:43:03 +03:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-05-29 16:15:51 +04:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Library General Public License for more details .
2008-12-27 20:43:03 +03:00
2009-05-29 16:15:51 +04:00
You should have received a copy of the GNU Lesser General Public License
2008-12-27 20:43:03 +03:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2009-04-16 16:53:36 +04:00
# include "replace.h"
# include "system/filesys.h"
# include "system/network.h"
# include <talloc.h>
# include <tevent.h>
# include "lib/async_req/async_sock.h"
# include "nsswitch/winbind_struct_protocol.h"
# include "nsswitch/libwbclient/wbclient.h"
2010-12-08 22:11:46 +03:00
# include "wbc_async.h"
2008-12-27 20:43:03 +03:00
2009-05-06 17:10:00 +04:00
wbcErr map_wbc_err_from_errno ( int error )
{
switch ( error ) {
case EPERM :
case EACCES :
return WBC_ERR_AUTH_ERROR ;
case ENOMEM :
return WBC_ERR_NO_MEMORY ;
case EIO :
default :
return WBC_ERR_UNKNOWN_FAILURE ;
}
}
bool tevent_req_is_wbcerr ( struct tevent_req * req , wbcErr * pwbc_err )
{
enum tevent_req_state state ;
uint64_t error ;
if ( ! tevent_req_is_error ( req , & state , & error ) ) {
* pwbc_err = WBC_ERR_SUCCESS ;
return false ;
}
switch ( state ) {
case TEVENT_REQ_USER_ERROR :
* pwbc_err = error ;
break ;
case TEVENT_REQ_TIMED_OUT :
* pwbc_err = WBC_ERR_UNKNOWN_FAILURE ;
break ;
case TEVENT_REQ_NO_MEMORY :
* pwbc_err = WBC_ERR_NO_MEMORY ;
break ;
default :
* pwbc_err = WBC_ERR_UNKNOWN_FAILURE ;
break ;
}
return true ;
}
wbcErr tevent_req_simple_recv_wbcerr ( struct tevent_req * req )
{
wbcErr wbc_err ;
if ( tevent_req_is_wbcerr ( req , & wbc_err ) ) {
return wbc_err ;
}
return WBC_ERR_SUCCESS ;
}
2009-06-02 01:33:27 +04:00
struct wbc_debug_ops {
void ( * debug ) ( void * context , enum wbcDebugLevel level ,
const char * fmt , va_list ap ) PRINTF_ATTRIBUTE ( 3 , 0 ) ;
void * context ;
} ;
2009-03-16 22:23:37 +03:00
struct wb_context {
2009-03-16 22:38:11 +03:00
struct tevent_queue * queue ;
2009-03-16 22:23:37 +03:00
int fd ;
bool is_priv ;
2009-04-21 11:58:42 +04:00
const char * dir ;
2009-06-02 01:33:27 +04:00
struct wbc_debug_ops debug_ops ;
2009-03-16 22:23:37 +03:00
} ;
2008-12-27 20:43:03 +03:00
static int make_nonstd_fd ( int fd )
{
int i ;
int sys_errno = 0 ;
int fds [ 3 ] ;
int num_fds = 0 ;
if ( fd = = - 1 ) {
return - 1 ;
}
while ( fd < 3 ) {
fds [ num_fds + + ] = fd ;
fd = dup ( fd ) ;
if ( fd = = - 1 ) {
sys_errno = errno ;
break ;
}
}
for ( i = 0 ; i < num_fds ; i + + ) {
close ( fds [ i ] ) ;
}
if ( fd = = - 1 ) {
errno = sys_errno ;
}
return fd ;
}
/****************************************************************************
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int make_safe_fd ( int fd )
{
int result , flags ;
int new_fd = make_nonstd_fd ( fd ) ;
if ( new_fd = = - 1 ) {
goto fail ;
}
/* 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 ) {
goto fail ;
}
flags | = FLAG_TO_SET ;
if ( fcntl ( new_fd , F_SETFL , flags ) = = - 1 ) {
goto fail ;
}
# undef FLAG_TO_SET
/* 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 ) {
goto fail ;
}
# endif
return new_fd ;
fail :
if ( new_fd ! = - 1 ) {
int sys_errno = errno ;
close ( new_fd ) ;
errno = sys_errno ;
}
return - 1 ;
}
2009-04-21 11:58:42 +04:00
/* Just put a prototype to avoid moving the whole function around */
static const char * winbindd_socket_dir ( void ) ;
struct wb_context * wb_context_init ( TALLOC_CTX * mem_ctx , const char * dir )
2008-12-27 20:43:03 +03:00
{
struct wb_context * result ;
2010-01-29 13:54:33 +03:00
result = talloc_zero ( mem_ctx , struct wb_context ) ;
2008-12-27 20:43:03 +03:00
if ( result = = NULL ) {
return NULL ;
}
2009-03-16 22:38:11 +03:00
result - > queue = tevent_queue_create ( result , " wb_trans " ) ;
2008-12-27 20:43:03 +03:00
if ( result - > queue = = NULL ) {
TALLOC_FREE ( result ) ;
return NULL ;
}
result - > fd = - 1 ;
2009-05-20 01:05:51 +04:00
result - > is_priv = false ;
2009-04-21 11:58:42 +04:00
if ( dir ! = NULL ) {
2009-05-30 11:54:14 +04:00
result - > dir = talloc_strdup ( result , dir ) ;
2009-04-21 11:58:42 +04:00
} else {
result - > dir = winbindd_socket_dir ( ) ;
}
2009-05-30 11:54:14 +04:00
if ( result - > dir = = NULL ) {
TALLOC_FREE ( result ) ;
return NULL ;
}
2008-12-27 20:43:03 +03:00
return result ;
}
2009-02-22 21:49:18 +03:00
struct wb_connect_state {
int dummy ;
} ;
static void wbc_connect_connected ( struct tevent_req * subreq ) ;
2009-03-08 14:15:39 +03:00
static struct tevent_req * wb_connect_send ( TALLOC_CTX * mem_ctx ,
2009-02-22 21:49:18 +03:00
struct tevent_context * ev ,
struct wb_context * wb_ctx ,
const char * dir )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:15:39 +03:00
struct tevent_req * result , * subreq ;
2009-02-22 21:49:18 +03:00
struct wb_connect_state * state ;
2008-12-27 20:43:03 +03:00
struct sockaddr_un sunaddr ;
struct stat st ;
char * path = NULL ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-12-27 20:43:03 +03:00
2009-03-08 14:15:39 +03:00
result = tevent_req_create ( mem_ctx , & state , struct wb_connect_state ) ;
if ( result = = NULL ) {
2009-02-22 21:49:18 +03:00
return NULL ;
}
2008-12-27 20:43:03 +03:00
if ( wb_ctx - > fd ! = - 1 ) {
close ( wb_ctx - > fd ) ;
wb_ctx - > fd = - 1 ;
}
/* Check permissions on unix socket directory */
if ( lstat ( dir , & st ) = = - 1 ) {
2009-02-04 11:07:36 +03:00
wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE ;
2008-12-27 20:43:03 +03:00
goto post_status ;
}
if ( ! S_ISDIR ( st . st_mode ) | |
( st . st_uid ! = 0 & & st . st_uid ! = geteuid ( ) ) ) {
2009-02-04 11:07:36 +03:00
wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE ;
2008-12-27 20:43:03 +03:00
goto post_status ;
}
/* Connect to socket */
2009-06-08 10:15:57 +04:00
path = talloc_asprintf ( mem_ctx , " %s/%s " , dir ,
2008-12-27 20:43:03 +03:00
WINBINDD_SOCKET_NAME ) ;
if ( path = = NULL ) {
goto nomem ;
}
sunaddr . sun_family = AF_UNIX ;
strlcpy ( sunaddr . sun_path , path , sizeof ( sunaddr . sun_path ) ) ;
TALLOC_FREE ( path ) ;
/* 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 . */
if ( ( lstat ( sunaddr . sun_path , & st ) = = - 1 )
| | ! S_ISSOCK ( st . st_mode )
| | ( st . st_uid ! = 0 & & st . st_uid ! = geteuid ( ) ) ) {
2009-02-04 11:07:36 +03:00
wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE ;
2008-12-27 20:43:03 +03:00
goto post_status ;
}
wb_ctx - > fd = make_safe_fd ( socket ( AF_UNIX , SOCK_STREAM , 0 ) ) ;
if ( wb_ctx - > fd = = - 1 ) {
2009-02-04 11:07:36 +03:00
wbc_err = map_wbc_err_from_errno ( errno ) ;
2008-12-27 20:43:03 +03:00
goto post_status ;
}
2009-02-22 21:49:18 +03:00
subreq = async_connect_send ( mem_ctx , ev , wb_ctx - > fd ,
2009-05-09 23:12:33 +04:00
( struct sockaddr * ) ( void * ) & sunaddr ,
2009-02-22 21:49:18 +03:00
sizeof ( sunaddr ) ) ;
if ( subreq = = NULL ) {
2008-12-27 20:43:03 +03:00
goto nomem ;
}
2009-03-02 23:38:45 +03:00
tevent_req_set_callback ( subreq , wbc_connect_connected , result ) ;
2009-02-22 21:49:18 +03:00
return result ;
2008-12-27 20:43:03 +03:00
post_status :
2009-03-08 14:15:39 +03:00
tevent_req_error ( result , wbc_err ) ;
return tevent_req_post ( result , ev ) ;
nomem :
2009-02-22 21:49:18 +03:00
TALLOC_FREE ( result ) ;
2008-12-27 20:43:03 +03:00
return NULL ;
}
2009-02-22 21:49:18 +03:00
static void wbc_connect_connected ( struct tevent_req * subreq )
{
2009-03-08 14:15:39 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-02-22 21:49:18 +03:00
int res , err ;
res = async_connect_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( res = = - 1 ) {
2009-03-08 14:15:39 +03:00
tevent_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2009-02-22 21:49:18 +03:00
return ;
}
2009-03-08 14:15:39 +03:00
tevent_req_done ( req ) ;
2009-02-22 21:49:18 +03:00
}
2009-03-08 14:15:39 +03:00
static wbcErr wb_connect_recv ( struct tevent_req * req )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:15:39 +03:00
return tevent_req_simple_recv_wbcerr ( req ) ;
2008-12-27 20:43:03 +03:00
}
static const char * winbindd_socket_dir ( void )
{
# ifdef SOCKET_WRAPPER
const char * env_dir ;
env_dir = getenv ( WINBINDD_SOCKET_DIR_ENVVAR ) ;
if ( env_dir ) {
return env_dir ;
}
# endif
return WINBINDD_SOCKET_DIR ;
}
struct wb_open_pipe_state {
struct wb_context * wb_ctx ;
2009-02-03 00:14:57 +03:00
struct tevent_context * ev ;
2008-12-27 20:43:03 +03:00
bool need_priv ;
struct winbindd_request wb_req ;
} ;
2009-03-08 14:15:39 +03:00
static void wb_open_pipe_connect_nonpriv_done ( struct tevent_req * subreq ) ;
2009-03-08 14:10:00 +03:00
static void wb_open_pipe_ping_done ( struct tevent_req * subreq ) ;
static void wb_open_pipe_getpriv_done ( struct tevent_req * subreq ) ;
2009-03-08 14:15:39 +03:00
static void wb_open_pipe_connect_priv_done ( struct tevent_req * subreq ) ;
2008-12-27 20:43:03 +03:00
2009-03-08 14:22:29 +03:00
static struct tevent_req * wb_open_pipe_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct wb_context * wb_ctx ,
bool need_priv )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:22:29 +03:00
struct tevent_req * result , * subreq ;
2008-12-27 20:43:03 +03:00
struct wb_open_pipe_state * state ;
2009-03-08 14:22:29 +03:00
result = tevent_req_create ( mem_ctx , & state , struct wb_open_pipe_state ) ;
if ( result = = NULL ) {
2008-12-27 20:43:03 +03:00
return NULL ;
}
state - > wb_ctx = wb_ctx ;
state - > ev = ev ;
state - > need_priv = need_priv ;
if ( wb_ctx - > fd ! = - 1 ) {
close ( wb_ctx - > fd ) ;
wb_ctx - > fd = - 1 ;
}
2009-04-21 11:58:42 +04:00
subreq = wb_connect_send ( state , ev , wb_ctx , wb_ctx - > dir ) ;
2008-12-27 20:43:03 +03:00
if ( subreq = = NULL ) {
goto fail ;
}
2009-03-08 14:15:39 +03:00
tevent_req_set_callback ( subreq , wb_open_pipe_connect_nonpriv_done ,
result ) ;
2008-12-27 20:43:03 +03:00
return result ;
fail :
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-03-08 14:15:39 +03:00
static void wb_open_pipe_connect_nonpriv_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:22:29 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_open_pipe_state * state = tevent_req_data (
req , struct wb_open_pipe_state ) ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-12-27 20:43:03 +03:00
2009-02-04 11:07:36 +03:00
wbc_err = wb_connect_recv ( subreq ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-04 11:07:36 +03:00
if ( ! WBC_ERROR_IS_OK ( wbc_err ) ) {
2008-12-27 20:43:03 +03:00
state - > wb_ctx - > is_priv = true ;
2009-03-08 14:22:29 +03:00
tevent_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
ZERO_STRUCT ( state - > wb_req ) ;
state - > wb_req . cmd = WINBINDD_INTERFACE_VERSION ;
2009-05-09 23:12:33 +04:00
state - > wb_req . pid = getpid ( ) ;
2008-12-27 20:43:03 +03:00
2009-05-23 00:30:09 +04:00
subreq = wb_simple_trans_send ( state , state - > ev , NULL ,
2009-05-09 23:12:33 +04:00
state - > wb_ctx - > fd , & state - > wb_req ) ;
2009-03-08 14:22:29 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-08 14:15:39 +03:00
tevent_req_set_callback ( subreq , wb_open_pipe_ping_done , req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 14:10:00 +03:00
static void wb_open_pipe_ping_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:22:29 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_open_pipe_state * state = tevent_req_data (
req , struct wb_open_pipe_state ) ;
2008-12-27 20:43:03 +03:00
struct winbindd_response * wb_resp ;
2009-05-09 23:12:33 +04:00
int ret , err ;
2008-12-27 20:43:03 +03:00
2009-05-09 23:12:33 +04:00
ret = wb_simple_trans_recv ( subreq , state , & wb_resp , & err ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-05-09 23:12:33 +04:00
if ( ret = = - 1 ) {
tevent_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2008-12-27 20:43:03 +03:00
return ;
}
if ( ! state - > need_priv ) {
2009-03-08 14:22:29 +03:00
tevent_req_done ( req ) ;
2008-12-27 20:43:03 +03:00
return ;
}
state - > wb_req . cmd = WINBINDD_PRIV_PIPE_DIR ;
2009-05-09 23:12:33 +04:00
state - > wb_req . pid = getpid ( ) ;
2008-12-27 20:43:03 +03:00
2009-05-23 00:30:09 +04:00
subreq = wb_simple_trans_send ( state , state - > ev , NULL ,
2009-05-09 23:12:33 +04:00
state - > wb_ctx - > fd , & state - > wb_req ) ;
2009-03-08 14:22:29 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-08 14:10:00 +03:00
tevent_req_set_callback ( subreq , wb_open_pipe_getpriv_done , req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 14:10:00 +03:00
static void wb_open_pipe_getpriv_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:22:29 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_open_pipe_state * state = tevent_req_data (
req , struct wb_open_pipe_state ) ;
2008-12-27 20:43:03 +03:00
struct winbindd_response * wb_resp = NULL ;
2009-05-09 23:12:33 +04:00
int ret , err ;
2008-12-27 20:43:03 +03:00
2009-05-09 23:12:33 +04:00
ret = wb_simple_trans_recv ( subreq , state , & wb_resp , & err ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-05-09 23:12:33 +04:00
if ( ret = = - 1 ) {
tevent_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2008-12-27 20:43:03 +03:00
return ;
}
close ( state - > wb_ctx - > fd ) ;
state - > wb_ctx - > fd = - 1 ;
2009-03-08 14:15:39 +03:00
subreq = wb_connect_send ( state , state - > ev , state - > wb_ctx ,
2009-03-08 14:10:00 +03:00
( char * ) wb_resp - > extra_data . data ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( wb_resp ) ;
2009-03-08 14:22:29 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-08 14:15:39 +03:00
tevent_req_set_callback ( subreq , wb_open_pipe_connect_priv_done , req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 14:15:39 +03:00
static void wb_open_pipe_connect_priv_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:22:29 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_open_pipe_state * state = tevent_req_data (
req , struct wb_open_pipe_state ) ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-12-27 20:43:03 +03:00
2009-02-04 11:07:36 +03:00
wbc_err = wb_connect_recv ( subreq ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-04 11:07:36 +03:00
if ( ! WBC_ERROR_IS_OK ( wbc_err ) ) {
2009-03-08 14:22:29 +03:00
tevent_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
state - > wb_ctx - > is_priv = true ;
2009-03-08 14:22:29 +03:00
tevent_req_done ( req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 14:22:29 +03:00
static wbcErr wb_open_pipe_recv ( struct tevent_req * req )
2008-12-27 20:43:03 +03:00
{
2009-03-08 14:22:29 +03:00
return tevent_req_simple_recv_wbcerr ( req ) ;
2008-12-27 20:43:03 +03:00
}
struct wb_trans_state {
struct wb_trans_state * prev , * next ;
struct wb_context * wb_ctx ;
2009-02-03 00:14:57 +03:00
struct tevent_context * ev ;
2008-12-27 20:43:03 +03:00
struct winbindd_request * wb_req ;
struct winbindd_response * wb_resp ;
bool need_priv ;
} ;
2009-05-23 00:30:09 +04:00
static bool closed_fd ( int fd )
{
struct timeval tv ;
fd_set r_fds ;
int selret ;
if ( fd = = - 1 ) {
return true ;
}
FD_ZERO ( & r_fds ) ;
FD_SET ( fd , & r_fds ) ;
ZERO_STRUCT ( tv ) ;
selret = select ( fd + 1 , & r_fds , NULL , NULL , & tv ) ;
if ( selret = = - 1 ) {
return true ;
}
if ( selret = = 0 ) {
return false ;
}
return ( FD_ISSET ( fd , & r_fds ) ) ;
}
static void wb_trans_trigger ( struct tevent_req * req , void * private_data ) ;
2009-03-08 14:22:29 +03:00
static void wb_trans_connect_done ( struct tevent_req * subreq ) ;
2009-03-08 14:10:00 +03:00
static void wb_trans_done ( struct tevent_req * subreq ) ;
2009-03-16 22:15:23 +03:00
static void wb_trans_retry_wait_done ( struct tevent_req * subreq ) ;
2008-12-27 20:43:03 +03:00
2009-03-16 22:38:11 +03:00
struct tevent_req * wb_trans_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct wb_context * wb_ctx , bool need_priv ,
struct winbindd_request * wb_req )
2008-12-27 20:43:03 +03:00
{
2009-05-23 00:30:09 +04:00
struct tevent_req * req ;
2008-12-27 20:43:03 +03:00
struct wb_trans_state * state ;
2009-03-16 22:38:11 +03:00
req = tevent_req_create ( mem_ctx , & state , struct wb_trans_state ) ;
if ( req = = NULL ) {
2008-12-27 20:43:03 +03:00
return NULL ;
}
state - > wb_ctx = wb_ctx ;
state - > ev = ev ;
2009-03-08 14:25:10 +03:00
state - > wb_req = wb_req ;
2008-12-27 20:43:03 +03:00
state - > need_priv = need_priv ;
2009-05-23 00:30:09 +04:00
if ( ! tevent_queue_add ( wb_ctx - > queue , ev , req , wb_trans_trigger ,
NULL ) ) {
2011-06-19 23:10:01 +04:00
tevent_req_oom ( req ) ;
2009-05-23 00:30:09 +04:00
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void wb_trans_trigger ( struct tevent_req * req , void * private_data )
{
struct wb_trans_state * state = tevent_req_data (
req , struct wb_trans_state ) ;
struct tevent_req * subreq ;
if ( ( state - > wb_ctx - > fd ! = - 1 ) & & closed_fd ( state - > wb_ctx - > fd ) ) {
close ( state - > wb_ctx - > fd ) ;
state - > wb_ctx - > fd = - 1 ;
}
if ( ( state - > wb_ctx - > fd = = - 1 )
| | ( state - > need_priv & & ! state - > wb_ctx - > is_priv ) ) {
subreq = wb_open_pipe_send ( state , state - > ev , state - > wb_ctx ,
state - > need_priv ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
2009-03-16 22:38:11 +03:00
}
tevent_req_set_callback ( subreq , wb_trans_connect_done , req ) ;
2009-05-23 00:30:09 +04:00
return ;
2008-12-27 20:43:03 +03:00
}
2009-05-09 23:12:33 +04:00
state - > wb_req - > pid = getpid ( ) ;
2009-05-23 00:30:09 +04:00
subreq = wb_simple_trans_send ( state , state - > ev , NULL ,
state - > wb_ctx - > fd , state - > wb_req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
2009-03-16 22:38:11 +03:00
}
tevent_req_set_callback ( subreq , wb_trans_done , req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-16 22:38:11 +03:00
static bool wb_trans_retry ( struct tevent_req * req ,
2008-12-27 20:43:03 +03:00
struct wb_trans_state * state ,
2009-02-04 11:07:36 +03:00
wbcErr wbc_err )
2008-12-27 20:43:03 +03:00
{
2009-03-16 22:15:23 +03:00
struct tevent_req * subreq ;
2008-12-27 20:43:03 +03:00
2009-02-04 11:07:36 +03:00
if ( WBC_ERROR_IS_OK ( wbc_err ) ) {
2008-12-27 20:43:03 +03:00
return false ;
}
2009-02-04 11:07:36 +03:00
if ( wbc_err = = WBC_ERR_WINBIND_NOT_AVAILABLE ) {
2008-12-27 20:43:03 +03:00
/*
* Winbind not around or we can ' t connect to the pipe . Fail
* immediately .
*/
2009-03-16 22:38:11 +03:00
tevent_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return true ;
}
/*
* The transfer as such failed , retry after one second
*/
if ( state - > wb_ctx - > fd ! = - 1 ) {
close ( state - > wb_ctx - > fd ) ;
state - > wb_ctx - > fd = - 1 ;
}
2009-03-16 22:15:23 +03:00
subreq = tevent_wakeup_send ( state , state - > ev ,
2009-06-08 10:15:57 +04:00
tevent_timeval_current_ofs ( 1 , 0 ) ) ;
2009-03-16 22:38:11 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return true ;
}
2009-03-16 22:15:23 +03:00
tevent_req_set_callback ( subreq , wb_trans_retry_wait_done , req ) ;
2008-12-27 20:43:03 +03:00
return true ;
}
2009-03-16 22:15:23 +03:00
static void wb_trans_retry_wait_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-16 22:38:11 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_trans_state * state = tevent_req_data (
req , struct wb_trans_state ) ;
2009-02-01 18:32:02 +03:00
bool ret ;
2008-12-27 20:43:03 +03:00
2009-03-16 22:15:23 +03:00
ret = tevent_wakeup_recv ( subreq ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-03-16 22:15:23 +03:00
if ( ! ret ) {
2009-03-16 22:38:11 +03:00
tevent_req_error ( req , WBC_ERR_UNKNOWN_FAILURE ) ;
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-16 22:15:23 +03:00
subreq = wb_open_pipe_send ( state , state - > ev , state - > wb_ctx ,
2009-03-16 22:38:11 +03:00
state - > need_priv ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-16 22:15:23 +03:00
tevent_req_set_callback ( subreq , wb_trans_connect_done , req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 14:22:29 +03:00
static void wb_trans_connect_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-16 22:38:11 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_trans_state * state = tevent_req_data (
req , struct wb_trans_state ) ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-12-27 20:43:03 +03:00
2009-02-04 11:07:36 +03:00
wbc_err = wb_open_pipe_recv ( subreq ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-04 11:07:36 +03:00
if ( wb_trans_retry ( req , state , wbc_err ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-05-23 00:30:09 +04:00
subreq = wb_simple_trans_send ( state , state - > ev , NULL ,
2009-05-09 23:12:33 +04:00
state - > wb_ctx - > fd , state - > wb_req ) ;
2009-03-16 22:38:11 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-16 22:25:25 +03:00
tevent_req_set_callback ( subreq , wb_trans_done , req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 14:10:00 +03:00
static void wb_trans_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-16 22:38:11 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_trans_state * state = tevent_req_data (
req , struct wb_trans_state ) ;
2009-05-09 23:12:33 +04:00
int ret , err ;
2008-12-27 20:43:03 +03:00
2009-05-09 23:12:33 +04:00
ret = wb_simple_trans_recv ( subreq , state , & state - > wb_resp , & err ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-05-20 01:06:48 +04:00
if ( ( ret = = - 1 )
& & wb_trans_retry ( req , state , map_wbc_err_from_errno ( err ) ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-16 22:38:11 +03:00
tevent_req_done ( req ) ;
2008-12-27 20:43:03 +03:00
}
2009-03-16 22:38:11 +03:00
wbcErr wb_trans_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
2009-02-04 11:07:36 +03:00
struct winbindd_response * * presponse )
2008-12-27 20:43:03 +03:00
{
2009-03-16 22:38:11 +03:00
struct wb_trans_state * state = tevent_req_data (
req , struct wb_trans_state ) ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-12-27 20:43:03 +03:00
2009-03-16 22:38:11 +03:00
if ( tevent_req_is_wbcerr ( req , & wbc_err ) ) {
2009-02-04 11:07:36 +03:00
return wbc_err ;
2008-12-27 20:43:03 +03:00
}
* presponse = talloc_move ( mem_ctx , & state - > wb_resp ) ;
2009-02-04 11:07:36 +03:00
return WBC_ERR_SUCCESS ;
2008-12-27 20:43:03 +03:00
}
2009-06-02 01:33:27 +04:00
/********************************************************************
* Debug wrapper functions , modeled ( with lot ' s of code copied as is )
* after the tevent debug wrapper functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
this allows the user to choose their own debug function
*/
int wbcSetDebug ( struct wb_context * wb_ctx ,
void ( * debug ) ( void * context ,
enum wbcDebugLevel level ,
const char * fmt ,
va_list ap ) PRINTF_ATTRIBUTE ( 3 , 0 ) ,
void * context )
{
wb_ctx - > debug_ops . debug = debug ;
wb_ctx - > debug_ops . context = context ;
return 0 ;
}
/*
debug function for wbcSetDebugStderr
*/
static void wbcDebugStderr ( void * private_data ,
enum wbcDebugLevel level ,
const char * fmt ,
va_list ap ) PRINTF_ATTRIBUTE ( 3 , 0 ) ;
static void wbcDebugStderr ( void * private_data ,
enum wbcDebugLevel level ,
const char * fmt , va_list ap )
{
if ( level < = WBC_DEBUG_WARNING ) {
vfprintf ( stderr , fmt , ap ) ;
}
}
/*
convenience function to setup debug messages on stderr
messages of level WBC_DEBUG_WARNING and higher are printed
*/
int wbcSetDebugStderr ( struct wb_context * wb_ctx )
{
return wbcSetDebug ( wb_ctx , wbcDebugStderr , wb_ctx ) ;
}
/*
* log a message
*
* The default debug action is to ignore debugging messages .
* This is the most appropriate action for a library .
* Applications using the library must decide where to
* redirect debugging messages
*/
void wbcDebug ( struct wb_context * wb_ctx , enum wbcDebugLevel level ,
const char * fmt , . . . )
{
va_list ap ;
if ( ! wb_ctx ) {
return ;
}
if ( wb_ctx - > debug_ops . debug = = NULL ) {
return ;
}
va_start ( ap , fmt ) ;
wb_ctx - > debug_ops . debug ( wb_ctx - > debug_ops . context , level , fmt , ap ) ;
va_end ( ap ) ;
}