Windows FindACLCache must hold scp write locked
[openafs.git] / src / WINNT / afsd / smb.c
index 1ede828..6836ff9 100644 (file)
@@ -773,7 +773,7 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
         vcp->lana = lana;
         vcp->secCtx = NULL;
 
-        if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
+        if (smb_authType == SMB_AUTH_NTLM) {
             /* We must obtain a challenge for extended auth
              * in case the client negotiates smb v3
              */
@@ -1931,7 +1931,7 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         p = pathName;
         cchlen = lengthof(pathName);
 
-        /* within this code block, we maintain, cchlen = writeable
+        /* within this code block, we maintain, cchlen = writable
            buffer length of p */
 
         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
@@ -3078,7 +3078,7 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
         smb_FreeNCB(ncbp);
 }
 
-void smb_MapNTError(long code, unsigned long *NTStatusp)
+void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
 {
     unsigned long NTStatus;
 
@@ -3094,26 +3094,34 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0xC0000034L;        /* Name not found */
     }
     else if (code == CM_ERROR_TIMEDOUT) {
+        if (redir)
+            NTStatus = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
+        else {
 #ifdef COMMENT
-        NTStatus = 0xC00000CFL;        /* Sharing Paused */
-
-        /* Do not send Timeout to the SMB redirector.
-         * It causes the redirector to drop the connection */
-        NTStatus = 0x00000102L; /* Timeout */
-        /* do not send Retry to the SMB redirector.
-         * It believes the error comes from the transport
-         * layer not from the SMB server. */
-        NTStatus = 0xC000022DL;        /* Retry */
+            NTStatus = 0xC00000CFL;    /* Sharing Paused */
+
+            /* Do not send Timeout to the SMB redirector.
+             * It causes the redirector to drop the connection */
+            NTStatus = 0x00000102L; /* Timeout */
+            /* do not send Retry to the SMB redirector.
+             * It believes the error comes from the transport
+             * layer not from the SMB server. */
+            NTStatus = 0xC000022DL;    /* Retry */
 #else
-        NTStatus = 0xC00000B5L;        /* I/O Timeout */
+            NTStatus = 0xC00000B5L;    /* I/O Timeout */
 #endif
+        }
     }
     else if (code == CM_ERROR_RETRY) {
+        if (redir)
+            NTStatus = 0xC000022DL;    /* Retry */
+        else {
 #ifdef COMMENT
-        NTStatus = 0xC000022DL;        /* Retry */
+            NTStatus = 0xC000022DL;    /* Retry */
 #else
-        NTStatus = 0xC00000B5L; /* I/O Timeout */
+            NTStatus = 0xC00000B5L; /* I/O Timeout */
 #endif
+        }
     }
     else if (code == CM_ERROR_NOACCESS) {
         NTStatus = 0xC0000022L;        /* Access denied */
@@ -3273,7 +3281,10 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_RPC_MOREDATA) {
        NTStatus = 0x80000005L; /* Buffer overflow */
     }
-    else  {
+    else {
+        char foo[256];
+        sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
+        OutputDebugString(foo);
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
 
@@ -3923,8 +3934,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
          * the same value for all sessions.  We should generate a random value
          * and store it into the vcp
          */
-        smb_SetSMBParm(outp, 7, 1);    /* next 2: session key */
-        smb_SetSMBParm(outp, 8, 1);
+        smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d);       /* session key */
         /*
          * Tried changing the capabilities to support for W2K - defect 117695
          * Maybe something else needs to be changed here?
@@ -3980,26 +3990,45 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                                   datap + MSV1_0_CHALLENGE_LENGTH,
                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
-            void * secBlob;
-            int secBlobLength;
+            void * secBlob = NULL;
+            int secBlobLength = 0;
 
             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
 
-            smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
+            /*
+             * The SMB specification permits the server to save a round trip
+             * in the GSS negotiation by sending an initial security blob.
+             * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
+             * whereby the SMB 1.x redirector drops the blob on the floor after
+             * the first connection to the server and simply attempts to reuse
+             * the previous authentication context.  This bug can be avoided by
+             * the server sending no security blob in the SMB_COM_NEGOTIATE
+             * response.  This forces the client to send an initial GSS init_sec_context
+             * blob under all circumstances which works around the bug in Microsoft's
+             * code.
+             *
+             * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
+             */
 
             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
-
             datap = smb_GetSMBData(outp, NULL);
+
             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
+            datap += sizeof(smb_ServerGUID);
 
             if (secBlob) {
-                datap += sizeof(smb_ServerGUID);
                 memcpy(datap, secBlob, secBlobLength);
                 free(secBlob);
+                datap += sizeof(secBlobLength);
             }
         } else {
-            smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
-            smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
+            smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
+            smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
+            datap = smb_GetSMBData(outp, NULL);
+            /* the faux domain name */
+            cm_ClientStringToUtf8(smb_ServerDomainName, -1,
+                                  datap,
+                                  (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
         }
     }
     else if (v3ProtoIndex != -1) {
@@ -4612,17 +4641,17 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
     afs_uint32 rights;
     afs_int32 mustFake = 0;
 
+    lock_ObtainWrite(&dscp->rw);
     code = cm_FindACLCache(dscp, userp, &rights);
     if (code == -1) {
-        lock_ObtainWrite(&dscp->rw);
         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        lock_ReleaseWrite(&dscp->rw);
         if (code == CM_ERROR_NOACCESS) {
             mustFake = 1;
             code = 0;
         }
     }
+    lock_ReleaseWrite(&dscp->rw);
     if (code)
         goto cleanup;
 
@@ -4682,7 +4711,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
         reqp->relPathp = path;
         reqp->tidPathp = tidPathp;
 
-        code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+        code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
         reqp->relPathp = reqp->tidPathp = NULL;
 
         if (code) {
@@ -5607,7 +5636,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
                 code = CM_ERROR_NOSUCHFILE;
             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
-                cm_buf_t *bp = buf_Find(dscp, &hzero);
+                cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
                 if (bp) {
                     buf_Release(bp);
                    bp = NULL;
@@ -6920,8 +6949,10 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
         lock_ReleaseMutex(&fidp->mx);
 
-        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
-              * in zero. */
+        /*
+         * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
+         * We pass in zero.
+         */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
         lock_ObtainWrite(&scp->rw);
 
@@ -6936,7 +6967,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             goto post_syncopdone;
         }
 
-        cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
+        cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
 
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
 
@@ -7455,7 +7486,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
         /* now copy the data */
        memcpy(bufferp->datap + bufIndex, op, nbytes);
-        buf_SetDirty(bufferp, bufIndex, nbytes, userp);
+        buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
 
         /* adjust counters, pointers, etc. */
         op += nbytes;
@@ -7505,7 +7536,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
                 lock_ReleaseWrite(&scp->rw);
                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
                                     writeBackOffset.HighPart,
-                                    smb_AsyncStoreSize, 0, userp);
+                                    smb_AsyncStoreSize, 0, userp, &req);
                 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
             }
         } else {
@@ -8687,7 +8718,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
          */
         if (code) {
             if (vcp->flags & SMB_VCFLAG_STATUS32) {
-                smb_MapNTError(code, &NTStatus);
+                smb_MapNTError(code, &NTStatus, FALSE);
                 outWctp = outp->wctp;
                 smbp = (smb_t *) &outp->data;
                 if (code != CM_ERROR_PARTIALWRITE
@@ -9888,7 +9919,7 @@ void smb_Listener(void *parmp)
 
             if (vcp->flags & SMB_VCFLAG_STATUS32) {
                 unsigned long NTStatus;
-                smb_MapNTError(code, &NTStatus);
+                smb_MapNTError(code, &NTStatus, FALSE);
                 outWctp = outp->wctp;
                 smbp = (smb_t *) &outp->data;
                 *outWctp++ = 0;
@@ -9985,8 +10016,8 @@ exit_thread:
     return;
 }
 
-static void
-configureBackConnectionHostNames(void)
+void
+smb_configureBackConnectionHostNames(int bEnable)
 {
     /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
      * there is a restriction on the use of SMB authentication on loopback connections.
@@ -10027,10 +10058,31 @@ configureBackConnectionHostNames(void)
     DWORD dwSize, dwAllocSize;
     DWORD dwValue;
     PBYTE pHostNames = NULL, pName = NULL;
+    PBYTE pOrigNames = NULL, pOrig = NULL;
     BOOL  bNameFound = FALSE;
+    DWORD dwLoopbackCheckDisabled;
+    DWORD dwszBackConnectionHostNames;
+    size_t nbsize = strlen(cm_NetbiosName) + 2;
+    size_t len;
     static BOOL bLoopbackCheckDisabled = FALSE;
 
-    /* BackConnectionHostNames and DisableLoopbackCheck */
+    /* DisableLoopbackCheck */
+    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+                       "SYSTEM\\CurrentControlSet\\Control\\Lsa",
+                       0,
+                       KEY_READ|KEY_WRITE,
+                       &hkLsa) == ERROR_SUCCESS )
+    {
+        dwSize = sizeof(DWORD);
+        if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
+        {
+            dwLoopbackCheckDisabled = 0;
+        }
+    } else {
+        hkLsa = INVALID_HANDLE_VALUE;
+    }
+
+    /* BackConnectionHostNames */
     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                        "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
                        0,
@@ -10044,12 +10096,12 @@ configureBackConnectionHostNames(void)
            dwAllocSize += 1 /* in case the source string is not nul terminated */
                + (DWORD)strlen(cm_NetbiosName) + 2;
            pHostNames = malloc(dwAllocSize);
-           dwSize = dwAllocSize;
+           dwszBackConnectionHostNames = dwAllocSize;
             if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
-                                pHostNames, &dwSize) == ERROR_SUCCESS)
+                                pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
             {
                for (pName = pHostNames;
-                    (pName - pHostNames < (int) dwSize) && *pName ;
+                    (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
                     pName += strlen(pName) + 1)
                {
                    if ( !stricmp(pName, cm_NetbiosName) ) {
@@ -10060,33 +10112,27 @@ configureBackConnectionHostNames(void)
            }
         }
 
-        if ( !bNameFound ) {
-            size_t size = strlen(cm_NetbiosName) + 2;
-            if ( !pHostNames ) {
-                pHostNames = malloc(size);
-               pName = pHostNames;
-            }
-            StringCbCopyA(pName, size, cm_NetbiosName);
-            pName += size - 1;
-            *pName = '\0';  /* add a second nul terminator */
+        if ( bEnable ) {
+            if ( !bNameFound ) {
+                size_t size = strlen(cm_NetbiosName) + 2;
+                if ( !pHostNames ) {
+                    pHostNames = malloc(size);
+                    pName = pHostNames;
+                }
+                StringCbCopyA(pName, size, cm_NetbiosName);
+                pName += size - 1;
+                *pName = '\0';  /* add a second nul terminator */
 
-            dwType = REG_MULTI_SZ;
-           dwSize = (DWORD)(pName - pHostNames + 1);
-            RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
+                dwType = REG_MULTI_SZ;
+                dwSize = (DWORD)(pName - pHostNames + 1);
+                RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
 
-            if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
-                               "SYSTEM\\CurrentControlSet\\Control\\Lsa",
-                               0,
-                               KEY_READ|KEY_WRITE,
-                               &hkLsa) == ERROR_SUCCESS )
-            {
-                dwSize = sizeof(DWORD);
-                if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
-                     dwValue == 0 ) {
+                if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
+                {
                     dwType = REG_DWORD;
                     dwSize = sizeof(DWORD);
-                    dwValue = 1;
-                    RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
+                    dwLoopbackCheckDisabled = 1;
+                    RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
 
                     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
                                         AFSREG_CLT_OPENAFS_SUBKEY,
@@ -10105,36 +10151,83 @@ configureBackConnectionHostNames(void)
                         bLoopbackCheckDisabled = TRUE;
                         RegCloseKey(hkClient);
                     }
-                    RegCloseKey(hkLsa);
                 }
+            } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
+                if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+                                    AFSREG_CLT_OPENAFS_SUBKEY,
+                                    0,
+                                    NULL,
+                                    REG_OPTION_NON_VOLATILE,
+                                    KEY_READ|KEY_WRITE,
+                                    NULL,
+                                    &hkClient,
+                                    NULL) == ERROR_SUCCESS) {
+
+                    dwSize = sizeof(DWORD);
+                    if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
+                         dwValue == 1 ) {
+                        RegDeleteValue(hkLsa, "DisableLoopbackCheck");
+                    }
+                }
+                RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
+                RegCloseKey(hkClient);
             }
-        } else if (!bLoopbackCheckDisabled) {
-            if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
-                                AFSREG_CLT_OPENAFS_SUBKEY,
-                                0,
-                                NULL,
-                                REG_OPTION_NON_VOLATILE,
-                                KEY_READ|KEY_WRITE,
-                                NULL,
-                                &hkClient,
-                                NULL) == ERROR_SUCCESS) {
-
-                dwSize = sizeof(DWORD);
-                if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
-                     dwValue == 1 ) {
-                    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
-                                       "SYSTEM\\CurrentControlSet\\Control\\Lsa",
-                                       0,
-                                       KEY_READ|KEY_WRITE,
-                                       &hkLsa) == ERROR_SUCCESS )
-                    {
+        } else {
+            /*
+             * Disable SMB.  Start by removing the DisableLoopbackCheck value if present.
+             */
+            if (hkLsa != INVALID_HANDLE_VALUE) {
+                if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+                                    AFSREG_CLT_OPENAFS_SUBKEY,
+                                    0,
+                                    NULL,
+                                    REG_OPTION_NON_VOLATILE,
+                                    KEY_READ|KEY_WRITE,
+                                    NULL,
+                                    &hkClient,
+                                    NULL) == ERROR_SUCCESS) {
+
+                    dwSize = sizeof(DWORD);
+                    if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
+                         dwValue == 1 ) {
                         RegDeleteValue(hkLsa, "DisableLoopbackCheck");
-                        RegCloseKey(hkLsa);
                     }
                 }
                 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
                 RegCloseKey(hkClient);
             }
+
+            /* Then remove our NetbiosName from the BackConnectionHostNames list */
+            if ( bNameFound ) {
+                /*
+                * we found our name so if the size of the value is smaller
+                * or equal to the length of our name alone, we are done.
+                */
+                if ( dwszBackConnectionHostNames <= nbsize ) {
+                    RegDeleteValue( hkMSV10, "BackConnectionHostNames");
+                } else {
+                    pOrigNames = pHostNames;
+                    pHostNames = malloc(dwAllocSize);
+
+                    pOrig = pOrigNames;
+                    pName = pHostNames;
+                    while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
+                        len = strlen(pOrig);
+                        if ( stricmp(pOrig, cm_NetbiosName)) {
+                            /* not our name */
+                            StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
+                            pName += len + 1;
+                        }
+                        pOrig += len + 1;
+                    }
+                    *pName = '\0';  /* add a second nul terminator */
+                    pName++;
+
+                    dwType = REG_MULTI_SZ;
+                    dwSize = (DWORD)(pName - pHostNames + 1);
+                    RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
+                }
+            }
         }
 
         if (pHostNames) {
@@ -10142,19 +10235,28 @@ configureBackConnectionHostNames(void)
             pHostNames = NULL;
         }
 
+        if (pOrigNames) {
+            free(pOrigNames);
+            pOrigNames = NULL;
+        }
+
         RegCloseKey(hkMSV10);
     }
+
+    if ( hkLsa != INVALID_HANDLE_VALUE ) {
+        RegCloseKey(hkLsa);
+    }
 }
 
 
-static void
-configureExtendedSMBSessionTimeouts(void)
+void
+smb_configureExtendedSMBSessionTimeouts(int bEnable)
 {
     /*
      * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
      * new functionality:
      *
-     *  [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
+     *  [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
      *   "ReconnectableServers"            REG_MULTI_SZ
      *   "ExtendedSessTimeout"             REG_DWORD  (seconds)
      *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ
@@ -10162,32 +10264,36 @@ configureExtendedSMBSessionTimeouts(void)
      * These values can be used to prevent the smb redirector from timing out
      * smb connection to the afs smb server prematurely.
      */
-    HKEY hkLanMan;
+    HKEY hkLanman;
     DWORD dwType;
     DWORD dwSize, dwAllocSize;
     DWORD dwValue;
-    PBYTE pHostNames = NULL, pName = NULL;
+    PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
     BOOL  bNameFound = FALSE;
+    DWORD dwszReconnectableServers;
+    DWORD dwszServersWithExtendedSessTimeout;
+    size_t nbsize = strlen(cm_NetbiosName) + 2;
+    size_t len;
 
     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
-                       "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
+                       "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
                        0,
                        KEY_READ|KEY_WRITE,
-                       &hkLanMan) == ERROR_SUCCESS )
+                       &hkLanman) == ERROR_SUCCESS )
     {
-        if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
+        if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
                             &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
             (dwType == REG_MULTI_SZ))
         {
            dwAllocSize += 1 /* in case the source string is not nul terminated */
                + (DWORD)strlen(cm_NetbiosName) + 2;
            pHostNames = malloc(dwAllocSize);
-           dwSize = dwAllocSize;
-            if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
-                                pHostNames, &dwSize) == ERROR_SUCCESS)
+           dwszReconnectableServers = dwAllocSize;
+            if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
+                                pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
             {
                for (pName = pHostNames;
-                    (pName - pHostNames < (int) dwSize) && *pName ;
+                    (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
                     pName += strlen(pName) + 1)
                {
                    if ( !stricmp(pName, cm_NetbiosName) ) {
@@ -10198,19 +10304,58 @@ configureExtendedSMBSessionTimeouts(void)
            }
         }
 
-        if ( !bNameFound ) {
-            size_t size = strlen(cm_NetbiosName) + 2;
+        /*
+         * If our name was not found and we are enabling SMB,
+         * add our name to the current value.
+         */
+        if ( bEnable && !bNameFound ) {
             if ( !pHostNames ) {
-                pHostNames = malloc(size);
+                pHostNames = malloc(nbsize);
                pName = pHostNames;
             }
-            StringCbCopyA(pName, size, cm_NetbiosName);
-            pName += size - 1;
+            StringCbCopyA(pName, nbsize, cm_NetbiosName);
+            pName += nbsize - 1;
             *pName = '\0';  /* add a second nul terminator */
 
             dwType = REG_MULTI_SZ;
            dwSize = (DWORD)(pName - pHostNames + 1);
-            RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
+            RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
+        }
+
+        /*
+         * If our name was found and we are disabling SMB,
+         * remove our name from the list and update the value.
+         * If our name is the only entry, remove the value.
+         */
+        if ( !bEnable && bNameFound ) {
+            /*
+             * we found our name so if the size of the value is smaller
+             * or equal to the length of our name alone, we are done.
+             */
+            if ( dwszReconnectableServers <= nbsize ) {
+                RegDeleteValue( hkLanman, "ReconnectableServers");
+            } else {
+                pOrigNames = pHostNames;
+                pHostNames = malloc(dwAllocSize);
+
+                pOrig = pOrigNames;
+                pName = pHostNames;
+                while (pOrig - pOrigNames <dwszReconnectableServers ) {
+                    len = strlen(pOrig);
+                    if ( stricmp(pOrig, cm_NetbiosName)) {
+                        /* not our name */
+                        StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
+                        pName += len + 1;
+                    }
+                    pOrig += len + 1;
+                }
+                *pName = '\0';  /* add a second nul terminator */
+                pName++;
+
+                dwType = REG_MULTI_SZ;
+                dwSize = (DWORD)(pName - pHostNames + 1);
+                RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
+            }
         }
 
         if (pHostNames) {
@@ -10218,19 +10363,24 @@ configureExtendedSMBSessionTimeouts(void)
             pHostNames = NULL;
         }
 
-        if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
+        if (pOrigNames) {
+            free(pOrigNames);
+            pOrigNames = NULL;
+        }
+
+        if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
                             &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
             (dwType == REG_MULTI_SZ))
         {
            dwAllocSize += 1 /* in case the source string is not nul terminated */
                + (DWORD)strlen(cm_NetbiosName) + 2;
            pHostNames = malloc(dwAllocSize);
-           dwSize = dwAllocSize;
-            if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
-                                pHostNames, &dwSize) == ERROR_SUCCESS)
+           dwszServersWithExtendedSessTimeout = dwAllocSize;
+            if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
+                                pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
             {
                for (pName = pHostNames;
-                    (pName - pHostNames < (int) dwSize) && *pName ;
+                    (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
                     pName += strlen(pName) + 1)
                {
                    if ( !stricmp(pName, cm_NetbiosName) ) {
@@ -10241,7 +10391,11 @@ configureExtendedSMBSessionTimeouts(void)
            }
         }
 
-        if ( !bNameFound ) {
+        /*
+         * If our name was not found and we are enabling SMB,
+         * add our name to the current value.
+         */
+        if ( bEnable && !bNameFound ) {
             size_t size = strlen(cm_NetbiosName) + 2;
             if ( !pHostNames ) {
                 pHostNames = malloc(size);
@@ -10253,7 +10407,43 @@ configureExtendedSMBSessionTimeouts(void)
 
             dwType = REG_MULTI_SZ;
            dwSize = (DWORD)(pName - pHostNames + 1);
-            RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
+            RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
+        }
+
+        /*
+         * If our name was found and we are disabling SMB,
+         * remove our name from the list and update the value.
+         * If our name is the only entry, remove the value.
+         */
+        if ( !bEnable && bNameFound ) {
+            /*
+             * we found our name so if the size of the value is smaller
+             * or equal to the length of our name alone, we are done.
+             */
+            if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
+                RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
+            } else {
+                pOrigNames = pHostNames;
+                pHostNames = malloc(dwAllocSize);
+
+                pOrig = pOrigNames;
+                pName = pHostNames;
+                while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
+                    len = strlen(pOrig);
+                    if ( stricmp(pOrig, cm_NetbiosName)) {
+                        /* not our name */
+                        StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
+                        pName += len + 1;
+                    }
+                    pOrig += len + 1;
+                }
+                *pName = '\0';  /* add a second nul terminator */
+                pName++;
+
+                dwType = REG_MULTI_SZ;
+                dwSize = (DWORD)(pName - pHostNames + 1);
+                RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
+            }
         }
 
         if (pHostNames) {
@@ -10261,16 +10451,23 @@ configureExtendedSMBSessionTimeouts(void)
             pHostNames = NULL;
         }
 
-        if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
-                              &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
-             (dwType != REG_DWORD))
-        {
-            dwType = REG_DWORD;
-           dwSize = sizeof(dwValue);
-            dwValue = 300;      /* 5 minutes */
-            RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
+        if (pOrigNames) {
+            free(pOrigNames);
+            pOrigNames = NULL;
+        }
+
+        if ( bEnable ) {
+            if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
+                                  &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
+                 (dwType != REG_DWORD))
+            {
+                dwType = REG_DWORD;
+                dwSize = sizeof(dwValue);
+                dwValue = 300;      /* 5 minutes */
+                RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
+            }
         }
-        RegCloseKey(hkLanMan);
+        RegCloseKey(hkLanman);
     }
 }
 
@@ -10386,6 +10583,9 @@ int smb_NetbiosInit(int locked)
     int lana_found = 0;
     lana_number_t lanaNum;
 
+    if (!smb_Enabled)
+        return 0;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10570,6 +10770,9 @@ void smb_StartListeners(int locked)
     int lpid;
     thread_t phandle;
 
+    if (!smb_Enabled)
+        return;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10581,12 +10784,12 @@ void smb_StartListeners(int locked)
 
     afsi_log("smb_StartListeners");
     /* Ensure the AFS Netbios Name is registered to allow loopback access */
-    configureBackConnectionHostNames();
+    smb_configureBackConnectionHostNames(TRUE);
 
     /* Configure Extended SMB Session Timeouts */
     if (msftSMBRedirectorSupportsExtendedTimeouts()) {
         afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
-        configureExtendedSMBSessionTimeouts();
+        smb_configureExtendedSMBSessionTimeouts(TRUE);
     }
 
     smb_ListenerState = SMB_LISTENER_STARTED;
@@ -10610,6 +10813,9 @@ void smb_StartListeners(int locked)
 
 void smb_RestartListeners(int locked)
 {
+    if (!smb_Enabled)
+        return;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10664,6 +10870,9 @@ void smb_StopListeners(int locked)
     NCB *ncbp;
     int lana, l;
 
+    if (!smb_Enabled)
+        return;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10717,6 +10926,9 @@ void smb_Init(osi_log_t *logp, int useV3,
     char eventName[MAX_PATH];
     int startListeners = 0;
 
+    if (!smb_Enabled)
+        return;
+
     smb_MBfunc = aMBfunc;
 
     smb_useV3 = useV3;
@@ -11077,6 +11289,9 @@ void smb_Shutdown(void)
     afs_uint32 i;
     smb_vc_t *vcp;
 
+    if (!smb_Enabled)
+        return;
+
     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
 
     /* setup the NCB system */
@@ -11319,10 +11534,12 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
 
+    if (!smb_Enabled)
+        goto done;
+
     sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
-
     for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
         smb_waitingLock_t *lockp;
 
@@ -11450,6 +11667,7 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
+  done:
     if (lock)
         lock_ReleaseRead(&smb_rctLock);
     return 0;
@@ -11458,6 +11676,10 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
 long smb_IsNetworkStarted(void)
 {
     long rc;
+
+    if (!smb_Enabled)
+        return 0;
+
     lock_ObtainWrite(&smb_globalLock);
     rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
     lock_ReleaseWrite(&smb_globalLock);