Windows: preserve prior vlserver list on dns failure
[openafs.git] / src / WINNT / afsd / cm_config.c
index e43df19..44db379 100644 (file)
@@ -1,30 +1,32 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <afs/stds.h>
+
+#include <roken.h>
+
 #include <windows.h>
 #include <winsock2.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include <shlwapi.h>
+#include <strsafe.h>
 
 #include "afsd.h"
 #include <WINNT\afssw.h>
 #include <WINNT\afsreg.h>
 
-#include <afs/param.h>
-#include <afs/stds.h>
 #include <afs/cellconfig.h>
 
-#ifdef AFS_AFSDB_ENV
 #include "cm_dns.h"
 #include <afs/afsint.h>
-#endif
 
 static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
 {
@@ -32,7 +34,7 @@ static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
     char tc;
     int sawEquals;
     int sawBracket;
-        
+
     sawEquals = 0;
     sawBracket = 0;
     for(tp = lineBufferp; *tp; tp++) {
@@ -45,17 +47,17 @@ static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
        }
 
        /* comment or line end */
-        if (tc == '#' || tc == '\r' || tc == '\n') 
+        if (tc == '#' || tc == '\r' || tc == '\n')
             break;
 
        /* square bracket comment -- look for closing delim */
        if (tc == '[') {
-            sawBracket = 1; 
+            sawBracket = 1;
             continue;
-        }      
+        }
 
        /* space or tab */
-        if (tc == ' ' || tc == '\t') 
+        if (tc == ' ' || tc == '\t')
             continue;
 
         if (tc == '=') {
@@ -66,8 +68,8 @@ static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
         /* now we have a real character, put it in the appropriate bucket */
         if (sawEquals == 0) {
            *leftp++ = tc;
-        }      
-        else { 
+        }
+        else {
            *rightp++ = tc;
         }
     }
@@ -92,7 +94,8 @@ IsWindowsModule(const char * name)
     }
     p = strrchr(name, '.');
     if (p) {
-       if (i == 1 && 
+        /* as of 2009-09-04 these are not valid ICANN ccTLDs */
+       if (i == 1 &&
            (!cm_stricmp_utf8N(p,".dll") ||
             !cm_stricmp_utf8N(p,".exe") ||
             !cm_stricmp_utf8N(p,".ini") ||
@@ -138,6 +141,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
     int foundCell = 0;
     long code;
     int tracking = 1, partial = 0;
+    size_t len;
 
     if ( IsWindowsModule(cellNamep) )
        return -3;
@@ -146,13 +150,13 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
     if (*wdir)
         tfilep = fopen(wdir, "r");
 
-    if (!tfilep) 
+    if (!tfilep)
         return -2;
 
     bestp = fopen(wdir, "r");
-    
+
 #ifdef CELLSERV_DEBUG
-    osi_Log2(afsd_logp,"cm_searchfile fopen handle[%p], wdir[%s]", bestp, 
+    osi_Log2(afsd_logp,"cm_searchfile fopen handle[%p], wdir[%s]", bestp,
             osi_LogSaveString(afsd_logp,wdir));
 #endif
     /* have we seen the cell line for the guy we're looking for? */
@@ -182,7 +186,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                    return (foundCell? 0 : -3);
                }
            }
-        }      
+        }
 
         /* turn trailing cr or lf into null */
         tp = strrchr(lineBuffer, '\r');
@@ -205,7 +209,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                 return(foundCell ? 0 : -6);
             }
 
-            /* 
+            /*
              * terminate the cellname at the first white space
              * leaving 'tp' pointing to the next string if any
              */
@@ -216,7 +220,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                 if (*tp != '#') {
                     linkp = tp;
                     for (; tp && !isspace(*tp); tp++);
-                    if (tp) 
+                    if (tp)
                         *tp = '\0';
                 }
             }
@@ -225,18 +229,24 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
             if (stricmp(lineBuffer+1, cellNamep) == 0) {
                /* found the cell we're looking for */
                if (newCellNamep) {
-                   strncpy(newCellNamep, lineBuffer+1,CELL_MAXNAMELEN);
-                    newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+                    if (FAILED(StringCchCopy(newCellNamep, CELL_MAXNAMELEN, lineBuffer+1))) {
+                        fclose(tfilep);
+                        fclose(bestp);
+                        return(-1);
+                    }
                     strlwr(newCellNamep);
                 }
                 if (linkedNamep) {
-                    strncpy(linkedNamep, linkp ? linkp : "", CELL_MAXNAMELEN);
-                    linkedNamep[CELL_MAXNAMELEN-1] = '\0';
+                    if (FAILED(StringCchCopy(linkedNamep, CELL_MAXNAMELEN, linkp ? linkp : ""))) {
+                        fclose(tfilep);
+                        fclose(bestp);
+                        return(-1);
+                    }
                     strlwr(linkedNamep);
                 }
                 inRightCell = 1;
                tracking = 0;
-#ifdef CELLSERV_DEBUG                
+#ifdef CELLSERV_DEBUG
                osi_Log2(afsd_logp, "cm_searchfile is cell inRightCell[%p], linebuffer[%s]",
                         inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
 #endif
@@ -249,13 +259,19 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                    return -5;
                }
                if (newCellNamep) {
-                   strncpy(newCellNamep, lineBuffer+1,CELL_MAXNAMELEN);
-                    newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+                    if (FAILED(StringCchCopy(newCellNamep, CELL_MAXNAMELEN, lineBuffer+1))) {
+                        fclose(tfilep);
+                        fclose(bestp);
+                        return(-1);
+                    }
                     strlwr(newCellNamep);
                 }
                 if (linkedNamep) {
-                    strncpy(linkedNamep, linkp ? linkp : "", CELL_MAXNAMELEN);
-                    linkedNamep[CELL_MAXNAMELEN-1] = '\0';
+                    if (FAILED(StringCchCopy(linkedNamep, CELL_MAXNAMELEN, linkp ? linkp : ""))) {
+                        fclose(tfilep);
+                        fclose(bestp);
+                        return(-1);
+                    }
                     strlwr(linkedNamep);
                 }
                inRightCell = 0;
@@ -274,39 +290,72 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
             valuep++;  /* skip the "#" */
 
             valuep += strspn(valuep, " \t"); /* skip SP & TAB */
-            /* strip spaces and tabs in the end. They should not be there according to CellServDB format
-             * so do this just in case                        
+            /*
+             * strip spaces and tabs in the end. They should not be there according to CellServDB format
+             * so do this just in case
             */
-            while (valuep[strlen(valuep) - 1] == ' ' || valuep[strlen(valuep) - 1] == '\t') 
-                valuep[strlen(valuep) - 1] = '\0';
+            if(FAILED(StringCchLength(valuep, sizeof(lineBuffer), &len))) {
+                fclose(tfilep);
+                fclose(bestp);
+                return(-1);
+            } else {
+                len--;
+                while(isspace(valuep[len]))
+                    valuep[len--] = '\0';
+                while(isspace(*valuep))
+                    valuep++;
+            }
 
            if (inRightCell) {
+                char hostname[256];
+                int  i, isClone = 0;
+
+                isClone = (lineBuffer[0] == '[');
+
+                /* copy just the first word and ignore trailing white space */
+                for ( i=0; valuep[i] && !isspace(valuep[i]) && i<sizeof(hostname); i++)
+                    hostname[i] = valuep[i];
+                hostname[i] = '\0';
+
                /* add the server to the VLDB list */
                 WSASetLastError(0);
-                thp = gethostbyname(valuep);
+                thp = gethostbyname(hostname);
 #ifdef CELLSERV_DEBUG
                osi_Log3(afsd_logp,"cm_searchfile inRightCell thp[%p], valuep[%s], WSAGetLastError[%d]",
-                        thp, osi_LogSaveString(afsd_logp,valuep), WSAGetLastError());
+                        thp, osi_LogSaveString(afsd_logp,hostname), WSAGetLastError());
 #endif
                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, valuep, 0);
-                    foundCell = 1;
+                    int foundAddr = 0;
+                    for (i=0 ; thp->h_addr_list[i]; i++) {
+                        if (thp->h_addrtype != AF_INET)
+                            continue;
+                        memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr_list[i],
+                               sizeof(long));
+                        vlSockAddr.sin_port = htons(7003);
+                        vlSockAddr.sin_family = AF_INET;
+                        /* sin_port supplied by connection code */
+                        if (procp)
+                            (*procp)(rockp, &vlSockAddr, hostname, 0);
+                        foundAddr = 1;
+                    }
+                    /* if we didn't find a valid address, force the use of the specified one */
+                    if (!foundAddr)
+                        thp = NULL;
                }
                 if (!thp) {
                     afs_uint32 ip_addr;
                    unsigned int c1, c2, c3, c4;
-                    
-                    /* Since there is no gethostbyname() data 
+
+                    /* Since there is no gethostbyname() data
                     * available we will read the IP address
                     * stored in the CellServDB file
                      */
-                    code = sscanf(lineBuffer, " %u.%u.%u.%u",
-                                   &c1, &c2, &c3, &c4);
+                    if (isClone)
+                        code = sscanf(lineBuffer, "[%u.%u.%u.%u]",
+                                      &c1, &c2, &c3, &c4);
+                    else
+                        code = sscanf(lineBuffer, " %u.%u.%u.%u",
+                                      &c1, &c2, &c3, &c4);
                     if (code == 4 && c1<256 && c2<256 && c3<256 && c4<256) {
                         tp = (unsigned char *) &ip_addr;
                         *tp++ = c1;
@@ -315,13 +364,14 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
                         *tp++ = c4;
                         memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
                                 sizeof(long));
+                        vlSockAddr.sin_port = htons(7003);
                         vlSockAddr.sin_family = AF_INET;
                         /* sin_port supplied by connection code */
                         if (procp)
-                            (*procp)(rockp, &vlSockAddr, valuep, 0);
-                        foundCell = 1;
+                            (*procp)(rockp, &vlSockAddr, hostname, 0);
                     }
                 }
+                foundCell = 1;
             }
         }      /* a vldb line */
     }          /* while loop processing all lines */
@@ -330,23 +380,86 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
     return (foundCell) ? 0 : -11;
 }
 
+long
+cm_EnumerateCellFile(afs_uint32 client, cm_enumCellProc_t *procp, void *rockp)
+{
+    char wdir[MAX_PATH]="";
+    FILE *tfilep = NULL;
+    char *tp;
+    char lineBuffer[257];
+
+    if (!procp)
+        return 0;
+
+    cm_GetCellServDB(wdir, sizeof(wdir));
+    if (*wdir)
+        tfilep = fopen(wdir, "r");
+
+    if (!tfilep)
+        return -2;
+
+#ifdef CELLSERV_DEBUG
+    osi_Log2(afsd_logp,"cm_enumfile fopen handle[%p], wdir[%s]", tfilep,
+            osi_LogSaveString(afsd_logp,wdir));
+#endif
+    while (1) {
+        tp = fgets(lineBuffer, sizeof(lineBuffer), tfilep);
+        if (tp == NULL && feof(tfilep)) {
+            /* hit EOF */
+            fclose(tfilep);
+            return (0);
+        }
+
+        /* turn trailing cr or lf into null */
+        tp = strrchr(lineBuffer, '\r');
+        if (tp) *tp = 0;
+        tp = strrchr(lineBuffer, '\n');
+        if (tp) *tp = 0;
+
+       /* skip blank lines */
+        if (lineBuffer[0] == 0)
+            continue;
+
+        /*
+         * The format is:
+         *   >[cell] [linked-cell] #[Description]
+         * where linked-cell and Description are optional
+         * but we are only going to use the initial cell name
+         */
+        if (lineBuffer[0] == '>') {
+            /*
+             * terminate the cellname at the first white space
+             * leaving 'tp' pointing to the next string if any
+             */
+            for (tp = &lineBuffer[1]; tp && !isspace(*tp); tp++);
+            if (tp)
+                *tp = '\0';
+
+            /* Now process the cell */
+            (*procp)(rockp, &lineBuffer[1]);
+        }
+    }          /* while loop processing all lines */
+
+    return 0;
+}
+
 /*
  * The CellServDB registry schema is as follows:
  *
  * HKLM\SOFTWARE\OpenAFS\Client\CellServDB\[cellname]\
- *   "LinkedCell"    REG_SZ "[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]" 
+ *   "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>
+ *   "ptserver"      DWORD  "7002"        <future>
  *
  * ForceDNS is implied non-zero if there are no [servername]
  * keys under the [cellname] key.  Otherwise, ForceDNS is zero.
@@ -354,7 +467,7 @@ long cm_SearchCellFileEx(char *cellNamep, char *newCellNamep,
  * 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, 
+long cm_SearchCellRegistry(afs_uint32 client,
                            char *cellNamep, char *newCellNamep,
                            char *linkedNamep,
                            cm_configProc_t *procp, void *rockp)
@@ -362,8 +475,9 @@ long cm_SearchCellRegistry(afs_uint32 client,
     HKEY hkCellServDB = 0, hkCellName = 0, hkServerName = 0;
     DWORD dwType, dwSize;
     DWORD dwCells, dwServers, dwForceDNS;
-    DWORD dwIndex, dwRank;
-    unsigned short ipRank;
+    DWORD dwIndex, dwRank, dwPort;
+    unsigned short adminRank;
+    unsigned short vlPort;
     LONG code;
     FILETIME ftLastWriteTime;
     char szCellName[CELL_MAXNAMELEN];
@@ -373,6 +487,7 @@ long cm_SearchCellRegistry(afs_uint32 client,
     struct hostent *thp;
     struct sockaddr_in vlSockAddr;
     char * s;
+    size_t len;
 
     if ( IsWindowsModule(cellNamep) )
        return -1;
@@ -384,14 +499,14 @@ long cm_SearchCellRegistry(afs_uint32 client,
     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                       AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
                       0,
-                      KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                      KEY_READ|KEY_QUERY_VALUE,
                       &hkCellServDB) != ERROR_SUCCESS)
         return CM_ERROR_NOSUCHCELL;
 
-    if (RegOpenKeyEx( hkCellServDB, 
+    if (RegOpenKeyEx( hkCellServDB,
                       cellNamep,
                       0,
-                      KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                      KEY_READ|KEY_QUERY_VALUE,
                       &hkCellName) != ERROR_SUCCESS) {
         BOOL bFound = 0;
 
@@ -413,13 +528,13 @@ long cm_SearchCellRegistry(afs_uint32 client,
         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, 
+            code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL,
                                  NULL, NULL, &ftLastWriteTime);
             if (code != ERROR_SUCCESS)
                 continue;
@@ -427,7 +542,10 @@ long cm_SearchCellRegistry(afs_uint32 client,
             strlwr(szCellName);
 
             /* if not a prefix match, try the next key */
-            if (strncmp(cellNamep, szCellName, strlen(cellNamep)))
+            if (FAILED(StringCchLength(cellNamep, CELL_MAXNAMELEN, &len)))
+                continue;
+
+            if (strncmp(cellNamep, szCellName, len))
                 continue;
 
             /* If we have a prefix match and we already found another
@@ -438,16 +556,16 @@ long cm_SearchCellRegistry(afs_uint32 client,
                 break;
             }
 
-            if (RegOpenKeyEx( hkCellServDB, 
+            if (RegOpenKeyEx( hkCellServDB,
                               szCellName,
                               0,
-                              KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                              KEY_READ|KEY_QUERY_VALUE,
                               &hkCellName) != ERROR_SUCCESS)
                 continue;
 
             if (newCellNamep) {
-                strncpy(newCellNamep, szCellName, CELL_MAXNAMELEN);
-                newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+                if (FAILED(StringCchCopy(newCellNamep, CELL_MAXNAMELEN, cellNamep)))
+                    goto done;
             }
             bFound = 1;
         }
@@ -485,7 +603,7 @@ long cm_SearchCellRegistry(afs_uint32 client,
         dwForceDNS = 0;
     }
 
-    /* 
+    /*
      * Using the defined server list.  Enumerate and populate
      * the server list for the cell.
      */
@@ -507,22 +625,22 @@ long cm_SearchCellRegistry(afs_uint32 client,
 
     for ( dwIndex = 0; dwIndex < dwServers; dwIndex++ ) {
         dwSize = MAXHOSTCHARS;
-        code = RegEnumKeyEx( hkCellName, dwIndex, szServerName, &dwSize, NULL, 
+        code = RegEnumKeyEx( hkCellName, dwIndex, szServerName, &dwSize, NULL,
                              NULL, NULL, &ftLastWriteTime);
         if (code != ERROR_SUCCESS)
             continue;
 
         szServerName[MAXHOSTCHARS-1] = '\0';
-        if (RegOpenKeyEx( hkCellName, 
+        if (RegOpenKeyEx( hkCellName,
                           szServerName,
                           0,
-                          KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                          KEY_READ|KEY_QUERY_VALUE,
                           &hkServerName) != ERROR_SUCCESS)
             continue;
 
-        /* We have a handle to a valid server key.  Now we need 
+        /* 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,
@@ -539,9 +657,9 @@ long cm_SearchCellRegistry(afs_uint32 client,
         code = RegQueryValueEx(hkServerName, "Rank", NULL, &dwType,
                                 (BYTE *) &dwRank, &dwSize);
         if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
-            ipRank = (unsigned short)(dwRank <= 65535 ? dwRank : 65535);
+            adminRank = (unsigned short)(dwRank <= 65535 ? dwRank : 65535);
         } else {
-            ipRank = 0;
+            adminRank = 0;
         }
 
         dwSize = sizeof(szAddr);
@@ -553,19 +671,29 @@ long cm_SearchCellRegistry(afs_uint32 client,
             szAddr[0] = '\0';
         }
 
+        dwSize = sizeof(DWORD);
+        code = RegQueryValueEx(hkServerName, "vlserver", NULL, &dwType,
+                                (BYTE *) &dwPort, &dwSize);
+        if (code == ERROR_SUCCESS && dwType == REG_DWORD) {
+            vlPort = htons((unsigned short)dwPort);
+        } else {
+            vlPort = htons(7003);
+        }
+
         WSASetLastError(0);
         thp = gethostbyname(s);
         if (thp) {
             memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr, sizeof(long));
+            vlSockAddr.sin_port = htons(7003);
             vlSockAddr.sin_family = AF_INET;
             /* sin_port supplied by connection code */
             if (procp)
-                (*procp)(rockp, &vlSockAddr, s, ipRank);
+                (*procp)(rockp, &vlSockAddr, s, adminRank);
         } else if (szAddr[0]) {
             afs_uint32 ip_addr;
             unsigned int c1, c2, c3, c4;
 
-            /* Since there is no gethostbyname() data 
+            /* Since there is no gethostbyname() data
              * available we will read the IP address
              * stored in the CellServDB file
              */
@@ -579,10 +707,11 @@ long cm_SearchCellRegistry(afs_uint32 client,
                 *tp++ = c4;
                 memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
                         sizeof(long));
+                vlSockAddr.sin_port = vlPort;
                 vlSockAddr.sin_family = AF_INET;
                 /* sin_port supplied by connection code */
                 if (procp)
-                    (*procp)(rockp, &vlSockAddr, s, ipRank);
+                    (*procp)(rockp, &vlSockAddr, s, adminRank);
             }
         }
 
@@ -596,24 +725,131 @@ long cm_SearchCellRegistry(afs_uint32 client,
     return ((dwForceDNS || dwServers == 0) ? CM_ERROR_FORCE_DNS_LOOKUP : 0);
 }
 
-long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellRegistryProc_t *procp, void *rockp)
+/*
+ * Following the registry schema listed above, cm_AddCellToRegistry
+ * will either create or update the registry configuration data for
+ * the specified cellname.
+ */
+long cm_AddCellToRegistry( char * cellname,
+                           char * linked_cellname,
+                           unsigned short vlport,
+                           afs_uint32 host_count,
+                           char *hostname[],
+                           afs_uint32 flags)
+{
+    HKEY hkCellServDB = 0, hkCellName = 0, hkServerName = 0;
+    DWORD dwPort, dwDisposition;
+    long code;
+    unsigned int i;
+
+    if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+                        AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
+                        0,
+                        NULL,
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                        NULL,
+                        &hkCellServDB,
+                        &dwDisposition) != ERROR_SUCCESS) {
+        code = CM_ERROR_NOACCESS;
+        goto done;
+    }
+
+    /* Perform a recursive deletion of the cellname key */
+    SHDeleteKey( hkCellServDB, cellname);
+
+    if (RegCreateKeyEx( hkCellServDB,
+                        cellname,
+                        0,
+                        NULL,
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                        NULL,
+                        &hkCellName,
+                        &dwDisposition) != ERROR_SUCCESS ||
+        (dwDisposition == REG_OPENED_EXISTING_KEY) ) {
+        code = CM_ERROR_NOACCESS;
+        goto done;
+    }
+
+    /* If we get here, hkCellName is a handle to an empty key */
+
+    if (linked_cellname && linked_cellname[0]) {
+        code = RegSetValueEx( hkCellName, "LinkedCell",
+                              0, REG_SZ,
+                              (BYTE *) linked_cellname, CELL_MAXNAMELEN);
+    }
+
+    if (flags & CM_CELLFLAG_DNS) {
+        DWORD dwForceDNS = 1;
+        code = RegSetValueEx( hkCellName, "ForceDNS",
+                              0, REG_DWORD,
+                              (BYTE *) &dwForceDNS, sizeof(DWORD));
+    }
+
+    for ( i = 0; i < host_count; i++ ) {
+        if (RegCreateKeyEx( hkCellName,
+                            hostname[i],
+                            0,
+                            NULL,
+                            REG_OPTION_NON_VOLATILE,
+                            KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                            NULL,
+                            &hkServerName,
+                            &dwDisposition) != ERROR_SUCCESS ||
+             (dwDisposition == REG_OPENED_EXISTING_KEY)) {
+            code = CM_ERROR_NOACCESS;
+            goto done;
+        }
+
+        /* 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 */
+        code = RegSetValueEx( hkServerName, "HostName",
+                              0, REG_SZ,
+                              (BYTE *) hostname[i], (DWORD)strlen(hostname[i]) + 1);
+
+        if (vlport) {
+            dwPort = vlport;
+            code = RegSetValueEx( hkServerName, "vlserver",
+                                  0, REG_DWORD,
+                                  (BYTE *) &dwPort, (DWORD)sizeof(DWORD));
+        }
+        RegCloseKey( hkServerName);
+        hkServerName = 0;
+    }
+
+  done:
+    if (hkServerName)
+        RegCloseKey(hkServerName);
+    if (hkCellName)
+        RegCloseKey(hkCellName);
+    if (hkCellServDB)
+        RegCloseKey(hkCellServDB);
+
+    return code;
+}
+
+long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellProc_t *procp, void *rockp)
 {
     HKEY hkCellServDB = 0;
-    DWORD dwType, dwSize;
+    DWORD dwSize;
     DWORD dwCells;
     DWORD dwIndex;
     LONG code;
     FILETIME ftLastWriteTime;
     char szCellName[CELL_MAXNAMELEN];
+       char * subkey = AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB";
 
     /* No server CellServDB in the registry. */
     if (!client || procp == NULL)
         return 0;
 
     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
-                      AFSREG_CLT_OPENAFS_SUBKEY "\\CellServDB",
+                     subkey,
                       0,
-                      KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
+                     KEY_READ|KEY_QUERY_VALUE,
                       &hkCellServDB) != ERROR_SUCCESS)
         return 0;
 
@@ -633,12 +869,12 @@ long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellRegistryProc_t *proc
     if (code != ERROR_SUCCESS)
         dwCells = 0;
 
-    /* 
-     * Enumerate each Cell and 
+    /*
+     * Enumerate each Cell and
      */
     for ( dwIndex = 0; dwIndex < dwCells; dwIndex++ ) {
         dwSize = CELL_MAXNAMELEN;
-        code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL, 
+        code = RegEnumKeyEx( hkCellServDB, dwIndex, szCellName, &dwSize, NULL,
                              NULL, NULL, &ftLastWriteTime);
         if (code != ERROR_SUCCESS)
             continue;
@@ -656,69 +892,80 @@ long cm_EnumerateCellRegistry(afs_uint32 client, cm_enumCellRegistryProc_t *proc
 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
                         cm_configProc_t *procp, void *rockp)
 {
-#ifdef AFS_AFSDB_ENV
     int rc;
     int  cellHostAddrs[AFSMAXCELLHOSTS];
     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
-    unsigned short ipRanks[AFSMAXCELLHOSTS];
+    unsigned short adminRanks[AFSMAXCELLHOSTS];
+    unsigned short ports[AFSMAXCELLHOSTS];      /* network byte order */
     int numServers;
     int i;
     struct sockaddr_in vlSockAddr;
+
 #ifdef CELLSERV_DEBUG
     osi_Log1(afsd_logp,"SearchCellDNS-Doing search for [%s]", osi_LogSaveString(afsd_logp,cellNamep));
 #endif
-    if ( IsWindowsModule(cellNamep) )
+    /*
+     * Do not perform a DNS lookup if the name is
+     * either a well-known Windows DLL or directory,
+     * or if the name does not contain a top-level
+     * domain, or if the file prefix is the afs pioctl
+     * file name.
+     */
+    if ( IsWindowsModule(cellNamep) ||
+         cm_FsStrChr(cellNamep, '.') == NULL ||
+         strncasecmp(cellNamep, CM_IOCTL_FILENAME_NOSLASH, sizeof(CM_IOCTL_FILENAME_NOSLASH)-1) == 0)
        return -1;
-    rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, ipRanks, &numServers, ttl);
+
+    rc = getAFSServer("afs3-vlserver", "udp", cellNamep, htons(7003),
+                      cellHostAddrs, cellHostNames, ports, adminRanks, &numServers, ttl);
     if (rc == 0 && numServers > 0) {     /* found the cell */
-        for (i = 0; i < numServers; i++) {
+       for (i = 0; i < numServers; i++) {
             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
                    sizeof(long));
+            vlSockAddr.sin_port = ports[i];
             vlSockAddr.sin_family = AF_INET;
-            /* sin_port supplied by connection code */
             if (procp)
-                (*procp)(rockp, &vlSockAddr, cellHostNames[i], ipRanks[i]);
+                (*procp)(rockp, &vlSockAddr, cellHostNames[i], adminRanks[i]);
         }
         if (newCellNamep) {
-            strncpy(newCellNamep,cellNamep,CELL_MAXNAMELEN);
-            newCellNamep[CELL_MAXNAMELEN-1] = '\0';
+            if(FAILED(StringCchCopy(newCellNamep, CELL_MAXNAMELEN, cellNamep)))
+                return -1;
             strlwr(newCellNamep);
         }
         return 0;   /* found cell */
     }
     else
        return -1;  /* not found */
-#else
-    return -1;  /* not found */
-#endif /* AFS_AFSDB_ENV */
 }
 
-/* use cm_GetConfigDir() plus AFS_CELLSERVDB to 
- * generate the fully qualified name of the CellServDB 
+/* use cm_GetConfigDir() plus AFS_CELLSERVDB to
+ * generate the fully qualified name of the CellServDB
  * file.
  */
 long cm_GetCellServDB(char *cellNamep, afs_uint32 len)
 {
     size_t tlen;
-    
+
     cm_GetConfigDir(cellNamep, len);
 
     /* add trailing backslash, if required */
-    tlen = (int)strlen(cellNamep);
+    if (FAILED(StringCchLength(cellNamep, len, &tlen)))
+        return(-1L);
+
     if (tlen) {
         if (cellNamep[tlen-1] != '\\') {
-            strncat(cellNamep, "\\", len);
-            cellNamep[len-1] = '\0';
+            if (FAILED(StringCchCat(cellNamep, len, "\\")))
+                return(-1L);
         }
-        
-        strncat(cellNamep, AFS_CELLSERVDB, len);
-        cellNamep[len-1] = '\0';
+
+        if (FAILED(StringCchCat(cellNamep, len, AFS_CELLSERVDB)))
+            return(-1L);
     }
     return 0;
 }
 
-/* look up the root cell's name in the Registry 
- * Input buffer must be at least CELL_MAXNAMELEN 
+/* look up the root cell's name in the Registry
+ * Input buffer must be at least CELL_MAXNAMELEN
  * in size.  (Defined in cm_cell.h)
  */
 long cm_GetRootCellName(char *cellNamep)
@@ -748,18 +995,19 @@ cm_configFile_t *cm_CommonOpen(char *namep, char *rwp)
 
     cm_GetConfigDir(wdir, sizeof(wdir));
     if (*wdir) {
-        strncat(wdir, namep, sizeof(wdir));
-        wdir[sizeof(wdir)-1] = '\0';
-        
+        if (FAILED(StringCchCat(wdir, MAX_PATH, namep)))
+            return NULL;
+
         tfilep = fopen(wdir, rwp);
     }
-    return ((cm_configFile_t *) tfilep);        
-}      
+    return ((cm_configFile_t *) tfilep);
+}
 
 long cm_WriteConfigString(char *labelp, char *valuep)
 {
     DWORD code, dummyDisp;
     HKEY parmKey;
+    size_t len;
 
     code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
                           0, "container", 0, KEY_SET_VALUE, NULL,
@@ -767,13 +1015,15 @@ long cm_WriteConfigString(char *labelp, char *valuep)
     if (code != ERROR_SUCCESS)
        return -1;
 
-    code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
-                         valuep, (DWORD)strlen(valuep) + 1);
+    if (FAILED(StringCchLength(valuep, CM_CONFIGDEFAULT_CELLS, &len)))
+        return -1;
+
+    code = RegSetValueEx(parmKey, labelp, 0, REG_SZ, valuep, (DWORD)(len + 1));
     RegCloseKey (parmKey);
     if (code != ERROR_SUCCESS)
-       return (long)-1;
+       return -1;
 
-    return (long)0;
+    return 0;
 }
 
 long cm_WriteConfigInt(char *labelp, long value)
@@ -814,7 +1064,7 @@ long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
     int foundCell;
 
     tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
-    if (!tfilep) 
+    if (!tfilep)
         return -1;
 
     foundCell = 0;
@@ -836,7 +1086,7 @@ long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
         if (tp) *tp = 0;
         tp = strchr(lineBuffer, '\n');
         if (tp) *tp = 0;
-                
+
         /* skip blank lines */
         if (lineBuffer[0] == 0) {
             fprintf((FILE *)ofp, "%s\n", lineBuffer);
@@ -871,7 +1121,7 @@ long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
             }
         }      /* a vldb line */
     }          /* while loop processing all lines */
-}       
+}
 
 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
 {
@@ -890,42 +1140,42 @@ long cm_CloseCellFile(cm_configFile_t *filep)
     char wdir[MAX_PATH];
     char sdir[MAX_PATH];
     long code;
-    long closeCode;
-    closeCode = fclose((FILE *)filep);
+    long closeCode = fclose((FILE *)filep);
 
     cm_GetConfigDir(wdir, sizeof(wdir));
-    strcpy(sdir, wdir);
+    if (FAILED(StringCchCopy(sdir, sizeof(sdir), wdir)))
+        return -1;
 
     if (closeCode != 0) {
         /* something went wrong, preserve original database */
-        strncat(wdir, AFS_CELLSERVDB ".new", sizeof(wdir));
-        wdir[sizeof(wdir)-1] = '\0';
+        if (FAILED(StringCchCat(wdir, sizeof(wdir), AFS_CELLSERVDB ".new")))
+            return -1;
         unlink(wdir);
         return closeCode;
     }
 
-    strncat(wdir, AFS_CELLSERVDB, sizeof(wdir));
-    wdir[sizeof(wdir)-1] = '\0';
-    strncat(sdir, AFS_CELLSERVDB ".new", sizeof(sdir));/* new file */
-    sdir[sizeof(sdir)-1] = '\0';
+    if (FAILED(StringCchCat(wdir, sizeof(wdir), AFS_CELLSERVDB)))
+        return -1;
+    if (FAILED(StringCchCat(sdir, sizeof(sdir), AFS_CELLSERVDB ".new"))) /* new file */
+        return -1;
 
     unlink(sdir);                      /* delete old file */
 
     code = rename(sdir, wdir); /* do the rename */
 
-    if (code) 
+    if (code)
         code = errno;
 
     return code;
-}   
+}
 
 void cm_GetConfigDir(char *dir, afs_uint32 len)
 {
     char * dirp = NULL;
 
     if (!afssw_GetClientCellServDBDir(&dirp)) {
-        strncpy(dir, dirp, len);
-        dir[len-1] = '\0';
+        if (FAILED(StringCchCopy(dir, len, dirp)))
+            return;
         free(dirp);
     } else {
         dir[0] = '\0';