r18006: Actually a smaller change than it looks. Leverage
authorJeremy Allison <jra@samba.org>
Sat, 2 Sep 2006 19:27:44 +0000 (19:27 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:39:47 +0000 (11:39 -0500)
the get_dc_list code to get the _kerberos. names
for site support. This way we don't depend on one
KDC to do ticket refresh. Even though we know it's
up when we add it, it may go down when we're trying
to refresh.
Jeremy.

source/include/smb.h
source/libads/dns.c
source/libads/kerberos.c
source/libsmb/namecache.c
source/libsmb/namequery.c

index c5115a551febc55bde9248887f6d5a021ebb4dba..5a9d0f7d15d53dc59b73638142f7d531ce97f1dc 100644 (file)
@@ -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 {
index 579296ea1fbf700b6c47756c4033d403a90c363e..d5c851d5ca8dd100457f99f156d6e3d4a2e17793 100644 (file)
@@ -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;
index 4801aec23e9fdf7cd2c656695d3c35bf045ea0c7..c872508fe84d025ea9c96ac6c01295ac1aba4072 100644 (file)
@@ -464,6 +464,46 @@ int kerberos_kinit_password(const char *principal,
                                           0);
 }
 
+/************************************************************************
+ 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
@@ -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);
index ec8a1900d871fb3a9d75e7cef9b6fc739ba236af..afbd807198f17aa78327dcc7e47d1733d8ff583d 100644 (file)
@@ -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;
 
        /* 
index 4c361a37165889b74fb34ecf7daf8c0d596dcd78..af3ac319cc242a3d879ff8e5b3909414bfd9005a 100644 (file)
@@ -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;
+}