2008-09-23 08:58:17 +04:00
/*
2005-01-31 09:55:25 +03:00
Unix SMB / CIFS implementation .
send out a name refresh request
Copyright ( C ) Andrew Tridgell 2005
2008-09-23 08:58:17 +04:00
2005-01-31 09:55:25 +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-31 09:55:25 +03:00
( at your option ) any later version .
2008-09-23 08:58:17 +04:00
2005-01-31 09:55:25 +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-31 09:55:25 +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-31 09:55:25 +03:00
*/
# include "includes.h"
2010-10-11 10:54:27 +04:00
# include <tevent.h>
2008-09-23 08:58:17 +04:00
# include "../libcli/nbt/libnbt.h"
# include "../libcli/nbt/nbt_proto.h"
2006-01-10 01:12:53 +03:00
# include "lib/socket/socket.h"
2010-10-11 10:54:27 +04:00
# include "lib/util/tevent_ntstatus.h"
2005-01-31 09:55:25 +03:00
/*
send a nbt name refresh request
*/
struct nbt_name_request * nbt_name_refresh_send ( struct nbt_name_socket * nbtsock ,
struct nbt_name_refresh * io )
{
struct nbt_name_request * req ;
struct nbt_name_packet * packet ;
2006-01-10 01:12:53 +03:00
struct socket_address * dest ;
2005-01-31 09:55:25 +03:00
packet = talloc_zero ( nbtsock , struct nbt_name_packet ) ;
if ( packet = = NULL ) return NULL ;
packet - > qdcount = 1 ;
packet - > arcount = 1 ;
packet - > operation = NBT_OPCODE_REFRESH ;
if ( io - > in . broadcast ) {
packet - > operation | = NBT_FLAG_BROADCAST ;
}
packet - > questions = talloc_array ( packet , struct nbt_name_question , 1 ) ;
if ( packet - > questions = = NULL ) goto failed ;
packet - > questions [ 0 ] . name = io - > in . name ;
packet - > questions [ 0 ] . question_type = NBT_QTYPE_NETBIOS ;
packet - > questions [ 0 ] . question_class = NBT_QCLASS_IP ;
packet - > additional = talloc_array ( packet , struct nbt_res_rec , 1 ) ;
if ( packet - > additional = = NULL ) goto failed ;
packet - > additional [ 0 ] . name = io - > in . name ;
packet - > additional [ 0 ] . rr_type = NBT_QTYPE_NETBIOS ;
packet - > additional [ 0 ] . rr_class = NBT_QCLASS_IP ;
packet - > additional [ 0 ] . ttl = io - > in . ttl ;
packet - > additional [ 0 ] . rdata . netbios . length = 6 ;
packet - > additional [ 0 ] . rdata . netbios . addresses = talloc_array ( packet - > additional ,
struct nbt_rdata_address , 1 ) ;
if ( packet - > additional [ 0 ] . rdata . netbios . addresses = = NULL ) goto failed ;
packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . nb_flags = io - > in . nb_flags ;
2008-09-23 08:58:17 +04:00
packet - > additional [ 0 ] . rdata . netbios . addresses [ 0 ] . ipaddr =
2005-02-01 07:12:44 +03:00
talloc_strdup ( packet - > additional , io - > in . address ) ;
2005-10-14 16:22:15 +04:00
2008-09-23 08:58:17 +04:00
dest = socket_address_from_strings ( nbtsock ,
nbtsock - > sock - > backend_name ,
2007-12-10 20:41:41 +03:00
io - > in . dest_addr , io - > in . dest_port ) ;
2006-01-10 01:12:53 +03:00
if ( dest = = NULL ) goto failed ;
req = nbt_name_request_send ( nbtsock , dest , packet ,
2007-10-07 02:28:14 +04:00
io - > in . timeout , io - > in . retries , false ) ;
2005-01-31 09:55:25 +03:00
if ( req = = NULL ) goto failed ;
talloc_free ( packet ) ;
return req ;
failed :
talloc_free ( packet ) ;
2008-09-23 08:58:17 +04:00
return NULL ;
2005-01-31 09:55:25 +03:00
}
/*
wait for a refresh reply
*/
2008-09-23 08:58:17 +04:00
_PUBLIC_ NTSTATUS nbt_name_refresh_recv ( struct nbt_name_request * req ,
2005-02-06 11:22:18 +03:00
TALLOC_CTX * mem_ctx , struct nbt_name_refresh * io )
2005-01-31 09:55:25 +03:00
{
NTSTATUS status ;
struct nbt_name_packet * packet ;
status = nbt_name_request_recv ( req ) ;
if ( ! NT_STATUS_IS_OK ( status ) | |
req - > num_replies = = 0 ) {
talloc_free ( req ) ;
return status ;
}
2008-09-23 08:58:17 +04:00
2005-01-31 09:55:25 +03:00
packet = req - > replies [ 0 ] . packet ;
2006-01-10 01:12:53 +03:00
io - > out . reply_from = talloc_steal ( mem_ctx , req - > replies [ 0 ] . dest - > addr ) ;
2005-01-31 09:55:25 +03:00
if ( packet - > ancount ! = 1 | |
packet - > answers [ 0 ] . rr_type ! = NBT_QTYPE_NETBIOS | |
packet - > answers [ 0 ] . rr_class ! = NBT_QCLASS_IP ) {
talloc_free ( req ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
io - > out . rcode = packet - > operation & NBT_RCODE ;
io - > out . name = packet - > answers [ 0 ] . name ;
if ( packet - > answers [ 0 ] . rdata . netbios . length < 6 ) {
talloc_free ( req ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2008-09-23 08:58:17 +04:00
io - > out . reply_addr = talloc_steal ( mem_ctx ,
2005-02-01 07:12:44 +03:00
packet - > answers [ 0 ] . rdata . netbios . addresses [ 0 ] . ipaddr ) ;
2005-01-31 09:55:25 +03:00
talloc_steal ( mem_ctx , io - > out . name . name ) ;
talloc_steal ( mem_ctx , io - > out . name . scope ) ;
2005-02-06 11:22:18 +03:00
2005-01-31 09:55:25 +03:00
talloc_free ( req ) ;
return NT_STATUS_OK ;
}
/*
synchronous name refresh request
*/
2008-09-23 08:58:17 +04:00
_PUBLIC_ NTSTATUS nbt_name_refresh ( struct nbt_name_socket * nbtsock ,
2005-01-31 09:55:25 +03:00
TALLOC_CTX * mem_ctx , struct nbt_name_refresh * io )
{
struct nbt_name_request * req = nbt_name_refresh_send ( nbtsock , io ) ;
return nbt_name_refresh_recv ( req , mem_ctx , io ) ;
}
2005-02-06 11:22:18 +03:00
2007-12-10 20:42:07 +03:00
/**
2005-02-06 11:22:18 +03:00
a wins name refresh with multiple WINS servers and multiple
addresses to refresh . Try each WINS server in turn , until we get a
reply for each address
*/
2010-10-11 10:18:16 +04:00
struct nbt_name_refresh_wins_state {
2005-02-06 11:22:18 +03:00
struct nbt_name_socket * nbtsock ;
struct nbt_name_refresh * io ;
2010-10-11 10:54:27 +04:00
char * * wins_servers ;
2007-12-12 04:15:20 +03:00
uint16_t wins_port ;
2010-10-11 10:54:27 +04:00
char * * addresses ;
2005-02-06 11:22:18 +03:00
int address_idx ;
} ;
2010-10-11 10:54:27 +04:00
static void nbt_name_refresh_wins_handler ( struct nbt_name_request * subreq ) ;
2010-10-11 10:15:01 +04:00
/**
the async send call for a multi - server WINS refresh
*/
2010-10-11 10:54:27 +04:00
_PUBLIC_ struct tevent_req * nbt_name_refresh_wins_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct nbt_name_socket * nbtsock ,
struct nbt_name_refresh_wins * io )
2010-10-11 10:15:01 +04:00
{
2010-10-11 10:54:27 +04:00
struct tevent_req * req ;
2010-10-11 10:18:16 +04:00
struct nbt_name_refresh_wins_state * state ;
2010-10-11 10:54:27 +04:00
struct nbt_name_request * subreq ;
2010-10-11 10:15:01 +04:00
2010-10-11 10:54:27 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct nbt_name_refresh_wins_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2010-10-11 10:15:01 +04:00
state - > io = talloc ( state , struct nbt_name_refresh ) ;
2010-10-11 10:54:27 +04:00
if ( tevent_req_nomem ( state - > io , req ) ) {
return tevent_req_post ( req , ev ) ;
}
if ( io - > in . wins_servers = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
if ( io - > in . wins_servers [ 0 ] = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
if ( io - > in . addresses = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
if ( io - > in . addresses [ 0 ] = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
2010-10-11 10:15:01 +04:00
state - > wins_port = io - > in . wins_port ;
2010-10-11 10:54:27 +04:00
state - > wins_servers = str_list_copy ( state , io - > in . wins_servers ) ;
if ( tevent_req_nomem ( state - > wins_servers , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2010-10-11 10:15:01 +04:00
2010-10-11 10:54:27 +04:00
state - > addresses = str_list_copy ( state , io - > in . addresses ) ;
if ( tevent_req_nomem ( state - > addresses , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2010-10-11 10:15:01 +04:00
state - > io - > in . name = io - > in . name ;
state - > io - > in . dest_addr = state - > wins_servers [ 0 ] ;
state - > io - > in . dest_port = state - > wins_port ;
state - > io - > in . address = io - > in . addresses [ 0 ] ;
state - > io - > in . nb_flags = io - > in . nb_flags ;
state - > io - > in . broadcast = false ;
state - > io - > in . ttl = io - > in . ttl ;
state - > io - > in . timeout = 2 ;
state - > io - > in . retries = 2 ;
state - > nbtsock = nbtsock ;
state - > address_idx = 0 ;
2010-10-11 10:54:27 +04:00
subreq = nbt_name_refresh_send ( nbtsock , state - > io ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2010-10-11 10:15:01 +04:00
2010-10-11 10:54:27 +04:00
subreq - > async . fn = nbt_name_refresh_wins_handler ;
subreq - > async . private_data = req ;
2010-10-11 10:15:01 +04:00
2010-10-11 10:54:27 +04:00
return req ;
2010-10-11 10:15:01 +04:00
}
2010-10-11 10:54:27 +04:00
static void nbt_name_refresh_wins_handler ( struct nbt_name_request * subreq )
2005-02-06 11:22:18 +03:00
{
2010-10-11 10:54:27 +04:00
struct tevent_req * req =
talloc_get_type_abort ( subreq - > async . private_data ,
struct tevent_req ) ;
struct nbt_name_refresh_wins_state * state =
tevent_req_data ( req ,
struct nbt_name_refresh_wins_state ) ;
2005-02-06 11:22:18 +03:00
NTSTATUS status ;
2010-10-11 10:54:27 +04:00
status = nbt_name_refresh_recv ( subreq , state , state - > io ) ;
2005-02-06 11:22:18 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) ) {
/* the refresh timed out - try the next WINS server */
state - > wins_servers + + ;
if ( state - > wins_servers [ 0 ] = = NULL ) {
2010-10-11 10:54:27 +04:00
tevent_req_nterror ( req , status ) ;
return ;
2005-02-06 11:22:18 +03:00
}
2010-10-11 10:54:27 +04:00
state - > address_idx = 0 ;
2005-02-06 11:22:18 +03:00
state - > io - > in . dest_addr = state - > wins_servers [ 0 ] ;
2007-12-12 04:15:20 +03:00
state - > io - > in . dest_port = state - > wins_port ;
2005-02-06 11:22:18 +03:00
state - > io - > in . address = state - > addresses [ 0 ] ;
2010-10-11 10:54:27 +04:00
subreq = nbt_name_refresh_send ( state - > nbtsock , state - > io ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
2005-02-06 11:22:18 +03:00
}
2010-10-11 10:54:27 +04:00
subreq - > async . fn = nbt_name_refresh_wins_handler ;
subreq - > async . private_data = req ;
2005-02-06 11:22:18 +03:00
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-10-11 10:54:27 +04:00
tevent_req_nterror ( req , status ) ;
return ;
2005-02-06 11:22:18 +03:00
}
2010-10-11 10:54:27 +04:00
if ( state - > io - > out . rcode = = 0 & &
state - > addresses [ state - > address_idx + 1 ] ! = NULL ) {
/* refresh our next address */
state - > io - > in . address = state - > addresses [ + + ( state - > address_idx ) ] ;
subreq = nbt_name_refresh_send ( state - > nbtsock , state - > io ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
subreq - > async . fn = nbt_name_refresh_wins_handler ;
subreq - > async . private_data = req ;
return ;
2005-02-06 11:22:18 +03:00
}
2010-10-11 10:54:27 +04:00
tevent_req_done ( req ) ;
2005-02-06 11:22:18 +03:00
}
/*
multi - homed WINS name refresh - recv side
*/
2010-10-11 10:54:27 +04:00
_PUBLIC_ NTSTATUS nbt_name_refresh_wins_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct nbt_name_refresh_wins * io )
2005-02-06 11:22:18 +03:00
{
2010-10-11 10:54:27 +04:00
struct nbt_name_refresh_wins_state * state =
tevent_req_data ( req ,
struct nbt_name_refresh_wins_state ) ;
2005-02-06 11:22:18 +03:00
NTSTATUS status ;
2010-10-11 10:54:27 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
2005-02-06 11:22:18 +03:00
}
2010-10-11 10:54:27 +04:00
io - > out . wins_server = talloc_move ( mem_ctx , & state - > wins_servers [ 0 ] ) ;
io - > out . rcode = state - > io - > out . rcode ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
2005-02-06 11:22:18 +03:00
}
/*
multi - homed WINS refresh - sync interface
*/
2008-04-02 06:53:27 +04:00
_PUBLIC_ NTSTATUS nbt_name_refresh_wins ( struct nbt_name_socket * nbtsock ,
2010-10-11 10:54:27 +04:00
TALLOC_CTX * mem_ctx ,
struct nbt_name_refresh_wins * io )
2005-02-06 11:22:18 +03:00
{
2010-10-11 10:54:27 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * subreq ;
NTSTATUS status ;
/*
* TODO : create a temporary event context
*/
ev = nbtsock - > event_ctx ;
subreq = nbt_name_refresh_wins_send ( frame , ev , nbtsock , io ) ;
if ( subreq = = NULL ) {
talloc_free ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( ! tevent_req_poll ( subreq , ev ) ) {
2011-06-20 08:55:32 +04:00
status = map_nt_error_from_unix_common ( errno ) ;
2010-10-11 10:54:27 +04:00
talloc_free ( frame ) ;
return status ;
}
status = nbt_name_refresh_wins_recv ( subreq , mem_ctx , io ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( frame ) ;
return status ;
}
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
2005-02-06 11:22:18 +03:00
}