2007-10-29 23:34:00 +03:00
/*
2006-05-05 23:24:48 +04:00
Unix SMB / CIFS implementation .
DNS utility library
Copyright ( C ) Gerald ( Jerry ) Carter 2006.
2007-10-29 23:34:00 +03:00
Copyright ( C ) Jeremy Allison 2007.
2006-05-05 23:24:48 +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
2006-05-05 23:24:48 +04:00
( at your option ) any later version .
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +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-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-05-05 23:24:48 +04:00
*/
# include "includes.h"
/* AIX resolv.h uses 'class' in struct ns_rr */
# if defined(AIX)
# if defined(class)
# undef class
# endif
# endif /* AIX */
/* resolver headers */
# include <sys/types.h>
# include <netinet/in.h>
# include <arpa/nameser.h>
# include <resolv.h>
# include <netdb.h>
# define MAX_DNS_PACKET_SIZE 0xffff
2006-05-06 01:19:25 +04:00
# ifdef NS_HFIXEDSZ /* Bind 8/9 interface */
2006-07-11 22:01:26 +04:00
# if !defined(C_IN) /* AIX 5.3 already defines C_IN */
2006-05-06 01:19:25 +04:00
# define C_IN ns_c_in
2006-07-11 22:01:26 +04:00
# endif
# if !defined(T_A) /* AIX 5.3 already defines T_A */
2006-05-06 01:19:25 +04:00
# define T_A ns_t_a
2006-07-11 22:01:26 +04:00
# endif
2007-10-29 23:34:00 +03:00
# if defined(HAVE_IPV6)
# if !defined(T_AAAA)
# define T_AAAA ns_t_aaaa
# endif
# endif
2006-05-06 01:19:25 +04:00
# define T_SRV ns_t_srv
2006-09-13 17:02:51 +04:00
# if !defined(T_NS) /* AIX 5.3 already defines T_NS */
2006-07-20 00:53:10 +04:00
# define T_NS ns_t_ns
2006-09-13 17:02:51 +04:00
# endif
2006-05-06 01:19:25 +04:00
# else
2006-05-06 00:18:50 +04:00
# ifdef HFIXEDSZ
# define NS_HFIXEDSZ HFIXEDSZ
# else
2006-05-06 01:19:25 +04:00
# define NS_HFIXEDSZ sizeof(HEADER)
2006-05-12 20:38:51 +04:00
# endif /* HFIXEDSZ */
# ifdef PACKETSZ
# define NS_PACKETSZ PACKETSZ
# else /* 512 is usually the default */
# define NS_PACKETSZ 512
# endif /* PACKETSZ */
2006-05-06 01:19:25 +04:00
# define T_SRV 33
2006-05-06 00:18:50 +04:00
# endif
2006-05-05 23:24:48 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_query ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-05-05 23:24:48 +04:00
uint8 * * ptr , struct dns_query * q )
{
uint8 * p = * ptr ;
2007-11-16 05:27:26 +03:00
char hostname [ MAX_DNS_NAME_LENGTH ] ;
2006-05-05 23:24:48 +04:00
int namelen ;
ZERO_STRUCTP ( q ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
if ( ! start | | ! end | | ! q | | ! * ptr )
return False ;
/* See RFC 1035 for details. If this fails, then return. */
namelen = dn_expand ( start , end , p , hostname , sizeof ( hostname ) ) ;
if ( namelen < 0 ) {
return False ;
}
p + = namelen ;
q - > hostname = talloc_strdup ( ctx , hostname ) ;
/* check that we have space remaining */
if ( PTR_DIFF ( p + 4 , end ) > 0 )
return False ;
q - > type = RSVAL ( p , 0 ) ;
q - > in_class = RSVAL ( p , 2 ) ;
p + = 4 ;
* ptr = p ;
return True ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_rr ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-05-05 23:24:48 +04:00
uint8 * * ptr , struct dns_rr * rr )
{
uint8 * p = * ptr ;
2007-11-16 05:27:26 +03:00
char hostname [ MAX_DNS_NAME_LENGTH ] ;
2006-05-05 23:24:48 +04:00
int namelen ;
if ( ! start | | ! end | | ! rr | | ! * ptr )
return - 1 ;
ZERO_STRUCTP ( rr ) ;
/* pull the name from the answer */
namelen = dn_expand ( start , end , p , hostname , sizeof ( hostname ) ) ;
if ( namelen < 0 ) {
return - 1 ;
}
p + = namelen ;
rr - > hostname = talloc_strdup ( ctx , hostname ) ;
/* check that we have space remaining */
if ( PTR_DIFF ( p + 10 , end ) > 0 )
return False ;
/* pull some values and then skip onto the string */
rr - > type = RSVAL ( p , 0 ) ;
rr - > in_class = RSVAL ( p , 2 ) ;
rr - > ttl = RIVAL ( p , 4 ) ;
rr - > rdatalen = RSVAL ( p , 8 ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
p + = 10 ;
/* sanity check the available space */
if ( PTR_DIFF ( p + rr - > rdatalen , end ) > 0 ) {
return False ;
}
/* save a point to the rdata for this section */
rr - > rdata = p ;
p + = rr - > rdatalen ;
* ptr = p ;
return True ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_rr_srv ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-05-05 23:24:48 +04:00
uint8 * * ptr , struct dns_rr_srv * srv )
{
struct dns_rr rr ;
uint8 * p ;
2007-11-16 05:27:26 +03:00
char dcname [ MAX_DNS_NAME_LENGTH ] ;
2006-05-05 23:24:48 +04:00
int namelen ;
if ( ! start | | ! end | | ! srv | | ! * ptr )
return - 1 ;
2007-10-29 23:34:00 +03:00
/* Parse the RR entry. Coming out of the this, ptr is at the beginning
2006-05-05 23:24:48 +04:00
of the next record */
if ( ! ads_dns_parse_rr ( ctx , start , end , ptr , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_srv: Failed to parse RR record \n " ) ) ;
return False ;
}
2006-05-06 01:19:25 +04:00
if ( rr . type ! = T_SRV ) {
2007-10-29 23:34:00 +03:00
DEBUG ( 1 , ( " ads_dns_parse_rr_srv: Bad answer type (%d) \n " ,
rr . type ) ) ;
2006-05-05 23:24:48 +04:00
return False ;
}
p = rr . rdata ;
srv - > priority = RSVAL ( p , 0 ) ;
srv - > weight = RSVAL ( p , 2 ) ;
srv - > port = RSVAL ( p , 4 ) ;
p + = 6 ;
namelen = dn_expand ( start , end , p , dcname , sizeof ( dcname ) ) ;
if ( namelen < 0 ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_srv: Failed to uncompress name! \n " ) ) ;
return False ;
}
2008-04-30 18:57:15 +04:00
2006-05-05 23:24:48 +04:00
srv - > hostname = talloc_strdup ( ctx , dcname ) ;
2008-04-30 18:57:15 +04:00
DEBUG ( 10 , ( " ads_dns_parse_rr_srv: Parsed %s [%u, %u, %u] \n " ,
srv - > hostname ,
srv - > priority ,
srv - > weight ,
srv - > port ) ) ;
2006-05-05 23:24:48 +04:00
return True ;
}
2006-07-20 00:53:10 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool ads_dns_parse_rr_ns ( TALLOC_CTX * ctx , uint8 * start , uint8 * end ,
2006-07-20 00:53:10 +04:00
uint8 * * ptr , struct dns_rr_ns * nsrec )
{
struct dns_rr rr ;
uint8 * p ;
2007-11-16 05:27:26 +03:00
char nsname [ MAX_DNS_NAME_LENGTH ] ;
2006-07-20 00:53:10 +04:00
int namelen ;
if ( ! start | | ! end | | ! nsrec | | ! * ptr )
return - 1 ;
2007-10-29 23:34:00 +03:00
/* Parse the RR entry. Coming out of the this, ptr is at the beginning
2006-07-20 00:53:10 +04:00
of the next record */
if ( ! ads_dns_parse_rr ( ctx , start , end , ptr , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_ns: Failed to parse RR record \n " ) ) ;
return False ;
}
if ( rr . type ! = T_NS ) {
2007-10-29 23:34:00 +03:00
DEBUG ( 1 , ( " ads_dns_parse_rr_ns: Bad answer type (%d) \n " ,
rr . type ) ) ;
2006-07-20 00:53:10 +04:00
return False ;
}
p = rr . rdata ;
/* ame server hostname */
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
namelen = dn_expand ( start , end , p , nsname , sizeof ( nsname ) ) ;
if ( namelen < 0 ) {
DEBUG ( 1 , ( " ads_dns_parse_rr_ns: Failed to uncompress name! \n " ) ) ;
return False ;
}
nsrec - > hostname = talloc_strdup ( ctx , nsname ) ;
return True ;
}
2006-05-05 23:24:48 +04:00
/*********************************************************************
Sort SRV record list based on weight and priority . See RFC 2782.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int dnssrvcmp ( struct dns_rr_srv * a , struct dns_rr_srv * b )
{
if ( a - > priority = = b - > priority ) {
/* randomize entries with an equal weight and priority */
2007-10-29 23:34:00 +03:00
if ( a - > weight = = b - > weight )
2006-07-25 23:59:35 +04:00
return 0 ;
2006-05-05 23:24:48 +04:00
2007-10-29 23:34:00 +03:00
/* higher weights should be sorted lower */
2006-05-05 23:24:48 +04:00
if ( a - > weight > b - > weight )
return - 1 ;
else
return 1 ;
}
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
if ( a - > priority < b - > priority )
return - 1 ;
return 1 ;
}
/*********************************************************************
2006-07-20 00:53:10 +04:00
Simple wrapper for a DNS query
2006-05-05 23:24:48 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-07 01:06:55 +04:00
# define DNS_FAILED_WAITTIME 30
2007-10-29 23:34:00 +03:00
static NTSTATUS dns_send_req ( TALLOC_CTX * ctx , const char * name , int q_type ,
2006-07-20 00:53:10 +04:00
uint8 * * buf , int * resp_length )
2006-05-05 23:24:48 +04:00
{
uint8 * buffer = NULL ;
2008-04-30 18:57:15 +04:00
size_t buf_len = 0 ;
2007-10-29 23:34:00 +03:00
int resp_len = NS_PACKETSZ ;
2007-05-07 01:06:55 +04:00
static time_t last_dns_check = 0 ;
2007-10-29 23:34:00 +03:00
static NTSTATUS last_dns_status = NT_STATUS_OK ;
2007-05-07 01:06:55 +04:00
time_t now = time ( NULL ) ;
/* Try to prevent bursts of DNS lookups if the server is down */
/* Protect against large clock changes */
if ( last_dns_check > now )
last_dns_check = 0 ;
2007-10-29 23:34:00 +03:00
/* IF we had a DNS timeout or a bad server and we are still
in the 30 second cache window , just return the previous
2007-05-07 01:06:55 +04:00
status and save the network timeout . */
if ( ( NT_STATUS_EQUAL ( last_dns_status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( last_dns_status , NT_STATUS_CONNECTION_REFUSED ) ) & &
2007-10-29 23:34:00 +03:00
( last_dns_check + DNS_FAILED_WAITTIME ) > now )
2007-05-07 01:06:55 +04:00
{
DEBUG ( 10 , ( " last_dns_check: Returning cached status (%s) \n " ,
nt_errstr ( last_dns_status ) ) ) ;
return last_dns_status ;
}
/* Send the Query */
2006-05-05 23:24:48 +04:00
do {
if ( buffer )
TALLOC_FREE ( buffer ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
buf_len = resp_len * sizeof ( uint8 ) ;
2007-10-29 23:34:00 +03:00
if ( buf_len ) {
if ( ( buffer = TALLOC_ARRAY ( ctx , uint8 , buf_len ) )
= = NULL ) {
DEBUG ( 0 , ( " ads_dns_lookup_srv: "
" talloc() failed! \n " ) ) ;
2007-05-07 01:06:55 +04:00
last_dns_status = NT_STATUS_NO_MEMORY ;
last_dns_check = time ( NULL ) ;
2007-10-29 23:34:00 +03:00
return last_dns_status ;
2007-04-30 06:39:34 +04:00
}
2006-05-05 23:24:48 +04:00
}
2007-10-29 23:34:00 +03:00
if ( ( resp_len = res_query ( name , C_IN , q_type , buffer , buf_len ) )
< 0 ) {
DEBUG ( 3 , ( " ads_dns_lookup_srv: "
" Failed to resolve %s (%s) \n " ,
name , strerror ( errno ) ) ) ;
2006-05-05 23:24:48 +04:00
TALLOC_FREE ( buffer ) ;
2007-05-07 01:06:55 +04:00
last_dns_status = NT_STATUS_UNSUCCESSFUL ;
2007-10-29 23:34:00 +03:00
2007-01-17 22:20:11 +03:00
if ( errno = = ETIMEDOUT ) {
2007-10-29 23:34:00 +03:00
last_dns_status = NT_STATUS_IO_TIMEOUT ;
2007-01-17 22:20:11 +03:00
}
if ( errno = = ECONNREFUSED ) {
2007-10-29 23:34:00 +03:00
last_dns_status = NT_STATUS_CONNECTION_REFUSED ;
2007-01-17 22:20:11 +03:00
}
2007-05-07 01:06:55 +04:00
last_dns_check = time ( NULL ) ;
return last_dns_status ;
2006-05-05 23:24:48 +04:00
}
2008-04-30 18:57:15 +04:00
/* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8)
truncated replies never give back a resp_len > buflen
which ends up causing DNS resolve failures on large tcp DNS replies */
if ( buf_len = = resp_len ) {
if ( resp_len = = MAX_DNS_PACKET_SIZE ) {
DEBUG ( 1 , ( " dns_send_req: DNS reply too large when resolving %s \n " ,
name ) ) ;
TALLOC_FREE ( buffer ) ;
last_dns_status = NT_STATUS_BUFFER_TOO_SMALL ;
last_dns_check = time ( NULL ) ;
return last_dns_status ;
}
resp_len = MIN ( resp_len * 2 , MAX_DNS_PACKET_SIZE ) ;
}
} while ( buf_len < resp_len & & resp_len < = MAX_DNS_PACKET_SIZE ) ;
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
* buf = buffer ;
* resp_length = resp_len ;
2007-05-07 01:06:55 +04:00
last_dns_check = time ( NULL ) ;
2007-10-29 23:34:00 +03:00
last_dns_status = NT_STATUS_OK ;
2007-05-07 01:06:55 +04:00
return last_dns_status ;
2006-07-20 00:53:10 +04:00
}
/*********************************************************************
Simple wrapper for a DNS SRV query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-29 23:34:00 +03:00
static NTSTATUS ads_dns_lookup_srv ( TALLOC_CTX * ctx ,
const char * name ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-07-20 00:53:10 +04:00
{
uint8 * buffer = NULL ;
int resp_len = 0 ;
struct dns_rr_srv * dcs = NULL ;
int query_count , answer_count , auth_count , additional_count ;
uint8 * p = buffer ;
int rrnum ;
int idx = 0 ;
NTSTATUS status ;
if ( ! ctx | | ! name | | ! dclist ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-10-29 23:34:00 +03:00
/* Send the request. May have to loop several times in case
2006-07-20 00:53:10 +04:00
of large replies */
2006-05-05 23:24:48 +04:00
2006-07-20 00:53:10 +04:00
status = dns_send_req ( ctx , name , T_SRV , & buffer , & resp_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-09-08 01:08:29 +04:00
DEBUG ( 3 , ( " ads_dns_lookup_srv: Failed to send DNS query (%s) \n " ,
2006-07-20 00:53:10 +04:00
nt_errstr ( status ) ) ) ;
return status ;
}
2006-05-05 23:24:48 +04:00
p = buffer ;
/* For some insane reason, the ns_initparse() et. al. routines are only
available in libresolv . a , and not the shared lib . Who knows why . . . .
So we have to parse the DNS reply ourselves */
2007-10-29 23:34:00 +03:00
/* Pull the answer RR's count from the header.
* Use the NMB ordering macros */
2006-05-05 23:24:48 +04:00
query_count = RSVAL ( p , 4 ) ;
answer_count = RSVAL ( p , 6 ) ;
auth_count = RSVAL ( p , 8 ) ;
additional_count = RSVAL ( p , 10 ) ;
2007-10-29 23:34:00 +03:00
DEBUG ( 4 , ( " ads_dns_lookup_srv: "
" %d records returned in the answer section. \n " ,
2006-05-05 23:24:48 +04:00
answer_count ) ) ;
2007-10-29 23:34:00 +03:00
2007-04-30 06:51:26 +04:00
if ( answer_count ) {
2007-10-29 23:34:00 +03:00
if ( ( dcs = TALLOC_ZERO_ARRAY ( ctx , struct dns_rr_srv ,
answer_count ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_dns_lookup_srv: "
" talloc() failure for %d char*'s \n " ,
2007-04-30 06:51:26 +04:00
answer_count ) ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
dcs = NULL ;
2006-05-05 23:24:48 +04:00
}
/* now skip the header */
p + = NS_HFIXEDSZ ;
/* parse the query section */
for ( rrnum = 0 ; rrnum < query_count ; rrnum + + ) {
struct dns_query q ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_query ( ctx , buffer ,
buffer + resp_len , & p , & q ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: "
2008-04-30 18:57:15 +04:00
" Failed to parse query record [%d]! \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* now we are at the answer section */
for ( rrnum = 0 ; rrnum < answer_count ; rrnum + + ) {
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr_srv ( ctx , buffer , buffer + resp_len ,
& p , & dcs [ rrnum ] ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: "
2008-04-30 18:57:15 +04:00
" Failed to parse answer recordi [%d]! \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2007-10-29 23:34:00 +03:00
}
2006-05-05 23:24:48 +04:00
}
idx = rrnum ;
/* Parse the authority section */
/* just skip these for now */
for ( rrnum = 0 ; rrnum < auth_count ; rrnum + + ) {
struct dns_rr rr ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer ,
buffer + resp_len , & p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: "
2008-04-30 18:57:15 +04:00
" Failed to parse authority record! [%d] \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* Parse the additional records section */
for ( rrnum = 0 ; rrnum < additional_count ; rrnum + + ) {
struct dns_rr rr ;
int i ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer , buffer + resp_len ,
& p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_srv: Failed "
2008-04-30 18:57:15 +04:00
" to parse additional records section! [%d] \n " , rrnum ) ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2007-10-29 23:34:00 +03:00
/* Only interested in A or AAAA records as a shortcut for having
* to come back later and lookup the name . For multi - homed
* hosts , the number of additional records and exceed the
* number of answer records . */
if ( rr . type ! = T_A | | rr . rdatalen ! = 4 ) {
# if defined(HAVE_IPV6)
2009-09-23 16:40:25 +04:00
/* RFC2874 defines A6 records. This
2007-10-29 23:34:00 +03:00
* requires recusive and horribly complex lookups .
* Bastards . Ignore this for now . . . . JRA .
2009-09-23 16:40:25 +04:00
* Luckily RFC3363 reprecates A6 records .
2007-10-29 23:34:00 +03:00
*/
if ( rr . type ! = T_AAAA | | rr . rdatalen ! = 16 )
# endif
continue ;
}
2006-05-05 23:24:48 +04:00
for ( i = 0 ; i < idx ; i + + ) {
if ( strcmp ( rr . hostname , dcs [ i ] . hostname ) = = 0 ) {
2006-08-24 16:13:57 +04:00
int num_ips = dcs [ i ] . num_ips ;
2007-10-29 23:34:00 +03:00
struct sockaddr_storage * tmp_ss_s ;
2006-08-24 16:13:57 +04:00
/* allocate new memory */
2007-10-29 23:34:00 +03:00
if ( dcs [ i ] . num_ips = = 0 ) {
if ( ( dcs [ i ] . ss_s = TALLOC_ARRAY ( dcs ,
struct sockaddr_storage , 1 ) )
= = NULL ) {
2006-08-24 16:13:57 +04:00
return NT_STATUS_NO_MEMORY ;
}
} else {
2007-10-29 23:34:00 +03:00
if ( ( tmp_ss_s = TALLOC_REALLOC_ARRAY ( dcs ,
dcs [ i ] . ss_s ,
struct sockaddr_storage ,
dcs [ i ] . num_ips + 1 ) )
= = NULL ) {
2006-08-24 16:13:57 +04:00
return NT_STATUS_NO_MEMORY ;
}
2007-10-29 23:34:00 +03:00
dcs [ i ] . ss_s = tmp_ss_s ;
2006-08-24 16:13:57 +04:00
}
dcs [ i ] . num_ips + + ;
2007-10-29 23:34:00 +03:00
2006-08-24 16:13:57 +04:00
/* copy the new IP address */
2007-10-29 23:34:00 +03:00
if ( rr . type = = T_A ) {
struct in_addr ip ;
memcpy ( & ip , rr . rdata , 4 ) ;
in_addr_to_sockaddr_storage (
& dcs [ i ] . ss_s [ num_ips ] ,
ip ) ;
}
# if defined(HAVE_IPV6)
if ( rr . type = = T_AAAA ) {
struct in6_addr ip6 ;
memcpy ( & ip6 , rr . rdata , rr . rdatalen ) ;
in6_addr_to_sockaddr_storage (
& dcs [ i ] . ss_s [ num_ips ] ,
ip6 ) ;
}
# endif
2006-05-05 23:24:48 +04:00
}
}
}
qsort ( dcs , idx , sizeof ( struct dns_rr_srv ) , QSORT_CAST dnssrvcmp ) ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
* dclist = dcs ;
* numdcs = idx ;
2007-10-29 23:34:00 +03:00
2006-05-05 23:24:48 +04:00
return NT_STATUS_OK ;
}
2006-07-20 00:53:10 +04:00
/*********************************************************************
Simple wrapper for a DNS NS query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-29 23:34:00 +03:00
NTSTATUS ads_dns_lookup_ns ( TALLOC_CTX * ctx ,
const char * dnsdomain ,
struct dns_rr_ns * * nslist ,
int * numns )
2006-07-20 00:53:10 +04:00
{
uint8 * buffer = NULL ;
int resp_len = 0 ;
struct dns_rr_ns * nsarray = NULL ;
int query_count , answer_count , auth_count , additional_count ;
uint8 * p ;
int rrnum ;
int idx = 0 ;
NTSTATUS status ;
if ( ! ctx | | ! dnsdomain | | ! nslist ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-10-29 23:34:00 +03:00
/* Send the request. May have to loop several times in case
2006-07-20 00:53:10 +04:00
of large replies */
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
status = dns_send_req ( ctx , dnsdomain , T_NS , & buffer , & resp_len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-09-08 01:08:29 +04:00
DEBUG ( 3 , ( " ads_dns_lookup_ns: Failed to send DNS query (%s) \n " ,
2006-07-20 00:53:10 +04:00
nt_errstr ( status ) ) ) ;
return status ;
}
p = buffer ;
/* For some insane reason, the ns_initparse() et. al. routines are only
available in libresolv . a , and not the shared lib . Who knows why . . . .
So we have to parse the DNS reply ourselves */
2007-10-29 23:34:00 +03:00
/* Pull the answer RR's count from the header.
* Use the NMB ordering macros */
2006-07-20 00:53:10 +04:00
query_count = RSVAL ( p , 4 ) ;
answer_count = RSVAL ( p , 6 ) ;
auth_count = RSVAL ( p , 8 ) ;
additional_count = RSVAL ( p , 10 ) ;
2007-10-29 23:34:00 +03:00
DEBUG ( 4 , ( " ads_dns_lookup_ns: "
" %d records returned in the answer section. \n " ,
2006-07-20 00:53:10 +04:00
answer_count ) ) ;
2007-10-29 23:34:00 +03:00
2007-04-30 06:39:34 +04:00
if ( answer_count ) {
2007-10-29 23:34:00 +03:00
if ( ( nsarray = TALLOC_ARRAY ( ctx , struct dns_rr_ns ,
answer_count ) ) = = NULL ) {
DEBUG ( 0 , ( " ads_dns_lookup_ns: "
" talloc() failure for %d char*'s \n " ,
2007-04-30 06:39:34 +04:00
answer_count ) ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
nsarray = NULL ;
2006-07-20 00:53:10 +04:00
}
/* now skip the header */
p + = NS_HFIXEDSZ ;
/* parse the query section */
for ( rrnum = 0 ; rrnum < query_count ; rrnum + + ) {
struct dns_query q ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_query ( ctx , buffer , buffer + resp_len ,
& p , & q ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: "
" Failed to parse query record! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* now we are at the answer section */
for ( rrnum = 0 ; rrnum < answer_count ; rrnum + + ) {
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr_ns ( ctx , buffer , buffer + resp_len ,
& p , & nsarray [ rrnum ] ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: "
" Failed to parse answer record! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
2007-10-29 23:34:00 +03:00
}
2006-07-20 00:53:10 +04:00
}
idx = rrnum ;
/* Parse the authority section */
/* just skip these for now */
for ( rrnum = 0 ; rrnum < auth_count ; rrnum + + ) {
struct dns_rr rr ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer , buffer + resp_len ,
& p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: "
" Failed to parse authority record! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
}
/* Parse the additional records section */
for ( rrnum = 0 ; rrnum < additional_count ; rrnum + + ) {
struct dns_rr rr ;
int i ;
2007-10-29 23:34:00 +03:00
if ( ! ads_dns_parse_rr ( ctx , buffer , buffer + resp_len ,
& p , & rr ) ) {
DEBUG ( 1 , ( " ads_dns_lookup_ns: Failed "
" to parse additional records section! \n " ) ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2007-10-29 23:34:00 +03:00
/* only interested in A records as a shortcut for having to come
2006-07-20 00:53:10 +04:00
back later and lookup the name */
2007-10-29 23:34:00 +03:00
if ( rr . type ! = T_A | | rr . rdatalen ! = 4 ) {
# if defined(HAVE_IPV6)
if ( rr . type ! = T_AAAA | | rr . rdatalen ! = 16 )
# endif
continue ;
}
2006-07-20 00:53:10 +04:00
for ( i = 0 ; i < idx ; i + + ) {
2007-10-29 23:34:00 +03:00
if ( strcmp ( rr . hostname , nsarray [ i ] . hostname ) = = 0 ) {
if ( rr . type = = T_A ) {
struct in_addr ip ;
memcpy ( & ip , rr . rdata , 4 ) ;
in_addr_to_sockaddr_storage (
& nsarray [ i ] . ss ,
ip ) ;
}
# if defined(HAVE_IPV6)
if ( rr . type = = T_AAAA ) {
struct in6_addr ip6 ;
memcpy ( & ip6 , rr . rdata , rr . rdatalen ) ;
in6_addr_to_sockaddr_storage (
& nsarray [ i ] . ss ,
ip6 ) ;
}
# endif
2006-07-20 00:53:10 +04:00
}
}
}
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
* nslist = nsarray ;
* numns = idx ;
2007-10-29 23:34:00 +03:00
2006-07-20 00:53:10 +04:00
return NT_STATUS_OK ;
}
2006-08-30 08:40:03 +04:00
/****************************************************************************
Store and fetch the AD client sitename .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-20 00:53:10 +04:00
2007-01-18 12:58:57 +03:00
# define SITENAME_KEY "AD_SITENAME / DOMAIN / %s"
static char * sitename_key ( const char * realm )
{
char * keystr ;
2007-10-29 23:34:00 +03:00
2007-11-24 19:27:54 +03:00
if ( asprintf_strupper_m ( & keystr , SITENAME_KEY , realm ) = = - 1 ) {
2007-01-18 12:58:57 +03:00
return NULL ;
}
return keystr ;
}
2006-08-30 08:40:03 +04:00
/****************************************************************************
Store the AD client sitename .
We store indefinately as every new CLDAP query will re - write this .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-05-05 23:24:48 +04:00
2007-10-19 04:40:25 +04:00
bool sitename_store ( const char * realm , const char * sitename )
2006-05-05 23:24:48 +04:00
{
2006-08-30 08:40:03 +04:00
time_t expire ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-01-18 12:58:57 +03:00
char * key ;
2006-08-31 04:07:24 +04:00
2007-01-18 12:58:57 +03:00
if ( ! realm | | ( strlen ( realm ) = = 0 ) ) {
2007-06-29 15:54:29 +04:00
DEBUG ( 0 , ( " sitename_store: no realm \n " ) ) ;
2007-01-18 12:58:57 +03:00
return False ;
}
2007-10-29 23:34:00 +03:00
2007-01-18 12:58:57 +03:00
key = sitename_key ( realm ) ;
2006-08-31 04:07:24 +04:00
if ( ! sitename | | ( sitename & & ! * sitename ) ) {
DEBUG ( 5 , ( " sitename_store: deleting empty sitename! \n " ) ) ;
2007-01-18 22:18:43 +03:00
ret = gencache_del ( key ) ;
2007-01-18 12:58:57 +03:00
SAFE_FREE ( key ) ;
return ret ;
2006-08-31 04:07:24 +04:00
}
2006-08-30 08:40:03 +04:00
expire = get_time_t_max ( ) ; /* Store indefinately. */
2007-10-29 23:34:00 +03:00
2007-01-18 12:58:57 +03:00
DEBUG ( 10 , ( " sitename_store: realm = [%s], sitename = [%s], expire = [%u] \n " ,
realm , sitename , ( unsigned int ) expire ) ) ;
2006-08-30 08:40:03 +04:00
2007-01-18 12:58:57 +03:00
ret = gencache_set ( key , sitename , expire ) ;
SAFE_FREE ( key ) ;
2006-08-30 08:40:03 +04:00
return ret ;
}
2006-05-05 23:24:48 +04:00
2006-08-30 08:40:03 +04:00
/****************************************************************************
Fetch the AD client sitename .
Caller must free .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-05-05 23:24:48 +04:00
2007-01-18 12:58:57 +03:00
char * sitename_fetch ( const char * realm )
2006-08-30 08:40:03 +04:00
{
char * sitename = NULL ;
2008-07-11 19:44:25 +04:00
time_t timeout ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-01-18 12:58:57 +03:00
const char * query_realm ;
char * key ;
2007-10-29 23:34:00 +03:00
2007-01-18 12:58:57 +03:00
if ( ! realm | | ( strlen ( realm ) = = 0 ) ) {
2007-10-29 23:34:00 +03:00
query_realm = lp_realm ( ) ;
2007-01-18 12:58:57 +03:00
} else {
query_realm = realm ;
}
key = sitename_key ( query_realm ) ;
2008-07-11 19:44:25 +04:00
ret = gencache_get ( key , & sitename , & timeout ) ;
2007-01-18 12:58:57 +03:00
SAFE_FREE ( key ) ;
2006-08-30 08:40:03 +04:00
if ( ! ret ) {
2007-01-18 12:58:57 +03:00
DEBUG ( 5 , ( " sitename_fetch: No stored sitename for %s \n " ,
query_realm ) ) ;
2006-08-30 08:40:03 +04:00
} else {
2007-01-18 12:58:57 +03:00
DEBUG ( 5 , ( " sitename_fetch: Returning sitename for %s: \" %s \" \n " ,
query_realm , sitename ) ) ;
2006-08-30 08:40:03 +04:00
}
return sitename ;
}
2006-08-30 09:52:31 +04:00
/****************************************************************************
Did the sitename change ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool stored_sitename_changed ( const char * realm , const char * sitename )
2006-08-30 09:52:31 +04:00
{
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-01-18 12:58:57 +03:00
char * new_sitename ;
if ( ! realm | | ( strlen ( realm ) = = 0 ) ) {
2007-06-29 15:54:29 +04:00
DEBUG ( 0 , ( " stored_sitename_changed: no realm \n " ) ) ;
2007-01-18 12:58:57 +03:00
return False ;
}
new_sitename = sitename_fetch ( realm ) ;
2006-08-30 09:52:31 +04:00
if ( sitename & & new_sitename & & ! strequal ( sitename , new_sitename ) ) {
ret = True ;
} else if ( ( sitename & & ! new_sitename ) | |
( ! sitename & & new_sitename ) ) {
ret = True ;
}
SAFE_FREE ( new_sitename ) ;
return ret ;
}
2006-08-30 08:40:03 +04:00
/********************************************************************
Query with optional sitename .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-08-28 18:27:48 +04:00
static NTSTATUS ads_dns_query_internal ( TALLOC_CTX * ctx ,
const char * servicename ,
const char * dc_pdc_gc_domains ,
const char * realm ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-08-30 08:40:03 +04:00
{
char * name ;
if ( sitename ) {
2007-08-28 18:27:48 +04:00
name = talloc_asprintf ( ctx , " %s._tcp.%s._sites.%s._msdcs.%s " ,
servicename , sitename ,
dc_pdc_gc_domains , realm ) ;
} else {
name = talloc_asprintf ( ctx , " %s._tcp.%s._msdcs.%s " ,
servicename , dc_pdc_gc_domains , realm ) ;
}
2006-08-30 08:40:03 +04:00
if ( ! name ) {
return NT_STATUS_NO_MEMORY ;
}
2006-05-05 23:24:48 +04:00
return ads_dns_lookup_srv ( ctx , name , dclist , numdcs ) ;
}
2006-08-30 08:40:03 +04:00
/********************************************************************
2007-01-17 21:25:35 +03:00
Query for AD DC ' s .
2006-08-30 08:40:03 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_dcs ( TALLOC_CTX * ctx ,
2007-08-28 18:27:48 +04:00
const char * realm ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-08-30 08:40:03 +04:00
{
NTSTATUS status ;
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _ldap " , " dc " , realm , sitename ,
2006-09-02 23:27:44 +04:00
dclist , numdcs ) ;
2007-01-17 22:20:11 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
2007-08-28 18:27:48 +04:00
if ( sitename & &
( ( ! NT_STATUS_IS_OK ( status ) ) | |
( NT_STATUS_IS_OK ( status ) & & ( numdcs = = 0 ) ) ) ) {
2006-08-30 08:40:03 +04:00
/* Sitename DNS query may have failed. Try without. */
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _ldap " , " dc " , realm ,
NULL , dclist , numdcs ) ;
}
return status ;
}
/********************************************************************
Query for AD GC ' s .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_gcs ( TALLOC_CTX * ctx ,
const char * realm ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
NTSTATUS status ;
status = ads_dns_query_internal ( ctx , " _ldap " , " gc " , realm , sitename ,
dclist , numdcs ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
if ( sitename & &
( ( ! NT_STATUS_IS_OK ( status ) ) | |
( NT_STATUS_IS_OK ( status ) & & ( numdcs = = 0 ) ) ) ) {
/* Sitename DNS query may have failed. Try without. */
status = ads_dns_query_internal ( ctx , " _ldap " , " gc " , realm ,
NULL , dclist , numdcs ) ;
2006-09-02 23:27:44 +04:00
}
return status ;
}
/********************************************************************
2007-01-17 21:25:35 +03:00
Query for AD KDC ' s .
2006-09-02 23:27:44 +04:00
Even if our underlying kerberos libraries are UDP only , this
is pretty safe as it ' s unlikely that a KDC supports TCP and not UDP .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_kdcs ( TALLOC_CTX * ctx ,
2007-08-28 18:27:48 +04:00
const char * dns_forest_name ,
const char * sitename ,
struct dns_rr_srv * * dclist ,
int * numdcs )
2006-09-02 23:27:44 +04:00
{
NTSTATUS status ;
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _kerberos " , " dc " ,
dns_forest_name , sitename , dclist ,
numdcs ) ;
2007-01-17 22:20:11 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
2007-08-28 18:27:48 +04:00
if ( sitename & &
( ( ! NT_STATUS_IS_OK ( status ) ) | |
( NT_STATUS_IS_OK ( status ) & & ( numdcs = = 0 ) ) ) ) {
2006-09-02 23:27:44 +04:00
/* Sitename DNS query may have failed. Try without. */
2007-08-28 18:27:48 +04:00
status = ads_dns_query_internal ( ctx , " _kerberos " , " dc " ,
dns_forest_name , NULL ,
2006-09-02 23:27:44 +04:00
dclist , numdcs ) ;
2006-08-30 08:40:03 +04:00
}
return status ;
}
2007-08-28 18:27:48 +04:00
/********************************************************************
Query for AD PDC . Sitename is obsolete here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_pdc ( TALLOC_CTX * ctx ,
const char * dns_domain_name ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
return ads_dns_query_internal ( ctx , " _ldap " , " pdc " , dns_domain_name ,
NULL , dclist , numdcs ) ;
}
/********************************************************************
Query for AD DC by guid . Sitename is obsolete here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_dcs_guid ( TALLOC_CTX * ctx ,
const char * dns_forest_name ,
const struct GUID * domain_guid ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
/*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
const char * domains ;
2009-08-25 19:02:53 +04:00
char * guid_string ;
2007-08-28 18:27:48 +04:00
guid_string = GUID_string ( ctx , domain_guid ) ;
if ( ! guid_string ) {
return NT_STATUS_NO_MEMORY ;
}
/* little hack */
domains = talloc_asprintf ( ctx , " %s.domains " , guid_string ) ;
if ( ! domains ) {
return NT_STATUS_NO_MEMORY ;
}
2009-08-25 19:02:53 +04:00
TALLOC_FREE ( guid_string ) ;
2007-08-28 18:27:48 +04:00
return ads_dns_query_internal ( ctx , " _ldap " , domains , dns_forest_name ,
NULL , dclist , numdcs ) ;
}