2010-03-09 15:29:43 +03:00
/*
Unix SMB / CIFS implementation .
read a file containing DNS names , types and IP addresses
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Jeremy Allison 2007
2011-04-26 03:49:08 +04:00
Copyright ( C ) Andrew Bartlett 2009 - 2011
2010-03-09 15:29:43 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/* The purpose of this file is to read the file generated by the samba_dnsupdate script */
# include "includes.h"
# include "lib/util/xfile.h"
# include "lib/util/util_net.h"
# include "system/filesys.h"
# include "system/network.h"
2011-03-19 02:45:56 +03:00
# include "libcli/nbt/libnbt.h"
2011-04-26 03:49:08 +04:00
# include "libcli/dns/dns.h"
# ifdef strcasecmp
# undef strcasecmp
# endif
2010-03-09 15:29:43 +03:00
/********************************************************
Start parsing the dns_hosts_file file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static XFILE * startdns_hosts_file ( const char * fname )
{
XFILE * fp = x_fopen ( fname , O_RDONLY , 0 ) ;
if ( ! fp ) {
DEBUG ( 4 , ( " startdns_hosts_file: Can't open dns_hosts_file file %s. "
" Error was %s \n " ,
fname , strerror ( errno ) ) ) ;
return NULL ;
}
return fp ;
}
/********************************************************
Parse the next line in the dns_hosts_file file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool getdns_hosts_fileent ( TALLOC_CTX * ctx , XFILE * fp , char * * pp_name , char * * pp_name_type ,
2011-04-26 03:49:08 +04:00
char * * pp_next_name ,
2010-03-09 15:29:43 +03:00
struct sockaddr_storage * pss , uint32_t * p_port )
{
char line [ 1024 ] ;
* pp_name = NULL ;
* pp_name_type = NULL ;
* pp_next_name = NULL ;
* p_port = 0 ;
while ( ! x_feof ( fp ) & & ! x_ferror ( fp ) ) {
char * name_type = NULL ;
char * name = NULL ;
char * next_name = NULL ;
char * ip = NULL ;
char * port = NULL ;
const char * ptr ;
int count = 0 ;
if ( ! fgets_slash ( line , sizeof ( line ) , fp ) ) {
continue ;
}
if ( * line = = ' # ' ) {
continue ;
}
ptr = line ;
if ( next_token_talloc ( ctx , & ptr , & name_type , NULL ) )
+ + count ;
if ( next_token_talloc ( ctx , & ptr , & name , NULL ) )
+ + count ;
2011-04-06 06:09:41 +04:00
if ( name_type & & strcasecmp ( name_type , " A " ) = = 0 ) {
2010-03-09 15:29:43 +03:00
if ( next_token_talloc ( ctx , & ptr , & ip , NULL ) )
+ + count ;
2011-04-06 06:09:41 +04:00
} else if ( name_type & & strcasecmp ( name_type , " SRV " ) = = 0 ) {
2010-03-09 15:29:43 +03:00
if ( next_token_talloc ( ctx , & ptr , & next_name , NULL ) )
+ + count ;
if ( next_token_talloc ( ctx , & ptr , & port , NULL ) )
+ + count ;
2011-04-06 06:09:41 +04:00
} else if ( name_type & & strcasecmp ( name_type , " CNAME " ) = = 0 ) {
2010-03-09 15:29:43 +03:00
if ( next_token_talloc ( ctx , & ptr , & next_name , NULL ) )
+ + count ;
}
if ( count < = 0 )
continue ;
if ( strcasecmp ( name_type , " A " ) = = 0 ) {
if ( count ! = 3 ) {
DEBUG ( 0 , ( " getdns_hosts_fileent: Ill formed hosts A record [%s] \n " ,
line ) ) ;
continue ;
}
DEBUG ( 4 , ( " getdns_hosts_fileent: host entry: %s %s %s \n " ,
name_type , name , ip ) ) ;
if ( ! interpret_string_addr ( pss , ip , AI_NUMERICHOST ) ) {
DEBUG ( 0 , ( " getdns_hosts_fileent: invalid address "
" %s. \n " , ip ) ) ;
}
} else if ( strcasecmp ( name_type , " SRV " ) = = 0 ) {
if ( count ! = 4 ) {
DEBUG ( 0 , ( " getdns_hosts_fileent: Ill formed hosts SRV record [%s] \n " ,
line ) ) ;
continue ;
}
* p_port = strtoul ( port , NULL , 10 ) ;
2010-03-30 21:08:57 +04:00
if ( * p_port = = UINT32_MAX ) {
2010-03-09 15:29:43 +03:00
DEBUG ( 0 , ( " getdns_hosts_fileent: Ill formed hosts SRV record [%s] (invalid port: %s) \n " ,
line , port ) ) ;
continue ;
}
DEBUG ( 4 , ( " getdns_hosts_fileent: host entry: %s %s %s %u \n " ,
name_type , name , next_name , ( unsigned int ) * p_port ) ) ;
* pp_next_name = talloc_strdup ( ctx , next_name ) ;
if ( ! * pp_next_name ) {
return false ;
}
} else if ( strcasecmp ( name_type , " CNAME " ) = = 0 ) {
if ( count ! = 3 ) {
DEBUG ( 0 , ( " getdns_hosts_fileent: Ill formed hosts CNAME record [%s] \n " ,
line ) ) ;
continue ;
}
DEBUG ( 4 , ( " getdns_hosts_fileent: host entry: %s %s %s \n " ,
name_type , name , next_name ) ) ;
* pp_next_name = talloc_strdup ( ctx , next_name ) ;
if ( ! * pp_next_name ) {
return false ;
}
} else {
DEBUG ( 0 , ( " getdns_hosts_fileent: unknown type %s \n " , name_type ) ) ;
continue ;
}
* pp_name = talloc_strdup ( ctx , name ) ;
if ( ! * pp_name ) {
return false ;
}
* pp_name_type = talloc_strdup ( ctx , name_type ) ;
if ( ! * pp_name_type ) {
return false ;
}
return true ;
}
return false ;
}
/********************************************************
Finish parsing the dns_hosts_file file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void enddns_hosts_file ( XFILE * fp )
{
x_fclose ( fp ) ;
}
/********************************************************
Resolve via " dns_hosts " method .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-04-26 03:49:08 +04:00
static NTSTATUS resolve_dns_hosts_file_as_dns_rr_recurse ( const char * dns_hosts_file ,
const char * name , bool srv_lookup ,
int level , uint32_t port ,
TALLOC_CTX * mem_ctx ,
struct dns_rr_srv * * return_rr ,
int * return_count )
2010-03-09 15:29:43 +03:00
{
/*
* " dns_hosts " means parse the local dns_hosts file .
*/
XFILE * fp ;
char * host_name = NULL ;
char * name_type = NULL ;
char * next_name = NULL ;
struct sockaddr_storage return_ss ;
uint32_t srv_port ;
NTSTATUS status = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
TALLOC_CTX * ctx = NULL ;
TALLOC_CTX * ip_list_ctx = NULL ;
2011-04-26 03:49:08 +04:00
struct dns_rr_srv * rr = NULL ;
* return_rr = NULL ;
2010-03-09 15:29:43 +03:00
/* Don't recurse forever, even on our own flat files */
if ( level > 11 ) {
2011-04-26 03:49:08 +04:00
DEBUG ( 0 , ( " resolve_dns_hosts_file recursion limit reached looking up %s! \n " , name ) ) ;
return status ;
2010-03-09 15:29:43 +03:00
}
* return_count = 0 ;
2011-04-26 03:49:08 +04:00
DEBUG ( 3 , ( " resolve_dns_hosts: (%d) "
" Attempting %s dns_hosts lookup for name %s \n " ,
level , srv_lookup ? " SRV " : " A " , name ) ) ;
2010-03-09 15:29:43 +03:00
fp = startdns_hosts_file ( dns_hosts_file ) ;
if ( fp = = NULL )
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
ip_list_ctx = talloc_new ( mem_ctx ) ;
if ( ! ip_list_ctx ) {
enddns_hosts_file ( fp ) ;
return NT_STATUS_NO_MEMORY ;
}
ctx = talloc_new ( ip_list_ctx ) ;
if ( ! ctx ) {
talloc_free ( ip_list_ctx ) ;
enddns_hosts_file ( fp ) ;
return NT_STATUS_NO_MEMORY ;
}
while ( getdns_hosts_fileent ( ctx , fp , & host_name , & name_type , & next_name , & return_ss , & srv_port ) ) {
if ( ! strequal ( name , host_name ) ) {
2011-04-26 03:49:08 +04:00
/* continue at the bottom of the loop */
} else if ( srv_lookup ) {
2010-03-09 15:29:43 +03:00
if ( strcasecmp ( name_type , " SRV " ) = = 0 ) {
2011-04-26 03:49:08 +04:00
NTSTATUS status_recurse ;
struct dns_rr_srv * tmp_rr ;
int tmp_count = 0 ;
2010-03-09 15:29:43 +03:00
/* we only accept one host name per SRV entry */
2011-04-26 03:49:08 +04:00
status_recurse
= resolve_dns_hosts_file_as_dns_rr_recurse ( dns_hosts_file , next_name ,
false ,
level + 1 , srv_port ,
ip_list_ctx , & tmp_rr ,
& tmp_count ) ;
if ( NT_STATUS_EQUAL ( status_recurse , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
/* Don't fail on a dangling SRV record */
} else if ( ! NT_STATUS_IS_OK ( status_recurse ) ) {
enddns_hosts_file ( fp ) ;
talloc_free ( ip_list_ctx ) ;
return status_recurse ;
} else if ( tmp_count ! = 1 ) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
} else {
status = status_recurse ;
rr = talloc_realloc ( ip_list_ctx , rr , struct dns_rr_srv , ( * return_count ) + 1 ) ;
if ( ! rr ) {
enddns_hosts_file ( fp ) ;
return NT_STATUS_NO_MEMORY ;
}
talloc_steal ( rr , tmp_rr ) ;
rr [ * return_count ] = * tmp_rr ;
* return_count = ( * return_count ) + 1 ;
}
2010-03-09 15:29:43 +03:00
}
} else if ( strcasecmp ( name_type , " CNAME " ) = = 0 ) {
/* we only accept one host name per CNAME */
enddns_hosts_file ( fp ) ;
2011-04-26 03:49:08 +04:00
status = resolve_dns_hosts_file_as_dns_rr_recurse ( dns_hosts_file , next_name , false ,
level + 1 , port ,
mem_ctx , return_rr , return_count ) ;
2010-03-09 15:29:43 +03:00
talloc_free ( ip_list_ctx ) ;
return status ;
} else if ( strcasecmp ( name_type , " A " ) = = 0 ) {
2011-04-26 03:49:08 +04:00
if ( * return_count = = 0 ) {
/* We are happy to keep looking for other possible A record matches */
rr = talloc_zero ( ip_list_ctx ,
struct dns_rr_srv ) ;
if ( rr = = NULL ) {
TALLOC_FREE ( ctx ) ;
enddns_hosts_file ( fp ) ;
DEBUG ( 3 , ( " resolve_dns_hosts: talloc_realloc fail ! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
rr - > hostname = talloc_strdup ( rr , host_name ) ;
if ( rr - > hostname = = NULL ) {
TALLOC_FREE ( ctx ) ;
enddns_hosts_file ( fp ) ;
DEBUG ( 3 , ( " resolve_dns_hosts: talloc_realloc fail ! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
rr - > port = port ;
* return_count = 1 ;
}
2010-03-09 15:29:43 +03:00
/* Set the specified port (possibly from a SRV lookup) into the structure we return */
set_sockaddr_port ( ( struct sockaddr * ) & return_ss , port ) ;
/* We are happy to keep looking for other possible A record matches */
2011-04-26 03:49:08 +04:00
rr - > ss_s = talloc_realloc ( rr , rr - > ss_s ,
struct sockaddr_storage ,
rr - > num_ips + 1 ) ;
2010-03-09 15:29:43 +03:00
2011-04-26 03:49:08 +04:00
if ( rr - > ss_s = = NULL ) {
2010-03-09 15:29:43 +03:00
TALLOC_FREE ( ctx ) ;
enddns_hosts_file ( fp ) ;
DEBUG ( 3 , ( " resolve_dns_hosts: talloc_realloc fail ! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
2011-04-26 03:49:08 +04:00
rr - > ss_s [ rr - > num_ips ] = return_ss ;
rr - > num_ips + = 1 ;
2010-03-09 15:29:43 +03:00
/* we found something */
status = NT_STATUS_OK ;
}
2011-04-26 03:49:08 +04:00
TALLOC_FREE ( ctx ) ;
ctx = talloc_new ( mem_ctx ) ;
if ( ! ctx ) {
enddns_hosts_file ( fp ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-03-09 15:29:43 +03:00
}
2011-04-26 03:49:08 +04:00
* return_rr = talloc_steal ( mem_ctx , rr ) ;
2010-03-09 15:29:43 +03:00
TALLOC_FREE ( ip_list_ctx ) ;
enddns_hosts_file ( fp ) ;
return status ;
}
/********************************************************
2011-04-26 03:49:08 +04:00
Resolve via " dns_hosts_file " method , returning a list of sockaddr_storage values
2010-03-09 15:29:43 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-04-26 03:49:08 +04:00
NTSTATUS resolve_dns_hosts_file_as_sockaddr ( const char * dns_hosts_file ,
2010-03-09 15:29:43 +03:00
const char * name , bool srv_lookup ,
2011-04-26 03:49:08 +04:00
TALLOC_CTX * mem_ctx ,
2010-03-09 15:29:43 +03:00
struct sockaddr_storage * * return_iplist ,
int * return_count )
{
2011-04-26 03:49:08 +04:00
NTSTATUS status ;
struct dns_rr_srv * dns_rr = NULL ;
int i , j , rr_count = 0 ;
* return_iplist = NULL ;
* return_count = 0 ;
status = resolve_dns_hosts_file_as_dns_rr_recurse ( dns_hosts_file , name , srv_lookup ,
0 , 0 ,
mem_ctx , & dns_rr , & rr_count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " resolve_dns_hosts (sockaddr): "
" failed to obtain %s result records for for name %s: %s \n " ,
srv_lookup ? " SRV " : " A " , name , nt_errstr ( status ) ) ) ;
return status ;
}
for ( i = 0 ; i < rr_count ; i + + ) {
* return_iplist = talloc_realloc ( mem_ctx , * return_iplist , struct sockaddr_storage , * return_count + dns_rr [ i ] . num_ips ) ;
if ( ! * return_iplist ) {
return NT_STATUS_NO_MEMORY ;
}
for ( j = 0 ; j < dns_rr [ i ] . num_ips ; j + + ) {
( * return_iplist ) [ * return_count ] = dns_rr [ i ] . ss_s [ j ] ;
* return_count = * return_count + 1 ;
}
}
DEBUG ( 3 , ( " resolve_dns_hosts (sockaddr): "
" Found %d results for for name %s \n " ,
* return_count , name ) ) ;
return NT_STATUS_OK ;
}
/********************************************************
Resolve via " dns_hosts_file " method , returning struct dns_rr_srv
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS resolve_dns_hosts_file_as_dns_rr ( const char * dns_hosts_file ,
const char * name , bool srv_lookup ,
TALLOC_CTX * mem_ctx ,
struct dns_rr_srv * * return_rr ,
int * return_count )
{
NTSTATUS status ;
* return_rr = NULL ;
* return_count = 0 ;
status = resolve_dns_hosts_file_as_dns_rr_recurse ( dns_hosts_file , name , srv_lookup ,
0 , 0 ,
mem_ctx , return_rr , return_count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " resolve_dns_hosts (dns_rr): "
" Found %d %s result records for for name %s \n " ,
* return_count , srv_lookup ? " SRV " : " A " , name ) ) ;
} else {
DEBUG ( 3 , ( " resolve_dns_hosts (dns_rr): "
" failed to obtain %s result records for for name %s: %s \n " ,
srv_lookup ? " SRV " : " A " , name , nt_errstr ( status ) ) ) ;
}
return status ;
2010-03-09 15:29:43 +03:00
}