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
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-11-28 21:54:46 +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-11-28 21:54:46 +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-11-28 21:54:46 +03:00
2009-05-29 16:15:51 +04:00
You should have received a copy of the GNU Lesser General Public License
2008-11-28 21:54:46 +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 "lib/util/tevent_unix.h"
# include "nsswitch/winbind_struct_protocol.h"
# include "nsswitch/libwbclient/wbclient.h"
2011-02-17 02:43:05 +03:00
# include "nsswitch/wb_reqtrans.h"
2009-04-16 16:53:36 +04:00
2009-06-08 10:15:57 +04:00
/* can't use DEBUG here... */
# define DEBUG(a,b)
2008-11-28 21:54:46 +03:00
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-06-12 19:27:58 +04:00
if ( buflen > sizeof ( struct winbindd_request ) ) {
/* We've been here, we're done */
return 0 ;
}
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-10 12:49:39 +04: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 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
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 ;
}
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 ) ;
2009-05-10 12:49:39 +04:00
TALLOC_FREE ( subreq ) ;
2009-05-09 23:01:09 +04:00
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 ) ;
2009-05-10 12:49:39 +04:00
TALLOC_FREE ( subreq ) ;
2009-05-09 23:01:09 +04:00
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 ;
}