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"
2020-07-21 22:34:02 +03:00
# include "librpc/gen_ndr/dns.h"
2020-07-28 21:28:19 +03:00
# include "lib/util/util_net.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.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
2020-07-28 21:28:19 +03:00
/*
* Utility function that copes only with AF_INET and AF_INET6
* as that ' s all we ' re going to get out of DNS / NetBIOS / WINS
* name resolution functions .
*/
bool sockaddr_storage_to_samba_sockaddr ( struct samba_sockaddr * sa ,
const struct sockaddr_storage * ss )
{
sa - > u . ss = * ss ;
switch ( ss - > ss_family ) {
case AF_INET :
sa - > sa_socklen = sizeof ( struct sockaddr_in ) ;
break ;
# ifdef HAVE_IPV6
case AF_INET6 :
sa - > sa_socklen = sizeof ( struct sockaddr_in6 ) ;
break ;
# endif
default :
return false ;
}
return true ;
}
2020-08-27 21:59:20 +03:00
/*
* Utility function to convert from a struct ip_service
* array to a struct samba_sockaddr array . Will go away
* once ip_service is gone .
*/
static NTSTATUS ip_service_to_samba_sockaddr ( TALLOC_CTX * ctx ,
struct samba_sockaddr * * sa_out ,
const struct ip_service * iplist_in ,
size_t count )
{
struct samba_sockaddr * sa = NULL ;
size_t i ;
bool ok ;
if ( count = = 0 ) {
/*
* Zero length arrays are returned as NULL .
* in the name resolution code .
*/
* sa_out = NULL ;
return NT_STATUS_OK ;
}
sa = talloc_zero_array ( ctx ,
struct samba_sockaddr ,
count ) ;
if ( sa = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
for ( i = 0 ; i < count ; i + + ) {
ok = sockaddr_storage_to_samba_sockaddr ( & sa [ i ] ,
& iplist_in [ i ] . ss ) ;
if ( ! ok ) {
TALLOC_FREE ( sa ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
}
* sa_out = sa ;
return NT_STATUS_OK ;
}
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 ;
}
2020-08-24 21:12:03 +03:00
static void set_socket_addr_v4 ( struct samba_sockaddr * addr )
2011-05-14 20:04:49 +04:00
{
2020-08-24 21:12:03 +03:00
if ( ! interpret_string_addr ( & addr - > u . ss , lp_nbt_client_socket_address ( ) ,
2011-05-14 20:04:49 +04:00
AI_NUMERICHOST | AI_PASSIVE ) ) {
2020-08-24 21:12:03 +03:00
zero_sockaddr ( & addr - > u . ss ) ;
/* zero_sockaddr sets family to AF_INET. */
addr - > sa_socklen = sizeof ( struct sockaddr_in ) ;
2011-05-14 20:04:49 +04:00
}
2020-08-24 21:12:03 +03:00
if ( addr - > u . ss . ss_family ! = AF_INET ) {
zero_sockaddr ( & addr - > u . ss ) ;
/* zero_sockaddr sets family to AF_INET. */
addr - > sa_socklen = sizeof ( struct sockaddr_in ) ;
2011-05-14 20:04:49 +04:00
}
}
2011-05-14 20:24:03 +04:00
static struct in_addr my_socket_addr_v4 ( void )
{
2020-08-24 21:12:03 +03:00
struct samba_sockaddr my_addr = { 0 } ;
2011-05-14 20:24:03 +04:00
set_socket_addr_v4 ( & my_addr ) ;
2020-08-24 21:12:03 +03:00
return my_addr . u . in . sin_addr ;
2011-05-14 20:24:03 +04:00
}
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 ,
2020-09-08 23:07:07 +03:00
size_t * num_names ,
2007-10-25 01:16:54 +04:00
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 ;
2020-09-08 23:07:07 +03:00
size_t i ;
2020-09-10 12:27:26 +03:00
size_t result_count = 0 ;
1996-06-04 10:42:03 +04:00
2020-09-10 12:27:26 +03:00
result_count = CVAL ( p , 0 ) ;
2000-12-20 06:22:51 +03:00
2020-09-10 12:27:26 +03:00
if ( result_count = = 0 )
2003-06-14 01:03:15 +04:00
return NULL ;
2000-12-20 06:22:51 +03:00
2020-09-10 12:27:26 +03:00
ret = talloc_array ( mem_ctx , struct node_status , result_count ) ;
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 + + ;
2020-09-10 12:27:26 +03:00
for ( i = 0 ; i < result_count ; i + + ) {
2018-12-31 09:14:48 +03:00
strlcpy ( ret [ i ] . name , p , 16 ) ;
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 */
}
2020-09-10 12:27:26 +03:00
* num_names = result_count ;
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 ) ;
2020-08-24 22:00:29 +03:00
struct samba_sockaddr addr = { 0 } ;
2015-05-21 05:43:27 +03:00
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 ,
2020-08-24 22:00:29 +03:00
& addr . u . sa ,
sizeof ( addr . u . in ) ) ;
2015-05-21 05:43:27 +03:00
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 ,
2020-08-24 22:00:29 +03:00
addr . u . in . sin_addr , addr . u . in . 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 ,
2020-08-24 22:04:16 +03:00
const struct samba_sockaddr * _my_addr ,
const struct samba_sockaddr * _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 )
{
2020-08-24 22:04:16 +03:00
const struct sockaddr * my_addr = & _my_addr - > u . sa ;
size_t my_addr_len = sizeof ( _my_addr - > u . in ) ; /*We know it's AF_INET.*/
const struct sockaddr * dst_addr = & _dst_addr - > u . sa ;
size_t dst_addr_len = sizeof ( _dst_addr - > u . in ) ; /*We know it's AF_INET.*/
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 {
2020-08-24 21:12:03 +03:00
struct samba_sockaddr my_addr ;
2020-08-24 21:19:29 +03:00
struct samba_sockaddr addr ;
2011-01-04 20:34:38 +03:00
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 ;
2020-08-24 21:19:29 +03:00
bool ok ;
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
2020-08-24 21:19:29 +03:00
ok = sockaddr_storage_to_samba_sockaddr ( & state - > addr , addr ) ;
if ( ! ok ) {
/* node status must be IPv4 */
tevent_req_nterror ( req , NT_STATUS_INVALID_ADDRESS ) ;
return tevent_req_post ( req , ev ) ;
}
state - > addr . u . in . sin_port = htons ( NMB_PORT ) ;
2011-01-04 20:34:38 +03:00
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
2020-08-24 21:16:11 +03:00
subreq = nb_trans_send ( state ,
ev ,
2020-08-24 22:04:16 +03:00
& state - > my_addr ,
& state - > addr ,
2020-08-24 21:16:11 +03:00
false ,
state - > buf ,
state - > buflen ,
NMB_PACKET ,
nmb - > header . name_trn_id ,
node_status_query_validator ,
NULL ) ;
2011-01-04 20:34:38 +03:00
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 ,
2020-09-08 23:07:07 +03:00
size_t * pnum_names ,
2011-01-04 20:34:38 +03:00
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 ;
2020-09-08 23:07:07 +03:00
size_t num_names = 0 ;
2011-01-04 20:34:38 +03:00
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 ,
2020-09-08 23:07:07 +03:00
size_t * pnum_names ,
2011-01-04 20:34:38 +03:00
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 ;
2020-08-24 21:23:53 +03:00
struct samba_sockaddr addr_in = { 0 } ;
struct samba_sockaddr addr = { 0 } ;
bool ok ;
2016-12-19 22:18:41 +03:00
2020-08-24 21:23:53 +03:00
ok = sockaddr_storage_to_samba_sockaddr ( & addr_in , paddr ) ;
if ( ! ok ) {
return false ;
}
if ( addr_in . u . ss . ss_family ! = AF_INET ) {
2016-12-19 22:18:41 +03:00
return false ;
}
f = startlmhosts ( get_dyn_LMHOSTSFILE ( ) ) ;
if ( f = = NULL ) {
return false ;
}
2020-08-24 21:23:53 +03:00
while ( getlmhostsent ( talloc_tos ( ) , f , & name , & name_type , & addr . u . ss ) ) {
if ( addr . u . ss . ss_family ! = AF_INET ) {
2016-12-19 22:18:41 +03:00
continue ;
}
if ( name_type ! = qname_type ) {
continue ;
}
2020-08-24 21:23:53 +03:00
if ( sockaddr_equal ( & addr_in . u . sa , & addr . u . sa ) ) {
2016-12-19 22:18:41 +03:00
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 ] ;
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 ;
2020-09-08 23:07:07 +03:00
size_t count = 0 , 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 ;
}
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 ;
2020-08-24 21:32:52 +03:00
struct samba_sockaddr sa1 ;
struct samba_sockaddr sa2 ;
bool ok ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa1 , ss1 ) ;
if ( ! ok ) {
return 0 ; /* No change. */
}
ok = sockaddr_storage_to_samba_sockaddr ( & sa2 , ss2 ) ;
if ( ! ok ) {
return 0 ; /* No change. */
}
2001-02-18 13:36:03 +03:00
2009-07-28 22:51:58 +04:00
/* Sort IPv4 addresses first. */
2020-08-24 21:32:52 +03:00
if ( sa1 . u . ss . ss_family ! = sa2 . u . ss . ss_family ) {
if ( sa2 . u . ss . 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 + + ) {
2020-08-24 21:32:52 +03:00
struct samba_sockaddr sif = { 0 } ;
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
2020-08-24 21:32:52 +03:00
ok = sockaddr_storage_to_samba_sockaddr ( & sif , iface_n_bcast ( i ) ) ;
if ( ! ok ) {
return 0 ; /* No change. */
}
if ( sif . u . ss . ss_family ! = sa1 . u . ss . 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 ;
}
2020-08-24 21:32:52 +03:00
if ( sif . u . ss . ss_family = = AF_INET ) {
p_if = ( const unsigned char * ) & sif . u . in . sin_addr ;
p_ss1 = ( const unsigned char * ) & sa1 . u . in . sin_addr ;
p_ss2 = ( const unsigned char * ) & sa2 . u . in . sin_addr ;
2007-10-25 01:16:54 +04:00
len = 4 ;
}
# if defined(HAVE_IPV6)
2020-08-24 21:32:52 +03:00
if ( sif . u . ss . ss_family = = AF_INET6 ) {
p_if = ( const unsigned char * ) & sif . u . in6 . sin6_addr ;
p_ss1 = ( const unsigned char * ) & sa1 . u . in6 . sin6_addr ;
p_ss2 = ( const unsigned char * ) & sa2 . u . in6 . sin6_addr ;
2007-10-25 01:16:54 +04:00
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 */
2020-08-24 21:32:52 +03:00
if ( iface_local ( & sa1 . u . sa ) ) {
if ( sa1 . u . ss . ss_family = = AF_INET ) {
2007-10-25 01:16:54 +04:00
max_bits1 + = 32 ;
} else {
max_bits1 + = 128 ;
}
}
2020-08-24 21:32:52 +03:00
if ( iface_local ( & sa2 . u . sa ) ) {
if ( sa2 . u . ss . 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
2020-09-09 02:01:37 +03:00
static void sort_addr_list ( struct sockaddr_storage * sslist , size_t 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
2020-09-09 02:01:37 +03:00
static void sort_service_list ( struct ip_service * servlist , size_t 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-08-27 01:16:48 +03:00
size_t remove_duplicate_addrs2 ( struct ip_service * iplist , size_t count )
2003-06-25 21:41:05 +04:00
{
2020-08-27 01:16:48 +03:00
size_t 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 + + ) {
2020-08-24 21:54:26 +03:00
bool ok ;
struct samba_sockaddr sa_i = { 0 } ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa_i , & iplist [ i ] . ss ) ;
if ( ! ok ) {
continue ;
}
if ( is_zero_addr ( & sa_i . u . 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 + + ) {
2020-08-24 21:54:26 +03:00
struct samba_sockaddr sa_j = { 0 } ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa_j ,
& iplist [ j ] . ss ) ;
if ( ! ok ) {
continue ;
}
if ( sockaddr_equal ( & sa_i . u . sa , & sa_j . u . sa ) & &
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 ) ) {
2020-03-26 12:36:19 +03:00
ARRAY_DEL_ELEMENT ( iplist , i , count ) ;
2003-06-25 21:41:05 +04:00
count - - ;
}
}
return count ;
}
2020-09-09 01:58:57 +03:00
static bool prioritize_ipv4_list ( struct ip_service * iplist , size_t count )
2009-07-28 22:51:58 +04:00
{
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 ) ;
2020-09-09 01:58:57 +03:00
size_t i , j ;
2009-07-28 22:51:58 +04:00
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 {
2020-08-24 21:12:03 +03:00
struct samba_sockaddr my_addr ;
2020-08-24 21:26:23 +03:00
struct samba_sockaddr addr ;
2011-01-04 20:48:47 +03:00
bool bcast ;
2020-01-14 19:12:33 +03:00
bool bcast_star_query ;
2011-01-04 20:48:47 +03:00
uint8_t buf [ 1024 ] ;
ssize_t buflen ;
NTSTATUS validate_error ;
uint8_t flags ;
struct sockaddr_storage * addrs ;
2020-09-08 23:37:59 +03:00
size_t num_addrs ;
2011-01-04 20:48:47 +03:00
} ;
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 ;
2020-08-24 21:26:23 +03:00
bool ok ;
2011-01-04 20:48:47 +03:00
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
}
2020-08-24 21:26:23 +03:00
ok = sockaddr_storage_to_samba_sockaddr ( & state - > addr , addr ) ;
if ( ! ok ) {
/* Node status must be IPv4 */
tevent_req_nterror ( req , NT_STATUS_INVALID_ADDRESS ) ;
return tevent_req_post ( req , ev ) ;
}
state - > addr . u . in . 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
2020-01-14 19:12:33 +03:00
if ( bcast & & ( strcmp ( name , " * " ) = = 0 ) ) {
/*
* We ' re doing a broadcast query for all
* names in the area . Remember this so
* we will wait for all names within
* the timeout period .
*/
state - > bcast_star_query = true ;
}
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
2020-08-24 21:16:11 +03:00
subreq = nb_trans_send ( state ,
ev ,
2020-08-24 22:04:16 +03:00
& state - > my_addr ,
& state - > addr ,
2020-08-24 21:16:11 +03:00
bcast ,
state - > buf ,
state - > buflen ,
NMB_PACKET ,
nmb - > header . name_trn_id ,
name_query_validator ,
state ) ;
2011-01-04 20:48:47 +03:00
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 ;
2020-08-24 21:57:59 +03:00
struct samba_sockaddr sa = { 0 } ;
bool ok ;
2011-05-03 23:28:37 +04:00
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 ) ;
2020-08-24 21:57:59 +03:00
ok = sockaddr_storage_to_samba_sockaddr ( & sa , & addr ) ;
if ( ! ok ) {
continue ;
}
if ( is_zero_addr ( & sa . u . ss ) ) {
2012-04-28 03:25:58 +04:00
continue ;
}
2011-05-03 23:28:37 +04:00
for ( j = 0 ; j < state - > num_addrs ; j + + ) {
2020-08-24 21:57:59 +03:00
struct samba_sockaddr sa_j = { 0 } ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa_j ,
& state - > addrs [ j ] ) ;
if ( ! ok ) {
continue ;
}
if ( sockaddr_equal ( & sa . u . sa , & sa_j . u . sa ) ) {
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 ;
2020-09-08 23:37:59 +03:00
/* wrap check. */
if ( state - > num_addrs + 1 < state - > num_addrs ) {
return false ;
}
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
2020-01-14 19:12:33 +03:00
* queries . If we got a unique name and we are not querying
* all names registered within broadcast area ( query
* for the name ' * ' , so state - > bcast_star_query is set ) ,
* we ' re done .
2011-01-04 20:48:47 +03:00
*/
2020-01-14 19:12:33 +03:00
return ( got_unique_netbios_name & & ! state - > bcast_star_query ) ;
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 ,
2020-09-08 23:37:59 +03:00
struct sockaddr_storage * * addrs , size_t * num_addrs ,
2011-01-04 20:48:47 +03:00
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 ,
2020-09-08 23:37:59 +03:00
size_t * num_addrs , uint8_t * flags )
2011-01-04 20:48:47 +03:00
{
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 ;
2020-08-27 01:54:49 +03:00
orig_count is the length of ss_list on input ,
* count_out is the length of return_iplist on output as we remove any
2012-04-28 03:07:20 +04:00
zero addresses from ss_list .
2003-06-25 21:41:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-08-27 05:05:28 +03:00
static bool convert_ss2service ( TALLOC_CTX * ctx ,
struct ip_service * * return_iplist ,
2007-10-25 01:16:54 +04:00
const struct sockaddr_storage * ss_list ,
2020-08-27 01:54:49 +03:00
size_t orig_count ,
size_t * count_out )
2003-06-25 21:41:05 +04:00
{
2020-08-27 01:54:49 +03:00
size_t i ;
size_t real_count = 0 ;
2020-08-27 01:57:27 +03:00
struct ip_service * iplist = NULL ;
2001-02-18 13:36:03 +03:00
2020-08-27 01:54:49 +03:00
if ( orig_count = = 0 | | ss_list = = NULL ) {
return false ;
}
2007-10-25 01:16:54 +04:00
2012-04-28 03:07:20 +04:00
/* Filter out zero addrs. */
2020-08-27 01:54:49 +03:00
for ( i = 0 ; i < orig_count ; i + + ) {
2012-04-28 03:07:20 +04:00
if ( is_zero_addr ( & ss_list [ i ] ) ) {
continue ;
}
real_count + + ;
}
2020-08-27 01:54:49 +03:00
if ( real_count = = 0 ) {
2012-04-28 03:07:20 +04:00
return false ;
}
2003-06-25 21:41:05 +04:00
/* copy the ip address; port will be PORT_NONE */
2020-08-27 05:05:28 +03:00
iplist = talloc_zero_array ( ctx , struct ip_service , real_count ) ;
2020-08-27 01:57:27 +03:00
if ( iplist = = NULL ) {
2020-08-27 05:05:28 +03:00
DBG_ERR ( " talloc failed for %zu enetries! \n " , real_count ) ;
2020-08-27 01:54:49 +03:00
return false ;
2003-06-25 21:41:05 +04:00
}
2007-10-25 01:16:54 +04:00
2020-08-27 01:54:49 +03:00
real_count = 0 ;
for ( i = 0 ; i < orig_count ; i + + ) {
2012-04-28 03:07:20 +04:00
if ( is_zero_addr ( & ss_list [ i ] ) ) {
continue ;
}
2020-08-27 01:57:27 +03:00
iplist [ real_count ] . ss = ss_list [ i ] ;
iplist [ real_count ] . port = PORT_NONE ;
2012-04-28 03:07:20 +04:00
real_count + + ;
2003-06-25 21:41:05 +04:00
}
2020-08-27 01:57:27 +03:00
* return_iplist = iplist ;
2020-08-27 01:54:49 +03:00
* count_out = 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 ;
2020-09-08 23:37:59 +03:00
size_t num_addrs ;
2011-04-25 20:30:35 +04:00
int wait_msec ;
int timeout_msec ;
struct tevent_req * * subreqs ;
2020-09-08 23:37:59 +03:00
size_t num_received ;
size_t num_sent ;
2011-04-25 20:30:35 +04:00
2020-09-08 23:37:59 +03:00
size_t received_index ;
2011-04-25 20:30:35 +04:00
struct sockaddr_storage * result_addrs ;
2020-09-08 23:37:59 +03:00
size_t num_result_addrs ;
2011-04-25 20:30:35 +04:00
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 ,
2020-09-08 23:37:59 +03:00
size_t num_addrs , int wait_msec , int timeout_msec )
2011-04-25 20:30:35 +04:00
{
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 ) ;
2020-09-08 23:37:59 +03:00
size_t i ;
2011-04-25 20:30:35 +04:00
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 ] ) ;
2020-09-08 23:37:59 +03:00
/* wrap check. */
if ( state - > num_received + 1 < state - > num_received ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
2011-04-25 20:30:35 +04:00
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 ,
2020-09-08 23:37:59 +03:00
size_t * num_result_addrs , uint8_t * flags ,
size_t * received_index )
2011-04-25 20:30:35 +04:00
{
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 ;
2020-09-08 23:37:59 +03:00
size_t num_addrs ;
2011-06-19 15:05:29 +04:00
} ;
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 ;
2020-09-08 23:37:59 +03:00
size_t 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 ,
2019-10-31 09:47:53 +03:00
bcast_addrs , num_bcast_addrs , 0 , 250 ) ;
2011-06-19 15:05:29 +04:00
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 ,
2020-09-08 23:37:59 +03:00
size_t * num_addrs )
2011-06-19 15:05:29 +04:00
{
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 ;
}
2020-07-21 03:56:48 +03:00
NTSTATUS name_resolve_bcast ( TALLOC_CTX * mem_ctx ,
const char * name ,
2011-06-19 15:05:29 +04:00
int name_type ,
struct sockaddr_storage * * return_iplist ,
2020-09-08 23:37:59 +03:00
size_t * return_count )
2011-06-19 15:05:29 +04:00
{
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 ;
2020-09-08 23:37:59 +03:00
size_t num_servers ;
2011-05-14 20:24:03 +04:00
struct sockaddr_storage server ;
2020-09-08 23:37:59 +03:00
size_t num_sent ;
2011-05-14 20:24:03 +04:00
struct sockaddr_storage * addrs ;
2020-09-08 23:37:59 +03:00
size_t num_addrs ;
2011-05-14 20:24:03 +04:00
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 ,
2020-09-08 23:37:59 +03:00
struct in_addr * servers , size_t num_servers )
2011-05-14 20:24:03 +04:00
{
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 ) ;
2020-09-08 23:37:59 +03:00
2011-05-14 20:24:03 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2020-09-08 23:37:59 +03:00
/* wrap check */
if ( state - > num_sent + 1 < state - > num_sent ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return tevent_req_post ( req , ev ) ;
}
state - > num_sent + = 1 ;
2011-05-14 20:24:03 +04:00
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 ,
2020-09-08 23:37:59 +03:00
size_t * num_addrs ,
2011-05-14 20:24:03 +04:00
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 {
2020-09-08 23:37:59 +03:00
size_t num_sent ;
size_t num_received ;
2011-06-02 16:12:06 +04:00
struct sockaddr_storage * addrs ;
2020-09-08 23:37:59 +03:00
size_t num_addrs ;
2011-06-02 16:12:06 +04:00
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 ;
2020-08-25 01:35:32 +03:00
struct samba_sockaddr src_sa = { 0 } ;
2011-06-02 16:12:06 +04:00
struct in_addr src_ip ;
2020-09-08 23:37:59 +03:00
size_t i , num_wins_tags ;
2020-08-25 01:35:32 +03:00
bool ok ;
2011-06-02 16:12:06 +04:00
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 ) ;
}
2020-08-25 01:35:32 +03:00
ok = sockaddr_storage_to_samba_sockaddr ( & src_sa , & src_ss ) ;
if ( ! ok ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
goto fail ;
}
if ( src_sa . u . ss . ss_family ! = AF_INET ) {
2011-06-02 16:12:06 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2020-08-25 01:35:32 +03:00
print_sockaddr ( addr , sizeof ( addr ) , & src_sa . u . ss ) ;
2011-06-02 16:12:06 +04:00
DEBUG ( 3 , ( " resolve_wins: cannot receive WINS replies "
" on IPv6 address %s \n " ,
addr ) ) ;
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
goto fail ;
}
2020-08-25 01:35:32 +03:00
src_ip = src_sa . u . in . sin_addr ;
2011-06-02 16:12:06 +04:00
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 ) {
2020-09-08 23:37:59 +03:00
/* wrap check. */
if ( num_wins_tags + 1 < num_wins_tags ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
goto fail ;
}
2011-06-02 16:12:06 +04:00
num_wins_tags + = 1 ;
}
for ( i = 0 ; i < num_wins_tags ; i + + ) {
2020-09-08 23:37:59 +03:00
size_t num_servers , num_alive ;
2011-06-02 16:12:06 +04:00
struct in_addr * servers , * alive ;
2020-09-08 23:37:59 +03:00
size_t j ;
2011-06-02 16:12:06 +04:00
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 ;
}
2020-09-08 23:37:59 +03:00
/* wrap check. */
if ( state - > num_received + 1 < state - > num_received ) {
tevent_req_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
2011-06-02 16:12:06 +04:00
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 ,
2020-09-08 23:37:59 +03:00
size_t * num_addrs , uint8_t * flags )
2011-06-02 16:12:06 +04:00
{
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
2020-07-21 03:53:28 +03:00
NTSTATUS resolve_wins ( TALLOC_CTX * mem_ctx ,
const char * name ,
2007-10-25 01:16:54 +04:00
int name_type ,
2011-06-03 17:49:55 +04:00
struct sockaddr_storage * * return_iplist ,
2020-09-08 23:37:59 +03:00
size_t * 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
}
2020-07-21 22:34:02 +03:00
/********************************************************
Use ads_dns_lookup_ [ a | aaaa ] _send ( ) calls to look up a
list of names asynchronously .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct dns_query_state {
/* Used to tell our parent we've completed. */
struct dns_lookup_list_async_state * p_async_state ;
const char * query_name ; /* For debugging only. */
size_t num_addrs ;
struct samba_sockaddr * addrs ;
} ;
struct dns_lookup_list_async_state {
bool timed_out ;
size_t num_query_returns ;
struct dns_query_state * queries ;
} ;
/* Called on query timeout. */
static void dns_lookup_send_timeout_handler ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t ,
void * private_data )
{
bool * timed_out = ( bool * ) private_data ;
* timed_out = true ;
}
static void dns_lookup_list_a_done ( struct tevent_req * req ) ;
# if defined(HAVE_IPV6)
static void dns_lookup_list_aaaa_done ( struct tevent_req * req ) ;
# endif
2020-07-22 00:56:47 +03:00
NTSTATUS dns_lookup_list_async ( TALLOC_CTX * ctx ,
size_t num_dns_names ,
const char * * dns_lookup_names ,
size_t * p_num_addrs ,
2020-07-29 02:51:03 +03:00
struct samba_sockaddr * * pp_addrs ,
2020-07-22 00:56:47 +03:00
char * * * pp_dns_names )
2020-07-21 22:34:02 +03:00
{
struct dns_lookup_list_async_state * state = NULL ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
struct tevent_timer * timer = NULL ;
size_t num_queries_sent = 0 ;
size_t queries_size = num_dns_names ;
size_t i ;
size_t num_addrs = 0 ;
2020-07-29 02:51:03 +03:00
struct samba_sockaddr * addr_out = NULL ;
2020-07-21 22:34:02 +03:00
char * * dns_names_ret = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
/* Nothing to do. */
if ( num_dns_names = = 0 ) {
* p_num_addrs = 0 ;
* pp_addrs = NULL ;
if ( pp_dns_names ! = NULL ) {
* pp_dns_names = NULL ;
}
return NT_STATUS_OK ;
}
state = talloc_zero ( ctx , struct dns_lookup_list_async_state ) ;
if ( state = = NULL ) {
goto fail ;
}
ev = samba_tevent_context_init ( ctx ) ;
if ( ev = = NULL ) {
goto fail ;
}
# if defined(HAVE_IPV6)
queries_size = 2 * num_dns_names ;
/* Wrap protection. */
if ( queries_size < num_dns_names ) {
goto fail ;
}
# else
queries_size = num_dns_names ;
# endif
state - > queries = talloc_zero_array ( state ,
struct dns_query_state ,
queries_size ) ;
2020-08-11 10:51:39 +03:00
if ( state - > queries = = NULL ) {
2020-07-21 22:34:02 +03:00
goto fail ;
}
/* Hit all the DNS servers with asnyc lookups for all the names. */
for ( i = 0 ; i < num_dns_names ; i + + ) {
DBG_INFO ( " async DNS lookup A record for %s \n " ,
dns_lookup_names [ i ] ) ;
/* Setup the query state. */
state - > queries [ num_queries_sent ] . query_name =
dns_lookup_names [ i ] ;
state - > queries [ num_queries_sent ] . p_async_state = state ;
req = ads_dns_lookup_a_send ( ev , ev , dns_lookup_names [ i ] ) ;
if ( req = = NULL ) {
goto fail ;
}
tevent_req_set_callback ( req ,
dns_lookup_list_a_done ,
& state - > queries [ num_queries_sent ] ) ;
num_queries_sent + + ;
# if defined(HAVE_IPV6)
/* If we're IPv6 capable ask for that too. */
state - > queries [ num_queries_sent ] . query_name =
dns_lookup_names [ i ] ;
state - > queries [ num_queries_sent ] . p_async_state = state ;
DBG_INFO ( " async DNS lookup AAAA record for %s \n " ,
dns_lookup_names [ i ] ) ;
req = ads_dns_lookup_aaaa_send ( ev , ev , dns_lookup_names [ i ] ) ;
if ( req = = NULL ) {
goto fail ;
}
tevent_req_set_callback ( req ,
dns_lookup_list_aaaa_done ,
& state - > queries [ num_queries_sent ] ) ;
num_queries_sent + + ;
# endif
}
/* We must always have a timeout. */
timer = tevent_add_timer ( ev ,
ev ,
timeval_current_ofs ( lp_get_async_dns_timeout ( ) ,
0 ) ,
dns_lookup_send_timeout_handler ,
& state - > timed_out ) ;
if ( timer = = NULL ) {
goto fail ;
}
/* Loop until timed out or got all replies. */
for ( ; ; ) {
int ret ;
if ( state - > timed_out ) {
break ;
}
if ( state - > num_query_returns = = num_queries_sent ) {
break ;
}
ret = tevent_loop_once ( ev ) ;
if ( ret ! = 0 ) {
goto fail ;
}
}
/* Count what we got back. */
for ( i = 0 ; i < num_queries_sent ; i + + ) {
struct dns_query_state * query = & state - > queries [ i ] ;
/* Wrap check. */
if ( num_addrs + query - > num_addrs < num_addrs ) {
goto fail ;
}
num_addrs + = query - > num_addrs ;
}
if ( state - > timed_out ) {
DBG_INFO ( " async DNS lookup timed out after %zu entries "
" (not an error) \n " ,
num_addrs ) ;
}
addr_out = talloc_zero_array ( ctx ,
2020-07-29 02:51:03 +03:00
struct samba_sockaddr ,
2020-07-21 22:34:02 +03:00
num_addrs ) ;
if ( addr_out = = NULL ) {
goto fail ;
}
/*
* Did the caller want an array of names back
* that match the IP addresses ? If we provide
* this , dsgetdcname ( ) internals can now use this
* async lookup code also .
*/
if ( pp_dns_names ! = NULL ) {
dns_names_ret = talloc_zero_array ( ctx ,
char * ,
num_addrs ) ;
if ( dns_names_ret = = NULL ) {
goto fail ;
}
}
/* Copy what we got back. */
num_addrs = 0 ;
for ( i = 0 ; i < num_queries_sent ; i + + ) {
size_t j ;
struct dns_query_state * query = & state - > queries [ i ] ;
if ( query - > num_addrs = = 0 ) {
continue ;
}
if ( dns_names_ret ! = NULL ) {
/*
* If caller wants a name array matched with
* the addrs array , copy the same queried name for
* each IP address returned .
*/
for ( j = 0 ; j < query - > num_addrs ; j + + ) {
dns_names_ret [ num_addrs + j ] = talloc_strdup (
ctx ,
query - > query_name ) ;
if ( dns_names_ret [ num_addrs + j ] = = NULL ) {
goto fail ;
}
}
}
for ( j = 0 ; j < query - > num_addrs ; j + + ) {
2020-07-29 02:51:03 +03:00
addr_out [ num_addrs ] = query - > addrs [ j ] ;
2020-07-21 22:34:02 +03:00
}
num_addrs + = query - > num_addrs ;
}
* p_num_addrs = num_addrs ;
* pp_addrs = addr_out ;
if ( pp_dns_names ! = NULL ) {
* pp_dns_names = dns_names_ret ;
}
status = NT_STATUS_OK ;
fail :
TALLOC_FREE ( state ) ;
TALLOC_FREE ( ev ) ;
return status ;
}
/*
Called when an A record lookup completes .
*/
static void dns_lookup_list_a_done ( struct tevent_req * req )
{
/*
* Callback data is an element of a talloc ' ed array ,
* not a talloc object in its own right . So use the
* tevent_req_callback_data_void ( ) void * cast function .
*/
struct dns_query_state * state = ( struct dns_query_state * )
tevent_req_callback_data_void ( req ) ;
uint8_t rcode = 0 ;
size_t i ;
char * * hostnames_out = NULL ;
struct samba_sockaddr * addrs = NULL ;
size_t num_addrs = 0 ;
NTSTATUS status ;
/* For good or ill, tell the parent we're finished. */
state - > p_async_state - > num_query_returns + + ;
status = ads_dns_lookup_a_recv ( req ,
state - > p_async_state ,
& rcode ,
& num_addrs ,
& hostnames_out ,
& addrs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_INFO ( " async DNS A lookup for %s returned %s \n " ,
state - > query_name ,
nt_errstr ( status ) ) ;
return ;
}
if ( rcode ! = DNS_RCODE_OK ) {
DBG_INFO ( " async DNS A lookup for %s returned DNS code %u \n " ,
state - > query_name ,
( unsigned int ) rcode ) ;
return ;
}
if ( num_addrs = = 0 ) {
DBG_INFO ( " async DNS A lookup for %s returned 0 addresses. \n " ,
state - > query_name ) ;
return ;
}
/* Copy data out. */
state - > addrs = talloc_zero_array ( state - > p_async_state ,
struct samba_sockaddr ,
num_addrs ) ;
if ( state - > addrs = = NULL ) {
return ;
}
for ( i = 0 ; i < num_addrs ; i + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
DBG_INFO ( " async DNS A lookup for %s [%zu] got %s -> %s \n " ,
state - > query_name ,
i ,
hostnames_out [ i ] ,
print_sockaddr ( addr ,
sizeof ( addr ) ,
& addrs [ i ] . u . ss ) ) ;
state - > addrs [ i ] = addrs [ i ] ;
}
state - > num_addrs = num_addrs ;
}
# if defined(HAVE_IPV6)
/*
Called when an AAAA record lookup completes .
*/
static void dns_lookup_list_aaaa_done ( struct tevent_req * req )
{
/*
* Callback data is an element of a talloc ' ed array ,
* not a talloc object in its own right . So use the
* tevent_req_callback_data_void ( ) void * cast function .
*/
struct dns_query_state * state = ( struct dns_query_state * )
tevent_req_callback_data_void ( req ) ;
uint8_t rcode = 0 ;
size_t i ;
char * * hostnames_out = NULL ;
struct samba_sockaddr * addrs = NULL ;
size_t num_addrs = 0 ;
NTSTATUS status ;
/* For good or ill, tell the parent we're finished. */
state - > p_async_state - > num_query_returns + + ;
status = ads_dns_lookup_aaaa_recv ( req ,
state - > p_async_state ,
& rcode ,
& num_addrs ,
& hostnames_out ,
& addrs ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_INFO ( " async DNS AAAA lookup for %s returned %s \n " ,
state - > query_name ,
nt_errstr ( status ) ) ;
return ;
}
if ( rcode ! = DNS_RCODE_OK ) {
DBG_INFO ( " async DNS AAAA lookup for %s returned DNS code %u \n " ,
state - > query_name ,
( unsigned int ) rcode ) ;
return ;
}
if ( num_addrs = = 0 ) {
DBG_INFO ( " async DNS AAAA lookup for %s returned 0 addresses. \n " ,
state - > query_name ) ;
return ;
}
/* Copy data out. */
state - > addrs = talloc_zero_array ( state - > p_async_state ,
struct samba_sockaddr ,
num_addrs ) ;
if ( state - > addrs = = NULL ) {
return ;
}
for ( i = 0 ; i < num_addrs ; i + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
DBG_INFO ( " async DNS AAAA lookup for %s [%zu] got %s -> %s \n " ,
state - > query_name ,
i ,
hostnames_out [ i ] ,
print_sockaddr ( addr ,
sizeof ( addr ) ,
& addrs [ i ] . u . ss ) ) ;
state - > addrs [ i ] = addrs [ i ] ;
}
state - > num_addrs = num_addrs ;
}
# endif
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
2020-07-21 03:45:44 +03:00
static NTSTATUS resolve_hosts ( TALLOC_CTX * mem_ctx ,
const char * name ,
int name_type ,
2015-12-15 23:43:50 +03:00
struct sockaddr_storage * * return_iplist ,
2020-09-09 01:18:33 +03:00
size_t * 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 ;
2020-09-09 00:04:41 +03:00
size_t i = 0 ;
size_t ret_count = 0 ;
struct sockaddr_storage * iplist = NULL ;
2007-10-16 03:11:48 +04:00
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
}
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 ;
}
2020-09-09 00:04:41 +03:00
/* wrap check. */
if ( ret_count + 1 < ret_count ) {
freeaddrinfo ( ailist ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
ret_count + = 1 ;
2007-10-16 03:11:48 +04:00
2020-09-09 00:04:41 +03:00
iplist = talloc_realloc (
mem_ctx , iplist , struct sockaddr_storage ,
ret_count ) ;
if ( iplist = = NULL ) {
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
}
2020-09-09 00:04:41 +03:00
iplist [ i ] = ss ;
2007-10-19 23:36:34 +04:00
i + + ;
2007-10-16 03:11:48 +04:00
}
if ( ailist ) {
freeaddrinfo ( ailist ) ;
}
2020-09-09 00:04:41 +03:00
if ( ret_count = = 0 ) {
return NT_STATUS_UNSUCCESSFUL ;
}
2020-09-09 01:18:33 +03:00
* return_count = ret_count ;
2020-09-09 00:04:41 +03:00
* return_iplist = iplist ;
return NT_STATUS_OK ;
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
2020-07-21 03:59:20 +03:00
static NTSTATUS resolve_ads ( TALLOC_CTX * ctx ,
const char * name ,
2008-01-16 17:52:53 +03:00
int name_type ,
const char * sitename ,
2020-07-21 06:17:54 +03:00
struct sockaddr_storage * * return_addrs ,
2020-09-09 01:24:26 +03:00
size_t * return_count )
2004-01-09 05:38:58 +03:00
{
2020-09-10 18:19:37 +03:00
size_t i ;
2006-05-12 19:17:35 +04:00
NTSTATUS status ;
struct dns_rr_srv * dcs = NULL ;
2020-09-10 18:19:37 +03:00
size_t numdcs = 0 ;
2020-09-09 01:24:26 +03:00
size_t numaddrs = 0 ;
2020-07-21 05:50:04 +03:00
size_t num_srv_addrs = 0 ;
struct sockaddr_storage * srv_addrs = NULL ;
size_t num_dns_addrs = 0 ;
2020-07-29 02:51:03 +03:00
struct samba_sockaddr * dns_addrs = NULL ;
2020-07-21 05:50:04 +03:00
size_t num_dns_names = 0 ;
const char * * dns_lookup_names = NULL ;
2020-07-21 06:17:54 +03:00
struct sockaddr_storage * ret_addrs = NULL ;
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 ;
}
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
2020-07-21 05:50:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( dcs ) ;
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 ) {
2020-07-21 06:17:54 +03:00
* return_addrs = NULL ;
2015-06-30 17:51:43 +03:00
* return_count = 0 ;
2020-07-21 05:50:04 +03:00
TALLOC_FREE ( dcs ) ;
2015-06-30 17:51:43 +03:00
return NT_STATUS_OK ;
}
2020-07-21 05:50:04 +03:00
/*
* Split the returned values into 2 arrays . First one
* is a struct sockaddr_storage array that contains results
* from the SRV record lookup that contain both hostnames
* and IP addresses . We only need to copy out the IP
* addresses . This is srv_addrs .
*
* Second array contains the results from the SRV record
* lookup that only contain hostnames - no IP addresses .
* We must then call dns_lookup_list ( ) to lookup
* hostnames - > IP address . This is dns_addrs .
*
* Finally we will merge these two arrays to create the
2020-07-21 06:17:54 +03:00
* return sockaddr_storage array .
2020-07-21 05:50:04 +03:00
*/
/* First count the sizes of each array. */
for ( i = 0 ; i < numdcs ; i + + ) {
if ( dcs [ i ] . ss_s ! = NULL ) {
/* IP address returned in SRV record. */
if ( num_srv_addrs + dcs [ i ] . num_ips < num_srv_addrs ) {
/* Wrap check. */
TALLOC_FREE ( dcs ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
/* Add in the number of addresses we got. */
num_srv_addrs + = dcs [ i ] . num_ips ;
/*
* If we got any IP addresses zero out
* the hostname so we know we ' ve already
* processed this entry and won ' t add it
* to the dns_lookup_names array we use
* to do DNS queries below .
*/
dcs [ i ] . hostname = NULL ;
2012-04-30 22:05:51 +04:00
} else {
2020-07-21 05:50:04 +03:00
/* Ensure we have a hostname to lookup. */
if ( dcs [ i ] . hostname = = NULL ) {
continue ;
}
/* No IP address returned in SRV record. */
if ( num_dns_names + 1 < num_dns_names ) {
/* Wrap check. */
TALLOC_FREE ( dcs ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
/* One more name to lookup. */
num_dns_names + = 1 ;
2012-04-30 22:05:51 +04:00
}
2020-07-21 05:50:04 +03:00
}
2007-10-25 01:16:54 +04:00
2020-07-21 05:50:04 +03:00
/* Allocate the list of IP addresses we already have. */
srv_addrs = talloc_zero_array ( ctx ,
struct sockaddr_storage ,
num_srv_addrs ) ;
if ( srv_addrs = = NULL ) {
TALLOC_FREE ( dcs ) ;
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
2020-07-21 05:50:04 +03:00
/* Copy the addresses we already have. */
num_srv_addrs = 0 ;
for ( i = 0 ; i < numdcs ; i + + ) {
/* Copy all the IP addresses from the SRV response */
size_t j ;
for ( j = 0 ; j < dcs [ i ] . num_ips ; j + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
2007-10-25 01:16:54 +04:00
2020-07-21 05:50:04 +03:00
srv_addrs [ num_srv_addrs ] = dcs [ i ] . ss_s [ j ] ;
if ( is_zero_addr ( & srv_addrs [ num_srv_addrs ] ) ) {
2006-08-24 16:13:57 +04:00
continue ;
}
2020-07-21 05:50:04 +03:00
DBG_DEBUG ( " SRV lookup %s got IP[%zu] %s \n " ,
name ,
j ,
print_sockaddr ( addr ,
sizeof ( addr ) ,
& srv_addrs [ num_srv_addrs ] ) ) ;
num_srv_addrs + + ;
2007-10-25 01:16:54 +04:00
}
2006-05-12 19:17:35 +04:00
}
2007-10-25 01:16:54 +04:00
2020-07-21 05:50:04 +03:00
/* Allocate the array of hostnames we must look up. */
dns_lookup_names = talloc_zero_array ( ctx ,
const char * ,
num_dns_names ) ;
if ( dns_lookup_names = = NULL ) {
TALLOC_FREE ( dcs ) ;
TALLOC_FREE ( srv_addrs ) ;
return NT_STATUS_NO_MEMORY ;
}
num_dns_names = 0 ;
for ( i = 0 ; i < numdcs ; i + + ) {
if ( dcs [ i ] . hostname = = NULL ) {
/*
* Must have been a SRV return with an IP address .
* We don ' t need to look up this hostname .
*/
continue ;
}
dns_lookup_names [ num_dns_names ] = dcs [ i ] . hostname ;
num_dns_names + + ;
}
/* Lookup the addresses on the dns_lookup_list. */
2020-07-21 22:38:42 +03:00
status = dns_lookup_list_async ( ctx ,
2020-07-21 05:50:04 +03:00
num_dns_names ,
dns_lookup_names ,
& num_dns_addrs ,
2020-07-21 22:38:42 +03:00
& dns_addrs ,
NULL ) ;
2020-07-21 05:50:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( dcs ) ;
TALLOC_FREE ( srv_addrs ) ;
TALLOC_FREE ( dns_lookup_names ) ;
2020-08-05 17:22:10 +03:00
TALLOC_FREE ( dns_addrs ) ;
2020-07-21 05:50:04 +03:00
return status ;
}
/*
2020-07-21 06:17:54 +03:00
* Combine the two sockaddr_storage arrays into a talloc ' ed
* struct sockaddr_storage array return .
*/
2020-07-21 05:50:04 +03:00
numaddrs = num_srv_addrs + num_dns_addrs ;
2020-09-09 01:24:26 +03:00
/* Wrap check */
if ( numaddrs < num_srv_addrs ) {
2020-07-21 05:50:04 +03:00
TALLOC_FREE ( dcs ) ;
TALLOC_FREE ( srv_addrs ) ;
TALLOC_FREE ( dns_addrs ) ;
TALLOC_FREE ( dns_lookup_names ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
if ( numaddrs = = 0 ) {
/* Keep the same semantics for zero names. */
TALLOC_FREE ( dcs ) ;
TALLOC_FREE ( srv_addrs ) ;
TALLOC_FREE ( dns_addrs ) ;
TALLOC_FREE ( dns_lookup_names ) ;
2020-07-21 06:17:54 +03:00
* return_addrs = NULL ;
2020-07-21 05:50:04 +03:00
* return_count = 0 ;
return NT_STATUS_OK ;
}
2020-07-21 06:17:54 +03:00
ret_addrs = talloc_zero_array ( ctx ,
struct sockaddr_storage ,
numaddrs ) ;
if ( ret_addrs = = NULL ) {
2020-07-21 05:50:04 +03:00
TALLOC_FREE ( dcs ) ;
TALLOC_FREE ( srv_addrs ) ;
TALLOC_FREE ( dns_addrs ) ;
TALLOC_FREE ( dns_lookup_names ) ;
return NT_STATUS_NO_MEMORY ;
}
for ( i = 0 ; i < num_srv_addrs ; i + + ) {
2020-07-21 06:17:54 +03:00
ret_addrs [ i ] = srv_addrs [ i ] ;
2020-07-21 05:50:04 +03:00
}
for ( i = 0 ; i < num_dns_addrs ; i + + ) {
2020-07-29 02:51:03 +03:00
ret_addrs [ num_srv_addrs + i ] = dns_addrs [ i ] . u . ss ;
2020-07-21 05:50:04 +03:00
}
TALLOC_FREE ( dcs ) ;
TALLOC_FREE ( srv_addrs ) ;
TALLOC_FREE ( dns_addrs ) ;
TALLOC_FREE ( dns_lookup_names ) ;
2020-07-21 06:17:54 +03:00
* return_addrs = ret_addrs ;
2020-07-21 05:50:04 +03:00
* return_count = numaddrs ;
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
/*******************************************************************
2020-08-27 21:14:10 +03:00
Samba interface to resolve a name into an IP address .
1999-12-13 16:27:58 +03:00
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
2020-08-27 21:14:10 +03:00
NTSTATUS internal_resolve_name ( TALLOC_CTX * ctx ,
2020-08-27 05:05:28 +03:00
const char * name ,
2008-04-22 02:06:57 +04:00
int name_type ,
2007-10-25 01:16:54 +04:00
const char * sitename ,
struct ip_service * * return_iplist ,
2020-08-27 02:42:29 +03:00
size_t * 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 ;
2020-08-27 01:42:15 +03:00
size_t i ;
size_t nc_count = 0 ;
2020-08-27 01:54:49 +03:00
size_t ret_count = 0 ;
2020-07-21 03:02:15 +03:00
bool ok ;
2020-07-21 06:40:02 +03:00
struct sockaddr_storage * ss_list = NULL ;
2020-08-27 01:42:15 +03:00
struct samba_sockaddr * sa_list = NULL ;
2020-08-27 02:38:32 +03:00
struct ip_service * iplist = NULL ;
2020-08-26 23:59:14 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
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
2020-07-21 03:32:47 +03:00
DBG_DEBUG ( " looking up %s#%x (sitename %s) \n " ,
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 ) ) {
2020-08-27 01:26:54 +03:00
struct sockaddr_storage ss ;
2007-10-25 01:16:54 +04:00
/* if it's in the form of an IP address then get the lib to interpret it */
2020-08-27 01:26:54 +03:00
ok = interpret_string_addr ( & ss , name , AI_NUMERICHOST ) ;
2020-07-21 03:27:13 +03:00
if ( ! ok ) {
2020-07-21 03:32:47 +03:00
DBG_WARNING ( " interpret_string_addr failed on %s \n " ,
name ) ;
2020-08-26 23:59:14 +03:00
TALLOC_FREE ( frame ) ;
2007-10-25 01:16:54 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2003-02-18 00:19:00 +03:00
}
2020-08-27 01:26:54 +03:00
if ( is_zero_addr ( & ss ) ) {
2020-08-26 23:59:14 +03:00
TALLOC_FREE ( frame ) ;
2012-04-28 03:25:58 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2020-08-27 01:26:54 +03:00
2020-08-27 05:05:28 +03:00
iplist = talloc_zero_array ( frame ,
struct ip_service ,
1 ) ;
2020-08-27 01:26:54 +03:00
if ( iplist = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
iplist [ 0 ] . ss = ss ;
/* ignore the port here */
iplist [ 0 ] . port = PORT_NONE ;
2020-08-27 05:05:28 +03:00
* return_iplist = talloc_move ( ctx , & iplist ) ;
2004-07-02 05:09:10 +04:00
* return_count = 1 ;
2020-08-26 23:59:14 +03:00
TALLOC_FREE ( frame ) ;
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
2020-08-27 01:42:15 +03:00
ok = namecache_fetch ( frame ,
name ,
name_type ,
& sa_list ,
& nc_count ) ;
2020-08-27 01:20:22 +03:00
if ( ok ) {
2020-08-27 01:42:15 +03:00
/*
* Create a struct ip_service list from the
* returned samba_sockaddrs .
*/
size_t count = 0 ;
2020-08-27 05:05:28 +03:00
iplist = talloc_zero_array ( frame ,
struct ip_service ,
nc_count ) ;
2020-08-27 01:42:15 +03:00
if ( iplist = = NULL ) {
2020-08-26 23:59:14 +03:00
TALLOC_FREE ( frame ) ;
2020-08-27 01:42:15 +03:00
return NT_STATUS_NO_MEMORY ;
}
count = 0 ;
for ( i = 0 ; i < nc_count ; i + + ) {
if ( is_zero_addr ( & sa_list [ i ] . u . ss ) ) {
continue ;
}
iplist [ count ] . ss = sa_list [ i ] . u . ss ;
iplist [ count ] . port = 0 ;
count + + ;
}
count = remove_duplicate_addrs2 ( iplist , count ) ;
if ( count = = 0 ) {
2020-08-27 05:05:28 +03:00
TALLOC_FREE ( iplist ) ;
2020-08-26 23:59:14 +03:00
TALLOC_FREE ( frame ) ;
2007-08-28 18:20:53 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2020-08-27 02:42:29 +03:00
* return_count = count ;
2020-08-27 05:05:28 +03:00
* return_iplist = talloc_move ( ctx , & iplist ) ;
2020-08-27 01:42:15 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
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 ) {
2020-07-21 03:32:47 +03:00
DBG_DEBUG ( " all lookups disabled \n " ) ;
2020-08-26 23:59:14 +03:00
TALLOC_FREE ( frame ) ;
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
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 " ) ) ) {
2020-07-21 03:45:44 +03:00
status = resolve_hosts ( talloc_tos ( ) ,
name ,
2020-07-21 03:38:20 +03:00
name_type ,
& ss_list ,
2020-09-09 01:28:14 +03:00
& ret_count ) ;
2020-07-21 02:54:45 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
}
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 */
2020-07-21 03:59:20 +03:00
status = resolve_ads ( talloc_tos ( ) ,
name ,
2020-07-21 03:39:33 +03:00
KDC_NAME_TYPE ,
sitename ,
2020-07-21 06:17:54 +03:00
& ss_list ,
2020-09-09 01:28:14 +03:00
& ret_count ) ;
2020-07-21 02:56:14 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
2006-09-02 23:27:44 +04:00
}
2020-07-21 02:56:14 +03:00
/* Ensure we don't namecache
* this with the KDC port . */
name_type = KDC_NAME_TYPE ;
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 */
2020-07-21 03:59:20 +03:00
status = resolve_ads ( talloc_tos ( ) ,
name ,
2020-07-21 03:40:06 +03:00
name_type ,
sitename ,
2020-07-21 06:17:54 +03:00
& ss_list ,
2020-09-09 01:28:14 +03:00
& ret_count ) ;
2020-07-21 02:57:43 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
2006-08-29 04:56:08 +04:00
}
2020-07-21 02:57:43 +03:00
goto done ;
2015-05-13 09:53:43 +03:00
} else if ( strequal ( tok , " lmhosts " ) ) {
2015-12-15 23:52:38 +03:00
status = resolve_lmhosts_file_as_sockaddr (
2020-07-21 03:50:21 +03:00
talloc_tos ( ) ,
2020-07-21 03:42:44 +03:00
get_dyn_LMHOSTSFILE ( ) ,
name ,
name_type ,
& ss_list ,
2020-09-09 01:28:14 +03:00
& ret_count ) ;
2020-07-21 02:58:46 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
2004-07-02 05:09:10 +04:00
}
2020-07-21 02:58:46 +03:00
goto done ;
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 */
2020-07-21 02:59:38 +03:00
if ( name_type = = 0x1D ) {
continue ;
}
2020-07-21 03:53:28 +03:00
status = resolve_wins ( talloc_tos ( ) ,
name ,
2020-07-21 03:43:26 +03:00
name_type ,
2020-07-21 02:59:38 +03:00
& ss_list ,
2020-09-09 01:28:14 +03:00
& ret_count ) ;
2020-07-21 03:00:35 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
2006-08-29 04:56:08 +04:00
}
2020-07-21 03:00:35 +03:00
goto done ;
2015-05-13 09:53:43 +03:00
} else if ( strequal ( tok , " bcast " ) ) {
2011-04-30 21:23:55 +04:00
status = name_resolve_bcast (
2020-07-21 03:56:48 +03:00
talloc_tos ( ) ,
2020-07-21 03:44:03 +03:00
name ,
name_type ,
& ss_list ,
2020-09-09 01:28:14 +03:00
& ret_count ) ;
2020-07-21 03:01:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
}
goto done ;
2006-08-29 04:56:08 +04:00
} else {
2020-07-21 03:32:47 +03:00
DBG_ERR ( " 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
* return_count = 0 ;
2004-07-02 05:09:10 +04:00
2019-08-08 17:18:03 +03:00
return status ;
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
2020-08-27 01:54:49 +03:00
/*
* convert_ss2service ( ) leaves the correct
* count to return after removing zero addresses
* in ret_count .
*/
2020-08-27 05:05:28 +03:00
ok = convert_ss2service ( frame ,
& iplist ,
2020-08-27 01:54:49 +03:00
ss_list ,
2020-09-09 01:28:14 +03:00
ret_count ,
2020-08-27 01:54:49 +03:00
& ret_count ) ;
2020-07-21 06:52:58 +03:00
if ( ! ok ) {
2020-08-27 05:05:28 +03:00
TALLOC_FREE ( iplist ) ;
2020-07-21 06:52:58 +03:00
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
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
2020-08-27 02:38:32 +03:00
ret_count = remove_duplicate_addrs2 ( iplist , ret_count ) ;
2007-10-25 01:16:54 +04:00
2006-08-29 04:56:08 +04:00
/* Save in name cache */
if ( DEBUGLEVEL > = 100 ) {
2020-08-27 02:34:57 +03:00
for ( i = 0 ; i < ret_count & & DEBUGLEVEL = = 100 ; i + + ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
2020-08-27 02:38:32 +03:00
& iplist [ i ] . ss ) ;
2007-10-25 01:16:54 +04:00
DEBUG ( 100 , ( " Storing name %s of type %d (%s:%d) \n " ,
name ,
name_type ,
addr ,
2020-08-27 02:38:32 +03:00
iplist [ i ] . port ) ) ;
2007-10-25 01:16:54 +04:00
}
2006-08-29 04:56:08 +04:00
}
2007-10-25 01:16:54 +04:00
2020-08-27 02:34:57 +03:00
if ( ret_count ) {
2020-08-27 22:04:50 +03:00
/*
* Convert the ip_service list to a samba_sockaddr array
* to store in the namecache . This conversion
* will go away once ip_service is gone .
*/
struct samba_sockaddr * sa_converted_list = NULL ;
status = ip_service_to_samba_sockaddr ( talloc_tos ( ) ,
& sa_converted_list ,
iplist ,
ret_count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( iplist ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
2020-08-27 22:17:07 +03:00
namecache_store ( name ,
2020-08-27 22:04:50 +03:00
name_type ,
ret_count ,
sa_converted_list ) ;
TALLOC_FREE ( sa_converted_list ) ;
2012-04-28 03:25:58 +04:00
}
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 ) {
2020-08-27 02:34:57 +03:00
DBG_DEBUG ( " returning %zu addresses: " ,
ret_count ) ;
2002-01-09 07:26:41 +03:00
2020-08-27 02:34:57 +03:00
for ( i = 0 ; i < ret_count ; i + + ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
2020-08-27 02:38:32 +03:00
& iplist [ i ] . ss ) ;
2007-10-25 01:16:54 +04:00
DEBUGADD ( 10 , ( " %s:%d " ,
addr ,
2020-08-27 02:38:32 +03:00
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
2020-08-27 02:34:57 +03:00
* return_count = ret_count ;
2020-08-27 05:05:28 +03:00
* return_iplist = talloc_move ( ctx , & iplist ) ;
2020-08-27 02:34:57 +03: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 ;
2020-08-26 23:28:12 +03:00
size_t 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
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( frame ,
2020-08-26 23:28:12 +03:00
name ,
name_type ,
sitename ,
& ss_list ,
& count ,
lp_name_resolve_order ( ) ) ;
2011-09-12 22:56:13 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
2020-08-26 23:28:12 +03:00
size_t 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 + + ) {
2020-08-24 21:49:25 +03:00
struct samba_sockaddr sa = { 0 } ;
bool ok ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa ,
& ss_list [ i ] . ss ) ;
if ( ! ok ) {
2020-08-26 23:28:12 +03:00
TALLOC_FREE ( ss_list ) ;
2020-08-24 21:49:25 +03:00
TALLOC_FREE ( frame ) ;
return false ;
}
2020-08-27 21:33:20 +03:00
if ( ! is_broadcast_addr ( & sa . u . sa ) & &
2020-08-24 21:49:25 +03:00
( sa . u . ss . ss_family = = AF_INET ) ) {
2009-07-28 22:51:58 +04:00
* return_ss = ss_list [ i ] . ss ;
2020-08-26 23:28:12 +03:00
TALLOC_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 + + ) {
2020-08-24 21:49:25 +03:00
struct samba_sockaddr sa = { 0 } ;
bool ok ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa ,
& ss_list [ i ] . ss ) ;
if ( ! ok ) {
2020-08-26 23:28:12 +03:00
TALLOC_FREE ( ss_list ) ;
2020-08-24 21:49:25 +03:00
TALLOC_FREE ( frame ) ;
return false ;
}
2020-08-27 21:33:20 +03:00
if ( ! is_broadcast_addr ( & sa . u . sa ) ) {
2007-10-25 01:16:54 +04:00
* return_ss = ss_list [ i ] . ss ;
2020-08-26 23:28:12 +03:00
TALLOC_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
2020-08-26 23:28:12 +03:00
TALLOC_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 ;
2020-09-02 20:52:08 +03:00
size_t count = 0 ;
size_t i ;
unsigned int num_entries = 0 ;
struct sockaddr_storage * result_arr = NULL ;
2007-12-12 20:42:58 +03:00
NTSTATUS status ;
if ( is_ipaddress ( name ) ) {
2020-09-02 20:52:08 +03:00
result_arr = talloc ( ctx , struct sockaddr_storage ) ;
if ( result_arr = = NULL ) {
2007-12-12 20:42:58 +03:00
return NT_STATUS_NO_MEMORY ;
}
2020-09-02 20:52:08 +03:00
if ( ! interpret_string_addr ( result_arr , name , AI_NUMERICHOST ) ) {
TALLOC_FREE ( result_arr ) ;
2007-12-12 20:42:58 +03:00
return NT_STATUS_BAD_NETWORK_NAME ;
}
* p_num_entries = 1 ;
2020-09-02 20:52:08 +03:00
* return_ss_arr = result_arr ;
2007-12-12 20:42:58 +03:00
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
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( ctx ,
2020-08-26 23:30:02 +03:00
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 + + ) {
2020-08-26 22:41:27 +03:00
struct samba_sockaddr sa = { 0 } ;
bool ok ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa ,
& ss_list [ i ] . ss ) ;
if ( ! ok ) {
2020-08-27 19:49:05 +03:00
continue ;
2020-08-26 22:41:27 +03:00
}
if ( ! is_zero_addr ( & sa . u . ss ) & &
! is_broadcast_addr ( & sa . u . sa ) ) {
2007-12-12 20:42:58 +03:00
num_entries + + ;
}
}
if ( num_entries = = 0 ) {
2019-08-09 18:00:35 +03:00
status = NT_STATUS_BAD_NETWORK_NAME ;
goto done ;
2007-12-12 20:42:58 +03:00
}
2020-09-02 20:52:08 +03:00
result_arr = talloc_array ( ctx ,
2007-12-12 20:42:58 +03:00
struct sockaddr_storage ,
num_entries ) ;
2020-09-02 20:52:08 +03:00
if ( result_arr = = NULL ) {
2019-08-09 18:00:35 +03:00
status = NT_STATUS_NO_MEMORY ;
goto done ;
2007-12-12 20:42:58 +03:00
}
for ( i = 0 , num_entries = 0 ; i < count ; i + + ) {
2020-08-26 22:41:27 +03:00
struct samba_sockaddr sa = { 0 } ;
bool ok ;
ok = sockaddr_storage_to_samba_sockaddr ( & sa ,
& ss_list [ i ] . ss ) ;
if ( ! ok ) {
2020-08-27 19:49:05 +03:00
continue ;
2020-08-26 22:41:27 +03:00
}
if ( ! is_zero_addr ( & sa . u . ss ) & &
! is_broadcast_addr ( & sa . u . sa ) ) {
2020-09-02 20:52:08 +03:00
result_arr [ num_entries + + ] = ss_list [ i ] . ss ;
2007-12-12 20:42:58 +03:00
}
}
2020-08-27 19:49:05 +03:00
if ( num_entries = = 0 ) {
2020-09-02 20:52:08 +03:00
TALLOC_FREE ( result_arr ) ;
2020-08-27 19:49:05 +03:00
status = NT_STATUS_BAD_NETWORK_NAME ;
goto done ;
}
2007-12-12 20:42:58 +03:00
status = NT_STATUS_OK ;
* p_num_entries = num_entries ;
2020-09-02 20:52:08 +03:00
* return_ss_arr = result_arr ;
2019-08-09 18:00:35 +03:00
done :
2020-08-26 23:30:02 +03:00
TALLOC_FREE ( ss_list ) ;
2019-08-09 18:00:35 +03:00
return status ;
2007-12-12 20:42:58 +03:00
}
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 ;
2020-08-26 23:32:15 +03:00
size_t 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
}
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( talloc_tos ( ) ,
2020-08-26 23:32:15 +03:00
group ,
0x1D ,
NULL ,
& ip_list ,
& count ,
lp_name_resolve_order ( ) ) ;
2007-08-28 18:20:53 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
2007-10-25 01:16:54 +04:00
* master_ss = ip_list [ 0 ] . ss ;
2020-08-26 23:32:15 +03:00
TALLOC_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
2020-08-26 23:32:15 +03:00
TALLOC_FREE ( ip_list ) ;
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( talloc_tos ( ) ,
2020-08-26 23:32:15 +03:00
group ,
0x1B ,
NULL ,
& ip_list ,
& count ,
lp_name_resolve_order ( ) ) ;
2007-08-28 18:20:53 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
2007-10-25 01:16:54 +04:00
* master_ss = ip_list [ 0 ] . ss ;
2020-08-26 23:32:15 +03:00
TALLOC_FREE ( ip_list ) ;
2007-10-25 01:16:54 +04:00
return true ;
1999-12-13 16:27:58 +03:00
}
2020-08-26 23:32:15 +03:00
TALLOC_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 ;
2020-08-26 23:35:22 +03:00
size_t 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 ) {
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( talloc_tos ( ) ,
2020-08-26 23:35:22 +03:00
domain ,
0x1b ,
NULL ,
& ip_list ,
& count ,
ads_order ) ;
2007-08-28 18:27:48 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) | | count = = 0 ) {
2020-08-26 23:35:22 +03:00
TALLOC_FREE ( ip_list ) ;
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( talloc_tos ( ) ,
2020-08-26 23:35:22 +03:00
domain ,
0x1b ,
NULL ,
& ip_list ,
& count ,
lp_name_resolve_order ( ) ) ;
2007-08-28 18:27:48 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-08-26 23:35:22 +03:00
TALLOC_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 ) {
2020-08-26 23:35:22 +03:00
DBG_INFO ( " PDC has %zu IP addresses! \n " , count ) ;
2007-10-25 01:16:54 +04:00
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 ;
2020-08-26 23:35:22 +03:00
TALLOC_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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-08-26 22:31:53 +03:00
static NTSTATUS get_dc_list ( TALLOC_CTX * ctx ,
const char * domain ,
2007-10-25 01:16:54 +04:00
const char * sitename ,
struct ip_service * * ip_list ,
2020-08-26 22:13:08 +03:00
size_t * ret_count ,
2007-10-25 01:16:54 +04:00
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 ;
2019-03-18 11:41:57 +03:00
size_t num_addresses = 0 ;
2020-09-04 14:23:14 +03:00
size_t local_count = 0 ;
size_t i ;
2006-02-04 00:19:24 +03:00
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 ;
2020-08-26 23:41:15 +03:00
size_t auto_count = 0 ;
2007-08-28 18:20:53 +04:00
NTSTATUS status ;
2020-08-26 22:05:06 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2015-06-03 13:50:25 +03:00
int auto_name_type = 0x1C ;
2007-11-28 10:10:20 +03:00
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
2020-08-26 22:05:06 +03:00
saf_servername = saf_fetch ( frame , domain ) ;
2007-10-25 01:16:54 +04:00
if ( strequal ( domain , lp_workgroup ( ) ) | | strequal ( domain , lp_realm ( ) ) ) {
2020-08-26 22:05:06 +03:00
pserver = talloc_asprintf ( frame , " %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 {
2020-08-26 22:05:06 +03:00
pserver = talloc_asprintf ( frame , " %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 ;
2020-08-26 22:05:06 +03:00
while ( next_token_talloc ( frame , & p , & name , LIST_SEP ) ) {
2008-06-06 01:27:26 +04:00
if ( ! done_auto_lookup & & strequal ( name , " * " ) ) {
2020-08-26 22:07:18 +03:00
done_auto_lookup = true ;
2020-08-26 23:41:15 +03:00
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( frame ,
2020-08-26 23:41:15 +03:00
domain ,
auto_name_type ,
sitename ,
& auto_ip_list ,
& auto_count ,
resolve_order ) ;
2020-08-26 22:07:18 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
continue ;
2007-08-28 18:20:53 +04:00
}
2020-08-26 22:13:08 +03:00
/* Wrap check. */
if ( num_addresses + auto_count < num_addresses ) {
2020-08-26 23:41:15 +03:00
TALLOC_FREE ( auto_ip_list ) ;
2020-08-26 22:13:08 +03:00
status = NT_STATUS_INVALID_PARAMETER ;
goto out ;
}
2020-08-26 22:07:18 +03:00
num_addresses + = auto_count ;
2020-08-26 23:41:15 +03:00
DBG_DEBUG ( " Adding %zu DC's from auto lookup \n " ,
auto_count ) ;
2006-02-04 00:19:24 +03:00
} else {
2020-08-26 22:13:08 +03:00
/* Wrap check. */
if ( num_addresses + 1 < num_addresses ) {
2020-08-26 23:41:15 +03:00
TALLOC_FREE ( auto_ip_list ) ;
2020-08-26 22:13:08 +03:00
status = NT_STATUS_INVALID_PARAMETER ;
goto out ;
}
2006-02-04 00:19:24 +03:00
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 ) {
2020-08-26 23:41:15 +03:00
struct ip_service * dc_iplist = NULL ;
size_t dc_count = 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
}
2020-08-26 23:41:15 +03:00
/* talloc off frame, only move to ctx on success. */
2020-08-26 23:56:50 +03:00
status = internal_resolve_name ( frame ,
2020-08-26 23:41:15 +03:00
domain ,
auto_name_type ,
sitename ,
& dc_iplist ,
& dc_count ,
resolve_order ) ;
2020-09-09 04:19:07 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
2020-08-26 23:41:15 +03:00
}
2020-09-09 04:19:07 +03:00
return_iplist = talloc_move ( ctx , & dc_iplist ) ;
local_count = dc_count ;
2007-11-28 10:10:20 +03:00
goto out ;
2006-02-04 00:19:24 +03:00
}
2020-08-26 22:31:53 +03:00
return_iplist = talloc_zero_array ( ctx ,
struct ip_service ,
num_addresses ) ;
if ( return_iplist = = 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 ) & &
2020-08-26 22:05:06 +03:00
next_token_talloc ( frame , & p , & name , LIST_SEP ) ) {
2020-08-26 22:35:42 +03:00
struct samba_sockaddr name_sa = { 0 } ;
2007-10-25 01:16:54 +04:00
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 , " * " ) ) {
2020-08-26 23:41:15 +03:00
size_t j ;
2007-10-25 01:16:54 +04:00
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 */
2020-08-26 22:35:42 +03:00
if ( resolve_name ( name , & name_sa . u . ss , 0x20 , true ) ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2020-08-26 22:35:42 +03:00
bool ok ;
/*
* Ensure we set sa_socklen correctly .
* Doesn ' t matter now , but eventually we
* will remove ip_service and return samba_sockaddr
* arrays directly .
*/
ok = sockaddr_storage_to_samba_sockaddr (
& name_sa ,
& name_sa . u . ss ) ;
if ( ! ok ) {
status = NT_STATUS_INVALID_ADDRESS ;
goto out ;
}
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr ,
sizeof ( addr ) ,
2020-08-26 22:35:42 +03:00
& name_sa . u . 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
2020-08-26 22:35:42 +03:00
return_iplist [ local_count ] . ss = name_sa . u . 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 ) {
2019-03-18 11:41:57 +03:00
DEBUG ( 4 , ( " get_dc_list: returning %zu ip addresses "
2007-10-25 01:16:54 +04:00
" 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
2020-09-04 14:23:14 +03:00
status = ( local_count ! = 0 ? NT_STATUS_OK : NT_STATUS_NO_LOGON_SERVERS ) ;
2007-11-28 10:10:20 +03:00
out :
2020-09-04 14:23:14 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
* ip_list = return_iplist ;
* ret_count = local_count ;
} else {
2020-08-26 22:31:53 +03:00
TALLOC_FREE ( return_iplist ) ;
2008-06-06 01:27:26 +04:00
}
2020-08-26 22:31:53 +03:00
TALLOC_FREE ( auto_ip_list ) ;
2020-08-26 22:05:06 +03:00
TALLOC_FREE ( frame ) ;
2007-11-28 10:10:20 +03:00
return status ;
1998-10-04 15:25:06 +04:00
}
2004-02-08 03:54:32 +03:00
2020-08-26 21:47:44 +03:00
/*********************************************************************
Talloc version .
Small wrapper function to get the DC list and sort it if neccessary .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-08-26 22:03:31 +03:00
NTSTATUS get_sorted_dc_list ( TALLOC_CTX * ctx ,
2020-08-26 21:47:44 +03:00
const char * domain ,
const char * sitename ,
struct ip_service * * ip_list_ret ,
size_t * ret_count ,
bool ads_only )
{
bool ordered = false ;
NTSTATUS status ;
enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP ;
struct ip_service * ip_list = NULL ;
2020-08-26 22:13:08 +03:00
size_t count = 0 ;
2020-08-26 21:47:44 +03:00
DBG_INFO ( " attempting lookup for name %s (sitename %s) \n " ,
domain ,
sitename ? sitename : " NULL " ) ;
if ( ads_only ) {
lookup_type = DC_ADS_ONLY ;
}
2020-08-26 22:31:53 +03:00
status = get_dc_list ( ctx ,
domain ,
2020-08-26 21:47:44 +03:00
sitename ,
2020-08-26 22:31:53 +03:00
& ip_list ,
2020-08-26 21:47:44 +03:00
& count ,
lookup_type ,
& ordered ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NO_LOGON_SERVERS )
& & sitename ) {
DBG_NOTICE ( " no server for name %s available "
" in site %s, fallback to all servers \n " ,
domain ,
sitename ) ;
2020-08-26 22:31:53 +03:00
status = get_dc_list ( ctx ,
domain ,
2020-08-26 21:47:44 +03:00
NULL ,
2020-08-26 22:31:53 +03:00
& ip_list ,
2020-08-26 21:47:44 +03:00
& count ,
lookup_type ,
& ordered ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-08-26 22:31:53 +03:00
return status ;
2020-08-26 21:47:44 +03:00
}
/* only sort if we don't already have an ordered list */
if ( ! ordered ) {
2020-08-26 22:31:53 +03:00
sort_service_list ( ip_list , count ) ;
2020-08-26 21:47:44 +03:00
}
2020-08-26 22:13:08 +03:00
* ret_count = count ;
2020-08-26 21:47:44 +03:00
* ip_list_ret = ip_list ;
return status ;
}
2020-08-26 21:26:33 +03:00
/*********************************************************************
Talloc version .
Get the KDC list - re - use all the logic in get_dc_list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-08-26 21:43:32 +03:00
NTSTATUS get_kdc_list ( TALLOC_CTX * ctx ,
2020-08-26 21:26:33 +03:00
const char * realm ,
const char * sitename ,
struct ip_service * * ip_list_ret ,
size_t * ret_count )
{
2020-08-26 22:13:08 +03:00
size_t count = 0 ;
2020-08-26 21:26:33 +03:00
struct ip_service * ip_list = NULL ;
bool ordered = false ;
NTSTATUS status ;
2020-08-26 22:31:53 +03:00
status = get_dc_list ( ctx ,
realm ,
2020-08-26 21:26:33 +03:00
sitename ,
2020-08-26 22:31:53 +03:00
& ip_list ,
2020-08-26 21:26:33 +03:00
& count ,
DC_KDC_ONLY ,
& ordered ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-08-26 22:31:53 +03:00
return status ;
2020-08-26 21:26:33 +03:00
}
/* only sort if we don't already have an ordered list */
if ( ! ordered ) {
2020-08-26 22:31:53 +03:00
sort_service_list ( ip_list , count ) ;
2020-08-26 21:26:33 +03:00
}
2020-08-26 22:13:08 +03:00
* ret_count = count ;
2020-08-26 21:26:33 +03:00
* ip_list_ret = ip_list ;
return status ;
}