windows-cellservdb-lookup-20090525
authorJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 25 May 2009 23:06:16 +0000 (23:06 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 25 May 2009 23:06:16 +0000 (23:06 +0000)
LICENSE MIT

Add a new Registry distribution method for CellServDB info.

The CellServDB registry schema is as follows:

 HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\
   "LinkedCell"    REG_SZ "[cellname]"
   "Description"   REG_SZ "[comment]"
   "ForceDNS"      DWORD  {0,1}

 HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\[servername]\
   "HostName"      REG_SZ "[hostname]"
   "IPv4Address"   REG_SZ "[address]"
   "IPv6Address"   REG_SZ "[address]"   <future>
   "Comment"       REG_SZ "[comment]"
   "Rank"          DWORD  "0..65535"
   "Clone"         DWORD  "{0,1}"       <future - server only>
   "vlserver"      DWORD  "7003"        <future>
   "ptserver"      DWORD  ...           <future>

 ForceDNS is implied non-zero if there are no [servername]
 keys under the [cellname] key.  Otherwise, ForceDNS is zero.
 If [servername] keys are specified and none of them evaluate
 to a valid server configuration, the return code is success.
 This prevents failover to the CellServDB file or DNS.

Registry distributed info takes precedence over the CellServDB file.

Registry support has been added to both the Windows specific cm_config
interface and the auth/cellconfig interface utilized by aklog, the
services, and the vast majority of support commands.

Enhance the DNS lookup for Cell vlserver info to support ranking info
which is used with _vlserver._udp SRV record lookups when AFSDB records
are not present.  Priorities become ranks.

12 files changed:
src/WINNT/afsd/afskfw.c
src/WINNT/afsd/cm.h
src/WINNT/afsd/cm_cell.c
src/WINNT/afsd/cm_cell.h
src/WINNT/afsd/cm_config.c
src/WINNT/afsd/cm_config.h
src/WINNT/afsd/cm_dns.c
src/WINNT/afsd/cm_dns.h
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/libafsconf.def
src/WINNT/afsd/smb.c
src/auth/cellconfig.c

index 7653574..1836b4a 100644 (file)
@@ -76,6 +76,7 @@
 #include <rx/rxkad.h>
 
 #include <WINNT\afsreg.h>
+#include "cm.h"
 
 /*
  * TIMING _____________________________________________________________________
@@ -375,7 +376,7 @@ FUNC_INFO lsa_fi[] = {
 
 /* Static Prototypes */
 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
-static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
+static long get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short);
 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
            void *data, const char *name, const char *banner, int num_prompts,
@@ -3390,7 +3391,7 @@ afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
 /**************************************/
 /* KFW_AFS_get_cellconfig():          */
 /**************************************/
-int 
+int
 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
 {
     int        rc;
@@ -3409,8 +3410,9 @@ KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_
     if (strlen(cell) == 0)
         strcpy(cell, local_cell);
 
-    /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
-    rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
+    rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
+    if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
+        rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
 #ifdef AFS_AFSDB_ENV
     if (rc != 0) {
         int ttl;
@@ -3430,7 +3432,7 @@ KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_
 /* get_cellconfig_callback():         */
 /**************************************/
 static long 
-get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
+get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
 {
     struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
 
index 5ce70a9..bc63b89 100644 (file)
 #define CM_ERROR_NOSUCHDEVICE           (CM_ERROR_BASE+58)
 #define CM_ERROR_LOCK_NOT_GRANTED       (CM_ERROR_BASE+59)
 #define CM_ERROR_NOTINCACHE             (CM_ERROR_BASE+60)
+#define CM_ERROR_FORCE_DNS_LOOKUP       (CM_ERROR_BASE+61)
 
 /* Used by cm_FollowMountPoint and cm_FindVolumeByName */
 /* And as an index in cm_volume_t */
index a2a012a..12bbbf5 100644 (file)
@@ -28,7 +28,7 @@ osi_rwlock_t cm_cellLock;
  *
  * At the present time the return value is ignored by the caller.
  */
-long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *hostnamep)
+long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *hostnamep, unsigned short ipRank)
 {
     cm_server_t *tsp;
     cm_serverRef_t *tsrp;
@@ -54,6 +54,8 @@ long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *hostnamep)
     else
         tsp = cm_NewServer(addrp, CM_SERVER_VLDB, cellp, NULL, probe ? 0 : CM_FLAG_NOPROBE);
 
+    tsp->ipRank = ipRank;
+
     /* Insert the vlserver into a sorted list, sorted by server rank */
     tsrp = cm_NewServerRef(tsp, 0);
     cm_InsertServerList(&cellp->vlServersp, tsrp);
@@ -99,7 +101,9 @@ cm_cell_t *cm_UpdateCell(cm_cell_t * cp, afs_uint32 flags)
 
         rock.cellp = cp;
         rock.flags = flags;
-        code = cm_SearchCellFileEx(cp->name, NULL, cp->linkedName, cm_AddCellProc, &rock);
+        code = cm_SearchCellRegistry(1, cp->name, NULL, cp->linkedName, cm_AddCellProc, &rock);
+        if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
+            code = cm_SearchCellFileEx(cp->name, NULL, cp->linkedName, cm_AddCellProc, &rock);
         if (code == 0) {
             lock_ObtainMutex(&cp->mx);
            cp->timeout = time(0) + 7200;
@@ -271,7 +275,9 @@ cm_cell_t *cm_GetCell_Gen(char *namep, char *newnamep, afs_uint32 flags)
 
         rock.cellp = cp;
         rock.flags = flags;
-        code = cm_SearchCellFileEx(namep, fullname, linkedName, cm_AddCellProc, &rock);
+        code = cm_SearchCellRegistry(1, namep, fullname, linkedName, cm_AddCellProc, &rock);
+        if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
+            code = cm_SearchCellFileEx(namep, fullname, linkedName, cm_AddCellProc, &rock);
         if (code) {
             osi_Log4(afsd_logp,"in cm_GetCell_gen cm_SearchCellFileEx(%s) returns code= %d fullname= %s linkedName= %s", 
                       osi_LogSaveString(afsd_logp,namep), code, osi_LogSaveString(afsd_logp,fullname),
index 56fcfdc..b592153 100644 (file)
@@ -72,7 +72,8 @@ extern void cm_AddCellToNameHashTable(cm_cell_t * cellp);
 
 extern void cm_AddCellToIDHashTable(cm_cell_t * cellp);
 
-extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
+extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep, 
+                           unsigned short ipRank);
 
 extern cm_cell_t *cm_UpdateCell(cm_cell_t * cp, afs_uint32 flags);
 
index c153066..04e3558 100644 (file)
@@ -294,7 +294,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                     vlSockAddr.sin_family = AF_INET;
                     /* sin_port supplied by connection code */
                    if (procp)
-                       (*procp)(rockp, &vlSockAddr, valuep);
+                       (*procp)(rockp, &vlSockAddr, valuep, 0);
                     foundCell = 1;
                }
                 if (!thp) {
@@ -318,7 +318,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                         vlSockAddr.sin_family = AF_INET;
                         /* sin_port supplied by connection code */
                         if (procp)
-                            (*procp)(rockp, &vlSockAddr, valuep);
+                            (*procp)(rockp, &vlSockAddr, valuep, 0);
                         foundCell = 1;
                     }
                 }
@@ -330,14 +330,339 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
     return (foundCell) ? 0 : -11;
 }
 
+/*
+ * The CellServDB registry schema is as follows:
+ *
+ * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\
+ *   "LinkedCell"    REG_SZ "[cellname]" 
+ *   "Description"   REG_SZ "[comment]"
+ *   "ForceDNS"      DWORD  {0,1}
+ *
+ * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\[servername]\
+ *   "HostName"      REG_SZ "[hostname]" 
+ *   "IPv4Address"   REG_SZ "[address]" 
+ *   "IPv6Address"   REG_SZ "[address]"   <future>
+ *   "Comment"       REG_SZ "[comment]"
+ *   "Rank"          DWORD  "0..65535"
+ *   "Clone"         DWORD  "{0,1}"
+ *   "vlserver"      DWORD  "7003"        <future>
+ *   "ptserver"      DWORD  ...           <future>
+ *
+ * ForceDNS is implied non-zero if there are no [servername]
+ * keys under the [cellname] key.  Otherwise, ForceDNS is zero.
+ * If [servername] keys are specified and none of them evaluate
+ * to a valid server configuration, the return code is success.
+ * This prevents failover to the CellServDB file or DNS.
+ */
+long cm_SearchCellRegistry(afs_uint32 client, 
+                           char *cellNamep, char *newCellNamep,
+                           char *linkedNamep,
+                           cm_configProc_t *procp, void *rockp)
+{
+    HKEY hkCellServDB = 0, hkCellName = 0, hkServerName = 0;
+    DWORD dwType, dwSize;
+    DWORD dwCells, dwServers, dwForceDNS;
+    DWORD dwIndex, dwRank;
+    unsigned short ipRank;
+    LONG code;
+    FILETIME ftLastWriteTime;
+    char szCellName[CELL_MAXNAMELEN];
+    char szServerName[MAXHOSTCHARS];
+    char szHostName[MAXHOSTCHARS];
+    char szAddr[64];
+    struct hostent *thp;
+    struct sockaddr_in vlSockAddr;
+    char * s;
+
+    if ( IsWindowsModule(cellNamep) )
+       return -1;
+
+    /* No Server CellServDB list (yet) */
+    if ( !client )
+        return CM_ERROR_NOSUCHCELL;
+
+    if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+                      AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
+                      0,
+                      KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                      &hkCellServDB) != ERROR_SUCCESS)
+        return CM_ERROR_NOSUCHCELL;
+
+    if (RegOpenKeyEx( hkCellServDB, 
+                      cellNamep,
+                      0,
+                      KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                      &hkCellName) != ERROR_SUCCESS) {
+        BOOL bFound = 0;
+
+        /* We did not find an exact match.  Much search for partial matches. */
+
+        code = RegQueryInfoKey( hkCellServDB,
+                                NULL,  /* lpClass */
+                                NULL,  /* lpcClass */
+                                NULL,  /* lpReserved */
+                                &dwCells,  /* lpcSubKeys */
+                                NULL,  /* lpcMaxSubKeyLen */
+                                NULL,  /* lpcMaxClassLen */
+                                NULL,  /* lpcValues */
+                                NULL,  /* lpcMaxValueNameLen */
+                                NULL,  /* lpcMaxValueLen */
+                                NULL,  /* lpcbSecurityDescriptor */
+                                &ftLastWriteTime /* lpftLastWriteTime */
+                                );
+        if (code != ERROR_SUCCESS)
+            dwCells = 0;
+
+        /* 
+         * We search the entire list to ensure that there is only
+         * one prefix match.  If there is more than one, we return none.
+         */
+        for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
+            dwSize = CELL_MAXNAMELEN;
+            code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
+                                 NULL, NULL, &ftLastWriteTime);
+            if (code != ERROR_SUCCESS)
+                continue;
+            szCellName[CELL_MAXNAMELEN-1] = '\0';
+            strlwr(szCellName);
+
+            /* if not a prefix match, try the next key */
+            if (strncmp(cellNamep, szCellName, strlen(cellNamep)))
+                continue;
+
+            /* If we have a prefix match and we already found another
+             * match, return neither */
+            if (hkCellName) {
+                bFound = 0;
+                RegCloseKey( hkCellName);
+                break;
+            }
+
+            if (RegOpenKeyEx( hkCellServDB, 
+                              szCellName,
+                              0,
+                              KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                              &hkCellName) != ERROR_SUCCESS)
+                continue;
+
+            if (newCellNamep) {
+                strncpy(newCellNamep, szCellName, CELL_MAXNAMELEN);
+                newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+            }
+            bFound = 1;
+        }
+
+        if ( !bFound ) {
+            if (newCellNamep)
+                newCellNamep[0] = '\0';
+            RegCloseKey(hkCellServDB);
+            return CM_ERROR_NOSUCHCELL;
+        }
+    } else if (newCellNamep) {
+        strncpy(newCellNamep, cellNamep, CELL_MAXNAMELEN);
+        newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+        strlwr(newCellNamep);
+    }
+
+    if (linkedNamep) {
+        dwSize = CELL_MAXNAMELEN;
+        code = RegQueryValueEx(hkCellName, "LinkedCell", NULL, &dwType,
+                                (BYTE *) linkedNamep, &dwSize);
+        if (code == ERROR_SUCCESS && dwType == REG_SZ) {
+            linkedNamep[CELL_MAXNAMELEN-1] = '\0';
+            strlwr(linkedNamep);
+        } else {
+            linkedNamep[0] = '\0';
+        }
+    }
+
+    /* Check to see if DNS lookups are required */
+    dwSize = sizeof(DWORD);
+    code = RegQueryValueEx(hkCellName, "ForceDNS", NULL, &dwType,
+                            (BYTE *) &dwForceDNS, &dwSize);
+    if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
+        if (dwForceDNS)
+            goto done;
+    } else {
+        dwForceDNS = 0;
+    }
+
+    /* 
+     * Using the defined server list.  Enumerate and populate
+     * the server list for the cell.
+     */
+    code = RegQueryInfoKey( hkCellName,
+                            NULL,  /* lpClass */
+                            NULL,  /* lpcClass */
+                            NULL,  /* lpReserved */
+                            &dwServers,  /* lpcSubKeys */
+                            NULL,  /* lpcMaxSubKeyLen */
+                            NULL,  /* lpcMaxClassLen */
+                            NULL,  /* lpcValues */
+                            NULL,  /* lpcMaxValueNameLen */
+                            NULL,  /* lpcMaxValueLen */
+                            NULL,  /* lpcbSecurityDescriptor */
+                            &ftLastWriteTime /* lpftLastWriteTime */
+                            );
+    if (code != ERROR_SUCCESS)
+        dwServers = 0;
+
+    for ( dwIndex = 0; dwIndex < dwServers; dwIndex++ ) {
+        dwSize = MAXHOSTCHARS;
+        code = RegEnumKeyEx( hkCellName, dwIndex, szServerName, &dwSize, NULL, 
+                             NULL, NULL, &ftLastWriteTime);
+        if (code != ERROR_SUCCESS)
+            continue;
+
+        szServerName[MAXHOSTCHARS-1] = '\0';
+        if (RegOpenKeyEx( hkCellName, 
+                          szServerName,
+                          0,
+                          KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                          &hkServerName) != ERROR_SUCCESS)
+            continue;
+
+        /* We have a handle to a valid server key.  Now we need 
+         * to add the server to the cell */
+        
+        /* First, see if there is an alternate hostname specified */
+        dwSize = MAXHOSTCHARS;
+        code = RegQueryValueEx(hkServerName, "HostName", NULL, &dwType,
+                                (BYTE *) szHostName, &dwSize);
+        if (code == ERROR_SUCCESS && dwType == REG_SZ) {
+            szHostName[MAXHOSTCHARS-1] = '\0';
+            strlwr(szHostName);
+            s = szHostName;
+        } else {
+            s = szServerName;
+        }
+
+        dwSize = sizeof(DWORD);
+        code = RegQueryValueEx(hkServerName, "Rank", NULL, &dwType,
+                                (BYTE *) &dwRank, &dwSize);
+        if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
+            ipRank = (unsigned short)(dwRank <= 65535 ? dwRank : 65535);
+        } else {
+            ipRank = 0;
+        }
+
+        dwSize = sizeof(szAddr);
+        code = RegQueryValueEx(hkServerName, "IPv4Address", NULL, &dwType,
+                                (BYTE *) szAddr, &dwSize);
+        if (code == ERROR_SUCCESS && dwType == REG_SZ) {
+            szAddr[63] = '\0';
+        } else {
+            szAddr[0] = '\0';
+        }
+
+        WSASetLastError(0);
+        thp = gethostbyname(s);
+        if (thp) {
+            memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr, sizeof(long));
+            vlSockAddr.sin_family = AF_INET;
+            /* sin_port supplied by connection code */
+            if (procp)
+                (*procp)(rockp, &vlSockAddr, s, ipRank);
+        } else if (szAddr[0]) {
+            afs_uint32 ip_addr;
+            unsigned int c1, c2, c3, c4;
+
+            /* Since there is no gethostbyname() data 
+             * available we will read the IP address
+             * stored in the CellServDB file
+             */
+            code = sscanf(szAddr, " %u.%u.%u.%u",
+                           &c1, &c2, &c3, &c4);
+            if (code == 4 && c1<256 && c2<256 && c3<256 && c4<256) {
+                unsigned char * tp = (unsigned char *) &ip_addr;
+                *tp++ = c1;
+                *tp++ = c2;
+                *tp++ = c3;
+                *tp++ = c4;
+                memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
+                        sizeof(long));
+                vlSockAddr.sin_family = AF_INET;
+                /* sin_port supplied by connection code */
+                if (procp)
+                    (*procp)(rockp, &vlSockAddr, s, ipRank);
+            }
+        }
+
+        RegCloseKey( hkServerName);
+    }
+
+  done:
+    RegCloseKey(hkCellName);
+    RegCloseKey(hkCellServDB);
+
+    return ((dwForceDNS || dwServers == 0) ? CM_ERROR_FORCE_DNS_LOOKUP : 0);
+}
+
+long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellRegistryProc_t *procp, void *rockp)
+{
+    HKEY hkCellServDB = 0;
+    DWORD dwType, dwSize;
+    DWORD dwCells;
+    DWORD dwIndex;
+    LONG code;
+    FILETIME ftLastWriteTime;
+    char szCellName[CELL_MAXNAMELEN];
+
+    /* No server CellServDB in the registry. */
+    if (!client || procp == NULL)
+        return 0;
+
+    if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+                      AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
+                      0,
+                      KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                      &hkCellServDB) != ERROR_SUCCESS)
+        return 0;
+
+    code = RegQueryInfoKey( hkCellServDB,
+                            NULL,  /* lpClass */
+                            NULL,  /* lpcClass */
+                            NULL,  /* lpReserved */
+                            &dwCells,  /* lpcSubKeys */
+                            NULL,  /* lpcMaxSubKeyLen */
+                            NULL,  /* lpcMaxClassLen */
+                            NULL,  /* lpcValues */
+                            NULL,  /* lpcMaxValueNameLen */
+                            NULL,  /* lpcMaxValueLen */
+                            NULL,  /* lpcbSecurityDescriptor */
+                            &ftLastWriteTime /* lpftLastWriteTime */
+                            );
+    if (code != ERROR_SUCCESS)
+        dwCells = 0;
+
+    /* 
+     * Enumerate each Cell and 
+     */
+    for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
+        dwSize = CELL_MAXNAMELEN;
+        code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
+                             NULL, NULL, &ftLastWriteTime);
+        if (code != ERROR_SUCCESS)
+            continue;
+        szCellName[CELL_MAXNAMELEN-1] = '\0';
+        strlwr(szCellName);
+
+        (*procp)(rockp, szCellName);
+    }
+
+    RegCloseKey(hkCellServDB);
+    return 0;
+}
+
 /* newCellNamep is required to be CELL_MAXNAMELEN in size */
 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
-               cm_configProc_t *procp, void *rockp)
+                        cm_configProc_t *procp, void *rockp)
 {
 #ifdef AFS_AFSDB_ENV
     int rc;
     int  cellHostAddrs[AFSMAXCELLHOSTS];
     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
+    unsigned short ipRanks[AFSMAXCELLHOSTS];
     int numServers;
     int i;
     struct sockaddr_in vlSockAddr;
@@ -346,7 +671,7 @@ long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
 #endif
     if ( IsWindowsModule(cellNamep) )
        return -1;
-    rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, &numServers, ttl);
+    rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, ipRanks, &numServers, ttl);
     if (rc == 0 && numServers > 0) {     /* found the cell */
         for (i = 0; i < numServers; i++) {
             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
@@ -354,12 +679,12 @@ long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
             vlSockAddr.sin_family = AF_INET;
             /* sin_port supplied by connection code */
             if (procp)
-                (*procp)(rockp, &vlSockAddr, cellHostNames[i]);
-            if (newCellNamep) {
-                strncpy(newCellNamep,cellNamep,CELL_MAXNAMELEN);
-                newCellNamep[CELL_MAXNAMELEN-1] = '\0';
-                strlwr(newCellNamep);
-            }
+                (*procp)(rockp, &vlSockAddr, cellHostNames[i], ipRanks[i]);
+        }
+        if (newCellNamep) {
+            strncpy(newCellNamep,cellNamep,CELL_MAXNAMELEN);
+            newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+            strlwr(newCellNamep);
         }
         return 0;   /* found cell */
     }
index c6fb5ab..a6b0a57 100644 (file)
@@ -26,7 +26,9 @@
 
 typedef FILE cm_configFile_t;
 
-typedef long (cm_configProc_t)(void *rockp, struct sockaddr_in *addrp, char *namep);
+typedef long (cm_configProc_t)(void *rockp, struct sockaddr_in *addrp, char *namep, unsigned short);
+
+typedef long (cm_enumCellRegistryProc_t)(void *rockp, char *cellNamep);
 
 extern long cm_GetRootCellName(char *namep);
 
@@ -37,6 +39,15 @@ extern long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                                 char *linkedNamep,
                                 cm_configProc_t *procp, void *rockp);
 
+extern long cm_SearchCellRegistry(afs_uint32 client, 
+                                  char *cellNamep, char *newCellNamep,
+                                  char *linkedNamep,
+                                  cm_configProc_t *procp, void *rockp);
+
+extern long cm_EnumerateCellRegistry(afs_uint32 client, 
+                                     cm_enumCellRegistryProc_t *procp, 
+                                     void *rockp);
+
 extern long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
                                cm_configProc_t *procp, void *rockp);
 
index e23daeb..e5fdb13 100644 (file)
@@ -482,7 +482,8 @@ void printReplyBuffer_AFSDB(PDNS_HDR replyBuff)
 
 };
 
-void processReplyBuffer_AFSDB(SOCKET commSock, PDNS_HDR replyBuff, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], int *numServers, int *ttl)
+void processReplyBuffer_AFSDB(SOCKET commSock, PDNS_HDR replyBuff, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], 
+                              unsigned short ipRanks[], int *numServers, int *ttl)
   /*PAFS_SRV_LIST (srvList)*/
 {
   u_char *ptr = (u_char *) replyBuff;
@@ -535,6 +536,7 @@ void processReplyBuffer_AFSDB(SOCKET commSock, PDNS_HDR replyBuff, int *cellHost
       memcpy(&cellHostAddrs[srvCount], &addr.s_addr, sizeof(addr.s_addr));
          strncpy(cellHostNames[srvCount], hostName, CELL_MAXNAMELEN);
          cellHostNames[srvCount][CELL_MAXNAMELEN-1] = '\0';
+      ipRanks[srvCount] = 0;
       srvCount++;
     }
     else {
@@ -621,7 +623,7 @@ int DNSgetAddr(SOCKET commSock, char *hostName, struct in_addr *iNet)
 #endif /* DNSAPI_ENV */
 
 int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], 
-                 int *numServers, int *ttl)
+                 unsigned short ipRanks[], int *numServers, int *ttl)
 {
 #ifndef DNSAPI_ENV
     SOCKET commSock;
@@ -664,6 +666,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
 
     rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
     if (rc < 0) {
+        closesocket(commSock);
         fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
         *numServers = 0;
         return -1;
@@ -673,7 +676,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
   
     /*printReplyBuffer_AFSDB(pDNShdr);*/
     if (pDNShdr)
-        processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
+        processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, ipRanks, numServers, ttl);
     else
         *numServers = 0;
 
@@ -683,7 +686,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
     else
         return 0;
 #else /* DNSAPI_ENV */
-    PDNS_RECORD pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
+    PDNS_RECORD pDnsCell, pDnsIter, pDnsVol, pDnsVolIter, pDnsCIter;
     int i;
     struct sockaddr_in vlSockAddr;
     char query[1024];
@@ -707,10 +710,11 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
 
         /* go through the returned records */
         for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
-            /* if we find an AFSDB record with Preference set to 1, we found a volserver */
+            /* if we find an AFSDB record with Preference set to 1, we found a afs3-vlserver */
             if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
                 StringCbCopyA(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
                               pDnsIter->Data.Afsdb.pNameExchange);
+                ipRanks[*numServers] = 0;
                 (*numServers)++;
                 
                 if (!*ttl) 
@@ -726,14 +730,14 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
         /* now check if there are any A records in the results */
         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
             if(pDnsIter->wType == DNS_TYPE_A)
-                /* check if its for one of the volservers */
+                /* check if its for one of the afs3-vlservers */
                 for (i=0;i<*numServers;i++)
                     if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
         }
 
         for (i=0;i<*numServers;i++) {
-            /* if we don't have an IP yet, then we should try resolving the volserver hostname
+            /* if we don't have an IP yet, then we should try resolving the afs3-vlserver hostname
             in a separate query. */
             if (!cellHostAddrs[i]) {
                 if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
@@ -756,13 +760,83 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
                             /* TODO: if the additional section is missing, then do another lookup for the CNAME */
                         }
                     }
-                    /* we are done with the volserver lookup */
+                    /* we are done with the afs3-vlserver lookup */
                     DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
                 }
             }
         }
         DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
     }
+    else {
+        /* query the SRV _afs3-vlserver._udp records of cell */
+        StringCbPrintf(query, sizeof(query), "_afs3-vlserver._udp.%s", cellName);
+        if (query[strlen(query)-1] != '.') {
+            StringCbCatA(query, sizeof(query), ".");
+        }
+        
+        if (DnsQuery_A(query, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
+            memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
+
+            /* go through the returned records */
+            for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
+                /* if we find an SRV record, we found a afs3-vlserver */
+                if (pDnsIter->wType == DNS_TYPE_SRV) {
+                    StringCbCopyA(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
+                                   pDnsIter->Data.SRV.pNameTarget);
+                    ipRanks[*numServers] = pDnsIter->Data.SRV.wPriority;
+                    (*numServers)++;
+
+                    if (!*ttl) 
+                        *ttl = pDnsIter->dwTtl;
+                    if (*numServers == AFSMAXCELLHOSTS) 
+                        break;
+                }
+            }
+
+            for (i=0;i<*numServers;i++) 
+                cellHostAddrs[i] = 0;
+
+            /* now check if there are any A records in the results */
+            for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
+                if(pDnsIter->wType == DNS_TYPE_A)
+                    /* check if its for one of the afs3-vlservers */
+                    for (i=0;i<*numServers;i++)
+                        if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
+                            cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
+            }
+
+            for (i=0;i<*numServers;i++) {
+                /* if we don't have an IP yet, then we should try resolving the afs3-vlserver hostname
+                in a separate query. */
+                if (!cellHostAddrs[i]) {
+                    if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
+                        for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
+                            /* if we get an A record, keep it */
+                            if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
+                                cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
+                                break;
+                            }
+                            /* if we get a CNAME, look for a corresponding A record */
+                            if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
+                                for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
+                                    if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf8(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
+                                        cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
+                                        break;
+                                    }
+                                }
+                                if (cellHostAddrs[i]) 
+                                    break;
+                                /* TODO: if the additional section is missing, then do another lookup for the CNAME */
+                            }
+                        }
+                        /* we are done with the afs3-vlserver lookup */
+                        DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
+                    }
+                }
+            }
+            DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
+        }
+    }
 
     if ( *numServers > 0 )
         return 0;
@@ -773,6 +847,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
 
 int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
                   cm_unichar_t cellHostNames[][MAXHOSTCHARS], 
+                  unsigned short ipRanks[],
                   int *numServers, int *ttl)
 {
 #ifdef DNSAPI_ENV
@@ -801,10 +876,11 @@ int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
 
         /* go through the returned records */
         for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
-            /* if we find an AFSDB record with Preference set to 1, we found a volserver */
+            /* if we find an AFSDB record with Preference set to 1, we found a afs3-vlserver */
             if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
                 StringCbCopyW(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
                               pDnsIter->Data.Afsdb.pNameExchange);
+                ipRanks[*numServers] = 0;
                 (*numServers)++;
                 
                 if (!*ttl) 
@@ -820,14 +896,14 @@ int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
         /* now check if there are any A records in the results */
         for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
             if(pDnsIter->wType == DNS_TYPE_A)
-                /* check if its for one of the volservers */
+                /* check if its for one of the afs3-vlservers */
                 for (i=0;i<*numServers;i++)
                     if(cm_stricmp_utf16(pDnsIter->pName, cellHostNames[i]) == 0)
                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
         }
 
         for (i=0;i<*numServers;i++) {
-            /* if we don't have an IP yet, then we should try resolving the volserver hostname
+            /* if we don't have an IP yet, then we should try resolving the afs3-vlserver hostname
                in a separate query. */
             if (!cellHostAddrs[i]) {
                 if (DnsQuery_W(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL,
@@ -851,13 +927,85 @@ int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
                             /* TODO: if the additional section is missing, then do another lookup for the CNAME */
                         }
                     }
-                    /* we are done with the volserver lookup */
+                    /* we are done with the afs3-vlserver lookup */
                     DnsRecordListFree((PDNS_RECORD) pDnsVol, DnsFreeRecordListDeep);
                 }
             }
         }
         DnsRecordListFree((PDNS_RECORD) pDnsCell, DnsFreeRecordListDeep);
     }
+    else {
+        /* query the SRV _afs3-vlserver._udp records of cell */
+        StringCbPrintfW(query, sizeof(query), L"_afs3-vlserver._udp.%S", cellName);
+        if (query[wcslen(query)-1] != L'.') {
+            StringCbCatW(query, sizeof(query), L".");
+        }
+
+        if (DnsQuery_W(query, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD *) &pDnsCell,
+                        NULL) == ERROR_SUCCESS) {
+            memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
+
+            /* go through the returned records */
+            for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
+                /* if we find an SRV record, we found a afs3-vlserver */
+                if (pDnsIter->wType == DNS_TYPE_SRV) {
+                    StringCbCopyW(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
+                                   pDnsIter->Data.SRV.pNameTarget);
+                    ipRanks[*numServers] = pDnsIter->Data.SRV.wPriority;
+                    (*numServers)++;
+                
+                    if (!*ttl) 
+                        *ttl = pDnsIter->dwTtl;
+                    if (*numServers == AFSMAXCELLHOSTS) 
+                        break;
+                }
+            }
+
+            for (i=0;i<*numServers;i++) 
+                cellHostAddrs[i] = 0;
+
+            /* now check if there are any A records in the results */
+            for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
+                if(pDnsIter->wType == DNS_TYPE_A)
+                    /* check if its for one of the afs3-vlservers */
+                    for (i=0;i<*numServers;i++)
+                        if(cm_stricmp_utf16(pDnsIter->pName, cellHostNames[i]) == 0)
+                            cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
+            }
+
+            for (i=0;i<*numServers;i++) {
+                /* if we don't have an IP yet, then we should try resolving the afs3-vlserver hostname
+                in a separate query. */
+                if (!cellHostAddrs[i]) {
+                    if (DnsQuery_W(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL,
+                                    (PDNS_RECORD *) &pDnsVol, NULL) == ERROR_SUCCESS) {
+                        for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
+                            /* if we get an A record, keep it */
+                            if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
+                                cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
+                                break;
+                            }
+                            /* if we get a CNAME, look for a corresponding A record */
+                            if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
+                                for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
+                                    if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf16(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
+                                        cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
+                                        break;
+                                    }
+                                }
+                                if (cellHostAddrs[i]) 
+                                    break;
+                                /* TODO: if the additional section is missing, then do another lookup for the CNAME */
+                            }
+                        }
+                        /* we are done with the afs3-vlserver lookup */
+                        DnsRecordListFree((PDNS_RECORD) pDnsVol, DnsFreeRecordListDeep);
+                    }
+                }
+            }
+            DnsRecordListFree((PDNS_RECORD) pDnsCell, DnsFreeRecordListDeep);
+        }
+    }
 
     if ( *numServers > 0 )
         return 0;
index ed41d9c..410ed8c 100644 (file)
 
 /* this function will continue to return cell server
    names for the given cell, ending in null */
-int getAFSServer(char *cellname, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], int *numServers, int *ttl);
+int getAFSServer(char *cellname, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], 
+                 unsigned short ipRanks[], int *numServers, int *ttl);
 
 /* Same as above, but using cm_unichar_t.  Note that this functon will
    only be defined for DNSAPI_ENV. */
 int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
                   cm_unichar_t cellHostNames[][MAXHOSTCHARS], 
+                  unsigned short ipRanks[],
                   int *numServers, int *ttl);
 
 /* a supplement for the DJGPP gethostbyname ... which 
index c2b1e2b..bf3c9f4 100644 (file)
@@ -1408,7 +1408,9 @@ cm_IoctlNewCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
 
         rock.cellp = cp;
         rock.flags = 0;
-        code = cm_SearchCellFileEx(cp->name, cp->name, cp->linkedName, cm_AddCellProc, &rock);
+        code = cm_SearchCellRegistry(1, cp->name, cp->name, cp->linkedName, cm_AddCellProc, &rock);
+        if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
+            code = cm_SearchCellFileEx(cp->name, cp->name, cp->linkedName, cm_AddCellProc, &rock);
 #ifdef AFS_AFSDB_ENV
         if (code) {
             if (cm_dnsEnabled) {
index e5d8b40..9430bff 100644 (file)
@@ -25,3 +25,5 @@ EXPORTS
         afs_uuid_equal                  @18
         cm_GetCellServDB                @19
        cm_SearchCellFileEx             @20
+        cm_SearchCellRegistry           @21
+        cm_EnumerateCellRegistry        @22
index 70d5f4b..c164182 100644 (file)
@@ -2095,7 +2095,9 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         }
         /* Get the full name for this cell */
         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
-        code = cm_SearchCellFile(cellname, ftemp, 0, 0);
+        code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
+        if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
+            code = cm_SearchCellFile(cellname, ftemp, 0, 0);
 #ifdef AFS_AFSDB_ENV
         if (code && cm_dnsEnabled) {
             int ttl;
index 04a9942..2af281d 100644 (file)
@@ -62,6 +62,8 @@ RCSID
 #include "keys.h"
 #ifdef AFS_NT40_ENV
 #ifdef AFS_AFSDB_ENV
+#include <cm.h>
+#include <cm_config.h>
 /* cm_dns.h depends on cellconfig.h */
 #include <cm_nls.h>
 #include <cm_dns.h>
@@ -524,6 +526,69 @@ GetCellNT(struct afsconf_dir *adir)
        return GetCellUnix(adir);
     }
 }
+
+/* The following procedures and structs are used on Windows only
+ * to enumerate the Cell information distributed within the 
+ * Windows registry.  (See src/WINNT/afsd/cm_config.c)
+ */
+typedef struct _cm_enumCellRegistry {
+    afs_uint32 client;  /* non-zero if client query */
+    struct afsconf_dir *adir;
+} cm_enumCellRegistry_t;
+
+static long
+cm_serverConfigProc(void *rockp, struct sockaddr_in *addrp, 
+                    char *hostNamep, unsigned short rank)
+{
+    struct afsconf_cell *cellInfop = (struct afsconf_cell *)rockp;
+
+    if (cellInfop->numServers == MAXHOSTSPERCELL)
+        return 0;
+
+    cellInfop->hostAddr[cellInfop->numServers] = *addrp;
+    strncpy(cellInfop->hostName[cellInfop->numServers], hostNamep, MAXHOSTCHARS);
+    cellInfop->hostName[cellInfop->numServers][MAXHOSTCHARS-1] = '\0';
+    cellInfop->numServers++;
+
+    return 0;
+}
+
+static long
+cm_enumCellRegistryProc(void *rockp, char * cellNamep)
+{
+    long code;
+    cm_enumCellRegistry_t *enump = (cm_enumCellRegistry_t *)rockp;
+    char linkedName[256] = "";
+    int timeout = 0;
+    struct afsconf_entry *newEntry;
+
+
+    newEntry = malloc(sizeof(struct afsconf_entry));
+    if (newEntry == NULL)
+        return ENOMEM;
+    newEntry->cellInfo.numServers = 0;
+
+    code = cm_SearchCellRegistry(enump->client, cellNamep, NULL, linkedName, cm_serverConfigProc, &newEntry->cellInfo);
+    if (code == CM_ERROR_FORCE_DNS_LOOKUP)
+        code = cm_SearchCellByDNS(cellNamep, NULL, &timeout, cm_serverConfigProc, &newEntry->cellInfo);
+
+    if (code == 0) {
+        strncpy(newEntry->cellInfo.name, cellNamep, MAXCELLCHARS);
+        newEntry->cellInfo.name[MAXCELLCHARS-1];
+        if (linkedName[0])
+            newEntry->cellInfo.linkedCell = strdup(linkedName);
+        else
+            newEntry->cellInfo.linkedCell = NULL;
+        newEntry->cellInfo.timeout = timeout;
+        newEntry->cellInfo.flags = 0;
+
+        newEntry->next = enump->adir->entries;
+       enump->adir->entries = newEntry;
+    } else {
+        free(newEntry);
+    }
+    return code;
+}       
 #endif /* AFS_NT40_ENV */
 
 
@@ -539,10 +604,14 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
     afs_int32 i;
     char tbuffer[256], tbuf1[256];
     struct stat tstat;
+#ifdef AFS_NT40_ENV
+    cm_enumCellRegistry_t enumCellRegistry = {0, 0};
+#endif /* AFS_NT40_ENV */
 
     /* figure out the local cell name */
 #ifdef AFS_NT40_ENV
     i = GetCellNT(adir);
+    enumCellRegistry.adir = adir;
 #else
     i = GetCellUnix(adir);
 #endif
@@ -563,6 +632,9 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
     if (IsClientConfigDirectory(adir->name)) {
        /* NT client config dir */
        char *p;
+
+        enumCellRegistry.client = 1;
+
        if (!afssw_GetClientCellServDBDir(&p)) {
            strcompose(tbuffer, sizeof(tbuffer), p, "/",
                       AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
@@ -598,6 +670,19 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
     if (!tf) {
        return -1;
     }
+
+    /* The CellServDB file is now open.  
+     * The following code parses the contents of the 
+     * file and creates a list with the first cell entry
+     * in the CellServDB file at the end of the list.
+     * 
+     * No checking is performed for duplicates.
+     * The side effects of this process are that duplicate
+     * entries appended to the end of the CellServDB file
+     * take precedence and are found in a shorter period 
+     * of time.
+     */
+
     while (1) {
        tp = fgets(tbuffer, sizeof(tbuffer), tf);
        if (!tp)
@@ -670,6 +755,18 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
        adir->entries = curEntry;
     }
 
+#ifdef AFS_NT40_ENV
+     /* 
+      * Windows maintains a CellServDB list in the Registry
+      * that supercedes the contents of the CellServDB file.
+      * Prepending these entries to the head of the list 
+      * is sufficient to enforce the precedence.
+      */
+     cm_EnumerateCellRegistry( enumCellRegistry.client,
+                               cm_enumCellRegistryProc,
+                               &enumCellRegistry);
+#endif /* AFS_NT40_ENV */
+
     /* Read in the alias list */
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
 
@@ -989,13 +1086,14 @@ afsconf_GetAfsdbInfo(char *acellName, char *aservice,
     struct afsconf_entry DNSce;
     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
+    unsigned short ipRanks[AFSMAXCELLHOSTS];
     int numServers;
     int rc;
     int ttl;
 
     DNSce.cellInfo.numServers = 0;
     DNSce.next = NULL;
-    rc = getAFSServer(acellName, cellHostAddrs, cellHostNames, &numServers,
+    rc = getAFSServer(acellName, cellHostAddrs, cellHostNames, ipRanks, &numServers,
                      &ttl);
     /* ignore the ttl here since this code is only called by transitory programs
      * like klog, etc. */