Windows FindACLCache must hold scp write locked
[openafs.git] / src / WINNT / afsd / smb.c
index 47bdf7e..6836ff9 100644 (file)
@@ -1,13 +1,16 @@
 /*
  * 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 <roken.h>
+
 #include <afs/stds.h>
 
 #include <windows.h>
@@ -15,6 +18,7 @@
 #pragma warning(disable: 4005)
 #include <ntstatus.h>
 #pragma warning(pop)
+#include <sddl.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <malloc.h>
@@ -134,6 +138,11 @@ long smb_dirSearchCounter = 1;
 smb_dirSearch_t *smb_firstDirSearchp;
 smb_dirSearch_t *smb_lastDirSearchp;
 
+/* Initial mode bits for files and directories.  Set to 0 to use
+   defaults. */
+int smb_unixModeDefaultFile = 0666;
+int smb_unixModeDefaultDir = 0777;
+
 /* hide dot files? */
 int smb_hideDotFiles;
 
@@ -171,7 +180,7 @@ int smb_NetbiosInit(int);
 #ifdef LOG_PACKET
 void smb_LogPacket(smb_packet_t *packet);
 #endif /* LOG_PACKET */
-                                                         
+
 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
 int smb_ServerDomainNameLength = 0;
 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
@@ -192,43 +201,43 @@ const char * ncb_error_string(int code)
 {
     const char * s;
     switch ( code ) {
-    case 0x01: s = "NRC_BUFLEN llegal buffer length";                  break; 
-    case 0x03: s = "NRC_ILLCMD illegal command";                       break; 
-    case 0x05: s = "NRC_CMDTMO command timed out";                     break; 
-    case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break; 
-    case 0x07: s = "NRC_BADDR  illegal buffer address";                break; 
-    case 0x08: s = "NRC_SNUMOUT session number out of range";          break; 
-    case 0x09: s = "NRC_NORES no resource available";                  break; 
-    case 0x0a: s = "NRC_SCLOSED asession closed";                      break; 
-    case 0x0b: s = "NRC_CMDCAN command cancelled";                     break; 
-    case 0x0d: s = "NRC_DUPNAME duplicate name";                       break; 
-    case 0x0e: s = "NRC_NAMTFUL name table full";                      break; 
-    case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break; 
-    case 0x11: s = "NRC_LOCTFUL local session table full";             break; 
-    case 0x12: s = "NRC_REMTFUL remote session table full";            break; 
-    case 0x13: s = "NRC_ILLNN illegal name number";                    break; 
-    case 0x14: s = "NRC_NOCALL no callname";                           break; 
-    case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME";              break; 
-    case 0x16: s = "NRC_INUSE name in use on remote adapter";          break; 
-    case 0x17: s = "NRC_NAMERR name deleted";                          break; 
-    case 0x18: s = "NRC_SABORT session ended abnormally";              break; 
-    case 0x19: s = "NRC_NAMCONF name conflict detected";               break; 
-    case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying";  break; 
+    case 0x01: s = "NRC_BUFLEN llegal buffer length";                  break;
+    case 0x03: s = "NRC_ILLCMD illegal command";                       break;
+    case 0x05: s = "NRC_CMDTMO command timed out";                     break;
+    case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
+    case 0x07: s = "NRC_BADDR  illegal buffer address";                break;
+    case 0x08: s = "NRC_SNUMOUT session number out of range";          break;
+    case 0x09: s = "NRC_NORES no resource available";                  break;
+    case 0x0a: s = "NRC_SCLOSED asession closed";                      break;
+    case 0x0b: s = "NRC_CMDCAN command cancelled";                     break;
+    case 0x0d: s = "NRC_DUPNAME duplicate name";                       break;
+    case 0x0e: s = "NRC_NAMTFUL name table full";                      break;
+    case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
+    case 0x11: s = "NRC_LOCTFUL local session table full";             break;
+    case 0x12: s = "NRC_REMTFUL remote session table full";            break;
+    case 0x13: s = "NRC_ILLNN illegal name number";                    break;
+    case 0x14: s = "NRC_NOCALL no callname";                           break;
+    case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME";              break;
+    case 0x16: s = "NRC_INUSE name in use on remote adapter";          break;
+    case 0x17: s = "NRC_NAMERR name deleted";                          break;
+    case 0x18: s = "NRC_SABORT session ended abnormally";              break;
+    case 0x19: s = "NRC_NAMCONF name conflict detected";               break;
+    case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying";  break;
     case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
-    case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid";            break; 
-    case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break; 
-    case 0x26: s = "NRC_CANCEL command not valid to cancel";           break; 
-    case 0x30: s = "NRC_DUPENV name defined by anther local process";  break; 
-    case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required";     break; 
-    case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted";   break; 
-    case 0x36: s = "NRC_MAXAPPS max number of applications exceeded";  break; 
-    case 0x37: s = "NRC_NOSAPS no saps available for netbios";                 break; 
-    case 0x38: s = "NRC_NORESOURCES requested resources are not available";    break; 
-    case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment";   break; 
-    case 0x3B: s = "NRC_INVDDID invalid NCB DDID";                     break; 
-    case 0x3C: s = "NRC_LOCKFAILlock of user area failed";             break; 
-    case 0x3f: s = "NRC_OPENERR NETBIOS not loaded";                   break; 
-    case 0x40: s = "NRC_SYSTEM system error";                          break;                 
+    case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid";            break;
+    case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
+    case 0x26: s = "NRC_CANCEL command not valid to cancel";           break;
+    case 0x30: s = "NRC_DUPENV name defined by anther local process";  break;
+    case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required";     break;
+    case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted";   break;
+    case 0x36: s = "NRC_MAXAPPS max number of applications exceeded";  break;
+    case 0x37: s = "NRC_NOSAPS no saps available for netbios";                 break;
+    case 0x38: s = "NRC_NORESOURCES requested resources are not available";    break;
+    case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment";   break;
+    case 0x3B: s = "NRC_INVDDID invalid NCB DDID";                     break;
+    case 0x3C: s = "NRC_LOCKFAILlock of user area failed";             break;
+    case 0x3f: s = "NRC_OPENERR NETBIOS not loaded";                   break;
+    case 0x40: s = "NRC_SYSTEM system error";                          break;
     default:   s = "unknown error";
     }
     return s;
@@ -356,7 +365,7 @@ char * myCrt_Dispatch(int i)
     default:
         return "unknown SMB op";
     }
-}       
+}
 
 char * myCrt_2Dispatch(int i)
 {
@@ -401,7 +410,7 @@ char * myCrt_2Dispatch(int i)
     case 17:
         return "S(11)_ReceiveTran2ReportDfsInconsistency";
     }
-}       
+}
 
 char * myCrt_RapDispatch(int i)
 {
@@ -492,6 +501,24 @@ unsigned int smb_Attributes(cm_scache_t *scp)
     return attrs;
 }
 
+void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
+{
+    if (smb_unixModeDefaultFile != 0) {
+        attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
+        attr->unixModeBits = smb_unixModeDefaultFile;
+        if (smb_attr & SMB_ATTR_READONLY)
+            attr->unixModeBits &= ~0222;
+    }
+}
+
+void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
+{
+    if (smb_unixModeDefaultDir != 0) {
+        attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
+        attr->unixModeBits = smb_unixModeDefaultDir;
+    }
+}
+
 /* Check if the named file/dir is a dotfile/dotdir */
 /* String pointed to by lastComp can have leading slashes, but otherwise should have
    no other patch components */
@@ -509,9 +536,9 @@ unsigned int smb_IsDotFile(clientchar_t *lastComp) {
     if (!*s)
         return 0;
     if (*s == _C('.')) {
-        if (!*(s + 1)) 
+        if (!*(s + 1))
             return 0;
-        if(*(s+1) == _C('.') && !*(s + 2)) 
+        if(*(s+1) == _C('.') && !*(s + 2))
             return 0;
         return 1;
     }
@@ -524,7 +551,7 @@ static int ExtractBits(WORD bits, short start, short len)
     WORD num;
 
     end = start + len;
-        
+
     num = bits << (16 - end);
     num = num >> ((16 - end) + start);
 
@@ -555,7 +582,7 @@ void ShowUnixTime(char *FuncName, time_t unixTime)
         sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
     }
-}       
+}
 
 /* Determine if we are observing daylight savings time */
 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
@@ -578,18 +605,18 @@ void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
     GetSystemTime(&utc);
 
     /* Convert UTC time to local time using the time zone info.  If we are
-       observing DST, the calculated local time will include this. 
+       observing DST, the calculated local time will include this.
      */
     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
 
     /* Set the daylight bias to 0.  The daylight bias is the amount of change
      * in time that we use for daylight savings time.  By setting this to 0
-     * we cause there to be no change in time during daylight savings time. 
+     * we cause there to be no change in time during daylight savings time.
      */
     timeZoneInformation.DaylightBias = 0;
 
     /* Convert the utc time to local time again, but this time without any
-       adjustment for daylight savings time. 
+       adjustment for daylight savings time.
        */
     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
 
@@ -598,8 +625,8 @@ void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
        observing daylight savings time.
      */
     *pDST = localDST.wHour != local.wHour;
-}       
+}
+
 
 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
 {
@@ -635,7 +662,7 @@ void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
     /* Now adjust for a positive offset from GMT (a negative bias). */
     if (bias < 0)
         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
-}                      
+}
 
 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
 {
@@ -665,7 +692,7 @@ void smb_MarkAllVCsDead(smb_vc_t * exclude)
     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
 
        if (vcp->magic != SMB_VC_MAGIC)
-           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
                       __FILE__, __LINE__);
 
         if (vcp == exclude)
@@ -718,7 +745,7 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
     lock_ObtainWrite(&smb_rctLock);
     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
        if (vcp->magic != SMB_VC_MAGIC)
-           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
                       __FILE__, __LINE__);
 
         lock_ObtainMutex(&vcp->mx);
@@ -746,9 +773,9 @@ 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) {
-            /* We must obtain a challenge for extended auth 
-             * in case the client negotiates smb v3 
+        if (smb_authType == SMB_AUTH_NTLM) {
+            /* We must obtain a challenge for extended auth
+             * in case the client negotiates smb v3
              */
             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
@@ -775,9 +802,9 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
             if (ntsEx == STATUS_SUCCESS) {
                 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
             } else {
-                /* 
+                /*
                  * This will cause the subsequent authentication to fail but
-                 * that is better than us dereferencing a NULL pointer and 
+                 * that is better than us dereferencing a NULL pointer and
                  * crashing.
                  */
                 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
@@ -808,7 +835,7 @@ static int smb_Is8Dot3StarMask(clientchar_t *maskp)
 {
     int i;
     clientchar_t tc;
-        
+
     for(i=0; i<11; i++) {
         tc = *maskp++;
         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
@@ -820,7 +847,7 @@ static int smb_Is8Dot3StarMask(clientchar_t *maskp)
 static int smb_IsStarMask(clientchar_t *maskp)
 {
     clientchar_t tc;
-        
+
     while (*maskp) {
         tc = *maskp++;
         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
@@ -854,7 +881,7 @@ void smb_ReleaseVCInternal(smb_vc_t *vcp)
                     *vcpp = vcp->nextp;
                     break;
                 }
-            } 
+            }
             lock_FinalizeMutex(&vcp->mx);
             memset(vcp,0,sizeof(smb_vc_t));
             free(vcp);
@@ -885,7 +912,7 @@ void smb_ReleaseVCInternal(smb_vc_t *vcp)
         }
     } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
         /* The reference count is non-zero but the VC is dead.
-         * This implies that some FIDs, TIDs, etc on the VC have yet to 
+         * This implies that some FIDs, TIDs, etc on the VC have yet to
          * be cleaned up.  If we were not called by smb_CleanupDeadVC(),
          * add a reference that will be dropped by
          * smb_CleanupDeadVC() and try to cleanup the VC again.
@@ -919,7 +946,7 @@ void smb_ReleaseVCNoLock(smb_vc_t *vcp)
     lock_AssertWrite(&smb_rctLock);
     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
     smb_ReleaseVCInternal(vcp);
-}       
+}
 
 #ifdef DEBUG_SMB_REFCOUNT
 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
@@ -931,7 +958,7 @@ void smb_ReleaseVC(smb_vc_t *vcp)
     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
     smb_ReleaseVCInternal(vcp);
     lock_ReleaseWrite(&smb_rctLock);
-}       
+}
 
 #ifdef DEBUG_SMB_REFCOUNT
 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
@@ -947,7 +974,7 @@ void smb_HoldVCNoLock(smb_vc_t *vcp)
 #else
     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
 #endif
-}       
+}
 
 #ifdef DEBUG_SMB_REFCOUNT
 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
@@ -964,7 +991,7 @@ void smb_HoldVC(smb_vc_t *vcp)
     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
 #endif
     lock_ReleaseWrite(&smb_rctLock);
-}       
+}
 
 void smb_CleanupDeadVC(smb_vc_t *vcp)
 {
@@ -993,7 +1020,7 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     /* remove VCP from smb_allVCsp */
     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
        if ((*vcpp)->magic != SMB_VC_MAGIC)
-           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
                       __FILE__, __LINE__);
         if (*vcpp == vcp) {
             *vcpp = vcp->nextp;
@@ -1054,10 +1081,10 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     }
 
     /* The vcp is now on the deadVCsp list.  We intentionally drop the
-     * reference so that the refcount can reach 0 and we can delete it 
+     * reference so that the refcount can reach 0 and we can delete it
      *
-     * If the refCount == 1 going into the ReleaseVCNoLock call 
-     * the object will be freed and it won't be safe to clear 
+     * If the refCount == 1 going into the ReleaseVCNoLock call
+     * the object will be freed and it won't be safe to clear
      * the flag.
      */
     refCount = vcp->refCount;
@@ -1154,7 +1181,7 @@ void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
         if (tidp->deleteOk) {
             ltpp = &tidp->vcp->tidsp;
             for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
-                if (tp == tidp) 
+                if (tp == tidp)
                     break;
             }
             osi_assertx(tp != NULL, "null smb_tid_t");
@@ -1173,7 +1200,7 @@ void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
         lock_ReleaseWrite(&smb_rctLock);
     if (userp)
         cm_ReleaseUser(userp);
-}              
+}
 
 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
 {
@@ -1184,7 +1211,7 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
         if (uid == uidp->userID) {
             uidp->refCount++;
             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
-                    vcp, uidp->userID, 
+                    vcp, uidp->userID,
                     ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
             break;
         }
@@ -1205,7 +1232,67 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
     }
     lock_ReleaseWrite(&smb_rctLock);
     return uidp;
-}              
+}
+
+afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
+{
+    SID *pSid = NULL;
+    DWORD dwSize1 = 0, dwSize2 = 0;
+    wchar_t *pszRefDomain = NULL;
+    SID_NAME_USE snu = SidTypeGroup;
+    clientchar_t * secSidString = NULL;
+    DWORD gle;
+    afs_int32 isSystem = 0;
+
+    if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
+        isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
+        return isSystem;
+    }
+
+    /*
+     * The input name is not a SID for the user.  See if we can
+     * obtain the SID for the specified name.  If we can, use
+     * that instead of the name provided for the comparison.
+     */
+
+    LookupAccountNameW( NULL /* System Name to begin Search */,
+                        uidp->unp->name,
+                        NULL, &dwSize1,
+                        NULL, &dwSize2,
+                        &snu);
+    gle = GetLastError();
+    if (gle == ERROR_INSUFFICIENT_BUFFER) {
+        pSid = malloc(dwSize1);
+        /*
+         * Although dwSize2 is supposed to include the terminating
+         * NUL character, on Win7 it does not.
+         */
+        pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
+    }
+
+    if ( pSid && pszRefDomain ) {
+        memset(pSid, 0, dwSize1);
+
+        if (LookupAccountNameW( NULL /* System Name to begin Search */,
+                                uidp->unp->name,
+                                pSid, &dwSize1,
+                                pszRefDomain, &dwSize2,
+                                &snu))
+            ConvertSidToStringSidW(pSid, &secSidString);
+    }
+
+    if (secSidString) {
+        isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
+        LocalFree(secSidString);
+    }
+
+    if (pSid)
+        free(pSid);
+    if (pszRefDomain)
+        free(pszRefDomain);
+
+    return isSystem;
+}
 
 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
                                    afs_uint32 flags)
@@ -1235,7 +1322,7 @@ smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
 
     lock_ReleaseWrite(&smb_rctLock);
     return unp;
-}      
+}
 
 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
 {
@@ -1243,7 +1330,7 @@ smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
 
     lock_ObtainWrite(&smb_rctLock);
     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
-        if (!uidp->unp) 
+        if (!uidp->unp)
             continue;
         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
             uidp->refCount++;
@@ -1252,10 +1339,10 @@ smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
             break;
         } else
             continue;
-    }          
+    }
     lock_ReleaseWrite(&smb_rctLock);
     return uidp;
-}       
+}
 
 void smb_ReleaseUsername(smb_username_t *unp)
 {
@@ -1270,7 +1357,7 @@ void smb_ReleaseUsername(smb_username_t *unp)
        (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
         lupp = &usernamesp;
         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
-            if (up == unp) 
+            if (up == unp)
                 break;
         }
         osi_assertx(up != NULL, "null smb_username_t");
@@ -1285,7 +1372,7 @@ void smb_ReleaseUsername(smb_username_t *unp)
     lock_ReleaseWrite(&smb_rctLock);
     if (userp)
         cm_ReleaseUser(userp);
-}      
+}
 
 void smb_HoldUIDNoLock(smb_user_t *uidp)
 {
@@ -1304,7 +1391,7 @@ void smb_ReleaseUID(smb_user_t *uidp)
     if (uidp->refCount == 0) {
         lupp = &uidp->vcp->usersp;
         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
-            if (up == uidp) 
+            if (up == uidp)
                 break;
         }
         osi_assertx(up != NULL, "null smb_user_t");
@@ -1314,7 +1401,7 @@ void smb_ReleaseUID(smb_user_t *uidp)
         smb_ReleaseVCNoLock(uidp->vcp);
        uidp->vcp = NULL;
        free(uidp);
-    }          
+    }
     lock_ReleaseWrite(&smb_rctLock);
 
     if (unp) {
@@ -1322,7 +1409,7 @@ void smb_ReleaseUID(smb_user_t *uidp)
            cm_ReleaseUserVCRef(unp->userp);
        smb_ReleaseUsername(unp);
     }
-}      
+}
 
 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
 {
@@ -1330,7 +1417,7 @@ cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
 
     if (!uidp)
        return NULL;
-    
+
     lock_ObtainMutex(&uidp->mx);
     if (uidp->unp) {
        up = uidp->unp->userp;
@@ -1356,7 +1443,7 @@ cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
     uidp = smb_FindUID(vcp, smbp->uid, 0);
     if (!uidp)
        return NULL;
-    
+
     up = smb_GetUserFromUID(uidp);
 
     smb_ReleaseUID(uidp);
@@ -1393,9 +1480,9 @@ long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepa
  */
 int smb_ChainFID(int fid, smb_packet_t *inp)
 {
-    if (inp->fid == 0 || inp->inCount == 0) 
+    if (inp->fid == 0 || inp->inCount == 0)
         return fid;
-    else 
+    else
         return inp->fid;
 }
 
@@ -1406,7 +1493,7 @@ int smb_SUser(cm_user_t *userp)
 }
 
 /* find a file ID.  If we pass in 0 we select an unused File ID.
- * If the SMB_FLAG_CREATE flag is set, we allocate a new  
+ * If the SMB_FLAG_CREATE flag is set, we allocate a new
  * smb_fid_t data structure if desired File ID cannot be found.
  */
 #ifdef DEBUG_SMB_REFCOUNT
@@ -1417,7 +1504,7 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
 {
     smb_fid_t *fidp;
     int newFid = 0;
-        
+
     if (fid == 0) {
         if (!(flags & SMB_FLAG_CREATE))
             return NULL;
@@ -1521,14 +1608,14 @@ smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
 #endif
 {
     smb_fid_t *fidp = NULL, *nextp = NULL;
-        
+
     if (!scp)
         return NULL;
 
-    /* 
+    /*
      * If the fidp->scp changes out from under us then
      * we must not grab a refCount.  It means the *fidp
-     * was processed by smb_CloseFID() and the *fidp is 
+     * was processed by smb_CloseFID() and the *fidp is
      * no longer valid for use.
      */
     lock_ObtainWrite(&smb_rctLock);
@@ -1627,7 +1714,7 @@ void smb_ReleaseFID(smb_fid_t *fidp)
             userp = fidp->userp;
             fidp->userp = NULL;
 
-            if (vcp->fidsp) 
+            if (vcp->fidsp)
                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
             thrd_CloseHandle(fidp->raw_write_event);
 
@@ -1660,12 +1747,12 @@ void smb_ReleaseFID(smb_fid_t *fidp)
     lock_ReleaseWrite(&smb_rctLock);
 
     /* now release the scache structure */
-    if (scp) 
+    if (scp)
         cm_ReleaseSCache(scp);
 
     if (userp)
         cm_ReleaseUser(userp);
-}       
+}
 
 /*
  * Case-insensitive search for one string in another;
@@ -1729,7 +1816,7 @@ long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
             matchType = SMB_FINDSHARE_EXACT_MATCH;
         else
             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
-        if(vrock->match) 
+        if(vrock->match)
             free(vrock->match);
         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
         vrock->matchType = matchType;
@@ -1757,9 +1844,9 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
     DWORD code;
     DWORD allSubmount = 1;
 
-    /* if allSubmounts == 0, only return the //mountRoot/all share 
-     * if in fact it has been been created in the subMounts table.  
-     * This is to allow sites that want to restrict access to the 
+    /* if allSubmounts == 0, only return the //mountRoot/all share
+     * if in fact it has been been created in the subMounts table.
+     * This is to allow sites that want to restrict access to the
      * world to do so.
      */
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
@@ -1780,7 +1867,7 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
     }
 
     /* In case, the all share is disabled we need to still be able
-     * to handle ioctl requests 
+     * to handle ioctl requests
      */
     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
@@ -1796,7 +1883,7 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
     }
 
     /* Check for volume references
-     * 
+     *
      * They look like <cell>{%,#}<volume>
      */
     if (cm_ClientStrChr(shareName, '%') != NULL ||
@@ -1839,12 +1926,12 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
     cchlen = cblen / sizeof(clientchar_t);
     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
         /* We can accept either unix or PC style AFS pathnames.  Convert
-         * Unix-style to PC style here for internal use. 
+         * Unix-style to PC style here for internal use.
          */
         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) {
@@ -1868,34 +1955,34 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
                 else
                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
             }
-            else if (var = smb_stristr(p, VNLCUserName)) 
+            else if (var = smb_stristr(p, VNLCUserName))
             {
                 if (uidp && uidp->unp)
                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
-                else 
+                else
                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
                 cm_ClientStrLwr(temp);
                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
             }
-            else if (var = smb_stristr(p, VNComputerName)) 
+            else if (var = smb_stristr(p, VNComputerName))
             {
                 sizeTemp = lengthof(temp);
                 GetComputerNameW(temp, &sizeTemp);
                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
             }
-            else if (var = smb_stristr(p, VNLCComputerName)) 
+            else if (var = smb_stristr(p, VNLCComputerName))
             {
                 sizeTemp = lengthof(temp);
                 GetComputerName((LPTSTR)temp, &sizeTemp);
                 cm_ClientStrLwr(temp);
                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
             }
-            else     
+            else
                 break;
         }
         *pathNamep = cm_ClientStrDup(p);
         return 1;
-    } 
+    }
     else
     {
         /* First lookup shareName in root.afs */
@@ -1903,8 +1990,10 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         smb_findShare_rock_t vrock;
         osi_hyper_t thyper;
         fschar_t ftemp[1024];
-        clientchar_t * p = shareName; 
+        clientchar_t * p = shareName;
         int rw = 0;
+        cm_scache_t * rscp;
+        cm_user_t *userp;
 
         /*  attempt to locate a partial match in root.afs.  This is because
             when using the ANSI RAP calls, the share name is limited to 13 chars
@@ -1914,15 +2003,17 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         thyper.LowPart = 0;
 
         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
-        if (vrock.shareName == NULL) 
+        if (vrock.shareName == NULL)
             return 0;
         vrock.match = NULL;
         vrock.matchType = 0;
 
-        cm_HoldSCache(cm_data.rootSCachep);
-        code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
-                           (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
-        cm_ReleaseSCache(cm_data.rootSCachep);
+        userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
+        rscp = cm_RootSCachep(userp, &req);
+        cm_HoldSCache(rscp);
+        code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
+                           userp, &req, NULL);
+        cm_ReleaseSCache(rscp);
 
         free(vrock.shareName);
         vrock.shareName = NULL;
@@ -1945,12 +2036,10 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         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;
             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
         }
-#endif /* AFS_AFSDB_ENV */
         if (cellname)
             free(cellname);
 
@@ -2017,7 +2106,7 @@ int smb_FindShareCSCPolicy(clientchar_t *shareName)
     {
         retval = CSC_POLICY_DISABLE;
     }
-       
+
     RegCloseKey(hkCSCPolicy);
     return retval;
 }
@@ -2028,7 +2117,7 @@ int smb_FindShareCSCPolicy(clientchar_t *shareName)
 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
 {
     smb_dirSearch_t *dsp;
-        
+
     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
         if (dsp->cookie == cookie) {
             if (dsp != smb_firstDirSearchp) {
@@ -2052,12 +2141,12 @@ smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
         }
     }
     return dsp;
-}       
+}
 
 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
 {
     lock_ObtainMutex(&dsp->mx);
-    osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
+    osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
              dsp->cookie, dsp, dsp->scp);
     dsp->flags |= SMB_DIRSEARCH_DELETE;
     if (dsp->scp != NULL) {
@@ -2066,11 +2155,11 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
             dsp->scp->bulkStatProgress = hzero;
-        }      
+        }
         lock_ReleaseWrite(&dsp->scp->rw);
-    }  
+    }
     lock_ReleaseMutex(&dsp->mx);
-}               
+}
 
 /* Must be called with the smb_globalLock held */
 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
@@ -2087,7 +2176,7 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
             lock_ReleaseMutex(&dsp->mx);
             lock_FinalizeMutex(&dsp->mx);
             scp = dsp->scp;
-            osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
+            osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
                      dsp->cookie, dsp, scp);
             free(dsp);
         } else {
@@ -2095,16 +2184,16 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
         }
     }
     /* do this now to avoid spurious locking hierarchy creation */
-    if (scp) 
+    if (scp)
         cm_ReleaseSCache(scp);
-}       
+}
 
 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
 {
     lock_ObtainWrite(&smb_globalLock);
     smb_ReleaseDirSearchNoLock(dsp);
     lock_ReleaseWrite(&smb_globalLock);
-}       
+}
 
 /* find a dir search structure by cookie value, and return it held */
 smb_dirSearch_t *smb_FindDirSearch(long cookie)
@@ -2128,13 +2217,13 @@ void smb_GCDirSearches(int isV3)
     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
     int victimCount;
     int i;
-        
+
     victimCount = 0;   /* how many have we got so far */
     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
         /* we'll move tp from queue, so
          * do this early.
          */
-        prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);        
+        prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
         /* if no one is using this guy, and we're either in the new protocol,
          * or we're in the old one and this is a small enough ID to be useful
          * to the old protocol, GC this guy.
@@ -2149,10 +2238,10 @@ void smb_GCDirSearches(int isV3)
         }
 
         /* don't do more than this */
-        if (victimCount >= SMB_DIRSEARCH_GCMAX) 
+        if (victimCount >= SMB_DIRSEARCH_GCMAX)
             break;
     }
-       
+
     /* now release them */
     for (i = 0; i < victimCount; i++) {
         smb_ReleaseDirSearchNoLock(victimsp[i]);
@@ -2189,10 +2278,10 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         /* twice so we have enough tries to find guys we GC after one pass;
          * 10 extra is just in case I mis-counted.
          */
-        if (++counter > 2*maxAllowed+10) 
+        if (++counter > 2*maxAllowed+10)
             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
 
-        if (smb_dirSearchCounter > maxAllowed) {       
+        if (smb_dirSearchCounter > maxAllowed) {
             smb_dirSearchCounter = 1;
         }
         if (smb_dirSearchCounter == start) {
@@ -2208,7 +2297,7 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
             dsp->refCount--;
             ++smb_dirSearchCounter;
             continue;
-        }      
+        }
 
         dsp = malloc(sizeof(*dsp));
         memset(dsp, 0, sizeof(*dsp));
@@ -2218,13 +2307,13 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
         dsp->lastTime = osi_Time();
         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
-        if (!smb_lastDirSearchp) 
+        if (!smb_lastDirSearchp)
             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
-    
-       osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
+
+       osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
                 dsp->cookie, dsp);
        break;
-    }  
+    }
     lock_ReleaseWrite(&smb_globalLock);
     return dsp;
 }
@@ -2235,7 +2324,7 @@ static smb_packet_t *smb_GetPacket(void)
 
     lock_ObtainWrite(&smb_globalLock);
     tbp = smb_packetFreeListp;
-    if (tbp) 
+    if (tbp)
         smb_packetFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
@@ -2278,14 +2367,14 @@ static NCB *smb_GetNCB(void)
 
     lock_ObtainWrite(&smb_globalLock);
     tbp = smb_ncbFreeListp;
-    if (tbp) 
+    if (tbp)
         smb_ncbFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
         tbp = calloc(sizeof(*tbp),1);
         tbp->magic = SMB_NCBMAGIC;
     }
-        
+
     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
 
     memset(&tbp->ncb, 0, sizeof(NCB));
@@ -2309,7 +2398,7 @@ void smb_FreePacket(smb_packet_t *tbp)
 {
     smb_vc_t * vcp = NULL;
     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
-        
+
     lock_ObtainWrite(&smb_globalLock);
     tbp->nextp = smb_packetFreeListp;
     smb_packetFreeListp = tbp;
@@ -2335,10 +2424,10 @@ void smb_FreePacket(smb_packet_t *tbp)
 static void smb_FreeNCB(NCB *bufferp)
 {
     smb_ncb_t *tbp;
-        
+
     tbp = (smb_ncb_t *) bufferp;
     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
-        
+
     lock_ObtainWrite(&smb_globalLock);
     tbp->nextp = smb_ncbFreeListp;
     smb_ncbFreeListp = tbp;
@@ -2354,10 +2443,10 @@ unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
 
     parmBytes = *smbp->wctp << 1;
     afterParmsp = smbp->wctp + parmBytes + 1;
-        
+
     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
     if (nbytesp) *nbytesp = dataBytes;
-        
+
     /* don't forget to skip the data byte count, since it follows
      * the parameters; that's where the "2" comes from below.
      */
@@ -2373,10 +2462,10 @@ void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
     unsigned char *afterParmsp;
 
     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
-        
+
     *afterParmsp++ = dsize & 0xff;
     *afterParmsp = (dsize>>8) & 0xff;
-}       
+}
 
 /* return the parm'th parameter in the smbp packet */
 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
@@ -2393,12 +2482,12 @@ unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
                 parm, parmCount, smbp->ncb_length);
        osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
                  parm, parmCount, smbp->ncb_length);
-       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
                 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
         osi_panic(s, __FILE__, __LINE__);
     }
     parmDatap = smbp->wctp + (2*parm) + 1;
-        
+
     return parmDatap[0] + (parmDatap[1] << 8);
 }
 
@@ -2417,12 +2506,12 @@ unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
                 parm, parmCount, smbp->ncb_length);
        osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
                  parm, parmCount, smbp->ncb_length);
-       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
                 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
         osi_panic(s, __FILE__, __LINE__);
     }
     parmDatap = smbp->wctp + (2*parm) + 1;
-        
+
     return parmDatap[0];
 }
 
@@ -2441,12 +2530,12 @@ unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
                 parm, parmCount, smbp->ncb_length);
        osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
                  parm, parmCount, smbp->ncb_length);
-       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
                 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
         osi_panic(s, __FILE__, __LINE__);
     }
     parmDatap = smbp->wctp + (2*parm) + 1;
-        
+
     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
 }
 
@@ -2463,14 +2552,14 @@ unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
 
         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
                 parm, offset, parmCount, smbp->ncb_length);
-       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
                 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
                 parm, offset, parmCount, smbp->ncb_length);
         osi_panic(s, __FILE__, __LINE__);
     }
     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
-       
+
     return parmDatap[0] + (parmDatap[1] << 8);
 }
 
@@ -2479,20 +2568,20 @@ void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
     unsigned char *parmDatap;
 
     /* make sure we have enough slots */
-    if (*smbp->wctp <= slot) 
+    if (*smbp->wctp <= slot)
         *smbp->wctp = slot+1;
-        
+
     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
     *parmDatap++ = parmValue & 0xff;
     *parmDatap = (parmValue>>8) & 0xff;
-}       
+}
 
 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
 {
     unsigned char *parmDatap;
 
     /* make sure we have enough slots */
-    if (*smbp->wctp <= slot) 
+    if (*smbp->wctp <= slot)
         *smbp->wctp = slot+2;
 
     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
@@ -2508,13 +2597,13 @@ void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
     int i;
 
     /* make sure we have enough slots */
-    if (*smbp->wctp <= slot) 
+    if (*smbp->wctp <= slot)
         *smbp->wctp = slot+4;
 
     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
     for (i=0; i<8; i++)
         *parmDatap++ = *parmValuep++;
-}       
+}
 
 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
 {
@@ -2571,7 +2660,7 @@ void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponent
         }
 
         while (1) {
-            if (inPathp == lastSlashp) 
+            if (inPathp == lastSlashp)
                 break;
             *outPathp++ = *inPathp++;
         }
@@ -2588,7 +2677,7 @@ clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
     size_t cb;
     afs_uint32 type = *inp++;
 
-    /* 
+    /*
      * The first byte specifies the type of the input string.
      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
      * strings.
@@ -2859,7 +2948,7 @@ unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *length
 {
     int tlen;
 
-    if (*inp++ != 0x5) 
+    if (*inp++ != 0x5)
         return NULL;
     tlen = inp[0] + (inp[1]<<8);
     inp += 2;          /* skip length field */
@@ -2867,12 +2956,12 @@ unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *length
     if (chainpp) {
         *chainpp = inp + tlen;
     }
-        
-    if (lengthp) 
+
+    if (lengthp)
         *lengthp = tlen;
-        
+
     return inp;
-}      
+}
 
 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
 {
@@ -2881,13 +2970,13 @@ unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengt
     if (*inp++ != 0x1) return NULL;
     tlen = inp[0] + (inp[1]<<8);
     inp += 2;          /* skip length field */
-        
+
     if (chainpp) {
         *chainpp = inp + tlen;
-    }  
+    }
 
     if (lengthp) *lengthp = tlen;
-        
+
     return inp;
 }
 
@@ -2898,9 +2987,9 @@ void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op
     smb_t *inSmbp;
 
     outp = (smb_t *) op;
-       
+
     /* zero the basic structure through the smb_wct field, and zero the data
-     * size field, assuming that wct stays zero; otherwise, you have to 
+     * size field, assuming that wct stays zero; otherwise, you have to
      * explicitly set the data size field, too.
      */
     inSmbp = (smb_t *) inp;
@@ -2931,7 +3020,7 @@ void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op
 
     /* copy fields in generic packet area */
     op->wctp = &outp->wct;
-}       
+}
 
 /* send a (probably response) packet; vcp tells us to whom to send it.
  * we compute the length by looking at wct and bcc fields.
@@ -2943,13 +3032,13 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
     long code = 0;
     unsigned char *tp;
     int localNCB = 0;
-        
+
     ncbp = inp->ncbp;
     if (ncbp == NULL) {
         ncbp = smb_GetNCB();
         localNCB = 1;
     }
+
     memset(ncbp, 0, sizeof(NCB));
 
     extra = 2 * (*inp->wctp);  /* space used by parms, in bytes */
@@ -2957,14 +3046,14 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
     extra += tp[0] + (tp[1]<<8);
     extra += (unsigned int)(inp->wctp - inp->data);    /* distance to last wct field */
     extra += 3;                        /* wct and length fields */
-        
+
     ncbp->ncb_length = extra;  /* bytes to send */
     ncbp->ncb_lsn = (unsigned char) vcp->lsn;  /* vc to use */
     ncbp->ncb_lana_num = vcp->lana;
     ncbp->ncb_command = NCBSEND;       /* op means send data */
     ncbp->ncb_buffer = (char *) inp;/* packet */
     code = Netbios(ncbp);
-        
+
     if (code != 0) {
        const char * s = ncb_error_string(code);
         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
@@ -2989,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;
 
@@ -2997,7 +3086,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     /* NT Status codes are listed in ntstatus.h not winerror.h */
     if (code == 0) {
         NTStatus = 0;
-    } 
+    }
     else if (code == CM_ERROR_NOSUCHCELL) {
         NTStatus = 0xC0000034L;        /* Name not found */
     }
@@ -3005,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 */
@@ -3038,7 +3135,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     }
     else if (code == CM_ERROR_NOSUCHPATH) {
         NTStatus = 0xC000003AL;        /* Object path not found */
-    }          
+    }
     else if (code == CM_ERROR_TOOBIG) {
         NTStatus = 0xC000007BL;        /* Invalid image format */
     }
@@ -3059,7 +3156,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     }
     else if (code == CM_ERROR_NOTEMPTY) {
         NTStatus = 0xC0000101L;        /* Directory not empty */
-    }  
+    }
     else if (code == CM_ERROR_CROSSDEVLINK) {
         NTStatus = 0xC00000D4L;        /* Not same device */
     }
@@ -3083,7 +3180,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_NOIPC) {
 #ifdef COMMENT
         NTStatus = 0xC0000022L;        /* Access Denied */
-#else   
+#else
         NTStatus = 0xC000013DL; /* Remote Resources */
 #endif
     }
@@ -3124,9 +3221,12 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_BUFFERTOOSMALL) {
         NTStatus = 0xC0000023L;        /* Buffer too small */
     }
+    else if (code == CM_ERROR_BUFFER_OVERFLOW) {
+        NTStatus = 0x80000005L;        /* Buffer overflow */
+    }
     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
         NTStatus = 0xC0000035L;        /* Object name collision */
-    }   
+    }
     else if (code == CM_ERROR_BADPASSWORD) {
         NTStatus = 0xC000006DL; /* unknown username or bad password */
     }
@@ -3145,26 +3245,30 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     }
     else if (code == CM_ERROR_PATH_NOT_COVERED) {
         NTStatus = 0xC0000257L; /* Path Not Covered */
-    } 
+    }
     else if (code == CM_ERROR_ALLBUSY) {
 #ifdef COMMENT
         NTStatus = 0xC000022DL; /* Retry */
 #else
-        NTStatus = 0xC00000B5L; /* I/O Timeout */
+        NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
 #endif
-    } 
+    }
     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
+#ifdef COMMENT
         NTStatus = 0xC000003AL; /* Path not found */
-    } 
+#else
+        NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
+#endif
+    }
     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
        NTStatus = 0xC0000322L; /* No Kerberos key */
-    } 
+    }
     else if (code == CM_ERROR_BAD_LEVEL) {
        NTStatus = 0xC0000148L; /* Invalid Level */
-    } 
+    }
     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
        NTStatus = 0xC000007EL; /* Range Not Locked */
-    } 
+    }
     else if (code == CM_ERROR_NOSUCHDEVICE) {
         NTStatus = 0xC000000EL; /* No Such Device */
     }
@@ -3177,17 +3281,20 @@ 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 */
     }
 
     *NTStatusp = NTStatus;
     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
-}       
+}
 
-/* 
- * NTSTATUS <-> Win32 Error Translation 
- * http://support.microsoft.com/kb/113996 
+/*
+ * NTSTATUS <-> Win32 Error Translation
+ * http://support.microsoft.com/kb/113996
  */
 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
 {
@@ -3196,7 +3303,7 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     /* map CM_ERROR_* errors to Win32 32-bit error codes */
     if (code == 0) {
         Win32E = 0;
-    } 
+    }
     else if (code == CM_ERROR_NOSUCHCELL) {
         Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
     }
@@ -3225,7 +3332,7 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     }
     else if (code == CM_ERROR_NOSUCHPATH) {
         Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
-    }          
+    }
     else if (code == CM_ERROR_TOOBIG) {
         Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
     }
@@ -3246,7 +3353,7 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     }
     else if (code == CM_ERROR_NOTEMPTY) {
         Win32E = ERROR_DIR_NOT_EMPTY;  /* Directory not empty */
-    }  
+    }
     else if (code == CM_ERROR_CROSSDEVLINK) {
         Win32E = ERROR_NOT_SAME_DEVICE;        /* Not same device */
     }
@@ -3265,7 +3372,7 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     else if (code == CM_ERROR_NOIPC) {
 #ifdef COMMENT
         Win32E = ERROR_ACCESS_DENIED;  /* Access Denied */
-#else   
+#else
         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
 #endif
     }
@@ -3308,7 +3415,7 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     }
     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
         Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
-    }   
+    }
     else if (code == CM_ERROR_BADPASSWORD) {
         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
     }
@@ -3327,22 +3434,22 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     }
     else if (code == CM_ERROR_PATH_NOT_COVERED) {
         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
-    } 
+    }
     else if (code == CM_ERROR_ALLBUSY) {
         Win32E = ERROR_RETRY;           /* Retry */
-    } 
+    }
     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
-    } 
+    }
     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
        Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
-    } 
+    }
     else if (code == CM_ERROR_BAD_LEVEL) {
        Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
-    } 
+    }
     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
        Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
-    } 
+    }
     else if (code == CM_ERROR_NOSUCHDEVICE) {
         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
     }
@@ -3361,7 +3468,7 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
 
     *Win32Ep = Win32E;
     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
-}       
+}
 
 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
                       unsigned char *classp)
@@ -3438,7 +3545,7 @@ void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
     else if (code == CM_ERROR_ISDIR) {
         class = 1;     /* access denied; DOS doesn't have a good match */
         error = 5;
-    }       
+    }
     else if (code == CM_ERROR_BADOP) {
         class = 2;
         error = 65535;
@@ -3532,7 +3639,7 @@ void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
     *scodep = error;
     *classp = class;
     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
-}       
+}
 
 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
@@ -3586,21 +3693,12 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
 
     if (*inp->wctp == 10) {
         /* we were sent a request with 64-bit file offsets */
-#ifdef AFS_LARGEFILES
         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
 
         if (LargeIntegerLessThanZero(offset)) {
             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
             goto send1;
         }
-#else
-        if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
-            osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
-            goto send1;
-        } else {
-            offset.HighPart = 0;
-        }
-#endif
     } else {
         /* we were sent a request with 32-bit file offsets */
         offset.HighPart = 0;
@@ -3644,7 +3742,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
         lock_ReleaseWrite(&fidp->scp->rw);
-    }    
+    }
     if (code) {
         lock_ReleaseMutex(&fidp->mx);
         goto send1a;
@@ -3669,7 +3767,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
             /* Give back raw buffer */
             lock_ObtainMutex(&smb_RawBufLock);
             *((char **) rawBuf) = smb_RawBufs;
-            
+
             smb_RawBufs = rawBuf;
             lock_ReleaseMutex(&smb_RawBufLock);
         }
@@ -3773,7 +3871,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
          */
         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
             coreProtoIndex = tcounter;
-        }      
+        }
         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
             v3ProtoIndex = tcounter;
         }
@@ -3799,8 +3897,8 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (VistaProtoIndex != -1) {
         protoIndex = VistaProtoIndex;
         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
-    } else 
-#endif 
+    } else
+#endif
        if (NTProtoIndex != -1) {
         protoIndex = NTProtoIndex;
         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
@@ -3808,11 +3906,11 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     else if (v3ProtoIndex != -1) {
         protoIndex = v3ProtoIndex;
         vcp->flags |= SMB_VCFLAG_USEV3;
-    }  
+    }
     else if (coreProtoIndex != -1) {
         protoIndex = coreProtoIndex;
         vcp->flags |= SMB_VCFLAG_USECORE;
-    }  
+    }
     else protoIndex = -1;
     lock_ReleaseMutex(&vcp->mx);
 
@@ -3834,34 +3932,31 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         /* The session key is not a well documented field however most clients
          * will echo back the session key to the server.  Currently we are using
          * the same value for all sessions.  We should generate a random value
-         * and store it into the vcp 
+         * 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?
          */
         /*
-        if (isWindows2000) 
+        if (isWindows2000)
         smb_SetSMBParmLong(outp, 9, 0x43fd);
-        else 
+        else
         smb_SetSMBParmLong(outp, 9, 0x251);
         */
         /* Capabilities: *
          * 32-bit error codes *
          * and NT Find *
          * and NT SMB's *
-         * and raw mode 
+         * and raw mode
          * and DFS
          * and Unicode */
         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
 #endif
-#ifdef AFS_LARGEFILES
                NTNEGOTIATE_CAPABILITY_LARGEFILES |
-#endif
                NTNEGOTIATE_CAPABILITY_NTFIND |
                NTNEGOTIATE_CAPABILITY_RAWMODE |
                NTNEGOTIATE_CAPABILITY_NTSMB;
@@ -3895,33 +3990,52 @@ 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) {
         smb_SetSMBParm(outp, 0, protoIndex);
 
         /* NOTE: Extended authentication cannot be negotiated with v3
-         * therefore we fail over to NTLM 
+         * therefore we fail over to NTLM
          */
         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
             smb_SetSMBParm(outp, 1,
@@ -3945,7 +4059,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);   /* server tzone */
 
         /* NOTE: Extended authentication cannot be negotiated with v3
-         * therefore we fail over to NTLM 
+         * therefore we fail over to NTLM
          */
         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
@@ -3976,21 +4090,21 @@ void smb_CheckVCs(void)
     smb_vc_t * vcp, *nextp;
     smb_packet_t * outp = smb_GetPacket();
     smb_t *smbp;
-            
+
     lock_ObtainWrite(&smb_rctLock);
-    for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
+    for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
     {
        if (vcp->magic != SMB_VC_MAGIC)
-           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
                       __FILE__, __LINE__);
 
         /* on the first pass hold 'vcp' which was not held as 'nextp' */
         if (vcp != nextp)
             smb_HoldVCNoLock(vcp);
 
-        /* 
+        /*
          * obtain a reference to 'nextp' now because we drop the
-         * smb_rctLock later and the list contents could change 
+         * smb_rctLock later and the list contents could change
          * or 'vcp' could be destroyed when released.
          */
        nextp = vcp->nextp;
@@ -4037,11 +4151,11 @@ void smb_Daemon(void *parmp)
 
         if (smbShutdownFlag == 1)
             break;
-        
+
         if ((count % 72) == 0) {       /* every five minutes */
             struct tm myTime;
             time_t old_localZero = smb_localZero;
-                
+
             /* Initialize smb_localZero */
             myTime.tm_isdst = -1;              /* compute whether on DST or not */
             myTime.tm_year = 70;
@@ -4054,7 +4168,7 @@ void smb_Daemon(void *parmp)
 
 #ifdef AFS_FREELANCE
             if ( smb_localZero != old_localZero )
-                cm_noteLocalMountPointChange();
+                cm_noteLocalMountPointChange(FALSE);
 #endif
 
            smb_CheckVCs();
@@ -4068,8 +4182,8 @@ void smb_Daemon(void *parmp)
            smb_username_t *unp;
 
            lock_ObtainMutex(&(*unpp)->mx);
-           if ( (*unpp)->refCount > 0 || 
-                ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
+           if ( (*unpp)->refCount > 0 ||
+                ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
                 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
                ;
            else if (!smb_LogoffTokenTransfer ||
@@ -4080,7 +4194,7 @@ void smb_Daemon(void *parmp)
            if (deleteOk) {
                cm_user_t * userp;
 
-               unp = *unpp;    
+               unp = *unpp;
                *unpp = unp->nextp;
                unp->nextp = NULL;
                lock_FinalizeMutex(&unp->mx);
@@ -4146,7 +4260,7 @@ void smb_WaitingLocksDaemon()
                 }
 
                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
-                
+
                 /* wl->state is either _DONE or _WAITING.  _ERROR
                    would no longer be on the queue. */
                 code = cm_RetryLock( wl->lockp,
@@ -4188,16 +4302,16 @@ void smb_WaitingLocksDaemon()
 
                 for (wl = wlRequest->locks; wl; wl = wlNext) {
                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
-                
+
                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
-                        cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
+                        cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
                                   wl->LLength, wl->key, 0, NULL, &req);
 
                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
 
                     free(wl);
                 }
-                
+
                 lock_ReleaseWrite(&scp->rw);
 
             } else {
@@ -4338,46 +4452,46 @@ int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
 
     /* find last backslash, or use whole thing if there is none */
     tp = cm_ClientStrRChr(pathp, '\\');
-    if (!tp) 
+    if (!tp)
         tp = pathp;
-    else 
+    else
         tp++;  /* skip slash */
-        
+
     up = maskp;
 
     /* names starting with a dot are illegal */
-    if (*tp == '.') 
+    if (*tp == '.')
         valid8Dot3 = 0;
 
     for(i=0;; i++) {
         tc = *tp++;
-        if (tc == 0) 
+        if (tc == 0)
             return valid8Dot3;
-        if (tc == '.' || tc == '"') 
+        if (tc == '.' || tc == '"')
             break;
-        if (i < 8) 
+        if (i < 8)
             *up++ = tc;
         else
             valid8Dot3 = 0;
     }
-        
+
     /* if we get here, tp point after the dot */
     up = maskp+8;      /* ext goes here */
     for(i=0;;i++) {
         tc = *tp++;
-        if (tc == 0) 
+        if (tc == 0)
             return valid8Dot3;
 
         /* too many dots */
-        if (tc == '.' || tc == '"') 
+        if (tc == '.' || tc == '"')
             valid8Dot3 = 0;
 
         /* copy extension if not too long */
-        if (i < 3) 
+        if (i < 3)
             *up++ = tc;
-        else 
+        else
             valid8Dot3 = 0;
-    }   
+    }
 
     /* unreachable */
 }
@@ -4395,9 +4509,9 @@ int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
     /* XXX redo this, calling cm_MatchMask with a converted mask */
 
     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
-    if (!valid) 
+    if (!valid)
         return 0;
+
     /* otherwise, we have a valid 8.3 name; see if we have a match,
      * treating '?' as a wildcard in maskp (but not in the file name).
      */
@@ -4408,11 +4522,11 @@ int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
         tc2 = *tp2++;  /* clientchar_t from mask */
         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
-        if (tc1 == tc2) 
+        if (tc1 == tc2)
             continue;
-        if (tc2 == '?' && tc1 != ' ') 
+        if (tc2 == '?' && tc1 != ' ')
             continue;
-        if (tc2 == '>') 
+        if (tc2 == '>')
             continue;
         return 0;
     }
@@ -4424,14 +4538,14 @@ int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
 clientchar_t *smb_FindMask(clientchar_t *pathp)
 {
     clientchar_t *tp;
-        
+
     tp = cm_ClientStrRChr(pathp, '\\');        /* find last slash */
 
-    if (tp) 
+    if (tp)
         return tp+1;   /* skip the slash */
-    else 
+    else
         return pathp;  /* no slash, return the entire path */
-}       
+}
 
 /* SMB_COM_SEARCH for a volume label
 
@@ -4445,7 +4559,7 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     unsigned char *statBlockp;
     unsigned char initStatBlock[21];
     int statLen;
-        
+
     osi_Log0(smb_logp, "SMB receive search volume");
 
     /* pull pathname and stat block out of request */
@@ -4460,7 +4574,7 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
         statBlockp = initStatBlock;
         statBlockp[0] = 8;
     }
-        
+
     /* for returning to caller */
     smb_Get8Dot3MaskFromPath(mask, pathp);
 
@@ -4508,9 +4622,9 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
      */
     smb_SetSMBDataLength(outp, 46);
     return 0;
-}       
+}
 
-static long 
+static long
 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
                         clientchar_t * tidPathp, clientchar_t * relPathp,
                         cm_user_t *userp, cm_req_t *reqp)
@@ -4527,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;
 
@@ -4547,8 +4661,8 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
 
         memset(bsp, 0, sizeof(cm_bulkStat_t));
 
-        for (patchp = *dirPatchespp, count=0; 
-             patchp; 
+        for (patchp = *dirPatchespp, count=0;
+             patchp;
              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
             cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
             int i;
@@ -4597,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) {
@@ -4624,7 +4738,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
                 break;
             default:
                 /* if we get here we either have a normal file
-                * or we have a file for which we have never 
+                * or we have a file for which we have never
                 * received status info.  In this case, we can
                 * check the even/odd value of the entry's vnode.
                 * odd means it is to be treated as a directory
@@ -4649,7 +4763,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
             *((u_short *)dptr) = shortTemp;
             dptr += 2;
-                
+
             /* copy out file length */
             *((u_long *)dptr) = 0;
             dptr += 4;
@@ -4663,7 +4777,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
 
             /* get dos time */
             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
-                
+
             /* copy out time */
             shortTemp = (unsigned short) (dosTime & 0xffff);
             *((u_short *)dptr) = shortTemp;
@@ -4673,7 +4787,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
             *((u_short *)dptr) = shortTemp;
             dptr += 2;
-                
+
             /* copy out file length */
             *((u_long *)dptr) = scp->length.LowPart;
             dptr += 4;
@@ -4681,13 +4795,13 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
         }
         cm_ReleaseSCache(scp);
     }
-        
+
     /* now free the patches */
     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
         free(patchp);
-    }  
-        
+    }
+
     /* and mark the list as empty */
     *dirPatchespp = NULL;
 
@@ -4744,7 +4858,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     maxCount = smb_GetSMBParm(inp, 0);
 
     dirListPatchesp = NULL;
-        
+
     caseFold = CM_FLAG_CASEFOLD;
 
     tp = smb_GetSMBData(inp, NULL);
@@ -4787,9 +4901,9 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         memcpy(dsp->mask, mask, 12);
 
         /* track if this is likely to match a lot of entries */
-        if (smb_Is8Dot3StarMask(mask)) 
+        if (smb_Is8Dot3StarMask(mask))
             starPattern = 1;
-        else 
+        else
             starPattern = 0;
     } else {
         /* pull the next cookie value out of the search status block */
@@ -4844,7 +4958,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
 
-        code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+        code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
         if (code == 0) {
 #ifdef DFS_SUPPORT
@@ -4904,7 +5018,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         smb_ReleaseDirSearch(dsp);
         return code;
     }
-        
+
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
     dirLength = scp->length;
@@ -4955,7 +5069,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                       returnedNames, maxCount);
             break;
         }
-                
+
         /* check if we've passed the dir's EOF */
         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
 
@@ -4970,12 +5084,12 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             if (bufferp) {
                 buf_Release(bufferp);
                 bufferp = NULL;
-            }  
+            }
             lock_ReleaseWrite(&scp->rw);
             code = buf_Get(scp, &thyper, &req, &bufferp);
             lock_ObtainMutex(&dsp->mx);
 
-            /* now, if we're doing a star match, do bulk fetching of all of 
+            /* now, if we're doing a star match, do bulk fetching of all of
              * the status info for files in the dir.
              */
             if (starPattern)
@@ -5000,7 +5114,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
                     break;
                 }
-                                
+
                cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
 
                 if (cm_HaveBuffer(scp, bufferp, 0)) {
@@ -5011,7 +5125,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                 /* otherwise, load the buffer and try again */
                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
                 if (code) {
-                    osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
+                    osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
                               scp, bufferp, code);
                     break;
                 }
@@ -5231,13 +5345,13 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     osi_assertx(temp == (43 * returnedNames), "unexpected data length");
     origOp[1] = (unsigned char)(temp & 0xff);
     origOp[2] = (unsigned char)((temp>>8) & 0xff);
-    if (returnedNames == 0) 
+    if (returnedNames == 0)
         smb_DeleteDirSearch(dsp);
     smb_ReleaseDirSearch(dsp);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     return code;
-}      
+}
 
 
 /* verify that this is a valid path to a directory.  I don't know why they
@@ -5266,11 +5380,11 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         return CM_ERROR_BADSMB;
     osi_Log1(smb_logp, "SMB receive check path %S",
              osi_LogSaveClientString(smb_logp, pathp));
-        
-    rootScp = cm_data.rootSCachep;
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
+    rootScp = cm_RootSCachep(userp, &req);
+
     caseFold = CM_FLAG_CASEFOLD;
 
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
@@ -5286,7 +5400,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
@@ -5324,7 +5438,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_ReleaseSCache(newScp);
     cm_ReleaseUser(userp);
     return code;
-}      
+}
 
 /* SMB_COM_SET_INFORMATION */
 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -5352,14 +5466,14 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
-               
+
     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
              dosTime, attribute);
 
-    rootScp = cm_data.rootSCachep;
-        
     userp = smb_GetUserFromVCP(vcp, inp);
 
+    rootScp = cm_RootSCachep(userp, &req);
+
     caseFold = CM_FLAG_CASEFOLD;
 
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
@@ -5434,7 +5548,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         code = cm_SetAttr(newScp, &attr, userp, &req);
     else
         code = 0;
-        
+
     cm_ReleaseSCache(newScp);
     cm_ReleaseUser(userp);
 
@@ -5464,17 +5578,17 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
-        
+
     if (*pathp == 0)           /* null path */
         pathp = _C("\\");
 
     osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
              osi_LogSaveClientString(smb_logp, pathp));
 
-    rootScp = cm_data.rootSCachep;
-        
     userp = smb_GetUserFromVCP(vcp, inp);
 
+    rootScp = cm_RootSCachep(userp, &req);
+
     /* we shouldn't need this for V3 requests, but we seem to */
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -5522,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;
@@ -5535,6 +5649,13 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
                 return code;
             }
         }
+        else if (code != CM_ERROR_NOSUCHFILE &&
+                 code != CM_ERROR_NOSUCHPATH &&
+                 code != CM_ERROR_BPLUS_NOMATCH)
+        {
+            cm_ReleaseUser(userp);
+            return code;
+        }
     }
 #endif /* SPECIAL_FOLDERS */
 
@@ -5544,7 +5665,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
@@ -5573,7 +5694,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     attrs = smb_Attributes(newScp);
 
     smb_SetSMBParm(outp, 0, attrs);
-        
+
     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
@@ -5591,13 +5712,13 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     cm_ReleaseUser(userp);
 
     return 0;
-}      
+}
 
 /* SMB_COM_TREE_DISCONNECT */
 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tid_t *tidp;
-        
+
     osi_Log0(smb_logp, "SMB receive tree disconnect");
 
     /* find the tree and free it */
@@ -5699,9 +5820,9 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
+    code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
                     tidPathp, &req, &scp);
-        
+
     if (code) {
         cm_ReleaseUser(userp);
         return code;
@@ -5744,7 +5865,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     else if ((share & 0xf) == 1)
         fidp->flags |= SMB_FID_OPENWRITE;
-    else 
+    else
         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
 
     /* save the  user */
@@ -5756,7 +5877,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
     lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
+
     smb_SetSMBParm(outp, 0, fidp->fid);
     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -5769,7 +5890,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBDataLength(outp, 0);
        lock_ReleaseMutex(&fidp->mx);
     lock_ReleaseRead(&scp->rw);
-        
+
     /* notify open */
     cm_Open(scp, 0, userp);
 
@@ -5798,7 +5919,7 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     int caseFold;
     int match;
     normchar_t matchName[MAX_PATH];
-        
+
     rockp = vrockp;
 
     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
@@ -5860,7 +5981,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     memset(&rock, 0, sizeof(rock));
 
     attribute = smb_GetSMBParm(inp, 0);
-        
+
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
     if (!pathp)
@@ -5881,13 +6002,13 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
                     &req, &dscp);
     if (code) {
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
@@ -5901,9 +6022,9 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #endif /* DFS_SUPPORT */
 
     /* otherwise, scp points to the parent directory. */
-    if (!lastNamep) 
+    if (!lastNamep)
         lastNamep = pathp;
-    else 
+    else
         lastNamep++;
 
     rock.any = 0;
@@ -5922,8 +6043,8 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     rock.vcp = vcp;
     rock.matches = NULL;
 
-    /* Now, if we aren't dealing with a wildcard match, we first try an exact 
-     * match.  If that fails, we do a case insensitve match. 
+    /* Now, if we aren't dealing with a wildcard match, we first try an exact
+     * match.  If that fails, we do a case insensitve match.
      */
     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
         !smb_IsStarMask(rock.maskp)) {
@@ -5934,11 +6055,11 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             rock.flags |= SMB_MASKFLAG_CASEFOLD;
         }
     }
+
     if (!rock.any)
         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
-    
-    if (code == CM_ERROR_STOPNOW) 
+
+    if (code == CM_ERROR_STOPNOW)
         code = 0;
 
     if (code == 0 && rock.matches) {
@@ -5971,7 +6092,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
   done:
     if (userp)
     cm_ReleaseUser(userp);
-        
+
     if (dscp)
     cm_ReleaseSCache(dscp);
 
@@ -5981,7 +6102,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (code == 0 && !rock.any)
         code = CM_ERROR_NOSUCHFILE;
     return code;
-}       
+}
 
 typedef struct smb_renameRock {
     cm_scache_t *odscp;  /* old dir */
@@ -6040,7 +6161,7 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
 }
 
 
-long 
+long
 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
 {
     long code = 0;
@@ -6073,13 +6194,13 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
 
     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
                     userp, tidPathp, &req, &oldDscp);
     if (code) {
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
@@ -6093,7 +6214,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
 #endif /* DFS_SUPPORT */
 
     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
                     userp, tidPathp, &req, &newDscp);
 
     if (code) {
@@ -6121,15 +6242,15 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
      */
 
     /* handle the old name first */
-    if (!oldLastNamep) 
+    if (!oldLastNamep)
         oldLastNamep = oldPathp;
-    else 
+    else
         oldLastNamep++;
 
     /* and handle the new name, too */
-    if (!newLastNamep) 
+    if (!newLastNamep)
         newLastNamep = newPathp;
-    else 
+    else
         newLastNamep++;
 
     /* TODO: The old name could be a wildcard.  The new name must not be */
@@ -6137,22 +6258,22 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
-        (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
+        (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
     {
         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
                  osi_LogSaveClientString(smb_logp, newLastNamep));
 
         /* Check if the old and the new names differ only in case. If so return
-         * success, else return CM_ERROR_EXISTS 
+         * success, else return CM_ERROR_EXISTS
          */
         if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
 
             /* This would be a success only if the old file is *as same as* the new file */
             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
             if (!code) {
-                if (tmpscp == tmpscp2) 
+                if (tmpscp == tmpscp2)
                     code = 0;
-                else 
+                else
                     code = CM_ERROR_EXISTS;
                 cm_ReleaseSCache(tmpscp2);
                 tmpscp2 = NULL;
@@ -6236,7 +6357,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
     }
 
   done:
-    if (tmpscp != NULL) 
+    if (tmpscp != NULL)
         cm_ReleaseSCache(tmpscp);
     if (userp)
         cm_ReleaseUser(userp);
@@ -6248,10 +6369,10 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar
         free(rock.maskp);
 
     return code;
-}       
+}
 
-long 
-smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp) 
+long
+smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
 {
     long code = 0;
     cm_space_t *spacep = NULL;
@@ -6282,14 +6403,14 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
-    
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
+
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
                     userp, tidPathp, &req, &oldDscp);
     if (code) {
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
@@ -6303,7 +6424,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
 #endif /* DFS_SUPPORT */
 
     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
                     userp, tidPathp, &req, &newDscp);
     if (code) {
         cm_ReleaseSCache(oldDscp);
@@ -6335,15 +6456,15 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
     }
 
     /* handle the old name first */
-    if (!oldLastNamep) 
+    if (!oldLastNamep)
         oldLastNamep = oldPathp;
-    else 
+    else
         oldLastNamep++;
 
     /* and handle the new name, too */
-    if (!newLastNamep) 
+    if (!newLastNamep)
         newLastNamep = newPathp;
-    else 
+    else
         newLastNamep++;
 
     /* now lookup the old name */
@@ -6358,8 +6479,8 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
 
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
-    if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
-        (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
+    if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
+        (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
     {
         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
                  osi_LogSaveClientString(smb_logp, newLastNamep));
@@ -6380,7 +6501,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
         cm_ReleaseSCache(newDscp);
         cm_ReleaseSCache(oldDscp);
         cm_ReleaseUser(userp);
-        return code; 
+        return code;
     }
 
     /* now create the hardlink */
@@ -6397,7 +6518,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
                              NULL, TRUE);
     }
 
-    if (tmpscp != NULL) 
+    if (tmpscp != NULL)
         cm_ReleaseSCache(tmpscp);
     cm_ReleaseUser(userp);
     cm_ReleaseSCache(sscp);
@@ -6407,7 +6528,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t
 }
 
 /* SMB_COM_RENAME */
-long 
+long
 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     clientchar_t *oldPathp;
@@ -6461,12 +6582,12 @@ typedef struct smb_rmdirRock {
 } smb_rmdirRock_t;
 
 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
-{       
+{
     long code = 0;
     smb_rmdirRock_t *rockp;
     int match;
     normchar_t matchName[MAX_PATH];
-        
+
     rockp = (smb_rmdirRock_t *) vrockp;
 
     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
@@ -6484,7 +6605,7 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
          !cm_Is8Dot3(matchName)) {
         cm_Gen8Dot3Name(dep, matchName, NULL);
         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
-    }       
+    }
 
     if (match) {
         rockp->any = 1;
@@ -6530,14 +6651,14 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
                     userp, tidPathp, &req, &dscp);
 
     if (code) {
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
@@ -6551,11 +6672,11 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #endif /* DFS_SUPPORT */
 
     /* otherwise, scp points to the parent directory. */
-    if (!lastNamep) 
+    if (!lastNamep)
         lastNamep = pathp;
-    else 
+    else
         lastNamep++;
-       
+
     rock.any = 0;
     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
     if (!rock.maskp) {
@@ -6608,12 +6729,12 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 
     if (userp)
     cm_ReleaseUser(userp);
-        
+
     if (dscp)
     cm_ReleaseSCache(dscp);
 
     if (code == 0 && !rock.any)
-        code = CM_ERROR_NOSUCHFILE;        
+        code = CM_ERROR_NOSUCHFILE;
 
     if (rock.maskp)
     free(rock.maskp);
@@ -6665,15 +6786,15 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_scache_t * scp = fidp->scp;
         cm_HoldSCache(scp);
         lock_ReleaseMutex(&fidp->mx);
-        code = cm_FSync(scp, userp, &req);
+        code = cm_FSync(scp, userp, &req, FALSE);
         cm_ReleaseSCache(scp);
     } else {
         lock_ReleaseMutex(&fidp->mx);
         code = 0;
     }
-        
+
     cm_ReleaseUser(userp);
-    smb_ReleaseFID(fidp);                
+    smb_ReleaseFID(fidp);
     return code;
 }
 
@@ -6730,7 +6851,7 @@ void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
     rock.name = pathp;
     rock.vnode = scp;
 
-    code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
+    code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
     if (code == CM_ERROR_STOPNOW) {
         *newPathp = rock.fullName;
         *originalPathp = rock.originalName;
@@ -6761,7 +6882,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
            return CM_ERROR_BADFD;
        }
-        
+
         userp = fidp->userp;    /* no hold required since fidp is held
                                    throughout the function */
        lock_ReleaseMutex(&fidp->mx);
@@ -6772,7 +6893,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     lock_ObtainWrite(&smb_rctLock);
     if (fidp->deleteOk) {
         osi_Log0(smb_logp, "  Fid already closed.");
-        lock_ReleaseWrite(&smb_rctLock);    
+        lock_ReleaseWrite(&smb_rctLock);
         return CM_ERROR_BADFD;
     }
     fidp->deleteOk = 1;
@@ -6780,7 +6901,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     lock_ObtainMutex(&fidp->mx);
     if (fidp->NTopen_dscp) {
-        dscp = fidp->NTopen_dscp;   
+        dscp = fidp->NTopen_dscp;
         cm_HoldSCache(dscp);
     }
 
@@ -6813,11 +6934,11 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         }
         if (smb_AsyncStore != 2) {
             lock_ReleaseMutex(&fidp->mx);
-            code = cm_FSync(scp, userp, &req);
+            code = cm_FSync(scp, userp, &req, FALSE);
             lock_ObtainMutex(&fidp->mx);
         }
     }
-    else 
+    else
         code = 0;
 
     /* unlock any pending locks */
@@ -6828,9 +6949,11 @@ 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. */
-        key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
+        /*
+         * 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);
 
         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -6844,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);
 
@@ -6876,7 +6999,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
            }
         } else {
             code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
-           if (code == 0) {                            
+           if (code == 0) {
                if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
                    smb_NotifyChange(FILE_ACTION_REMOVED,
                                      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
@@ -6965,11 +7088,11 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                  vcp, fid);
         return CM_ERROR_BADFD;
     }
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
     code = smb_CloseFID(vcp, fidp, userp, dosTime);
-    
+
     smb_ReleaseFID(fidp);
     cm_ReleaseUser(userp);
     return code;
@@ -7015,7 +7138,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
         code = CM_ERROR_BADFD;
         goto done2;
     }
-       
+
     smb_InitReq(&req);
 
     bufferp = NULL;
@@ -7039,7 +7162,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) 
+    if (code)
        goto done;
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -7063,7 +7186,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
             count = 0;
         else
             count = thyper.LowPart;
-    }       
+    }
 
     *readp = count;
 
@@ -7096,9 +7219,9 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
                                  CM_SCACHESYNC_NEEDCALLBACK |
                                  CM_SCACHESYNC_READ);
-                if (code) 
+                if (code)
                    goto done;
-                    
+
                cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
 
                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
@@ -7125,7 +7248,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
         /* now copy the data */
        memcpy(op, bufferp->datap + bufIndex, nbytes);
-                
+
         /* adjust counters, pointers, etc. */
         op += nbytes;
         count -= nbytes;
@@ -7171,6 +7294,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
     osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
     DWORD filter = 0;
     cm_req_t req;
+    int needSyncOpDone = 0;
 
     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
               fidp->fid, offsetp->LowPart, count);
@@ -7186,7 +7310,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
         code = CM_ERROR_BADFDOP;
         goto done2;
     }
-    
+
     smb_InitReq(&req);
 
     scp = fidp->scp;
@@ -7199,9 +7323,9 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
                       CM_SCACHESYNC_NEEDCALLBACK
                       | CM_SCACHESYNC_SETSTATUS
                       | CM_SCACHESYNC_GETSTATUS);
-    if (code) 
+    if (code)
         goto done;
-        
+
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
 
     /* now we have the entry locked, look up the length */
@@ -7226,14 +7350,14 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
      * different storeback windows, remember to store back the previous
      * storeback window when we're done with the write.
      *
-     * the purpose of this logic is to slow down the CIFS client 
+     * the purpose of this logic is to slow down the CIFS client
      * in order to avoid the client disconnecting during the CLOSE
      * operation if there are too many dirty buffers left to write
      * than can be accomplished during 45 seconds.  This used to be
      * based upon cm_chunkSize but we desire cm_chunkSize to be large
      * so that we can read larger amounts of data at a time.
      */
-    if (smb_AsyncStore == 1 && 
+    if (smb_AsyncStore == 1 &&
          (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
          (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
         /* they're different */
@@ -7246,10 +7370,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
     /* now, copy the data one buffer at a time, until we've filled the
      * request packet */
-    while (1) {
-        /* if we've copied all the data requested, we're done */
-        if (count <= 0) 
-            break;
+    while (count != 0) {
 
         /* handle over quota or out of space */
         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
@@ -7264,10 +7385,17 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
             /* wrong buffer */
             if (bufferp) {
+                if (needSyncOpDone) {
+                    cm_SyncOpDone(scp, bufferp,
+                                  CM_SCACHESYNC_NEEDCALLBACK
+                                  | CM_SCACHESYNC_WRITE
+                                  | CM_SCACHESYNC_BUFLOCKED);
+                    needSyncOpDone = 0;
+                }
                 lock_ReleaseMutex(&bufferp->mx);
                 buf_Release(bufferp);
                 bufferp = NULL;
-            }  
+            }
             lock_ReleaseWrite(&scp->rw);
 
             code = buf_Get(scp, &thyper, &req, &bufferp);
@@ -7279,24 +7407,23 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
             bufferOffset = thyper;
 
             /* now get the data in the cache */
-            while (1) {
-                code = cm_SyncOp(scp, bufferp, userp, &req, 0,
-                                  CM_SCACHESYNC_NEEDCALLBACK
-                                  | CM_SCACHESYNC_WRITE
-                                  | CM_SCACHESYNC_BUFLOCKED);
-                if (code) 
-                    goto done;
-
-               cm_SyncOpDone(scp, bufferp, 
-                              CM_SCACHESYNC_NEEDCALLBACK 
-                              | CM_SCACHESYNC_WRITE 
-                              | CM_SCACHESYNC_BUFLOCKED);
+            while (code == 0) {
+                if (!needSyncOpDone) {
+                    code = cm_SyncOp(scp, bufferp, userp, &req, 0,
+                                     CM_SCACHESYNC_NEEDCALLBACK
+                                     | CM_SCACHESYNC_WRITE
+                                     | CM_SCACHESYNC_BUFLOCKED);
+                    if (code)
+                        goto done;
+
+                    needSyncOpDone = 1;
+                }
 
                 /* If we're overwriting the entire buffer, or
                  * if we're writing at or past EOF, mark the
                  * buffer as current so we don't call
                  * cm_GetBuffer.  This skips the fetch from the
-                 * server in those cases where we're going to 
+                 * server in those cases where we're going to
                  * obliterate all the data in the buffer anyway,
                  * or in those cases where there is no useful
                  * data at the server to start with.
@@ -7304,7 +7431,16 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
                  * Use minLength instead of scp->length, since
                  * the latter has already been updated by this
                  * call.
+                 *
+                 * The scp lock has been dropped multiple times
+                 * so the minLength must be refreshed before it
+                 * is used.
                  */
+
+                minLength = scp->length;
+                if (LargeIntegerGreaterThan(minLength, scp->serverLength))
+                    minLength = scp->serverLength;
+
                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
                      || LargeIntegerEqualTo(offset, bufferp->offset)
                      && (count >= cm_data.buf_blockSize
@@ -7321,20 +7457,21 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
 
                 /* otherwise, load the buffer and try again */
+               cm_SyncOpDone(scp, bufferp,
+                             CM_SCACHESYNC_NEEDCALLBACK
+                             | CM_SCACHESYNC_WRITE
+                             | CM_SCACHESYNC_BUFLOCKED);
+                needSyncOpDone = 0;
+
                 lock_ReleaseMutex(&bufferp->mx);
                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                      &req);
                 lock_ReleaseWrite(&scp->rw);
                 lock_ObtainMutex(&bufferp->mx);
                 lock_ObtainWrite(&scp->rw);
-                if (code) break;
             }
-            if (code) {
-                lock_ReleaseMutex(&bufferp->mx);
-                buf_Release(bufferp);
-                bufferp = NULL;
+            if (code)
                 goto done;
-            }
         }      /* if (wrong buffer) ... */
 
         /* now we have the right buffer loaded.  Copy out the
@@ -7344,23 +7481,28 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
         /* and figure out how many bytes we want from this buffer */
         nbytes = cm_data.buf_blockSize - bufIndex;     /* what remains in buffer */
-        if (nbytes > count) 
+        if (nbytes > count)
             nbytes = count;    /* don't go past end of request */
 
         /* 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;
         count -= nbytes;
         written += nbytes;
-        thyper.LowPart = nbytes;
-        thyper.HighPart = 0;
-        offset = LargeIntegerAdd(thyper, offset);
-    } /* while 1 */
+        offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
+    } /* while count != 0 */
 
   done:
+    if (bufferp && needSyncOpDone) {
+        cm_SyncOpDone(scp, bufferp,
+                      CM_SCACHESYNC_NEEDCALLBACK
+                      | CM_SCACHESYNC_WRITE
+                      | CM_SCACHESYNC_BUFLOCKED);
+    }
+
     lock_ReleaseWrite(&scp->rw);
 
     if (bufferp) {
@@ -7370,7 +7512,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
     lock_ObtainMutex(&fidp->mx);
     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
-         && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) 
+         && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
     {
         lock_ReleaseMutex(&fidp->mx);
         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
@@ -7393,8 +7535,8 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
                           fidp->fid, code2);
                 lock_ReleaseWrite(&scp->rw);
                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
-                                    writeBackOffset.HighPart, 
-                                    smb_AsyncStoreSize, 0, userp);
+                                    writeBackOffset.HighPart,
+                                    smb_AsyncStoreSize, 0, userp, &req);
                 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
             }
         } else {
@@ -7439,7 +7581,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
              fd, offset.LowPart, count);
-        
+
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
@@ -7447,7 +7589,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                  vcp, fd);
         return CM_ERROR_BADFD;
     }
-        
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -7511,7 +7653,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_req_t req;
 
        osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
-        
+
         smb_InitReq(&req);
 
         truncAttr.mask = CM_ATTRMASK_LENGTH;
@@ -7557,10 +7699,10 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         total_written += written;
         written = 0;
     }
-    
+
     osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
              total_written, code);
-        
+
     /* set the packet data length to 3 bytes for the data block header,
      * plus the size of the data.
      */
@@ -7604,7 +7746,7 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
         return;
     }
     lock_ReleaseMutex(&fidp->mx);
-       
+
     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
 
@@ -7675,7 +7817,6 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     if (*inp->wctp == 14) {
         /* we received a 64-bit file offset */
-#ifdef AFS_LARGEFILES
         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
 
         if (LargeIntegerLessThanZero(offset)) {
@@ -7684,26 +7825,17 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                      offset.HighPart, offset.LowPart);
             return CM_ERROR_BADSMB;
         }
-#else
-        if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
-            osi_Log0(smb_logp,
-                     "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
-            return CM_ERROR_BADSMB;
-        }
-
-        offset.HighPart = 0;
-#endif
     } else {
         offset.HighPart = 0;    /* 32-bit file offset */
     }
-    
+
     osi_Log4(smb_logp,
              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
              fd, offset.HighPart, offset.LowPart, count);
     osi_Log1(smb_logp,
              "               WriteRaw WriteMode 0x%x",
              writeMode);
-        
+
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
@@ -7753,7 +7885,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
             return code;
         }
     }
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /*
@@ -7800,7 +7932,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
         else
             code = CM_ERROR_USESTD;
-               
+
         lock_ReleaseMutex(&smb_RawBufLock);
     }
 
@@ -7857,15 +7989,15 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_user_t *userp;
     cm_scache_t *scp;
     char *op;
-        
+
     fd = smb_GetSMBParm(inp, 0);
     count = smb_GetSMBParm(inp, 1);
     offset.HighPart = 0;       /* too bad */
     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
-        
+
     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
              fd, offset.LowPart, count);
-        
+
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
@@ -7916,7 +8048,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LOffset.LowPart = offset.LowPart;
         LLength.HighPart = 0;
         LLength.LowPart = count;
-        
+
         lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckRead(scp, LOffset, LLength, key);
         lock_ReleaseWrite(&scp->rw);
@@ -7926,7 +8058,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_ReleaseFID(fidp);
         return code;
     }
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /* remember this for final results */
@@ -7940,7 +8072,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * plus the size of the data.
      */
     smb_SetSMBDataLength(outp, count+3);
-        
+
     /* get op ptr after putting in the parms, since otherwise we don't
      * know where the data really is.
      */
@@ -7950,7 +8082,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     *op++ = 1; /* data block marker */
     *op++ = (unsigned char) (count & 0xff);
     *op++ = (unsigned char) ((count >> 8) & 0xff);
-                
+
     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
 
     /* fix some things up */
@@ -7958,7 +8090,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBDataLength(outp, finalCount+3);
 
     smb_ReleaseFID(fidp);
-       
+
     cm_ReleaseUser(userp);
     cm_ReleaseSCache(scp);
     return code;
@@ -7984,10 +8116,10 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     smb_InitReq(&req);
 
     scp = NULL;
-        
+
     /* compute initial mode bits based on read-only flag in attributes */
     initialModeBits = 0777;
-        
+
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
     if (!pathp)
@@ -8009,7 +8141,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         return CM_ERROR_NOSUCHPATH;
     }
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
                     userp, tidPathp, &req, &dscp);
 
@@ -8017,7 +8149,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
@@ -8033,9 +8165,9 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     /* otherwise, scp points to the parent directory.  Do a lookup, and
      * fail if we find it.  Otherwise, we do the create.
      */
-    if (!lastNamep) 
+    if (!lastNamep)
         lastNamep = pathp;
-    else 
+    else
         lastNamep++;
     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
     if (scp) cm_ReleaseSCache(scp);
@@ -8045,15 +8177,17 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
     setAttr.clientModTime = time(NULL);
+    smb_SetInitialModeBitsForDir(0, &setAttr);
+
     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_ADDED,
                          FILE_NOTIFY_CHANGE_DIR_NAME,
                          dscp, lastNamep, NULL, TRUE);
-        
+
     /* we don't need this any longer */
     cm_ReleaseSCache(dscp);
 
@@ -8062,7 +8196,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
     /* otherwise we succeeded */
     smb_SetSMBDataLength(outp, 0);
     cm_ReleaseUser(userp);
@@ -8072,11 +8206,11 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
 
 BOOL smb_IsLegalFilename(clientchar_t *filename)
 {
-    /* 
+    /*
      *  Find the longest substring of filename that does not contain
      *  any of the chars in illegalChars.  If that substring is less
      *  than the length of the whole string, then one or more of the
-     *  illegal chars is in filename. 
+     *  illegal chars is in filename.
      */
     if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
         return FALSE;
@@ -8096,7 +8230,6 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_scache_t *dscp;                 /* dir we're dealing with */
     cm_scache_t *scp;                  /* file we're creating */
     cm_attr_t setAttr;
-    int initialModeBits;
     smb_fid_t *fidp;
     int attributes;
     clientchar_t *lastNamep;
@@ -8110,15 +8243,10 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     scp = NULL;
     excl = (inp->inCom == 0x03)? 0 : 1;
-        
+
     attributes = smb_GetSMBParm(inp, 0);
     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
-        
-    /* compute initial mode bits based on read-only flag in attributes */
-    initialModeBits = 0666;
-    if (attributes & SMB_ATTR_READONLY) 
-       initialModeBits &= ~0222;
-        
+
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
     if (!pathp)
@@ -8152,14 +8280,14 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
                     userp, tidPathp, &req, &dscp);
 
     if (code) {
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
@@ -8175,9 +8303,9 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* otherwise, scp points to the parent directory.  Do a lookup, and
      * truncate the file if we find it, otherwise we create the file.
      */
-    if (!lastNamep) 
+    if (!lastNamep)
         lastNamep = pathp;
-    else 
+    else
         lastNamep++;
 
     if (!smb_IsLegalFilename(lastNamep))
@@ -8191,7 +8319,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
         free(hexp);
     }
-#endif    
+#endif
 
     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
     if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
@@ -8199,7 +8327,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
     /* if we get here, if code is 0, the file exists and is represented by
      * scp.  Otherwise, we have to create it.
      */
@@ -8220,12 +8348,14 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     else {
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
+        smb_SetInitialModeBitsForFile(attributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                          &req);
         if (code == 0) {
            created = 1;
            if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
-               smb_NotifyChange(FILE_ACTION_ADDED,     
+               smb_NotifyChange(FILE_ACTION_ADDED,
                                 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
                                 dscp, lastNamep, NULL, TRUE);
        } else if (!excl && code == CM_ERROR_EXISTS) {
@@ -8245,7 +8375,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             }
         }
     }
-        
+
     /* we don't need this any longer */
     cm_ReleaseSCache(dscp);
 
@@ -8266,7 +8396,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
     osi_assertx(fidp, "null smb_fid_t");
-       
+
     cm_HoldUser(userp);
 
     lock_ObtainMutex(&fidp->mx);
@@ -8284,7 +8414,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
     lock_ReleaseWrite(&scp->rw);
-    
+
     /* and the user */
     fidp->userp = userp;
     lock_ReleaseMutex(&fidp->mx);
@@ -8314,11 +8444,11 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_req_t req;
 
     smb_InitReq(&req);
-        
+
     fd = smb_GetSMBParm(inp, 0);
     whence = smb_GetSMBParm(inp, 1);
     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
-        
+
     /* try to find the file descriptor */
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
@@ -8416,7 +8546,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
     /* Sanity check */
     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
         /* log it and discard it */
-       LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
+       LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
                 __FILE__, __LINE__, ncbp->ncb_length);
        osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
         return;
@@ -8463,7 +8593,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
             outWctp[0] = 0;    /* wct of zero */
             outWctp[1] = 0;    /* and bcc (word) of zero */
             outWctp[2] = 0;
-        }   
+        }
 
         /* once set, stays set.  Doesn't matter, since we never chain
          * "no response" calls.
@@ -8485,12 +8615,12 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
             } else {
                 code = (*(dp->procp)) (vcp, inp, outp);
-            }   
+            }
             osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
                       code, smbp->mid, vcp, vcp->lana, vcp->lsn);
 
             newTime = GetTickCount();
-            osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms", 
+            osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
                      opName, smbp->mid, newTime - oldTime);
 
 #ifdef LOG_PACKET
@@ -8522,12 +8652,12 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                         pathname = inp->stringsp->wdata;
                 }
 
-                afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", 
-                          opName, newTime - oldTime, 
+                afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
+                          opName, newTime - oldTime,
                           smbp->uid, uidp ? uidp->unp->name : NULL,
                           smbp->pid, smbp->mid, smbp->tid,
                           treepath,
-                          pathname, 
+                          pathname,
                           afid.cell, afid.volume, afid.vnode, afid.unique);
 
                 if (fidp)
@@ -8540,7 +8670,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
             }
 
             if (oldGen != sessionGen) {
-               LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
+               LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
                         newTime - oldTime, ncbp->ncb_length);
                osi_Log3(smb_logp, "Request %s straddled session startup, "
                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
@@ -8558,7 +8688,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
-                if (code == IDCANCEL) 
+                if (code == IDCANCEL)
                     showErrors = 0;
             }
             code = CM_ERROR_BADOP;
@@ -8566,7 +8696,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
 
         /* catastrophic failure:  log as much as possible */
         if (code == CM_ERROR_BADSMB) {
-           LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
+           LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
                     ncbp->ncb_length);
 #ifdef LOG_PACKET
             smb_LogPacket(inp);
@@ -8588,14 +8718,14 @@ 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
-                     && code != CM_ERROR_BUFFERTOOSMALL 
+                     && code != CM_ERROR_BUFFERTOOSMALL
                      && code != CM_ERROR_GSSCONTINUE) {
                     /* nuke wct and bcc.  For a partial
-                     * write or an in-process authentication handshake, 
+                     * write or an in-process authentication handshake,
                      * assume they're OK.
                      */
                     *outWctp++ = 0;
@@ -8640,7 +8770,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
          * parm fields are required, and are
          * AndXCommand/AndXReserved and
          * AndXOffset. */
-        if (tp[0] < 2) break;  
+        if (tp[0] < 2) break;
         if (tp[1] == 0xff) break;      /* no more chained opcodes */
         inp->inCom = tp[1];
         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
@@ -8706,7 +8836,7 @@ void smb_ClientWaiter(void *parmp)
             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
             continue;
         }
-        
+
         if (code == WAIT_TIMEOUT)
         {
             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
@@ -8718,7 +8848,7 @@ void smb_ClientWaiter(void *parmp)
         }
 
         idx = code - WAIT_OBJECT_0;
+
         /* check idx range! */
         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
         {
@@ -8726,7 +8856,7 @@ void smb_ClientWaiter(void *parmp)
             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
             osi_assertx(0, "invalid index");
         }
-        
+
         thrd_ResetEvent(NCBevents[idx]);
         thrd_SetEvent(NCBreturns[0][idx]);
     }
@@ -8754,23 +8884,23 @@ void smb_ServerWaiter(void *parmp)
             int abandonIdx = code - WAIT_ABANDONED_0;
             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
         }
-       
+
         if (code == WAIT_IO_COMPLETION)
         {
             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
             continue;
         }
-       
+
         if (code == WAIT_TIMEOUT)
         {
             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
         }
-       
+
         if (code == WAIT_FAILED)
         {
             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
         }
-       
+
         idx_session = code - WAIT_OBJECT_0;
 
         /* check idx range! */
@@ -8786,7 +8916,7 @@ void smb_ServerWaiter(void *parmp)
         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
                                                  FALSE, INFINITE);
         if (code == WAIT_OBJECT_0) {
-            if (smbShutdownFlag == 1) 
+            if (smbShutdownFlag == 1)
                 break;
             else
                 goto NCBretry;
@@ -8798,23 +8928,23 @@ void smb_ServerWaiter(void *parmp)
             int abandonIdx = code - WAIT_ABANDONED_0;
             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
         }
-       
+
         if (code == WAIT_IO_COMPLETION)
         {
             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
             continue;
         }
-       
+
         if (code == WAIT_TIMEOUT)
         {
             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
         }
-       
+
         if (code == WAIT_FAILED)
         {
             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
         }
-               
+
         idx_NCB = code - WAIT_OBJECT_0;
 
         /* check idx range! */
@@ -8840,6 +8970,361 @@ void smb_ServerWaiter(void *parmp)
     }
 }
 
+typedef struct _monitored_task {
+    osi_queue_t q;
+    INT_PTR     task_id;
+    LARGE_INTEGER start_time;
+    BOOL        started;
+    BOOL        trace_timer_hit;
+    BOOL        dump_timer_hit;
+} monitored_task;
+
+typedef struct osi_queueHT {
+    osi_queue_t * headp;
+    osi_queue_t * tailp;
+} osi_queueHT_t;
+
+static osi_queue_t *smb_monitored_tasks = NULL;
+static osi_queue_t *smb_free_monitored_tasks = NULL;
+
+static osi_mutex_t _monitor_mx;
+
+static HANDLE h_monitored_task_queue    = NULL;
+static HANDLE h_monitored_task_shutdown = NULL;
+
+static time_t smb_last_dump_time = 0;
+
+DWORD  smb_monitorReqs = 0;
+
+/* FILETIME comparison fuzz */
+#define MONITOR_FUZZ_TIMEOUT    (1 * 10000000i64)
+
+/* Trace timeout is at 60 seconds */
+#define MONITOR_TRACE_TIMEOUT   (60 * 10000000i64)
+
+/* Dump timeout is at 120 seconds */
+#define MONITOR_DUMP_TIMEOUT    (120 * 10000000i64)
+
+/* Time before another dump is performed in seconds*/
+#define MONITOR_DUMP_RESET_TIMEOUT  (600)
+
+static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
+{
+    FILETIME now;
+    LARGE_INTEGER earliest;
+    monitored_task * t;
+
+    GetSystemTimeAsFileTime(&now);
+    earliest.LowPart = now.dwLowDateTime;
+    earliest.HighPart = now.dwHighDateTime;
+    earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
+
+    while ((t = (monitored_task *) taskmq->headp) != NULL &&
+
+           (t->start_time.QuadPart < earliest.QuadPart ||
+
+            t->dump_timer_hit)) {
+
+        osi_QRemoveHT(&taskmq->headp,
+                      &taskmq->tailp,
+                      &t->q);
+
+        lock_ObtainMutex(&_monitor_mx);
+        osi_QAdd(&smb_free_monitored_tasks, &t->q);
+        lock_ReleaseMutex(&_monitor_mx);
+    }
+
+#ifdef INVARIANT_CHECK
+    {
+        LARGE_INTEGER last;
+
+        last.QuadPart = 0;
+
+        for (t = (monitored_task *) taskmq->headp;
+             t;
+             t = (monitored_task *) osi_QNext(&t->q)) {
+            osi_assert(last.QuadPart <= t->start_time.QuadPart);
+            last.QuadPart = t->start_time.QuadPart;
+        }
+    }
+#endif
+}
+
+static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
+{
+    monitored_task * task;
+    monitored_task * tasks;
+
+    lock_ObtainMutex(&_monitor_mx);
+    tasks = (monitored_task *) smb_monitored_tasks;
+    smb_monitored_tasks = NULL;
+    lock_ReleaseMutex(&_monitor_mx);
+
+    while (tasks) {
+
+        task = tasks;
+        osi_QRemove((osi_queue_t **) &tasks, &task->q);
+
+        if (task->started) {
+
+            osi_queue_t q;
+            osi_queue_t *p;
+
+            q.nextp = NULL;
+            q.prevp = taskmq->tailp;
+
+            /* Insertion sort by start_time.  Earliest request is
+               first.  Since we are likely to receive new requests
+               later, we start inserting from the back. */
+            for (p = &q;
+                 osi_QPrev(p) &&
+                     ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
+                 p = osi_QPrev(p));
+
+            if (p == &q)
+                osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
+            else if (p->prevp == NULL)
+                osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
+            else {
+                osi_queue_t *o = p->prevp;
+
+                osi_assert(o->nextp == p);
+
+                task->q.nextp = p;
+                task->q.prevp = o;
+                p->prevp = &task->q;
+                o->nextp = &task->q;
+            }
+
+        } else {
+            /* Some task ending */
+
+            osi_queue_t * p;
+
+            for (p = taskmq->headp;
+                 p != NULL;
+                 p = osi_QNext(p)) {
+
+                monitored_task * mt = (monitored_task *) p;
+
+                if (mt->task_id == task->task_id) {
+
+                    osi_QRemoveHT(&taskmq->headp,
+                                  &taskmq->tailp, p);
+
+                    lock_ObtainMutex(&_monitor_mx);
+                    osi_QAdd(&smb_free_monitored_tasks, p);
+                    lock_ReleaseMutex(&_monitor_mx);
+
+                    break;
+                }
+            }
+
+            lock_ObtainMutex(&_monitor_mx);
+            osi_QAdd(&smb_free_monitored_tasks, &task->q);
+            lock_ReleaseMutex(&_monitor_mx);
+        }
+    }
+
+#ifdef INVARIANT_CHECK
+    {
+        LARGE_INTEGER last;
+        monitored_task * t;
+
+        last.QuadPart = 0;
+
+        for (t = (monitored_task *) taskmq->headp;
+             t;
+             t = (monitored_task *) osi_QNext(&t->q)) {
+            osi_assert(last.QuadPart <= t->start_time.QuadPart);
+            last.QuadPart = t->start_time.QuadPart;
+        }
+    }
+#endif
+}
+
+static void smb_HandleTaskMonitorEvent(monitored_task * task)
+{
+    if (!task->trace_timer_hit) {
+
+        task->trace_timer_hit = TRUE;
+
+        osi_LogEnable(afsd_logp);
+        rx_DebugOnOff(TRUE);
+
+    } else if (!task->dump_timer_hit) {
+        time_t now;
+
+        time(&now);
+
+        if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
+            task->dump_timer_hit = TRUE;
+            smb_last_dump_time = now;
+
+            GenerateMiniDump(NULL);
+        }
+    }
+}
+
+/**
+ * Server request monitoring
+ *
+ * The server monitor runs in a separate thread and monitors server
+ * requests for potential timeouts.  It examines notifcations queued
+ * by smb_NotifyRequestEvent() and waits for potential timeout events:
+ *
+ * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
+ *   enables trace logging.
+ *
+ * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
+ *   out a dump file that will hopefully contain enough evidence to
+ *   figure out why the timeout event occurred.
+ *
+ */
+void smb_ServerMonitor(VOID * parmp)
+{
+    osi_queueHT_t in_progress = { NULL, NULL };
+    HANDLE h_timer = NULL;
+
+    HANDLE h_all[3];
+
+    h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
+    h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
+    h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
+
+    lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
+
+    h_all[0] = h_monitored_task_queue;
+    h_all[1] = h_timer;
+    h_all[2] = h_monitored_task_shutdown;
+
+    while(1) {
+        DWORD rv;
+
+        rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
+
+        if (rv == WAIT_OBJECT_0) {
+
+            smb_SlurpNewTaskMonitors(&in_progress);
+
+        } else if (rv == WAIT_OBJECT_0 + 1) {
+
+            smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
+
+        } else {
+
+            break;
+
+        }
+
+        /* refresh timers */
+        {
+            monitored_task * t;
+
+            smb_PurgeOldTaskMonitors(&in_progress);
+            t = (monitored_task *) in_progress.headp;
+
+            if (t && !t->trace_timer_hit) {
+                LARGE_INTEGER due;
+
+                due = t->start_time;
+                due.QuadPart += MONITOR_TRACE_TIMEOUT;
+
+                SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
+            } else if (t && !t->dump_timer_hit) {
+
+                LARGE_INTEGER due;
+
+                due = t->start_time;
+                due.QuadPart += MONITOR_DUMP_TIMEOUT;
+
+                SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
+            } else {
+                CancelWaitableTimer(h_timer);
+
+                /* CancelWaitableTimer() doesn't reset the timer if it
+                   was already signalled. */
+                WaitForSingleObject(h_timer, 0);
+            }
+        }
+    }
+
+    {
+        HANDLE h;
+
+        h = h_monitored_task_queue;
+        h_monitored_task_queue = NULL;
+        CloseHandle(h);
+
+        h = h_monitored_task_shutdown;
+        h_monitored_task_shutdown = NULL;
+        CloseHandle(h);
+
+        CloseHandle(h_timer);
+
+        lock_FinalizeMutex(&_monitor_mx);
+    }
+
+    {
+        monitored_task * task;
+
+        while (in_progress.headp) {
+            task = (monitored_task *) in_progress.headp;
+            osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
+            free(task);
+        }
+
+        for (task = (monitored_task  *) smb_free_monitored_tasks;
+             task; task = (monitored_task *) smb_free_monitored_tasks) {
+            osi_QRemove(&smb_free_monitored_tasks, &task->q);
+            free(task);
+        }
+
+        for (task = (monitored_task *) smb_monitored_tasks;
+             task; task = (monitored_task *) smb_monitored_tasks) {
+            osi_QRemove(&smb_monitored_tasks, &task->q);
+            free(task);
+        }
+    }
+}
+
+void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
+{
+    monitored_task * task;
+
+    lock_ObtainMutex(&_monitor_mx);
+    task = (monitored_task *) smb_free_monitored_tasks;
+    if (task)
+        osi_QRemove(&smb_free_monitored_tasks, &task->q);
+    lock_ReleaseMutex(&_monitor_mx);
+
+    if (task == NULL)
+        task = malloc(sizeof(monitored_task));
+    memset(task, 0, sizeof(*task));
+
+    task->task_id = task_id;
+    task->started = started;
+
+    {
+        FILETIME now;
+
+        GetSystemTimeAsFileTime(&now);
+        task->start_time.HighPart = now.dwHighDateTime;
+        task->start_time.LowPart = now.dwLowDateTime;
+    }
+
+    lock_ObtainMutex(&_monitor_mx);
+    osi_QAdd(&smb_monitored_tasks, &task->q);
+    lock_ReleaseMutex(&_monitor_mx);
+
+    SetEvent(h_monitored_task_queue);
+}
+
+void smb_ShutdownMonitor()
+{
+    SetEvent(h_monitored_task_shutdown);
+}
+
 /*
  * The top level loop for handling SMB request messages.  Each server thread
  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
@@ -8862,7 +9347,6 @@ void smb_Server(VOID *parmp)
     UCHAR rc;
     smb_vc_t *vcp = NULL;
     smb_t *smbp;
-    extern void rx_StartClientThread(void);
 
     rx_StartClientThread();
 
@@ -8896,25 +9380,25 @@ void smb_Server(VOID *parmp)
             int abandonIdx = code - WAIT_ABANDONED_0;
             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
         }
-       
+
         if (code == WAIT_IO_COMPLETION)
         {
             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
             continue;
         }
-       
+
         if (code == WAIT_TIMEOUT)
         {
             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
         }
-       
+
         if (code == WAIT_FAILED)
         {
             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
         }
 
         idx_NCB = code - WAIT_OBJECT_0;
-        
+
         /* check idx range! */
         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
         {
@@ -8931,7 +9415,7 @@ void smb_Server(VOID *parmp)
            osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
 
         switch (rc) {
-        case NRC_GOODRET: 
+        case NRC_GOODRET:
             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
             break;
 
@@ -8968,7 +9452,7 @@ void smb_Server(VOID *parmp)
 
         case NRC_INCOMP:
             /* Treat as transient error */
-           LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
+           LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
                     ncbp->ncb_length);
            osi_Log1(smb_logp,
                     "dispatch smb recv failed, message incomplete, ncb_length %d",
@@ -9033,7 +9517,7 @@ void smb_Server(VOID *parmp)
          *   b) Netbios screwed up the call.
         *   c) The VC was already marked dead before we were able to
         *      process the call
-         * Obviously this implies that 
+         * Obviously this implies that
          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
          *   lanas[idx_session] != ncbp->ncb_lana_num )
          * Either way, we can't do anything with this packet.
@@ -9064,6 +9548,9 @@ void smb_Server(VOID *parmp)
         }
 
        cm_SetRequestStartTime();
+        if (smb_monitorReqs) {
+            smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
+        }
 
         vcp->errorCount = 0;
         bufp = (struct smb_packet *) ncbp->ncb_buffer;
@@ -9077,7 +9564,7 @@ void smb_Server(VOID *parmp)
             if (smbp->com == 0x1d) {
                 /* Special handling for Write Raw */
                 raw_write_cont_t rwc;
-            
+
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
                 if (rwc.code == 0) {
                     EVENT_HANDLE rwevent;
@@ -9101,10 +9588,10 @@ void smb_Server(VOID *parmp)
                 thrd_SetEvent(SessionEvents[idx_session]);
                 if (rwc.code == 0)
                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
-            } 
+            }
             else if (smbp->com == 0xa0) {
-                /* 
-                 * Serialize the handling for NT Transact 
+                /*
+                 * Serialize the handling for NT Transact
                  * (defect 11626)
                  */
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
@@ -9114,12 +9601,15 @@ void smb_Server(VOID *parmp)
                 /* TODO: what else needs to be serialized? */
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
             }
-#ifndef NOTRACE        
+#ifndef NOTRACE
         }
         __except( smb_ServerExceptionFilter() ) {
         }
 #endif
 
+        if (smb_monitorReqs) {
+            smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
+        }
         smb_concurrentCalls--;
 
       doneWithNCB:
@@ -9148,7 +9638,7 @@ DWORD smb_ServerExceptionFilter(void) {
     afsd_ForceTrace(TRUE);
     buf_ForceTrace(TRUE);
     return EXCEPTION_CONTINUE_SEARCH;
-}       
+}
 
 /*
  * Create a new NCB and associated events, packet buffer, and "space" buffer.
@@ -9226,10 +9716,10 @@ void smb_Listener(void *parmp)
         len = (long)strlen(smb_localNamep);
         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
-        
+
         strcpy(ncbp->ncb_callname, "*");
         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
-        
+
         ncbp->ncb_lana_num = (UCHAR)lana;
 
         code = Netbios(ncbp);
@@ -9277,7 +9767,7 @@ void smb_Listener(void *parmp)
                     goto exit_thread;
                 Sleep(50);
             }
+
             osi_Log2(smb_logp,
                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
                       ncbp->ncb_lana_num, ncb_error_string(code));
@@ -9317,13 +9807,13 @@ void smb_Listener(void *parmp)
                 Sleep(50);
             }
 
-            osi_Log3(smb_logp, 
+            osi_Log3(smb_logp,
                      "NCBLISTEN lana=%d failed with code %d [%s]",
                      ncbp->ncb_lana_num, code, ncb_error_string(code));
-            osi_Log0(smb_logp, 
+            osi_Log0(smb_logp,
                      "Client exiting due to network failure. Please restart client.\n");
 
-            sprintf(tbuffer, 
+            sprintf(tbuffer,
                      "Client exiting due to network failure.  Please restart client.\n"
                      "NCBLISTEN lana=%d failed with code %d [%s]",
                      ncbp->ncb_lana_num, code, ncb_error_string(code));
@@ -9380,7 +9870,7 @@ void smb_Listener(void *parmp)
            if (reportSessionStartups) {
                LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
            }
-           
+
            lock_ObtainMutex(&vcp->mx);
             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
            vcp->flags |= flags;
@@ -9399,7 +9889,7 @@ void smb_Listener(void *parmp)
            }
            lock_ReleaseWrite(&smb_globalLock);
        } else {
-           /* We are re-using an existing VC because the lsn and lana 
+           /* We are re-using an existing VC because the lsn and lana
             * were re-used */
            session = vcp->session;
 
@@ -9423,13 +9913,13 @@ void smb_Listener(void *parmp)
             smb_packet_t * outp = smb_GetPacket();
             unsigned char *outWctp;
             smb_t *smbp;
-            
+
            smb_FormatResponsePacket(vcp, NULL, outp);
             outp->ncbp = ncbp;
 
             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;
@@ -9485,7 +9975,7 @@ void smb_Listener(void *parmp)
             LSNs[session]  = ncbp->ncb_lsn;
             lanas[session] = ncbp->ncb_lana_num;
            lock_ReleaseWrite(&smb_globalLock);
-               
+
             if (session == numSessions) {
                 /* Add new NCB for new session */
                 char eventName[MAX_PATH];
@@ -9526,13 +10016,13 @@ 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.
      * There are two work arounds available:
-     * 
+     *
      *   (1) We can disable the check for matching host names.  This does not
      *   require a reboot:
      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
@@ -9547,19 +10037,19 @@ configureBackConnectionHostNames(void)
      *   (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
      *   (2a) If not, add it to the list.  (This will not take effect until the next reboot.)
      *   (2b1)    and check to see if DisableLoopbackCheck is set.
-     *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1 
+     *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1
      *   (2b3)                and create HKLM\SOFTWARE\OpenAFS\Client  UnsetDisableLoopbackCheck
      *   (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
-     *             check for the UnsetDisableLoopbackCheck value.  
-     *             If set, set the DisableLoopbackCheck flag to 0x0 
+     *             check for the UnsetDisableLoopbackCheck value.
+     *             If set, set the DisableLoopbackCheck flag to 0x0
      *             and delete the UnsetDisableLoopbackCheck value
      *
      * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
-     * force Windows to use the loopback authentication mechanism for the specified 
+     * force Windows to use the loopback authentication mechanism for the specified
      * services.
-     * 
+     *
      * Do not permit the "DisableLoopbackCheck" value to be removed within the same
-     * service session that set it.  
+     * service session that set it.
      */
     HKEY hkLsa;
     HKEY hkMSV10;
@@ -9568,68 +10058,83 @@ configureBackConnectionHostNames(void)
     DWORD dwSize, dwAllocSize;
     DWORD dwValue;
     PBYTE pHostNames = NULL, pName = NULL;
-    BOOL  bNameFound = FALSE;   
+    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 */
-    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
+    /* 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,
                        KEY_READ|KEY_WRITE,
                        &hkMSV10) == ERROR_SUCCESS )
     {
-        if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, 
+        if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
                             &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
-            (dwType == REG_MULTI_SZ)) 
+            (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( hkMSV10, "BackConnectionHostNames", 0, &dwType, 
-                                pHostNames, &dwSize) == ERROR_SUCCESS) 
+           dwszBackConnectionHostNames = dwAllocSize;
+            if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
+                                pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
             {
-               for (pName = pHostNames; 
-                    (pName - pHostNames < (int) dwSize) && *pName ; 
+               for (pName = pHostNames;
+                    (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
                     pName += strlen(pName) + 1)
                {
                    if ( !stricmp(pName, cm_NetbiosName) ) {
                        bNameFound = TRUE;
                        break;
-                   }   
+                   }
                }
            }
         }
-             
-        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);
+        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 */
 
-            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 ) {
+                dwType = REG_MULTI_SZ;
+                dwSize = (DWORD)(pName - pHostNames + 1);
+                RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
+
+                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, 
+                    if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
                                         AFSREG_CLT_OPENAFS_SUBKEY,
                                         0,
                                         NULL,
@@ -9646,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) {
@@ -9683,106 +10235,167 @@ 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 
-     *  
+     *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ
+     *
      * 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;
-    BOOL  bNameFound = FALSE;   
+    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",
+    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+                       "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)) 
+            (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 ; 
+               for (pName = pHostNames;
+                    (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
                     pName += strlen(pName) + 1)
                {
                    if ( !stricmp(pName, cm_NetbiosName) ) {
                        bNameFound = TRUE;
                        break;
-                   }   
+                   }
                }
            }
         }
-             
-        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) {
             free(pHostNames);
             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)) 
+            (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 ; 
+               for (pName = pHostNames;
+                    (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
                     pName += strlen(pName) + 1)
                {
                    if ( !stricmp(pName, cm_NetbiosName) ) {
                        bNameFound = TRUE;
                        break;
-                   }   
+                   }
                }
            }
         }
-             
-        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);
@@ -9794,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) {
@@ -9802,23 +10451,30 @@ 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);
     }
 }
 
 static void
 smb_LanAdapterChangeThread(void *param)
 {
-    /* 
+    /*
      * Give the IPAddrDaemon thread a chance
      * to block before we trigger.
      */
@@ -9836,7 +10492,16 @@ void smb_SetLanAdapterChangeDetected(void)
     if (!powerStateSuspended) {
         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
                               NULL, 0, &lpid, "smb_LanAdapterChange");
-        osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
+        if (phandle == NULL) {
+            DWORD gle;
+            char msg[128];
+
+            gle = GetLastError();
+            StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
+                             "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
+                             gle);
+            osi_assertx(TRUE, msg);
+        }
         thrd_CloseHandle(phandle);
     }
 
@@ -9849,7 +10514,7 @@ void smb_LanAdapterChange(int locked) {
     BOOL          bGateway;
     char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
     int           change = 0;
-    LANA_ENUM     temp_list;           
+    LANA_ENUM     temp_list;
     long          code;
     int           i;
 
@@ -9858,12 +10523,12 @@ void smb_LanAdapterChange(int locked) {
 
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
-    
+
     smb_LanAdapterChangeDetected = 0;
 
-    if (!powerStateSuspended && 
-        SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway, 
-                                          LANA_NETBIOS_NAME_FULL)) &&
+    if (!powerStateSuspended &&
+        SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
+                                          LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
         if ( isGateway != bGateway ) {
             afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
@@ -9897,7 +10562,7 @@ void smb_LanAdapterChange(int locked) {
             }
            smb_FreeNCB(ncbp);
         }
-    } 
+    }
 
     if (change) {
         smb_StopListeners(1);
@@ -9918,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);
 
@@ -9931,7 +10599,10 @@ int smb_NetbiosInit(int locked)
     /* setup the NCB system */
     ncbp = smb_GetNCB();
 
-    /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
+    /*
+     * Call lanahelper to get Netbios name, lan adapter number and gateway flag
+     * This will reset all of the network adapter's netbios state.
+     */
     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
 
@@ -9976,7 +10647,7 @@ int smb_NetbiosInit(int locked)
         lana_list.length = 1;
         lana_list.lana[0] = smb_LANadapter;
     }
-         
+
     for (i = 0; i < lana_list.length; i++) {
         /* reset the adaptor: in Win32, this is required for every process, and
          * acts as an init call, not as a real hardware reset.
@@ -9986,7 +10657,7 @@ int smb_NetbiosInit(int locked)
         ncbp->ncb_callname[2] = 100;
         ncbp->ncb_lana_num = lana_list.lana[i];
         code = Netbios(ncbp);
-        if (code == 0) 
+        if (code == 0)
             code = ncbp->ncb_retcode;
         if (code != 0) {
             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
@@ -10011,7 +10682,7 @@ int smb_NetbiosInit(int locked)
         ncbp->ncb_lana_num = lana;
         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
         code = Netbios(ncbp);
-          
+
         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
         {
@@ -10021,7 +10692,7 @@ int smb_NetbiosInit(int locked)
             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
         }
 
-        if (code == 0) 
+        if (code == 0)
            code = ncbp->ncb_retcode;
 
         if (code == 0) {
@@ -10040,7 +10711,7 @@ int smb_NetbiosInit(int locked)
                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
                 ncbp->ncb_lana_num = lana;
                 code = Netbios(ncbp);
-                if (code == 0) 
+                if (code == 0)
                     code = ncbp->ncb_retcode;
                 else {
                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
@@ -10079,7 +10750,7 @@ int smb_NetbiosInit(int locked)
 #endif
                                       );
     }
-        
+
     /* we're done with the NCB now */
     smb_FreeNCB(ncbp);
 
@@ -10099,6 +10770,9 @@ void smb_StartListeners(int locked)
     int lpid;
     thread_t phandle;
 
+    if (!smb_Enabled)
+        return;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10110,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;
@@ -10126,7 +10800,7 @@ void smb_StartListeners(int locked)
                                   );
 
     for (i = 0; i < lana_list.length; i++) {
-        if (lana_list.lana[i] == LANA_INVALID) 
+        if (lana_list.lana[i] == LANA_INVALID)
             continue;
         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
@@ -10139,6 +10813,9 @@ void smb_StartListeners(int locked)
 
 void smb_RestartListeners(int locked)
 {
+    if (!smb_Enabled)
+        return;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10166,7 +10843,7 @@ void smb_StopListener(NCB *ncbp, int lana, int wait)
     ncbp->ncb_lana_num = lana;
     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
     code = Netbios(ncbp);
-          
+
     afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
              lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
 
@@ -10176,7 +10853,7 @@ void smb_StopListener(NCB *ncbp, int lana, int wait)
     ncbp->ncb_callname[2] = 100;
     ncbp->ncb_lana_num = lana;
     code = Netbios(ncbp);
-    if (code == 0) 
+    if (code == 0)
        code = ncbp->ncb_retcode;
     if (code != 0) {
        afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
@@ -10193,6 +10870,9 @@ void smb_StopListeners(int locked)
     NCB *ncbp;
     int lana, l;
 
+    if (!smb_Enabled)
+        return;
+
     if (!locked)
         lock_ObtainMutex(&smb_StartedLock);
 
@@ -10240,12 +10920,15 @@ void smb_Init(osi_log_t *logp, int useV3,
 {
     thread_t phandle;
     int lpid;
-    INT_PTR i;
+    UINT_PTR i;
     struct tm myTime;
     EVENT_HANDLE retHandle;
     char eventName[MAX_PATH];
     int startListeners = 0;
 
+    if (!smb_Enabled)
+        return;
+
     smb_MBfunc = aMBfunc;
 
     smb_useV3 = useV3;
@@ -10262,12 +10945,12 @@ void smb_Init(osi_log_t *logp, int useV3,
 
 #ifdef AFS_FREELANCE_CLIENT
     /* Make sure the root.afs volume has the correct time */
-    cm_noteLocalMountPointChange();
+    cm_noteLocalMountPointChange(FALSE);
 #endif
 
     /* initialize the remote debugging log */
     smb_logp = logp;
-        
+
     /* and the global lock */
     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
@@ -10277,7 +10960,7 @@ void smb_Init(osi_log_t *logp, int useV3,
 
     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
-       
+
     /* 4 Raw I/O buffers */
     smb_RawBufs = calloc(65536,1);
     *((char **)smb_RawBufs) = NULL;
@@ -10462,9 +11145,9 @@ void smb_Init(osi_log_t *logp, int useV3,
             packageName.MaximumLength = packageName.Length + 1;
             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
             if (nts == STATUS_SUCCESS) {
-                /* BEGIN 
-                 * This code forces Windows to authenticate against the Logon Cache 
-                 * first instead of attempting to authenticate against the Domain 
+                /* BEGIN
+                 * This code forces Windows to authenticate against the Logon Cache
+                 * first instead of attempting to authenticate against the Domain
                  * Controller.  When the Windows logon cache is enabled this improves
                  * performance by removing the network access and works around a bug
                  * seen at sites which are using a MIT Kerberos principal to login
@@ -10477,7 +11160,7 @@ void smb_Init(osi_log_t *logp, int useV3,
 
                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
-                OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST; 
+                OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
                 OptionsRequest.DisableOptions = FALSE;
 
                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
@@ -10528,8 +11211,8 @@ void smb_Init(osi_log_t *logp, int useV3,
          * external Kerberos principal mapped to a local account.
          */
         else if ( smb_authType == SMB_AUTH_EXTENDED) {
-            /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
-             * then the only option is NTLMSSP anyway; so just fallback. 
+            /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used
+             * then the only option is NTLMSSP anyway; so just fallback.
              */
             void * secBlob;
             int secBlobLength;
@@ -10549,7 +11232,7 @@ void smb_Init(osi_log_t *logp, int useV3,
         /* Now get ourselves a domain name. */
         /* For now we are using the local computer name as the domain name.
          * It is actually the domain for local logins, and we are acting as
-         * a local SMB server. 
+         * a local SMB server.
          */
         bufsize = lengthof(smb_ServerDomainName) - 1;
         GetComputerNameW(smb_ServerDomainName, &bufsize);
@@ -10588,6 +11271,13 @@ void smb_Init(osi_log_t *logp, int useV3,
     osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
     thrd_CloseHandle(phandle);
 
+    if (smb_monitorReqs) {
+        phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
+                              NULL, 0, &lpid, "smb_ServerMonitor");
+        osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
+        thrd_CloseHandle(phandle);
+    }
+
     lock_ReleaseMutex(&smb_StartedLock);
     return;
 }
@@ -10599,8 +11289,11 @@ 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 */
     ncbp = smb_GetNCB();
 
@@ -10613,7 +11306,7 @@ void smb_Shutdown(void)
     {
         if (dead_sessions[i])
             continue;
-      
+
         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
         ncbp->ncb_command = NCBHANGUP;
         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
@@ -10627,23 +11320,23 @@ void smb_Shutdown(void)
         }
     }
 
-    /* Trigger the shutdown of all SMB threads */                                
-    for (i = 0; i < smb_NumServerThreads; i++)                                   
-        thrd_SetEvent(NCBreturns[i][0]);                                         
-                                                                                 
-    thrd_SetEvent(NCBevents[0]);                                                 
-    thrd_SetEvent(SessionEvents[0]);                                             
-    thrd_SetEvent(NCBavails[0]);                                                 
-                                                                                 
-    for (i = 0;i < smb_NumServerThreads; i++) {                                  
-        DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500); 
-        if (code == WAIT_OBJECT_0) {                                             
-            continue;                                                            
-        } else {                                                                 
-            afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);      
-            thrd_SetEvent(NCBreturns[i--][0]);                                   
-        }                                                                        
-    }                                                                            
+    /* Trigger the shutdown of all SMB threads */
+    for (i = 0; i < smb_NumServerThreads; i++)
+        thrd_SetEvent(NCBreturns[i][0]);
+
+    thrd_SetEvent(NCBevents[0]);
+    thrd_SetEvent(SessionEvents[0]);
+    thrd_SetEvent(NCBavails[0]);
+
+    for (i = 0;i < smb_NumServerThreads; i++) {
+        DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
+        if (code == WAIT_OBJECT_0) {
+            continue;
+        } else {
+            afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
+            thrd_SetEvent(NCBreturns[i--][0]);
+        }
+    }
 
     /* Delete Netbios name */
     memset(ncbp, 0, sizeof(NCB));
@@ -10653,24 +11346,24 @@ void smb_Shutdown(void)
         ncbp->ncb_lana_num = lana_list.lana[i];
         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
         code = Netbios(ncbp);
-        if (code == 0) 
+        if (code == 0)
             code = ncbp->ncb_retcode;
         if (code != 0) {
             fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
                      ncbp->ncb_lana_num, code);
-        }       
+        }
         fflush(stderr);
     }
 
     /* Release the reference counts held by the VCs */
     lock_ObtainWrite(&smb_rctLock);
-    for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
+    for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
     {
         smb_fid_t *fidp;
         smb_tid_t *tidp;
-     
+
        if (vcp->magic != SMB_VC_MAGIC)
-           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
                       __FILE__, __LINE__);
 
        for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
@@ -10706,6 +11399,10 @@ void smb_Shutdown(void)
     }
     lock_ReleaseWrite(&smb_rctLock);
     smb_FreeNCB(ncbp);
+
+    if (smb_monitorReqs) {
+        smb_ShutdownMonitor();
+    }
 }
 
 /* Get the UNC \\<servername>\<sharename> prefix. */
@@ -10797,23 +11494,23 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
 {
     int zilch;
     char output[4196];
-  
+
     smb_vc_t *vcp;
     smb_username_t *unp;
     smb_waitingLockRequest_t *wlrp;
 
     if (lock)
         lock_ObtainRead(&smb_rctLock);
-  
+
     sprintf(output, "begin dumping smb_username_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    for (unp = usernamesp; unp; unp=unp->nextp) 
+    for (unp = usernamesp; unp; unp=unp->nextp)
     {
         cm_ucell_t *ucellp;
 
-        sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n", 
+        sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
                 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
-                unp->name ? unp->name : _C("NULL"), 
+                unp->name ? unp->name : _C("NULL"),
                 unp->machine ? unp->machine : _C("NULL"));
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
@@ -10821,9 +11518,9 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
         for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
-            sprintf(output, "  %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n", 
-                     cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno, 
-                     ucellp->expirationTime, ucellp->gen, 
+            sprintf(output, "  %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
+                     cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
+                     ucellp->expirationTime, ucellp->gen,
                      ucellp->userName,
                      ucellp->cellp->name);
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
@@ -10837,21 +11534,23 @@ 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;
 
         sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
                  cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-      
+
         sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
-            sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n", 
+            sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
                     cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
@@ -10865,20 +11564,20 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
     sprintf(output, "begin dumping smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
-    for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
+    for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
     {
         smb_fid_t *fidp;
         smb_tid_t *tidp;
         smb_user_t *userp;
-      
+
         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-      
+
         sprintf(output, "  begin dumping smb_user_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         for (userp = vcp->usersp; userp; userp = userp->nextp) {
-            sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
+            sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
@@ -10888,7 +11587,7 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
         sprintf(output, "  begin dumping smb_tid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
-            sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n", 
+            sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
                     tidp->pathname ? tidp->pathname : _C("NULL"));
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
@@ -10901,24 +11600,24 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
 
         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
-            sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n", 
+            sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
-                    fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
+                    fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
-      
+
         sprintf(output, "  done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
     sprintf(output, "done dumping smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-  
+
     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
-    for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
+    for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
     {
         smb_fid_t *fidp;
         smb_tid_t *tidp;
@@ -10927,11 +11626,11 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-      
+
         sprintf(output, "  begin dumping smb_user_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         for (userp = vcp->usersp; userp; userp = userp->nextp) {
-            sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
+            sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
@@ -10941,7 +11640,7 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
         sprintf(output, "  begin dumping smb_tid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
-            sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n", 
+            sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
                     tidp->pathname ? tidp->pathname : _C("NULL"));
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
@@ -10954,20 +11653,21 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
 
         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
-            sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n", 
+            sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
-                    fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
+                    fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
-      
+
         sprintf(output, "  done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
     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;
@@ -10976,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);