r20857: Silence gives assent :-). Checking in the fix for
[nivanova/samba-autobuild/.git] / source3 / libsmb / namequery.c
index dcb7dbf07087aedd241412d20c55baf8bf541665..6ebc26b8cbb960d116a0c212a842e9fe14b1ac28 100644 (file)
@@ -15,8 +15,7 @@
    
    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.
-   
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   
 */
 
 #include "includes.h"
@@ -24,7 +23,6 @@
 /* nmbd.c sets this to True. */
 BOOL global_in_nmbd = False;
 
-
 /****************************
  * SERVER AFFINITY ROUTINES *
  ****************************/
@@ -59,6 +57,11 @@ BOOL saf_store( const char *domain, const char *servername )
                DEBUG(2,("saf_store: Refusing to store empty domain or servername!\n"));
                return False;
        }
+
+       if ( (strlen(domain) == 0) || (strlen(servername) == 0) ) {
+               DEBUG(0,("saf_store: refusing to store 0 length domain or servername!\n"));
+               return False;
+       }
        
        if ( !gencache_init() ) 
                return False;
@@ -77,6 +80,31 @@ BOOL saf_store( const char *domain, const char *servername )
        return ret;
 }
 
+BOOL saf_delete( const char *domain )
+{
+       char *key;
+       BOOL ret = False;
+       
+       if ( !domain ) {
+               DEBUG(2,("saf_delete: Refusing to delete empty domain\n"));             
+               return False;
+       }
+       
+       if ( !gencache_init() ) 
+               return False;
+       
+       key = saf_key(domain);
+       ret = gencache_del(key);
+       
+       if (ret) {
+               DEBUG(10,("saf_delete: domain = [%s]\n", domain ));             
+       }
+
+       SAFE_FREE( key );
+
+       return ret;
+}
+
 /****************************************************************************
 ****************************************************************************/
 
@@ -87,7 +115,7 @@ char *saf_fetch( const char *domain )
        BOOL ret = False;
        char *key = NULL;
 
-       if ( !domain ) {
+       if ( !domain || strlen(domain) == 0) {
                DEBUG(2,("saf_fetch: Empty domain name!\n"));
                return NULL;
        }
@@ -111,7 +139,6 @@ char *saf_fetch( const char *domain )
        return server;
 }
 
-
 /****************************************************************************
  Generate a random trn_id.
 ****************************************************************************/
@@ -357,7 +384,7 @@ static int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
  compare 2 ldap IPs by nearness to our interfaces - used in qsort
 *******************************************************************/
 
-static int ip_service_compare(struct ip_service *ip1, struct ip_service *ip2)
+int ip_service_compare(struct ip_service *ip1, struct ip_service *ip2)
 {
        int result;
        
@@ -1022,6 +1049,7 @@ static BOOL resolve_hosts(const char *name, int name_type,
 *********************************************************/
 
 static BOOL resolve_ads(const char *name, int name_type,
+                       const char *sitename,
                          struct ip_service **return_iplist, int *return_count)
 {
        int                     i, j;
@@ -1031,19 +1059,24 @@ 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",
+       DEBUG(5,("resolve_ads: Attempting to resolve DC's for %s using DNS\n",
                name));
                        
        if ( (ctx = talloc_init("resolve_ads")) == NULL ) {
                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, sitename, &dcs, &numdcs);
+       } else {
+               status = ads_dns_query_dcs(ctx, name, sitename, &dcs, &numdcs);
+       }
        if ( !NT_STATUS_IS_OK( status ) ) {
+               talloc_destroy(ctx);
                return False;
        }
 
@@ -1053,6 +1086,7 @@ static BOOL resolve_ads(const char *name, int name_type,
                
        if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) == NULL ) {
                DEBUG(0,("resolve_ads: malloc failed for %d entries\n", numaddrs ));
+               talloc_destroy(ctx);
                return False;
        }
        
@@ -1096,8 +1130,7 @@ static BOOL resolve_ads(const char *name, int name_type,
                        (*return_count)++;
        }
                
-       TALLOC_FREE( dcs );
-                               
+       talloc_destroy(ctx);
        return True;
 }
 
@@ -1113,6 +1146,7 @@ static BOOL resolve_ads(const char *name, int name_type,
 **********************************************************************/
 
 BOOL internal_resolve_name(const char *name, int name_type,
+                          const char *sitename,
                           struct ip_service **return_iplist, 
                           int *return_count, const char *resolve_order)
 {
@@ -1128,7 +1162,8 @@ BOOL internal_resolve_name(const char *name, int name_type,
        *return_iplist = NULL;
        *return_count = 0;
 
-       DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
+       DEBUG(10, ("internal_resolve_name: looking up %s#%x (sitename %s)\n",
+                       name, name_type, sitename ? sitename : NULL));
 
        if (allzeros || allones || is_address) {
   
@@ -1188,10 +1223,19 @@ 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, sitename, return_iplist, return_count)) {
+                               result = True;
+                               /* Ensure we don't namecache this with the KDC port. */
+                               name_type = KDC_NAME_TYPE;
+                               goto done;
+                       }
                } else if(strequal( tok, "ads")) {
                        /* deal with 0x1c names here.  This will result in a
                                SRV record lookup */
-                       if (resolve_ads(name, name_type, return_iplist, return_count)) {
+                       if (resolve_ads(name, name_type, sitename, return_iplist, return_count)) {
                                result = True;
                                goto done;
                        }
@@ -1267,14 +1311,16 @@ BOOL internal_resolve_name(const char *name, int name_type,
 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
 {
        struct ip_service *ip_list = NULL;
+       char *sitename = sitename_fetch();
        int count = 0;
 
        if (is_ipaddress(name)) {
                *return_ip = *interpret_addr2(name);
+               SAFE_FREE(sitename);
                return True;
        }
 
-       if (internal_resolve_name(name, name_type, &ip_list, &count, lp_name_resolve_order())) {
+       if (internal_resolve_name(name, name_type, sitename, &ip_list, &count, lp_name_resolve_order())) {
                int i;
                
                /* only return valid addresses for TCP connections */
@@ -1286,12 +1332,14 @@ BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
                        {
                                *return_ip = ip_list[i].ip;
                                SAFE_FREE(ip_list);
+                               SAFE_FREE(sitename);
                                return True;
                        }
                }
        }
        
        SAFE_FREE(ip_list);
+       SAFE_FREE(sitename);
        return False;
 }
 
@@ -1309,12 +1357,12 @@ BOOL find_master_ip(const char *group, struct in_addr *master_ip)
                return False;
        }
 
-       if (internal_resolve_name(group, 0x1D, &ip_list, &count, lp_name_resolve_order())) {
+       if (internal_resolve_name(group, 0x1D, NULL, &ip_list, &count, lp_name_resolve_order())) {
                *master_ip = ip_list[0].ip;
                SAFE_FREE(ip_list);
                return True;
        }
-       if(internal_resolve_name(group, 0x1B, &ip_list, &count, lp_name_resolve_order())) {
+       if(internal_resolve_name(group, 0x1B, NULL, &ip_list, &count, lp_name_resolve_order())) {
                *master_ip = ip_list[0].ip;
                SAFE_FREE(ip_list);
                return True;
@@ -1331,15 +1379,19 @@ BOOL find_master_ip(const char *group, struct in_addr *master_ip)
 
 BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
 {
-       struct ip_service *ip_list;
-       int count;
+       char *sitename = sitename_fetch();
+       struct ip_service *ip_list = NULL;
+       int count = 0;
 
        /* Look up #1B name */
 
-       if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order())) {
+       if (!internal_resolve_name(domain, 0x1b, sitename, &ip_list, &count, lp_name_resolve_order())) {
+               SAFE_FREE(sitename);
                return False;
        }
 
+       SAFE_FREE(sitename);
+
        /* if we get more than 1 IP back we have to assume it is a
           multi-homed PDC and not a mess up */
 
@@ -1355,13 +1407,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)
+static NTSTATUS get_dc_list(const char *domain, const char *sitename, struct ip_service **ip_list, 
+                            int *count, enum dc_lookup_type lookup_type, int *ordered)
 {
        fstring resolve_order;
        char *saf_servername;
@@ -1387,7 +1443,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,12 +1453,17 @@ 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 
           'password server' list to a search for our domain controllers */
        
-       saf_servername = saf_fetch( domain );
+       saf_servername = saf_fetch( domain);
        
        if ( strequal(domain, lp_workgroup()) || strequal(domain, lp_realm()) ) {
                pstr_sprintf( pserver, "%s, %s", 
@@ -1421,7 +1482,7 @@ static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
                DEBUG(10,("get_dc_list: no preferred domain controllers.\n"));
                /* TODO: change return type of internal_resolve_name to
                 * NTSTATUS */
-               if (internal_resolve_name(domain, 0x1C, ip_list, count,
+               if (internal_resolve_name(domain, 0x1C, sitename, ip_list, count,
                                          resolve_order)) {
                        return NT_STATUS_OK;
                } else {
@@ -1441,7 +1502,7 @@ static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
        p = pserver;
        while (next_token(&p,name,LIST_SEP,sizeof(name))) {
                if (strequal(name, "*")) {
-                       if (internal_resolve_name(domain, 0x1C, &auto_ip_list,
+                       if (internal_resolve_name(domain, 0x1C, sitename, &auto_ip_list,
                                                  &auto_count, resolve_order))
                                num_addresses += auto_count;
                        done_auto_lookup = True;
@@ -1455,20 +1516,22 @@ static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
           just return the list of DC's.  Or maybe we just failed. */
                   
        if ( (num_addresses == 0) ) {
-               if ( !done_auto_lookup ) {
-                       if (internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order)) {
-                               return NT_STATUS_OK;
-                       } else {
-                               return NT_STATUS_NO_LOGON_SERVERS;
-                       }
-               } else {
+               if ( done_auto_lookup ) {
                        DEBUG(4,("get_dc_list: no servers found\n")); 
+                       SAFE_FREE(auto_ip_list);
+                       return NT_STATUS_NO_LOGON_SERVERS;
+               }
+               if (internal_resolve_name(domain, 0x1C, sitename, ip_list, count,
+                                         resolve_order)) {
+                       return NT_STATUS_OK;
+               } else {
                        return NT_STATUS_NO_LOGON_SERVERS;
                }
        }
 
        if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) {
                DEBUG(3,("get_dc_list: malloc fail !\n"));
+               SAFE_FREE(auto_ip_list);
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -1554,15 +1617,23 @@ static NTSTATUS get_dc_list(const char *domain, struct ip_service **ip_list,
  Small wrapper function to get the DC list and sort it if neccessary.
 *********************************************************************/
 
-NTSTATUS get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only )
+NTSTATUS get_sorted_dc_list( const char *domain, const char *sitename, struct ip_service **ip_list, int *count, BOOL ads_only )
 {
        BOOL ordered;
        NTSTATUS status;
-       
-       DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n",
+       enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP;
+
+       DEBUG(8,("get_sorted_dc_list: attempting lookup for name %s (sitename %s) "
+               "using [%s]\n",
+               domain,
+               sitename ? sitename : "NULL",
                (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, sitename, ip_list, count, lookup_type, &ordered);
        if (!NT_STATUS_IS_OK(status)) {
                return status; 
        }
@@ -1574,3 +1645,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, const char *sitename, struct ip_service **ip_list, int *count)
+{
+       BOOL ordered;
+       NTSTATUS status;
+
+       *count = 0;
+       *ip_list = NULL;
+
+       status = get_dc_list(realm, sitename, 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;
+}