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
2009-03-08 12:29:15 +03:00
struct req_read_state {
struct winbindd_request * wb_req ;
size_t max_extra_data ;
2009-05-06 17:10:00 +04:00
ssize_t ret ;
2009-03-08 12:29:15 +03:00
} ;
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
2009-03-08 12:04:04 +03:00
struct tevent_req * wb_req_read_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
int fd , size_t max_extra_data )
2008-11-28 21:54:46 +03:00
{
2009-05-06 16:52:17 +04:00
struct tevent_req * req , * subreq ;
2008-11-28 21:54:46 +03:00
struct req_read_state * state ;
2009-05-06 16:52:17 +04:00
req = tevent_req_create ( mem_ctx , & state , struct req_read_state ) ;
if ( req = = NULL ) {
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 ) ;
2009-05-06 16:52:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2008-11-28 21:54:46 +03:00
}
2009-05-06 16:52:17 +04:00
tevent_req_set_callback ( subreq , wb_req_read_done , req ) ;
return req ;
2008-11-28 21:54:46 +03:00
}
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-03-08 12:04:04 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct req_read_state * state = tevent_req_data (
req , struct req_read_state ) ;
2009-02-04 11:07:36 +03:00
int err ;
2009-02-23 02:06:56 +03:00
uint8_t * buf ;
2008-11-28 21:54:46 +03:00
2009-05-06 17:10:00 +04:00
state - > ret = read_packet_recv ( subreq , state , & buf , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-05-06 17:10:00 +04:00
if ( state - > ret = = - 1 ) {
tevent_req_error ( req , 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
}
2009-03-08 12:04:04 +03:00
tevent_req_done ( req ) ;
2008-11-28 21:54:46 +03:00
}
2009-05-06 17:10:00 +04:00
ssize_t wb_req_read_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_request * * preq , int * err )
2008-11-28 21:54:46 +03:00
{
2009-03-08 12:04:04 +03:00
struct req_read_state * state = tevent_req_data (
req , struct req_read_state ) ;
2008-11-28 21:54:46 +03:00
2009-05-06 17:10:00 +04:00
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
2008-11-28 21:54:46 +03:00
}
* preq = talloc_move ( mem_ctx , & state - > wb_req ) ;
2009-05-06 17:10:00 +04:00
return state - > ret ;
2008-11-28 21:54:46 +03:00
}
struct req_write_state {
2009-02-22 23:41:57 +03:00
struct iovec iov [ 2 ] ;
2009-05-06 17:10:00 +04:00
ssize_t ret ;
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
2009-03-08 11:35:13 +03:00
struct tevent_req * wb_req_write_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tevent_queue * queue , int fd ,
struct winbindd_request * wb_req )
2008-11-28 21:54:46 +03:00
{
2009-05-06 16:52:17 +04:00
struct tevent_req * 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-05-06 16:52:17 +04:00
req = tevent_req_create ( mem_ctx , & state , struct req_write_state ) ;
if ( req = = NULL ) {
2008-11-28 21:54:46 +03:00
return NULL ;
}
2009-05-12 22:45:37 +04:00
state - > iov [ 0 ] . iov_base = ( void * ) wb_req ;
2009-02-22 23:41:57 +03:00
state - > iov [ 0 ] . iov_len = sizeof ( struct winbindd_request ) ;
if ( wb_req - > extra_len ! = 0 ) {
2009-05-12 22:45:37 +04:00
state - > iov [ 1 ] . iov_base = ( void * ) wb_req - > extra_data . data ;
2009-02-22 23:41:57 +03:00
state - > iov [ 1 ] . iov_len = wb_req - > extra_len ;
count = 2 ;
2008-11-28 21:54:46 +03:00
}
2009-05-23 18:10:54 +04:00
subreq = writev_send ( state , ev , queue , fd , true , state - > iov , count ) ;
2009-05-06 16:52:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-02-22 23:41:57 +03:00
}
2009-05-06 16:52:17 +04:00
tevent_req_set_callback ( subreq , wb_req_write_done , req ) ;
return req ;
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
{
2009-03-08 11:35:13 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-05-06 17:10:00 +04:00
struct req_write_state * state = tevent_req_data (
req , struct req_write_state ) ;
2009-02-04 11:07:36 +03:00
int err ;
2008-11-28 21:54:46 +03:00
2009-05-06 17:10:00 +04:00
state - > ret = writev_recv ( subreq , & err ) ;
2009-05-09 23:01:09 +04:00
/*
* We do not TALLOC_FREE ( subreq ) here , as this would trigger the next
* write of a client . The winbind protocol is purely request / response
* without multiplex ID ' s , so having multiple requeusts on the fly
* would confuse sequencing .
*
* Eventually the writev_req will be freed , " subreq " a child of " req "
*/
2009-05-06 17:10:00 +04:00
if ( state - > ret < 0 ) {
tevent_req_error ( req , err ) ;
2008-11-28 21:54:46 +03:00
return ;
}
2009-03-08 11:35:13 +03:00
tevent_req_done ( req ) ;
2008-11-28 21:54:46 +03:00
}
2009-05-06 17:10:00 +04:00
ssize_t wb_req_write_recv ( struct tevent_req * req , int * err )
2008-11-28 21:54:46 +03:00
{
2009-05-06 17:10:00 +04:00
struct req_write_state * state = tevent_req_data (
req , struct req_write_state ) ;
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
}
return state - > ret ;
2008-11-28 21:54:46 +03:00
}
struct resp_read_state {
struct winbindd_response * wb_resp ;
2009-05-06 17:10:00 +04:00
ssize_t ret ;
2008-11-28 21:54:46 +03:00
} ;
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
2009-03-08 12:20:27 +03:00
struct tevent_req * wb_resp_read_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev , int fd )
2008-11-28 21:54:46 +03:00
{
2009-05-06 16:52:17 +04:00
struct tevent_req * req , * subreq ;
2008-11-28 21:54:46 +03:00
struct resp_read_state * state ;
2009-05-06 16:52:17 +04:00
req = tevent_req_create ( mem_ctx , & state , struct resp_read_state ) ;
if ( req = = NULL ) {
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 ) ;
2009-05-06 16:52:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2008-11-28 21:54:46 +03:00
}
2009-05-06 16:52:17 +04:00
tevent_req_set_callback ( subreq , wb_resp_read_done , req ) ;
return req ;
2008-11-28 21:54:46 +03:00
}
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-03-08 12:20:27 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct resp_read_state * state = tevent_req_data (
req , 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 ;
2008-11-28 21:54:46 +03:00
2009-05-06 17:10:00 +04:00
state - > ret = read_packet_recv ( subreq , state , & buf , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-05-06 17:10:00 +04:00
if ( state - > ret = = - 1 ) {
tevent_req_error ( req , 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
}
2009-03-08 12:20:27 +03:00
tevent_req_done ( req ) ;
2008-11-28 21:54:46 +03:00
}
2009-05-06 17:10:00 +04:00
ssize_t wb_resp_read_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presp , int * err )
2008-11-28 21:54:46 +03:00
{
2009-03-08 12:20:27 +03:00
struct resp_read_state * state = tevent_req_data (
req , struct resp_read_state ) ;
2008-11-28 21:54:46 +03:00
2009-05-06 17:10:00 +04:00
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
2008-11-28 21:54:46 +03:00
}
* presp = talloc_move ( mem_ctx , & state - > wb_resp ) ;
2009-05-06 17:10:00 +04:00
return state - > ret ;
2008-11-28 21:54:46 +03:00
}
struct resp_write_state {
2009-02-22 23:55:03 +03:00
struct iovec iov [ 2 ] ;
2009-05-06 17:10:00 +04:00
ssize_t ret ;
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
2009-03-08 12:28:05 +03:00
struct tevent_req * wb_resp_write_send ( TALLOC_CTX * mem_ctx ,
2009-03-15 13:25:20 +03:00
struct tevent_context * ev ,
struct tevent_queue * queue , int fd ,
2009-03-08 12:28:05 +03:00
struct winbindd_response * wb_resp )
2008-11-28 21:54:46 +03:00
{
2009-05-06 16:52:17 +04:00
struct tevent_req * 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-05-06 16:52:17 +04:00
req = tevent_req_create ( mem_ctx , & state , struct resp_write_state ) ;
if ( req = = NULL ) {
2008-11-28 21:54:46 +03:00
return NULL ;
}
2009-05-12 22:45:37 +04:00
state - > iov [ 0 ] . iov_base = ( void * ) wb_resp ;
2009-02-22 23:55:03 +03:00
state - > iov [ 0 ] . iov_len = sizeof ( struct winbindd_response ) ;
if ( wb_resp - > length > sizeof ( struct winbindd_response ) ) {
2009-05-12 22:45:37 +04:00
state - > iov [ 1 ] . iov_base = ( void * ) wb_resp - > extra_data . data ;
2009-02-22 23:55:03 +03:00
state - > iov [ 1 ] . iov_len =
wb_resp - > length - sizeof ( struct winbindd_response ) ;
count = 2 ;
2008-11-28 21:54:46 +03:00
}
2009-05-23 18:10:54 +04:00
subreq = writev_send ( state , ev , queue , fd , true , state - > iov , count ) ;
2009-05-06 16:52:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-02-22 23:55:03 +03:00
}
2009-05-06 16:52:17 +04:00
tevent_req_set_callback ( subreq , wb_resp_write_done , req ) ;
return req ;
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
{
2009-03-08 12:28:05 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-05-06 17:10:00 +04:00
struct resp_write_state * state = tevent_req_data (
req , struct resp_write_state ) ;
2009-02-04 11:07:36 +03:00
int err ;
2008-11-28 21:54:46 +03:00
2009-05-06 17:10:00 +04:00
state - > ret = writev_recv ( subreq , & err ) ;
2008-11-28 21:54:46 +03:00
TALLOC_FREE ( subreq ) ;
2009-05-06 17:10:00 +04:00
if ( state - > ret < 0 ) {
tevent_req_error ( req , err ) ;
2008-11-28 21:54:46 +03:00
return ;
}
2009-03-08 12:28:05 +03:00
tevent_req_done ( req ) ;
2008-11-28 21:54:46 +03:00
}
2009-05-06 17:10:00 +04:00
ssize_t wb_resp_write_recv ( struct tevent_req * req , int * err )
2008-11-28 21:54:46 +03:00
{
2009-05-06 17:10:00 +04:00
struct resp_write_state * state = tevent_req_data (
req , struct resp_write_state ) ;
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
}
return state - > ret ;
2008-12-01 10:25:25 +03:00
}
2009-05-09 23:01:09 +04:00
static bool 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_simple_trans_state {
struct tevent_context * ev ;
int fd ;
struct winbindd_response * wb_resp ;
} ;
static void wb_simple_trans_write_done ( struct tevent_req * subreq ) ;
static void wb_simple_trans_read_done ( struct tevent_req * subreq ) ;
struct tevent_req * wb_simple_trans_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tevent_queue * queue , int fd ,
struct winbindd_request * wb_req )
{
struct tevent_req * req , * subreq ;
struct wb_simple_trans_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct wb_simple_trans_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( closed_fd ( fd ) ) {
tevent_req_error ( req , EPIPE ) ;
return tevent_req_post ( req , ev ) ;
}
wb_req - > length = sizeof ( struct winbindd_request ) ;
state - > ev = ev ;
state - > fd = fd ;
subreq = wb_req_write_send ( state , ev , queue , fd , wb_req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , wb_simple_trans_write_done , req ) ;
return req ;
}
static void wb_simple_trans_write_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_simple_trans_state * state = tevent_req_data (
req , struct wb_simple_trans_state ) ;
ssize_t ret ;
int err ;
ret = wb_req_write_recv ( subreq , & err ) ;
/*
* We do not TALLOC_FREE ( subreq ) here , as this would trigger the next
* write of a client . The winbind protocol is purely request / response
* without multiplex ID ' s , so having multiple requeusts on the fly
* would confuse sequencing .
*
* Eventually the " subreq " will be freed , it is a child of " req "
*/
if ( ret = = - 1 ) {
tevent_req_error ( req , err ) ;
return ;
}
subreq = wb_resp_read_send ( state , state - > ev , state - > fd ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wb_simple_trans_read_done , req ) ;
}
static void wb_simple_trans_read_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_simple_trans_state * state = tevent_req_data (
req , struct wb_simple_trans_state ) ;
ssize_t ret ;
int err ;
ret = wb_resp_read_recv ( subreq , state , & state - > wb_resp , & err ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , err ) ;
return ;
}
tevent_req_done ( req ) ;
}
int wb_simple_trans_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presponse , int * err )
{
struct wb_simple_trans_state * state = tevent_req_data (
req , struct wb_simple_trans_state ) ;
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
}
* presponse = talloc_move ( mem_ctx , & state - > wb_resp ) ;
return 0 ;
}