diff options
-rw-r--r-- | source3/include/smb.h | 3 | ||||
-rw-r--r-- | source3/libads/dns.c | 45 | ||||
-rw-r--r-- | source3/libads/kerberos.c | 51 | ||||
-rw-r--r-- | source3/libsmb/namecache.c | 8 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 65 |
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; +} |