2007-10-25 01:16:54 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-06-04 10:42:03 +04:00
name query routines
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1994 - 1998
2007-10-25 01:16:54 +04:00
Copyright ( C ) Jeremy Allison 2007.
1996-06-04 10:42:03 +04: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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1996-06-04 10:42:03 +04:00
( at your option ) any later version .
2007-10-25 01:16:54 +04:00
1996-06-04 10:42:03 +04: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 .
2007-10-25 01:16:54 +04:00
1996-06-04 10:42:03 +04:00
You should have received a copy of the GNU General Public License
2007-10-25 01:16:54 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-06-04 10:42:03 +04:00
*/
# include "includes.h"
2018-03-10 17:31:11 +03:00
# include "libsmb/namequery.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2010-02-23 19:11:37 +03:00
# include "libads/sitename_cache.h"
2012-05-05 00:47:27 +04:00
# include "../lib/addns/dnsquery.h"
2011-01-07 14:01:42 +03:00
# include "../libcli/netlogon/netlogon.h"
2011-01-04 20:17:33 +03:00
# include "lib/async_req/async_sock.h"
2015-05-21 05:43:27 +03:00
# include "lib/tsocket/tsocket.h"
2011-03-23 16:18:59 +03:00
# include "libsmb/nmblib.h"
2018-01-15 18:12:15 +03:00
# include "libsmb/unexpected.h"
2011-11-03 17:40:46 +04:00
# include "../libcli/nbt/libnbt.h"
2015-05-21 10:38:42 +03:00
# include "libads/kerberos_proto.h"
2018-10-18 22:53:36 +03:00
# include "lib/gencache.h"
1996-06-04 10:42:03 +04:00
1998-03-16 23:59:47 +03:00
/* nmbd.c sets this to True. */
2007-10-19 04:40:25 +04:00
bool global_in_nmbd = False ;
1996-06-04 10:42:03 +04:00
2006-02-04 00:19:24 +03:00
/****************************
* SERVER AFFINITY ROUTINES *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-25 01:16:54 +04:00
/* Server affinity is the concept of preferring the last domain
2006-02-04 00:19:24 +03:00
controller with whom you had a successful conversation */
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SAFKEY_FMT "SAF / DOMAIN / %s"
# define SAF_TTL 900
2008-10-27 21:31:30 +03:00
# define SAFJOINKEY_FMT "SAFJOIN / DOMAIN / %s"
# define SAFJOIN_TTL 3600
2006-02-04 00:19:24 +03:00
2011-09-12 23:07:16 +04:00
static char * saf_key ( TALLOC_CTX * mem_ctx , const char * domain )
2006-02-04 00:19:24 +03:00
{
2011-09-12 23:07:16 +04:00
return talloc_asprintf_strupper_m ( mem_ctx , SAFKEY_FMT , domain ) ;
2006-02-04 00:19:24 +03:00
}
2011-09-12 23:11:57 +04:00
static char * saf_join_key ( TALLOC_CTX * mem_ctx , const char * domain )
2008-10-27 21:31:30 +03:00
{
2011-09-12 23:11:57 +04:00
return talloc_asprintf_strupper_m ( mem_ctx , SAFJOINKEY_FMT , domain ) ;
2008-10-27 21:31:30 +03:00
}
2006-02-04 00:19:24 +03:00
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool saf_store ( const char * domain , const char * servername )
2006-02-04 00:19:24 +03:00
{
char * key ;
time_t expire ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
if ( ! domain | | ! servername ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 2 , ( " saf_store: "
" Refusing to store empty domain or servername! \n " ) ) ;
2006-02-04 00:19:24 +03:00
return False ;
}
2006-11-10 16:46:19 +03:00
if ( ( strlen ( domain ) = = 0 ) | | ( strlen ( servername ) = = 0 ) ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 0 , ( " saf_store: "
" refusing to store 0 length domain or servername! \n " ) ) ;
2006-11-10 16:46:19 +03:00
return False ;
}
2007-10-25 01:16:54 +04:00
2011-09-12 23:07:16 +04:00
key = saf_key ( talloc_tos ( ) , domain ) ;
if ( key = = NULL ) {
DEBUG ( 1 , ( " saf_key() failed \n " ) ) ;
return false ;
}
2008-10-27 21:31:30 +03:00
expire = time ( NULL ) + lp_parm_int ( - 1 , " saf " , " ttl " , SAF_TTL ) ;
2007-10-25 01:16:54 +04:00
2006-02-04 02:31:56 +03:00
DEBUG ( 10 , ( " saf_store: domain = [%s], server = [%s], expire = [%u] \n " ,
domain , servername , ( unsigned int ) expire ) ) ;
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
ret = gencache_set ( key , servername , expire ) ;
2007-10-25 01:16:54 +04:00
2011-09-12 23:07:16 +04:00
TALLOC_FREE ( key ) ;
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
return ret ;
}
2008-10-27 21:31:30 +03:00
bool saf_join_store ( const char * domain , const char * servername )
{
char * key ;
time_t expire ;
bool ret = False ;
if ( ! domain | | ! servername ) {
DEBUG ( 2 , ( " saf_join_store: Refusing to store empty domain or servername! \n " ) ) ;
return False ;
}
if ( ( strlen ( domain ) = = 0 ) | | ( strlen ( servername ) = = 0 ) ) {
DEBUG ( 0 , ( " saf_join_store: refusing to store 0 length domain or servername! \n " ) ) ;
return False ;
}
2011-09-12 23:11:57 +04:00
key = saf_join_key ( talloc_tos ( ) , domain ) ;
if ( key = = NULL ) {
DEBUG ( 1 , ( " saf_join_key() failed \n " ) ) ;
return false ;
}
2008-10-27 21:31:30 +03:00
expire = time ( NULL ) + lp_parm_int ( - 1 , " saf " , " join ttl " , SAFJOIN_TTL ) ;
DEBUG ( 10 , ( " saf_join_store: domain = [%s], server = [%s], expire = [%u] \n " ,
domain , servername , ( unsigned int ) expire ) ) ;
ret = gencache_set ( key , servername , expire ) ;
2011-09-12 23:11:57 +04:00
TALLOC_FREE ( key ) ;
2008-10-27 21:31:30 +03:00
return ret ;
}
2007-10-19 04:40:25 +04:00
bool saf_delete ( const char * domain )
2006-09-07 07:44:05 +04:00
{
char * key ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-10-25 01:16:54 +04:00
2006-11-17 02:48:46 +03:00
if ( ! domain ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 2 , ( " saf_delete: Refusing to delete empty domain \n " ) ) ;
2006-09-07 07:44:05 +04:00
return False ;
}
2007-10-25 01:16:54 +04:00
2011-09-12 23:11:57 +04:00
key = saf_join_key ( talloc_tos ( ) , domain ) ;
if ( key = = NULL ) {
DEBUG ( 1 , ( " saf_join_key() failed \n " ) ) ;
return false ;
}
2008-10-27 21:31:30 +03:00
ret = gencache_del ( key ) ;
2011-09-12 23:11:57 +04:00
TALLOC_FREE ( key ) ;
2008-10-27 21:31:30 +03:00
if ( ret ) {
DEBUG ( 10 , ( " saf_delete[join]: domain = [%s] \n " , domain ) ) ;
}
2011-09-12 23:07:16 +04:00
key = saf_key ( talloc_tos ( ) , domain ) ;
if ( key = = NULL ) {
DEBUG ( 1 , ( " saf_key() failed \n " ) ) ;
return false ;
}
2006-09-07 07:44:05 +04:00
ret = gencache_del ( key ) ;
2011-09-12 23:07:16 +04:00
TALLOC_FREE ( key ) ;
2007-10-25 01:16:54 +04:00
2006-09-07 07:44:05 +04:00
if ( ret ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 10 , ( " saf_delete: domain = [%s] \n " , domain ) ) ;
2006-09-07 07:44:05 +04:00
}
2006-11-17 02:48:46 +03:00
2006-09-07 07:44:05 +04:00
return ret ;
}
2006-02-04 00:19:24 +03:00
/****************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-09-05 00:39:31 +04:00
char * saf_fetch ( TALLOC_CTX * mem_ctx , const char * domain )
2006-02-04 00:19:24 +03:00
{
char * server = NULL ;
2008-07-11 19:44:25 +04:00
time_t timeout ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2006-02-04 00:19:24 +03:00
char * key = NULL ;
2006-11-10 16:46:19 +03:00
if ( ! domain | | strlen ( domain ) = = 0 ) {
2006-02-04 00:19:24 +03:00
DEBUG ( 2 , ( " saf_fetch: Empty domain name! \n " ) ) ;
return NULL ;
}
2007-10-25 01:16:54 +04:00
2011-09-12 23:11:57 +04:00
key = saf_join_key ( talloc_tos ( ) , domain ) ;
if ( key = = NULL ) {
DEBUG ( 1 , ( " saf_join_key() failed \n " ) ) ;
return NULL ;
}
2008-10-27 21:31:30 +03:00
2013-09-05 00:39:31 +04:00
ret = gencache_get ( key , mem_ctx , & server , & timeout ) ;
2008-10-27 21:31:30 +03:00
2011-09-12 23:11:57 +04:00
TALLOC_FREE ( key ) ;
2008-10-27 21:31:30 +03:00
if ( ret ) {
DEBUG ( 5 , ( " saf_fetch[join]: Returning \" %s \" for \" %s \" domain \n " ,
server , domain ) ) ;
return server ;
}
2011-09-12 23:07:16 +04:00
key = saf_key ( talloc_tos ( ) , domain ) ;
if ( key = = NULL ) {
DEBUG ( 1 , ( " saf_key() failed \n " ) ) ;
return NULL ;
}
2007-10-25 01:16:54 +04:00
2013-09-05 00:39:31 +04:00
ret = gencache_get ( key , mem_ctx , & server , & timeout ) ;
2007-10-25 01:16:54 +04:00
2011-09-12 23:07:16 +04:00
TALLOC_FREE ( key ) ;
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
if ( ! ret ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 5 , ( " saf_fetch: failed to find server for \" %s \" domain \n " ,
domain ) ) ;
2006-02-04 00:19:24 +03:00
} else {
2007-10-25 01:16:54 +04:00
DEBUG ( 5 , ( " saf_fetch: Returning \" %s \" for \" %s \" domain \n " ,
2006-02-04 00:19:24 +03:00
server , domain ) ) ;
}
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
return server ;
}
2011-05-14 20:04:49 +04:00
static void set_socket_addr_v4 ( struct sockaddr_storage * addr )
{
2012-07-27 06:56:22 +04:00
if ( ! interpret_string_addr ( addr , lp_nbt_client_socket_address ( ) ,
2011-05-14 20:04:49 +04:00
AI_NUMERICHOST | AI_PASSIVE ) ) {
zero_sockaddr ( addr ) ;
}
if ( addr - > ss_family ! = AF_INET ) {
zero_sockaddr ( addr ) ;
}
}
2011-05-14 20:24:03 +04:00
static struct in_addr my_socket_addr_v4 ( void )
{
struct sockaddr_storage my_addr ;
struct sockaddr_in * in_addr = ( struct sockaddr_in * ) ( ( char * ) & my_addr ) ;
set_socket_addr_v4 ( & my_addr ) ;
return in_addr - > sin_addr ;
}
2000-01-03 06:17:16 +03:00
/****************************************************************************
2003-06-14 01:03:15 +04:00
Generate a random trn_id .
2000-01-03 06:17:16 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-14 01:03:15 +04:00
2000-01-03 06:17:16 +03:00
static int generate_trn_id ( void )
{
2015-05-10 02:59:45 +03:00
uint16_t id ;
2000-01-03 06:17:16 +03:00
2015-05-10 02:59:45 +03:00
generate_random_buffer ( ( uint8_t * ) & id , sizeof ( id ) ) ;
2000-01-03 06:17:16 +03:00
2007-07-05 02:30:25 +04:00
return id % ( unsigned ) 0x7FFF ;
2000-01-03 06:17:16 +03:00
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
2003-06-14 01:03:15 +04:00
Parse a node status response into an array of structures .
1996-06-04 10:42:03 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-14 01:03:15 +04:00
2010-12-28 14:53:12 +03:00
static struct node_status * parse_node_status ( TALLOC_CTX * mem_ctx , char * p ,
2007-10-25 01:16:54 +04:00
int * num_names ,
struct node_status_extra * extra )
1996-06-04 10:42:03 +04:00
{
2010-12-28 13:55:47 +03:00
struct node_status * ret ;
2000-12-20 06:22:51 +03:00
int i ;
1996-06-04 10:42:03 +04:00
2000-12-20 06:22:51 +03:00
* num_names = CVAL ( p , 0 ) ;
2003-06-14 01:03:15 +04:00
if ( * num_names = = 0 )
return NULL ;
2000-12-20 06:22:51 +03:00
2011-06-07 05:30:12 +04:00
ret = talloc_array ( mem_ctx , struct node_status , * num_names ) ;
2004-07-02 05:09:10 +04:00
if ( ! ret )
return NULL ;
1999-12-13 16:27:58 +03:00
2000-12-20 06:22:51 +03:00
p + + ;
for ( i = 0 ; i < * num_names ; i + + ) {
StrnCpy ( ret [ i ] . name , p , 15 ) ;
2003-09-05 23:59:55 +04:00
trim_char ( ret [ i ] . name , ' \0 ' , ' ' ) ;
2000-12-20 06:22:51 +03:00
ret [ i ] . type = CVAL ( p , 15 ) ;
ret [ i ] . flags = p [ 16 ] ;
p + = 18 ;
2007-10-25 01:16:54 +04:00
DEBUG ( 10 , ( " %s#%02x: flags = 0x%02x \n " , ret [ i ] . name ,
2002-01-21 01:50:23 +03:00
ret [ i ] . type , ret [ i ] . flags ) ) ;
2000-12-20 06:22:51 +03:00
}
2004-04-16 07:57:30 +04:00
/*
* Also , pick up the MAC address . . .
*/
if ( extra ) {
memcpy ( & extra - > mac_addr , p , 6 ) ; /* Fill in the mac addr */
}
2000-12-20 06:22:51 +03:00
return ret ;
1996-06-04 10:42:03 +04:00
}
2011-01-04 20:17:33 +03:00
struct sock_packet_read_state {
struct tevent_context * ev ;
enum packet_type type ;
int trn_id ;
struct nb_packet_reader * reader ;
struct tevent_req * reader_req ;
2015-05-21 05:43:27 +03:00
struct tdgram_context * sock ;
2011-01-04 20:17:33 +03:00
struct tevent_req * socket_req ;
2015-05-21 05:43:27 +03:00
uint8_t * buf ;
struct tsocket_address * addr ;
2011-01-04 20:17:33 +03:00
bool ( * validator ) ( struct packet_struct * p ,
void * private_data ) ;
void * private_data ;
struct packet_struct * packet ;
} ;
static void sock_packet_read_got_packet ( struct tevent_req * subreq ) ;
static void sock_packet_read_got_socket ( struct tevent_req * subreq ) ;
static struct tevent_req * sock_packet_read_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2015-05-21 05:43:27 +03:00
struct tdgram_context * sock ,
2011-01-04 20:17:33 +03:00
struct nb_packet_reader * reader ,
enum packet_type type ,
int trn_id ,
bool ( * validator ) ( struct packet_struct * p , void * private_data ) ,
void * private_data )
{
struct tevent_req * req ;
struct sock_packet_read_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct sock_packet_read_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > reader = reader ;
state - > sock = sock ;
state - > type = type ;
state - > trn_id = trn_id ;
state - > validator = validator ;
state - > private_data = private_data ;
if ( reader ! = NULL ) {
state - > reader_req = nb_packet_read_send ( state , ev , reader ) ;
if ( tevent_req_nomem ( state - > reader_req , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback (
state - > reader_req , sock_packet_read_got_packet , req ) ;
}
2015-05-21 05:43:27 +03:00
state - > socket_req = tdgram_recvfrom_send ( state , ev , state - > sock ) ;
2011-01-04 20:17:33 +03:00
if ( tevent_req_nomem ( state - > socket_req , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( state - > socket_req , sock_packet_read_got_socket ,
req ) ;
return req ;
}
static void sock_packet_read_got_packet ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_packet_read_state * state = tevent_req_data (
req , struct sock_packet_read_state ) ;
NTSTATUS status ;
2018-01-16 17:50:19 +03:00
status = nb_packet_read_recv ( subreq , state , & state - > packet ) ;
2011-01-04 20:17:33 +03:00
TALLOC_FREE ( state - > reader_req ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( state - > socket_req ! = NULL ) {
/*
* Still waiting for socket
*/
return ;
}
/*
* Both socket and packet reader failed
*/
tevent_req_nterror ( req , status ) ;
return ;
}
if ( ( state - > validator ! = NULL ) & &
! state - > validator ( state - > packet , state - > private_data ) ) {
DEBUG ( 10 , ( " validator failed \n " ) ) ;
2018-01-16 17:50:19 +03:00
TALLOC_FREE ( state - > packet ) ;
2011-01-04 20:17:33 +03:00
state - > reader_req = nb_packet_read_send ( state , state - > ev ,
state - > reader ) ;
if ( tevent_req_nomem ( state - > reader_req , req ) ) {
return ;
}
tevent_req_set_callback (
state - > reader_req , sock_packet_read_got_packet , req ) ;
return ;
}
TALLOC_FREE ( state - > socket_req ) ;
tevent_req_done ( req ) ;
}
static void sock_packet_read_got_socket ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct sock_packet_read_state * state = tevent_req_data (
req , struct sock_packet_read_state ) ;
2015-05-21 05:43:27 +03:00
union {
struct sockaddr sa ;
struct sockaddr_in sin ;
} addr ;
ssize_t ret ;
2011-01-04 20:17:33 +03:00
ssize_t received ;
int err ;
2015-05-21 05:43:27 +03:00
bool ok ;
2011-01-04 20:17:33 +03:00
2015-05-21 05:43:27 +03:00
received = tdgram_recvfrom_recv ( subreq , & err , state ,
& state - > buf , & state - > addr ) ;
2011-01-04 20:17:33 +03:00
TALLOC_FREE ( state - > socket_req ) ;
if ( received = = - 1 ) {
if ( state - > reader_req ! = NULL ) {
/*
* Still waiting for reader
*/
return ;
}
/*
* Both socket and reader failed
*/
tevent_req_nterror ( req , map_nt_error_from_unix ( err ) ) ;
return ;
}
2015-05-21 05:43:27 +03:00
ok = tsocket_address_is_inet ( state - > addr , " ipv4 " ) ;
if ( ! ok ) {
2011-01-04 20:17:33 +03:00
goto retry ;
}
2015-05-21 05:43:27 +03:00
ret = tsocket_address_bsd_sockaddr ( state - > addr ,
& addr . sa ,
sizeof ( addr . sin ) ) ;
if ( ret = = - 1 ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return ;
}
2011-01-04 20:17:33 +03:00
2018-01-16 17:50:19 +03:00
state - > packet = parse_packet_talloc (
state , ( char * ) state - > buf , received , state - > type ,
addr . sin . sin_addr , addr . sin . sin_port ) ;
2011-01-04 20:17:33 +03:00
if ( state - > packet = = NULL ) {
DEBUG ( 10 , ( " parse_packet failed \n " ) ) ;
goto retry ;
}
if ( ( state - > trn_id ! = - 1 ) & &
( state - > trn_id ! = packet_trn_id ( state - > packet ) ) ) {
DEBUG ( 10 , ( " Expected transaction id %d, got %d \n " ,
state - > trn_id , packet_trn_id ( state - > packet ) ) ) ;
goto retry ;
}
if ( ( state - > validator ! = NULL ) & &
! state - > validator ( state - > packet , state - > private_data ) ) {
DEBUG ( 10 , ( " validator failed \n " ) ) ;
goto retry ;
}
tevent_req_done ( req ) ;
return ;
retry :
2018-01-16 17:50:19 +03:00
TALLOC_FREE ( state - > packet ) ;
2015-05-21 05:43:27 +03:00
TALLOC_FREE ( state - > buf ) ;
TALLOC_FREE ( state - > addr ) ;
state - > socket_req = tdgram_recvfrom_send ( state , state - > ev , state - > sock ) ;
2011-01-04 20:17:33 +03:00
if ( tevent_req_nomem ( state - > socket_req , req ) ) {
return ;
}
tevent_req_set_callback ( state - > socket_req , sock_packet_read_got_socket ,
req ) ;
}
static NTSTATUS sock_packet_read_recv ( struct tevent_req * req ,
2018-01-16 17:50:19 +03:00
TALLOC_CTX * mem_ctx ,
2011-01-04 20:17:33 +03:00
struct packet_struct * * ppacket )
{
struct sock_packet_read_state * state = tevent_req_data (
req , struct sock_packet_read_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
2018-01-16 17:50:19 +03:00
* ppacket = talloc_move ( mem_ctx , & state - > packet ) ;
2011-01-04 20:17:33 +03:00
return NT_STATUS_OK ;
}
2011-01-04 20:22:38 +03:00
struct nb_trans_state {
struct tevent_context * ev ;
2015-05-21 05:43:27 +03:00
struct tdgram_context * sock ;
2011-01-04 20:22:38 +03:00
struct nb_packet_reader * reader ;
2015-05-21 05:43:27 +03:00
struct tsocket_address * src_addr ;
struct tsocket_address * dst_addr ;
2011-01-04 20:22:38 +03:00
uint8_t * buf ;
size_t buflen ;
enum packet_type type ;
int trn_id ;
bool ( * validator ) ( struct packet_struct * p ,
void * private_data ) ;
void * private_data ;
struct packet_struct * packet ;
} ;
static void nb_trans_got_reader ( struct tevent_req * subreq ) ;
static void nb_trans_done ( struct tevent_req * subreq ) ;
static void nb_trans_sent ( struct tevent_req * subreq ) ;
static void nb_trans_send_next ( struct tevent_req * subreq ) ;
static struct tevent_req * nb_trans_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
2015-05-21 05:43:27 +03:00
const struct sockaddr_storage * _my_addr ,
const struct sockaddr_storage * _dst_addr ,
2011-01-04 20:22:38 +03:00
bool bcast ,
uint8_t * buf , size_t buflen ,
enum packet_type type , int trn_id ,
bool ( * validator ) ( struct packet_struct * p ,
void * private_data ) ,
void * private_data )
{
2015-05-21 05:43:27 +03:00
const struct sockaddr * my_addr =
discard_const_p ( const struct sockaddr , _my_addr ) ;
size_t my_addr_len = sizeof ( * _my_addr ) ;
const struct sockaddr * dst_addr =
discard_const_p ( const struct sockaddr , _dst_addr ) ;
size_t dst_addr_len = sizeof ( * _dst_addr ) ;
2011-01-04 20:22:38 +03:00
struct tevent_req * req , * subreq ;
struct nb_trans_state * state ;
2015-05-21 05:43:27 +03:00
int ret ;
2011-01-04 20:22:38 +03:00
req = tevent_req_create ( mem_ctx , & state , struct nb_trans_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > buf = buf ;
state - > buflen = buflen ;
state - > type = type ;
state - > trn_id = trn_id ;
state - > validator = validator ;
state - > private_data = private_data ;
2015-05-21 05:43:27 +03:00
ret = tsocket_address_bsd_from_sockaddr ( state ,
my_addr , my_addr_len ,
& state - > src_addr ) ;
if ( ret = = - 1 ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return tevent_req_post ( req , ev ) ;
}
ret = tsocket_address_bsd_from_sockaddr ( state ,
dst_addr , dst_addr_len ,
& state - > dst_addr ) ;
if ( ret = = - 1 ) {
2011-01-04 20:22:38 +03:00
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return tevent_req_post ( req , ev ) ;
}
2015-05-21 05:43:27 +03:00
ret = tdgram_inet_udp_broadcast_socket ( state - > src_addr , state ,
& state - > sock ) ;
if ( ret = = - 1 ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return tevent_req_post ( req , ev ) ;
2011-01-04 20:22:38 +03:00
}
subreq = nb_packet_reader_send ( state , ev , type , state - > trn_id , NULL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , nb_trans_got_reader , req ) ;
return req ;
}
static void nb_trans_got_reader ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct nb_trans_state * state = tevent_req_data (
req , struct nb_trans_state ) ;
NTSTATUS status ;
status = nb_packet_reader_recv ( subreq , state , & state - > reader ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " nmbd not around \n " ) ) ;
state - > reader = NULL ;
}
subreq = sock_packet_read_send (
state , state - > ev , state - > sock ,
state - > reader , state - > type , state - > trn_id ,
state - > validator , state - > private_data ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , nb_trans_done , req ) ;
2015-05-21 05:43:27 +03:00
subreq = tdgram_sendto_send ( state , state - > ev ,
state - > sock ,
state - > buf , state - > buflen ,
state - > dst_addr ) ;
2011-01-04 20:22:38 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , nb_trans_sent , req ) ;
}
static void nb_trans_sent ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct nb_trans_state * state = tevent_req_data (
req , struct nb_trans_state ) ;
ssize_t sent ;
int err ;
2015-05-21 05:43:27 +03:00
sent = tdgram_sendto_recv ( subreq , & err ) ;
2011-01-04 20:22:38 +03:00
TALLOC_FREE ( subreq ) ;
if ( sent = = - 1 ) {
DEBUG ( 10 , ( " sendto failed: %s \n " , strerror ( err ) ) ) ;
tevent_req_nterror ( req , map_nt_error_from_unix ( err ) ) ;
return ;
}
subreq = tevent_wakeup_send ( state , state - > ev ,
timeval_current_ofs ( 1 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , nb_trans_send_next , req ) ;
}
static void nb_trans_send_next ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct nb_trans_state * state = tevent_req_data (
req , struct nb_trans_state ) ;
bool ret ;
ret = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! ret ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
2015-05-21 05:43:27 +03:00
subreq = tdgram_sendto_send ( state , state - > ev ,
state - > sock ,
state - > buf , state - > buflen ,
state - > dst_addr ) ;
2011-01-04 20:22:38 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , nb_trans_sent , req ) ;
}
static void nb_trans_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct nb_trans_state * state = tevent_req_data (
req , struct nb_trans_state ) ;
NTSTATUS status ;
2018-01-16 17:50:19 +03:00
status = sock_packet_read_recv ( subreq , state , & state - > packet ) ;
2011-01-04 20:22:38 +03:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2018-01-16 17:50:19 +03:00
static NTSTATUS nb_trans_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
2011-01-04 20:22:38 +03:00
struct packet_struct * * ppacket )
{
struct nb_trans_state * state = tevent_req_data (
req , struct nb_trans_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
2018-01-16 17:50:19 +03:00
* ppacket = talloc_move ( mem_ctx , & state - > packet ) ;
2011-01-04 20:22:38 +03:00
return NT_STATUS_OK ;
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
2003-06-14 01:03:15 +04:00
Do a NBT node status query on an open socket and return an array of
structures holding the returned names or NULL if the query failed .
1999-12-13 16:27:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-14 01:03:15 +04:00
2011-01-04 20:34:38 +03:00
struct node_status_query_state {
struct sockaddr_storage my_addr ;
struct sockaddr_storage addr ;
uint8_t buf [ 1024 ] ;
ssize_t buflen ;
struct packet_struct * packet ;
} ;
static bool node_status_query_validator ( struct packet_struct * p ,
void * private_data ) ;
static void node_status_query_done ( struct tevent_req * subreq ) ;
struct tevent_req * node_status_query_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct nmb_name * name ,
const struct sockaddr_storage * addr )
1996-06-04 10:42:03 +04:00
{
2011-01-04 20:34:38 +03:00
struct tevent_req * req , * subreq ;
struct node_status_query_state * state ;
2000-12-20 06:22:51 +03:00
struct packet_struct p ;
struct nmb_packet * nmb = & p . packet . nmb ;
2011-01-04 20:34:38 +03:00
struct sockaddr_in * in_addr ;
2000-12-20 06:22:51 +03:00
2011-01-04 20:34:38 +03:00
req = tevent_req_create ( mem_ctx , & state ,
struct node_status_query_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2000-12-20 06:22:51 +03:00
2011-01-04 20:34:38 +03:00
if ( addr - > ss_family ! = AF_INET ) {
2007-10-25 01:16:54 +04:00
/* Can't do node status to IPv6 */
2011-01-04 20:34:38 +03:00
tevent_req_nterror ( req , NT_STATUS_INVALID_ADDRESS ) ;
return tevent_req_post ( req , ev ) ;
2007-10-25 01:16:54 +04:00
}
2011-01-04 20:34:38 +03:00
state - > addr = * addr ;
in_addr = ( struct sockaddr_in * ) ( void * ) & state - > addr ;
in_addr - > sin_port = htons ( NMB_PORT ) ;
2011-05-14 20:04:49 +04:00
set_socket_addr_v4 ( & state - > my_addr ) ;
2011-01-04 20:34:38 +03:00
ZERO_STRUCT ( p ) ;
2000-12-20 06:22:51 +03:00
nmb - > header . name_trn_id = generate_trn_id ( ) ;
nmb - > header . opcode = 0 ;
2007-10-25 01:16:54 +04:00
nmb - > header . response = false ;
nmb - > header . nm_flags . bcast = false ;
nmb - > header . nm_flags . recursion_available = false ;
nmb - > header . nm_flags . recursion_desired = false ;
nmb - > header . nm_flags . trunc = false ;
nmb - > header . nm_flags . authoritative = false ;
2000-12-20 06:22:51 +03:00
nmb - > header . rcode = 0 ;
nmb - > header . qdcount = 1 ;
nmb - > header . ancount = 0 ;
nmb - > header . nscount = 0 ;
nmb - > header . arcount = 0 ;
nmb - > question . question_name = * name ;
nmb - > question . question_type = 0x21 ;
nmb - > question . question_class = 0x1 ;
2011-01-04 20:34:38 +03:00
state - > buflen = build_packet ( ( char * ) state - > buf , sizeof ( state - > buf ) ,
& p ) ;
if ( state - > buflen = = 0 ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
DEBUG ( 10 , ( " build_packet failed \n " ) ) ;
return tevent_req_post ( req , ev ) ;
}
2000-12-20 06:22:51 +03:00
2011-01-04 20:48:47 +03:00
subreq = nb_trans_send ( state , ev , & state - > my_addr , & state - > addr , false ,
2011-01-04 20:34:38 +03:00
state - > buf , state - > buflen ,
NMB_PACKET , nmb - > header . name_trn_id ,
node_status_query_validator , NULL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
DEBUG ( 10 , ( " nb_trans_send failed \n " ) ) ;
return tevent_req_post ( req , ev ) ;
}
if ( ! tevent_req_set_endtime ( req , ev , timeval_current_ofs ( 10 , 0 ) ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , node_status_query_done , req ) ;
return req ;
}
1996-06-04 10:42:03 +04:00
2011-01-04 20:34:38 +03:00
static bool node_status_query_validator ( struct packet_struct * p ,
void * private_data )
{
struct nmb_packet * nmb = & p - > packet . nmb ;
debug_nmb_packet ( p ) ;
if ( nmb - > header . opcode ! = 0 | |
nmb - > header . nm_flags . bcast | |
nmb - > header . rcode | |
! nmb - > header . ancount | |
nmb - > answers - > rr_type ! = 0x21 ) {
/*
* XXXX what do we do with this ? could be a redirect ,
* but we ' ll discard it for the moment
*/
return false ;
}
return true ;
}
1996-06-04 10:42:03 +04:00
2011-01-04 20:34:38 +03:00
static void node_status_query_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct node_status_query_state * state = tevent_req_data (
req , struct node_status_query_state ) ;
NTSTATUS status ;
2018-01-16 17:50:19 +03:00
status = nb_trans_recv ( subreq , state , & state - > packet ) ;
2011-01-04 20:34:38 +03:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS node_status_query_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct node_status * * pnode_status ,
int * pnum_names ,
struct node_status_extra * extra )
{
struct node_status_query_state * state = tevent_req_data (
req , struct node_status_query_state ) ;
struct node_status * node_status ;
int num_names ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
node_status = parse_node_status (
mem_ctx , & state - > packet - > packet . nmb . answers - > rdata [ 0 ] ,
& num_names , extra ) ;
if ( node_status = = NULL ) {
return NT_STATUS_NO_MEMORY ;
2000-12-20 06:22:51 +03:00
}
2011-01-04 20:34:38 +03:00
* pnode_status = node_status ;
* pnum_names = num_names ;
return NT_STATUS_OK ;
}
NTSTATUS node_status_query ( TALLOC_CTX * mem_ctx , struct nmb_name * name ,
const struct sockaddr_storage * addr ,
struct node_status * * pnode_status ,
int * pnum_names ,
struct node_status_extra * extra )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2007-10-25 01:16:54 +04:00
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-01-04 20:34:38 +03:00
if ( ev = = NULL ) {
goto fail ;
}
req = node_status_query_send ( ev , ev , name , addr ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = node_status_query_recv ( req , mem_ctx , pnode_status ,
pnum_names , extra ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
2000-12-20 06:22:51 +03:00
}
1999-12-13 16:27:58 +03:00
2016-12-19 22:18:41 +03:00
static bool name_status_lmhosts ( const struct sockaddr_storage * paddr ,
int qname_type , fstring pname )
{
FILE * f ;
char * name ;
int name_type ;
struct sockaddr_storage addr ;
if ( paddr - > ss_family ! = AF_INET ) {
return false ;
}
f = startlmhosts ( get_dyn_LMHOSTSFILE ( ) ) ;
if ( f = = NULL ) {
return false ;
}
while ( getlmhostsent ( talloc_tos ( ) , f , & name , & name_type , & addr ) ) {
if ( addr . ss_family ! = AF_INET ) {
continue ;
}
if ( name_type ! = qname_type ) {
continue ;
}
if ( memcmp ( & ( ( const struct sockaddr_in * ) paddr ) - > sin_addr ,
& ( ( const struct sockaddr_in * ) & addr ) - > sin_addr ,
sizeof ( struct in_addr ) ) = = 0 ) {
fstrcpy ( pname , name ) ;
endlmhosts ( f ) ;
return true ;
}
}
endlmhosts ( f ) ;
return false ;
}
2000-12-20 06:22:51 +03:00
/****************************************************************************
2003-06-14 01:03:15 +04:00
Find the first type XX name in a node status reply - used for finding
a servers name given its IP . Return the matched name in * name .
2000-12-20 06:22:51 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-22 02:00:59 +03:00
2007-10-25 01:16:54 +04:00
bool name_status_find ( const char * q_name ,
int q_type ,
int type ,
const struct sockaddr_storage * to_ss ,
fstring name )
2000-12-20 06:22:51 +03:00
{
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
struct sockaddr_storage ss ;
2010-12-28 14:53:12 +03:00
struct node_status * addrs = NULL ;
2000-12-20 06:22:51 +03:00
struct nmb_name nname ;
int count , i ;
2007-10-25 01:16:54 +04:00
bool result = false ;
2010-12-28 14:53:12 +03:00
NTSTATUS status ;
2002-01-16 04:41:30 +03:00
2002-08-17 21:00:51 +04:00
if ( lp_disable_netbios ( ) ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 5 , ( " name_status_find(%s#%02x): netbios is disabled \n " ,
q_name , q_type ) ) ;
2002-08-17 21:00:51 +04:00
return False ;
}
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , to_ss ) ;
DEBUG ( 10 , ( " name_status_find: looking up %s#%02x at %s \n " , q_name ,
q_type , addr ) ) ;
1996-06-04 10:42:03 +04:00
2003-06-14 01:03:15 +04:00
/* Check the cache first. */
2007-10-25 01:16:54 +04:00
if ( namecache_status_fetch ( q_name , q_type , type , to_ss , name ) ) {
2003-06-14 01:03:15 +04:00
return True ;
2007-10-25 01:16:54 +04:00
}
if ( to_ss - > ss_family ! = AF_INET ) {
/* Can't do node status to IPv6 */
return false ;
}
2016-12-19 22:18:41 +03:00
result = name_status_lmhosts ( to_ss , type , name ) ;
if ( result ) {
DBG_DEBUG ( " Found name %s in lmhosts \n " , name ) ;
namecache_status_store ( q_name , q_type , type , to_ss , name ) ;
return true ;
}
2011-05-14 20:04:49 +04:00
set_socket_addr_v4 ( & ss ) ;
2003-06-14 01:03:15 +04:00
2001-11-22 02:00:59 +03:00
/* W2K PDC's seem not to respond to '*'#0. JRA */
make_nmb_name ( & nname , q_name , q_type ) ;
2011-01-04 20:34:38 +03:00
status = node_status_query ( talloc_tos ( ) , & nname , to_ss ,
2010-12-28 14:53:12 +03:00
& addrs , & count , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2002-01-16 04:41:30 +03:00
goto done ;
2010-12-28 14:53:12 +03:00
}
2000-01-03 06:17:16 +03:00
2000-12-20 06:22:51 +03:00
for ( i = 0 ; i < count ; i + + ) {
2009-04-27 17:27:52 +04:00
/* Find first one of the requested type that's not a GROUP. */
2010-12-28 14:53:12 +03:00
if ( addrs [ i ] . type = = type & & ! ( addrs [ i ] . flags & 0x80 ) )
2001-11-22 02:00:59 +03:00
break ;
2000-12-20 06:22:51 +03:00
}
2001-11-22 02:00:59 +03:00
if ( i = = count )
2002-01-16 04:41:30 +03:00
goto done ;
1996-06-04 10:42:03 +04:00
2010-12-28 14:53:12 +03:00
pull_ascii_nstring ( name , sizeof ( fstring ) , addrs [ i ] . name ) ;
2003-06-14 01:03:15 +04:00
/* Store the result in the cache. */
2007-10-25 01:16:54 +04:00
/* but don't store an entry for 0x1c names here. Here we have
2003-06-25 21:41:05 +04:00
a single host and DOMAIN < 0x1c > names should be a list of hosts */
2003-06-14 01:03:15 +04:00
2007-10-25 01:16:54 +04:00
if ( q_type ! = 0x1c ) {
namecache_status_store ( q_name , q_type , type , to_ss , name ) ;
}
result = true ;
2001-02-14 08:34:50 +03:00
2002-01-16 04:41:30 +03:00
done :
2010-12-28 14:53:12 +03:00
TALLOC_FREE ( addrs ) ;
2002-01-16 04:41:30 +03:00
DEBUG ( 10 , ( " name_status_find: name %sfound " , result ? " " : " not " ) ) ;
if ( result )
2007-10-25 01:16:54 +04:00
DEBUGADD ( 10 , ( " , name %s ip address is %s " , name , addr ) ) ;
2002-01-16 04:41:30 +03:00
2007-10-25 01:16:54 +04:00
DEBUG ( 10 , ( " \n " ) ) ;
2002-01-16 04:41:30 +03:00
return result ;
1996-06-04 10:42:03 +04:00
}
2002-07-15 14:35:28 +04:00
/*
2007-10-25 01:16:54 +04:00
comparison function used by sort_addr_list
2002-07-15 14:35:28 +04:00
*/
2003-06-14 01:03:15 +04:00
2010-02-14 01:59:26 +03:00
static int addr_compare ( const struct sockaddr_storage * ss1 ,
const struct sockaddr_storage * ss2 )
2002-07-15 14:35:28 +04:00
{
int max_bits1 = 0 , max_bits2 = 0 ;
int num_interfaces = iface_count ( ) ;
int i ;
2001-02-18 13:36:03 +03:00
2009-07-28 22:51:58 +04:00
/* Sort IPv4 addresses first. */
2010-02-14 01:59:26 +03:00
if ( ss1 - > ss_family ! = ss2 - > ss_family ) {
if ( ss2 - > ss_family = = AF_INET ) {
2007-10-25 01:16:54 +04:00
return 1 ;
2009-07-28 22:51:58 +04:00
} else {
return - 1 ;
2007-10-25 01:16:54 +04:00
}
}
/* Here we know both addresses are of the same
* family . */
2002-07-15 14:35:28 +04:00
for ( i = 0 ; i < num_interfaces ; i + + ) {
2007-10-11 05:25:16 +04:00
const struct sockaddr_storage * pss = iface_n_bcast ( i ) ;
2011-05-06 01:22:11 +04:00
const unsigned char * p_ss1 = NULL ;
const unsigned char * p_ss2 = NULL ;
const unsigned char * p_if = NULL ;
2007-10-25 01:16:54 +04:00
size_t len = 0 ;
2002-07-15 14:35:28 +04:00
int bits1 , bits2 ;
2007-10-11 05:25:16 +04:00
2010-02-14 01:59:26 +03:00
if ( pss - > ss_family ! = ss1 - > ss_family ) {
2007-10-25 01:16:54 +04:00
/* Ignore interfaces of the wrong type. */
2007-10-11 05:25:16 +04:00
continue ;
}
2007-10-25 01:16:54 +04:00
if ( pss - > ss_family = = AF_INET ) {
2011-05-06 01:22:11 +04:00
p_if = ( const unsigned char * )
2007-10-25 01:16:54 +04:00
& ( ( const struct sockaddr_in * ) pss ) - > sin_addr ;
2011-05-06 01:22:11 +04:00
p_ss1 = ( const unsigned char * )
2007-10-25 01:16:54 +04:00
& ( ( const struct sockaddr_in * ) ss1 ) - > sin_addr ;
2011-05-06 01:22:11 +04:00
p_ss2 = ( const unsigned char * )
2007-10-25 01:16:54 +04:00
& ( ( const struct sockaddr_in * ) ss2 ) - > sin_addr ;
len = 4 ;
}
# if defined(HAVE_IPV6)
if ( pss - > ss_family = = AF_INET6 ) {
2011-05-06 01:22:11 +04:00
p_if = ( const unsigned char * )
2007-10-25 01:16:54 +04:00
& ( ( const struct sockaddr_in6 * ) pss ) - > sin6_addr ;
2011-05-06 01:22:11 +04:00
p_ss1 = ( const unsigned char * )
2007-10-25 01:16:54 +04:00
& ( ( const struct sockaddr_in6 * ) ss1 ) - > sin6_addr ;
2011-05-06 01:22:11 +04:00
p_ss2 = ( const unsigned char * )
2007-10-25 01:16:54 +04:00
& ( ( const struct sockaddr_in6 * ) ss2 ) - > sin6_addr ;
len = 16 ;
}
# endif
if ( ! p_ss1 | | ! p_ss2 | | ! p_if | | len = = 0 ) {
continue ;
}
bits1 = matching_len_bits ( p_ss1 , p_if , len ) ;
bits2 = matching_len_bits ( p_ss2 , p_if , len ) ;
2002-07-15 14:35:28 +04:00
max_bits1 = MAX ( bits1 , max_bits1 ) ;
max_bits2 = MAX ( bits2 , max_bits2 ) ;
}
2001-02-18 13:36:03 +03:00
2007-10-25 01:16:54 +04:00
/* Bias towards directly reachable IPs */
2011-05-06 01:22:11 +04:00
if ( iface_local ( ( const struct sockaddr * ) ss1 ) ) {
2010-02-14 01:59:26 +03:00
if ( ss1 - > ss_family = = AF_INET ) {
2007-10-25 01:16:54 +04:00
max_bits1 + = 32 ;
} else {
max_bits1 + = 128 ;
}
}
2011-05-06 01:22:11 +04:00
if ( iface_local ( ( const struct sockaddr * ) ss2 ) ) {
2010-02-14 01:59:26 +03:00
if ( ss2 - > ss_family = = AF_INET ) {
2007-10-25 01:16:54 +04:00
max_bits2 + = 32 ;
} else {
max_bits2 + = 128 ;
}
}
2002-07-15 14:35:28 +04:00
return max_bits2 - max_bits1 ;
}
2001-02-18 13:36:03 +03:00
2003-06-25 21:41:05 +04:00
/*******************************************************************
compare 2 ldap IPs by nearness to our interfaces - used in qsort
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-02-26 00:17:57 +03:00
static int ip_service_compare ( struct ip_service * ss1 , struct ip_service * ss2 )
2003-06-25 21:41:05 +04:00
{
int result ;
2007-10-25 01:16:54 +04:00
2010-02-14 01:59:26 +03:00
if ( ( result = addr_compare ( & ss1 - > ss , & ss2 - > ss ) ) ! = 0 ) {
2003-06-25 21:41:05 +04:00
return result ;
2007-10-25 01:16:54 +04:00
}
if ( ss1 - > port > ss2 - > port ) {
2003-06-25 21:41:05 +04:00
return 1 ;
2007-10-25 01:16:54 +04:00
}
if ( ss1 - > port < ss2 - > port ) {
2003-06-25 21:41:05 +04:00
return - 1 ;
2007-10-25 01:16:54 +04:00
}
2003-06-25 21:41:05 +04:00
return 0 ;
}
2002-07-15 14:35:28 +04:00
/*
2007-10-25 01:16:54 +04:00
sort an IP list so that names that are close to one of our interfaces
are at the top . This prevents the problem where a WINS server returns an IP
that is not reachable from our subnet as the first match
2002-07-15 14:35:28 +04:00
*/
2003-06-14 01:03:15 +04:00
2007-10-25 01:16:54 +04:00
static void sort_addr_list ( struct sockaddr_storage * sslist , int count )
2002-07-15 14:35:28 +04:00
{
if ( count < = 1 ) {
return ;
}
2001-02-18 13:36:03 +03:00
2010-02-14 01:59:26 +03:00
TYPESAFE_QSORT ( sslist , count , addr_compare ) ;
2001-02-18 13:36:03 +03:00
}
1996-06-04 10:42:03 +04:00
2007-10-25 01:16:54 +04:00
static void sort_service_list ( struct ip_service * servlist , int count )
2003-06-25 21:41:05 +04:00
{
if ( count < = 1 ) {
return ;
}
2010-02-14 01:59:26 +03:00
TYPESAFE_QSORT ( servlist , count , ip_service_compare ) ;
2003-06-25 21:41:05 +04:00
}
/**********************************************************************
2007-10-25 01:16:54 +04:00
Remove any duplicate address / port pairs in the list
2003-06-25 21:41:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-05-22 01:29:11 +04:00
int remove_duplicate_addrs2 ( struct ip_service * iplist , int count )
2003-06-25 21:41:05 +04:00
{
int i , j ;
2007-10-25 01:16:54 +04:00
DEBUG ( 10 , ( " remove_duplicate_addrs2: "
" looking for duplicate address/port pairs \n " ) ) ;
2012-04-28 03:02:15 +04:00
/* One loop to set duplicates to a zero addr. */
2003-06-25 21:41:05 +04:00
for ( i = 0 ; i < count ; i + + ) {
2011-02-27 11:57:18 +03:00
if ( is_zero_addr ( & iplist [ i ] . ss ) ) {
2003-06-25 21:41:05 +04:00
continue ;
2007-10-25 01:16:54 +04:00
}
2003-06-25 21:41:05 +04:00
for ( j = i + 1 ; j < count ; j + + ) {
2011-06-19 15:06:00 +04:00
if ( sockaddr_equal ( ( struct sockaddr * ) ( void * ) & iplist [ i ] . ss ,
( struct sockaddr * ) ( void * ) & iplist [ j ] . ss ) & &
2007-10-25 01:16:54 +04:00
iplist [ i ] . port = = iplist [ j ] . port ) {
2008-12-03 10:29:57 +03:00
zero_sockaddr ( & iplist [ j ] . ss ) ;
2007-10-25 01:16:54 +04:00
}
2003-06-25 21:41:05 +04:00
}
}
2007-10-25 01:16:54 +04:00
2012-04-28 03:02:15 +04:00
/* Now remove any addresses set to zero above. */
for ( i = 0 ; i < count ; i + + ) {
while ( i < count & &
is_zero_addr ( & iplist [ i ] . ss ) ) {
if ( count - i - 1 > 0 ) {
memmove ( & iplist [ i ] ,
& iplist [ i + 1 ] ,
( count - i - 1 ) * sizeof ( struct ip_service ) ) ;
2007-10-25 01:16:54 +04:00
}
2003-06-25 21:41:05 +04:00
count - - ;
}
}
return count ;
}
2009-07-28 22:51:58 +04:00
static bool prioritize_ipv4_list ( struct ip_service * iplist , int count )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-06-07 05:30:12 +04:00
struct ip_service * iplist_new = talloc_array ( frame , struct ip_service , count ) ;
2009-07-28 22:51:58 +04:00
int i , j ;
if ( iplist_new = = NULL ) {
TALLOC_FREE ( frame ) ;
return false ;
}
j = 0 ;
/* Copy IPv4 first. */
for ( i = 0 ; i < count ; i + + ) {
if ( iplist [ i ] . ss . ss_family = = AF_INET ) {
iplist_new [ j + + ] = iplist [ i ] ;
}
}
/* Copy IPv6. */
for ( i = 0 ; i < count ; i + + ) {
if ( iplist [ i ] . ss . ss_family ! = AF_INET ) {
iplist_new [ j + + ] = iplist [ i ] ;
}
}
memcpy ( iplist , iplist_new , sizeof ( struct ip_service ) * count ) ;
TALLOC_FREE ( frame ) ;
return true ;
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Do a netbios name query to find someones IP .
Returns an array of IP addresses or NULL if none .
* count will be set to the number of addresses returned .
2002-07-15 14:35:28 +04:00
* timed_out is set if we failed by timing out
1999-12-13 16:27:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-14 01:03:15 +04:00
2011-01-04 20:48:47 +03:00
struct name_query_state {
struct sockaddr_storage my_addr ;
struct sockaddr_storage addr ;
bool bcast ;
uint8_t buf [ 1024 ] ;
ssize_t buflen ;
NTSTATUS validate_error ;
uint8_t flags ;
struct sockaddr_storage * addrs ;
int num_addrs ;
} ;
static bool name_query_validator ( struct packet_struct * p , void * private_data ) ;
static void name_query_done ( struct tevent_req * subreq ) ;
struct tevent_req * name_query_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * name , int name_type ,
bool bcast , bool recurse ,
const struct sockaddr_storage * addr )
1996-06-04 10:42:03 +04:00
{
2011-01-04 20:48:47 +03:00
struct tevent_req * req , * subreq ;
struct name_query_state * state ;
2002-07-15 14:35:28 +04:00
struct packet_struct p ;
struct nmb_packet * nmb = & p . packet . nmb ;
2011-01-04 20:48:47 +03:00
struct sockaddr_in * in_addr ;
req = tevent_req_create ( mem_ctx , & state , struct name_query_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > bcast = bcast ;
if ( addr - > ss_family ! = AF_INET ) {
/* Can't do node status to IPv6 */
tevent_req_nterror ( req , NT_STATUS_INVALID_ADDRESS ) ;
return tevent_req_post ( req , ev ) ;
}
1999-12-13 16:27:58 +03:00
2002-08-17 21:00:51 +04:00
if ( lp_disable_netbios ( ) ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 5 , ( " name_query(%s#%02x): netbios is disabled \n " ,
name , name_type ) ) ;
2011-01-04 20:48:47 +03:00
tevent_req_nterror ( req , NT_STATUS_NOT_SUPPORTED ) ;
return tevent_req_post ( req , ev ) ;
2007-10-25 01:16:54 +04:00
}
2011-01-04 20:48:47 +03:00
state - > addr = * addr ;
in_addr = ( struct sockaddr_in * ) ( void * ) & state - > addr ;
in_addr - > sin_port = htons ( NMB_PORT ) ;
2002-08-17 21:00:51 +04:00
2011-05-14 20:04:49 +04:00
set_socket_addr_v4 ( & state - > my_addr ) ;
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
ZERO_STRUCT ( p ) ;
2002-07-15 14:35:28 +04:00
nmb - > header . name_trn_id = generate_trn_id ( ) ;
nmb - > header . opcode = 0 ;
2007-10-25 01:16:54 +04:00
nmb - > header . response = false ;
2002-07-15 14:35:28 +04:00
nmb - > header . nm_flags . bcast = bcast ;
2007-10-25 01:16:54 +04:00
nmb - > header . nm_flags . recursion_available = false ;
2002-07-15 14:35:28 +04:00
nmb - > header . nm_flags . recursion_desired = recurse ;
2007-10-25 01:16:54 +04:00
nmb - > header . nm_flags . trunc = false ;
nmb - > header . nm_flags . authoritative = false ;
2002-07-15 14:35:28 +04:00
nmb - > header . rcode = 0 ;
nmb - > header . qdcount = 1 ;
nmb - > header . ancount = 0 ;
nmb - > header . nscount = 0 ;
nmb - > header . arcount = 0 ;
2007-10-25 01:16:54 +04:00
2002-07-15 14:35:28 +04:00
make_nmb_name ( & nmb - > question . question_name , name , name_type ) ;
2007-10-25 01:16:54 +04:00
2002-07-15 14:35:28 +04:00
nmb - > question . question_type = 0x20 ;
nmb - > question . question_class = 0x1 ;
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
state - > buflen = build_packet ( ( char * ) state - > buf , sizeof ( state - > buf ) ,
& p ) ;
if ( state - > buflen = = 0 ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
DEBUG ( 10 , ( " build_packet failed \n " ) ) ;
return tevent_req_post ( req , ev ) ;
}
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
subreq = nb_trans_send ( state , ev , & state - > my_addr , & state - > addr , bcast ,
state - > buf , state - > buflen ,
NMB_PACKET , nmb - > header . name_trn_id ,
name_query_validator , state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
DEBUG ( 10 , ( " nb_trans_send failed \n " ) ) ;
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , name_query_done , req ) ;
return req ;
}
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
static bool name_query_validator ( struct packet_struct * p , void * private_data )
{
struct name_query_state * state = talloc_get_type_abort (
private_data , struct name_query_state ) ;
struct nmb_packet * nmb = & p - > packet . nmb ;
struct sockaddr_storage * tmp_addrs ;
2011-05-03 01:35:06 +04:00
bool got_unique_netbios_name = false ;
2011-01-04 20:48:47 +03:00
int i ;
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
debug_nmb_packet ( p ) ;
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
/*
* If we get a Negative Name Query Response from a WINS
* server , we should report it and give up .
*/
if ( 0 = = nmb - > header . opcode /* A query response */
& & ! state - > bcast /* from a WINS server */
& & nmb - > header . rcode /* Error returned */
) {
if ( DEBUGLVL ( 3 ) ) {
/* Only executed if DEBUGLEVEL >= 3 */
dbgtext ( " Negative name query "
" response, rcode 0x%02x: " ,
nmb - > header . rcode ) ;
switch ( nmb - > header . rcode ) {
case 0x01 :
dbgtext ( " Request was invalidly formatted. \n " ) ;
break ;
case 0x02 :
dbgtext ( " Problem with NBNS, cannot process "
" name. \n " ) ;
break ;
case 0x03 :
dbgtext ( " The name requested does not "
" exist. \n " ) ;
break ;
case 0x04 :
dbgtext ( " Unsupported request error. \n " ) ;
break ;
case 0x05 :
dbgtext ( " Query refused error. \n " ) ;
2002-07-15 14:35:28 +04:00
break ;
2011-01-04 20:48:47 +03:00
default :
dbgtext ( " Unrecognized error code. \n " ) ;
break ;
}
2002-07-15 14:35:28 +04:00
}
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
/*
* We accept this packet as valid , but tell the upper
* layers that it ' s a negative response .
*/
state - > validate_error = NT_STATUS_NOT_FOUND ;
return true ;
}
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
if ( nmb - > header . opcode ! = 0 | |
nmb - > header . nm_flags . bcast | |
nmb - > header . rcode | |
! nmb - > header . ancount ) {
/*
* XXXX what do we do with this ? Could be a redirect ,
* but we ' ll discard it for the moment .
*/
return false ;
}
2007-10-25 01:16:54 +04:00
2011-06-07 05:10:15 +04:00
tmp_addrs = talloc_realloc (
2011-01-04 20:48:47 +03:00
state , state - > addrs , struct sockaddr_storage ,
state - > num_addrs + nmb - > answers - > rdlength / 6 ) ;
if ( tmp_addrs = = NULL ) {
state - > validate_error = NT_STATUS_NO_MEMORY ;
return true ;
}
state - > addrs = tmp_addrs ;
DEBUG ( 2 , ( " Got a positive name query response "
" from %s ( " , inet_ntoa ( p - > ip ) ) ) ;
for ( i = 0 ; i < nmb - > answers - > rdlength / 6 ; i + + ) {
2011-05-03 01:35:06 +04:00
uint16_t flags ;
2011-01-04 20:48:47 +03:00
struct in_addr ip ;
2011-05-03 23:28:37 +04:00
struct sockaddr_storage addr ;
int j ;
2011-05-03 01:35:06 +04:00
flags = RSVAL ( & nmb - > answers - > rdata [ i * 6 ] , 0 ) ;
got_unique_netbios_name | = ( ( flags & 0x8000 ) = = 0 ) ;
2011-01-04 20:48:47 +03:00
putip ( ( char * ) & ip , & nmb - > answers - > rdata [ 2 + i * 6 ] ) ;
2011-05-03 23:28:37 +04:00
in_addr_to_sockaddr_storage ( & addr , ip ) ;
2012-04-28 03:25:58 +04:00
if ( is_zero_addr ( & addr ) ) {
continue ;
}
2011-05-03 23:28:37 +04:00
for ( j = 0 ; j < state - > num_addrs ; j + + ) {
if ( sockaddr_equal (
2011-06-19 15:06:00 +04:00
( struct sockaddr * ) ( void * ) & addr ,
( struct sockaddr * ) ( void * ) & state - > addrs [ j ] ) ) {
2011-05-03 23:28:37 +04:00
break ;
}
}
if ( j < state - > num_addrs ) {
/* Already got it */
continue ;
}
2011-01-04 20:48:47 +03:00
DEBUGADD ( 2 , ( " %s " , inet_ntoa ( ip ) ) ) ;
2011-05-03 23:28:37 +04:00
state - > addrs [ state - > num_addrs ] = addr ;
2011-01-04 20:48:47 +03:00
state - > num_addrs + = 1 ;
}
DEBUGADD ( 2 , ( " ) \n " ) ) ;
/* We add the flags back ... */
if ( nmb - > header . response )
state - > flags | = NM_FLAGS_RS ;
if ( nmb - > header . nm_flags . authoritative )
state - > flags | = NM_FLAGS_AA ;
if ( nmb - > header . nm_flags . trunc )
state - > flags | = NM_FLAGS_TC ;
if ( nmb - > header . nm_flags . recursion_desired )
state - > flags | = NM_FLAGS_RD ;
if ( nmb - > header . nm_flags . recursion_available )
state - > flags | = NM_FLAGS_RA ;
if ( nmb - > header . nm_flags . bcast )
state - > flags | = NM_FLAGS_B ;
if ( state - > bcast ) {
/*
2011-05-03 01:35:06 +04:00
* We have to collect all entries coming in from broadcast
* queries . If we got a unique name , we ' re done .
2011-01-04 20:48:47 +03:00
*/
2011-05-03 01:35:06 +04:00
return got_unique_netbios_name ;
2011-01-04 20:48:47 +03:00
}
/*
* WINS responses are accepted when they are received
*/
return true ;
}
2007-10-25 01:16:54 +04:00
2011-01-04 20:48:47 +03:00
static void name_query_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct name_query_state * state = tevent_req_data (
req , struct name_query_state ) ;
NTSTATUS status ;
struct packet_struct * p = NULL ;
2007-10-25 01:16:54 +04:00
2018-01-16 17:50:19 +03:00
status = nb_trans_recv ( subreq , state , & p ) ;
2011-01-04 20:48:47 +03:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( ! NT_STATUS_IS_OK ( state - > validate_error ) ) {
tevent_req_nterror ( req , state - > validate_error ) ;
return ;
2002-07-15 14:35:28 +04:00
}
2011-01-04 20:48:47 +03:00
tevent_req_done ( req ) ;
}
1998-11-06 21:40:51 +03:00
2011-01-04 20:48:47 +03:00
NTSTATUS name_query_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * addrs , int * num_addrs ,
uint8_t * flags )
{
struct name_query_state * state = tevent_req_data (
req , struct name_query_state ) ;
NTSTATUS status ;
2007-10-25 01:16:54 +04:00
2011-06-12 17:44:19 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
if ( state - > bcast & &
NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) ) {
/*
* In the broadcast case we collect replies until the
* timeout .
*/
status = NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2011-01-04 20:48:47 +03:00
}
if ( state - > num_addrs = = 0 ) {
return NT_STATUS_NOT_FOUND ;
2002-07-15 14:35:28 +04:00
}
2011-01-04 20:48:47 +03:00
* addrs = talloc_move ( mem_ctx , & state - > addrs ) ;
sort_addr_list ( * addrs , state - > num_addrs ) ;
* num_addrs = state - > num_addrs ;
if ( flags ! = NULL ) {
* flags = state - > flags ;
}
return NT_STATUS_OK ;
}
1996-06-04 10:42:03 +04:00
2011-01-04 20:48:47 +03:00
NTSTATUS name_query ( const char * name , int name_type ,
bool bcast , bool recurse ,
const struct sockaddr_storage * to_ss ,
TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * addrs ,
int * num_addrs , uint8_t * flags )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
2011-04-25 19:37:08 +04:00
struct timeval timeout ;
2011-01-04 20:48:47 +03:00
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2000-08-12 02:29:44 +04:00
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-01-04 20:48:47 +03:00
if ( ev = = NULL ) {
goto fail ;
}
req = name_query_send ( ev , ev , name , name_type , bcast , recurse , to_ss ) ;
if ( req = = NULL ) {
goto fail ;
}
2011-04-25 19:37:08 +04:00
if ( bcast ) {
timeout = timeval_current_ofs ( 0 , 250000 ) ;
} else {
timeout = timeval_current_ofs ( 2 , 0 ) ;
}
if ( ! tevent_req_set_endtime ( req , ev , timeout ) ) {
goto fail ;
}
2011-01-04 20:48:47 +03:00
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = name_query_recv ( req , mem_ctx , addrs , num_addrs , flags ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
1996-06-04 10:42:03 +04:00
}
1998-03-16 23:59:47 +03:00
2003-06-25 21:41:05 +04:00
/********************************************************
2012-04-28 03:07:20 +04:00
Convert an array if struct sockaddr_storage to struct ip_service
2007-10-25 01:16:54 +04:00
return false on failure . Port is set to PORT_NONE ;
2012-04-28 03:07:20 +04:00
pcount is [ in / out ] - it is the length of ss_list on input ,
and the length of return_iplist on output as we remove any
zero addresses from ss_list .
2003-06-25 21:41:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-25 01:16:54 +04:00
static bool convert_ss2service ( struct ip_service * * return_iplist ,
const struct sockaddr_storage * ss_list ,
2012-04-28 03:07:20 +04:00
int * pcount )
2003-06-25 21:41:05 +04:00
{
int i ;
2012-04-28 03:07:20 +04:00
int orig_count = * pcount ;
int real_count = 0 ;
2001-02-18 13:36:03 +03:00
2012-04-28 03:07:20 +04:00
if ( orig_count = = 0 | | ! ss_list )
2003-06-25 21:41:05 +04:00
return False ;
2007-10-25 01:16:54 +04:00
2012-04-28 03:07:20 +04:00
/* Filter out zero addrs. */
for ( i = 0 ; i < orig_count ; i + + ) {
if ( is_zero_addr ( & ss_list [ i ] ) ) {
continue ;
}
real_count + + ;
}
if ( real_count = = 0 ) {
return false ;
}
2003-06-25 21:41:05 +04:00
/* copy the ip address; port will be PORT_NONE */
2012-04-28 03:07:20 +04:00
if ( ( * return_iplist = SMB_MALLOC_ARRAY ( struct ip_service , real_count ) ) = =
2007-10-25 01:16:54 +04:00
NULL ) {
DEBUG ( 0 , ( " convert_ip2service: malloc failed "
2012-04-28 03:07:20 +04:00
" for %d enetries! \n " , real_count ) ) ;
2003-06-25 21:41:05 +04:00
return False ;
}
2007-10-25 01:16:54 +04:00
2012-04-28 03:07:20 +04:00
for ( i = 0 , real_count = 0 ; i < orig_count ; i + + ) {
if ( is_zero_addr ( & ss_list [ i ] ) ) {
continue ;
}
( * return_iplist ) [ real_count ] . ss = ss_list [ i ] ;
( * return_iplist ) [ real_count ] . port = PORT_NONE ;
real_count + + ;
2003-06-25 21:41:05 +04:00
}
2012-04-28 03:07:20 +04:00
* pcount = real_count ;
2007-10-25 01:16:54 +04:00
return true ;
}
2011-04-25 20:30:35 +04:00
struct name_queries_state {
struct tevent_context * ev ;
const char * name ;
int name_type ;
bool bcast ;
bool recurse ;
const struct sockaddr_storage * addrs ;
int num_addrs ;
int wait_msec ;
int timeout_msec ;
struct tevent_req * * subreqs ;
int num_received ;
int num_sent ;
int received_index ;
struct sockaddr_storage * result_addrs ;
int num_result_addrs ;
uint8_t flags ;
} ;
static void name_queries_done ( struct tevent_req * subreq ) ;
static void name_queries_next ( struct tevent_req * subreq ) ;
/*
* Send a name query to multiple destinations with a wait time in between
*/
static struct tevent_req * name_queries_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
const char * name , int name_type ,
bool bcast , bool recurse ,
const struct sockaddr_storage * addrs ,
int num_addrs , int wait_msec , int timeout_msec )
{
struct tevent_req * req , * subreq ;
struct name_queries_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct name_queries_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > name = name ;
state - > name_type = name_type ;
state - > bcast = bcast ;
state - > recurse = recurse ;
state - > addrs = addrs ;
state - > num_addrs = num_addrs ;
state - > wait_msec = wait_msec ;
state - > timeout_msec = timeout_msec ;
state - > subreqs = talloc_zero_array (
state , struct tevent_req * , num_addrs ) ;
if ( tevent_req_nomem ( state - > subreqs , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > num_sent = 0 ;
subreq = name_query_send (
state - > subreqs , state - > ev , name , name_type , bcast , recurse ,
& state - > addrs [ state - > num_sent ] ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
if ( ! tevent_req_set_endtime (
subreq , state - > ev ,
timeval_current_ofs ( 0 , state - > timeout_msec * 1000 ) ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , name_queries_done , req ) ;
state - > subreqs [ state - > num_sent ] = subreq ;
state - > num_sent + = 1 ;
if ( state - > num_sent < state - > num_addrs ) {
subreq = tevent_wakeup_send (
state , state - > ev ,
timeval_current_ofs ( 0 , state - > wait_msec * 1000 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , name_queries_next , req ) ;
}
return req ;
}
static void name_queries_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct name_queries_state * state = tevent_req_data (
req , struct name_queries_state ) ;
int i ;
NTSTATUS status ;
status = name_query_recv ( subreq , state , & state - > result_addrs ,
& state - > num_result_addrs , & state - > flags ) ;
for ( i = 0 ; i < state - > num_sent ; i + + ) {
if ( state - > subreqs [ i ] = = subreq ) {
break ;
}
}
if ( i = = state - > num_sent ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
TALLOC_FREE ( state - > subreqs [ i ] ) ;
state - > num_received + = 1 ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( state - > num_received > = state - > num_addrs ) {
tevent_req_nterror ( req , status ) ;
return ;
}
/*
* Still outstanding requests , just wait
*/
return ;
}
state - > received_index = i ;
tevent_req_done ( req ) ;
}
static void name_queries_next ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct name_queries_state * state = tevent_req_data (
req , struct name_queries_state ) ;
if ( ! tevent_wakeup_recv ( subreq ) ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
subreq = name_query_send (
state - > subreqs , state - > ev ,
state - > name , state - > name_type , state - > bcast , state - > recurse ,
& state - > addrs [ state - > num_sent ] ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , name_queries_done , req ) ;
if ( ! tevent_req_set_endtime (
subreq , state - > ev ,
timeval_current_ofs ( 0 , state - > timeout_msec * 1000 ) ) ) {
return ;
}
state - > subreqs [ state - > num_sent ] = subreq ;
state - > num_sent + = 1 ;
if ( state - > num_sent < state - > num_addrs ) {
subreq = tevent_wakeup_send (
state , state - > ev ,
timeval_current_ofs ( 0 , state - > wait_msec * 1000 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , name_queries_next , req ) ;
}
}
static NTSTATUS name_queries_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * result_addrs ,
int * num_result_addrs , uint8_t * flags ,
int * received_index )
{
struct name_queries_state * state = tevent_req_data (
req , struct name_queries_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( result_addrs ! = NULL ) {
* result_addrs = talloc_move ( mem_ctx , & state - > result_addrs ) ;
}
if ( num_result_addrs ! = NULL ) {
* num_result_addrs = state - > num_result_addrs ;
}
if ( flags ! = NULL ) {
* flags = state - > flags ;
}
if ( received_index ! = NULL ) {
* received_index = state - > received_index ;
}
return NT_STATUS_OK ;
}
1998-10-04 16:00:40 +04:00
/********************************************************
1999-12-13 16:27:58 +03:00
Resolve via " bcast " method .
1998-10-04 16:00:40 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2011-06-19 15:05:29 +04:00
struct name_resolve_bcast_state {
struct sockaddr_storage * addrs ;
int num_addrs ;
} ;
static void name_resolve_bcast_done ( struct tevent_req * subreq ) ;
struct tevent_req * name_resolve_bcast_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * name ,
int name_type )
1998-10-04 16:00:40 +04:00
{
2011-06-19 15:05:29 +04:00
struct tevent_req * req , * subreq ;
struct name_resolve_bcast_state * state ;
2011-04-25 20:47:42 +04:00
struct sockaddr_storage * bcast_addrs ;
int i , num_addrs , num_bcast_addrs ;
2011-06-19 15:05:29 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct name_resolve_bcast_state ) ;
if ( req = = NULL ) {
return NULL ;
}
1999-12-13 16:27:58 +03:00
2002-08-17 21:00:51 +04:00
if ( lp_disable_netbios ( ) ) {
2011-06-19 15:05:29 +04:00
DEBUG ( 5 , ( " name_resolve_bcast(%s#%02x): netbios is disabled \n " ,
name , name_type ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
2002-08-17 21:00:51 +04:00
}
1998-10-04 16:00:40 +04:00
/*
* " bcast " means do a broadcast lookup on all the local interfaces .
*/
2011-06-19 15:05:29 +04:00
DEBUG ( 3 , ( " name_resolve_bcast: Attempting broadcast lookup "
" for name %s<0x%x> \n " , name , name_type ) ) ;
1998-10-04 16:00:40 +04:00
2011-04-25 20:47:42 +04:00
num_addrs = iface_count ( ) ;
2011-06-19 15:05:29 +04:00
bcast_addrs = talloc_array ( state , struct sockaddr_storage , num_addrs ) ;
if ( tevent_req_nomem ( bcast_addrs , req ) ) {
return tevent_req_post ( req , ev ) ;
2011-04-25 20:47:42 +04:00
}
1999-12-13 16:27:58 +03:00
/*
* Lookup the name on all the interfaces , return on
* the first successful match .
*/
2011-04-25 20:47:42 +04:00
num_bcast_addrs = 0 ;
for ( i = 0 ; i < num_addrs ; i + + ) {
2007-10-25 01:16:54 +04:00
const struct sockaddr_storage * pss = iface_n_bcast ( i ) ;
2007-10-11 05:25:16 +04:00
2011-04-25 20:47:42 +04:00
if ( pss - > ss_family ! = AF_INET ) {
2007-10-11 05:25:16 +04:00
continue ;
}
2011-04-25 20:47:42 +04:00
bcast_addrs [ num_bcast_addrs ] = * pss ;
num_bcast_addrs + = 1 ;
1998-10-04 16:00:40 +04:00
}
2007-10-25 01:16:54 +04:00
2011-06-19 15:05:29 +04:00
subreq = name_queries_send ( state , ev , name , name_type , true , true ,
bcast_addrs , num_bcast_addrs , 0 , 1000 ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , name_resolve_bcast_done , req ) ;
return req ;
}
static void name_resolve_bcast_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct name_resolve_bcast_state * state = tevent_req_data (
req , struct name_resolve_bcast_state ) ;
NTSTATUS status ;
status = name_queries_recv ( subreq , state ,
& state - > addrs , & state - > num_addrs ,
NULL , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS name_resolve_bcast_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * addrs ,
int * num_addrs )
{
struct name_resolve_bcast_state * state = tevent_req_data (
req , struct name_resolve_bcast_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* addrs = talloc_move ( mem_ctx , & state - > addrs ) ;
* num_addrs = state - > num_addrs ;
return NT_STATUS_OK ;
}
NTSTATUS name_resolve_bcast ( const char * name ,
int name_type ,
TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * return_iplist ,
int * return_count )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ;
2011-06-19 15:05:29 +04:00
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-06-19 15:05:29 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = name_resolve_bcast_send ( frame , ev , name , name_type ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = name_resolve_bcast_recv ( req , mem_ctx , return_iplist ,
return_count ) ;
fail :
TALLOC_FREE ( frame ) ;
2011-06-19 13:26:55 +04:00
return status ;
1998-10-04 16:00:40 +04:00
}
2011-05-14 20:24:03 +04:00
struct query_wins_list_state {
struct tevent_context * ev ;
const char * name ;
uint8_t name_type ;
struct in_addr * servers ;
uint32_t num_servers ;
struct sockaddr_storage server ;
uint32_t num_sent ;
struct sockaddr_storage * addrs ;
int num_addrs ;
uint8_t flags ;
} ;
static void query_wins_list_done ( struct tevent_req * subreq ) ;
/*
* Query a list of ( replicating ) wins servers in sequence , call them
* dead if they don ' t reply
*/
static struct tevent_req * query_wins_list_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct in_addr src_ip , const char * name , uint8_t name_type ,
struct in_addr * servers , int num_servers )
{
struct tevent_req * req , * subreq ;
struct query_wins_list_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct query_wins_list_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > name = name ;
state - > name_type = name_type ;
state - > servers = servers ;
state - > num_servers = num_servers ;
if ( state - > num_servers = = 0 ) {
tevent_req_nterror ( req , NT_STATUS_NOT_FOUND ) ;
return tevent_req_post ( req , ev ) ;
}
in_addr_to_sockaddr_storage (
& state - > server , state - > servers [ state - > num_sent ] ) ;
subreq = name_query_send ( state , state - > ev ,
state - > name , state - > name_type ,
false , true , & state - > server ) ;
state - > num_sent + = 1 ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
if ( ! tevent_req_set_endtime ( subreq , state - > ev ,
timeval_current_ofs ( 2 , 0 ) ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , query_wins_list_done , req ) ;
return req ;
}
static void query_wins_list_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct query_wins_list_state * state = tevent_req_data (
req , struct query_wins_list_state ) ;
NTSTATUS status ;
status = name_query_recv ( subreq , state ,
& state - > addrs , & state - > num_addrs ,
& state - > flags ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
tevent_req_done ( req ) ;
return ;
}
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
wins_srv_died ( state - > servers [ state - > num_sent - 1 ] ,
my_socket_addr_v4 ( ) ) ;
if ( state - > num_sent = = state - > num_servers ) {
tevent_req_nterror ( req , NT_STATUS_NOT_FOUND ) ;
return ;
}
in_addr_to_sockaddr_storage (
& state - > server , state - > servers [ state - > num_sent ] ) ;
subreq = name_query_send ( state , state - > ev ,
state - > name , state - > name_type ,
false , true , & state - > server ) ;
state - > num_sent + = 1 ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
if ( ! tevent_req_set_endtime ( subreq , state - > ev ,
timeval_current_ofs ( 2 , 0 ) ) ) {
return ;
}
tevent_req_set_callback ( subreq , query_wins_list_done , req ) ;
}
static NTSTATUS query_wins_list_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * addrs ,
int * num_addrs ,
uint8_t * flags )
{
struct query_wins_list_state * state = tevent_req_data (
req , struct query_wins_list_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( addrs ! = NULL ) {
* addrs = talloc_move ( mem_ctx , & state - > addrs ) ;
}
if ( num_addrs ! = NULL ) {
* num_addrs = state - > num_addrs ;
}
if ( flags ! = NULL ) {
* flags = state - > flags ;
}
return NT_STATUS_OK ;
}
2011-06-02 16:12:06 +04:00
struct resolve_wins_state {
int num_sent ;
int num_received ;
struct sockaddr_storage * addrs ;
int num_addrs ;
uint8_t flags ;
} ;
static void resolve_wins_done ( struct tevent_req * subreq ) ;
struct tevent_req * resolve_wins_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * name ,
int name_type )
{
struct tevent_req * req , * subreq ;
struct resolve_wins_state * state ;
char * * wins_tags = NULL ;
struct sockaddr_storage src_ss ;
struct in_addr src_ip ;
int i , num_wins_tags ;
req = tevent_req_create ( mem_ctx , & state ,
struct resolve_wins_state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( wins_srv_count ( ) < 1 ) {
DEBUG ( 3 , ( " resolve_wins: WINS server resolution selected "
" and no WINS servers listed. \n " ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
goto fail ;
}
/* the address we will be sending from */
2012-07-27 06:56:22 +04:00
if ( ! interpret_string_addr ( & src_ss , lp_nbt_client_socket_address ( ) ,
2011-06-02 16:12:06 +04:00
AI_NUMERICHOST | AI_PASSIVE ) ) {
zero_sockaddr ( & src_ss ) ;
}
if ( src_ss . ss_family ! = AF_INET ) {
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) , & src_ss ) ;
DEBUG ( 3 , ( " resolve_wins: cannot receive WINS replies "
" on IPv6 address %s \n " ,
addr ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
goto fail ;
}
src_ip = ( ( const struct sockaddr_in * ) ( void * ) & src_ss ) - > sin_addr ;
wins_tags = wins_srv_tags ( ) ;
if ( wins_tags = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
goto fail ;
}
num_wins_tags = 0 ;
while ( wins_tags [ num_wins_tags ] ! = NULL ) {
num_wins_tags + = 1 ;
}
for ( i = 0 ; i < num_wins_tags ; i + + ) {
int num_servers , num_alive ;
struct in_addr * servers , * alive ;
int j ;
if ( ! wins_server_tag_ips ( wins_tags [ i ] , talloc_tos ( ) ,
& servers , & num_servers ) ) {
DEBUG ( 10 , ( " wins_server_tag_ips failed for tag %s \n " ,
wins_tags [ i ] ) ) ;
continue ;
}
alive = talloc_array ( state , struct in_addr , num_servers ) ;
if ( tevent_req_nomem ( alive , req ) ) {
goto fail ;
}
num_alive = 0 ;
for ( j = 0 ; j < num_servers ; j + + ) {
struct in_addr wins_ip = servers [ j ] ;
if ( global_in_nmbd & & ismyip_v4 ( wins_ip ) ) {
/* yikes! we'll loop forever */
continue ;
}
/* skip any that have been unresponsive lately */
if ( wins_srv_is_dead ( wins_ip , src_ip ) ) {
continue ;
}
DEBUG ( 3 , ( " resolve_wins: using WINS server %s "
" and tag '%s' \n " ,
inet_ntoa ( wins_ip ) , wins_tags [ i ] ) ) ;
alive [ num_alive ] = wins_ip ;
num_alive + = 1 ;
}
TALLOC_FREE ( servers ) ;
if ( num_alive = = 0 ) {
continue ;
}
subreq = query_wins_list_send (
state , ev , src_ip , name , name_type ,
alive , num_alive ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto fail ;
}
tevent_req_set_callback ( subreq , resolve_wins_done , req ) ;
state - > num_sent + = 1 ;
}
if ( state - > num_sent = = 0 ) {
tevent_req_nterror ( req , NT_STATUS_NOT_FOUND ) ;
goto fail ;
}
wins_srv_tags_free ( wins_tags ) ;
return req ;
fail :
wins_srv_tags_free ( wins_tags ) ;
return tevent_req_post ( req , ev ) ;
}
static void resolve_wins_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct resolve_wins_state * state = tevent_req_data (
req , struct resolve_wins_state ) ;
NTSTATUS status ;
status = query_wins_list_recv ( subreq , state , & state - > addrs ,
& state - > num_addrs , & state - > flags ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
tevent_req_done ( req ) ;
return ;
}
state - > num_received + = 1 ;
if ( state - > num_received < state - > num_sent ) {
/*
* Wait for the others
*/
return ;
}
tevent_req_nterror ( req , status ) ;
}
NTSTATUS resolve_wins_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * addrs ,
int * num_addrs , uint8_t * flags )
{
struct resolve_wins_state * state = tevent_req_data (
req , struct resolve_wins_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( addrs ! = NULL ) {
* addrs = talloc_move ( mem_ctx , & state - > addrs ) ;
}
if ( num_addrs ! = NULL ) {
* num_addrs = state - > num_addrs ;
}
if ( flags ! = NULL ) {
* flags = state - > flags ;
}
return NT_STATUS_OK ;
}
1998-10-04 16:00:40 +04:00
/********************************************************
1999-12-13 16:27:58 +03:00
Resolve via " wins " method .
1998-10-04 16:00:40 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-14 01:03:15 +04:00
2007-10-25 01:16:54 +04:00
NTSTATUS resolve_wins ( const char * name ,
int name_type ,
2011-06-03 17:49:55 +04:00
TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * return_iplist ,
2007-10-25 01:16:54 +04:00
int * return_count )
1998-10-04 16:00:40 +04:00
{
2011-06-03 18:11:17 +04:00
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2002-07-15 14:35:28 +04:00
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( talloc_tos ( ) ) ;
2011-06-03 18:11:17 +04:00
if ( ev = = NULL ) {
goto fail ;
2007-10-25 01:16:54 +04:00
}
2011-06-03 18:11:17 +04:00
req = resolve_wins_send ( ev , ev , name , name_type ) ;
if ( req = = NULL ) {
goto fail ;
2007-10-25 01:16:54 +04:00
}
2011-06-03 18:11:17 +04:00
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
1999-12-13 16:27:58 +03:00
}
2011-06-03 18:11:17 +04:00
status = resolve_wins_recv ( req , mem_ctx , return_iplist , return_count ,
NULL ) ;
fail :
TALLOC_FREE ( ev ) ;
2007-08-28 18:20:53 +04:00
return status ;
1998-10-04 16:00:40 +04:00
}
/********************************************************
1999-12-13 16:27:58 +03:00
Resolve via " hosts " method .
1998-10-04 16:00:40 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2007-08-28 18:20:53 +04:00
static NTSTATUS resolve_hosts ( const char * name , int name_type ,
2015-12-15 23:43:50 +03:00
TALLOC_CTX * mem_ctx ,
struct sockaddr_storage * * return_iplist ,
2007-08-28 18:20:53 +04:00
int * return_count )
1998-10-04 16:00:40 +04:00
{
/*
* " host " means do a localhost , or dns lookup .
*/
2007-10-16 03:11:48 +04:00
struct addrinfo hints ;
struct addrinfo * ailist = NULL ;
struct addrinfo * res = NULL ;
int ret = - 1 ;
int i = 0 ;
2004-01-09 05:38:58 +03:00
if ( name_type ! = 0x20 & & name_type ! = 0x0 ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 5 , ( " resolve_hosts: not appropriate "
" for name type <0x%x> \n " ,
name_type ) ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2004-01-09 05:38:58 +03:00
}
* return_iplist = NULL ;
* return_count = 0 ;
2007-10-25 01:16:54 +04:00
DEBUG ( 3 , ( " resolve_hosts: Attempting host lookup for name %s<0x%x> \n " ,
name , name_type ) ) ;
2007-10-16 03:11:48 +04:00
ZERO_STRUCT ( hints ) ;
/* By default make sure it supports TCP. */
hints . ai_socktype = SOCK_STREAM ;
hints . ai_flags = AI_ADDRCONFIG ;
2007-12-10 01:01:57 +03:00
# if !defined(HAVE_IPV6)
/* Unless we have IPv6, we really only want IPv4 addresses back. */
hints . ai_family = AF_INET ;
# endif
2007-10-16 03:11:48 +04:00
ret = getaddrinfo ( name ,
NULL ,
& hints ,
& ailist ) ;
if ( ret ) {
DEBUG ( 3 , ( " resolve_hosts: getaddrinfo failed for name %s [%s] \n " ,
name ,
gai_strerror ( ret ) ) ) ;
}
for ( res = ailist ; res ; res = res - > ai_next ) {
2007-10-25 01:16:54 +04:00
struct sockaddr_storage ss ;
2007-10-16 03:11:48 +04:00
2007-10-25 01:16:54 +04:00
if ( ! res - > ai_addr | | res - > ai_addrlen = = 0 ) {
2007-10-16 03:11:48 +04:00
continue ;
}
2008-03-29 19:20:15 +03:00
ZERO_STRUCT ( ss ) ;
2007-10-25 01:16:54 +04:00
memcpy ( & ss , res - > ai_addr , res - > ai_addrlen ) ;
2007-10-16 03:11:48 +04:00
2012-04-28 03:25:58 +04:00
if ( is_zero_addr ( & ss ) ) {
continue ;
}
2007-10-16 03:11:48 +04:00
* return_count + = 1 ;
2015-12-15 23:43:50 +03:00
* return_iplist = talloc_realloc (
mem_ctx , * return_iplist , struct sockaddr_storage ,
* return_count ) ;
2007-10-16 03:11:48 +04:00
if ( ! * return_iplist ) {
2004-01-09 05:38:58 +03:00
DEBUG ( 3 , ( " resolve_hosts: malloc fail ! \n " ) ) ;
2007-10-16 03:11:48 +04:00
freeaddrinfo ( ailist ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_NO_MEMORY ;
2004-01-09 05:38:58 +03:00
}
2015-12-15 23:43:50 +03:00
( * return_iplist ) [ i ] = ss ;
2007-10-19 23:36:34 +04:00
i + + ;
2007-10-16 03:11:48 +04:00
}
if ( ailist ) {
freeaddrinfo ( ailist ) ;
}
if ( * return_count ) {
2007-08-28 18:20:53 +04:00
return NT_STATUS_OK ;
2004-01-09 05:38:58 +03:00
}
2007-08-28 18:20:53 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2004-01-09 05:38:58 +03:00
}
/********************************************************
Resolve via " ADS " method .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-02-09 22:56:57 +03:00
/* Special name type used to cause a _kerberos DNS lookup. */
# define KDC_NAME_TYPE 0xDCDC
2008-01-16 17:52:53 +03:00
static NTSTATUS resolve_ads ( const char * name ,
int name_type ,
const char * sitename ,
struct ip_service * * return_iplist ,
int * return_count )
2004-01-09 05:38:58 +03:00
{
2012-04-30 22:05:51 +04:00
int i ;
2006-05-12 19:17:35 +04:00
NTSTATUS status ;
TALLOC_CTX * ctx ;
struct dns_rr_srv * dcs = NULL ;
int numdcs = 0 ;
2006-08-24 16:13:57 +04:00
int numaddrs = 0 ;
2006-05-12 19:17:35 +04:00
2007-08-28 18:27:48 +04:00
if ( ( name_type ! = 0x1c ) & & ( name_type ! = KDC_NAME_TYPE ) & &
( name_type ! = 0x1b ) ) {
2007-08-28 18:20:53 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
2006-05-12 19:17:35 +04:00
if ( ( ctx = talloc_init ( " resolve_ads " ) ) = = NULL ) {
DEBUG ( 0 , ( " resolve_ads: talloc_init() failed! \n " ) ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_NO_MEMORY ;
2006-05-12 19:17:35 +04:00
}
2006-09-02 23:27:44 +04:00
2007-10-25 01:16:54 +04:00
/* The DNS code needs fixing to find IPv6 addresses... JRA. */
2007-08-28 18:20:53 +04:00
switch ( name_type ) {
2007-08-28 18:27:48 +04:00
case 0x1b :
DEBUG ( 5 , ( " resolve_ads: Attempting to resolve "
" PDC for %s using DNS \n " , name ) ) ;
2014-11-20 13:31:29 +03:00
status = ads_dns_query_pdc ( ctx ,
name ,
& dcs ,
& numdcs ) ;
2007-08-28 18:27:48 +04:00
break ;
2007-08-28 18:20:53 +04:00
case 0x1c :
DEBUG ( 5 , ( " resolve_ads: Attempting to resolve "
" DCs for %s using DNS \n " , name ) ) ;
2014-11-20 13:31:29 +03:00
status = ads_dns_query_dcs ( ctx ,
name ,
sitename ,
& dcs ,
2007-08-28 18:20:53 +04:00
& numdcs ) ;
break ;
case KDC_NAME_TYPE :
DEBUG ( 5 , ( " resolve_ads: Attempting to resolve "
" KDCs for %s using DNS \n " , name ) ) ;
2014-11-20 13:31:29 +03:00
status = ads_dns_query_kdcs ( ctx ,
name ,
sitename ,
& dcs ,
2007-08-28 18:20:53 +04:00
& numdcs ) ;
break ;
default :
status = NT_STATUS_INVALID_PARAMETER ;
break ;
2006-09-02 23:27:44 +04:00
}
2007-08-28 18:20:53 +04:00
2006-05-12 19:17:35 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-08-30 08:40:03 +04:00
talloc_destroy ( ctx ) ;
2007-08-28 18:20:53 +04:00
return status ;
2006-05-12 19:17:35 +04:00
}
2006-08-24 16:13:57 +04:00
2015-06-30 17:51:43 +03:00
if ( numdcs = = 0 ) {
* return_iplist = NULL ;
* return_count = 0 ;
talloc_destroy ( ctx ) ;
return NT_STATUS_OK ;
}
2006-08-24 16:13:57 +04:00
for ( i = 0 ; i < numdcs ; i + + ) {
2012-04-30 22:05:51 +04:00
if ( ! dcs [ i ] . ss_s ) {
numaddrs + = 1 ;
} else {
numaddrs + = dcs [ i ] . num_ips ;
}
}
2007-10-25 01:16:54 +04:00
if ( ( * return_iplist = SMB_MALLOC_ARRAY ( struct ip_service , numaddrs ) ) = =
NULL ) {
DEBUG ( 0 , ( " resolve_ads: malloc failed for %d entries \n " ,
numaddrs ) ) ;
2006-08-30 08:40:03 +04:00
talloc_destroy ( ctx ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_NO_MEMORY ;
2006-05-12 19:17:35 +04:00
}
2007-10-25 01:16:54 +04:00
2006-08-24 16:13:57 +04:00
/* now unroll the list of IP addresses */
2003-06-25 21:41:05 +04:00
2006-07-19 04:13:01 +04:00
* return_count = 0 ;
2007-10-25 01:16:54 +04:00
2012-05-30 22:50:06 +04:00
for ( i = 0 ; i < numdcs & & ( * return_count < numaddrs ) ; i + + ) {
2006-08-24 16:13:57 +04:00
/* If we don't have an IP list for a name, lookup it up */
2007-10-29 23:34:00 +03:00
if ( ! dcs [ i ] . ss_s ) {
2012-04-30 22:05:51 +04:00
/* We need to get all IP addresses here. */
struct addrinfo * res = NULL ;
struct addrinfo * p ;
int extra_addrs = 0 ;
if ( ! interpret_string_addr_internal ( & res ,
dcs [ i ] . hostname ,
0 ) ) {
2006-08-24 16:13:57 +04:00
continue ;
}
2012-04-30 22:05:51 +04:00
/* Add in every IP from the lookup. How
many is that ? */
for ( p = res ; p ; p = p - > ai_next ) {
struct sockaddr_storage ss ;
memcpy ( & ss , p - > ai_addr , p - > ai_addrlen ) ;
if ( is_zero_addr ( & ss ) ) {
continue ;
}
extra_addrs + + ;
}
if ( extra_addrs > 1 ) {
/* We need to expand the return_iplist array
as we only budgeted for one address . */
numaddrs + = ( extra_addrs - 1 ) ;
* return_iplist = SMB_REALLOC_ARRAY ( * return_iplist ,
struct ip_service ,
numaddrs ) ;
if ( * return_iplist = = NULL ) {
if ( res ) {
freeaddrinfo ( res ) ;
}
talloc_destroy ( ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
}
for ( p = res ; p ; p = p - > ai_next ) {
( * return_iplist ) [ * return_count ] . port = dcs [ i ] . port ;
memcpy ( & ( * return_iplist ) [ * return_count ] . ss ,
p - > ai_addr ,
p - > ai_addrlen ) ;
if ( is_zero_addr ( & ( * return_iplist ) [ * return_count ] . ss ) ) {
continue ;
}
( * return_count ) + + ;
/* Should never happen, but still... */
if ( * return_count > = numaddrs ) {
break ;
}
}
if ( res ) {
freeaddrinfo ( res ) ;
}
} else {
2017-11-07 15:04:21 +03:00
/* use all the IP addresses from the SRV response */
2012-04-30 22:05:51 +04:00
int j ;
for ( j = 0 ; j < dcs [ i ] . num_ips ; j + + ) {
( * return_iplist ) [ * return_count ] . port = dcs [ i ] . port ;
( * return_iplist ) [ * return_count ] . ss = dcs [ i ] . ss_s [ j ] ;
if ( is_zero_addr ( & ( * return_iplist ) [ * return_count ] . ss ) ) {
continue ;
}
( * return_count ) + + ;
/* Should never happen, but still... */
if ( * return_count > = numaddrs ) {
break ;
}
}
2007-10-25 01:16:54 +04:00
}
2006-05-12 19:17:35 +04:00
}
2007-10-25 01:16:54 +04:00
2006-08-30 08:40:03 +04:00
talloc_destroy ( ctx ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_OK ;
1998-10-04 16:00:40 +04:00
}
2015-05-13 09:53:43 +03:00
static const char * * filter_out_nbt_lookup ( TALLOC_CTX * mem_ctx ,
const char * * resolve_order )
{
size_t i , len , result_idx ;
const char * * result ;
len = 0 ;
while ( resolve_order [ len ] ! = NULL ) {
len + = 1 ;
}
result = talloc_array ( mem_ctx , const char * , len + 1 ) ;
if ( result = = NULL ) {
return NULL ;
}
result_idx = 0 ;
for ( i = 0 ; i < len ; i + + ) {
const char * tok = resolve_order [ i ] ;
if ( strequal ( tok , " lmhosts " ) | | strequal ( tok , " wins " ) | |
strequal ( tok , " bcast " ) ) {
continue ;
}
result [ result_idx + + ] = tok ;
}
result [ result_idx ] = NULL ;
return result ;
}
2003-06-25 21:41:05 +04:00
/*******************************************************************
1999-12-13 16:27:58 +03:00
Internal interface to resolve a name into an IP address .
Use this function if the string is either an IP address , DNS
or host name or NetBIOS name . This uses the name switch in the
1998-03-16 23:59:47 +03:00
smb . conf to determine the order of name resolution .
2007-10-25 01:16:54 +04:00
2003-06-25 21:41:05 +04:00
Added support for ip addr / port to support ADS ldap servers .
2007-10-25 01:16:54 +04:00
the only place we currently care about the port is in the
2003-06-25 21:41:05 +04:00
resolve_hosts ( ) when looking up DC ' s via SRV RR entries in DNS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-11-28 01:34:12 +03:00
2008-04-22 02:06:57 +04:00
NTSTATUS internal_resolve_name ( const char * name ,
int name_type ,
2007-10-25 01:16:54 +04:00
const char * sitename ,
struct ip_service * * return_iplist ,
int * return_count ,
2012-07-18 09:19:15 +04:00
const char * * resolve_order )
1999-11-28 01:34:12 +03:00
{
2012-07-18 09:19:15 +04:00
const char * tok ;
2007-08-28 18:20:53 +04:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2004-07-02 05:09:10 +04:00
int i ;
2007-12-08 04:32:32 +03:00
TALLOC_CTX * frame = NULL ;
2002-01-09 07:26:41 +03:00
2004-07-02 05:09:10 +04:00
* return_iplist = NULL ;
* return_count = 0 ;
1999-12-13 16:27:58 +03:00
2007-01-17 21:25:35 +03:00
DEBUG ( 10 , ( " internal_resolve_name: looking up %s#%x (sitename %s) \n " ,
2009-02-04 01:25:31 +03:00
name , name_type , sitename ? sitename : " (null) " ) ) ;
2002-01-09 07:26:41 +03:00
2007-10-25 01:16:54 +04:00
if ( is_ipaddress ( name ) ) {
if ( ( * return_iplist = SMB_MALLOC_P ( struct ip_service ) ) = =
NULL ) {
2004-07-02 05:09:10 +04:00
DEBUG ( 0 , ( " internal_resolve_name: malloc fail ! \n " ) ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_NO_MEMORY ;
2004-07-02 05:09:10 +04:00
}
2007-10-25 01:16:54 +04:00
/* ignore the port here */
( * return_iplist ) - > port = PORT_NONE ;
/* if it's in the form of an IP address then get the lib to interpret it */
if ( ! interpret_string_addr ( & ( * return_iplist ) - > ss ,
name , AI_NUMERICHOST ) ) {
DEBUG ( 1 , ( " internal_resolve_name: interpret_string_addr "
" failed on %s \n " ,
name ) ) ;
SAFE_FREE ( * return_iplist ) ;
return NT_STATUS_INVALID_PARAMETER ;
2003-02-18 00:19:00 +03:00
}
2012-04-28 03:25:58 +04:00
if ( is_zero_addr ( & ( * return_iplist ) - > ss ) ) {
SAFE_FREE ( * return_iplist ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
2004-07-02 05:09:10 +04:00
* return_count = 1 ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_OK ;
1999-12-13 16:27:58 +03:00
}
2007-10-25 01:16:54 +04:00
2004-07-02 05:09:10 +04:00
/* Check name cache */
2002-08-17 21:00:51 +04:00
2004-07-02 05:09:10 +04:00
if ( namecache_fetch ( name , name_type , return_iplist , return_count ) ) {
2012-04-28 03:25:58 +04:00
* return_count = remove_duplicate_addrs2 ( * return_iplist ,
* return_count ) ;
2004-07-02 05:09:10 +04:00
/* This could be a negative response */
2007-08-28 18:20:53 +04:00
if ( * return_count > 0 ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_UNSUCCESSFUL ;
}
2004-07-02 05:09:10 +04:00
}
2002-08-17 21:00:51 +04:00
2004-07-02 05:09:10 +04:00
/* set the name resolution order */
2004-01-13 22:42:53 +03:00
2012-07-18 09:19:15 +04:00
if ( resolve_order & & strcmp ( resolve_order [ 0 ] , " NULL " ) = = 0 ) {
2004-07-02 05:09:10 +04:00
DEBUG ( 8 , ( " internal_resolve_name: all lookups disabled \n " ) ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2004-07-02 05:09:10 +04:00
}
2007-10-25 01:16:54 +04:00
2012-07-18 09:19:15 +04:00
if ( ! resolve_order | | ! resolve_order [ 0 ] ) {
static const char * host_order [ ] = { " host " , NULL } ;
resolve_order = host_order ;
2006-08-29 04:56:08 +04:00
}
1998-04-12 06:50:43 +04:00
2015-05-13 09:53:43 +03:00
frame = talloc_stackframe ( ) ;
if ( ( strlen ( name ) > MAX_NETBIOSNAME_LEN - 1 ) | |
( strchr ( name , ' . ' ) ! = NULL ) ) {
/*
* Don ' t do NBT lookup , the name would not fit anyway
*/
resolve_order = filter_out_nbt_lookup ( frame , resolve_order ) ;
if ( resolve_order = = NULL ) {
2015-05-14 14:28:16 +03:00
TALLOC_FREE ( frame ) ;
2015-05-13 09:53:43 +03:00
return NT_STATUS_NO_MEMORY ;
2015-01-30 16:28:48 +03:00
}
}
2007-10-25 01:16:54 +04:00
2015-05-13 09:53:43 +03:00
/* iterate through the name resolution backends */
2012-07-18 09:19:15 +04:00
for ( i = 0 ; resolve_order [ i ] ; i + + ) {
tok = resolve_order [ i ] ;
2006-08-29 04:56:08 +04:00
if ( ( strequal ( tok , " host " ) | | strequal ( tok , " hosts " ) ) ) {
2015-12-15 23:43:50 +03:00
struct sockaddr_storage * ss_list ;
status = resolve_hosts ( name , name_type ,
talloc_tos ( ) , & ss_list ,
2007-08-28 18:20:53 +04:00
return_count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2015-12-15 23:43:50 +03:00
if ( ! convert_ss2service ( return_iplist ,
ss_list ,
return_count ) ) {
status = NT_STATUS_NO_MEMORY ;
}
2006-08-29 04:56:08 +04:00
goto done ;
}
2006-09-02 23:27:44 +04:00
} else if ( strequal ( tok , " kdc " ) ) {
2007-10-25 01:16:54 +04:00
/* deal with KDC_NAME_TYPE names here.
* This will result in a SRV record lookup */
2007-08-28 18:20:53 +04:00
status = resolve_ads ( name , KDC_NAME_TYPE , sitename ,
return_iplist , return_count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2007-10-25 01:16:54 +04:00
/* Ensure we don't namecache
* this with the KDC port . */
2006-09-03 00:17:05 +04:00
name_type = KDC_NAME_TYPE ;
2006-09-02 23:27:44 +04:00
goto done ;
}
2006-08-29 04:56:08 +04:00
} else if ( strequal ( tok , " ads " ) ) {
2007-10-25 01:16:54 +04:00
/* deal with 0x1c and 0x1b names here.
* This will result in a SRV record lookup */
2007-08-28 18:20:53 +04:00
status = resolve_ads ( name , name_type , sitename ,
return_iplist , return_count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2006-08-29 04:56:08 +04:00
goto done ;
}
2015-05-13 09:53:43 +03:00
} else if ( strequal ( tok , " lmhosts " ) ) {
2015-12-15 23:52:38 +03:00
struct sockaddr_storage * ss_list ;
status = resolve_lmhosts_file_as_sockaddr (
get_dyn_LMHOSTSFILE ( ) , name , name_type ,
talloc_tos ( ) , & ss_list , return_count ) ;
2007-08-28 18:20:53 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
2015-12-15 23:52:38 +03:00
if ( ! convert_ss2service ( return_iplist ,
ss_list ,
return_count ) ) {
status = NT_STATUS_NO_MEMORY ;
}
2006-08-29 04:56:08 +04:00
goto done ;
2004-07-02 05:09:10 +04:00
}
2015-05-13 09:53:43 +03:00
} else if ( strequal ( tok , " wins " ) ) {
2006-08-29 04:56:08 +04:00
/* don't resolve 1D via WINS */
2011-06-03 17:49:55 +04:00
struct sockaddr_storage * ss_list ;
2007-08-28 18:20:53 +04:00
if ( name_type ! = 0x1D ) {
status = resolve_wins ( name , name_type ,
2011-06-03 17:49:55 +04:00
talloc_tos ( ) ,
& ss_list ,
2007-08-28 18:20:53 +04:00
return_count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2011-06-03 17:49:55 +04:00
if ( ! convert_ss2service ( return_iplist ,
ss_list ,
2012-04-28 03:07:20 +04:00
return_count ) ) {
2011-06-03 17:49:55 +04:00
status = NT_STATUS_NO_MEMORY ;
}
2007-08-28 18:20:53 +04:00
goto done ;
}
2006-08-29 04:56:08 +04:00
}
2015-05-13 09:53:43 +03:00
} else if ( strequal ( tok , " bcast " ) ) {
2011-04-30 21:23:55 +04:00
struct sockaddr_storage * ss_list ;
status = name_resolve_bcast (
name , name_type , talloc_tos ( ) ,
& ss_list , return_count ) ;
2007-08-28 18:20:53 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
2011-04-30 21:23:55 +04:00
if ( ! convert_ss2service ( return_iplist ,
ss_list ,
2012-04-28 03:07:20 +04:00
return_count ) ) {
2011-04-30 21:23:55 +04:00
status = NT_STATUS_NO_MEMORY ;
}
2006-08-29 04:56:08 +04:00
goto done ;
}
} else {
2007-08-28 18:20:53 +04:00
DEBUG ( 0 , ( " resolve_name: unknown name switch type %s \n " ,
tok ) ) ;
2004-07-02 05:09:10 +04:00
}
2006-08-29 04:56:08 +04:00
}
2002-01-09 07:26:41 +03:00
2006-08-29 04:56:08 +04:00
/* All of the resolve_* functions above have returned false. */
2004-07-02 05:09:10 +04:00
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2006-08-29 04:56:08 +04:00
SAFE_FREE ( * return_iplist ) ;
* return_count = 0 ;
2004-07-02 05:09:10 +04:00
2007-08-28 18:20:53 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2002-01-09 07:26:41 +03:00
2004-07-02 05:09:10 +04:00
done :
2002-01-09 07:26:41 +03:00
2006-08-29 04:56:08 +04:00
/* Remove duplicate entries. Some queries, notably #1c (domain
controllers ) return the PDC in iplist [ 0 ] and then all domain
controllers including the PDC in iplist [ 1. . n ] . Iterating over
the iplist when the PDC is down will cause two sets of timeouts . */
2004-07-02 05:09:10 +04:00
2012-04-28 03:25:58 +04:00
* return_count = remove_duplicate_addrs2 ( * return_iplist , * return_count ) ;
2007-10-25 01:16:54 +04:00
2006-08-29 04:56:08 +04:00
/* Save in name cache */
if ( DEBUGLEVEL > = 100 ) {
2007-10-25 01:16:54 +04:00
for ( i = 0 ; i < * return_count & & DEBUGLEVEL = = 100 ; i + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
& ( * return_iplist ) [ i ] . ss ) ;
DEBUG ( 100 , ( " Storing name %s of type %d (%s:%d) \n " ,
name ,
name_type ,
addr ,
( * return_iplist ) [ i ] . port ) ) ;
}
2006-08-29 04:56:08 +04:00
}
2007-10-25 01:16:54 +04:00
2012-04-28 03:25:58 +04:00
if ( * return_count ) {
namecache_store ( name , name_type , * return_count , * return_iplist ) ;
}
2002-01-09 07:26:41 +03:00
2006-08-29 04:56:08 +04:00
/* Display some debugging info */
2002-01-09 07:26:41 +03:00
2006-08-29 04:56:08 +04:00
if ( DEBUGLEVEL > = 10 ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 10 , ( " internal_resolve_name: returning %d addresses: " ,
* return_count ) ) ;
2002-01-09 07:26:41 +03:00
2006-08-29 04:56:08 +04:00
for ( i = 0 ; i < * return_count ; i + + ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
& ( * return_iplist ) [ i ] . ss ) ;
DEBUGADD ( 10 , ( " %s:%d " ,
addr ,
( * return_iplist ) [ i ] . port ) ) ;
2004-07-02 05:09:10 +04:00
}
2006-08-29 04:56:08 +04:00
DEBUG ( 10 , ( " \n " ) ) ;
2004-07-02 05:09:10 +04:00
}
2007-10-25 01:16:54 +04:00
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2007-08-28 18:20:53 +04:00
return status ;
1998-03-16 23:59:47 +03:00
}
1998-10-04 15:25:06 +04:00
1999-11-27 02:04:19 +03:00
/********************************************************
1999-12-13 16:27:58 +03:00
Internal interface to resolve a name into one IP address .
Use this function if the string is either an IP address , DNS
or host name or NetBIOS name . This uses the name switch in the
smb . conf to determine the order of name resolution .
1999-11-27 02:04:19 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-02 19:31:24 +03:00
2007-10-25 01:16:54 +04:00
bool resolve_name ( const char * name ,
struct sockaddr_storage * return_ss ,
2009-07-28 22:51:58 +04:00
int name_type ,
bool prefer_ipv4 )
1999-12-13 16:27:58 +03:00
{
2007-10-25 01:16:54 +04:00
struct ip_service * ss_list = NULL ;
char * sitename = NULL ;
1999-12-13 16:27:58 +03:00
int count = 0 ;
2011-09-12 22:56:13 +04:00
NTSTATUS status ;
2017-10-26 06:06:27 +03:00
TALLOC_CTX * frame = NULL ;
1998-10-04 15:25:06 +04:00
2007-10-25 01:16:54 +04:00
if ( is_ipaddress ( name ) ) {
return interpret_string_addr ( return_ss , name , AI_NUMERICHOST ) ;
2002-01-11 12:48:27 +03:00
}
2017-10-26 06:06:27 +03:00
frame = talloc_stackframe ( ) ;
sitename = sitename_fetch ( frame , lp_realm ( ) ) ; /* wild guess */
2007-10-25 01:16:54 +04:00
2011-09-12 22:56:13 +04:00
status = internal_resolve_name ( name , name_type , sitename ,
& ss_list , & count ,
lp_name_resolve_order ( ) ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2002-01-11 03:23:29 +03:00
int i ;
2007-10-25 01:16:54 +04:00
2009-07-28 22:51:58 +04:00
if ( prefer_ipv4 ) {
for ( i = 0 ; i < count ; i + + ) {
2011-02-27 11:57:18 +03:00
if ( ! is_zero_addr ( & ss_list [ i ] . ss ) & &
2011-06-19 15:06:00 +04:00
! is_broadcast_addr ( ( struct sockaddr * ) ( void * ) & ss_list [ i ] . ss ) & &
2009-07-28 22:51:58 +04:00
( ss_list [ i ] . ss . ss_family = = AF_INET ) ) {
* return_ss = ss_list [ i ] . ss ;
SAFE_FREE ( ss_list ) ;
2017-10-26 06:06:27 +03:00
TALLOC_FREE ( frame ) ;
2009-07-28 22:51:58 +04:00
return True ;
}
}
}
2002-01-11 03:23:29 +03:00
/* only return valid addresses for TCP connections */
for ( i = 0 ; i < count ; i + + ) {
2011-02-27 11:57:18 +03:00
if ( ! is_zero_addr ( & ss_list [ i ] . ss ) & &
2011-06-19 15:06:00 +04:00
! is_broadcast_addr ( ( struct sockaddr * ) ( void * ) & ss_list [ i ] . ss ) ) {
2007-10-25 01:16:54 +04:00
* return_ss = ss_list [ i ] . ss ;
SAFE_FREE ( ss_list ) ;
2017-10-26 06:06:27 +03:00
TALLOC_FREE ( frame ) ;
2002-01-11 03:23:29 +03:00
return True ;
}
}
1999-11-27 02:04:19 +03:00
}
2007-10-25 01:16:54 +04:00
SAFE_FREE ( ss_list ) ;
2017-10-26 06:06:27 +03:00
TALLOC_FREE ( frame ) ;
1999-12-13 16:27:58 +03:00
return False ;
}
1999-11-27 02:04:19 +03:00
2007-12-12 20:42:58 +03:00
/********************************************************
Internal interface to resolve a name into a list of IP addresses .
Use this function if the string is either an IP address , DNS
or host name or NetBIOS name . This uses the name switch in the
smb . conf to determine the order of name resolution .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS resolve_name_list ( TALLOC_CTX * ctx ,
const char * name ,
int name_type ,
struct sockaddr_storage * * return_ss_arr ,
unsigned int * p_num_entries )
{
struct ip_service * ss_list = NULL ;
char * sitename = NULL ;
int count = 0 ;
int i ;
unsigned int num_entries ;
NTSTATUS status ;
* p_num_entries = 0 ;
* return_ss_arr = NULL ;
if ( is_ipaddress ( name ) ) {
2011-06-07 05:38:41 +04:00
* return_ss_arr = talloc ( ctx , struct sockaddr_storage ) ;
2007-12-12 20:42:58 +03:00
if ( ! * return_ss_arr ) {
return NT_STATUS_NO_MEMORY ;
}
if ( ! interpret_string_addr ( * return_ss_arr , name , AI_NUMERICHOST ) ) {
TALLOC_FREE ( * return_ss_arr ) ;
return NT_STATUS_BAD_NETWORK_NAME ;
}
* p_num_entries = 1 ;
return NT_STATUS_OK ;
}
2013-09-05 00:58:18 +04:00
sitename = sitename_fetch ( ctx , lp_realm ( ) ) ; /* wild guess */
2007-12-12 20:42:58 +03:00
status = internal_resolve_name ( name , name_type , sitename ,
& ss_list , & count ,
lp_name_resolve_order ( ) ) ;
2013-09-05 00:58:18 +04:00
TALLOC_FREE ( sitename ) ;
2007-12-12 20:42:58 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* only return valid addresses for TCP connections */
for ( i = 0 , num_entries = 0 ; i < count ; i + + ) {
2011-02-27 11:57:18 +03:00
if ( ! is_zero_addr ( & ss_list [ i ] . ss ) & &
2011-06-19 15:06:00 +04:00
! is_broadcast_addr ( ( struct sockaddr * ) ( void * ) & ss_list [ i ] . ss ) ) {
2007-12-12 20:42:58 +03:00
num_entries + + ;
}
}
if ( num_entries = = 0 ) {
SAFE_FREE ( ss_list ) ;
return NT_STATUS_BAD_NETWORK_NAME ;
}
2011-06-07 05:30:12 +04:00
* return_ss_arr = talloc_array ( ctx ,
2007-12-12 20:42:58 +03:00
struct sockaddr_storage ,
num_entries ) ;
if ( ! ( * return_ss_arr ) ) {
SAFE_FREE ( ss_list ) ;
return NT_STATUS_NO_MEMORY ;
}
for ( i = 0 , num_entries = 0 ; i < count ; i + + ) {
2011-02-27 11:57:18 +03:00
if ( ! is_zero_addr ( & ss_list [ i ] . ss ) & &
2011-06-19 15:06:00 +04:00
! is_broadcast_addr ( ( struct sockaddr * ) ( void * ) & ss_list [ i ] . ss ) ) {
2007-12-12 20:42:58 +03:00
( * return_ss_arr ) [ num_entries + + ] = ss_list [ i ] . ss ;
}
}
status = NT_STATUS_OK ;
* p_num_entries = num_entries ;
SAFE_FREE ( ss_list ) ;
return NT_STATUS_OK ;
}
1999-12-13 16:27:58 +03:00
/********************************************************
Find the IP address of the master browser or DMB for a workgroup .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-11-27 02:04:19 +03:00
2007-10-25 01:16:54 +04:00
bool find_master_ip ( const char * group , struct sockaddr_storage * master_ss )
1999-12-13 16:27:58 +03:00
{
2003-06-25 21:41:05 +04:00
struct ip_service * ip_list = NULL ;
1999-12-13 16:27:58 +03:00
int count = 0 ;
2007-08-28 18:20:53 +04:00
NTSTATUS status ;
1999-12-13 16:27:58 +03:00
2002-08-17 21:00:51 +04:00
if ( lp_disable_netbios ( ) ) {
DEBUG ( 5 , ( " find_master_ip(%s): netbios is disabled \n " , group ) ) ;
2007-10-25 01:16:54 +04:00
return false ;
2002-08-17 21:00:51 +04:00
}
2007-08-28 18:20:53 +04:00
status = internal_resolve_name ( group , 0x1D , NULL , & ip_list , & count ,
lp_name_resolve_order ( ) ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2007-10-25 01:16:54 +04:00
* master_ss = ip_list [ 0 ] . ss ;
2001-09-17 07:33:37 +04:00
SAFE_FREE ( ip_list ) ;
2007-10-25 01:16:54 +04:00
return true ;
1999-11-28 01:34:12 +03:00
}
2007-08-28 18:20:53 +04:00
status = internal_resolve_name ( group , 0x1B , NULL , & ip_list , & count ,
lp_name_resolve_order ( ) ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2007-10-25 01:16:54 +04:00
* master_ss = ip_list [ 0 ] . ss ;
2001-09-17 07:44:52 +04:00
SAFE_FREE ( ip_list ) ;
2007-10-25 01:16:54 +04:00
return true ;
1999-12-13 16:27:58 +03:00
}
2001-09-17 07:33:37 +04:00
SAFE_FREE ( ip_list ) ;
2007-10-25 01:16:54 +04:00
return false ;
1999-11-27 02:04:19 +03:00
}
1998-10-04 15:25:06 +04:00
1999-12-13 16:27:58 +03:00
/********************************************************
2002-11-06 08:14:15 +03:00
Get the IP address list of the primary domain controller
for a domain .
1999-12-13 16:27:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-22 02:00:59 +03:00
2007-10-25 01:16:54 +04:00
bool get_pdc_ip ( const char * domain , struct sockaddr_storage * pss )
1999-12-13 16:27:58 +03:00
{
2007-01-17 21:25:35 +03:00
struct ip_service * ip_list = NULL ;
int count = 0 ;
2007-08-28 18:20:53 +04:00
NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ;
2012-07-18 09:19:15 +04:00
static const char * ads_order [ ] = { " ads " , NULL } ;
2002-11-06 08:14:15 +03:00
/* Look up #1B name */
2007-08-28 18:27:48 +04:00
if ( lp_security ( ) = = SEC_ADS ) {
status = internal_resolve_name ( domain , 0x1b , NULL , & ip_list ,
2012-07-18 09:19:15 +04:00
& count , ads_order ) ;
2007-08-28 18:27:48 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) | | count = = 0 ) {
status = internal_resolve_name ( domain , 0x1b , NULL , & ip_list ,
& count ,
lp_name_resolve_order ( ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-12-04 17:01:58 +04:00
SAFE_FREE ( ip_list ) ;
2007-10-25 01:16:54 +04:00
return false ;
2007-08-28 18:27:48 +04:00
}
2004-07-02 05:09:10 +04:00
}
2002-11-06 08:14:15 +03:00
2002-12-04 22:01:01 +03:00
/* if we get more than 1 IP back we have to assume it is a
multi - homed PDC and not a mess up */
2003-06-25 21:41:05 +04:00
2002-12-04 22:01:01 +03:00
if ( count > 1 ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 6 , ( " get_pdc_ip: PDC has %d IP addresses! \n " , count ) ) ;
sort_service_list ( ip_list , count ) ;
2002-12-04 22:01:01 +03:00
}
2002-11-06 08:14:15 +03:00
2007-10-25 01:16:54 +04:00
* pss = ip_list [ 0 ] . ss ;
2002-11-06 08:14:15 +03:00
SAFE_FREE ( ip_list ) ;
2007-10-25 01:16:54 +04:00
return true ;
2002-11-06 08:14:15 +03:00
}
2001-11-25 09:38:17 +03:00
2006-09-02 23:27:44 +04:00
/* Private enum type for lookups. */
enum dc_lookup_type { DC_NORMAL_LOOKUP , DC_ADS_ONLY , DC_KDC_ONLY } ;
2002-11-06 08:14:15 +03:00
/********************************************************
Get the IP address list of the domain controllers for
a domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-25 01:16:54 +04:00
static NTSTATUS get_dc_list ( const char * domain ,
const char * sitename ,
struct ip_service * * ip_list ,
int * count ,
enum dc_lookup_type lookup_type ,
bool * ordered )
2002-11-06 08:14:15 +03:00
{
2012-07-18 09:19:15 +04:00
const char * * resolve_order = NULL ;
2007-11-28 10:10:20 +03:00
char * saf_servername = NULL ;
char * pserver = NULL ;
2006-02-04 00:19:24 +03:00
const char * p ;
2007-11-28 10:10:20 +03:00
char * port_str = NULL ;
2006-02-04 00:19:24 +03:00
int port ;
2007-12-08 04:32:32 +03:00
char * name ;
2006-02-04 00:19:24 +03:00
int num_addresses = 0 ;
int local_count , i , j ;
struct ip_service * return_iplist = NULL ;
struct ip_service * auto_ip_list = NULL ;
2007-11-28 10:10:20 +03:00
bool done_auto_lookup = false ;
2006-02-04 00:19:24 +03:00
int auto_count = 0 ;
2007-08-28 18:20:53 +04:00
NTSTATUS status ;
2017-10-26 06:06:27 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
2015-06-03 13:50:25 +03:00
int auto_name_type = 0x1C ;
2007-11-28 10:10:20 +03:00
2008-06-06 01:27:26 +04:00
* ip_list = NULL ;
* count = 0 ;
2006-08-24 01:04:47 +04:00
* ordered = False ;
2004-01-13 22:42:53 +03:00
/* if we are restricted to solely using DNS for looking
up a domain controller , make sure that host lookups
are enabled for the ' name resolve order ' . If host lookups
are disabled and ads_only is True , then set the string to
NULL . */
2012-07-18 09:19:15 +04:00
resolve_order = lp_name_resolve_order ( ) ;
2007-11-28 10:10:20 +03:00
if ( ! resolve_order ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
2007-10-25 01:16:54 +04:00
if ( lookup_type = = DC_ADS_ONLY ) {
2012-07-18 09:19:15 +04:00
if ( str_list_check_ci ( resolve_order , " host " ) ) {
static const char * ads_order [ ] = { " ads " , NULL } ;
resolve_order = ads_order ;
2006-08-24 01:04:47 +04:00
/* DNS SRV lookups used by the ads resolver
are already sorted by priority and weight */
2007-10-25 01:16:54 +04:00
* ordered = true ;
2006-08-24 16:13:57 +04:00
} else {
2012-07-18 09:19:15 +04:00
/* this is quite bizarre! */
static const char * null_order [ ] = { " NULL " , NULL } ;
resolve_order = null_order ;
2006-08-24 01:04:47 +04:00
}
2006-09-02 23:27:44 +04:00
} else if ( lookup_type = = DC_KDC_ONLY ) {
2012-07-18 09:19:15 +04:00
static const char * kdc_order [ ] = { " kdc " , NULL } ;
2006-09-02 23:27:44 +04:00
/* DNS SRV lookups used by the ads/kdc resolver
are already sorted by priority and weight */
2007-10-25 01:16:54 +04:00
* ordered = true ;
2012-07-18 09:19:15 +04:00
resolve_order = kdc_order ;
2015-06-03 13:50:25 +03:00
auto_name_type = KDC_NAME_TYPE ;
2007-11-28 10:10:20 +03:00
}
2004-01-13 22:42:53 +03:00
2007-10-25 01:16:54 +04:00
/* fetch the server we have affinity for. Add the
2006-02-04 00:19:24 +03:00
' password server ' list to a search for our domain controllers */
2007-10-25 01:16:54 +04:00
2013-09-05 00:39:31 +04:00
saf_servername = saf_fetch ( ctx , domain ) ;
2007-10-25 01:16:54 +04:00
if ( strequal ( domain , lp_workgroup ( ) ) | | strequal ( domain , lp_realm ( ) ) ) {
2010-12-17 15:06:13 +03:00
pserver = talloc_asprintf ( ctx , " %s, %s " ,
2006-02-04 00:19:24 +03:00
saf_servername ? saf_servername : " " ,
2014-02-03 06:52:14 +04:00
lp_password_server ( ) ) ;
2006-02-04 00:19:24 +03:00
} else {
2010-12-17 15:06:13 +03:00
pserver = talloc_asprintf ( ctx , " %s, * " ,
2007-10-25 01:16:54 +04:00
saf_servername ? saf_servername : " " ) ;
2006-02-04 00:19:24 +03:00
}
2001-11-22 02:00:59 +03:00
2013-09-05 00:39:31 +04:00
TALLOC_FREE ( saf_servername ) ;
2007-11-28 10:10:20 +03:00
if ( ! pserver ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
2001-11-22 02:00:59 +03:00
2006-02-04 00:19:24 +03:00
DEBUG ( 3 , ( " get_dc_list: preferred server list: \" %s \" \n " , pserver ) ) ;
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
/*
* if ' * ' appears in the " password server " list then add
* an auto lookup to the list of manually configured
2007-10-25 01:16:54 +04:00
* DC ' s . If any DC is listed by name , then the list should be
* considered to be ordered
2006-02-04 00:19:24 +03:00
*/
p = pserver ;
2007-12-08 04:32:32 +03:00
while ( next_token_talloc ( ctx , & p , & name , LIST_SEP ) ) {
2008-06-06 01:27:26 +04:00
if ( ! done_auto_lookup & & strequal ( name , " * " ) ) {
2015-06-03 13:50:25 +03:00
status = internal_resolve_name ( domain , auto_name_type ,
sitename ,
2007-08-28 18:20:53 +04:00
& auto_ip_list ,
& auto_count ,
resolve_order ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2006-02-04 00:19:24 +03:00
num_addresses + = auto_count ;
2007-08-28 18:20:53 +04:00
}
2007-10-25 01:16:54 +04:00
done_auto_lookup = true ;
DEBUG ( 8 , ( " Adding %d DC's from auto lookup \n " ,
auto_count ) ) ;
2006-02-04 00:19:24 +03:00
} else {
num_addresses + + ;
2001-11-22 02:00:59 +03:00
}
2006-02-04 00:19:24 +03:00
}
2002-11-06 08:14:15 +03:00
2006-02-04 00:19:24 +03:00
/* if we have no addresses and haven't done the auto lookup, then
just return the list of DC ' s . Or maybe we just failed . */
2007-10-25 01:16:54 +04:00
2012-02-26 12:20:38 +04:00
if ( num_addresses = = 0 ) {
2007-10-25 01:16:54 +04:00
if ( done_auto_lookup ) {
DEBUG ( 4 , ( " get_dc_list: no servers found \n " ) ) ;
2007-11-28 10:10:20 +03:00
status = NT_STATUS_NO_LOGON_SERVERS ;
goto out ;
2001-11-22 02:00:59 +03:00
}
2015-06-03 13:50:25 +03:00
status = internal_resolve_name ( domain , auto_name_type ,
sitename , ip_list ,
2007-08-28 18:20:53 +04:00
count , resolve_order ) ;
2007-11-28 10:10:20 +03:00
goto out ;
2006-02-04 00:19:24 +03:00
}
2007-10-25 01:16:54 +04:00
if ( ( return_iplist = SMB_MALLOC_ARRAY ( struct ip_service ,
num_addresses ) ) = = NULL ) {
2006-02-04 00:19:24 +03:00
DEBUG ( 3 , ( " get_dc_list: malloc fail ! \n " ) ) ;
2007-11-28 10:10:20 +03:00
status = NT_STATUS_NO_MEMORY ;
goto out ;
2006-02-04 00:19:24 +03:00
}
2002-11-06 08:14:15 +03:00
2006-02-04 00:19:24 +03:00
p = pserver ;
local_count = 0 ;
2002-11-06 08:14:15 +03:00
2006-02-04 00:19:24 +03:00
/* fill in the return list now with real IP's */
2007-10-25 01:16:54 +04:00
while ( ( local_count < num_addresses ) & &
2007-12-08 04:32:32 +03:00
next_token_talloc ( ctx , & p , & name , LIST_SEP ) ) {
2007-10-25 01:16:54 +04:00
struct sockaddr_storage name_ss ;
2016-07-12 11:43:45 +03:00
/* copy any addresses from the auto lookup */
2007-10-25 01:16:54 +04:00
if ( strequal ( name , " * " ) ) {
for ( j = 0 ; j < auto_count ; j + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr ,
sizeof ( addr ) ,
& auto_ip_list [ j ] . ss ) ;
/* Check for and don't copy any
* known bad DC IP ' s . */
if ( ! NT_STATUS_IS_OK ( check_negative_conn_cache (
domain ,
addr ) ) ) {
DEBUG ( 5 , ( " get_dc_list: "
" negative entry %s removed "
" from DC list \n " ,
addr ) ) ;
2006-02-04 00:19:24 +03:00
continue ;
2003-06-25 21:41:05 +04:00
}
2007-10-25 01:16:54 +04:00
return_iplist [ local_count ] . ss =
auto_ip_list [ j ] . ss ;
return_iplist [ local_count ] . port =
auto_ip_list [ j ] . port ;
2006-02-04 00:19:24 +03:00
local_count + + ;
2002-11-23 17:52:34 +03:00
}
2006-02-04 00:19:24 +03:00
continue ;
}
2007-10-25 01:16:54 +04:00
/* added support for address:port syntax for ads
* ( not that I think anyone will ever run the LDAP
* server in an AD domain on something other than
2015-05-21 10:38:42 +03:00
* port 389
* However , the port should not be used for kerberos
*/
2007-10-25 01:16:54 +04:00
2015-05-21 10:38:42 +03:00
port = ( lookup_type = = DC_ADS_ONLY ) ? LDAP_PORT :
( ( lookup_type = = DC_KDC_ONLY ) ? DEFAULT_KRB5_PORT :
PORT_NONE ) ;
2007-10-25 01:16:54 +04:00
if ( ( port_str = strchr ( name , ' : ' ) ) ! = NULL ) {
2006-02-04 00:19:24 +03:00
* port_str = ' \0 ' ;
2015-05-21 10:38:42 +03:00
if ( lookup_type ! = DC_KDC_ONLY ) {
port_str + + ;
port = atoi ( port_str ) ;
}
2006-02-04 00:19:24 +03:00
}
2004-07-02 05:09:10 +04:00
2007-10-25 01:16:54 +04:00
/* explicit lookup; resolve_name() will
* handle names & IP addresses */
2009-07-28 22:51:58 +04:00
if ( resolve_name ( name , & name_ss , 0x20 , true ) ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr ,
sizeof ( addr ) ,
& name_ss ) ;
2004-07-02 05:09:10 +04:00
2006-02-04 00:19:24 +03:00
/* Check for and don't copy any known bad DC IP's. */
2007-10-25 01:16:54 +04:00
if ( ! NT_STATUS_IS_OK ( check_negative_conn_cache ( domain ,
addr ) ) ) {
DEBUG ( 5 , ( " get_dc_list: negative entry %s "
" removed from DC list \n " ,
name ) ) ;
2006-02-04 00:19:24 +03:00
continue ;
2002-11-23 17:52:34 +03:00
}
2006-02-04 00:19:24 +03:00
2007-10-25 01:16:54 +04:00
return_iplist [ local_count ] . ss = name_ss ;
2006-02-04 00:19:24 +03:00
return_iplist [ local_count ] . port = port ;
local_count + + ;
2007-10-25 01:16:54 +04:00
* ordered = true ;
2001-11-22 02:00:59 +03:00
}
2006-02-04 00:19:24 +03:00
}
2007-10-25 01:16:54 +04:00
/* need to remove duplicates in the list if we have any
2006-02-04 00:19:24 +03:00
explicit password servers */
2007-10-25 01:16:54 +04:00
2012-04-28 03:25:58 +04:00
local_count = remove_duplicate_addrs2 ( return_iplist , local_count ) ;
2007-10-25 01:16:54 +04:00
2009-07-28 22:51:58 +04:00
/* For DC's we always prioritize IPv4 due to W2K3 not
* supporting LDAP , KRB5 or CLDAP over IPv6 . */
if ( local_count & & return_iplist ) {
prioritize_ipv4_list ( return_iplist , local_count ) ;
}
2006-02-04 00:19:24 +03:00
if ( DEBUGLEVEL > = 4 ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 4 , ( " get_dc_list: returning %d ip addresses "
" in an %sordered list \n " ,
local_count ,
* ordered ? " " : " un " ) ) ;
2006-02-04 00:19:24 +03:00
DEBUG ( 4 , ( " get_dc_list: " ) ) ;
2007-10-25 01:16:54 +04:00
for ( i = 0 ; i < local_count ; i + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr ,
sizeof ( addr ) ,
& return_iplist [ i ] . ss ) ;
DEBUGADD ( 4 , ( " %s:%d " , addr , return_iplist [ i ] . port ) ) ;
}
2006-02-04 00:19:24 +03:00
DEBUGADD ( 4 , ( " \n " ) ) ;
}
2007-10-25 01:16:54 +04:00
2006-02-04 00:19:24 +03:00
* ip_list = return_iplist ;
* count = local_count ;
2002-11-06 08:14:15 +03:00
2007-11-28 10:10:20 +03:00
status = ( * count ! = 0 ? NT_STATUS_OK : NT_STATUS_NO_LOGON_SERVERS ) ;
out :
2008-06-06 01:27:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
SAFE_FREE ( return_iplist ) ;
* ip_list = NULL ;
* count = 0 ;
}
2007-11-28 10:10:20 +03:00
SAFE_FREE ( auto_ip_list ) ;
TALLOC_FREE ( ctx ) ;
return status ;
1998-10-04 15:25:06 +04:00
}
2004-02-08 03:54:32 +03:00
/*********************************************************************
2004-07-02 05:09:10 +04:00
Small wrapper function to get the DC list and sort it if neccessary .
2004-02-08 03:54:32 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-07-02 05:09:10 +04:00
2007-10-25 01:16:54 +04:00
NTSTATUS get_sorted_dc_list ( const char * domain ,
const char * sitename ,
struct ip_service * * ip_list ,
int * count ,
bool ads_only )
2004-02-08 03:54:32 +03:00
{
2009-02-19 02:51:51 +03:00
bool ordered = false ;
2006-08-28 13:19:30 +04:00
NTSTATUS status ;
2006-09-02 23:27:44 +04:00
enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP ;
2008-06-06 01:27:26 +04:00
* ip_list = NULL ;
* count = 0 ;
2007-10-25 01:16:54 +04:00
DEBUG ( 8 , ( " get_sorted_dc_list: attempting lookup "
2012-07-18 09:19:15 +04:00
" for name %s (sitename %s) \n " ,
2007-01-17 21:25:35 +03:00
domain ,
2012-07-18 09:19:15 +04:00
sitename ? sitename : " NULL " ) ) ;
2007-10-25 01:16:54 +04:00
2006-09-02 23:27:44 +04:00
if ( ads_only ) {
lookup_type = DC_ADS_ONLY ;
}
2007-10-25 01:16:54 +04:00
status = get_dc_list ( domain , sitename , ip_list ,
count , lookup_type , & ordered ) ;
2008-10-27 11:40:25 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NO_LOGON_SERVERS )
& & sitename ) {
DEBUG ( 3 , ( " get_sorted_dc_list: no server for name %s available "
" in site %s, fallback to all servers \n " ,
domain , sitename ) ) ;
status = get_dc_list ( domain , NULL , ip_list ,
count , lookup_type , & ordered ) ;
}
2006-08-28 13:19:30 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-06-06 01:27:26 +04:00
SAFE_FREE ( * ip_list ) ;
* count = 0 ;
2007-10-25 01:16:54 +04:00
return status ;
2004-07-02 05:09:10 +04:00
}
2007-10-25 01:16:54 +04:00
2004-02-08 03:54:32 +03:00
/* only sort if we don't already have an ordered list */
2007-10-25 01:16:54 +04:00
if ( ! ordered ) {
sort_service_list ( * ip_list , * count ) ;
2004-07-02 05:09:10 +04:00
}
2007-10-25 01:16:54 +04:00
2006-08-28 13:19:30 +04:00
return NT_STATUS_OK ;
2004-02-08 03:54:32 +03:00
}
2006-09-02 23:27:44 +04:00
/*********************************************************************
Get the KDC list - re - use all the logic in get_dc_list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-25 01:16:54 +04:00
NTSTATUS get_kdc_list ( const char * realm ,
const char * sitename ,
struct ip_service * * ip_list ,
int * count )
2006-09-02 23:27:44 +04:00
{
2007-10-19 04:40:25 +04:00
bool ordered ;
2006-09-02 23:27:44 +04:00
NTSTATUS status ;
* count = 0 ;
* ip_list = NULL ;
2007-10-25 01:16:54 +04:00
status = get_dc_list ( realm , sitename , ip_list ,
count , DC_KDC_ONLY , & ordered ) ;
2006-09-02 23:27:44 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-06-06 01:27:26 +04:00
SAFE_FREE ( * ip_list ) ;
* count = 0 ;
2007-10-25 01:16:54 +04:00
return status ;
2006-09-02 23:27:44 +04:00
}
/* only sort if we don't already have an ordered list */
if ( ! ordered ) {
2007-10-25 01:16:54 +04:00
sort_service_list ( * ip_list , * count ) ;
2006-09-02 23:27:44 +04:00
}
return NT_STATUS_OK ;
}