2008-11-28 21:54:46 +03:00
/*
Unix SMB / CIFS implementation .
Async transfer of winbindd_request and _response structs
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-11-28 21:54:46 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
struct req_read_state {
struct winbindd_request * wb_req ;
size_t max_extra_data ;
} ;
2009-02-04 11:07:36 +03:00
bool async_req_is_wbcerr ( struct async_req * req , wbcErr * pwbc_err )
{
enum async_req_state state ;
uint64_t error ;
if ( ! async_req_is_error ( req , & state , & error ) ) {
* pwbc_err = WBC_ERR_SUCCESS ;
return false ;
}
switch ( state ) {
case ASYNC_REQ_USER_ERROR :
* pwbc_err = error ;
break ;
case ASYNC_REQ_TIMED_OUT :
* pwbc_err = WBC_ERR_UNKNOWN_FAILURE ;
break ;
case ASYNC_REQ_NO_MEMORY :
* pwbc_err = WBC_ERR_NO_MEMORY ;
break ;
default :
* pwbc_err = WBC_ERR_UNKNOWN_FAILURE ;
break ;
}
return true ;
}
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 ;
}
}
wbcErr async_req_simple_recv_wbcerr ( struct async_req * req )
{
wbcErr wbc_err ;
if ( async_req_is_wbcerr ( req , & wbc_err ) ) {
return wbc_err ;
}
return WBC_ERR_SUCCESS ;
}
2009-03-08 11:34:35 +03:00
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-02-23 02:06:56 +03:00
static ssize_t wb_req_more ( uint8_t * buf , size_t buflen , void * private_data ) ;
static void wb_req_read_done ( struct tevent_req * subreq ) ;
2008-11-28 21:54:46 +03:00
struct async_req * wb_req_read_send ( TALLOC_CTX * mem_ctx ,
2009-02-03 00:14:57 +03:00
struct tevent_context * ev ,
2008-11-28 21:54:46 +03:00
int fd , size_t max_extra_data )
{
2009-02-23 02:06:56 +03:00
struct async_req * result ;
struct tevent_req * subreq ;
2008-11-28 21:54:46 +03:00
struct req_read_state * state ;
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct req_read_state ) ) {
2008-11-28 21:54:46 +03:00
return NULL ;
}
state - > max_extra_data = max_extra_data ;
2009-02-23 02:06:56 +03:00
subreq = read_packet_send ( state , ev , fd , 4 , wb_req_more , state ) ;
2008-11-28 21:54:46 +03:00
if ( subreq = = NULL ) {
goto nomem ;
}
2009-02-28 23:44:30 +03:00
tevent_req_set_callback ( subreq , wb_req_read_done , result ) ;
2008-11-28 21:54:46 +03:00
return result ;
nomem :
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-02-23 02:06:56 +03:00
static ssize_t wb_req_more ( uint8_t * buf , size_t buflen , void * private_data )
2008-11-28 21:54:46 +03:00
{
struct req_read_state * state = talloc_get_type_abort (
2009-02-23 02:06:56 +03:00
private_data , struct req_read_state ) ;
struct winbindd_request * req = ( struct winbindd_request * ) buf ;
2008-11-28 21:54:46 +03:00
2009-02-23 02:06:56 +03:00
if ( buflen = = 4 ) {
if ( req - > length ! = sizeof ( struct winbindd_request ) ) {
DEBUG ( 0 , ( " wb_req_read_len: Invalid request size "
" received: %d (expected %d) \n " ,
( int ) req - > length ,
( int ) sizeof ( struct winbindd_request ) ) ) ;
return - 1 ;
}
return sizeof ( struct winbindd_request ) - 4 ;
2008-11-28 21:54:46 +03:00
}
2009-02-23 02:06:56 +03:00
if ( ( state - > max_extra_data ! = 0 )
& & ( req - > extra_len > state - > max_extra_data ) ) {
DEBUG ( 3 , ( " Got request with %d bytes extra data on "
" unprivileged socket \n " , ( int ) req - > extra_len ) ) ;
return - 1 ;
2008-11-28 21:54:46 +03:00
}
2009-02-23 02:06:56 +03:00
return req - > extra_len ;
2008-11-28 21:54:46 +03:00
}
2009-02-23 02:06:56 +03:00
static void wb_req_read_done ( struct tevent_req * subreq )
2008-11-28 21:54:46 +03:00
{
2009-02-28 23:44:30 +03:00
struct async_req * req =
tevent_req_callback_data ( subreq , struct async_req ) ;
2008-11-28 21:54:46 +03:00
struct req_read_state * state = talloc_get_type_abort (
req - > private_data , struct req_read_state ) ;
2009-02-04 11:07:36 +03:00
int err ;
ssize_t ret ;
2009-02-23 02:06:56 +03:00
uint8_t * buf ;
2008-11-28 21:54:46 +03:00
2009-02-23 02:06:56 +03:00
ret = read_packet_recv ( subreq , state , & buf , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-23 02:06:56 +03:00
if ( ret = = - 1 ) {
2009-02-04 11:07:36 +03:00
async_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2008-11-28 21:54:46 +03:00
return ;
}
2009-02-23 02:06:56 +03:00
state - > wb_req = ( struct winbindd_request * ) buf ;
2008-11-28 21:54:46 +03:00
2009-02-23 02:06:56 +03:00
if ( state - > wb_req - > extra_len ! = 0 ) {
state - > wb_req - > extra_data . data =
( char * ) buf + sizeof ( struct winbindd_request ) ;
} else {
state - > wb_req - > extra_data . data = NULL ;
2008-11-28 21:54:46 +03:00
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
wbcErr wb_req_read_recv ( struct async_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_request * * preq )
2008-11-28 21:54:46 +03:00
{
struct req_read_state * state = talloc_get_type_abort (
req - > private_data , struct req_read_state ) ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-11-28 21:54:46 +03:00
2009-02-04 11:07:36 +03:00
if ( async_req_is_wbcerr ( req , & wbc_err ) ) {
return wbc_err ;
2008-11-28 21:54:46 +03:00
}
* preq = talloc_move ( mem_ctx , & state - > wb_req ) ;
2009-02-04 11:07:36 +03:00
return WBC_ERR_SUCCESS ;
2008-11-28 21:54:46 +03:00
}
struct req_write_state {
2009-02-22 23:41:57 +03:00
struct iovec iov [ 2 ] ;
2008-11-28 21:54:46 +03:00
} ;
2009-02-22 23:41:57 +03:00
static void wb_req_write_done ( struct tevent_req * subreq ) ;
2008-11-28 21:54:46 +03:00
struct async_req * wb_req_write_send ( TALLOC_CTX * mem_ctx ,
2009-02-03 00:14:57 +03:00
struct tevent_context * ev , int fd ,
2008-11-28 21:54:46 +03:00
struct winbindd_request * wb_req )
{
2009-02-22 23:41:57 +03:00
struct async_req * result ;
struct tevent_req * subreq ;
2008-11-28 21:54:46 +03:00
struct req_write_state * state ;
2009-02-22 23:41:57 +03:00
int count = 1 ;
2008-11-28 21:54:46 +03:00
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct req_write_state ) ) {
2008-11-28 21:54:46 +03:00
return NULL ;
}
2009-02-22 23:41:57 +03:00
state - > iov [ 0 ] . iov_base = wb_req ;
state - > iov [ 0 ] . iov_len = sizeof ( struct winbindd_request ) ;
if ( wb_req - > extra_len ! = 0 ) {
state - > iov [ 1 ] . iov_base = wb_req - > extra_data . data ;
state - > iov [ 1 ] . iov_len = wb_req - > extra_len ;
count = 2 ;
2008-11-28 21:54:46 +03:00
}
2009-03-01 21:43:07 +03:00
subreq = writev_send ( state , ev , NULL , fd , state - > iov , count ) ;
2009-02-22 23:41:57 +03:00
if ( subreq = = NULL ) {
goto fail ;
}
2009-03-02 22:10:13 +03:00
tevent_req_set_callback ( subreq , wb_req_write_done , result ) ;
2008-11-28 21:54:46 +03:00
return result ;
2009-02-22 23:41:57 +03:00
fail :
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-02-22 23:41:57 +03:00
static void wb_req_write_done ( struct tevent_req * subreq )
2008-11-28 21:54:46 +03:00
{
2009-02-28 23:44:30 +03:00
struct async_req * req =
tevent_req_callback_data ( subreq , struct async_req ) ;
2009-02-04 11:07:36 +03:00
int err ;
ssize_t ret ;
2008-11-28 21:54:46 +03:00
2009-02-22 23:41:57 +03:00
ret = writev_recv ( subreq , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-04 11:07:36 +03:00
if ( ret < 0 ) {
async_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2008-11-28 21:54:46 +03:00
return ;
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
wbcErr wb_req_write_recv ( struct async_req * req )
2008-11-28 21:54:46 +03:00
{
2009-02-04 11:07:36 +03:00
return async_req_simple_recv_wbcerr ( req ) ;
2008-11-28 21:54:46 +03:00
}
struct resp_read_state {
struct winbindd_response * wb_resp ;
} ;
2009-02-23 02:18:29 +03:00
static ssize_t wb_resp_more ( uint8_t * buf , size_t buflen , void * private_data ) ;
static void wb_resp_read_done ( struct tevent_req * subreq ) ;
2008-11-28 21:54:46 +03:00
struct async_req * wb_resp_read_send ( TALLOC_CTX * mem_ctx ,
2009-02-03 00:14:57 +03:00
struct tevent_context * ev , int fd )
2008-11-28 21:54:46 +03:00
{
2009-02-23 02:18:29 +03:00
struct async_req * result ;
struct tevent_req * subreq ;
2008-11-28 21:54:46 +03:00
struct resp_read_state * state ;
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct resp_read_state ) ) {
2008-11-28 21:54:46 +03:00
return NULL ;
}
2009-02-23 02:18:29 +03:00
subreq = read_packet_send ( state , ev , fd , 4 , wb_resp_more , state ) ;
2008-11-28 21:54:46 +03:00
if ( subreq = = NULL ) {
goto nomem ;
}
2009-02-28 23:44:30 +03:00
tevent_req_set_callback ( subreq , wb_resp_read_done , result ) ;
2008-11-28 21:54:46 +03:00
return result ;
nomem :
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-02-23 02:18:29 +03:00
static ssize_t wb_resp_more ( uint8_t * buf , size_t buflen , void * private_data )
2008-11-28 21:54:46 +03:00
{
2009-02-23 02:18:29 +03:00
struct winbindd_response * resp = ( struct winbindd_response * ) buf ;
2008-11-28 21:54:46 +03:00
2009-02-23 02:18:29 +03:00
if ( buflen = = 4 ) {
if ( resp - > length < sizeof ( struct winbindd_response ) ) {
DEBUG ( 0 , ( " wb_resp_read_len: Invalid response size "
" received: %d (expected at least%d) \n " ,
( int ) resp - > length ,
( int ) sizeof ( struct winbindd_response ) ) ) ;
return - 1 ;
}
2008-11-28 21:54:46 +03:00
}
2009-02-28 14:20:56 +03:00
return resp - > length - buflen ;
2008-11-28 21:54:46 +03:00
}
2009-02-23 02:18:29 +03:00
static void wb_resp_read_done ( struct tevent_req * subreq )
2008-11-28 21:54:46 +03:00
{
2009-02-28 23:44:30 +03:00
struct async_req * req =
tevent_req_callback_data ( subreq , struct async_req ) ;
2008-11-28 21:54:46 +03:00
struct resp_read_state * state = talloc_get_type_abort (
req - > private_data , struct resp_read_state ) ;
2009-02-23 02:18:29 +03:00
uint8_t * buf ;
2009-02-04 11:07:36 +03:00
int err ;
ssize_t ret ;
2008-11-28 21:54:46 +03:00
2009-02-23 02:18:29 +03:00
ret = read_packet_recv ( subreq , state , & buf , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-23 02:18:29 +03:00
if ( ret = = - 1 ) {
2009-02-04 11:07:36 +03:00
async_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2008-11-28 21:54:46 +03:00
return ;
}
2009-02-23 02:18:29 +03:00
state - > wb_resp = ( struct winbindd_response * ) buf ;
2008-11-28 21:54:46 +03:00
2009-02-23 02:18:29 +03:00
if ( state - > wb_resp - > length > sizeof ( struct winbindd_response ) ) {
state - > wb_resp - > extra_data . data =
( char * ) buf + sizeof ( struct winbindd_response ) ;
} else {
state - > wb_resp - > extra_data . data = NULL ;
2008-11-28 21:54:46 +03:00
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
wbcErr wb_resp_read_recv ( struct async_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presp )
2008-11-28 21:54:46 +03:00
{
struct resp_read_state * state = talloc_get_type_abort (
req - > private_data , struct resp_read_state ) ;
2009-02-04 11:07:36 +03:00
wbcErr wbc_err ;
2008-11-28 21:54:46 +03:00
2009-02-04 11:07:36 +03:00
if ( async_req_is_wbcerr ( req , & wbc_err ) ) {
return wbc_err ;
2008-11-28 21:54:46 +03:00
}
* presp = talloc_move ( mem_ctx , & state - > wb_resp ) ;
2009-02-04 11:07:36 +03:00
return WBC_ERR_SUCCESS ;
2008-11-28 21:54:46 +03:00
}
struct resp_write_state {
2009-02-22 23:55:03 +03:00
struct iovec iov [ 2 ] ;
2008-11-28 21:54:46 +03:00
} ;
2009-02-22 23:55:03 +03:00
static void wb_resp_write_done ( struct tevent_req * subreq ) ;
2008-11-28 21:54:46 +03:00
struct async_req * wb_resp_write_send ( TALLOC_CTX * mem_ctx ,
2009-02-03 00:14:57 +03:00
struct tevent_context * ev , int fd ,
2008-11-28 21:54:46 +03:00
struct winbindd_response * wb_resp )
{
2009-02-22 23:55:03 +03:00
struct async_req * result ;
struct tevent_req * subreq ;
2008-11-28 21:54:46 +03:00
struct resp_write_state * state ;
2009-02-22 23:55:03 +03:00
int count = 1 ;
2008-11-28 21:54:46 +03:00
2009-01-18 18:38:30 +03:00
if ( ! async_req_setup ( mem_ctx , & result , & state ,
struct resp_write_state ) ) {
2008-11-28 21:54:46 +03:00
return NULL ;
}
2009-02-22 23:55:03 +03:00
state - > iov [ 0 ] . iov_base = wb_resp ;
state - > iov [ 0 ] . iov_len = sizeof ( struct winbindd_response ) ;
if ( wb_resp - > length > sizeof ( struct winbindd_response ) ) {
state - > iov [ 1 ] . iov_base = wb_resp - > extra_data . data ;
state - > iov [ 1 ] . iov_len =
wb_resp - > length - sizeof ( struct winbindd_response ) ;
count = 2 ;
2008-11-28 21:54:46 +03:00
}
2009-03-01 21:43:07 +03:00
subreq = writev_send ( state , ev , NULL , fd , state - > iov , count ) ;
2009-02-22 23:55:03 +03:00
if ( subreq = = NULL ) {
goto fail ;
}
2009-02-28 23:44:30 +03:00
tevent_req_set_callback ( subreq , wb_resp_write_done , result ) ;
2008-11-28 21:54:46 +03:00
return result ;
2009-02-22 23:55:03 +03:00
fail :
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( result ) ;
return NULL ;
}
2009-02-22 23:55:03 +03:00
static void wb_resp_write_done ( struct tevent_req * subreq )
2008-11-28 21:54:46 +03:00
{
2009-02-28 23:44:30 +03:00
struct async_req * req =
2009-03-02 22:10:13 +03:00
tevent_req_callback_data ( subreq , struct async_req ) ;
2009-02-04 11:07:36 +03:00
int err ;
ssize_t ret ;
2008-11-28 21:54:46 +03:00
2009-02-22 23:55:03 +03:00
ret = writev_recv ( subreq , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-02-04 11:07:36 +03:00
if ( ret < 0 ) {
async_req_error ( req , map_wbc_err_from_errno ( err ) ) ;
2008-11-28 21:54:46 +03:00
return ;
}
async_req_done ( req ) ;
}
2009-02-04 11:07:36 +03:00
wbcErr wb_resp_write_recv ( struct async_req * req )
2008-11-28 21:54:46 +03:00
{
2009-02-04 11:07:36 +03:00
return async_req_simple_recv_wbcerr ( req ) ;
2008-12-01 10:25:25 +03:00
}