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"
2012-05-05 00:47:27 +04:00
# include "lib/util/util_net.h"
# include "lib/util/tsort.h"
2018-01-03 15:26:54 +03:00
# include "librpc/gen_ndr/dns.h"
# include "libcli/dns/dns_lookup.h"
# include "lib/util/tevent_ntstatus.h"
2012-05-05 00:47:27 +04:00
# include "dnsquery.h"
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 ;
}
2018-01-03 15:26:54 +03:00
struct ads_dns_lookup_srv_state {
struct dns_rr_srv * srvs ;
size_t num_srvs ;
} ;
2006-07-20 00:53:10 +04:00
2018-01-03 15:26:54 +03:00
static void ads_dns_lookup_srv_done ( struct tevent_req * subreq ) ;
struct tevent_req * ads_dns_lookup_srv_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * name )
2006-07-20 00:53:10 +04:00
{
2018-01-03 15:26:54 +03:00
struct tevent_req * req , * subreq ;
struct ads_dns_lookup_srv_state * state ;
2006-07-20 00:53:10 +04:00
2018-01-03 15:26:54 +03:00
req = tevent_req_create ( mem_ctx , & state ,
struct ads_dns_lookup_srv_state ) ;
if ( req = = NULL ) {
return NULL ;
2006-07-20 00:53:10 +04:00
}
2007-10-29 23:34:00 +03:00
2018-01-03 15:26:54 +03:00
subreq = dns_lookup_send (
state ,
ev ,
NULL ,
name ,
DNS_QCLASS_IN ,
DNS_QTYPE_SRV ) ;
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2006-07-20 00:53:10 +04:00
}
2018-01-03 15:26:54 +03:00
tevent_req_set_callback ( subreq , ads_dns_lookup_srv_done , req ) ;
return req ;
}
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
static void ads_dns_lookup_srv_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct ads_dns_lookup_srv_state * state = tevent_req_data (
req , struct ads_dns_lookup_srv_state ) ;
int ret ;
struct dns_name_packet * reply ;
uint16_t i , idx ;
ret = dns_lookup_recv ( subreq , state , & reply ) ;
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
tevent_req_nterror ( req , map_nt_error_from_unix_common ( ret ) ) ;
return ;
}
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
for ( i = 0 ; i < reply - > ancount ; i + + ) {
if ( reply - > answers [ i ] . rr_type = = DNS_QTYPE_SRV ) {
state - > num_srvs + = 1 ;
2006-05-05 23:24:48 +04:00
}
}
2018-01-03 15:26:54 +03:00
state - > srvs = talloc_array ( state , struct dns_rr_srv , state - > num_srvs ) ;
if ( tevent_req_nomem ( state - > srvs , req ) ) {
return ;
2006-05-05 23:24:48 +04:00
}
2018-01-03 15:26:54 +03:00
idx = 0 ;
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
for ( i = 0 ; i < reply - > ancount ; i + + ) {
struct dns_res_rec * an = & reply - > answers [ i ] ;
struct dns_rr_srv * dst = & state - > srvs [ idx ] ;
struct dns_srv_record * src ;
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
if ( an - > rr_type ! = DNS_QTYPE_SRV ) {
continue ;
2006-05-05 23:24:48 +04:00
}
2018-01-03 15:26:54 +03:00
src = & an - > rdata . srv_record ;
* dst = ( struct dns_rr_srv ) {
. hostname = talloc_move ( state - > srvs , & src - > target ) ,
. priority = src - > priority ,
. weight = src - > weight ,
. port = src - > port ,
} ;
idx + = 1 ;
2006-05-05 23:24:48 +04:00
}
2018-01-03 15:26:54 +03:00
for ( i = 0 ; i < reply - > arcount ; i + + ) {
struct dns_res_rec * ar = & reply - > additional [ i ] ;
struct sockaddr_storage addr ;
bool ok ;
size_t j ;
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
ok = dns_res_rec_get_sockaddr ( ar , & addr ) ;
if ( ! ok ) {
continue ;
2006-05-05 23:24:48 +04:00
}
2018-01-03 15:26:54 +03:00
for ( j = 0 ; j < state - > num_srvs ; j + + ) {
struct dns_rr_srv * srv = & state - > srvs [ j ] ;
struct sockaddr_storage * tmp ;
2007-10-29 23:34:00 +03:00
2018-01-03 15:26:54 +03:00
if ( strcmp ( srv - > hostname , ar - > name ) ! = 0 ) {
2007-10-29 23:34:00 +03:00
continue ;
2018-01-03 15:26:54 +03:00
}
2006-05-05 23:24:48 +04:00
2018-01-03 15:26:54 +03:00
tmp = talloc_realloc (
state - > srvs ,
srv - > ss_s ,
struct sockaddr_storage ,
srv - > num_ips + 1 ) ;
if ( tevent_req_nomem ( tmp , req ) ) {
return ;
2006-05-05 23:24:48 +04:00
}
2018-01-03 15:26:54 +03:00
srv - > ss_s = tmp ;
srv - > ss_s [ srv - > num_ips ] = addr ;
srv - > num_ips + = 1 ;
2006-05-05 23:24:48 +04:00
}
}
2018-01-03 15:26:54 +03:00
TYPESAFE_QSORT ( state - > srvs , state - > num_srvs , dnssrvcmp ) ;
tevent_req_done ( req ) ;
}
2007-10-29 23:34:00 +03:00
2018-01-03 15:26:54 +03:00
NTSTATUS ads_dns_lookup_srv_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct dns_rr_srv * * srvs ,
size_t * num_srvs )
{
struct ads_dns_lookup_srv_state * state = tevent_req_data (
req , struct ads_dns_lookup_srv_state ) ;
NTSTATUS status ;
2007-10-29 23:34:00 +03:00
2018-01-03 15:26:54 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* srvs = talloc_move ( mem_ctx , & state - > srvs ) ;
* num_srvs = state - > num_srvs ;
tevent_req_received ( req ) ;
2006-05-05 23:24:48 +04:00
return NT_STATUS_OK ;
}
2018-01-03 15:26:54 +03:00
/*********************************************************************
Simple wrapper for a DNS SRV query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_lookup_srv ( TALLOC_CTX * ctx ,
const char * name ,
struct dns_rr_srv * * dclist ,
int * numdcs )
{
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2019-07-09 18:06:30 +03:00
size_t num_srvs = 0 ;
2018-01-03 15:26:54 +03:00
ev = samba_tevent_context_init ( ctx ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = ads_dns_lookup_srv_send ( ev , ev , name ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = ads_dns_lookup_srv_recv ( req , ctx , dclist , & num_srvs ) ;
2019-07-09 18:06:30 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
* numdcs = num_srvs ; /* size_t->int */
}
2018-01-03 15:26:54 +03:00
fail :
TALLOC_FREE ( ev ) ;
return status ;
}
2018-01-03 18:22:24 +03:00
struct ads_dns_lookup_ns_state {
struct dns_rr_ns * nss ;
size_t num_nss ;
} ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
static void ads_dns_lookup_ns_done ( struct tevent_req * subreq ) ;
struct tevent_req * ads_dns_lookup_ns_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * name )
2006-07-20 00:53:10 +04:00
{
2018-01-03 18:22:24 +03:00
struct tevent_req * req , * subreq ;
struct ads_dns_lookup_ns_state * state ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
req = tevent_req_create ( mem_ctx , & state ,
struct ads_dns_lookup_ns_state ) ;
if ( req = = NULL ) {
return NULL ;
2006-07-20 00:53:10 +04:00
}
2007-10-29 23:34:00 +03:00
2018-01-03 18:22:24 +03:00
subreq = dns_lookup_send ( state , ev , NULL , name , DNS_QCLASS_IN ,
DNS_QTYPE_NS ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2006-07-20 00:53:10 +04:00
}
2018-01-03 18:22:24 +03:00
tevent_req_set_callback ( subreq , ads_dns_lookup_ns_done , req ) ;
return req ;
}
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
static void ads_dns_lookup_ns_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct ads_dns_lookup_ns_state * state = tevent_req_data (
req , struct ads_dns_lookup_ns_state ) ;
int ret ;
struct dns_name_packet * reply ;
uint16_t i , idx ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
ret = dns_lookup_recv ( subreq , state , & reply ) ;
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
tevent_req_nterror ( req , map_nt_error_from_unix_common ( ret ) ) ;
return ;
}
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
for ( i = 0 ; i < reply - > ancount ; i + + ) {
if ( reply - > answers [ i ] . rr_type = = DNS_QTYPE_NS ) {
state - > num_nss + = 1 ;
2006-07-20 00:53:10 +04:00
}
}
2018-01-03 18:22:24 +03:00
state - > nss = talloc_array ( state , struct dns_rr_ns , state - > num_nss ) ;
if ( tevent_req_nomem ( state - > nss , req ) ) {
return ;
2006-07-20 00:53:10 +04:00
}
2018-01-03 18:22:24 +03:00
idx = 0 ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
for ( i = 0 ; i < reply - > ancount ; i + + ) {
struct dns_res_rec * an = & reply - > answers [ i ] ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
if ( an - > rr_type ! = DNS_QTYPE_NS ) {
continue ;
2006-07-20 00:53:10 +04:00
}
2018-01-03 18:22:24 +03:00
state - > nss [ idx ] . hostname = talloc_move ( state - > nss ,
& an - > rdata . ns_record ) ;
idx + = 1 ;
}
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
for ( i = 0 ; i < reply - > arcount ; i + + ) {
struct dns_res_rec * ar = & reply - > additional [ i ] ;
struct sockaddr_storage addr ;
bool ok ;
size_t j ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
ok = dns_res_rec_get_sockaddr ( ar , & addr ) ;
if ( ! ok ) {
continue ;
2006-07-20 00:53:10 +04:00
}
2018-01-03 18:22:24 +03:00
for ( j = 0 ; j < state - > num_nss ; j + + ) {
struct dns_rr_ns * ns = & state - > nss [ j ] ;
2006-07-20 00:53:10 +04:00
2018-01-03 18:22:24 +03:00
if ( strcmp ( ns - > hostname , ar - > name ) = = 0 ) {
ns - > ss = addr ;
2006-07-20 00:53:10 +04:00
}
}
}
2007-10-29 23:34:00 +03:00
2018-01-03 18:22:24 +03:00
tevent_req_done ( req ) ;
}
NTSTATUS ads_dns_lookup_ns_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
struct dns_rr_ns * * nss ,
size_t * num_nss )
{
struct ads_dns_lookup_ns_state * state = tevent_req_data (
req , struct ads_dns_lookup_ns_state ) ;
NTSTATUS status ;
2007-10-29 23:34:00 +03:00
2018-01-03 18:22:24 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* nss = talloc_move ( mem_ctx , & state - > nss ) ;
* num_nss = state - > num_nss ;
tevent_req_received ( req ) ;
2006-07-20 00:53:10 +04:00
return NT_STATUS_OK ;
}
2018-01-03 18:22:24 +03:00
/*********************************************************************
Simple wrapper for a DNS NS query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_lookup_ns ( TALLOC_CTX * ctx ,
const char * dnsdomain ,
struct dns_rr_ns * * nslist ,
int * numns )
{
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
size_t num_ns = 0 ;
ev = samba_tevent_context_init ( ctx ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = ads_dns_lookup_ns_send ( ev , ev , dnsdomain ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = ads_dns_lookup_ns_recv ( req , ctx , nslist , & num_ns ) ;
* numns = num_ns ;
fail :
TALLOC_FREE ( ev ) ;
return status ;
}
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 ;
2019-01-11 16:18:53 +03:00
NTSTATUS status ;
int num_srvs = 0 ;
if ( ( sitename ! = NULL ) & & ( strlen ( sitename ) ! = 0 ) ) {
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 ) ;
2019-01-11 16:18:53 +03:00
if ( name = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = ads_dns_lookup_srv ( ctx , name , dclist , & num_srvs ) ;
TALLOC_FREE ( name ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_REFUSED ) ) {
return status ;
}
if ( NT_STATUS_IS_OK ( status ) & & ( num_srvs ! = 0 ) ) {
goto done ;
}
2012-05-05 00:47:27 +04:00
}
2019-01-11 16:18:53 +03:00
name = talloc_asprintf ( ctx , " %s._tcp.%s._msdcs.%s " ,
servicename , dc_pdc_gc_domains , realm ) ;
if ( name = = NULL ) {
2006-08-30 08:40:03 +04:00
return NT_STATUS_NO_MEMORY ;
}
2019-01-11 16:18:53 +03:00
status = ads_dns_lookup_srv ( ctx , name , dclist , & num_srvs ) ;
done :
* numdcs = num_srvs ; /* automatic conversion size_t->int */
return status ;
2006-05-05 23:24:48 +04:00
}
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 ;
2014-11-20 13:31:29 +03:00
status = ads_dns_query_internal ( ctx ,
" _ldap " ,
" dc " ,
realm ,
sitename ,
dclist ,
numdcs ) ;
2007-08-28 18:27:48 +04:00
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 ;
2014-11-20 13:31:29 +03:00
status = ads_dns_query_internal ( ctx ,
" _ldap " ,
" gc " ,
realm ,
sitename ,
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 ;
2014-11-20 13:31:29 +03:00
status = ads_dns_query_internal ( ctx ,
" _kerberos " ,
" dc " ,
dns_forest_name ,
sitename ,
dclist ,
2007-08-28 18:27:48 +04:00
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 )
{
2014-11-20 13:31:29 +03:00
return ads_dns_query_internal ( ctx ,
" _ldap " ,
" pdc " ,
dns_domain_name ,
NULL ,
dclist ,
numdcs ) ;
2007-08-28 18:27:48 +04:00
}
/********************************************************************
Query for AD DC by guid . Sitename is obsolete here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS ads_dns_query_dcs_guid ( TALLOC_CTX * ctx ,
const char * dns_forest_name ,
2012-05-05 06:32:47 +04:00
const char * domain_guid ,
2007-08-28 18:27:48 +04:00
struct dns_rr_srv * * dclist ,
int * numdcs )
{
/*_ldap._tcp.DomainGuid.domains._msdcs.DnsForestName */
const char * domains ;
/* little hack */
2012-05-05 06:32:47 +04:00
domains = talloc_asprintf ( ctx , " %s.domains " , domain_guid ) ;
2007-08-28 18:27:48 +04:00
if ( ! domains ) {
return NT_STATUS_NO_MEMORY ;
}
2014-11-20 13:31:29 +03:00
return ads_dns_query_internal ( ctx ,
" _ldap " ,
domains ,
dns_forest_name ,
NULL ,
dclist ,
numdcs ) ;
2007-08-28 18:27:48 +04:00
}