Windows: Improve SMB detection of Local System account
[openafs.git] / src / WINNT / afsd / smb.c
index e35f113..79b7885 100644 (file)
@@ -15,6 +15,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 +135,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;
 
@@ -154,13 +160,6 @@ int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
  */
 time_t smb_localZero = 0;
 
-#define USE_NUMERIC_TIME_CONV 1
-
-#ifndef USE_NUMERIC_TIME_CONV
-/* Time difference for converting to kludge-GMT */
-afs_uint32 smb_NowTZ;
-#endif /* USE_NUMERIC_TIME_CONV */
-
 char *smb_localNamep = NULL;
 
 smb_vc_t *smb_allVCsp;
@@ -170,8 +169,6 @@ smb_username_t *usernamesp = NULL;
 
 smb_waitingLockRequest_t *smb_allWaitingLocks;
 
-DWORD smb_TlsRequestSlot = -1;
-
 /* forward decl */
 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                        NCB *ncbp, raw_write_cont_t *rwcp);
@@ -197,42 +194,6 @@ void smb_InitReq(cm_req_t *reqp)
     reqp->flags |= CM_REQ_SOURCE_SMB;
 }
 
-void smb_ResetServerPriority()
-{
-    void * p = TlsGetValue(smb_TlsRequestSlot);
-    if (p) {
-       free(p);
-       TlsSetValue(smb_TlsRequestSlot, NULL);
-       SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
-    }
-}
-
-void smb_SetRequestStartTime()
-{
-    time_t * tp = TlsGetValue(smb_TlsRequestSlot);
-    if (!tp)
-       tp = malloc(sizeof(time_t));
-    if (tp) {
-       *tp = osi_Time();
-
-       if (!TlsSetValue(smb_TlsRequestSlot, tp))
-           free(tp);
-    }  
-}
-
-void smb_UpdateServerPriority()
-{      
-    time_t *tp = TlsGetValue(smb_TlsRequestSlot);
-
-    if (tp) {
-       time_t now = osi_Time();
-
-       /* Give one priority boost for each 15 seconds */
-       SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
-    }
-}
-
-
 const char * ncb_error_string(int code)
 {
     const char * s;
@@ -527,16 +488,34 @@ unsigned int smb_Attributes(cm_scache_t *scp)
      * turns out to be impolitic in NT.  See defect 10007.
      */
 #ifdef notdef
-    if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
+    if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
         attrs |= SMB_ATTR_READONLY;    /* turn on read-only flag */
 #else
-    if ((scp->unixModeBits & 0222) == 0)
+    if ((scp->unixModeBits & 0200) == 0)
         attrs |= SMB_ATTR_READONLY;    /* turn on read-only flag */
 #endif
 
     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 */
@@ -581,7 +560,7 @@ void ShowUnixTime(char *FuncName, time_t unixTime)
     FILETIME ft;
     WORD wDate, wTime;
 
-    smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
+    cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
 
     if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
         osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
@@ -682,169 +661,6 @@ void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
 }                      
 
-#ifndef USE_NUMERIC_TIME_CONV
-/*
- * Calculate the difference (in seconds) between local time and GMT.
- * This enables us to convert file times to kludge-GMT.
- */
-static void
-smb_CalculateNowTZ()
-{
-    time_t t;
-    struct tm gmt_tm, local_tm;
-    int days, hours, minutes, seconds;
-
-    t = time(NULL);
-    gmt_tm = *(gmtime(&t));
-    local_tm = *(localtime(&t));
-
-    days = local_tm.tm_yday - gmt_tm.tm_yday;
-    hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
-    minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min; 
-    seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
-
-    smb_NowTZ = seconds;
-}
-#endif /* USE_NUMERIC_TIME_CONV */
-
-#ifdef USE_NUMERIC_TIME_CONV
-void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
-{
-    // Note that LONGLONG is a 64-bit value
-    LONGLONG ll;
-
-    ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
-    largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
-    largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
-}
-#else
-void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
-{
-    struct tm *ltp;
-    SYSTEMTIME stm;
-    struct tm localJunk;
-    time_t ersatz_unixTime;
-
-    /*
-     * Must use kludge-GMT instead of real GMT.
-     * kludge-GMT is computed by adding time zone difference to localtime.
-     *
-     * real GMT would be:
-     * ltp = gmtime(&unixTime);
-     */
-    ersatz_unixTime = unixTime - smb_NowTZ;
-    ltp = localtime(&ersatz_unixTime);
-
-    /* if we fail, make up something */
-    if (!ltp) {
-        ltp = &localJunk;
-        localJunk.tm_year = 89 - 20;
-        localJunk.tm_mon = 4;
-        localJunk.tm_mday = 12;
-        localJunk.tm_hour = 0;
-        localJunk.tm_min = 0;
-        localJunk.tm_sec = 0;
-    }
-
-    stm.wYear = ltp->tm_year + 1900;
-    stm.wMonth = ltp->tm_mon + 1;
-    stm.wDayOfWeek = ltp->tm_wday;
-    stm.wDay = ltp->tm_mday;
-    stm.wHour = ltp->tm_hour;
-    stm.wMinute = ltp->tm_min;
-    stm.wSecond = ltp->tm_sec;
-    stm.wMilliseconds = 0;
-
-    SystemTimeToFileTime(&stm, largeTimep);
-}
-#endif /* USE_NUMERIC_TIME_CONV */
-
-#ifdef USE_NUMERIC_TIME_CONV
-void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
-{
-    // Note that LONGLONG is a 64-bit value
-    LONGLONG ll;
-
-    ll = largeTimep->dwHighDateTime;
-    ll <<= 32;
-    ll += largeTimep->dwLowDateTime;
-
-    ll -= 116444736000000000;
-    ll /= 10000000;
-
-    *unixTimep = (DWORD)ll;
-}
-#else /* USE_NUMERIC_TIME_CONV */
-void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
-{
-    SYSTEMTIME stm;
-    struct tm lt;
-    long save_timezone;
-
-    FileTimeToSystemTime(largeTimep, &stm);
-
-    lt.tm_year = stm.wYear - 1900;
-    lt.tm_mon = stm.wMonth - 1;
-    lt.tm_wday = stm.wDayOfWeek;
-    lt.tm_mday = stm.wDay;
-    lt.tm_hour = stm.wHour;
-    lt.tm_min = stm.wMinute;
-    lt.tm_sec = stm.wSecond;
-    lt.tm_isdst = -1;
-
-    save_timezone = _timezone;
-    _timezone += smb_NowTZ;
-    *unixTimep = mktime(&lt);
-    _timezone = save_timezone;
-}       
-#endif /* USE_NUMERIC_TIME_CONV */
-
-void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
-{
-    struct tm *ltp;
-    int dosDate;
-    int dosTime;
-    struct tm localJunk;
-    time_t t = unixTime;
-
-    ltp = localtime(&t);
-
-    /* if we fail, make up something */
-    if (!ltp) {
-        ltp = &localJunk;
-        localJunk.tm_year = 89 - 20;
-        localJunk.tm_mon = 4;
-        localJunk.tm_mday = 12;
-        localJunk.tm_hour = 0;
-        localJunk.tm_min = 0;
-        localJunk.tm_sec = 0;
-    }  
-
-    dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
-    dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
-    *searchTimep = (dosDate<<16) | dosTime;
-}      
-
-void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
-{
-    unsigned short dosDate;
-    unsigned short dosTime;
-    struct tm localTm;
-        
-    dosDate = (unsigned short) (searchTime & 0xffff);
-    dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
-
-    localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
-    localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;       /* January is 0 in localTm */
-    localTm.tm_mday = (dosDate) & 0x1f;
-    localTm.tm_hour = (dosTime>>11) & 0x1f;
-    localTm.tm_min = (dosTime >> 5) & 0x3f;
-    localTm.tm_sec = (dosTime & 0x1f) * 2;
-    localTm.tm_isdst = -1;                             /* compute whether DST in effect */
-
-    *unixTimep = mktime(&localTm);
-}
-
 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
 {
     time_t diff_t = unixTime - smb_localZero;
@@ -1415,6 +1231,66 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
     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)
 {
@@ -1626,27 +1502,35 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
     smb_fid_t *fidp;
     int newFid = 0;
         
-    if (fid == 0 && !(flags & SMB_FLAG_CREATE))
-        return NULL;
-
-    lock_ObtainWrite(&smb_rctLock);
-    /* figure out if we need to allocate a new file ID */
     if (fid == 0) {
+        if (!(flags & SMB_FLAG_CREATE))
+            return NULL;
         newFid = 1;
-        fid = vcp->fidCounter;
     }
 
+    lock_ObtainWrite(&smb_rctLock);
+    if (newFid)
+        fid = vcp->fidCounter;
   retry:
+
     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
        if (fidp->refCount == 0 && fidp->deleteOk) {
            fidp->refCount++;
            lock_ReleaseWrite(&smb_rctLock);
            smb_ReleaseFID(fidp);
            lock_ObtainWrite(&smb_rctLock);
+            /*
+             * We dropped the smb_rctLock so the fid value we are using
+             * may now be used by another thread.  Start over with the
+             * current vcp->fidCounter.
+             */
+            if (newFid)
+                fid = vcp->fidCounter;
            goto retry;
        }
         if (fid == fidp->fid) {
             if (newFid) {
+                osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  fid %d found -- retrying ...", fid);
                 fid++;
                 if (fid == 0xFFFF) {
                     osi_Log1(smb_logp,
@@ -1663,6 +1547,12 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
     if (!fidp && (flags & SMB_FLAG_CREATE)) {
         char eventName[MAX_PATH];
         EVENT_HANDLE event;
+
+        if (!newFid)
+            osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
+        else
+            osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  Creating fid %d", fid);
+
         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
@@ -2099,6 +1989,8 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         fschar_t ftemp[1024];
         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
@@ -2113,10 +2005,12 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
         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;
@@ -2139,12 +2033,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
         if (cellname)
             free(cellname);
 
@@ -2179,21 +2071,26 @@ int smb_FindShareCSCPolicy(clientchar_t *shareName)
     HKEY hkCSCPolicy;
     int  retval = CSC_POLICY_MANUAL;
 
-    RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
-                    AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
-                    0, 
-                    "AFS", 
-                    REG_OPTION_NON_VOLATILE,
-                    KEY_READ,
-                    NULL, 
-                    &hkCSCPolicy,
-                    NULL );
+    if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+                        AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
+                        0,
+                        "AFS",
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ,
+                        NULL,
+                        &hkCSCPolicy,
+                        NULL ) != ERROR_SUCCESS)
+        retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
 
     len = sizeof(policy);
     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
          len == 0) {
         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
     }
+    else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
+    {
+        retval = CSC_POLICY_MANUAL;
+    }
     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
     {
         retval = CSC_POLICY_DOCUMENTS;
@@ -2728,11 +2625,37 @@ void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponent
                             clientchar_t *inPathp)
 {
     clientchar_t *lastSlashp;
-        
+    clientchar_t *streamp = NULL;
+    clientchar_t *typep = NULL;
+
     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
-    if (lastComponentp)
+    if (lastComponentp) {
         *lastComponentp = lastSlashp;
+    }
     if (lastSlashp) {
+        /*
+         * If the name contains a stream name and a type
+         * and the stream name is the nul-string and the
+         * type is $DATA, then strip "::$DATA" from the
+         * last component string that is returned.
+         *
+         * Otherwise, return the full path name and allow
+         * the file name to be rejected because it contains
+         * a colon.
+         */
+        typep = cm_ClientStrRChr(lastSlashp, L':');
+        if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
+            *typep = '\0';
+            streamp = cm_ClientStrRChr(lastSlashp, L':');
+            if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
+                *streamp = '\0';
+            } else
+                *typep = ':';
+            osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
+                     osi_LogSaveClientString(smb_logp,streamp),
+                     osi_LogSaveClientString(smb_logp,typep));
+        }
+
         while (1) {
             if (inPathp == lastSlashp) 
                 break;
@@ -3113,7 +3036,7 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
         localNCB = 1;
     }
  
-    memset((char *)ncbp, 0, sizeof(NCB));
+    memset(ncbp, 0, sizeof(NCB));
 
     extra = 2 * (*inp->wctp);  /* space used by parms, in bytes */
     tp = inp->wctp + 1+ extra; /* points to count of data bytes */
@@ -3162,20 +3085,32 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0;
     } 
     else if (code == CM_ERROR_NOSUCHCELL) {
-        NTStatus = 0xC000000FL;        /* No such file */
+        NTStatus = 0xC0000034L;        /* Name not found */
     }
     else if (code == CM_ERROR_NOSUCHVOLUME) {
-        NTStatus = 0xC000000FL;        /* No such file */
+        NTStatus = 0xC0000034L;        /* Name not found */
     }
     else if (code == CM_ERROR_TIMEDOUT) {
 #ifdef COMMENT
         NTStatus = 0xC00000CFL;        /* Sharing Paused */
-#else
+
+        /* 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 */
 #endif
     }
     else if (code == CM_ERROR_RETRY) {
+#ifdef COMMENT
         NTStatus = 0xC000022DL;        /* Retry */
+#else
+        NTStatus = 0xC00000B5L; /* I/O Timeout */
+#endif
     }
     else if (code == CM_ERROR_NOACCESS) {
         NTStatus = 0xC0000022L;        /* Access denied */
@@ -3185,7 +3120,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     }
     else if (code == CM_ERROR_NOSUCHFILE ||
              code == CM_ERROR_BPLUS_NOMATCH) {
-        NTStatus = 0xC000000FL;        /* No such file */
+        NTStatus = 0xC0000034L;        /* Name not found */
     }
     else if (code == CM_ERROR_NOSUCHPATH) {
         NTStatus = 0xC000003AL;        /* Object path not found */
@@ -3202,6 +3137,9 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_BADFDOP) {
         NTStatus = 0xC0000022L;        /* Access denied */
     }
+    else if (code == CM_ERROR_UNKNOWN) {
+        NTStatus = 0xC0000022L;        /* Access denied */
+    }
     else if (code == CM_ERROR_EXISTS) {
         NTStatus = 0xC0000035L;        /* Object name collision */
     }
@@ -3235,7 +3173,8 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0xC000013DL; /* Remote Resources */
 #endif
     }
-    else if (code == CM_ERROR_CLOCKSKEW) {
+    else if (code == CM_ERROR_CLOCKSKEW ||
+             code == RXKADNOAUTH) {
         NTStatus = 0xC0000133L;        /* Time difference at DC */
     }
     else if (code == CM_ERROR_BADTID) {
@@ -3271,6 +3210,9 @@ 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 */
     }   
@@ -3294,11 +3236,19 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0xC0000257L; /* Path Not Covered */
     } 
     else if (code == CM_ERROR_ALLBUSY) {
+#ifdef COMMENT
         NTStatus = 0xC000022DL; /* Retry */
-    } 
+#else
+        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 */
     } 
@@ -3381,6 +3331,9 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
     else if (code == CM_ERROR_BADFDOP) {
         Win32E = ERROR_ACCESS_DENIED;  /* Access denied */
     }
+    else if (code == CM_ERROR_UNKNOWN) {
+        Win32E = ERROR_ACCESS_DENIED;  /* Access denied */
+    }
     else if (code == CM_ERROR_EXISTS) {
         Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
     }
@@ -3409,7 +3362,8 @@ void smb_MapWin32Error(long code, unsigned long *Win32Ep)
         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
 #endif
     }
-    else if (code == CM_ERROR_CLOCKSKEW) {
+    else if (code == CM_ERROR_CLOCKSKEW ||
+             code == RXKADNOAUTH) {
         Win32E = ERROR_TIME_SKEW;      /* Time difference at DC */
     }
     else if (code == CM_ERROR_BADTID) {
@@ -3749,9 +3703,11 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
              fd, offset.HighPart, offset.LowPart, count);
 
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         goto send1;
-
+    }
     lock_ObtainMutex(&fidp->mx);
     if (!fidp->scp) {
         lock_ReleaseMutex(&fidp->mx);
@@ -3832,7 +3788,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
 
   send1:
     ncbp = outp->ncbp;
-    memset((char *)ncbp, 0, sizeof(NCB));
+    memset(ncbp, 0, sizeof(NCB));
 
     ncbp->ncb_length = (unsigned short) finalCount;
     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
@@ -4014,7 +3970,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         smb_SetSMBParmLong(outp, 9, caps);
         time(&unixTime);
-        smb_SearchTimeFromUnixTime(&dosTime, unixTime);
+        cm_SearchTimeFromUnixTime(&dosTime, unixTime);
         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
 
@@ -4074,7 +4030,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_SetSMBParm(outp, 6, 1);    /* next 2: session key */
         smb_SetSMBParm(outp, 7, 1);
         time(&unixTime);
-        smb_SearchTimeFromUnixTime(&dosTime, unixTime);
+        cm_SearchTimeFromUnixTime(&dosTime, unixTime);
         smb_SetSMBParm(outp, 8, LOWORD(dosTime));      /* server time */
         smb_SetSMBParm(outp, 9, HIWORD(dosTime));      /* server date */
 
@@ -4189,12 +4145,9 @@ void smb_Daemon(void *parmp)
             myTime.tm_sec = 0;
             smb_localZero = mktime(&myTime);
 
-#ifndef USE_NUMERIC_TIME_CONV
-            smb_CalculateNowTZ();
-#endif /* USE_NUMERIC_TIME_CONV */
 #ifdef AFS_FREELANCE
             if ( smb_localZero != old_localZero )
-                cm_noteLocalMountPointChange();
+                cm_noteLocalMountPointChange(FALSE);
 #endif
 
            smb_CheckVCs();
@@ -4802,7 +4755,7 @@ smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
             *dptr++ = attr;
 
             /* get dos time */
-            smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+            cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
                 
             /* copy out time */
             shortTemp = (unsigned short) (dosTime & 0xffff);
@@ -4984,7 +4937,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
@@ -5407,10 +5360,10 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     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);
@@ -5496,10 +5449,10 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     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);
@@ -5557,12 +5510,12 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
     }
-    if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
+    if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
         /* we're told to make a writable file read-only */
         attr.unixModeBits = newScp->unixModeBits & ~0222;
         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
     }
-    else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
+    else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
         /* we're told to make a read-only file writable */
         attr.unixModeBits = newScp->unixModeBits | 0222;
         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
@@ -5611,10 +5564,10 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     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;
 
@@ -5789,6 +5742,13 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 #endif
 
+    share = smb_GetSMBParm(inp, 0);
+    attribute = smb_GetSMBParm(inp, 1);
+
+    spacep = inp->spacep;
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
+
     if (!cm_IsValidClientString(pathp)) {
 #ifdef DEBUG
         clientchar_t * hexp;
@@ -5804,11 +5764,6 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADNTFILENAME;
     }
 
-    share = smb_GetSMBParm(inp, 0);
-    attribute = smb_GetSMBParm(inp, 1);
-
-    spacep = inp->spacep;
-    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
     if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
@@ -5837,7 +5792,7 @@ 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) {
@@ -6019,7 +5974,7 @@ 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);
@@ -6211,7 +6166,7 @@ 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);
@@ -6231,7 +6186,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) {
@@ -6421,7 +6376,7 @@ 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);
@@ -6441,7 +6396,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);
@@ -6668,7 +6623,7 @@ 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) {
@@ -6776,9 +6731,11 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     fid = smb_ChainFID(fid, inp);
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         return CM_ERROR_BADFD;
-    
+    }
     userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
@@ -6801,7 +6758,7 @@ 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);
@@ -6940,14 +6897,16 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
          == SMB_FID_OPENWRITE) {
         if (dosTime != 0 && dosTime != -1) {
+            lock_ObtainWrite(&fidp->scp->rw);
             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
             /* This fixes defect 10958 */
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
             smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
+            lock_ReleaseWrite(&fidp->scp->rw);
         }
         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);
         }
     }
@@ -7095,6 +7054,8 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fid = smb_ChainFID(fid, inp);
     fidp = smb_FindFID(vcp, fid, 0);
     if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         return CM_ERROR_BADFD;
     }
         
@@ -7303,6 +7264,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);
@@ -7378,10 +7340,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)) {
@@ -7396,6 +7355,13 @@ 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;
@@ -7411,18 +7377,17 @@ 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
@@ -7436,7 +7401,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
@@ -7453,20 +7427,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
@@ -7487,12 +7462,17 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
         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) {
@@ -7575,7 +7555,8 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
-       osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
+        osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         return CM_ERROR_BADFD;
     }
         
@@ -7669,8 +7650,10 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      */
     lock_ObtainMutex(&fidp->mx);
     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
+        lock_ObtainWrite(&fidp->scp->rw);
         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
         fidp->scp->clientModTime = time(NULL);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }
     lock_ReleaseMutex(&fidp->mx);
 
@@ -7835,9 +7818,11 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         return CM_ERROR_BADFD;
-
+    }
     lock_ObtainMutex(&fidp->mx);
     if (!fidp->scp) {
         lock_ReleaseMutex(&fidp->mx);
@@ -7895,8 +7880,10 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      */
     lock_ObtainMutex(&fidp->mx);
     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
+        lock_ObtainWrite(&fidp->scp->rw);
         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
         fidp->scp->clientModTime = time(NULL);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }
     lock_ReleaseMutex(&fidp->mx);
 
@@ -7993,9 +7980,11 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         return CM_ERROR_BADFD;
-
+    }
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -8132,7 +8121,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);
 
@@ -8171,6 +8160,8 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         
     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,
@@ -8219,7 +8210,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;
@@ -8237,16 +8227,15 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     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)
         return CM_ERROR_BADSMB;
 
+    spacep = inp->spacep;
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
+
     if (!cm_IsValidClientString(pathp)) {
 #ifdef DEBUG
         clientchar_t * hexp;
@@ -8262,9 +8251,6 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADNTFILENAME;
     }
 
-    spacep = inp->spacep;
-    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
-
     userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
@@ -8274,7 +8260,7 @@ 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) {
@@ -8342,6 +8328,8 @@ 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) {
@@ -8444,9 +8432,11 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* try to find the file descriptor */
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
        return CM_ERROR_BADFD;
-
+    }
     lock_ObtainMutex(&fidp->mx);
     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
        lock_ReleaseMutex(&fidp->mx);
@@ -8599,7 +8589,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
             smbp = (smb_t *) inp;
 
             osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
-                      opName, smbp->mid, vcp,vcp->lana,vcp->lsn);
+                      opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
             if (inp->inCom == 0x1d) {
                 /* Raw Write */
                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
@@ -8607,7 +8597,7 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                 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);
+                      code, smbp->mid, vcp, vcp->lana, vcp->lsn);
 
             newTime = GetTickCount();
             osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms", 
@@ -8960,6 +8950,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
@@ -8996,7 +9341,7 @@ void smb_Server(VOID *parmp)
            vcp = NULL;
        }
 
-       smb_ResetServerPriority();
+       cm_ResetServerPriority();
 
         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
                                                  FALSE, INFINITE);
@@ -9183,7 +9528,10 @@ void smb_Server(VOID *parmp)
             continue;
         }
 
-       smb_SetRequestStartTime();
+       cm_SetRequestStartTime();
+        if (smb_monitorReqs) {
+            smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
+        }
 
         vcp->errorCount = 0;
         bufp = (struct smb_packet *) ncbp->ncb_buffer;
@@ -9240,6 +9588,9 @@ void smb_Server(VOID *parmp)
         }
 #endif
 
+        if (smb_monitorReqs) {
+            smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
+        }
         smb_concurrentCalls--;
 
       doneWithNCB:
@@ -10360,14 +10711,12 @@ 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;
 
-    smb_TlsRequestSlot = TlsAlloc();
-
     smb_MBfunc = aMBfunc;
 
     smb_useV3 = useV3;
@@ -10382,13 +10731,9 @@ void smb_Init(osi_log_t *logp, int useV3,
     myTime.tm_sec = 0;
     smb_localZero = mktime(&myTime);
 
-#ifndef USE_NUMERIC_TIME_CONV
-    /* Initialize kludge-GMT */
-    smb_CalculateNowTZ();
-#endif /* USE_NUMERIC_TIME_CONV */
 #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 */
@@ -10714,6 +11059,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;
 }
@@ -10734,7 +11086,7 @@ void smb_Shutdown(void)
     smbShutdownFlag = 1;
 
     /* Hang up all sessions */
-    memset((char *)ncbp, 0, sizeof(NCB));
+    memset(ncbp, 0, sizeof(NCB));
     for (i = 1; i < numSessions; i++)
     {
         if (dead_sessions[i])
@@ -10772,7 +11124,7 @@ void smb_Shutdown(void)
     }                                                                            
 
     /* Delete Netbios name */
-    memset((char *)ncbp, 0, sizeof(NCB));
+    memset(ncbp, 0, sizeof(NCB));
     for (i = 0; i < lana_list.length; i++) {
         if (lana_list.lana[i] == LANA_INVALID) continue;
         ncbp->ncb_command = NCBDELNAME;
@@ -10832,7 +11184,10 @@ void smb_Shutdown(void)
     }
     lock_ReleaseWrite(&smb_rctLock);
     smb_FreeNCB(ncbp);
-    TlsFree(smb_TlsRequestSlot);
+
+    if (smb_monitorReqs) {
+        smb_ShutdownMonitor();
+    }
 }
 
 /* Get the UNC \\<servername>\<sharename> prefix. */