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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
# define T_A ns_t_a
#endif
# define T_SRV ns_t_srv
+#if !defined(T_NS) /* AIX 5.3 already defines T_NS */
# define T_NS ns_t_ns
+#endif
#else
# ifdef HFIXEDSZ
# define NS_HFIXEDSZ HFIXEDSZ
/*********************************************************************
*********************************************************************/
-static BOOL ads_dns_parse_query( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+static bool ads_dns_parse_query( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
uint8 **ptr, struct dns_query *q )
{
uint8 *p = *ptr;
/*********************************************************************
*********************************************************************/
-static BOOL ads_dns_parse_rr( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+static bool ads_dns_parse_rr( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
uint8 **ptr, struct dns_rr *rr )
{
uint8 *p = *ptr;
/*********************************************************************
*********************************************************************/
-static BOOL ads_dns_parse_rr_srv( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+static bool ads_dns_parse_rr_srv( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
uint8 **ptr, struct dns_rr_srv *srv )
{
struct dns_rr rr;
/*********************************************************************
*********************************************************************/
-static BOOL ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
+static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8 *start, uint8 *end,
uint8 **ptr, struct dns_rr_ns *nsrec )
{
struct dns_rr rr;
Simple wrapper for a DNS query
*********************************************************************/
+#define DNS_FAILED_WAITTIME 30
+
static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type,
uint8 **buf, int *resp_length )
{
uint8 *buffer = NULL;
size_t buf_len;
int resp_len = NS_PACKETSZ;
-
+ static time_t last_dns_check = 0;
+ static NTSTATUS last_dns_status = NT_STATUS_OK;
+ 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;
+
+ /* IF we had a DNS timeout or a bad server and we are still
+ in the 30 second cache window, just return the previous
+ 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)) &&
+ (last_dns_check+DNS_FAILED_WAITTIME) > now )
+ {
+ DEBUG(10,("last_dns_check: Returning cached status (%s)\n",
+ nt_errstr(last_dns_status) ));
+ return last_dns_status;
+ }
+
+ /* Send the Query */
do {
if ( buffer )
TALLOC_FREE( buffer );
buf_len = resp_len * sizeof(uint8);
- if ( (buffer = TALLOC_ARRAY(ctx, uint8, buf_len)) == NULL ) {
- DEBUG(0,("ads_dns_lookup_srv: talloc() failed!\n"));
- return NT_STATUS_NO_MEMORY;
+ if (buf_len) {
+ if ( (buffer = TALLOC_ARRAY(ctx, uint8, buf_len)) == NULL ) {
+ DEBUG(0,("ads_dns_lookup_srv: talloc() failed!\n"));
+ last_dns_status = NT_STATUS_NO_MEMORY;
+ last_dns_check = time(NULL);
+ return last_dns_status;
+ }
}
if ( (resp_len = res_query(name, C_IN, q_type, buffer, buf_len)) < 0 ) {
- DEBUG(1,("ads_dns_lookup_srv: Failed to resolve %s (%s)\n", name, strerror(errno)));
+ DEBUG(3,("ads_dns_lookup_srv: Failed to resolve %s (%s)\n", name, strerror(errno)));
TALLOC_FREE( buffer );
- return NT_STATUS_UNSUCCESSFUL;
+ last_dns_status = NT_STATUS_UNSUCCESSFUL;
+
+ if (errno == ETIMEDOUT) {
+ last_dns_status = NT_STATUS_IO_TIMEOUT;
+ }
+ if (errno == ECONNREFUSED) {
+ last_dns_status = NT_STATUS_CONNECTION_REFUSED;
+ }
+ last_dns_check = time(NULL);
+ return last_dns_status;
}
} while ( buf_len < resp_len && resp_len < MAX_DNS_PACKET_SIZE );
*buf = buffer;
*resp_length = resp_len;
- return NT_STATUS_OK;
+ last_dns_check = time(NULL);
+ last_dns_status = NT_STATUS_OK;
+ return last_dns_status;
}
/*********************************************************************
status = dns_send_req( ctx, name, T_SRV, &buffer, &resp_len );
if ( !NT_STATUS_IS_OK(status) ) {
- DEBUG(0,("ads_dns_lookup_srv: Failed to send DNS query (%s)\n",
+ DEBUG(3,("ads_dns_lookup_srv: Failed to send DNS query (%s)\n",
nt_errstr(status)));
return status;
}
DEBUG(4,("ads_dns_lookup_srv: %d records returned in the answer section.\n",
answer_count));
- 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",
- answer_count));
- return NT_STATUS_NO_MEMORY;
+ if (answer_count) {
+ 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",
+ answer_count));
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ dcs = NULL;
}
/* now skip the header */
status = dns_send_req( ctx, dnsdomain, T_NS, &buffer, &resp_len );
if ( !NT_STATUS_IS_OK(status) ) {
- DEBUG(0,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
+ DEBUG(3,("ads_dns_lookup_ns: Failed to send DNS query (%s)\n",
nt_errstr(status)));
return status;
}
DEBUG(4,("ads_dns_lookup_ns: %d records returned in the answer section.\n",
answer_count));
- 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",
- answer_count));
- return NT_STATUS_NO_MEMORY;
+ if (answer_count) {
+ 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",
+ answer_count));
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ nsarray = NULL;
}
/* now skip the header */
Store and fetch the AD client sitename.
****************************************************************************/
-#define SITENAME_KEY "AD_SITENAME"
+#define SITENAME_KEY "AD_SITENAME/DOMAIN/%s"
+
+static char *sitename_key(const char *realm)
+{
+ char *keystr;
+
+ if (asprintf(&keystr, SITENAME_KEY, strupper_static(realm)) == -1) {
+ return NULL;
+ }
+
+ return keystr;
+}
+
/****************************************************************************
Store the AD client sitename.
We store indefinately as every new CLDAP query will re-write this.
****************************************************************************/
-BOOL sitename_store(const char *sitename)
+bool sitename_store(const char *realm, const char *sitename)
{
time_t expire;
- BOOL ret = False;
-
- if ( !sitename || (sitename && !*sitename)) {
- DEBUG(2,("sitename_store: deleting empty sitename!\n"));
- return gencache_del(SITENAME_KEY);
- }
-
+ bool ret = False;
+ char *key;
+
if (!gencache_init()) {
return False;
}
+
+ if (!realm || (strlen(realm) == 0)) {
+ DEBUG(0,("sitename_store: no realm\n"));
+ return False;
+ }
+ key = sitename_key(realm);
+
+ if (!sitename || (sitename && !*sitename)) {
+ DEBUG(5,("sitename_store: deleting empty sitename!\n"));
+ ret = gencache_del(key);
+ SAFE_FREE(key);
+ return ret;
+ }
+
expire = get_time_t_max(); /* Store indefinately. */
- DEBUG(10,("sitename_store: sitename = [%s], expire = [%u]\n",
- sitename, (unsigned int)expire ));
+ DEBUG(10,("sitename_store: realm = [%s], sitename = [%s], expire = [%u]\n",
+ realm, sitename, (unsigned int)expire ));
- ret = gencache_set( SITENAME_KEY, sitename, expire );
+ ret = gencache_set( key, sitename, expire );
+ SAFE_FREE(key);
return ret;
}
Caller must free.
****************************************************************************/
-static char *sitename_fetch(void)
+char *sitename_fetch(const char *realm)
{
char *sitename = NULL;
time_t timeout;
- BOOL ret = False;
+ bool ret = False;
+ const char *query_realm;
+ char *key;
if (!gencache_init()) {
return False;
}
-
- ret = gencache_get( SITENAME_KEY, &sitename, &timeout );
+
+ if (!realm || (strlen(realm) == 0)) {
+ query_realm = lp_realm();
+ } else {
+ query_realm = realm;
+ }
+
+ key = sitename_key(query_realm);
+
+ ret = gencache_get( key, &sitename, &timeout );
+ SAFE_FREE(key);
if ( !ret ) {
- DEBUG(5,("sitename_fetch: No stored sitename\n"));
+ DEBUG(5,("sitename_fetch: No stored sitename for %s\n",
+ query_realm));
} else {
- DEBUG(5,("sitename_fetch: Returning sitename \"%s\"\n",
- sitename ));
+ DEBUG(5,("sitename_fetch: Returning sitename for %s: \"%s\"\n",
+ query_realm, sitename ));
}
return sitename;
}
+/****************************************************************************
+ Did the sitename change ?
+****************************************************************************/
+
+bool stored_sitename_changed(const char *realm, const char *sitename)
+{
+ bool ret = False;
+
+ char *new_sitename;
+
+ if (!realm || (strlen(realm) == 0)) {
+ DEBUG(0,("stored_sitename_changed: no realm\n"));
+ return False;
+ }
+
+ new_sitename = sitename_fetch(realm);
+
+ 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;
+}
+
/********************************************************************
Query with optional sitename.
********************************************************************/
-NTSTATUS ads_dns_query_dcs_internal(TALLOC_CTX *ctx,
- const char *domain,
- const char *sitename,
- struct dns_rr_srv **dclist,
- int *numdcs )
+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 )
{
char *name;
if (sitename) {
- name = talloc_asprintf(ctx, "_ldap._tcp.%s._sites.dc._msdcs.%s",
- sitename, domain );
- } else {
- name = talloc_asprintf(ctx, "_ldap._tcp.dc._msdcs.%s", domain );
- }
+ 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);
+ }
if (!name) {
return NT_STATUS_NO_MEMORY;
}
}
/********************************************************************
- Query for AD DC's. Transparently use sitename.
+ Query for AD DC's.
********************************************************************/
NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
- const char *domain,
- struct dns_rr_srv **dclist,
- int *numdcs )
+ const char *realm,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ NTSTATUS status;
+
+ status = ads_dns_query_internal(ctx, "_ldap", "dc", 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", "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);
+ }
+ return status;
+}
+
+/********************************************************************
+ Query for AD KDC's.
+ 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,
+ const char *dns_forest_name,
+ const char *sitename,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
{
NTSTATUS status;
- char *sitename = sitename_fetch();
- status = ads_dns_query_dcs_internal(ctx, domain, sitename, dclist, numdcs);
- if (sitename && !NT_STATUS_IS_OK(status)) {
+ status = ads_dns_query_internal(ctx, "_kerberos", "dc",
+ dns_forest_name, 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_dcs_internal(ctx, domain, NULL, dclist, numdcs);
+ status = ads_dns_query_internal(ctx, "_kerberos", "dc",
+ dns_forest_name, NULL,
+ dclist, numdcs);
}
- SAFE_FREE(sitename);
return status;
}
+
+/********************************************************************
+ 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;
+ const char *guid_string;
+
+ 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;
+ }
+
+ return ads_dns_query_internal(ctx, "_ldap", domains, dns_forest_name,
+ NULL, dclist, numdcs);
+}