2008-12-27 20:43:03 +03:00
/*
Unix SMB / CIFS implementation .
Infrastructure for async winbind requests
Copyright ( C ) Volker Lendecke 2008
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/>.
*/
# include "includes.h"
2009-02-04 11:07:36 +03:00
# include "wbc_async.h"
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 ;
}
static bool winbind_closed_fd ( int fd )
{
struct timeval tv ;
fd_set r_fds ;
if ( fd = = - 1 ) {
return true ;
}
FD_ZERO ( & r_fds ) ;
FD_SET ( fd , & r_fds ) ;
ZERO_STRUCT ( tv ) ;
if ( ( select ( fd + 1 , & r_fds , NULL , NULL , & tv ) = = - 1 )
| | FD_ISSET ( fd , & r_fds ) ) {
return true ;
}
return false ;
}
struct wb_context * wb_context_init ( TALLOC_CTX * mem_ctx )
{
struct wb_context * result ;
result = talloc ( mem_ctx , struct wb_context ) ;
if ( result = = NULL ) {
return NULL ;
}
result - > queue = async_req_queue_init ( result ) ;
if ( result - > queue = = NULL ) {
TALLOC_FREE ( result ) ;
return NULL ;
}
result - > fd = - 1 ;
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 ) ;
2008-12-27 20:43:03 +03:00
static struct async_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-02-22 21:49:18 +03:00
struct async_req * result ;
struct tevent_req * subreq ;
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-02-22 21:49:18 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct wb_connect_state ) ) {
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 */
path = talloc_asprintf ( talloc_tos ( ) , " %s/%s " , dir ,
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 ,
( struct sockaddr * ) & sunaddr ,
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
if ( ! tevent_req_set_endtime ( subreq , ev , timeval_current_ofs ( 30 , 0 ) ) ) {
2008-12-27 20:43:03 +03:00
goto nomem ;
}
2009-02-22 21:49:18 +03:00
return result ;
2008-12-27 20:43:03 +03:00
nomem :
2009-02-04 11:07:36 +03:00
wbc_err = WBC_ERR_NO_MEMORY ;
2008-12-27 20:43:03 +03:00
post_status :
2009-02-22 21:49:18 +03:00
if ( async_post_error ( result , ev , wbc_err ) ) {
return result ;
2008-12-27 20:43:03 +03:00
}
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-02 23:38:45 +03:00
struct async_req * req =
tevent_req_callback_data ( subreq , struct async_req ) ;
2009-02-22 21:49:18 +03:00
int res , err ;
res = async_connect_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( res = = - 1 ) {
async_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
return ;
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
static wbcErr wb_connect_recv ( struct async_req * req )
2008-12-27 20:43:03 +03:00
{
2009-02-04 11:07:36 +03:00
return async_req_simple_recv_wbcerr ( req ) ;
2008-12-27 20:43:03 +03:00
}
static struct winbindd_request * winbindd_request_copy (
TALLOC_CTX * mem_ctx ,
const struct winbindd_request * req )
{
struct winbindd_request * result ;
result = ( struct winbindd_request * ) TALLOC_MEMDUP (
mem_ctx , req , sizeof ( struct winbindd_request ) ) ;
if ( result = = NULL ) {
return NULL ;
}
if ( result - > extra_len = = 0 ) {
return result ;
}
result - > extra_data . data = ( char * ) TALLOC_MEMDUP (
result , result - > extra_data . data , result - > extra_len ) ;
if ( result - > extra_data . data = = NULL ) {
TALLOC_FREE ( result ) ;
return NULL ;
}
return result ;
}
struct wb_int_trans_state {
2009-02-03 00:14:57 +03:00
struct tevent_context * ev ;
2008-12-27 20:43:03 +03:00
int fd ;
struct winbindd_request * wb_req ;
struct winbindd_response * wb_resp ;
} ;
2009-03-08 11:35:13 +03:00
static void wb_int_trans_write_done ( struct tevent_req * subreq ) ;
2008-12-27 20:43:03 +03:00
static void wb_int_trans_read_done ( struct async_req * subreq ) ;
static struct async_req * wb_int_trans_send ( TALLOC_CTX * mem_ctx ,
2009-02-03 00:14:57 +03:00
struct tevent_context * ev , int fd ,
2008-12-27 20:43:03 +03:00
struct winbindd_request * wb_req )
{
struct async_req * result ;
2009-03-08 11:35:13 +03:00
struct tevent_req * subreq ;
2008-12-27 20:43:03 +03:00
struct wb_int_trans_state * state ;
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct wb_int_trans_state ) ) {
2008-12-27 20:43:03 +03:00
return NULL ;
}
if ( winbind_closed_fd ( fd ) ) {
2009-02-04 11:07:36 +03:00
if ( ! async_post_error ( result , ev ,
WBC_ERR_WINBIND_NOT_AVAILABLE ) ) {
2008-12-27 20:43:03 +03:00
goto fail ;
}
return result ;
}
state - > ev = ev ;
state - > fd = fd ;
state - > wb_req = wb_req ;
state - > wb_req - > length = sizeof ( struct winbindd_request ) ;
state - > wb_req - > pid = getpid ( ) ;
2009-03-08 11:35:13 +03:00
subreq = wb_req_write_send ( state , state - > ev , NULL , state - > fd ,
state - > wb_req ) ;
2008-12-27 20:43:03 +03:00
if ( subreq = = NULL ) {
goto fail ;
}
2009-03-08 11:35:13 +03:00
tevent_req_set_callback ( subreq , wb_int_trans_write_done , result ) ;
2008-12-27 20:43:03 +03:00
return result ;
fail :
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-03-08 11:35:13 +03:00
static void wb_int_trans_write_done ( struct tevent_req * subreq )
2008-12-27 20:43:03 +03:00
{
2009-03-08 11:35:13 +03:00
struct async_req * req = tevent_req_callback_data (
subreq , struct async_req ) ;
2008-12-27 20:43:03 +03:00
struct wb_int_trans_state * state = talloc_get_type_abort (
req - > private_data , struct wb_int_trans_state ) ;
2009-03-08 11:35:13 +03:00
struct async_req * subreq2 ;
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_req_write_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 ) ) {
async_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
2009-03-08 11:35:13 +03:00
subreq2 = wb_resp_read_send ( state , state - > ev , state - > fd ) ;
if ( async_req_nomem ( subreq2 , req ) ) {
return ;
2008-12-27 20:43:03 +03:00
}
2009-03-08 11:35:13 +03:00
subreq2 - > async . fn = wb_int_trans_read_done ;
subreq2 - > async . priv = req ;
2008-12-27 20:43:03 +03:00
}
static void wb_int_trans_read_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_int_trans_state * state = talloc_get_type_abort (
req - > private_data , struct wb_int_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_resp_read_recv ( subreq , state , & state - > wb_resp ) ;
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 ) ) {
async_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
static wbcErr wb_int_trans_recv ( struct async_req * req ,
TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presponse )
2008-12-27 20:43:03 +03:00
{
struct wb_int_trans_state * state = talloc_get_type_abort (
req - > private_data , struct wb_int_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
if ( async_req_is_wbcerr ( req , & wbc_err ) ) {
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
}
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 ;
} ;
static void wb_open_pipe_connect_nonpriv_done ( struct async_req * subreq ) ;
static void wb_open_pipe_ping_done ( struct async_req * subreq ) ;
static void wb_open_pipe_getpriv_done ( struct async_req * subreq ) ;
static void wb_open_pipe_connect_priv_done ( struct async_req * subreq ) ;
static struct async_req * wb_open_pipe_send ( TALLOC_CTX * mem_ctx ,
2009-02-03 00:14:57 +03:00
struct tevent_context * ev ,
2008-12-27 20:43:03 +03:00
struct wb_context * wb_ctx ,
bool need_priv )
{
struct async_req * result ;
struct async_req * subreq ;
struct wb_open_pipe_state * state ;
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct wb_open_pipe_state ) ) {
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 ;
}
subreq = wb_connect_send ( state , ev , wb_ctx , winbindd_socket_dir ( ) ) ;
if ( subreq = = NULL ) {
goto fail ;
}
subreq - > async . fn = wb_open_pipe_connect_nonpriv_done ;
subreq - > async . priv = result ;
return result ;
fail :
TALLOC_FREE ( result ) ;
return NULL ;
}
static void wb_open_pipe_connect_nonpriv_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_open_pipe_state * state = talloc_get_type_abort (
req - > private_data , 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-02-04 11:07:36 +03:00
async_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 ;
subreq = wb_int_trans_send ( state , state - > ev , state - > wb_ctx - > fd ,
& state - > wb_req ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_open_pipe_ping_done ;
subreq - > async . priv = req ;
}
static void wb_open_pipe_ping_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_open_pipe_state * state = talloc_get_type_abort (
req - > private_data , struct wb_open_pipe_state ) ;
struct winbindd_response * wb_resp ;
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_int_trans_recv ( subreq , state , & wb_resp ) ;
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 ) ) {
async_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
if ( ! state - > need_priv ) {
async_req_done ( req ) ;
return ;
}
state - > wb_req . cmd = WINBINDD_PRIV_PIPE_DIR ;
subreq = wb_int_trans_send ( state , state - > ev , state - > wb_ctx - > fd ,
& state - > wb_req ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_open_pipe_getpriv_done ;
subreq - > async . priv = req ;
}
static void wb_open_pipe_getpriv_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_open_pipe_state * state = talloc_get_type_abort (
req - > private_data , struct wb_open_pipe_state ) ;
struct winbindd_response * wb_resp = NULL ;
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_int_trans_recv ( subreq , state , & wb_resp ) ;
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 ) ) {
async_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
close ( state - > wb_ctx - > fd ) ;
state - > wb_ctx - > fd = - 1 ;
subreq = wb_connect_send ( state , state - > ev , state - > wb_ctx ,
( char * ) wb_resp - > extra_data . data ) ;
TALLOC_FREE ( wb_resp ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_open_pipe_connect_priv_done ;
subreq - > async . priv = req ;
}
static void wb_open_pipe_connect_priv_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_open_pipe_state * state = talloc_get_type_abort (
req - > private_data , 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 ) ) {
async_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return ;
}
state - > wb_ctx - > is_priv = true ;
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
static wbcErr wb_open_pipe_recv ( struct async_req * req )
2008-12-27 20:43:03 +03:00
{
2009-02-04 11:07:36 +03:00
return async_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 ;
int num_retries ;
bool need_priv ;
} ;
static void wb_trans_connect_done ( struct async_req * subreq ) ;
static void wb_trans_done ( struct async_req * subreq ) ;
static void wb_trans_retry_wait_done ( struct async_req * subreq ) ;
static void wb_trigger_trans ( struct async_req * req )
{
struct wb_trans_state * state = talloc_get_type_abort (
req - > private_data , struct wb_trans_state ) ;
struct async_req * subreq ;
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 ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_trans_connect_done ;
subreq - > async . priv = req ;
return ;
}
subreq = wb_int_trans_send ( state , state - > ev , state - > wb_ctx - > fd ,
state - > wb_req ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_trans_done ;
subreq - > async . priv = req ;
}
2009-02-03 00:14:57 +03:00
struct async_req * wb_trans_send ( TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
2008-12-27 20:43:03 +03:00
struct wb_context * wb_ctx , bool need_priv ,
const struct winbindd_request * wb_req )
{
struct async_req * result ;
struct wb_trans_state * state ;
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct wb_trans_state ) ) {
2008-12-27 20:43:03 +03:00
return NULL ;
}
state - > wb_ctx = wb_ctx ;
state - > ev = ev ;
state - > wb_req = winbindd_request_copy ( state , wb_req ) ;
if ( state - > wb_req = = NULL ) {
goto fail ;
}
state - > num_retries = 10 ;
state - > need_priv = need_priv ;
if ( ! async_req_enqueue ( wb_ctx - > queue , ev , result , wb_trigger_trans ) ) {
goto fail ;
}
return result ;
fail :
TALLOC_FREE ( result ) ;
return NULL ;
}
static bool wb_trans_retry ( struct async_req * req ,
struct wb_trans_state * state ,
2009-02-04 11:07:36 +03:00
wbcErr wbc_err )
2008-12-27 20:43:03 +03:00
{
struct async_req * subreq ;
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-02-04 11:07:36 +03:00
async_req_error ( req , wbc_err ) ;
2008-12-27 20:43:03 +03:00
return true ;
}
state - > num_retries - = 1 ;
if ( state - > num_retries = = 0 ) {
2009-02-04 11:07:36 +03:00
async_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 ;
}
subreq = async_wait_send ( state , state - > ev , timeval_set ( 1 , 0 ) ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return true ;
}
subreq - > async . fn = wb_trans_retry_wait_done ;
subreq - > async . priv = req ;
return true ;
}
static void wb_trans_retry_wait_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_trans_state * state = talloc_get_type_abort (
req - > private_data , struct wb_trans_state ) ;
2009-02-01 18:32:02 +03:00
bool ret ;
2008-12-27 20:43:03 +03:00
2009-02-01 18:32:02 +03:00
ret = async_wait_recv ( subreq ) ;
2008-12-27 20:43:03 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-01 18:32:02 +03:00
if ( ret ) {
2009-02-04 11:07:36 +03:00
async_req_error ( req , WBC_ERR_UNKNOWN_FAILURE ) ;
2008-12-27 20:43:03 +03:00
return ;
}
subreq = wb_open_pipe_send ( state , state - > ev , state - > wb_ctx ,
state - > need_priv ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_trans_connect_done ;
subreq - > async . priv = req ;
}
static void wb_trans_connect_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_trans_state * state = talloc_get_type_abort (
req - > private_data , 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 ;
}
subreq = wb_int_trans_send ( state , state - > ev , state - > wb_ctx - > fd ,
state - > wb_req ) ;
2009-02-02 19:23:35 +03:00
if ( async_req_nomem ( subreq , req ) ) {
2008-12-27 20:43:03 +03:00
return ;
}
subreq - > async . fn = wb_trans_done ;
subreq - > async . priv = req ;
}
static void wb_trans_done ( struct async_req * subreq )
{
struct async_req * req = talloc_get_type_abort (
subreq - > async . priv , struct async_req ) ;
struct wb_trans_state * state = talloc_get_type_abort (
req - > private_data , 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_int_trans_recv ( subreq , state , & state - > wb_resp ) ;
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 ;
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
wbcErr wb_trans_recv ( struct async_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presponse )
2008-12-27 20:43:03 +03:00
{
struct wb_trans_state * state = talloc_get_type_abort (
req - > private_data , 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
if ( async_req_is_wbcerr ( req , & wbc_err ) ) {
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
}