summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h3
-rw-r--r--source3/libads/dns.c45
-rw-r--r--source3/libads/kerberos.c51
-rw-r--r--source3/libsmb/namecache.c8
-rw-r--r--source3/libsmb/namequery.c65
5 files changed, 155 insertions, 17 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index c5115a551f..5a9d0f7d15 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1789,6 +1789,9 @@ struct ip_service {
unsigned port;
};
+/* Special name type used to cause a _kerberos DNS lookup. */
+#define KDC_NAME_TYPE 0xDCDC
+
/* Used by the SMB signing functions. */
typedef struct smb_sign_info {
diff --git a/source3/libads/dns.c b/source3/libads/dns.c
index 579296ea1f..d5c851d5ca 100644
--- a/source3/libads/dns.c
+++ b/source3/libads/dns.c
@@ -649,18 +649,20 @@ BOOL stored_sitename_changed(const char *sitename)
Query with optional sitename.
********************************************************************/
-NTSTATUS ads_dns_query_dcs_internal(TALLOC_CTX *ctx,
- const char *domain,
+NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
+ const char *servicename,
+ 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 );
+ name = talloc_asprintf(ctx, "%s._tcp.%s._sites.dc._msdcs.%s",
+ servicename, sitename, realm );
} else {
- name = talloc_asprintf(ctx, "_ldap._tcp.dc._msdcs.%s", domain );
+ name = talloc_asprintf(ctx, "%s._tcp.dc._msdcs.%s",
+ servicename, realm );
}
if (!name) {
return NT_STATUS_NO_MEMORY;
@@ -673,17 +675,44 @@ NTSTATUS ads_dns_query_dcs_internal(TALLOC_CTX *ctx,
********************************************************************/
NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
- const char *domain,
+ const char *realm,
struct dns_rr_srv **dclist,
int *numdcs )
{
NTSTATUS status;
char *sitename = sitename_fetch();
- status = ads_dns_query_dcs_internal(ctx, domain, sitename, dclist, numdcs);
+ status = ads_dns_query_internal(ctx, "_ldap", realm, sitename,
+ dclist, numdcs);
if (sitename && !NT_STATUS_IS_OK(status)) {
/* 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, "_ldap", realm, NULL,
+ dclist, numdcs);
+ }
+ SAFE_FREE(sitename);
+ return status;
+}
+
+/********************************************************************
+ Query for AD KDC's. Transparently use sitename.
+ 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 *realm,
+ struct dns_rr_srv **dclist,
+ int *numdcs )
+{
+ NTSTATUS status;
+ char *sitename = sitename_fetch();
+
+ status = ads_dns_query_internal(ctx, "_kerberos", realm, sitename,
+ dclist, numdcs);
+ if (sitename && !NT_STATUS_IS_OK(status)) {
+ /* Sitename DNS query may have failed. Try without. */
+ status = ads_dns_query_internal(ctx, "_kerberos", realm, NULL,
+ dclist, numdcs);
}
SAFE_FREE(sitename);
return status;
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 4801aec23e..c872508fe8 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -465,6 +465,46 @@ int kerberos_kinit_password(const char *principal,
}
/************************************************************************
+ Create a string list of available kdc's, possibly searching by sitename.
+ Does DNS queries.
+************************************************************************/
+
+static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr primary_ip)
+{
+ struct ip_service *ip_srv;
+ int count, i;
+ char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
+ inet_ntoa(primary_ip));
+
+ if (kdc_str == NULL) {
+ return NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(get_kdc_list(realm, &ip_srv, &count))) {
+ DEBUG(10,("get_kdc_ip_string: get_kdc_list failed. Returning %s\n",
+ kdc_str ));
+ return kdc_str;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (ip_equal(ip_srv[i].ip, primary_ip)) {
+ continue;
+ }
+ /* Append to the string - inefficient but not done often. */
+ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+ kdc_str, inet_ntoa(ip_srv[i].ip));
+ if (!kdc_str) {
+ return NULL;
+ }
+ }
+
+ DEBUG(10,("get_kdc_ip_string: Returning %s\n",
+ kdc_str ));
+
+ return kdc_str;
+}
+
+/************************************************************************
Create a specific krb5.conf file in the private directory pointing
at a specific kdc for a realm. Keyed off domain name. Sets
KRB5_CONFIG environment variable to point to this file. Must be
@@ -477,6 +517,7 @@ BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *do
char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
char *fname = NULL;
char *file_contents = NULL;
+ char *kdc_ip_string;
size_t flen = 0;
size_t ret;
char *realm_upper = NULL;
@@ -505,10 +546,16 @@ BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *do
realm_upper = talloc_strdup(fname, realm);
strupper_m(realm_upper);
+ kdc_ip_string = get_kdc_ip_string(dname, realm, ip);
+ if (!kdc_ip_string) {
+ TALLOC_FREE(dname);
+ return False;
+ }
+
file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
"[realms]\n\t%s = {\n"
- "\t\tkdc = %s\n\t}\n",
- realm_upper, realm_upper, inet_ntoa(ip));
+ "\t\t%s\t}\n",
+ realm_upper, realm_upper, kdc_ip_string);
if (!file_contents) {
TALLOC_FREE(dname);
diff --git a/source3/libsmb/namecache.c b/source3/libsmb/namecache.c
index ec8a1900d8..afbd807198 100644
--- a/source3/libsmb/namecache.c
+++ b/source3/libsmb/namecache.c
@@ -126,6 +126,10 @@ BOOL namecache_store(const char *name, int name_type,
*/
if (!gencache_init()) return False;
+ if (name_type > 255) {
+ return False; /* Don't store non-real name types. */
+ }
+
if ( DEBUGLEVEL >= 5 ) {
DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
num_names, num_names == 1 ? "": "es", name, name_type));
@@ -184,6 +188,10 @@ BOOL namecache_fetch(const char *name, int name_type, struct ip_service **ip_lis
if (!gencache_init())
return False;
+ if (name_type > 255) {
+ return False; /* Don't fetch non-real name types. */
+ }
+
*num_names = 0;
/*
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 4c361a3716..af3ac319cc 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -1030,7 +1030,7 @@ static BOOL resolve_ads(const char *name, int name_type,
int numdcs = 0;
int numaddrs = 0;
- if ( name_type != 0x1c )
+ if ((name_type != 0x1c) && (name_type != KDC_NAME_TYPE))
return False;
DEBUG(5,("resolve_hosts: Attempting to resolve DC's for %s using DNS\n",
@@ -1040,8 +1040,12 @@ static BOOL resolve_ads(const char *name, int name_type,
DEBUG(0,("resolve_ads: talloc_init() failed!\n"));
return False;
}
-
- status = ads_dns_query_dcs( ctx, name, &dcs, &numdcs );
+
+ if (name_type == KDC_NAME_TYPE) {
+ status = ads_dns_query_kdcs(ctx, name, &dcs, &numdcs);
+ } else {
+ status = ads_dns_query_dcs(ctx, name, &dcs, &numdcs);
+ }
if ( !NT_STATUS_IS_OK( status ) ) {
talloc_destroy(ctx);
return False;
@@ -1188,6 +1192,13 @@ BOOL internal_resolve_name(const char *name, int name_type,
result = True;
goto done;
}
+ } else if(strequal( tok, "kdc")) {
+ /* deal with KDC_NAME_TYPE names here. This will result in a
+ SRV record lookup */
+ if (resolve_ads(name, KDC_NAME_TYPE, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
} else if(strequal( tok, "ads")) {
/* deal with 0x1c names here. This will result in a
SRV record lookup */
@@ -1355,13 +1366,17 @@ BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
return True;
}
+/* Private enum type for lookups. */
+
+enum dc_lookup_type { DC_NORMAL_LOOKUP, DC_ADS_ONLY, DC_KDC_ONLY };
+
/********************************************************
Get the IP address list of the domain controllers for
a domain.
*********************************************************/
static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
- int *count, BOOL ads_only, int *ordered)
+ int *count, enum dc_lookup_type lookup_type, int *ordered)
{
fstring resolve_order;
char *saf_servername;
@@ -1387,7 +1402,7 @@ static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
fstrcpy( resolve_order, lp_name_resolve_order() );
strlower_m( resolve_order );
- if ( ads_only ) {
+ if ( lookup_type == DC_ADS_ONLY) {
if ( strstr( resolve_order, "host" ) ) {
fstrcpy( resolve_order, "ads" );
@@ -1397,6 +1412,11 @@ static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
} else {
fstrcpy( resolve_order, "NULL" );
}
+ } else if (lookup_type == DC_KDC_ONLY) {
+ /* DNS SRV lookups used by the ads/kdc resolver
+ are already sorted by priority and weight */
+ *ordered = True;
+ fstrcpy( resolve_order, "kdc" );
}
/* fetch the server we have affinity for. Add the
@@ -1558,11 +1578,16 @@ NTSTATUS get_sorted_dc_list( const char *domain, struct ip_service **ip_list, in
{
BOOL ordered;
NTSTATUS status;
-
+ enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP;
+
DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n",
(ads_only ? "ads" : lp_name_resolve_order())));
- status = get_dc_list(domain, ip_list, count, ads_only, &ordered);
+ if (ads_only) {
+ lookup_type = DC_ADS_ONLY;
+ }
+
+ status = get_dc_list(domain, ip_list, count, lookup_type, &ordered);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -1574,3 +1599,29 @@ NTSTATUS get_sorted_dc_list( const char *domain, struct ip_service **ip_list, in
return NT_STATUS_OK;
}
+
+/*********************************************************************
+ Get the KDC list - re-use all the logic in get_dc_list.
+*********************************************************************/
+
+NTSTATUS get_kdc_list( const char *realm, struct ip_service **ip_list, int *count)
+{
+ BOOL ordered;
+ NTSTATUS status;
+
+ *count = 0;
+ *ip_list = NULL;
+
+ status = get_dc_list(realm, ip_list, count, DC_KDC_ONLY, &ordered);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* only sort if we don't already have an ordered list */
+ if ( !ordered ) {
+ sort_ip_list2( *ip_list, *count );
+ }
+
+ return NT_STATUS_OK;
+}