2008-09-23 08:58:17 +04:00
/*
2005-01-21 09:54:10 +03:00
Unix SMB / CIFS implementation .
low level socket handling for nbt requests
Copyright ( C ) Andrew Tridgell 2005
2008-09-23 08:58:17 +04:00
2005-01-21 09:54:10 +03:00
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-01-21 09:54:10 +03:00
( at your option ) any later version .
2008-09-23 08:58:17 +04:00
2005-01-21 09:54:10 +03:00
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 .
2008-09-23 08:58:17 +04:00
2005-01-21 09:54:10 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-01-21 09:54:10 +03:00
*/
# include "includes.h"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
2008-09-23 08:58:17 +04:00
# include "../libcli/nbt/libnbt.h"
2008-10-20 20:59:51 +04:00
# include "../libcli/nbt/nbt_proto.h"
2005-02-10 09:59:29 +03:00
# include "lib/socket/socket.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/ndr_nbt.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2005-01-21 09:54:10 +03:00
# define NBT_MAX_REPLIES 1000
/*
destroy a pending request
*/
2006-05-24 11:34:11 +04:00
static int nbt_name_request_destructor ( struct nbt_name_request * req )
2008-09-23 08:58:17 +04:00
{
2005-01-21 09:54:10 +03:00
if ( req - > state = = NBT_REQUEST_SEND ) {
DLIST_REMOVE ( req - > nbtsock - > send_queue , req ) ;
}
if ( req - > state = = NBT_REQUEST_WAIT ) {
req - > nbtsock - > num_pending - - ;
}
2005-01-31 07:53:53 +03:00
if ( req - > name_trn_id ! = 0 & & ! req - > is_reply ) {
idr_remove ( req - > nbtsock - > idr , req - > name_trn_id ) ;
req - > name_trn_id = 0 ;
2005-01-21 09:54:10 +03:00
}
if ( req - > te ) {
2007-05-07 19:27:50 +04:00
talloc_free ( req - > te ) ;
2005-01-21 09:54:10 +03:00
req - > te = NULL ;
}
if ( req - > nbtsock - > send_queue = = NULL ) {
2012-05-14 13:48:50 +04:00
TEVENT_FD_NOT_WRITEABLE ( req - > nbtsock - > fde ) ;
2005-01-21 09:54:10 +03:00
}
2008-09-23 08:58:17 +04:00
if ( req - > nbtsock - > num_pending = = 0 & &
2005-01-30 13:24:36 +03:00
req - > nbtsock - > incoming . handler = = NULL ) {
2012-05-14 13:48:50 +04:00
TEVENT_FD_NOT_READABLE ( req - > nbtsock - > fde ) ;
2005-01-21 09:54:10 +03:00
}
return 0 ;
}
/*
handle send events on a nbt name socket
*/
static void nbt_name_socket_send ( struct nbt_name_socket * nbtsock )
{
struct nbt_name_request * req = nbtsock - > send_queue ;
2005-01-31 04:57:58 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( nbtsock ) ;
2005-01-21 09:54:10 +03:00
NTSTATUS status ;
while ( ( req = nbtsock - > send_queue ) ) {
size_t len ;
2008-09-23 08:58:17 +04:00
2005-01-31 07:53:53 +03:00
len = req - > encoded . length ;
2008-09-23 08:58:17 +04:00
status = socket_sendto ( nbtsock - > sock , & req - > encoded , & len ,
2006-01-10 01:12:53 +03:00
req - > dest ) ;
2008-09-23 08:58:17 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) goto failed ;
2005-01-21 09:54:10 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
DLIST_REMOVE ( nbtsock - > send_queue , req ) ;
2005-02-08 04:05:41 +03:00
req - > state = NBT_REQUEST_WAIT ;
2005-01-31 07:53:53 +03:00
if ( req - > is_reply ) {
2005-01-31 04:57:58 +03:00
talloc_free ( req ) ;
} else {
2012-05-14 13:48:50 +04:00
TEVENT_FD_READABLE ( nbtsock - > fde ) ;
2005-01-31 04:57:58 +03:00
nbtsock - > num_pending + + ;
}
2005-01-21 09:54:10 +03:00
}
2012-05-14 13:48:50 +04:00
TEVENT_FD_NOT_WRITEABLE ( nbtsock - > fde ) ;
2005-01-21 09:54:10 +03:00
talloc_free ( tmp_ctx ) ;
return ;
failed :
DLIST_REMOVE ( nbtsock - > send_queue , req ) ;
nbt_name_request_destructor ( req ) ;
req - > status = status ;
req - > state = NBT_REQUEST_ERROR ;
2005-01-22 02:53:10 +03:00
talloc_free ( tmp_ctx ) ;
2005-01-21 14:18:56 +03:00
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
2007-05-07 19:27:50 +04:00
} else if ( req - > is_reply ) {
talloc_free ( req ) ;
2005-01-21 14:18:56 +03:00
}
2005-01-21 09:54:10 +03:00
return ;
}
2005-02-06 11:22:18 +03:00
/*
handle a request timeout
*/
2008-12-29 22:24:57 +03:00
static void nbt_name_socket_timeout ( struct tevent_context * ev , struct tevent_timer * te ,
2009-02-02 13:07:48 +03:00
struct timeval t , void * private_data )
2005-02-06 11:22:18 +03:00
{
2009-02-02 13:07:48 +03:00
struct nbt_name_request * req = talloc_get_type ( private_data ,
2005-02-06 11:22:18 +03:00
struct nbt_name_request ) ;
if ( req - > num_retries ! = 0 ) {
req - > num_retries - - ;
2012-05-14 13:48:50 +04:00
req - > te = tevent_add_timer ( req - > nbtsock - > event_ctx , req ,
timeval_add ( & t , req - > timeout , 0 ) ,
nbt_name_socket_timeout , req ) ;
2005-02-08 04:05:41 +03:00
if ( req - > state ! = NBT_REQUEST_SEND ) {
req - > state = NBT_REQUEST_SEND ;
2008-09-23 08:58:17 +04:00
DLIST_ADD_END ( req - > nbtsock - > send_queue , req ,
2005-02-08 04:05:41 +03:00
struct nbt_name_request * ) ;
}
2012-05-14 13:48:50 +04:00
TEVENT_FD_WRITEABLE ( req - > nbtsock - > fde ) ;
2005-02-06 11:22:18 +03:00
return ;
}
nbt_name_request_destructor ( req ) ;
if ( req - > num_replies = = 0 ) {
req - > state = NBT_REQUEST_TIMEOUT ;
req - > status = NT_STATUS_IO_TIMEOUT ;
} else {
req - > state = NBT_REQUEST_DONE ;
req - > status = NT_STATUS_OK ;
}
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
2007-05-07 19:27:50 +04:00
} else if ( req - > is_reply ) {
talloc_free ( req ) ;
2005-02-06 11:22:18 +03:00
}
}
2007-12-12 04:15:20 +03:00
/**
2005-01-21 09:54:10 +03:00
handle recv events on a nbt name socket
*/
static void nbt_name_socket_recv ( struct nbt_name_socket * nbtsock )
{
TALLOC_CTX * tmp_ctx = talloc_new ( nbtsock ) ;
NTSTATUS status ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-01-10 01:12:53 +03:00
struct socket_address * src ;
2005-01-21 09:54:10 +03:00
DATA_BLOB blob ;
2005-06-03 17:31:27 +04:00
size_t nread , dsize ;
2005-01-21 09:54:10 +03:00
struct nbt_name_packet * packet ;
struct nbt_name_request * req ;
2005-06-03 17:31:27 +04:00
status = socket_pending ( nbtsock - > sock , & dsize ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
blob = data_blob_talloc ( tmp_ctx , NULL , dsize ) ;
2005-01-21 09:54:10 +03:00
if ( blob . data = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ;
}
2006-04-30 09:58:31 +04:00
status = socket_recvfrom ( nbtsock - > sock , blob . data , blob . length , & nread ,
2006-01-10 01:12:53 +03:00
tmp_ctx , & src ) ;
2005-01-21 09:54:10 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return ;
}
packet = talloc ( tmp_ctx , struct nbt_name_packet ) ;
if ( packet = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ;
}
2005-02-06 11:22:18 +03:00
/* parse the request */
2010-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob ( & blob , packet , packet ,
2007-11-09 21:24:51 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_nbt_name_packet ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
2005-01-21 09:54:10 +03:00
DEBUG ( 2 , ( " Failed to parse incoming NBT name packet - %s \n " ,
nt_errstr ( status ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ;
}
if ( DEBUGLVL ( 10 ) ) {
2008-09-23 08:58:17 +04:00
DEBUG ( 10 , ( " Received nbt packet of length %d from %s:%d \n " ,
2006-01-10 01:12:53 +03:00
( int ) blob . length , src - > addr , src - > port ) ) ;
2005-01-21 09:54:10 +03:00
NDR_PRINT_DEBUG ( nbt_name_packet , packet ) ;
}
2005-02-06 11:22:18 +03:00
/* if its not a reply then pass it off to the incoming request
handler , if any */
2005-01-21 09:54:10 +03:00
if ( ! ( packet - > operation & NBT_FLAG_REPLY ) ) {
2005-01-30 13:24:36 +03:00
if ( nbtsock - > incoming . handler ) {
2006-01-10 01:12:53 +03:00
nbtsock - > incoming . handler ( nbtsock , packet , src ) ;
2005-01-30 13:24:36 +03:00
}
2005-01-21 09:54:10 +03:00
talloc_free ( tmp_ctx ) ;
return ;
}
/* find the matching request */
2008-09-23 08:58:17 +04:00
req = ( struct nbt_name_request * ) idr_find ( nbtsock - > idr ,
2007-09-07 19:08:14 +04:00
packet - > name_trn_id ) ;
2005-01-21 09:54:10 +03:00
if ( req = = NULL ) {
2005-02-08 04:05:41 +03:00
if ( nbtsock - > unexpected . handler ) {
2006-01-10 01:12:53 +03:00
nbtsock - > unexpected . handler ( nbtsock , packet , src ) ;
2005-02-08 04:05:41 +03:00
} else {
2007-02-13 18:17:29 +03:00
DEBUG ( 10 , ( " Failed to match request for incoming name packet id 0x%04x on %p \n " ,
2005-02-08 04:05:41 +03:00
packet - > name_trn_id , nbtsock ) ) ;
}
2005-01-21 09:54:10 +03:00
talloc_free ( tmp_ctx ) ;
return ;
}
2008-01-16 16:51:56 +03:00
talloc_steal ( req , packet ) ;
talloc_steal ( req , src ) ;
talloc_free ( tmp_ctx ) ;
nbt_name_socket_handle_response_packet ( req , packet , src ) ;
}
void nbt_name_socket_handle_response_packet ( struct nbt_name_request * req ,
struct nbt_name_packet * packet ,
struct socket_address * src )
{
2005-02-06 11:22:18 +03:00
/* if this is a WACK response, this we need to go back to waiting,
but perhaps increase the timeout */
if ( ( packet - > operation & NBT_OPCODE ) = = NBT_OPCODE_WACK ) {
2009-01-17 20:14:29 +03:00
uint32_t ttl ;
2005-02-06 11:22:18 +03:00
if ( req - > received_wack | | packet - > ancount < 1 ) {
nbt_name_request_destructor ( req ) ;
req - > status = NT_STATUS_INVALID_NETWORK_RESPONSE ;
req - > state = NBT_REQUEST_ERROR ;
goto done ;
}
talloc_free ( req - > te ) ;
/* we know we won't need any more retries - the server
has received our request */
req - > num_retries = 0 ;
2007-10-07 02:28:14 +04:00
req - > received_wack = true ;
2009-01-17 20:14:29 +03:00
/*
* there is a timeout in the packet ,
* it is 5 + 4 * num_old_addresses
*
* although w2k3 screws it up
* and uses num_old_addresses = 0
*
* so we better fallback to the maximum
* of num_old_addresses = 25 if we got
* a timeout of less than 9 s ( 5 + 4 * 1 )
* or more than 105 s ( 5 + 4 * 25 ) .
*/
ttl = packet - > answers [ 0 ] . ttl ;
if ( ( ttl < ( 5 + 4 * 1 ) ) | | ( ttl > ( 5 + 4 * 25 ) ) ) {
ttl = 5 + 4 * 25 ;
}
req - > timeout = ttl ;
2012-05-14 13:48:50 +04:00
req - > te = tevent_add_timer ( req - > nbtsock - > event_ctx , req ,
timeval_current_ofs ( req - > timeout , 0 ) ,
nbt_name_socket_timeout , req ) ;
2005-02-06 11:22:18 +03:00
return ;
}
2008-09-23 08:58:17 +04:00
2005-02-06 11:22:18 +03:00
2005-01-21 09:54:10 +03:00
req - > replies = talloc_realloc ( req , req - > replies , struct nbt_name_reply , req - > num_replies + 1 ) ;
if ( req - > replies = = NULL ) {
nbt_name_request_destructor ( req ) ;
2005-02-06 11:22:18 +03:00
req - > state = NBT_REQUEST_ERROR ;
2005-01-21 09:54:10 +03:00
req - > status = NT_STATUS_NO_MEMORY ;
2005-02-06 11:22:18 +03:00
goto done ;
2005-01-21 09:54:10 +03:00
}
2006-01-10 01:12:53 +03:00
talloc_steal ( req , src ) ;
req - > replies [ req - > num_replies ] . dest = src ;
talloc_steal ( req , packet ) ;
req - > replies [ req - > num_replies ] . packet = packet ;
2005-01-21 09:54:10 +03:00
req - > num_replies + + ;
/* if we don't want multiple replies then we are done */
2005-02-06 11:22:18 +03:00
if ( req - > allow_multiple_replies & &
req - > num_replies < NBT_MAX_REPLIES ) {
return ;
}
nbt_name_request_destructor ( req ) ;
req - > state = NBT_REQUEST_DONE ;
req - > status = NT_STATUS_OK ;
done :
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
2005-01-21 09:54:10 +03:00
}
}
/*
handle fd events on a nbt_name_socket
*/
2008-12-29 22:24:57 +03:00
static void nbt_name_socket_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
2009-02-02 13:07:48 +03:00
uint16_t flags , void * private_data )
2005-01-21 09:54:10 +03:00
{
2009-02-02 13:07:48 +03:00
struct nbt_name_socket * nbtsock = talloc_get_type ( private_data ,
2005-01-21 09:54:10 +03:00
struct nbt_name_socket ) ;
2012-05-14 13:48:50 +04:00
if ( flags & TEVENT_FD_WRITE ) {
2005-01-21 09:54:10 +03:00
nbt_name_socket_send ( nbtsock ) ;
2008-09-23 08:58:17 +04:00
}
2012-05-14 13:48:50 +04:00
if ( flags & TEVENT_FD_READ ) {
2005-01-21 09:54:10 +03:00
nbt_name_socket_recv ( nbtsock ) ;
}
}
/*
initialise a nbt_name_socket . The event_ctx is optional , if provided
then operations will use that event context
*/
2008-09-23 08:58:17 +04:00
_PUBLIC_ struct nbt_name_socket * nbt_name_socket_init ( TALLOC_CTX * mem_ctx ,
2010-05-09 19:20:01 +04:00
struct tevent_context * event_ctx )
2005-01-21 09:54:10 +03:00
{
struct nbt_name_socket * nbtsock ;
NTSTATUS status ;
nbtsock = talloc ( mem_ctx , struct nbt_name_socket ) ;
if ( nbtsock = = NULL ) goto failed ;
2010-02-07 13:08:56 +03:00
nbtsock - > event_ctx = event_ctx ;
2005-01-21 09:54:10 +03:00
if ( nbtsock - > event_ctx = = NULL ) goto failed ;
status = socket_create ( " ip " , SOCKET_TYPE_DGRAM , & nbtsock - > sock , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2005-02-07 14:56:34 +03:00
socket_set_option ( nbtsock - > sock , " SO_BROADCAST " , " 1 " ) ;
2005-01-21 09:54:10 +03:00
talloc_steal ( nbtsock , nbtsock - > sock ) ;
nbtsock - > idr = idr_init ( nbtsock ) ;
if ( nbtsock - > idr = = NULL ) goto failed ;
nbtsock - > send_queue = NULL ;
nbtsock - > num_pending = 0 ;
2005-01-31 07:53:53 +03:00
nbtsock - > incoming . handler = NULL ;
2005-02-08 04:05:41 +03:00
nbtsock - > unexpected . handler = NULL ;
2005-01-21 09:54:10 +03:00
2012-05-14 13:48:50 +04:00
nbtsock - > fde = tevent_add_fd ( nbtsock - > event_ctx , nbtsock ,
socket_get_fd ( nbtsock - > sock ) , 0 ,
nbt_name_socket_handler , nbtsock ) ;
2008-09-23 08:58:17 +04:00
2005-01-21 09:54:10 +03:00
return nbtsock ;
failed :
talloc_free ( nbtsock ) ;
return NULL ;
}
/*
send off a nbt name request
*/
2008-09-23 08:58:17 +04:00
struct nbt_name_request * nbt_name_request_send ( struct nbt_name_socket * nbtsock ,
2006-01-10 01:12:53 +03:00
struct socket_address * dest ,
2005-01-21 09:54:10 +03:00
struct nbt_name_packet * request ,
2005-02-06 11:22:18 +03:00
int timeout , int retries ,
2007-10-07 02:28:14 +04:00
bool allow_multiple_replies )
2005-01-21 09:54:10 +03:00
{
struct nbt_name_request * req ;
int id ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-01-21 09:54:10 +03:00
req = talloc_zero ( nbtsock , struct nbt_name_request ) ;
if ( req = = NULL ) goto failed ;
2005-02-06 11:22:18 +03:00
req - > nbtsock = nbtsock ;
2005-01-21 09:54:10 +03:00
req - > allow_multiple_replies = allow_multiple_replies ;
2005-02-06 11:22:18 +03:00
req - > state = NBT_REQUEST_SEND ;
2007-10-07 02:28:14 +04:00
req - > is_reply = false ;
2005-02-06 11:22:18 +03:00
req - > timeout = timeout ;
req - > num_retries = retries ;
2006-01-10 01:12:53 +03:00
req - > dest = dest ;
if ( talloc_reference ( req , dest ) = = NULL ) goto failed ;
2005-01-21 09:54:10 +03:00
2005-01-21 14:18:56 +03:00
/* we select a random transaction id unless the user supplied one */
2005-01-31 07:53:53 +03:00
if ( request - > name_trn_id = = 0 ) {
2005-05-10 05:59:33 +04:00
id = idr_get_new_random ( req - > nbtsock - > idr , req , UINT16_MAX ) ;
} else {
if ( idr_find ( req - > nbtsock - > idr , request - > name_trn_id ) ) goto failed ;
2008-09-23 08:58:17 +04:00
id = idr_get_new_above ( req - > nbtsock - > idr , req , request - > name_trn_id ,
2005-01-21 09:54:10 +03:00
UINT16_MAX ) ;
}
if ( id = = - 1 ) goto failed ;
2005-02-08 04:05:41 +03:00
2005-01-31 07:53:53 +03:00
request - > name_trn_id = id ;
req - > name_trn_id = id ;
2005-01-21 09:54:10 +03:00
2012-05-14 13:48:50 +04:00
req - > te = tevent_add_timer ( nbtsock - > event_ctx , req ,
timeval_current_ofs ( req - > timeout , 0 ) ,
nbt_name_socket_timeout , req ) ;
2005-01-21 09:54:10 +03:00
2008-09-23 08:58:17 +04:00
talloc_set_destructor ( req , nbt_name_request_destructor ) ;
ndr_err = ndr_push_struct_blob ( & req - > encoded , req ,
2008-01-02 07:05:05 +03:00
request ,
2007-11-09 21:24:51 +03:00
( ndr_push_flags_fn_t ) ndr_push_nbt_name_packet ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) goto failed ;
2005-01-31 07:53:53 +03:00
2005-01-21 09:54:10 +03:00
DLIST_ADD_END ( nbtsock - > send_queue , req , struct nbt_name_request * ) ;
2005-01-31 07:53:53 +03:00
if ( DEBUGLVL ( 10 ) ) {
2008-09-23 08:58:17 +04:00
DEBUG ( 10 , ( " Queueing nbt packet to %s:%d \n " ,
2006-01-10 01:12:53 +03:00
req - > dest - > addr , req - > dest - > port ) ) ;
2005-01-31 07:53:53 +03:00
NDR_PRINT_DEBUG ( nbt_name_packet , request ) ;
}
2012-05-14 13:48:50 +04:00
TEVENT_FD_WRITEABLE ( nbtsock - > fde ) ;
2005-01-21 09:54:10 +03:00
return req ;
failed :
talloc_free ( req ) ;
return NULL ;
}
2005-01-31 04:57:58 +03:00
/*
send off a nbt name reply
*/
2008-09-23 08:58:17 +04:00
_PUBLIC_ NTSTATUS nbt_name_reply_send ( struct nbt_name_socket * nbtsock ,
2006-01-10 01:12:53 +03:00
struct socket_address * dest ,
2005-01-31 04:57:58 +03:00
struct nbt_name_packet * request )
{
struct nbt_name_request * req ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-01-31 04:57:58 +03:00
req = talloc_zero ( nbtsock , struct nbt_name_request ) ;
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
req - > nbtsock = nbtsock ;
2006-01-10 01:12:53 +03:00
req - > dest = dest ;
if ( talloc_reference ( req , dest ) = = NULL ) goto failed ;
2005-01-31 04:57:58 +03:00
req - > state = NBT_REQUEST_SEND ;
2007-10-07 02:28:14 +04:00
req - > is_reply = true ;
2005-01-31 04:57:58 +03:00
2008-09-23 08:58:17 +04:00
talloc_set_destructor ( req , nbt_name_request_destructor ) ;
2005-01-31 04:57:58 +03:00
2005-01-31 20:16:45 +03:00
if ( DEBUGLVL ( 10 ) ) {
2008-09-23 08:58:17 +04:00
NDR_PRINT_DEBUG ( nbt_name_packet , request ) ;
2005-01-31 20:16:45 +03:00
}
2008-09-23 08:58:17 +04:00
ndr_err = ndr_push_struct_blob ( & req - > encoded , req ,
2008-01-02 07:05:05 +03:00
request ,
2007-11-09 21:24:51 +03:00
( ndr_push_flags_fn_t ) ndr_push_nbt_name_packet ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2005-01-31 07:53:53 +03:00
talloc_free ( req ) ;
2007-11-09 21:24:51 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
2005-01-31 07:53:53 +03:00
}
2005-01-31 04:57:58 +03:00
DLIST_ADD_END ( nbtsock - > send_queue , req , struct nbt_name_request * ) ;
2012-05-14 13:48:50 +04:00
TEVENT_FD_WRITEABLE ( nbtsock - > fde ) ;
2005-01-31 04:57:58 +03:00
return NT_STATUS_OK ;
failed :
talloc_free ( req ) ;
return NT_STATUS_NO_MEMORY ;
}
2005-01-21 09:54:10 +03:00
/*
wait for a nbt request to complete
*/
NTSTATUS nbt_name_request_recv ( struct nbt_name_request * req )
{
if ( ! req ) return NT_STATUS_NO_MEMORY ;
while ( req - > state < NBT_REQUEST_DONE ) {
2012-05-14 13:48:50 +04:00
if ( tevent_loop_once ( req - > nbtsock - > event_ctx ) ! = 0 ) {
2005-01-21 09:54:10 +03:00
req - > state = NBT_REQUEST_ERROR ;
req - > status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
2007-05-07 19:27:50 +04:00
break ;
2005-01-21 09:54:10 +03:00
}
}
return req - > status ;
}
2005-01-30 13:24:36 +03:00
/*
setup a handler for incoming requests
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS nbt_set_incoming_handler ( struct nbt_name_socket * nbtsock ,
2008-09-23 08:58:17 +04:00
void ( * handler ) ( struct nbt_name_socket * , struct nbt_name_packet * ,
2006-01-10 01:12:53 +03:00
struct socket_address * ) ,
2009-02-02 13:07:48 +03:00
void * private_data )
2005-01-30 13:24:36 +03:00
{
nbtsock - > incoming . handler = handler ;
2009-02-02 13:07:48 +03:00
nbtsock - > incoming . private_data = private_data ;
2012-05-14 13:48:50 +04:00
TEVENT_FD_READABLE ( nbtsock - > fde ) ;
2005-01-30 13:24:36 +03:00
return NT_STATUS_OK ;
}
2009-01-17 20:15:24 +03:00
/*
setup a handler for unexpected requests
*/
NTSTATUS nbt_set_unexpected_handler ( struct nbt_name_socket * nbtsock ,
void ( * handler ) ( struct nbt_name_socket * , struct nbt_name_packet * ,
struct socket_address * ) ,
2009-01-19 13:39:24 +03:00
void * private_data )
2009-01-17 20:15:24 +03:00
{
nbtsock - > unexpected . handler = handler ;
2009-01-19 13:39:24 +03:00
nbtsock - > unexpected . private_data = private_data ;
2012-05-14 13:48:50 +04:00
TEVENT_FD_READABLE ( nbtsock - > fde ) ;
2009-01-17 20:15:24 +03:00
return NT_STATUS_OK ;
}
2005-02-07 15:10:38 +03:00
/*
turn a NBT rcode into a NTSTATUS
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS nbt_rcode_to_ntstatus ( uint8_t rcode )
2005-02-07 15:10:38 +03:00
{
int i ;
struct {
enum nbt_rcode rcode ;
NTSTATUS status ;
} map [ ] = {
{ NBT_RCODE_FMT , NT_STATUS_INVALID_PARAMETER } ,
{ NBT_RCODE_SVR , NT_STATUS_SERVER_DISABLED } ,
{ NBT_RCODE_NAM , NT_STATUS_OBJECT_NAME_NOT_FOUND } ,
{ NBT_RCODE_IMP , NT_STATUS_NOT_SUPPORTED } ,
{ NBT_RCODE_RFS , NT_STATUS_ACCESS_DENIED } ,
{ NBT_RCODE_ACT , NT_STATUS_ADDRESS_ALREADY_EXISTS } ,
2005-11-28 16:15:57 +03:00
{ NBT_RCODE_CFT , NT_STATUS_CONFLICTING_ADDRESSES }
2005-02-07 15:10:38 +03:00
} ;
for ( i = 0 ; i < ARRAY_SIZE ( map ) ; i + + ) {
if ( map [ i ] . rcode = = rcode ) {
return map [ i ] . status ;
}
}
return NT_STATUS_UNSUCCESSFUL ;
}