Windows: do not leak space allocation
[openafs.git] / src / WINNT / afsd / smb3.c
index 9bdcf00..2dcc708 100644 (file)
@@ -1,13 +1,17 @@
+
 /*
  * 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>
@@ -16,6 +20,7 @@
 #include <ntstatus.h>
 #define SECURITY_WIN32
 #include <security.h>
+#include <sddl.h>
 #include <lmaccess.h>
 #pragma warning(pop)
 #include <stdlib.h>
@@ -29,6 +34,7 @@
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
+#include "msrpc.h"
 #include <strsafe.h>
 
 extern osi_hyper_t hzero;
@@ -51,11 +57,11 @@ cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
 {
     smb_user_t *uidp;
     cm_user_t *up = NULL;
-        
+
     uidp = smb_FindUID(vcp, inp->uid, 0);
-    if (!uidp) 
+    if (!uidp)
        return NULL;
-        
+
     up = smb_GetUserFromUID(uidp);
 
     smb_ReleaseUID(uidp);
@@ -63,14 +69,14 @@ cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
     return up;
 }
 
-/* 
- * Return boolean specifying if the path name is thought to be an 
+/*
+ * Return boolean specifying if the path name is thought to be an
  * executable file.  For now .exe or .dll.
  */
 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
 {
     int i, j, len;
-        
+
     if ( smb_ExecutableExtensions == NULL || name == NULL)
         return 0;
 
@@ -106,7 +112,7 @@ unsigned long smb_ExtAttributes(cm_scache_t *scp)
         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
     } else if (scp->fid.vnode & 0x1)
         attrs = SMB_ATTR_DIRECTORY;
-    else 
+    else
         attrs = 0;
 
     /*
@@ -114,10 +120,10 @@ unsigned long smb_ExtAttributes(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;            /* Read-only */
 #else
-    if ((scp->unixModeBits & 0222) == 0)
+    if ((scp->unixModeBits & 0200) == 0)
         attrs |= SMB_ATTR_READONLY;            /* Read-only */
 #endif
 
@@ -132,7 +138,7 @@ int smb_V3IsStarMask(clientchar_t *maskp)
     clientchar_t tc;
 
     while (tc = *maskp++)
-        if (tc == '?' || tc == '*' || tc == '<' || tc == '>') 
+        if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
             return 1;
     return 0;
 }
@@ -144,8 +150,6 @@ void OutputDebugF(clientchar_t * format, ...) {
     va_start( args, format );
     cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
     osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
-    cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
-    OutputDebugStringW(vbuffer);
 }
 
 void OutputDebugHexDump(unsigned char * buffer, int len) {
@@ -159,8 +163,6 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         if(!(i%16)) {
             if(i) {
                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
-                StringCchCatA(buf, lengthof(buf), "\r\n");
-                OutputDebugString(buf);
             }
             StringCchPrintfA(buf, lengthof(buf), "%5x", i);
             memset(buf+5,' ',80);
@@ -177,12 +179,10 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         j = j + 56 + ((j>7)?1:0);
 
         buf[j] = (k>32 && k<127)?k:'.';
-    }    
+    }
     if(i) {
         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
-        StringCchCatA(buf, lengthof(buf), "\r\n");
-        OutputDebugString(buf);
-    }   
+    }
 }
 
 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
@@ -268,16 +268,160 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
     return;
 }
 
+afs_uint32
+smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
+{
+    BOOL bSuccess = FALSE;
+    DWORD dwIndex;
+    DWORD dwLength = 0;
+    PTOKEN_GROUPS ptg = NULL;
+
+    // Verify the parameter passed in is not NULL.
+    if (NULL == ppsid)
+        goto Cleanup;
+
+    // Get required buffer size and allocate the TOKEN_GROUPS buffer.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenGroups,    // get information about the token's groups
+                              (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
+                              0,              // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            goto Cleanup;
+
+        ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
+                                        HEAP_ZERO_MEMORY, dwLength);
+
+        if (ptg == NULL)
+            goto Cleanup;
+    }
+
+    // Get the token group information from the access token.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenGroups,    // get information about the token's groups
+                              (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
+                              dwLength,       // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        goto Cleanup;
+    }
+
+    // Loop through the groups to find the logon SID.
+    for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
+        if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) ==  SE_GROUP_LOGON_ID)
+        {
+            // Found the logon SID; make a copy of it.
+
+            dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
+            *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
+                                       HEAP_ZERO_MEMORY, dwLength);
+            if (*ppsid == NULL)
+                goto Cleanup;
+            if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
+            {
+                HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
+                goto Cleanup;
+            }
+            bSuccess = TRUE;
+            break;
+        }
+    }
+
+  Cleanup:
+
+    // Free the buffer for the token groups.
+    if (ptg != NULL)
+        HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
+
+    return bSuccess;
+}
+
+afs_uint32
+smb_GetUserSID(HANDLE hToken, PSID *ppsid)
+{
+    BOOL bSuccess = FALSE;
+    DWORD dwLength = 0;
+    PTOKEN_USER ptu = NULL;
+
+    // Verify the parameter passed in is not NULL.
+    if (NULL == ppsid)
+        goto Cleanup;
+
+    // Get required buffer size and allocate the TOKEN_USER buffer.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenUser,      // get information about the token's user
+                              (LPVOID) ptu,   // pointer to TOKEN_USER buffer
+                              0,              // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            goto Cleanup;
+
+        ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
+                                        HEAP_ZERO_MEMORY, dwLength);
+
+        if (ptu == NULL)
+            goto Cleanup;
+    }
+
+    // Get the token group information from the access token.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenUser,      // get information about the token's user
+                              (LPVOID) ptu,   // pointer to TOKEN_USER buffer
+                              dwLength,       // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        goto Cleanup;
+    }
+
+    // Found the user SID; make a copy of it.
+    dwLength = GetLengthSid(ptu->User.Sid);
+    *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
+    if (*ppsid == NULL)
+        goto Cleanup;
+    if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
+    {
+        HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
+        goto Cleanup;
+    }
+    bSuccess = TRUE;
+
+  Cleanup:
+
+    // Free the buffer for the token groups.
+    if (ptu != NULL)
+        HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
+
+    return bSuccess;
+}
+
+void
+smb_FreeSID (PSID psid)
+{
+    HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
+}
+
+
 struct smb_ext_context {
     CredHandle creds;
     CtxtHandle ctx;
     int partialTokenLen;
     void * partialToken;
-};      
+};
 
 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
                              char * secBlobIn, int secBlobInLength,
-                             char ** secBlobOut, int * secBlobOutLength) {
+                             char ** secBlobOut, int * secBlobOutLength,
+                             wchar_t **secSidString) {
     SECURITY_STATUS status, istatus;
     CredHandle creds;
     TimeStamp expiry;
@@ -297,6 +441,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
 
     *secBlobOut = NULL;
     *secBlobOutLength = 0;
+    *secSidString = NULL;
 
     if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
         secCtx = vcp->secCtx;
@@ -310,9 +455,9 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
         OutputDebugF(_C("Received incoming token:"));
         OutputDebugHexDump(secBlobIn,secBlobInLength);
     }
-    
+
     if (secCtx) {
-        OutputDebugF(_C("Continuing with existing context."));         
+        OutputDebugF(_C("Continuing with existing context."));
         creds = secCtx->creds;
         ctx = secCtx->ctx;
 
@@ -400,8 +545,8 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
         code = CM_ERROR_GSSCONTINUE;
     }
 
-    if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
-          status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
+    if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
+          status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
          secTokOut.pvBuffer) {
         OutputDebugF(_C("Need to send token back to client"));
 
@@ -432,6 +577,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
 
     if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
         /* woo hoo! */
+        HANDLE hToken = 0;
         SecPkgContext_NamesW names;
 
         OutputDebugF(_C("Authentication completed"));
@@ -445,7 +591,22 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
         } else {
             /* Force the user to retry if the context is invalid */
             OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
-            code = CM_ERROR_BADPASSWORD; 
+            code = CM_ERROR_BADPASSWORD;
+        }
+
+        /* Obtain the user's SID */
+        if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
+            PSID pSid = 0;
+            OutputDebugF(_C("Received hToken"));
+
+            if (smb_GetUserSID(hToken, &pSid))
+                ConvertSidToStringSidW(pSid, secSidString);
+
+            if (pSid)
+                smb_FreeSID(pSid);
+            CloseHandle(hToken);
+        } else {
+            OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
         }
     } else if (!code) {
         switch ( status ) {
@@ -506,7 +667,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
 #define P_LEN 256
 #define P_RESP_LEN 128
 
-/* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
+/* LsaLogonUser expects input parameters to be in a contiguous block of memory.
    So put stuff in a struct. */
 struct Lm20AuthBlob {
     MSV1_0_LM20_LOGON lmlogon;
@@ -519,7 +680,7 @@ struct Lm20AuthBlob {
     TOKEN_SOURCE tsource;
 };
 
-long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) 
+long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
 {
     NTSTATUS nts, ntsEx;
     struct Lm20AuthBlob lmAuth;
@@ -541,7 +702,7 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientcha
     memset(&lmAuth,0,sizeof(lmAuth));
 
     lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
-       
+
     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
     cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
     lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
@@ -618,11 +779,11 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientcha
             return CM_ERROR_BADLOGONTYPE;
         else /* our catchall is a bad password though we could be more specific */
             return CM_ERROR_BADPASSWORD;
-    }       
+    }
 }
 
 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
-long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName) 
+long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
 {
     clientchar_t * atsign;
     const clientchar_t * domain;
@@ -648,7 +809,7 @@ long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accoun
        it will either return an empty string or a '?' */
     if (!domain[0] || domain[0] == '?')
         /* Empty domains and empty usernames are usually sent from tokenless contexts.
-           This way such logins will get an empty username (easy to check).  I don't know 
+           This way such logins will get an empty username (easy to check).  I don't know
            when a non-empty username would be supplied with an anonymous domain, but *shrug* */
         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
     else {
@@ -667,7 +828,7 @@ long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accoun
 }
 
 /* When using SMB auth, all SMB sessions have to pass through here
- * first to authenticate the user.  
+ * first to authenticate the user.
  *
  * Caveat: If not using SMB auth, the protocol does not require
  * sending a session setup packet, which means that we can't rely on a
@@ -682,15 +843,45 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     unsigned long caps = 0;
     smb_username_t *unp;
     clientchar_t *s1 = _C(" ");
-    long code = 0; 
+    long code = 0;
     clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
+    int usernIsSID = 0;
     char *secBlobOut = NULL;
     int  secBlobOutLength = 0;
+    wchar_t *secSidString = 0;
+    int  maxBufferSize = 0;
+    int  maxMpxCount = 0;
+    int  vcNumber = 0;
 
     /* Check for bad conns */
     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
         return CM_ERROR_REMOTECONN;
 
+    /* maxBufferSize */
+    maxBufferSize = smb_GetSMBParm(inp, 2);
+    maxMpxCount = smb_GetSMBParm(inp, 3);
+    vcNumber = smb_GetSMBParm(inp, 4);
+
+    osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
+             maxBufferSize, maxMpxCount, vcNumber);
+
+    if (maxMpxCount > smb_maxMpxRequests) {
+        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
+        osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
+                 maxMpxCount, smb_maxMpxRequests);
+    }
+
+    if (maxBufferSize < SMB_PACKETSIZE) {
+        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
+        osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
+                 maxBufferSize, SMB_PACKETSIZE);
+    }
+
+    if (vcNumber == 0) {
+        osi_Log0(smb_logp, "Resetting all VCs");
+        smb_MarkAllVCsDead(vcp);
+    }
+
     if (vcp->flags & SMB_VCFLAG_USENT) {
         if (smb_authType == SMB_AUTH_EXTENDED) {
             /* extended authentication */
@@ -698,7 +889,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             int secBlobInLength;
 
             OutputDebugF(_C("NT Session Setup: Extended"));
-        
+
             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
             }
@@ -706,7 +897,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             secBlobInLength = smb_GetSMBParm(inp, 7);
             secBlobIn = smb_GetSMBData(inp, NULL);
 
-            code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
+            code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
 
             if (code == CM_ERROR_GSSCONTINUE) {
                 size_t cb_data = 0;
@@ -720,7 +911,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
                     free(secBlobOut);
                     tp += secBlobOutLength;
                     cb_data += secBlobOutLength;
-                }      
+                }
                 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
                 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
                 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
@@ -837,7 +1028,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         /* for the moment we can only deal with NTSTATUS */
         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
             vcp->flags |= SMB_VCFLAG_STATUS32;
-        }       
+        }
 
 #ifdef SMB_UNICODE
         if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
@@ -852,9 +1043,20 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
        early to avoid accidently stealing someone else's tokens. */
 
     if (code) {
+        if (secSidString)
+            LocalFree(secSidString);
         return code;
     }
 
+    /*
+     * If the SidString for the user could be obtained, use that
+     * for the user id
+     */
+    if (secSidString) {
+        cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
+        usernIsSID = 1;
+    }
+
     OutputDebugF(_C("Received username=[%s]"), usern);
 
     /* On Windows 2000, this function appears to be called more often than
@@ -881,11 +1083,13 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
        lock_ObtainMutex(&unp->mx);
        if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
-           /* clear the afslogon flag so that the tickets can now 
+           /* clear the afslogon flag so that the tickets can now
             * be freed when the refCount returns to zero.
             */
            unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
        }
+    if (usernIsSID)
+        unp->flags |= SMB_USERNAMEFLAG_SID;
        lock_ReleaseMutex(&unp->mx);
 
         /* Create a new UID and cm_user_t structure */
@@ -937,7 +1141,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
                 free(secBlobOut);
                 tp += secBlobOutLength;
                 cb_data +=  secBlobOutLength;
-            }  
+            }
 
             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
@@ -963,6 +1167,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         }
     }
 
+    if (secSidString)
+        LocalFree(secSidString);
     return 0;
 }
 
@@ -1004,7 +1210,7 @@ long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 
        smb_ReleaseUID(uidp);
     }
-    else    
+    else
         osi_Log0(smb_logp, "SMB3 user logoffX");
 
     smb_SetSMBDataLength(outp, 0);
@@ -1030,7 +1236,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     clientchar_t *servicep;
     cm_user_t *userp = NULL;
     int ipc = 0;
-        
+
     osi_Log0(smb_logp, "SMB3 receive tree connect");
 
     /* parse input parameters */
@@ -1067,7 +1273,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     lock_ObtainMutex(&vcp->mx);
     newTid = vcp->tidCounter++;
     lock_ReleaseMutex(&vcp->mx);
-        
+
     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
 
     if (!ipc) {
@@ -1097,7 +1303,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
                     dwAdvertiseDFS = 0;
                 RegCloseKey (parmKey);
             }
-            smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
+            smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
                            (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
                            (policy << 2));
         }
@@ -1111,7 +1317,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     lock_ObtainMutex(&tidp->mx);
     tidp->userp = userp;
     tidp->pathname = sharePath;
-    if (ipc) 
+    if (ipc)
         tidp->flags |= SMB_TIDFLAG_IPC;
     lock_ReleaseMutex(&tidp->mx);
     smb_ReleaseTID(tidp, FALSE);
@@ -1141,7 +1347,7 @@ smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
 {
     smb_tran2Packet_t *tp;
     smb_t *smbp;
-        
+
     smbp = (smb_t *) inp->data;
     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
@@ -1155,7 +1361,7 @@ smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
 {
     smb_tran2Packet_t *tp;
     smb_t *smbp;
-        
+
     smbp = (smb_t *) inp->data;
     tp = malloc(sizeof(*tp));
     memset(tp, 0, sizeof(*tp));
@@ -1190,7 +1396,7 @@ smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
 
 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
                                               smb_tran2Packet_t *inp, smb_packet_t *outp,
-                                              int totalParms, int totalData)  
+                                              int totalParms, int totalData)
 {
     smb_tran2Packet_t *tp;
     unsigned short parmOffset;
@@ -1229,7 +1435,7 @@ smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
     tp->datap = outp->data + dataOffset;
 
     return tp;
-}       
+}
 
 /* free a tran2 packet */
 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
@@ -1243,7 +1449,11 @@ void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
             free(t2p->parmsp);
         if (t2p->datap)
             free(t2p->datap);
-    }       
+    }
+    if (t2p->name) {
+       free(t2p->name);
+       t2p->name = NULL;
+    }
     while (t2p->stringsp) {
         cm_space_t * ns;
 
@@ -1299,7 +1509,7 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
-        
+
     /* now copy important fields from the tran 2 packet */
     smbp->com = t2p->com;
     smbp->tid = t2p->tid;
@@ -1319,10 +1529,10 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
         smbp->errLow = (unsigned char) (errCode & 0xff);
         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
     }
-        
+
     /* send packet */
     smb_SendPacket(vcp, tp);
-}        
+}
 
 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
 {
@@ -1348,6 +1558,30 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
     smbp->uid = t2p->uid;
     smbp->res[0] = t2p->res[0];
 
+    if (t2p->error_code) {
+       if (vcp->flags & SMB_VCFLAG_STATUS32) {
+           unsigned long NTStatus;
+
+           smb_MapNTError(t2p->error_code, &NTStatus);
+
+           smbp->rcls = (unsigned char) (NTStatus & 0xff);
+           smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
+           smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
+           smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
+           smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
+       }
+       else {
+           unsigned short errCode;
+           unsigned char errClass;
+
+           smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
+
+           smbp->rcls = errClass;
+           smbp->errLow = (unsigned char) (errCode & 0xff);
+           smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
+       }
+    }
+
     totalLength = 1 + t2p->totalData + t2p->totalParms;
 
     /* now add the core parameters (tran2 info) to the packet */
@@ -1374,10 +1608,84 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
 
     totalLength += dataAlign;
     smb_SetSMBDataLength(tp, totalLength);
-        
+
     /* next, send the datagram */
     smb_SendPacket(vcp, tp);
-}   
+}
+
+/* TRANS_SET_NMPIPE_STATE */
+long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+    smb_fid_t *fidp;
+    int fd;
+    int pipeState = 0x0100;    /* default */
+    smb_tran2Packet_t *outp = NULL;
+
+    fd = p->pipeParam;
+    if (p->totalParms > 0)
+       pipeState = p->parmsp[0];
+
+    osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
+
+    fidp = smb_FindFID(vcp, fd, 0);
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
+       return CM_ERROR_BADFD;
+    }
+    lock_ObtainMutex(&fidp->mx);
+    if (pipeState & 0x8000)
+       fidp->flags |= SMB_FID_BLOCKINGPIPE;
+    if (pipeState & 0x0100)
+       fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
+    lock_ReleaseMutex(&fidp->mx);
+
+    outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
+    smb_SendTran2Packet(vcp, outp, op);
+    smb_FreeTran2Packet(outp);
+
+    smb_ReleaseFID(fidp);
+
+    return 0;
+}
+
+long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+    smb_fid_t *fidp;
+    int fd;
+    int is_rpc = 0;
+
+    long code = 0;
+
+    fd = p->pipeParam;
+
+    osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
+            fd, p->totalData, p->maxReturnData);
+
+    fidp = smb_FindFID(vcp, fd, 0);
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
+       return CM_ERROR_BADFD;
+    }
+    lock_ObtainMutex(&fidp->mx);
+    if (fidp->flags & SMB_FID_RPC) {
+       is_rpc = 1;
+    }
+    lock_ReleaseMutex(&fidp->mx);
+
+    if (is_rpc) {
+       code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
+       smb_ReleaseFID(fidp);
+    } else {
+       /* We only deal with RPC pipes */
+        osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
+                 vcp, fd);
+       code = CM_ERROR_BADFD;
+    }
+
+    return code;
+}
 
 
 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
@@ -1398,7 +1706,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* We sometimes see 0 word count.  What to do? */
     if (*inp->wctp == 0) {
-        osi_Log0(smb_logp, "Transaction2 word count = 0"); 
+        osi_Log0(smb_logp, "Transaction2 word count = 0");
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
 
         smb_SetSMBDataLength(outp, 0);
@@ -1408,9 +1716,9 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     totalParms = smb_GetSMBParm(inp, 0);
     totalData = smb_GetSMBParm(inp, 1);
-        
+
     firstPacket = (inp->inCom == 0x25);
-        
+
     /* find the packet we're reassembling */
     lock_ObtainWrite(&smb_globalLock);
     asp = smb_FindTran2Packet(vcp, inp);
@@ -1418,7 +1726,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
     }
     lock_ReleaseWrite(&smb_globalLock);
-        
+
     /* now merge in this latest packet; start by looking up offsets */
     if (firstPacket) {
         parmDisp = dataDisp = 0;
@@ -1426,11 +1734,26 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         dataOffset = smb_GetSMBParm(inp, 12);
         parmCount = smb_GetSMBParm(inp, 9);
         dataCount = smb_GetSMBParm(inp, 11);
+       asp->setupCount = smb_GetSMBParmByte(inp, 13);
         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
         asp->maxReturnData = smb_GetSMBParm(inp, 3);
 
         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
                   totalData, dataCount, asp->maxReturnData);
+
+       if (asp->setupCount == 2) {
+           clientchar_t * pname;
+
+           asp->pipeCommand = smb_GetSMBParm(inp, 14);
+           asp->pipeParam = smb_GetSMBParm(inp, 15);
+           pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
+           if (pname) {
+               asp->name = cm_ClientStrDup(pname);
+           }
+
+           osi_Log2(smb_logp, "  Named Pipe command id [%d] with name [%S]",
+                    asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
+       }
     }
     else {
         parmDisp = smb_GetSMBParm(inp, 4);
@@ -1442,7 +1765,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
                  parmCount, dataCount);
-    }   
+    }
 
     /* now copy the parms and data */
     if ( asp->totalParms > 0 && parmCount != 0 )
@@ -1458,27 +1781,91 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     asp->curParms += parmCount;
 
     /* finally, if we're done, remove the packet from the queue and dispatch it */
-    if (asp->totalParms > 0 &&
-        asp->curParms > 0 &&
+    if (((asp->totalParms > 0 && asp->curParms > 0)
+        || asp->setupCount == 2) &&
         asp->totalData <= asp->curData &&
         asp->totalParms <= asp->curParms) {
+
         /* we've received it all */
         lock_ObtainWrite(&smb_globalLock);
         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
         lock_ReleaseWrite(&smb_globalLock);
 
-        /* now dispatch it */
-        rapOp = asp->parmsp[0];
+       switch(asp->setupCount) {
+       case 0:
+           {                   /* RAP */
+               rapOp = asp->parmsp[0];
 
-        if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
-            code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
-        }
-        else {
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
-            code = CM_ERROR_BADOP;
-        }
+               if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
+                    smb_rapDispatchTable[rapOp].procp) {
+
+                   osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
+                            myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
+
+                   code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
+
+                   osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",
+                            code,vcp,vcp->lana,vcp->lsn);
+               }
+               else {
+                   osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
+                            rapOp, vcp, vcp->lana, vcp->lsn);
+
+                   code = CM_ERROR_BADOP;
+               }
+           }
+           break;
+
+       case 2:
+           {                   /* Named pipe operation */
+               osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
+                        myCrt_NmpipeDispatch(asp->pipeCommand),
+                        osi_LogSaveClientString(smb_logp, asp->name));
+
+               code = CM_ERROR_BADOP;
+
+               switch (asp->pipeCommand) {
+               case SMB_TRANS_SET_NMPIPE_STATE:
+                   code = smb_nmpipeSetState(vcp, asp, outp);
+                   break;
+
+               case SMB_TRANS_RAW_READ_NMPIPE:
+                   break;
+
+               case SMB_TRANS_QUERY_NMPIPE_STATE:
+                   break;
+
+               case SMB_TRANS_QUERY_NMPIPE_INFO:
+                   break;
+
+               case SMB_TRANS_PEEK_NMPIPE:
+                   break;
+
+               case SMB_TRANS_TRANSACT_NMPIPE:
+                   code = smb_nmpipeTransact(vcp, asp, outp);
+                   break;
+
+               case SMB_TRANS_RAW_WRITE_NMPIPE:
+                   break;
+
+               case SMB_TRANS_READ_NMPIPE:
+                   break;
+
+               case SMB_TRANS_WRITE_NMPIPE:
+                   break;
+
+               case SMB_TRANS_WAIT_NMPIPE:
+                   break;
+
+               case SMB_TRANS_CALL_NMPIPE:
+                   break;
+               }
+           }
+           break;
+
+       default:
+           code = CM_ERROR_BADOP;
+       }
 
         /* if an error is returned, we're supposed to send an error packet,
          * otherwise the dispatched function already did the data sending.
@@ -1558,7 +1945,7 @@ int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp
         return CM_ERROR_STOPNOW;
     else
         return 0;
-}       
+}
 
 /* RAP NetShareEnumRequest */
 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
@@ -1589,6 +1976,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     cm_req_t req;
     cm_user_t * userp;
     osi_hyper_t thyper;
+    cm_scache_t *rootScp;
 
     tp = p->parmsp + 1; /* skip over function number (always 0) */
 
@@ -1651,16 +2039,17 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     rootShares.cShare = 0;
     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     userp = smb_GetTran2User(vcp,p);
 
     thyper.HighPart = 0;
     thyper.LowPart = 0;
 
-    cm_HoldSCache(cm_data.rootSCachep);
-    cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
-    cm_ReleaseSCache(cm_data.rootSCachep);
+    rootScp = cm_RootSCachep(userp, &req);
+    cm_HoldSCache(rootScp);
+    cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
+    cm_ReleaseSCache(rootScp);
 
     cm_ReleaseUser(userp);
 
@@ -1676,7 +2065,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     else {
         nSharesRet = nShares;
     }
-    
+
     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
 
     /* now for the submounts */
@@ -1719,11 +2108,11 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
 
     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
         /* in case there are collisions with submounts, submounts have
-           higher priority */          
+           higher priority */
         for (j=0; j < nonrootShares; j++)
             if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
                 break;
-               
+
         if (j < nonrootShares) {
             nShares--; /* uncount */
             continue;
@@ -1773,7 +2162,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     cm_user_t   *userp;
     cm_req_t    req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     tp = p->parmsp + 1; /* skip over function number (always 1) */
 
@@ -1796,7 +2185,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
 
     infoLevel = *tp++;
     bufsize = *tp++;
-    
+
     totalParam = 6;
 
     if (infoLevel == 0)
@@ -1827,10 +2216,10 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     } else {
         userp = smb_GetTran2User(vcp, p);
         if (!userp) {
-            osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
+            osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
             return CM_ERROR_BADSMB;
-        }   
-        code = cm_NameI(cm_data.rootSCachep, shareName,
+        }
+        code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
                          userp, NULL, &req, &scp);
         if (code == 0) {
@@ -1938,7 +2327,7 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     }
 
     totalParams = 6;
-       
+
     /* infolevel 10 */
     totalData = sizeof(*info) +                /* info */
         MAX_COMPUTERNAME_LENGTH +      /* wki10_computername */
@@ -2058,7 +2447,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
 
     totalParams = 6;
 
-    totalData = 
+    totalData =
         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
 
@@ -2076,7 +2465,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
         cstrp = (char *) (info1 + 1);
         StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
 
-        info1->sv1_type = 
+        info1->sv1_type =
             SMB_SV_TYPE_SERVER |
             SMB_SV_TYPE_NT |
             SMB_SV_TYPE_SERVER_NT;
@@ -2116,10 +2505,11 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int dataCount;
     int firstPacket;
     long code = 0;
+    DWORD oldTime, newTime;
 
     /* We sometimes see 0 word count.  What to do? */
     if (*inp->wctp == 0) {
-        osi_Log0(smb_logp, "Transaction2 word count = 0"); 
+        osi_Log0(smb_logp, "Transaction2 word count = 0");
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
 
         smb_SetSMBDataLength(outp, 0);
@@ -2129,9 +2519,9 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     totalParms = smb_GetSMBParm(inp, 0);
     totalData = smb_GetSMBParm(inp, 1);
-        
+
     firstPacket = (inp->inCom == 0x32);
-        
+
     /* find the packet we're reassembling */
     lock_ObtainWrite(&smb_globalLock);
     asp = smb_FindTran2Packet(vcp, inp);
@@ -2139,7 +2529,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
     }
     lock_ReleaseWrite(&smb_globalLock);
-        
+
     /* now merge in this latest packet; start by looking up offsets */
     if (firstPacket) {
         parmDisp = dataDisp = 0;
@@ -2163,7 +2553,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
                  parmCount, dataCount);
-    }   
+    }
 
     /* now copy the parms and data */
     if ( asp->totalParms > 0 && parmCount != 0 )
@@ -2188,6 +2578,8 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
         lock_ReleaseWrite(&smb_globalLock);
 
+        oldTime = GetTickCount();
+
         /* now dispatch it */
         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
@@ -2207,6 +2599,46 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             smb_SendTran2Error(vcp, asp, outp, code);
         }
 
+        newTime = GetTickCount();
+        if (newTime - oldTime > 45000) {
+            smb_user_t *uidp;
+            smb_fid_t *fidp;
+            clientchar_t *treepath = NULL;  /* do not free */
+            clientchar_t *pathname = NULL;
+            cm_fid_t afid = {0,0,0,0,0};
+
+            uidp = smb_FindUID(vcp, asp->uid, 0);
+            smb_LookupTIDPath(vcp, asp->tid, &treepath);
+            fidp = smb_FindFID(vcp, inp->fid, 0);
+
+            if (fidp) {
+                lock_ObtainMutex(&fidp->mx);
+                if (fidp->NTopen_pathp)
+                    pathname = fidp->NTopen_pathp;
+                if (fidp->scp)
+                    afid = fidp->scp->fid;
+            } else {
+                if (inp->stringsp->wdata)
+                    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)",
+                      myCrt_2Dispatch(asp->opcode), newTime - oldTime,
+                      asp->uid, uidp ? uidp->unp->name : NULL,
+                      asp->pid, asp->mid, asp->tid,
+                      treepath,
+                      pathname,
+                      afid.cell, afid.volume, afid.vnode, afid.unique);
+
+            if (fidp)
+                lock_ReleaseMutex(&fidp->mx);
+
+            if (uidp)
+                smb_ReleaseUID(uidp);
+            if (fidp)
+                smb_ReleaseFID(fidp);
+        }
+
         /* free the input tran 2 packet */
         smb_FreeTran2Packet(asp);
     }
@@ -2233,7 +2665,6 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     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;
@@ -2248,11 +2679,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     clientchar_t *tidPathp;
     cm_req_t req;
     int created = 0;
+    BOOL is_rpc = FALSE;
+    BOOL is_ipc = FALSE;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
-        
+
     extraInfo = (p->parmsp[0] & 1);    /* return extra info */
     returnEALength = (p->parmsp[0] & 8);       /* return extended attr length */
 
@@ -2264,30 +2697,51 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
     attributes = p->parmsp[3];
     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
-        
-    /* compute initial mode bits based on read-only flag in attributes */
-    initialModeBits = 0666;
-    if (attributes & SMB_ATTR_READONLY) 
-        initialModeBits &= ~0222;
-        
+
     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
                                   SMB_STRF_ANSIPATH);
-    
+
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
 
+    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+    if (code == CM_ERROR_TIDIPC) {
+       is_ipc = TRUE;
+        osi_Log0(smb_logp, "Tran2Open received IPC TID");
+    }
+
     spacep = cm_GetSpace();
+    /* smb_StripLastComponent will strip "::$DATA" if present */
     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
-    if (lastNamep && 
-        (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
-         cm_ClientStrCmpI(lastNamep,  _C("\\srvsvc")) == 0 ||
-         cm_ClientStrCmpI(lastNamep,  _C("\\wkssvc")) == 0 ||
-         cm_ClientStrCmpI(lastNamep,  _C("\\ipc$")) == 0)) {
+    if (lastNamep &&
+
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
+        (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+
+        /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
+        (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
+
+       unsigned short file_type = 0;
+       unsigned short device_state = 0;
+
         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-        smb_SetupIoctlFid(fidp, spacep);
+
+       if (is_rpc) {
+           code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
+           osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
+                     fidp->fid, code);
+           if (code) {
+               smb_ReleaseFID(fidp);
+               smb_FreeTran2Packet(outp);
+               osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
+               return code;
+           }
+       } else {
+           smb_SetupIoctlFid(fidp, spacep);
+           osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
+       }
 
         /* copy out remainder of the parms */
         parmSlot = 0;
@@ -2295,13 +2749,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         if (extraInfo) {
             outp->parmsp[parmSlot++] = 0;       /* attrs */
             outp->parmsp[parmSlot++] = 0;       /* mod time */
-            outp->parmsp[parmSlot++] = 0; 
+            outp->parmsp[parmSlot++] = 0;
             outp->parmsp[parmSlot++] = 0;       /* len */
             outp->parmsp[parmSlot++] = 0x7fff;
             outp->parmsp[parmSlot++] = openMode;
-            outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
-            outp->parmsp[parmSlot++] = 0;       /* IPC junk */
-        }   
+            outp->parmsp[parmSlot++] = file_type;
+            outp->parmsp[parmSlot++] = device_state;
+        }
         /* and the final "always present" stuff */
         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
         /* next write out the "unique" ID */
@@ -2311,13 +2765,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         if (returnEALength) {
             outp->parmsp[parmSlot++] = 0;
             outp->parmsp[parmSlot++] = 0;
-        }       
-                
+        }
+
         outp->totalData = 0;
         outp->totalParms = parmSlot * 2;
-                
+
         smb_SendTran2Packet(vcp, outp, op);
-                
+
         smb_FreeTran2Packet(outp);
 
         /* and clean up fid reference */
@@ -2325,6 +2779,30 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         return 0;
     }
 
+#ifndef DFS_SUPPORT
+    if (is_ipc) {
+        osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
+       smb_FreeTran2Packet(outp);
+       return CM_ERROR_BADFD;
+    }
+#endif
+
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
+#endif
+        smb_FreeTran2Packet(outp);
+        return CM_ERROR_BADNTFILENAME;
+    }
+
 #ifdef DEBUG_VERBOSE
     {
         char *hexp, *asciip;
@@ -2332,7 +2810,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         hexp = osi_HexifyString( asciip );
         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
         free(hexp);
-    }       
+    }
 #endif
 
     userp = smb_GetTran2User(vcp, p);
@@ -2343,29 +2821,17 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         return CM_ERROR_BADSMB;
     }
 
-    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
-    if (code == CM_ERROR_TIDIPC) {
-        /* Attempt to use a TID allocated for IPC.  The client
-         * is probably looking for DCE RPC end points which we
-         * don't support OR it could be looking to make a DFS
-         * referral request. 
-         */
-        osi_Log0(smb_logp, "Tran2Open received IPC TID");
-#ifndef DFS_SUPPORT
-        cm_ReleaseUser(userp);
-        smb_FreeTran2Packet(outp);
-        return CM_ERROR_NOSUCHPATH;
-#endif
-    }
-
     dscp = NULL;
-    code = cm_NameI(cm_data.rootSCachep, pathp,
+    code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &req, &scp);
     if (code != 0) {
-        code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
-                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                         userp, tidPathp, &req, &dscp);
+        if (code == CM_ERROR_NOSUCHFILE ||
+            code == CM_ERROR_NOSUCHPATH ||
+            code == CM_ERROR_BPLUS_NOMATCH)
+            code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
+                            CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                            userp, tidPathp, &req, &dscp);
         cm_FreeSpace(spacep);
 
         if (code) {
@@ -2373,7 +2839,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             smb_FreeTran2Packet(outp);
             return code;
         }
-        
+
 #ifdef DFS_SUPPORT
         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
@@ -2384,7 +2850,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
 
@@ -2392,9 +2858,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
          * and truncate the file if we find it, otherwise we create the
          * file.
          */
-        if (!lastNamep) 
+        if (!lastNamep)
             lastNamep = pathp;
-        else 
+        else
             lastNamep++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                          &req, &scp);
@@ -2405,6 +2871,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             return code;
         }
     } else {
+        /* macintosh is expensive to program for it */
+        cm_FreeSpace(spacep);
+
 #ifdef DFS_SUPPORT
         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
@@ -2414,21 +2883,18 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
-
-        /* macintosh is expensive to program for it */
-        cm_FreeSpace(spacep);
     }
-        
+
     /* if we get here, if code is 0, the file exists and is represented by
      * scp.  Otherwise, we have to create it.
      */
     if (code == 0) {
         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
         if (code) {
-            if (dscp) 
+            if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -2438,7 +2904,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
         if (excl) {
             /* oops, file shouldn't be there */
-            if (dscp) 
+            if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -2452,13 +2918,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             setAttr.length.HighPart = 0;
             code = cm_SetAttr(scp, &setAttr, userp, &req);
             openAction = 3;    /* truncated existing file */
-        }   
-        else 
+        }
+        else
             openAction = 1;    /* found existing file */
     }
     else if (!(openFun & 0x10)) {
         /* don't create if not found */
-        if (dscp) 
+        if (dscp)
             cm_ReleaseSCache(dscp);
         osi_assertx(scp == NULL, "null cm_scache_t");
         cm_ReleaseUser(userp);
@@ -2469,14 +2935,16 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
         openAction = 2;        /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
-        smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
+        cm_UnixTimeFromSearchTime(&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,
-                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
                                  dscp, lastNamep, NULL, TRUE);
        } else if (!excl && code == CM_ERROR_EXISTS) {
             /* not an exclusive create, and someone else tried
@@ -2494,24 +2962,24 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
                     setAttr.length.HighPart = 0;
                     code = cm_SetAttr(scp, &setAttr, userp,
                                        &req);
-                }   
+                }
             }  /* lookup succeeded */
         }
     }
-        
+
     /* we don't need this any longer */
-    if (dscp) 
+    if (dscp)
         cm_ReleaseSCache(dscp);
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) 
+        if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
         return code;
     }
-        
+
     /* make sure we're about to open a file */
     if (scp->fileType != CM_SCACHETYPE_FILE) {
         code = 0;
@@ -2540,7 +3008,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     /* 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);
     /* save a pointer to the vnode */
@@ -2549,12 +3017,12 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
     lock_ReleaseWrite(&scp->rw);
-    
+
     /* and the user */
     fidp->userp = userp;
-        
+
     /* compute open mode */
-    if (openMode != 1) 
+    if (openMode != 1)
        fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
@@ -2566,7 +3034,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     lock_ReleaseMutex(&fidp->mx);
 
     smb_ReleaseFID(fidp);
-        
+
     cm_Open(scp, 0, userp);
 
     /* copy out remainder of the parms */
@@ -2575,7 +3043,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     lock_ObtainRead(&scp->rw);
     if (extraInfo) {
         outp->parmsp[parmSlot++] = smb_Attributes(scp);
-        smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+        cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
@@ -2583,17 +3051,17 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         outp->parmsp[parmSlot++] = openMode;
         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
-    }   
+    }
     /* and the final "always present" stuff */
     outp->parmsp[parmSlot++] = openAction;
     /* next write out the "unique" ID */
-    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
-    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
-    outp->parmsp[parmSlot++] = 0; 
+    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
+    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
+    outp->parmsp[parmSlot++] = 0;
     if (returnEALength) {
-        outp->parmsp[parmSlot++] = 0; 
-        outp->parmsp[parmSlot++] = 0; 
-    }   
+        outp->parmsp[parmSlot++] = 0;
+        outp->parmsp[parmSlot++] = 0;
+    }
     lock_ReleaseRead(&scp->rw);
     outp->totalData = 0;               /* total # of data bytes */
     outp->totalParms = parmSlot * 2;   /* shorts are two bytes */
@@ -2605,7 +3073,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     cm_ReleaseUser(userp);
     /* leave scp held since we put it in fidp->scp */
     return 0;
-}   
+}
 
 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
@@ -2615,7 +3083,7 @@ long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     infolevel = p->parmsp[0];
     fid = p->parmsp[1];
     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
-    
+
     return CM_ERROR_BAD_LEVEL;
 }
 
@@ -2626,13 +3094,13 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
     smb_tran2QFSInfo_t qi;
     int responseSize;
     size_t sz = 0;
-        
+
     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
 
     switch (p->parmsp[0]) {
-    case SMB_INFO_ALLOCATION: 
+    case SMB_INFO_ALLOCATION:
         /* alloc info */
-       responseSize = sizeof(qi.u.allocInfo); 
+       responseSize = sizeof(qi.u.allocInfo);
 
         qi.u.allocInfo.FSID = 0;
         qi.u.allocInfo.sectorsPerAllocUnit = 1;
@@ -2641,10 +3109,10 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.allocInfo.bytesPerSector = 1024;
         break;
 
-    case SMB_INFO_VOLUME: 
+    case SMB_INFO_VOLUME:
         /* volume info */
         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
-        qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
+        qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
 
         /* we're supposed to pad it out with zeroes to the end */
         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
@@ -2653,7 +3121,7 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
         break;
 
-    case SMB_QUERY_FS_VOLUME_INFO: 
+    case SMB_QUERY_FS_VOLUME_INFO:
         /* FS volume info */
        responseSize = sizeof(qi.u.FSvolumeInfo);
 
@@ -2663,13 +3131,14 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         }
 
         qi.u.FSvolumeInfo.vsn = 1234;
-        qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
+        qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
+        memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
         break;
 
-    case SMB_QUERY_FS_SIZE_INFO: 
+    case SMB_QUERY_FS_SIZE_INFO:
         /* FS size info */
-       responseSize = sizeof(qi.u.FSsizeInfo); 
+       responseSize = sizeof(qi.u.FSsizeInfo);
 
         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
        qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
@@ -2679,20 +3148,21 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.FSsizeInfo.bytesPerSector = 1024;
         break;
 
-    case SMB_QUERY_FS_DEVICE_INFO: 
+    case SMB_QUERY_FS_DEVICE_INFO:
         /* FS device info */
-       responseSize = sizeof(qi.u.FSdeviceInfo); 
+       responseSize = sizeof(qi.u.FSdeviceInfo);
 
         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
         break;
 
-    case SMB_QUERY_FS_ATTRIBUTE_INFO: 
+    case SMB_QUERY_FS_ATTRIBUTE_INFO:
         /* FS attribute info */
 
         /* attributes, defined in WINNT.H:
          *     FILE_CASE_SENSITIVE_SEARCH      0x1
          *     FILE_CASE_PRESERVED_NAMES       0x2
+         *      FILE_UNICODE_ON_DISK            0x4
         *      FILE_VOLUME_QUOTAS              0x10
          *     <no name defined>               0x4000
          *        If bit 0x4000 is not set, Windows 95 thinks
@@ -2702,15 +3172,10 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.FSattributeInfo.attributes = 0x4003;
         /* The maxCompLength is supposed to be in bytes */
 #ifdef SMB_UNICODE
-        if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
-            qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
-        else {
-#endif
-        qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
-#ifdef SMB_UNICODE
-        }
+        qi.u.FSattributeInfo.attributes |= 0x04;
 #endif
-        smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, 0);
+        qi.u.FSattributeInfo.maxCompLength = 255;
+        smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
         qi.u.FSattributeInfo.FSnameLength = sz;
 
        responseSize =
@@ -2723,12 +3188,12 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
 
     case SMB_INFO_UNIX:        /* CIFS Unix Info */
     case SMB_INFO_MACOS:       /* Mac FS Info */
-    default: 
+    default:
        return CM_ERROR_BADOP;
-    }   
-        
+    }
+
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
-        
+
     /* copy out return data, and set corresponding sizes */
     outp->totalParms = 0;
     outp->totalData = responseSize;
@@ -2752,18 +3217,22 @@ struct smb_ShortNameRock {
     unsigned int vnode;
     clientchar_t *shortName;
     size_t shortNameLen;
-};      
+};
 
 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
                          osi_hyper_t *offp)
-{       
+{
     struct smb_ShortNameRock *rockp;
     normchar_t normName[MAX_PATH];
     clientchar_t *shortNameEnd;
 
     rockp = vrockp;
 
-    cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
+    if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
 
     /* compare both names and vnodes, though probably just comparing vnodes
      * would be safe enough.
@@ -2792,13 +3261,14 @@ long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
     osi_hyper_t thyper;
 
     spacep = cm_GetSpace();
+    /* smb_StripLastComponent will strip "::$DATA" if present */
     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+    code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
                     caseFold, userp, tidPathp,
                     reqp, &dscp);
     cm_FreeSpace(spacep);
-    if (code) 
+    if (code)
         return code;
 
 #ifdef DFS_SUPPORT
@@ -2848,7 +3318,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     cm_user_t *userp;
     cm_space_t *spacep;
     cm_scache_t *scp, *dscp;
-    int scp_mx_held = 0;
+    int scp_rw_held = 0;
     int delonclose = 0;
     long code = 0;
     clientchar_t *pathp;
@@ -2856,14 +3326,14 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     clientchar_t *lastComp;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     infoLevel = p->parmsp[0];
-    if (infoLevel == SMB_INFO_IS_NAME_VALID) 
+    if (infoLevel == SMB_INFO_IS_NAME_VALID)
         responseSize = 0;
-    else if (infoLevel == SMB_INFO_STANDARD) 
+    else if (infoLevel == SMB_INFO_STANDARD)
         responseSize = sizeof(qpi.u.QPstandardInfo);
-    else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
+    else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
         responseSize = sizeof(qpi.u.QPeaSizeInfo);
     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
         responseSize = sizeof(qpi.u.QPfileBasicInfo);
@@ -2871,21 +3341,24 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        responseSize = sizeof(qpi.u.QPfileStandardInfo);
     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
         responseSize = sizeof(qpi.u.QPfileEaInfo);
-    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
         responseSize = sizeof(qpi.u.QPfileNameInfo);
-    else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
         responseSize = sizeof(qpi.u.QPfileAllInfo);
-    else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
+        responseSize = sizeof(qpi.u.QPfileStreamInfo);
     else {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         return 0;
     }
+    memset(&qpi, 0, sizeof(qpi));
 
     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
-    osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
+    osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
               osi_LogSaveClientString(smb_logp, pathp));
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
@@ -2894,8 +3367,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->totalParms = 2;
     else
         outp->totalParms = 0;
-    outp->totalData = responseSize;
-        
+
     /* now, if we're at infoLevel 6, we're only being asked to check
      * the syntax, so we just OK things now.  In particular, we're *not*
      * being asked to verify anything about the state of any parent dirs.
@@ -2904,8 +3376,8 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         smb_SendTran2Packet(vcp, outp, opx);
         smb_FreeTran2Packet(outp);
         return 0;
-    }   
-        
+    }
+
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
@@ -2915,12 +3387,16 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if(code) {
+        osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
         cm_ReleaseUser(userp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
         smb_FreeTran2Packet(outp);
         return 0;
     }
 
+    osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
+              osi_LogSaveClientString(smb_logp, tidPathp));
+
     /*
      * XXX Strange hack XXX
      *
@@ -2937,12 +3413,13 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      */
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
         spacep = cm_GetSpace();
+        /* smb_StripLastComponent will strip "::$DATA" if present */
         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
-                code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+                code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
@@ -2955,7 +3432,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
-                            code = CM_ERROR_BADSHARENAME;
+                            code = CM_ERROR_NOSUCHPATH;
                     } else
 #endif /* DFS_SUPPORT */
                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
@@ -2985,9 +3462,14 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         cm_FreeSpace(spacep);
     }
 
-    /* now do namei and stat, and copy out the info */
-    code = cm_NameI(cm_data.rootSCachep, pathp,
-                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+    if (code == 0 ||
+        code == CM_ERROR_NOSUCHFILE ||
+        code == CM_ERROR_NOSUCHPATH ||
+        code == CM_ERROR_BPLUS_NOMATCH) {
+        /* now do namei and stat, and copy out the info */
+        code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
+                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+    }
 
     if (code) {
         cm_ReleaseUser(userp);
@@ -3004,7 +3486,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if ( WANTS_DFS_PATHNAMES(p) || pnc )
             code = CM_ERROR_PATH_NOT_COVERED;
         else
-            code = CM_ERROR_BADSHARENAME;
+            code = CM_ERROR_NOSUCHPATH;
         smb_SendTran2Error(vcp, p, opx, code);
         smb_FreeTran2Packet(outp);
         return 0;
@@ -3012,14 +3494,16 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #endif /* DFS_SUPPORT */
 
     lock_ObtainWrite(&scp->rw);
-    scp_mx_held = 1;
+    scp_rw_held = 2;
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) goto done;
+    if (code)
+        goto done;
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        
+
     lock_ConvertWToR(&scp->rw);
+    scp_rw_held = 1;
 
     len = 0;
 
@@ -3035,19 +3519,17 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             goto done;
         }
 
-        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
+        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
        qpi.u.QPfileAltNameInfo.fileNameLength = len;
-
-        goto done;
+        responseSize = sizeof(unsigned long) + len;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
+        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
        qpi.u.QPfileNameInfo.fileNameLength = len;
-
-        goto done;
+        responseSize = sizeof(unsigned long) + len;
     }
     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
-        smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+        cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
        qpi.u.QPstandardInfo.creationDateTime = dosTime;
        qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
        qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
@@ -3058,7 +3540,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPstandardInfo.eaSize = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         qpi.u.QPfileBasicInfo.creationTime = ft;
         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
@@ -3068,20 +3550,22 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPfileBasicInfo.reserved = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
-       smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
+       smb_fid_t * fidp;
+
+        lock_ReleaseRead(&scp->rw);
+        scp_rw_held = 0;
+        fidp = smb_FindFIDByScache(vcp, scp);
 
         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
-        qpi.u.QPfileStandardInfo.directory = 
+        qpi.u.QPfileStandardInfo.directory =
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         qpi.u.QPfileStandardInfo.reserved = 0;
 
        if (fidp) {
-           lock_ReleaseRead(&scp->rw);
-           scp_mx_held = 0;
            lock_ObtainMutex(&fidp->mx);
            delonclose = fidp->flags & SMB_FID_DELONCLOSE;
            lock_ReleaseMutex(&fidp->mx);
@@ -3093,7 +3577,13 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileEaInfo.eaSize = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+       smb_fid_t * fidp;
+
+        lock_ReleaseRead(&scp->rw);
+        scp_rw_held = 0;
+        fidp = smb_FindFIDByScache(vcp, scp);
+
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         qpi.u.QPfileAllInfo.creationTime = ft;
         qpi.u.QPfileAllInfo.lastAccessTime = ft;
         qpi.u.QPfileAllInfo.lastWriteTime = ft;
@@ -3104,29 +3594,69 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileAllInfo.endOfFile = scp->length;
         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
         qpi.u.QPfileAllInfo.deletePending = 0;
-        qpi.u.QPfileAllInfo.directory = 
+        qpi.u.QPfileAllInfo.directory =
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
-       qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
-       qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
+       qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
+       qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.unique;
        qpi.u.QPfileAllInfo.eaSize = 0;
-       qpi.u.QPfileAllInfo.accessFlags = 0;
-       qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
-       qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
+        qpi.u.QPfileAllInfo.accessFlags = 0;
+        if (fidp) {
+           lock_ObtainMutex(&fidp->mx);
+            if (fidp->flags & SMB_FID_OPENDELETE)
+                qpi.u.QPfileAllInfo.accessFlags |= DELETE;
+            if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
+                qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
+            if (fidp->flags & SMB_FID_OPENWRITE)
+                qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
+            if (fidp->flags & SMB_FID_DELONCLOSE)
+                qpi.u.QPfileAllInfo.deletePending = 1;
+           lock_ReleaseMutex(&fidp->mx);
+           smb_ReleaseFID(fidp);
+        }
+       qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
+       qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.volume;
        qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
        qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
        qpi.u.QPfileAllInfo.mode = 0;
        qpi.u.QPfileAllInfo.alignmentRequirement = 0;
 
-        smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
+        smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
        qpi.u.QPfileAllInfo.fileNameLength = len;
+        responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
+    }
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
+        size_t len = 0;
+        /* For now we have no streams */
+        qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
+        if (scp->fileType == CM_SCACHETYPE_FILE) {
+            qpi.u.QPfileStreamInfo.streamSize = scp->length;
+            qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
+            smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
+            qpi.u.QPfileStreamInfo.streamNameLength = len;
+            responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
+        } else {
+            qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
+            qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
+            smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
+            qpi.u.QPfileStreamInfo.streamNameLength = 0;
+            responseSize = 0;
+        }
     }
+    outp->totalData = responseSize;
 
     /* send and free the packets */
   done:
-    if (scp_mx_held)
+    switch (scp_rw_held) {
+    case 1:
        lock_ReleaseRead(&scp->rw);
+        break;
+    case 2:
+        lock_ReleaseWrite(&scp->rw);
+        break;
+    }
+    scp_rw_held = 0;
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     if (code == 0) {
@@ -3148,7 +3678,6 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     return CM_ERROR_BADOP;
 #else
     long code = 0;
-    smb_fid_t *fidp;
     unsigned short infoLevel;
     clientchar_t * pathp;
     smb_tran2Packet_t *outp;
@@ -3160,16 +3689,16 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     clientchar_t *tidPathp;
     clientchar_t *lastComp;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     infoLevel = p->parmsp[0];
     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
-    if (infoLevel != SMB_INFO_STANDARD && 
+    if (infoLevel != SMB_INFO_STANDARD &&
        infoLevel != SMB_INFO_QUERY_EA_SIZE &&
        infoLevel != SMB_INFO_QUERY_ALL_EAS) {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, 
+        smb_SendTran2Error(vcp, p, opx,
                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
         return 0;
     }
@@ -3184,14 +3713,14 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
-    }   
+    }
 
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if (code == CM_ERROR_TIDIPC) {
         /* Attempt to use a TID allocated for IPC.  The client
          * is probably looking for DCE RPC end points which we
          * don't support OR it could be looking to make a DFS
-         * referral request. 
+         * referral request.
          */
         osi_Log0(smb_logp, "Tran2Open received IPC TID");
         cm_ReleaseUser(userp);
@@ -3214,12 +3743,13 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     */
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
         spacep = cm_GetSpace();
+        /* smb_StripLastComponent will strip "::$DATA" if present */
         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
-                code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+                code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
@@ -3232,7 +3762,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
-                            code = CM_ERROR_BADSHARENAME;
+                            code = CM_ERROR_NOSUCHPATH;
                     } else
 #endif /* DFS_SUPPORT */
                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
@@ -3261,33 +3791,20 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         cm_FreeSpace(spacep);
     }
 
-    /* now do namei and stat, and copy out the info */
-    code = cm_NameI(cm_data.rootSCachep, pathp,
-                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
-    if (code) {
-        cm_ReleaseUser(userp);
-        smb_SendTran2Error(vcp, p, opx, code);
-        return 0;
-    }
-
-    fidp = smb_FindFIDByScache(vcp, scp);
-    if (!fidp) {
-        cm_ReleaseSCache(scp);
-        cm_ReleaseUser(userp);
-       smb_SendTran2Error(vcp, p, opx, code);
-        return 0;
+    if (code == 0 ||
+        code == CM_ERROR_NOSUCHFILE ||
+        code == CM_ERROR_NOSUCHPATH ||
+        code == CM_ERROR_BPLUS_NOMATCH) {
+        /* now do namei and stat, and copy out the info */
+        code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
+                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
     }
 
-    lock_ObtainMutex(&fidp->mx);
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       lock_ReleaseMutex(&fidp->mx);
-        cm_ReleaseSCache(scp);
-        smb_ReleaseFID(fidp);
+    if (code) {
         cm_ReleaseUser(userp);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
+        smb_SendTran2Error(vcp, p, opx, code);
         return 0;
     }
-    lock_ReleaseMutex(&fidp->mx);
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
 
@@ -3311,29 +3828,24 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         }
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-       lock_ReleaseWrite(&scp->rw);
-       lock_ObtainMutex(&fidp->mx);
-       lock_ObtainRead(&scp->rw);
-
         /* prepare for setattr call */
         attr.mask = CM_ATTRMASK_LENGTH;
         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
         attr.length.HighPart = 0;
 
        if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
-           smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
+           cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
-            fidp->flags |= SMB_FID_MTIMESETDONE;
         }
-               
+
         if (spi->u.QPstandardInfo.attributes != 0) {
-            if ((scp->unixModeBits & 0222)
+            if ((scp->unixModeBits & 0200)
                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
                 /* make a writable file read-only */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
                 attr.unixModeBits = scp->unixModeBits & ~0222;
             }
-            else if ((scp->unixModeBits & 0222) == 0
+            else if ((scp->unixModeBits & 0200) == 0
                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
                 /* make a read-only file writable */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
@@ -3341,26 +3853,24 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
             }
         }
         lock_ReleaseRead(&scp->rw);
-       lock_ReleaseMutex(&fidp->mx);
 
         /* call setattr */
         if (attr.mask)
             code = cm_SetAttr(scp, &attr, userp, &req);
         else
             code = 0;
-    }               
+    }
     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
        /* we don't support EAs */
        code = CM_ERROR_EAS_NOT_SUPPORTED;
-    }       
+    }
 
   done:
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
-    smb_ReleaseFID(fidp);
-    if (code == 0) 
+    if (code == 0)
         smb_SendTran2Packet(vcp, outp, opx);
-    else 
+    else
         smb_SendTran2Error(vcp, p, opx, code);
     smb_FreeTran2Packet(outp);
 
@@ -3386,40 +3896,48 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int  readlock = 0;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = p->parmsp[0];
     fidp = smb_FindFID(vcp, fid, 0);
 
     if (fidp == NULL) {
+        osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
         return 0;
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return 0;
     }
+    lock_ReleaseMutex(&fidp->mx);
 
     infoLevel = p->parmsp[1];
-    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
+    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
         responseSize = sizeof(qfi.u.QFbasicInfo);
-    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
         responseSize = sizeof(qfi.u.QFstandardInfo);
     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
         responseSize = sizeof(qfi.u.QFeaInfo);
-    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
         responseSize = sizeof(qfi.u.QFfileNameInfo);
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
+        responseSize = sizeof(qfi.u.QFfileStreamInfo);
     else {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
         return 0;
     }
     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
+    memset(&qfi, 0, sizeof(qfi));
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
 
@@ -3427,14 +3945,13 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->totalParms = 2;
     else
         outp->totalParms = 0;
-    outp->totalData = responseSize;
 
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
        osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
-    }   
+    }
 
     lock_ObtainMutex(&fidp->mx);
     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
@@ -3445,7 +3962,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     lock_ObtainWrite(&scp->rw);
     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);
@@ -3457,7 +3974,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * Marshall the output data.
      */
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         qfi.u.QFbasicInfo.creationTime = ft;
         qfi.u.QFbasicInfo.lastAccessTime = ft;
         qfi.u.QFbasicInfo.lastWriteTime = ft;
@@ -3470,7 +3987,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qfi.u.QFstandardInfo.endOfFile = scp->length;
         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
-        qfi.u.QFstandardInfo.directory = 
+        qfi.u.QFstandardInfo.directory =
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
@@ -3491,10 +4008,29 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             name = _C("\\");   /* probably can't happen */
        lock_ReleaseMutex(&fidp->mx);
 
-        smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
-        outp->totalData = len + 4;     /* this is actually what we want to return */
+        smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
+        responseSize = len + 4;        /* this is actually what we want to return */
         qfi.u.QFfileNameInfo.fileNameLength = len;
     }
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
+        size_t len = 0;
+
+        if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+            scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+            scp->fileType == CM_SCACHETYPE_INVALID) {
+            /* Do not return the alternate streams for directories */
+            responseSize = 0;
+        } else {
+            /* For now we have no alternate streams */
+            qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
+            qfi.u.QFfileStreamInfo.streamSize = scp->length;
+            qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
+            smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
+            qfi.u.QFfileStreamInfo.streamNameLength = len;
+            responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
+        }
+    }
+    outp->totalData = responseSize;
 
     /* send and free the packets */
   done:
@@ -3514,7 +4050,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     smb_FreeTran2Packet(outp);
 
     return 0;
-}       
+}
 
 
 /* TRANS2_SET_FILE_INFORMATION */
@@ -3529,27 +4065,22 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     cm_scache_t *scp = NULL;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = p->parmsp[0];
     fidp = smb_FindFID(vcp, fid, 0);
 
     if (fidp == NULL) {
+        osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
         return 0;
     }
 
-    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
-        smb_CloseFID(vcp, fidp, NULL, 0);
-        smb_ReleaseFID(fidp);
-        return 0;
-    }
-
     infoLevel = p->parmsp[1];
     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
@@ -3557,19 +4088,27 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }
 
     lock_ObtainMutex(&fidp->mx);
-    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
+    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
        !(fidp->flags & SMB_FID_OPENDELETE)) {
-       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
                  fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
         return 0;
     }
-    if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
+    if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
         infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
          && !(fidp->flags & SMB_FID_OPENWRITE)) {
-       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
                  fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
@@ -3592,7 +4131,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
-    }   
+    }
 
     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
         FILETIME lastMod;
@@ -3624,26 +4163,26 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         attr.mask = 0;
 
         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
-        /* when called as result of move a b, lastMod is (-1, -1). 
+        /* when called as result of move a b, lastMod is (-1, -1).
          * If the check for -1 is not present, timestamp
          * of the resulting file will be 1969 (-1)
          */
-        if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
+        if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
-            smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
+            cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
             fidp->flags |= SMB_FID_MTIMESETDONE;
         }
-               
+
         attribute = sfi->u.QFbasicInfo.attributes;
         if (attribute != 0) {
-            if ((scp->unixModeBits & 0222)
+            if ((scp->unixModeBits & 0200)
                  && (attribute & SMB_ATTR_READONLY) != 0) {
                 /* make a writable file read-only */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
                 attr.unixModeBits = scp->unixModeBits & ~0222;
             }
-            else if ((scp->unixModeBits & 0222) == 0
+            else if ((scp->unixModeBits & 0200) == 0
                       && (attribute & SMB_ATTR_READONLY) == 0) {
                 /* make a read-only file writable */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
@@ -3661,7 +4200,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }
     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
        int delflag = *((char *)(p->datap));
-       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
                 delflag, fidp, scp);
         if (*((char *)(p->datap))) {   /* File is Deleted */
             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
@@ -3671,17 +4210,17 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 fidp->flags |= SMB_FID_DELONCLOSE;
                lock_ReleaseMutex(&fidp->mx);
            } else {
-               osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
+               osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
                         fidp, scp, code);
            }
-       }               
-        else {  
+       }
+        else {
             code = 0;
            lock_ObtainMutex(&fidp->mx);
             fidp->flags &= ~SMB_FID_DELONCLOSE;
            lock_ReleaseMutex(&fidp->mx);
         }
-    }       
+    }
     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
             infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
@@ -3691,15 +4230,15 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         attr.length.LowPart = size.LowPart;
         attr.length.HighPart = size.HighPart;
         code = cm_SetAttr(scp, &attr, userp, &req);
-    }       
+    }
 
   done:
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
-    if (code == 0) 
+    if (code == 0)
         smb_SendTran2Packet(vcp, outp, opx);
-    else 
+    else
         smb_SendTran2Error(vcp, p, opx, code);
     smb_FreeTran2Packet(outp);
 
@@ -3707,7 +4246,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
 }
 
 /* TRANS2_FSCTL */
-long 
+long
 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
@@ -3715,7 +4254,7 @@ smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 }
 
 /* TRANS2_IOCTL2 */
-long 
+long
 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
@@ -3723,7 +4262,7 @@ smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 }
 
 /* TRANS2_FIND_NOTIFY_FIRST */
-long 
+long
 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
@@ -3731,7 +4270,7 @@ smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
 }
 
 /* TRANS2_FIND_NOTIFY_NEXT */
-long 
+long
 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
@@ -3739,7 +4278,7 @@ smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 }
 
 /* TRANS2_CREATE_DIRECTORY */
-long 
+long
 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
@@ -3747,7 +4286,7 @@ smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
 }
 
 /* TRANS2_SESSION_SETUP */
-long 
+long
 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
@@ -3765,7 +4304,7 @@ struct smb_v2_referral {
 };
 
 /* TRANS2_GET_DFS_REFERRAL */
-long 
+long
 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     /* This is a UNICODE only request (bit15 of Flags2) */
@@ -3791,14 +4330,14 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int i, nbnLen, reqLen, refLen;
     int idx;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     maxReferralLevel = p->parmsp[0];
 
     GetCPInfo(CP_ACP, &CodePageInfo);
     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
 
-    osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]", 
+    osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
 
     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
@@ -3806,7 +4345,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
-        requestFileName[nbnLen+1] == '\\') 
+        requestFileName[nbnLen+1] == '\\')
     {
         int found = 0;
 
@@ -3821,20 +4360,26 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
                 code = CM_ERROR_BADSMB;
                 goto done;
-            }   
-            
-            /* 
-             * We have a requested path.  Check to see if it is something 
+            }
+
+            /*
+             * We have a requested path.  Check to see if it is something
              * we know about.
-                        *
-                        * But be careful because the name that we might be searching
-                        * for might be a known name with the final character stripped
-                        * off.  If we 
+             *
+             * But be careful because the name that we might be searching
+             * for might be a known name with the final character stripped
+             * off.
              */
-            code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
+            code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
                             userp, NULL, &req, &scp);
-            if (code == 0) {
+            if (code == 0 ||
+                code == CM_ERROR_ALLDOWN ||
+                code == CM_ERROR_ALLBUSY ||
+                code == CM_ERROR_ALLOFFLINE ||
+                code == CM_ERROR_NOSUCHCELL ||
+                code == CM_ERROR_NOSUCHVOLUME ||
+                code == CM_ERROR_NOACCESS) {
                 /* Yes it is. */
                 found = 1;
                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
@@ -3843,7 +4388,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 clientchar_t temp[1024];
                 clientchar_t pathName[1024];
                 clientchar_t *lastComponent;
-                /* 
+                /*
                  * we have a msdfs link somewhere in the path
                  * we should figure out where in the path the link is.
                  * and return it.
@@ -3861,9 +4406,10 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         cm_ReleaseSCache(scp);
                         scp = 0;
                     }
+                    /* smb_StripLastComponent will strip "::$DATA" if present */
                     smb_StripLastComponent(pathName, &lastComponent, temp);
 
-                    code = cm_NameI(cm_data.rootSCachep, pathName,
+                    code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                     userp, NULL, &req, &dscp);
                     if (code == 0) {
@@ -3895,9 +4441,9 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     *q = *p;
                 }
                 *q = '\0';
-                
+
                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
-                    code = cm_NameI(cm_data.rootSCachep, _C(""), 
+                    code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                                     userp, p, &req, &scp);
                     free(p);
@@ -3911,7 +4457,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 }
             }
         }
-        
+
         if (found)
         {
             USHORT * sp;
@@ -3925,7 +4471,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             sp[idx++] = 0x03;     /* flags */
 #ifdef DFS_VERSION_1
             sp[idx++] = 1;        /* Version Number */
-            sp[idx++] = refLen + 4;  /* Referral Size */ 
+            sp[idx++] = refLen + 4;  /* Referral Size */
             sp[idx++] = 1;        /* Type = SMB Server */
             sp[idx++] = 0;        /* Do not strip path consumed */
             for ( i=0;i<=refLen; i++ )
@@ -3945,11 +4491,13 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             for ( i=0;i<=refLen; i++ )
                 sp[i+idx] = referralPath[i];
 #endif
-        } 
+        } else {
+            code = CM_ERROR_NOSUCHPATH;
+        }
     } else {
         code = CM_ERROR_NOSUCHPATH;
     }
-         
+
   done:
     if (dscp)
         cm_ReleaseSCache(dscp);
@@ -3957,29 +4505,29 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         cm_ReleaseSCache(scp);
     if (userp)
         cm_ReleaseUser(userp);
-    if (code == 0) 
+    if (code == 0)
         smb_SendTran2Packet(vcp, outp, op);
-    else 
+    else
         smb_SendTran2Error(vcp, p, op, code);
     if (outp)
         smb_FreeTran2Packet(outp);
+
     return 0;
 #else /* DFS_SUPPORT */
-    osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
+    osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
     return CM_ERROR_NOSUCHDEVICE;
 #endif /* DFS_SUPPORT */
 }
 
 /* TRANS2_REPORT_DFS_INCONSISTENCY */
-long 
+long
 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     /* This is a UNICODE only request (bit15 of Flags2) */
 
     /* There is nothing we can do about this operation.  The client is going to
      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
-     * Unfortunately, there is really nothing we can do about it other then log it 
+     * Unfortunately, there is really nothing we can do about it other then log it
      * somewhere.  Even then I don't think there is anything for us to do.
      * So let's return an error value.
      */
@@ -3988,11 +4536,10 @@ smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_
     return CM_ERROR_BADOP;
 }
 
-static long 
-smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp, 
-                          clientchar_t * tidPathp, clientchar_t * relPathp, 
-                          int infoLevel, cm_user_t *userp,
-                          cm_req_t *reqp)
+static long
+smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
+                          clientchar_t * tidPathp, clientchar_t * relPathp,
+                          int infoLevel, cm_user_t *userp, cm_req_t *reqp)
 {
     long code = 0;
     cm_scache_t *scp;
@@ -4008,12 +4555,12 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
     clientchar_t path[AFSPATHMAX];
 
     code = cm_FindACLCache(dscp, userp, &rights);
-    if (code == 0 && !(rights & PRSFS_READ))
-        mustFake = 1;
-    else if (code == -1) {
+    if (code == -1) {
         lock_ObtainWrite(&dscp->rw);
         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code == 0)
+            cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         lock_ReleaseWrite(&dscp->rw);
         if (code == CM_ERROR_NOACCESS) {
             mustFake = 1;
@@ -4021,25 +4568,116 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
         }
     }
     if (code)
-        return code;
+        goto cleanup;
+
+    if (!mustFake) {    /* Bulk Stat */
+        afs_uint32 count;
+        cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
+
+        memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+        for (patchp = *dirPatchespp, count=0;
+             patchp;
+             patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+            cm_scache_t *tscp = NULL;
+            int i;
 
-    for(patchp = *dirPatchespp; patchp; patchp =
-         (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+            /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
+            if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
+                continue;
+
+            code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
+            if (code == 0) {
+                if (lock_TryWrite(&tscp->rw)) {
+                    /* we have an entry that we can look at */
+#ifdef AFS_FREELANCE_CLIENT
+                    if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
+                        code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
+                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+                        if (code == 0)
+                            cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+                        lock_ReleaseWrite(&tscp->rw);
+                        cm_ReleaseSCache(tscp);
+                        continue;
+                    }
+#endif /* AFS_FREELANCE_CLIENT */
+                    if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                        /* we have a callback on it.  Don't bother
+                        * fetching this stat entry, since we're happy
+                        * with the info we have.
+                        */
+                        lock_ReleaseWrite(&tscp->rw);
+                        cm_ReleaseSCache(tscp);
+                        continue;
+                    }
+                    lock_ReleaseWrite(&tscp->rw);
+                } /* got lock */
+                cm_ReleaseSCache(tscp);
+            }  /* found entry */
+
+            i = bsp->counter++;
+            bsp->fids[i].Volume = patchp->fid.volume;
+            bsp->fids[i].Vnode = patchp->fid.vnode;
+            bsp->fids[i].Unique = patchp->fid.unique;
+
+            if (bsp->counter == AFSCBMAX) {
+                code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+                memset(bsp, 0, sizeof(cm_bulkStat_t));
+            }
+        }
+
+        if (bsp->counter > 0)
+            code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+
+        free(bsp);
+    }
+
+    for( patchp = *dirPatchespp;
+         patchp;
+         patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
         cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
                             relPathp ? relPathp : _C(""), patchp->dep->name);
         reqp->relPathp = path;
         reqp->tidPathp = tidPathp;
 
+        if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
+            /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
+               errors in the client. */
+            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+                smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+
+                /* 1969-12-31 23:59:59 +00 */
+                ft.dwHighDateTime = 0x19DB200;
+                ft.dwLowDateTime = 0x5BB78980;
+
+                /* copy to Creation Time */
+                fa->creationTime = ft;
+                fa->lastAccessTime = ft;
+                fa->lastWriteTime = ft;
+                fa->lastChangeTime = ft;
+                fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
+            } else {
+                smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
+                /* 1969-12-31 23:59:58 +00*/
+                dosTime = 0xEBBFBF7D;
+
+                fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
+                fa->lastAccessDateTime = fa->creationDateTime;
+                fa->lastWriteDateTime = fa->creationDateTime;
+                fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
+            }
+            continue;
+        }
+
         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
         reqp->relPathp = reqp->tidPathp = NULL;
-        if (code) 
+        if (code)
             continue;
 
         lock_ObtainWrite(&scp->rw);
-        if (mustFake == 0)
-            code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                             CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (mustFake || code) { 
+        if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
             lock_ReleaseWrite(&scp->rw);
 
             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
@@ -4060,17 +4698,22 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
-                case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                     break;
+                case CM_SCACHETYPE_SYMLINK:
+                    if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->extFileAttributes = SMB_ATTR_NORMAL;
+                    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.
-                     * even means it is to be treated as a directory
-                     * and odd means it is to be treated as a file.
+                     * odd means it is to be treated as a directory
+                     * and even means it is to be treated as a file.
                      */
                     if (mustFake && (scp->fid.vnode & 0x1))
                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
@@ -4095,34 +4738,38 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
-                case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
                     fa->attributes = SMB_ATTR_DIRECTORY;
                     break;
+                case CM_SCACHETYPE_SYMLINK:
+                    if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                        fa->attributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->attributes = SMB_ATTR_NORMAL;
+                    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.
                      * even means it is to be treated as a directory
                      * and odd means it is to be treated as a file.
                      */
                     if (mustFake && (scp->fid.vnode & 0x1))
-                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+                        fa->attributes = SMB_ATTR_DIRECTORY;
                     else
-                        fa->extFileAttributes = SMB_ATTR_NORMAL;
+                        fa->attributes = SMB_ATTR_NORMAL;
                 }
+
                 /* merge in hidden (dot file) attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
                     fa->attributes |= SMB_ATTR_HIDDEN;
-                }       
+                }
             }
-            
+
             cm_ReleaseSCache(scp);
             continue;
         }
-        
-       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
         /* now watch for a symlink */
         code = 0;
@@ -4153,7 +4800,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
 
             /* get filetime */
-            smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+            cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
 
             fa->creationTime = ft;
             fa->lastAccessTime = ft;
@@ -4166,7 +4813,9 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
 
             /* Copy attributes */
             lattr = smb_ExtAttributes(scp);
-            if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
+            if ((code == CM_ERROR_NOSUCHPATH &&
+                (scp->fileType == CM_SCACHETYPE_SYMLINK &&
+                cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
                 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
                 if (lattr == SMB_ATTR_NORMAL)
                     lattr = SMB_ATTR_DIRECTORY;
@@ -4186,7 +4835,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
 
             /* get dos time */
-            smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+            cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
 
             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
             fa->lastAccessDateTime = fa->creationDateTime;
@@ -4213,20 +4862,21 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
         lock_ReleaseRead(&scp->rw);
         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;
 
+  cleanup:
     return code;
 }
 
-/* smb_ReceiveTran2SearchDir implements both 
+/* smb_ReceiveTran2SearchDir implements both
  * Tran2_Find_First and Tran2_Find_Next
  */
 #define TRAN2_FIND_FLAG_CLOSE_SEARCH           0x01
@@ -4240,8 +4890,8 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
    application is using FindFirst(Ex) to get information about a
    single file or directory.  It will attempt to do a single lookup.
    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
-   the usual mechanism. 
-   
+   the usual mechanism.
+
    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
 
    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
@@ -4259,7 +4909,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     size_t ohbytes;                    /* # of bytes, except file name */
     size_t onbytes;                    /* # of bytes in name, incl. term. null */
     cm_scache_t *scp = NULL;
-    cm_scache_t *targetscp = NULL;
+    cm_scache_t *targetScp = NULL;
     cm_user_t *userp = NULL;
     char *op;                          /* output data ptr */
     char *origOp;                      /* original value of op */
@@ -4274,7 +4924,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     smb_tran2Packet_t *outp;           /* response packet */
     clientchar_t *tidPathp = 0;
     int align;
-    clientchar_t shortName[13];                        /* 8.3 name if needed */
+    clientchar_t shortName[13];                /* 8.3 name if needed */
     int NeedShortName;
     clientchar_t *shortNameEnd;
     cm_dirEntry_t * dep = NULL;
@@ -4282,8 +4932,10 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     char * s;
     void * attrp = NULL;
     smb_tran2Find_t * fp;
+    int afs_ioctl = 0;                  /* is this query for _._AFS_IOCTL_._? */
+    cm_dirFid_t dfid;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     eos = 0;
     osi_assertx(p->opcode == 1, "invalid opcode");
@@ -4300,9 +4952,9 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
     nextCookie = 0;
     maskp = cm_ClientStrRChr(pathp,  '\\');
-    if (maskp == NULL) 
+    if (maskp == NULL)
        maskp = pathp;
-    else 
+    else
        maskp++;        /* skip over backslash */
     /* track if this is likely to match a lot of entries */
 
@@ -4356,7 +5008,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     osi_Log4(smb_logp,
              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
              attribute, infoLevel, maxCount, searchFlags);
-    
+
     if (ohbytes == 0) {
         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
         return CM_ERROR_INVAL;
@@ -4374,23 +5026,18 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     maxReturnParms = 10;       /* return params for findfirst, which
                                    is the only one we handle.*/
 
-#ifndef CM_CONFIG_MULTITRAN2RESPONSES
-    if (maxReturnData > 6000) 
-        maxReturnData = 6000;
-#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
-
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                       maxReturnData);
 
     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
              maxCount, osi_LogSaveClientString(smb_logp, pathp));
-        
+
     /* bail out if request looks bad */
     if (!pathp) {
         smb_FreeTran2Packet(outp);
         return CM_ERROR_BADSMB;
     }
-        
+
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
        osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
@@ -4400,6 +5047,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     /* try to get the vnode for the path name next */
     spacep = cm_GetSpace();
+    /* smb_StripLastComponent will strip "::$DATA" if present */
     smb_StripLastComponent(spacep->wdata, NULL, pathp);
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if (code) {
@@ -4409,7 +5057,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         return 0;
     }
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                     userp, tidPathp, &req, &scp);
     cm_FreeSpace(spacep);
@@ -4429,7 +5077,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         if ( WANTS_DFS_PATHNAMES(p) || pnc )
            code = CM_ERROR_PATH_NOT_COVERED;
        else
-           code = CM_ERROR_BADSHARENAME;
+           code = CM_ERROR_NOSUCHPATH;
        smb_SendTran2Error(vcp, p, opx, code);
        smb_FreeTran2Packet(outp);
        return 0;
@@ -4437,32 +5085,43 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 #endif /* DFS_SUPPORT */
     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
 
-    /* now do a single case sensitive lookup for the file in question */
-    code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
+    afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
 
-    /* if a case sensitive match failed, we try a case insensitive one
-       next. */
-    if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
-        code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
-    }
+    /*
+     * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
+     * the target scp.
+     */
+    if (!afs_ioctl) {
+        /* now do a single case sensitive lookup for the file in question */
+        code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
 
-    if (code == 0 && targetscp->fid.vnode == 0) {
-        cm_ReleaseSCache(targetscp);
-        code = CM_ERROR_NOSUCHFILE;
-    }
+        /*
+         * if a case sensitive match failed, we try a case insensitive
+         * one next.
+         */
+        if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
+            code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
 
-    if (code) {
-        /* if we can't find the directory entry, this block will
-           return CM_ERROR_NOSUCHFILE, which we will pass on to
-           smb_ReceiveTran2SearchDir(). */
-        cm_ReleaseSCache(scp);
-        cm_ReleaseUser(userp);
-       if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
-           smb_SendTran2Error(vcp, p, opx, code);
-           code = 0;
-       }
-       smb_FreeTran2Packet(outp);
-        return code;
+        if (code == 0 && targetScp->fid.vnode == 0) {
+            cm_ReleaseSCache(targetScp);
+            code = CM_ERROR_NOSUCHFILE;
+        }
+
+        if (code) {
+            /*
+             * if we can't find the directory entry, this block will
+             * return CM_ERROR_NOSUCHFILE, which we will pass on to
+             * smb_ReceiveTran2SearchDir().
+             */
+            cm_ReleaseSCache(scp);
+            cm_ReleaseUser(userp);
+            if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+                smb_SendTran2Error(vcp, p, opx, code);
+                code = 0;
+            }
+            smb_FreeTran2Packet(outp);
+            return code;
+        }
     }
 
     /* now that we have the target in sight, we proceed with filling
@@ -4479,12 +5138,20 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     fp = (smb_tran2Find_t *) op;
 
     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
-        && targetscp->fid.vnode != 0
         && !cm_Is8Dot3(maskp)) {
 
-        cm_dirFid_t dfid;
-        dfid.vnode = htonl(targetscp->fid.vnode);
-        dfid.unique = htonl(targetscp->fid.unique);
+        /*
+         * Since the _._AFS_IOCTL_._ file does not actually exist
+         * we will make up a per directory FID equivalent to the
+         * directory vnode and the uniqifier 0.
+         */
+        if (afs_ioctl) {
+            dfid.vnode = htonl(scp->fid.vnode);
+            dfid.unique = htonl(0);
+        } else {
+            dfid.vnode = htonl(targetScp->fid.vnode);
+            dfid.unique = htonl(targetScp->fid.unique);
+        }
 
         cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
         NeedShortName = 1;
@@ -4493,8 +5160,8 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     }
 
     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
-             htonl(targetscp->fid.vnode),
-             htonl(targetscp->fid.unique),
+             ntohl(dfid.vnode),
+             ntohl(dfid.unique),
              osi_LogSaveClientString(smb_logp, pathp),
              (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
 
@@ -4509,10 +5176,11 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     }
 
     if (!(attribute & SMB_ATTR_DIRECTORY) &&
-        (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
-         targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
-         targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
-         targetscp->fileType == CM_SCACHETYPE_INVALID)) {
+        !afs_ioctl &&
+        (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
+         targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+         targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
+         targetScp->fileType == CM_SCACHETYPE_INVALID)) {
 
         code = CM_ERROR_NOSUCHFILE;
         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
@@ -4522,7 +5190,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     /* add header to name & term. null */
     onbytes = 0;
-    smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
+    smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
     orbytes = ohbytes + onbytes;
 
     /* now, we round up the record to a 4 byte alignment, and we make
@@ -4554,7 +5222,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     memset(origOp, 0, orbytes);
 
     onbytes = 0;
-    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
+    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
 
     switch (infoLevel) {
     case SMB_INFO_STANDARD:
@@ -4579,11 +5247,11 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 #ifdef SMB_UNICODE
             int nchars;
 
-            nchars = cm_ClientStringToUtf16(shortName, -1,
+            nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
                                             fp->u.FfileBothDirectoryInfo.shortName,
                                             sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
             if (nchars > 0)
-                fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
+                fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
             else
                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
             fp->u.FfileBothDirectoryInfo.reserved = 0;
@@ -4631,18 +5299,26 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
             curPatchp->flags = 0;
         }
 
-        cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
-
         /* temp */
         {
             int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
             dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
             cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
         }
-        dep->fid.vnode = targetscp->fid.vnode;
-        dep->fid.unique = targetscp->fid.unique;
-        curPatchp->dep = dep;
-    }   
+
+        if (afs_ioctl) {
+            cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
+            dep->fid.vnode = scp->fid.vnode;
+            dep->fid.unique = 0;
+            curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
+        } else {
+            cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
+            dep->fid.vnode = targetScp->fid.vnode;
+            dep->fid.unique = targetScp->fid.unique;
+        }
+
+        curPatchp->dep = dep;
+    }
 
     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
         /* put out resume key */
@@ -4687,8 +5363,9 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     if (dep)
         free(dep);
     if (scp)
-    cm_ReleaseSCache(scp);
-    cm_ReleaseSCache(targetscp);
+        cm_ReleaseSCache(scp);
+    if (targetScp)
+        cm_ReleaseSCache(targetScp);
     cm_ReleaseUser(userp);
 
     return code;
@@ -4751,7 +5428,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     char * s;
     smb_tran2Find_t * fp;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     eos = 0;
     if (p->opcode == 1) {
@@ -4763,9 +5440,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
         nextCookie = 0;
         maskp = cm_ClientStrRChr(pathp,  '\\');
-        if (maskp == NULL) 
+        if (maskp == NULL)
             maskp = pathp;
-        else 
+        else
             maskp++;   /* skip over backslash */
 
         /* track if this is likely to match a lot of entries */
@@ -4774,7 +5451,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #ifndef NOFINDFIRSTOPTIMIZE
         if (!starPattern) {
             /* if this is for a single directory or file, we let the
-               optimized routine handle it.  The only error it 
+               optimized routine handle it.  The only error it
               returns is CM_ERROR_NOSUCHFILE.  The  */
             code = smb_T2SearchDirSingle(vcp, p, opx);
 
@@ -4881,27 +5558,25 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     maxReturnData = p->maxReturnData;
     if (p->opcode == 1)        /* find first */
         maxReturnParms = 10;   /* bytes */
-    else    
+    else
         maxReturnParms = 8;    /* bytes */
 
-#ifndef CM_CONFIG_MULTITRAN2RESPONSES
-    if (maxReturnData > 6000) 
-        maxReturnData = 6000;
-#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
-
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                       maxReturnData);
 
+    if (maxCount > 500)
+        maxCount = 500;
+
     osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
              maxCount, osi_LogSaveClientString(smb_logp, pathp));
-        
+
     /* bail out if request looks bad */
     if (p->opcode == 1 && !pathp) {
         smb_ReleaseDirSearch(dsp);
         smb_FreeTran2Packet(outp);
         return CM_ERROR_BADSMB;
     }
-        
+
     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
              dsp->cookie, nextCookie, attribute);
 
@@ -4922,6 +5597,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         code = 0;
     } else {
         spacep = cm_GetSpace();
+        /* smb_StripLastComponent will strip "::$DATA" if present */
         smb_StripLastComponent(spacep->wdata, NULL, pathp);
         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
         if (code) {
@@ -4937,7 +5613,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         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,
                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &scp);
         cm_FreeSpace(spacep);
@@ -4951,7 +5627,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 if ( WANTS_DFS_PATHNAMES(p) || pnc )
                     code = CM_ERROR_PATH_NOT_COVERED;
                 else
-                    code = CM_ERROR_BADSHARENAME;
+                    code = CM_ERROR_NOSUCHPATH;
                 smb_SendTran2Error(vcp, p, opx, code);
                 smb_FreeTran2Packet(outp);
                 lock_ReleaseMutex(&dsp->mx);
@@ -4969,14 +5645,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * and so we do another hold now.
              */
             cm_HoldSCache(scp);
-            lock_ObtainWrite(&scp->rw);
-            if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
-                 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
-                scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
-                dsp->flags |= SMB_DIRSEARCH_BULKST;
-            }
-            lock_ReleaseWrite(&scp->rw);
-        } 
+            dsp->flags |= SMB_DIRSEARCH_BULKST;
+        }
     }
     lock_ReleaseMutex(&dsp->mx);
     if (code) {
@@ -5041,10 +5711,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* we're in a later dir page */
             if (temp < 32) temp = 32;
         }
-               
+
         /* make sure the low order 5 bits are zero */
         temp &= ~(32-1);
-                
+
         /* now put temp bits back ito curOffset.LowPart */
         curOffset.LowPart &= ~(2048-1);
         curOffset.LowPart |= temp;
@@ -5067,6 +5737,22 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             break;
         }
 
+        /* when we have obtained as many entries as can be processed in
+         * a single Bulk Status call to the file server, apply the dir listing
+         * patches.
+         */
+        if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
+            lock_ReleaseWrite(&scp->rw);
+            code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
+                                               dsp->relPath, infoLevel, userp, &req);
+            lock_ObtainWrite(&scp->rw);
+        }
+        /* Then check to see if we have time left to process more entries */
+        if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
+            osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
+            break;
+        }
+
         /* see if we can use the bufferp we have now; compute in which
          * page the current offset would be, and check whether that's
          * the offset of the buffer we have.  If not, get the buffer.
@@ -5078,33 +5764,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             if (bufferp) {
                 buf_Release(bufferp);
                 bufferp = NULL;
-            }       
-            lock_ReleaseWrite(&scp->rw);
-            code = buf_Get(scp, &thyper, &bufferp);
-            lock_ObtainMutex(&dsp->mx);
-
-            /* now, if we're doing a star match, do bulk fetching
-             * of all of the status info for files in the dir.
-             */
-            if (starPattern) {
-                code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
-                
-                lock_ObtainWrite(&scp->rw);
-                if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
-                    LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
-                    /* Don't bulk stat if risking timeout */
-                    DWORD now = GetTickCount();
-                    if (now - req.startTime > RDRtimeout * 1000) {
-                        scp->bulkStatProgress = thyper;
-                        scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
-                        dsp->flags &= ~SMB_DIRSEARCH_BULKST;
-                    } else
-                        code = cm_TryBulkStat(scp, &thyper, userp, &req);
-                }
-            } else {
-                lock_ObtainWrite(&scp->rw);
             }
-            lock_ReleaseMutex(&dsp->mx);
+            lock_ReleaseWrite(&scp->rw);
+            code = buf_Get(scp, &thyper, &req, &bufferp);
+            lock_ObtainWrite(&scp->rw);
             if (code) {
                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
                 break;
@@ -5122,19 +5785,19 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
                     break;
                 }
-                       
-               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
 
                 if (cm_HaveBuffer(scp, bufferp, 0)) {
                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
+                    cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
                     break;
                 }
 
                 /* otherwise, load the buffer and try again */
                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                     &req);
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
                 if (code) {
-                    osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
+                    osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
                               scp, bufferp, code);
                     break;
                 }
@@ -5145,7 +5808,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 break;
             }
         }      /* if (wrong buffer) ... */
-                
+
         /* now we have the buffer containing the entry we're interested
          * in; copy it out if it represents a non-deleted entry.
          */
@@ -5184,42 +5847,47 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
          * XXXX Probably should do more sanity checking.
          */
         numDirChunks = cm_NameEntries(dep->name, &onbytes);
-               
+
         /* compute offset of cookie representing next entry */
         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
 
-        if (dep->fid.vnode == 0) 
+        if (dep->fid.vnode == 0)
             goto nextEntry;             /* This entry is not in use */
 
-        cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
-        cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
+        if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
+            cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
+
+            osi_Log1(smb_logp, "Skipping entry [%s].  Can't convert or normalize FS String",
+                     osi_LogSaveString(smb_logp, dep->name));
+            goto nextEntry;
+        }
 
         /* Need 8.3 name? */
         NeedShortName = 0;
-        if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
+        if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
             !cm_Is8Dot3(cfileName)) {
             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
             NeedShortName = 1;
         }
 
         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
-                 dep->fid.vnode, dep->fid.unique, 
+                 dep->fid.vnode, dep->fid.unique,
                  osi_LogSaveClientString(smb_logp, cfileName),
                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
 
         /* When matching, we are using doing a case fold if we have a wildcard mask.
-         * If we get a non-wildcard match, it's a lookup for a specific file. 
+         * If we get a non-wildcard match, it's a lookup for a specific file.
          */
         if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
-            (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD))) 
+            (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
         {
             /* Eliminate entries that don't match requested attributes */
-            if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
+            if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
                 smb_IsDotFile(cfileName)) {
                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
                 goto nextEntry; /* no hidden files */
             }
-        
+
             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
             {
                 /* We have already done the cm_TryBulkStat above */
@@ -5239,7 +5907,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
             /* finally check if this name will fit */
             onbytes = 0;
-            smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH);
+            smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
             orbytes = ohbytes + onbytes;
 
             /* now, we round up the record to a 4 byte alignment,
@@ -5256,8 +5924,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             if (orbytes + bytesInBuffer + align > maxReturnData) {
                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
                          maxReturnData);
-                break;      
-            }       
+                break;
+            }
 
             /* this is one of the entries to use: it is not deleted
              * and it matches the star pattern we're looking for.
@@ -5267,7 +5935,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             memset(origOp, 0, orbytes);
 
             onbytes = 0;
-            smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH);
+            smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
 
             switch (infoLevel) {
             case SMB_INFO_STANDARD:
@@ -5292,11 +5960,11 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #ifdef SMB_UNICODE
                     int nchars;
 
-                    nchars = cm_ClientStringToUtf16(shortName, -1,
+                    nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
                                                     fp->u.FfileBothDirectoryInfo.shortName,
                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
                     if (nchars > 0)
-                        fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
+                        fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
                     else
                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
                     fp->u.FfileBothDirectoryInfo.reserved = 0;
@@ -5364,7 +6032,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
                 /* temp */
                 curPatchp->dep = dep;
-            }   
+            }
 
             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
                 /* put out resume key */
@@ -5394,10 +6062,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         curOffset = LargeIntegerAdd(thyper, curOffset);
     } /* while copying data for dir listing */
 
-    /* If we didn't get a star pattern, we did an exact match during the first pass. 
+    /* If we didn't get a star pattern, we did an exact match during the first pass.
      * If there were no exact matches found, we fail over to inexact matches by
      * marking the query as a star pattern (matches all case permutations), and
-     * re-running the query. 
+     * re-running the query.
      */
     if (returnedNames == 0 && !starPattern && foundInexact) {
         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
@@ -5412,14 +6080,14 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        bufferp = NULL;
     }
 
-    /* apply and free last set of patches; if not doing a star match, this
-     * will be empty, but better safe (and freeing everything) than sorry.
+    /*
+     * Finally, process whatever entries we have left.
      */
-    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, 
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
                                       dsp->relPath, infoLevel, userp, &req);
 
     /* now put out the final parameters */
-    if (returnedNames == 0) 
+    if (returnedNames == 0)
         eos = 1;
     if (p->opcode == 1) {
         /* find first */
@@ -5427,7 +6095,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->parmsp[1] = returnedNames;
         outp->parmsp[2] = eos;
         outp->parmsp[3] = 0;           /* nothing wrong with EAS */
-        outp->parmsp[4] = 0;   
+        outp->parmsp[4] = 0;
         /* don't need last name to continue
          * search, cookie is enough.  Normally,
          * this is the offset of the file name
@@ -5442,7 +6110,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->parmsp[2] = 0;   /* EAS error */
         outp->parmsp[3] = 0;   /* last name, as above */
         outp->totalParms = 8;  /* in bytes */
-    }   
+    }
 
     /* return # of bytes in the buffer */
     outp->totalData = bytesInBuffer;
@@ -5458,9 +6126,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * we're supposed to close the search if we're done, and we're done,
      * or if something went wrong, close the search.
      */
-    if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) || 
+    if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
        (returnedNames == 0) ||
-        ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) || 
+        ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
        code != 0)
         smb_DeleteDirSearch(dsp);
 
@@ -5483,18 +6151,18 @@ long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     smb_dirSearch_t *dsp;
 
     dirHandle = smb_GetSMBParm(inp, 0);
-       
+
     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
 
     dsp = smb_FindDirSearch(dirHandle);
-        
+
     if (!dsp)
         return CM_ERROR_BADFD;
-       
+
     /* otherwise, we have an FD to destroy */
     smb_DeleteDirSearch(dsp);
     smb_ReleaseDirSearch(dsp);
-        
+
     /* and return results */
     smb_SetSMBDataLength(outp, 0);
 
@@ -5520,7 +6188,6 @@ long smb_ReceiveV3OpenX(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;
@@ -5534,11 +6201,13 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     clientchar_t *tidPathp;
     cm_req_t req;
     int created = 0;
+    BOOL is_rpc = FALSE;
+    BOOL is_ipc = FALSE;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
-        
+
     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
     openFun = smb_GetSMBParm(inp, 8); /* open function */
     excl = ((openFun & 3) == 0);
@@ -5549,35 +6218,54 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     attributes = smb_GetSMBParm(inp, 5);
     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
 
-                                /* compute initial mode bits based on read-only flag in attributes */
-    initialModeBits = 0666;
-    if (attributes & SMB_ATTR_READONLY) 
-       initialModeBits &= ~0222;
-        
     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
                                 SMB_STRF_ANSIPATH);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
+
+    code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+    if (code) {
+       if (code == CM_ERROR_TIDIPC) {
+           is_ipc = TRUE;
+       } else {
+           return CM_ERROR_NOSUCHPATH;
+       }
+    }
 
     spacep = inp->spacep;
+    /* smb_StripLastComponent will strip "::$DATA" if present */
     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
-    if (lastNamep && 
-        (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
-         cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
-         cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
-         cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
+    if (lastNamep &&
+
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
-#ifdef NOTSERVICE
-        osi_Log0(smb_logp, "IOCTL Open");
-#endif
+        (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+
+        /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
+         (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
+
+       unsigned short file_type = 0;
+       unsigned short device_state = 0;
 
         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-        smb_SetupIoctlFid(fidp, spacep);
+       if (is_rpc) {
+           code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
+           osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
+           if (code) {
+               osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
+               smb_ReleaseFID(fidp);
+               return code;
+           }
+       } else {
+           smb_SetupIoctlFid(fidp, spacep);
+           osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
+       }
 
         /* set inp->fid so that later read calls in same msg can find fid */
         inp->fid = fidp->fid;
-        
+
         /* copy out remainder of the parms */
         parmSlot = 2;
         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
@@ -5588,9 +6276,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* len */
             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
-            smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
-            smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
-        }   
+            smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
+            smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
+        }
         /* and the final "always present" stuff */
         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
         /* next write out the "unique" ID */
@@ -5604,6 +6292,28 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
+#ifndef DFS_SUPPORT
+    if (is_ipc) {
+       osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
+       return CM_ERROR_BADFD;
+    }
+#endif
+
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
 #ifdef DEBUG_VERBOSE
     {
        char *hexp, *asciip;
@@ -5616,12 +6326,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     userp = smb_GetUserFromVCP(vcp, inp);
 
     dscp = NULL;
-    code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
-    if (code) {
-        cm_ReleaseUser(userp);
-        return CM_ERROR_NOSUCHPATH;
-    }
-    code = cm_NameI(cm_data.rootSCachep, pathp,
+    code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                     userp, tidPathp, &req, &scp);
 
@@ -5633,14 +6338,17 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
     if (code != 0) {
-        code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
-                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                        userp, tidPathp, &req, &dscp);
+        if (code == CM_ERROR_NOSUCHFILE ||
+            code == CM_ERROR_NOSUCHPATH ||
+            code == CM_ERROR_BPLUS_NOMATCH)
+            code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
+                            CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                            userp, tidPathp, &req, &dscp);
         if (code) {
             cm_ReleaseUser(userp);
             return code;
@@ -5655,16 +6363,16 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
         /* 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++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                           &req, &scp);
@@ -5674,7 +6382,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             return code;
         }
     }
-        
+
     /* if we get here, if code is 0, the file exists and is represented by
      * scp.  Otherwise, we have to create it.  The dir may be represented
      * by dscp, or we may have found the file directly.  If code is non-zero,
@@ -5691,7 +6399,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         if (excl) {
             /* oops, file shouldn't be there */
-            if (dscp) 
+            if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -5720,6 +6428,8 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         openAction = 2;        /* created file */
         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) {
@@ -5743,23 +6453,23 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     setAttr.length.LowPart = 0;
                     setAttr.length.HighPart = 0;
                     code = cm_SetAttr(scp, &setAttr, userp, &req);
-                }   
+                }
             }  /* lookup succeeded */
         }
     }
-        
+
     /* we don't need this any longer */
-    if (dscp) 
+    if (dscp)
         cm_ReleaseSCache(dscp);
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) 
+        if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
     /* make sure we're about to open a file */
     if (scp->fileType != CM_SCACHETYPE_FILE) {
         cm_ReleaseSCache(scp);
@@ -5770,7 +6480,7 @@ long smb_ReceiveV3OpenX(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);
     /* save a pointer to the vnode */
@@ -5781,9 +6491,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
     /* also the user */
     fidp->userp = userp;
-        
+
     /* compute open mode */
-    if (openMode != 1) 
+    if (openMode != 1)
         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
@@ -5794,12 +6504,12 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     lock_ReleaseMutex(&fidp->mx);
     smb_ReleaseFID(fidp);
-        
+
     cm_Open(scp, 0, userp);
 
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fidp->fid;
-        
+
     /* copy out remainder of the parms */
     parmSlot = 2;
     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
@@ -5829,12 +6539,12 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_ReleaseUser(userp);
     /* leave scp held since we put it in fidp->scp */
     return 0;
-}       
+}
 
-static void smb_GetLockParams(unsigned char LockType, 
-                              char ** buf, 
-                              unsigned int * ppid, 
-                              LARGE_INTEGER * pOffset, 
+static void smb_GetLockParams(unsigned char LockType,
+                              char ** buf,
+                              unsigned int * ppid,
+                              LARGE_INTEGER * pOffset,
                               LARGE_INTEGER * pLength)
 {
     if (LockType & LOCKING_ANDX_LARGE_FILES) {
@@ -5877,23 +6587,27 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int i;
     cm_key_t key;
     unsigned int pid;
+    afs_uint32 smb_vc_hold_required = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 2);
     fid = smb_ChainFID(fid, inp);
 
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
        return CM_ERROR_BADFD;
-    
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
        lock_ReleaseMutex(&fidp->mx);
@@ -5909,7 +6623,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     inp->fid = fid;
 
     userp = smb_GetUserFromVCP(vcp, inp);
-
+    smb_HoldVC(vcp);
 
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -5936,7 +6650,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
-        osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]"); 
+        osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
         code = CM_ERROR_BADOP;
         goto done;
 
@@ -5957,7 +6671,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
             {
                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
-                    if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
+                    if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
                         LargeIntegerEqualTo(wl->LLength, LLength)) {
                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
                         goto found_lock_request;
@@ -5978,9 +6692,9 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
 
-        code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
+        code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
 
-        if (code) 
+        if (code)
             goto done;
     }
 
@@ -5994,14 +6708,14 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
                         userp, &req, &lockp);
 
-       if (code == CM_ERROR_NOACCESS && LockType == LockWrite && 
+       if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
            (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
        {
            code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
                            userp, &req, &lockp);
        }
 
-        if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
+        if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
             smb_waitingLock_t * wLock;
 
             /* Put on waiting list */
@@ -6016,7 +6730,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 osi_assertx(wlRequest != NULL, "null wlRequest");
 
                 wlRequest->vcp = vcp;
-                smb_HoldVC(vcp);
+                smb_vc_hold_required = 1;
                 wlRequest->scp = scp;
                osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
                 cm_HoldSCache(scp);
@@ -6100,8 +6814,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
 
-                ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
-                
+                ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
+
                 if(ul_code != 0) {
                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
                 } else {
@@ -6140,7 +6854,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_SetSMBDataLength(outp, 0);
     }
 
-  done:   
+  done:
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
 
   doneSync:
@@ -6148,6 +6862,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
+    if (!smb_vc_hold_required)
+        smb_HoldVC(vcp);
 
     return code;
 }
@@ -6164,22 +6880,25 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     cm_req_t req;
     int readlock = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 0);
     fid = smb_ChainFID(fid, inp);
-        
+
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
        return CM_ERROR_BADFD;
-    
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
@@ -6189,26 +6908,27 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
-        
-        
+
+
     /* otherwise, stat the file */
     lock_ObtainWrite(&scp->rw);
     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);
 
     lock_ConvertWToR(&scp->rw);
+    readlock = 1;
 
     /* decode times.  We need a search time, but the response to this
      * call provides the date first, not the time, as returned in the
      * searchTime variable.  So we take the high-order bits first.
      */
-    smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
+    cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);      /* ctime */
     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);      /* atime */
@@ -6224,13 +6944,13 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
     /* file attribute */
     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
-        
+
     /* and finalize stuff */
     smb_SetSMBDataLength(outp, 0);
     code = 0;
 
   done:
-    if (readlock) 
+    if (readlock)
         lock_ReleaseRead(&scp->rw);
     else
         lock_ReleaseWrite(&scp->rw);
@@ -6238,7 +6958,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     return code;
-}       
+}
 
 /* SMB_COM_SET_INFORMATION2 */
 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -6253,22 +6973,25 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     cm_attr_t attrs;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 0);
     fid = smb_ChainFID(fid, inp);
-        
+
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
        return CM_ERROR_BADFD;
-    
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
@@ -6278,18 +7001,17 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
-        
-        
+
     /* now prepare to call cm_setattr.  This message only sets various times,
      * and AFS only implements mtime, and we'll set the mtime if that's
      * requested.  The others we'll ignore.
      */
     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
-        
+
     if (searchTime != 0) {
-        smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+        cm_UnixTimeFromSearchTime(&unixTime, searchTime);
 
         if ( unixTime != -1 ) {
             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
@@ -6298,10 +7020,10 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
         } else {
-            osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
+            osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
         }
     }
-    else 
+    else
        code = 0;
 
     cm_ReleaseSCache(scp);
@@ -6320,6 +7042,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_fid_t *fidp;
     smb_t *smbp = (smb_t*) inp;
     long code = 0;
+    cm_scache_t *scp;
     cm_user_t *userp;
     char *op;
     int inDataBlockCount;
@@ -6332,17 +7055,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (*inp->wctp == 14) {
         /* we have a request with 64-bit file offsets */
-#ifdef AFS_LARGEFILES
         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
-#else
-        if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
-            /* uh oh */
-            osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
-            /* we shouldn't have received this op if we didn't specify
-               largefile support */
-            return CM_ERROR_BADOP;
-        }
-#endif
     }
 
     op = inp->data + smb_GetSMBParm(inp, 11);
@@ -6350,26 +7063,46 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
              fd, offset.HighPart, offset.LowPart, count);
-        
+
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         return CM_ERROR_BADFD;
-        
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
        smb_ReleaseFID(fidp);
        return code;
     }
+
+    if (fidp->flags & SMB_FID_RPC) {
+       lock_ReleaseMutex(&fidp->mx);
+        code = smb_RPCV3Write(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFDOP;
+    }
+
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /* special case: 0 bytes transferred means there is no data
@@ -6381,7 +7114,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_key_t key;
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
-        cm_scache_t * scp;
 
         pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
@@ -6391,7 +7123,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        scp = fidp->scp;
         lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
         lock_ReleaseWrite(&scp->rw);
@@ -6412,8 +7143,10 @@ long smb_ReceiveV3WriteX(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) {
-        fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
-        fidp->scp->clientModTime = time(NULL);
+        lock_ObtainWrite(&fidp->scp->rw);
+        scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+        scp->clientModTime = time(NULL);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }
     lock_ReleaseMutex(&fidp->mx);
 
@@ -6439,6 +7172,8 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBDataLength(outp, 0);
 
  done:
+
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
 
@@ -6456,17 +7191,17 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_fid_t *fidp;
     smb_t *smbp = (smb_t*) inp;
     long code = 0;
+    cm_scache_t *scp;
     cm_user_t *userp;
     cm_key_t key;
     char *op;
-        
-    fd = smb_GetSMBParm(inp, 2);
-    count = smb_GetSMBParm(inp, 5);
+
+    fd = smb_GetSMBParm(inp, 2); /* File ID */
+    count = smb_GetSMBParm(inp, 5); /* MaxCount */
     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
 
     if (*inp->wctp == 12) {
         /* a request with 64-bit offsets */
-#ifdef AFS_LARGEFILES
         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
 
         if (LargeIntegerLessThanZero(offset)) {
@@ -6474,14 +7209,6 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                      offset.HighPart, offset.LowPart);
             return CM_ERROR_BADSMB;
         }
-#else
-        if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
-            osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
-            return CM_ERROR_BADSMB;
-        } else {
-            offset.HighPart = 0;
-        }
-#endif
     } else {
         offset.HighPart = 0;
     }
@@ -6492,31 +7219,62 @@ long smb_ReceiveV3ReadX(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_Log2(smb_logp, "smb_ReceiveV3Read 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);
+       inp->fid = fd;
+        code = smb_IoctlV3Read(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
+    if (fidp->flags & SMB_FID_RPC) {
+       lock_ReleaseMutex(&fidp->mx);
+       inp->fid = fd;
+        code = smb_RPCV3Read(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFDOP;
+    }
+
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
+
+    lock_ReleaseMutex(&fidp->mx);
+
     pid = smbp->pid;
     key = cm_GenerateKey(vcp->vcID, pid, fd);
     {
         LARGE_INTEGER LOffset, LLength;
-        cm_scache_t *scp;
 
         LOffset.HighPart = offset.HighPart;
         LOffset.LowPart = offset.LowPart;
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        scp = fidp->scp;
         lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckRead(scp, LOffset, LLength, key);
         lock_ReleaseWrite(&scp->rw);
     }
+    cm_ReleaseSCache(scp);
 
     if (code) {
         smb_ReleaseFID(fidp);
@@ -6526,15 +7284,6 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fd;
 
-    lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_IOCTL) {
-       lock_ReleaseMutex(&fidp->mx);
-        code = smb_IoctlV3Read(fidp, vcp, inp, outp);
-       smb_ReleaseFID(fidp);
-       return code;
-    }
-    lock_ReleaseMutex(&fidp->mx);
-
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /* 0 and 1 are reserved for request chaining, were setup by our caller,
@@ -6555,7 +7304,7 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * know where the data really is.
      */
     op = smb_GetSMBData(outp, NULL);
-        
+
     /* now fill in offset from start of SMB header to first data byte (to op) */
     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
 
@@ -6571,8 +7320,8 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     return code;
-}   
-        
+}
+
 /*
  * Values for createDisp, copied from NTDDK.H
  */
@@ -6599,6 +7348,12 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #define FILE_RANDOM_ACCESS        0x0800
 #define FILE_DELETE_ON_CLOSE      0x1000
 #define FILE_OPEN_BY_FILE_ID      0x2000
+#define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
+#define FILE_NO_COMPRESSION                     0x00008000
+#define FILE_RESERVE_OPFILTER                   0x00100000
+#define FILE_OPEN_REPARSE_POINT                 0x00200000
+#define FILE_OPEN_NO_RECALL                     0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
 
 /* SMB_COM_NT_CREATE_ANDX */
 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -6626,7 +7381,6 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned int createDisp;
     unsigned int createOptions;
     unsigned int shareAccess;
-    int initialModeBits;
     unsigned short baseFid;
     smb_fid_t *baseFidp;
     smb_fid_t *fidp;
@@ -6640,12 +7394,16 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     BOOL foundscp;
     cm_req_t req;
     int created = 0;
+    int prefetch = 0;
+    int checkDoneRequired = 0;
     cm_lock_data_t *ldp = NULL;
+    BOOL is_rpc = FALSE;
+    BOOL is_ipc = FALSE;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     /* This code is very long and has a lot of if-then-else clauses
-     * scp and dscp get reused frequently and we need to ensure that 
+     * scp and dscp get reused frequently and we need to ensure that
      * we don't lose a reference.  Start by ensuring that they are NULL.
      */
     scp = NULL;
@@ -6689,14 +7447,6 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     else
         realDirFlag = -1;
 
-    /*
-     * compute initial mode bits based on read-only flag in
-     * extended attributes
-     */
-    initialModeBits = 0666;
-    if (extAttributes & SMB_ATTR_READONLY) 
-        initialModeBits &= ~0222;
-
     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
                               NULL, SMB_STRF_ANSIPATH);
 
@@ -6706,23 +7456,57 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     realPathp[nameLength/sizeof(clientchar_t)] = 0;
 
     spacep = inp->spacep;
+    /* smb_StripLastComponent will strip "::$DATA" if present */
     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
 
     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
 
-       if (lastNamep && 
-            (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
-             cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
-             cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
-             cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
-        /* special case magic file name for receiving IOCTL requests
-         * (since IOCTL calls themselves aren't getting through).
-         */
+    if (baseFid == 0) {
+       baseFidp = NULL;
+        baseDirp = cm_RootSCachep(cm_rootUserp, &req);
+        code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+        if (code == CM_ERROR_TIDIPC) {
+            /* Attempt to use a TID allocated for IPC.  The client
+             * is probably looking for DCE RPC end points which we
+             * don't support OR it could be looking to make a DFS
+             * referral request.
+             */
+            osi_Log0(smb_logp, "NTCreateX received IPC TID");
+           is_ipc = TRUE;
+        }
+    }
+
+    osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
+
+    if (lastNamep &&
+
+       ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
+
+        /* special case magic file name for receiving IOCTL requests
+         * (since IOCTL calls themselves aren't getting through).
+         */
+        cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0)) {
+
+       unsigned short file_type = 0;
+       unsigned short device_state = 0;
+
         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-        smb_SetupIoctlFid(fidp, spacep);
-        osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
+
+       if (is_rpc) {
+           code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
+           osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
+           if (code) {
+               osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
+               smb_ReleaseFID(fidp);
+               free(realPathp);
+               return code;
+           }
+       } else {
+           smb_SetupIoctlFid(fidp, spacep);
+           osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
+       }
 
         /* set inp->fid so that later read calls in same msg can find fid */
         inp->fid = fidp->fid;
@@ -6742,8 +7526,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         sz.HighPart = 0x7fff; sz.LowPart = 0;
         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
-        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
-        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
+        smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
+        smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;      /* dev state */
         smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
         smb_SetSMBDataLength(outp, 0);
 
@@ -6753,16 +7537,30 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
-#ifdef DEBUG_VERBOSE
-    {
-       char *hexp, *asciip;
-       asciip = (lastNamep? lastNamep : realPathp);
-       hexp = osi_HexifyString( asciip );
-       DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
-       free(hexp);
+#ifndef DFS_SUPPORT
+    if (is_ipc) {
+       osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
+       free(realPathp);
+       return CM_ERROR_BADFD;
     }
 #endif
 
+    if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(realPathp, -1);
+        osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+           free(hexp);
+#else
+        osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
+#endif
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
+
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
        osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
@@ -6770,37 +7568,20 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        return CM_ERROR_INVAL;
     }
 
-    if (baseFid == 0) {
-       baseFidp = NULL;
-        baseDirp = cm_data.rootSCachep;
-        code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
-        if (code == CM_ERROR_TIDIPC) {
-            /* Attempt to use a TID allocated for IPC.  The client
-             * is probably looking for DCE RPC end points which we
-             * don't support OR it could be looking to make a DFS
-             * referral request. 
-             */
-            osi_Log0(smb_logp, "NTCreateX received IPC TID");
-#ifndef DFS_SUPPORT
-            free(realPathp);
-            cm_ReleaseUser(userp);
-            return CM_ERROR_NOSUCHFILE;
-#endif /* DFS_SUPPORT */
-        }
-    } else {
+    if (baseFidp != 0) {
         baseFidp = smb_FindFID(vcp, baseFid, 0);
         if (!baseFidp) {
             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
+           cm_ReleaseUser(userp);
             free(realPathp);
-            cm_ReleaseUser(userp);
             return CM_ERROR_INVAL;
-        }       
+        }
 
         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
             free(realPathp);
-            cm_ReleaseUser(userp);
            smb_CloseFID(vcp, baseFidp, NULL, 0);
             smb_ReleaseFID(baseFidp);
+           cm_ReleaseUser(userp);
             return CM_ERROR_NOSUCHPATH;
         }
 
@@ -6808,8 +7589,6 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         tidPathp = NULL;
     }
 
-    osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
-
     /* compute open mode */
     fidflags = 0;
     if (desiredAccess & DELETE)
@@ -6824,6 +7603,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        fidflags |= SMB_FID_SEQUENTIAL;
     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
        fidflags |= SMB_FID_RANDOM;
+    if (createOptions & FILE_OPEN_REPARSE_POINT)
+        osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
     if (smb_IsExecutableFileName(lastNamep))
         fidflags |= SMB_FID_EXECUTABLE;
 
@@ -6837,7 +7618,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     code = 0;
 
     /* For an exclusive create, we want to do a case sensitive match for the last component. */
-    if ( createDisp == FILE_CREATE || 
+    if ( createDisp == FILE_CREATE ||
          createDisp == FILE_OVERWRITE ||
          createDisp == FILE_OVERWRITE_IF) {
         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
@@ -6850,31 +7631,31 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
                 free(realPathp);
-               if (baseFidp) 
+               if (baseFidp)
                    smb_ReleaseFID(baseFidp);
                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
-                    return CM_ERROR_BADSHARENAME;
+                    return CM_ERROR_NOSUCHPATH;
             }
 #endif /* DFS_SUPPORT */
             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
                              userp, &req, &scp);
             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
-                code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
+                code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
                 if (code == 0 && realDirFlag == 1) {
                     cm_ReleaseSCache(scp);
                     cm_ReleaseSCache(dscp);
                     cm_ReleaseUser(userp);
                     free(realPathp);
-                   if (baseFidp) 
+                   if (baseFidp)
                        smb_ReleaseFID(baseFidp);
                     return CM_ERROR_EXISTS;
                 }
             }
+            /* we have both scp and dscp */
         }
-        /* we have both scp and dscp */
     } else {
         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &scp);
@@ -6884,20 +7665,31 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
-           if (baseFidp) 
+           if (baseFidp)
                smb_ReleaseFID(baseFidp);
             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
         /* we might have scp but not dscp */
     }
 
+    if (code &&
+        code != CM_ERROR_NOSUCHFILE &&
+        code != CM_ERROR_NOSUCHPATH &&
+        code != CM_ERROR_BPLUS_NOMATCH) {
+        cm_ReleaseUser(userp);
+        free(realPathp);
+        if (baseFidp)
+            smb_ReleaseFID(baseFidp);
+        return code;
+    }
+
     if (scp)
         foundscp = TRUE;
-    
+
     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
         /* look up parent directory */
         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
@@ -6924,16 +7716,19 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     cm_ReleaseSCache(dscp);
                     cm_ReleaseUser(userp);
                     free(realPathp);
-                   if (baseFidp) 
+                   if (baseFidp)
                        smb_ReleaseFID(baseFidp);
                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                         return CM_ERROR_PATH_NOT_COVERED;
                     else
-                        return CM_ERROR_BADSHARENAME;
+                        return CM_ERROR_NOSUCHPATH;
                 }
 #endif /* DFS_SUPPORT */
 
                 if (code &&
+                    (code == CM_ERROR_NOSUCHFILE ||
+                     code == CM_ERROR_NOSUCHPATH ||
+                     code == CM_ERROR_BPLUS_NOMATCH) &&
                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
                     (createDisp == FILE_CREATE) &&
                     (realDirFlag == 1)) {
@@ -6943,7 +7738,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                     if (*tp && !smb_IsLegalFilename(tp)) {
                         cm_ReleaseUser(userp);
-                        if (baseFidp) 
+                        if (baseFidp)
                             smb_ReleaseFID(baseFidp);
                         free(realPathp);
                         if (scp)
@@ -6982,9 +7777,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             return CM_ERROR_EXISTS;
         }
 
-        if (!lastNamep) 
+        if (!lastNamep)
             lastNamep = realPathp;
-        else 
+        else
             lastNamep++;
 
         if (!smb_IsLegalFilename(lastNamep)) {
@@ -6998,9 +7793,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         if (!foundscp && !treeCreate) {
-            if ( createDisp == FILE_CREATE || 
+            if ( createDisp == FILE_CREATE ||
                  createDisp == FILE_OVERWRITE ||
-                 createDisp == FILE_OVERWRITE_IF) 
+                 createDisp == FILE_OVERWRITE_IF)
             {
                 code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW, userp, &req, &scp);
@@ -7032,6 +7827,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (code == 0 && !treeCreate) {
         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
         if (code) {
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             if (scp)
@@ -7040,6 +7836,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             free(realPathp);
             return code;
         }
+        checkDoneRequired = 1;
 
        if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
@@ -7053,7 +7850,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             return CM_ERROR_EXISTS;
         }
 
-        if ( createDisp == FILE_OVERWRITE || 
+        if ( createDisp == FILE_OVERWRITE ||
              createDisp == FILE_OVERWRITE_IF) {
 
             setAttr.mask = CM_ATTRMASK_LENGTH;
@@ -7077,6 +7874,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     scp = targetScp;
                    code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
                    if (code) {
+                        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                        if (dscp)
                            cm_ReleaseSCache(dscp);
                        if (scp)
@@ -7090,7 +7888,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             code = cm_SetAttr(scp, &setAttr, userp, &req);
             openAction = 3;    /* truncated existing file */
         }
-        else 
+        else
             openAction = 1;    /* found existing file */
 
     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
@@ -7109,6 +7907,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         openAction = 2;                /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
+        smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
         if (code == 0) {
            created = 1;
@@ -7159,14 +7959,14 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         int isLast = 0;
 
         /* create directory */
-        if ( !treeCreate ) 
+        if ( !treeCreate )
             treeStartp = lastNamep;
         osi_assertx(dscp != NULL, "null cm_scache_t");
         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
                   osi_LogSaveClientString(smb_logp, treeStartp));
         openAction = 2;                /* created directory */
 
-       /* if the request is to create the root directory 
+       /* if the request is to create the root directory
         * it will appear as a directory name of the nul-string
         * and a code of CM_ERROR_NOSUCHFILE
         */
@@ -7175,6 +7975,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
+        smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
 
         pp = treeStartp;
         cp = spacep->wdata;
@@ -7197,11 +7998,11 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             }
             pp = tp;
 
-            if (clen == 0) 
+            if (clen == 0)
                 continue; /* the supplied path can't have consecutive slashes either , but */
 
             /* cp is the next component to be created. */
-            code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
+            code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_ADDED,
                                  FILE_NOTIFY_CHANGE_DIR_NAME,
@@ -7217,7 +8018,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
                                  userp, &req, &tscp2);
             }
-            if (code) 
+            if (code)
                 break;
 
             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
@@ -7233,7 +8034,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if (scp)
             cm_ReleaseSCache(scp);
         scp = tscp2;
-        /* 
+        /*
          * if we get here and code == 0, then scp is the last directory created, and dscp is the
          * parent of scp.
          */
@@ -7241,11 +8042,11 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (code) {
         /* something went wrong creating or truncating the file */
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
-        if (scp) 
+        if (scp)
             cm_ReleaseSCache(scp);
-        if (dscp) 
+        if (dscp)
             cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         free(realPathp);
@@ -7265,15 +8066,17 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 * we'll just use the symlink anyway.
                 */
                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
-               if (ldp)
+               if (checkDoneRequired) {
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                    checkDoneRequired = 0;
+                }
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
@@ -7286,7 +8089,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* (only applies to single component case) */
     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         if (dscp)
@@ -7329,13 +8132,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
-        
+
         lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
         lock_ReleaseWrite(&scp->rw);
 
         if (code) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             if (dscp)
@@ -7345,13 +8148,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
            smb_CloseFID(vcp, fidp, NULL, 0);
            smb_ReleaseFID(fidp);
             free(realPathp);
-            return code;
+            return CM_ERROR_SHARING_VIOLATION;
         }
     }
 
     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
-    if (ldp)
+    if (checkDoneRequired) {
        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        checkDoneRequired = 0;
+    }
 
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
@@ -7389,38 +8194,85 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fidp->fid;
 
-    /* out parms */
-    parmSlot = 2;
     lock_ObtainRead(&scp->rw);
-    smb_SetSMBParmByte(outp, parmSlot, 0);     /* oplock */
-    smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
-    smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
-    smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
-    parmSlot += 2;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
-    smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* filetype */
-    smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* dev state */
-    smb_SetSMBParmByte(outp, parmSlot,
-                        (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
-                        scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
-                        scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
-    smb_SetSMBDataLength(outp, 0);
 
-    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
-        LargeIntegerGreaterThanZero(fidp->scp->length) && 
+    /*
+     * Always send the standard response.  Sending the extended
+     * response results in the Explorer Shell being unable to
+     * access directories at random times.
+     */
+    if (1 /*!extendedRespRequired */) {
+        /* out parms */
+        parmSlot = 2;
+        smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
+        smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+        smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
+        parmSlot += 2;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
+        smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
+        parmSlot++;    /* dev state */
+        smb_SetSMBParmByte(outp, parmSlot,
+                            (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
+        smb_SetSMBDataLength(outp, 0);
+    } else {
+        /* out parms */
+        parmSlot = 2;
+        smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
+        smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+        smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
+        parmSlot += 2;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
+        smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
+        parmSlot++;    /* dev state */
+        smb_SetSMBParmByte(outp, parmSlot,
+                            (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
+        /* Setting the GUID results in a failure with cygwin */
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        /* Maxmimal access rights */
+        smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
+        /* Guest access rights */
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBDataLength(outp, 0);
+    }
+
+    if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+        LargeIntegerGreaterThanZero(scp->length) &&
         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
-        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
-                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
-                           userp);
+        prefetch = 1;
     }
     lock_ReleaseRead(&scp->rw);
 
+    if (prefetch)
+        cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
+                           scp->length.LowPart, scp->length.HighPart,
+                           userp);
+
+
     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
               osi_LogSaveClientString(smb_logp, realPathp));
 
@@ -7432,7 +8284,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* leave scp held since we put it in fidp->scp */
     return 0;
-}       
+}
 
 /*
  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
@@ -7459,17 +8311,15 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     unsigned int extendedRespRequired;
     int realDirFlag;
     unsigned int desiredAccess;
-#ifdef DEBUG_VERBOSE    
     unsigned int allocSize;
-#endif
     unsigned int shareAccess;
     unsigned int extAttributes;
     unsigned int createDisp;
-#ifdef DEBUG_VERBOSE
     unsigned int sdLen;
-#endif
+    unsigned int eaLen;
+    unsigned int impLevel;
+    unsigned int secFlags;
     unsigned int createOptions;
-    int initialModeBits;
     unsigned short baseFid;
     smb_fid_t *baseFidp;
     smb_fid_t *fidp;
@@ -7486,9 +8336,11 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     char *outData;
     cm_req_t req;
     int created = 0;
+    int prefetch = 0;
     cm_lock_data_t *ldp = NULL;
+    int checkDoneRequired = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     foundscp = FALSE;
     scp = NULL;
@@ -7512,23 +8364,16 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return CM_ERROR_INVAL;
     baseFid = (unsigned short)lparmp[1];
     desiredAccess = lparmp[2];
-#ifdef DEBUG_VERBOSE
     allocSize = lparmp[3];
-#endif /* DEBUG_VERSOSE */
     extAttributes = lparmp[5];
     shareAccess = lparmp[6];
     createDisp = lparmp[7];
     createOptions = lparmp[8];
-#ifdef DEBUG_VERBOSE
     sdLen = lparmp[9];
-#endif
-    nameLength = lparmp[11];
-
-#ifdef DEBUG_VERBOSE
-    osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
-    osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
-    osi_Log1(smb_logp,"... flags[%x]",flags);
-#endif
+    eaLen = lparmp[10];
+    nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
+    impLevel = lparmp[12];
+    secFlags = lparmp[13];
 
     /* mustBeDir is never set; createOptions directory bit seems to be
      * more important
@@ -7540,72 +8385,93 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     else
         realDirFlag = -1;
 
-    /*
-     * compute initial mode bits based on read-only flag in
-     * extended attributes
-     */
-    initialModeBits = 0666;
-    if (extAttributes & SMB_ATTR_READONLY) 
-        initialModeBits &= ~0222;
-
-    pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
+    pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
                                nameLength, NULL, SMB_STRF_ANSIPATH);
-    /* Sometimes path is not null-terminated, so we make a copy. */
-    realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
-    memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
-    realPathp[nameLength] = 0;
+    /* Sometimes path is not nul-terminated, so we make a copy. */
+    realPathp = malloc(nameLength+sizeof(clientchar_t));
+    memcpy(realPathp, pathp, nameLength);
+    realPathp[nameLength/sizeof(clientchar_t)] = 0;
     spacep = cm_GetSpace();
+    /* smb_StripLastComponent will strip "::$DATA" if present */
     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
 
+    osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
+    osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
+    osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
+    osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
+
+    if ( realDirFlag == 1 &&
+         ( createDisp == FILE_SUPERSEDE ||
+           createDisp == FILE_OVERWRITE ||
+           createDisp == FILE_OVERWRITE_IF))
+    {
+        osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
+        cm_FreeSpace(spacep);
+        free(realPathp);
+        return CM_ERROR_INVAL;
+    }
+
     /*
      * Nothing here to handle SMB_IOCTL_FILENAME.
      * Will add it if necessary.
      */
 
-#ifdef DEBUG_VERBOSE
-    {
-        char *hexp, *asciip;
-        asciip = (lastNamep? lastNamep : realPathp);
-        hexp = osi_HexifyString( asciip );
-        DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
+    if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(realPathp, -1);
+        osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
         free(hexp);
-    }
+#else
+        osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
 #endif
+        cm_FreeSpace(spacep);
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
        osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
+        cm_FreeSpace(spacep);
        free(realPathp);
        return CM_ERROR_INVAL;
     }
 
     if (baseFid == 0) {
        baseFidp = NULL;
-        baseDirp = cm_data.rootSCachep;
+        baseDirp = cm_RootSCachep(cm_rootUserp, &req);
         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
         if (code == CM_ERROR_TIDIPC) {
             /* Attempt to use a TID allocated for IPC.  The client
              * is probably looking for DCE RPC end points which we
              * don't support OR it could be looking to make a DFS
-             * referral request. 
+             * referral request.
              */
             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
 #ifndef DFS_SUPPORT
+            cm_FreeSpace(spacep);
             free(realPathp);
             cm_ReleaseUser(userp);
             return CM_ERROR_NOSUCHPATH;
-#endif 
+#endif
         }
     } else {
         baseFidp = smb_FindFID(vcp, baseFid, 0);
         if (!baseFidp) {
-           osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
+            osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
+                      vcp, baseFid);
+            cm_FreeSpace(spacep);
             free(realPathp);
             cm_ReleaseUser(userp);
             return CM_ERROR_BADFD;
-        }       
+        }
 
         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+            cm_FreeSpace(spacep);
             free(realPathp);
             cm_ReleaseUser(userp);
            smb_CloseFID(vcp, baseFidp, NULL, 0);
@@ -7631,6 +8497,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
        fidflags |= SMB_FID_SEQUENTIAL;
     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
        fidflags |= SMB_FID_RANDOM;
+    if (createOptions & FILE_OPEN_REPARSE_POINT)
+        osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
     if (smb_IsExecutableFileName(lastNamep))
         fidflags |= SMB_FID_EXECUTABLE;
 
@@ -7642,94 +8510,70 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     dscp = NULL;
     code = 0;
-    if ( createDisp == FILE_OPEN || 
-         createDisp == FILE_OVERWRITE ||
-         createDisp == FILE_OVERWRITE_IF) {
-        code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                        userp, tidPathp, &req, &dscp);
-        if (code == 0) {
-#ifdef DFS_SUPPORT
-            if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
-                cm_ReleaseSCache(dscp);
-                cm_ReleaseUser(userp);
-                free(realPathp);
-               if (baseFidp)
-                   smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
-                    return CM_ERROR_PATH_NOT_COVERED;
-                else
-                    return CM_ERROR_BADSHARENAME;
-            }
-#endif /* DFS_SUPPORT */
-            code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
-                             userp, &req, &scp);
-            if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
-                code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
-                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
-                if (code == 0 && realDirFlag == 1) {
-                    cm_ReleaseSCache(scp);
-                    cm_ReleaseSCache(dscp);
-                    cm_ReleaseUser(userp);
-                    free(realPathp);
-                   if (baseFidp)
-                       smb_ReleaseFID(baseFidp);
-                    return CM_ERROR_EXISTS;
-                }
-            }
-        } else 
-            dscp = NULL;
-    } else {
-        code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                        userp, tidPathp, &req, &scp);
+
+    code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                    userp, tidPathp, &req, &dscp);
+    if (code == 0) {
 #ifdef DFS_SUPPORT
-        if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
-            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
-            cm_ReleaseSCache(scp);
+        if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
+            cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
+            cm_FreeSpace(spacep);
             free(realPathp);
-           if (baseFidp)
-               smb_ReleaseFID(baseFidp);
+            if (baseFidp)
+                smb_ReleaseFID(baseFidp);
             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
-    }
-
-    if (code == 0) 
-        foundscp = TRUE;
-
-    if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
-        /* look up parent directory */
-        if ( !dscp ) {
-            code = cm_NameI(baseDirp, spacep->wdata,
-                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                             userp, tidPathp, &req, &dscp);
-#ifdef DFS_SUPPORT
-            if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
+        code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
+                         userp, &req, &scp);
+        if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
+
+            code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
+                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
+            if (code == 0 && realDirFlag == 1 &&
+                (createDisp == FILE_OPEN ||
+                 createDisp == FILE_OVERWRITE ||
+                 createDisp == FILE_OVERWRITE_IF)) {
+                cm_ReleaseSCache(scp);
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
+                cm_FreeSpace(spacep);
                 free(realPathp);
-               if (baseFidp)
-                   smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
-                    return CM_ERROR_PATH_NOT_COVERED;
-                else
-                    return CM_ERROR_BADSHARENAME;
+                if (baseFidp)
+                    smb_ReleaseFID(baseFidp);
+                return CM_ERROR_EXISTS;
             }
-#endif /* DFS_SUPPORT */
-        } else
-            code = 0;
-        
+        }
+    } else {
+        cm_ReleaseUser(userp);
+        if (baseFidp)
+            smb_ReleaseFID(baseFidp);
+        cm_FreeSpace(spacep);
+        free(realPathp);
+        return CM_ERROR_NOSUCHPATH;
+    }
+
+    if (code == 0)
+        foundscp = TRUE;
+
+    if (code == CM_ERROR_NOSUCHFILE ||
+        code == CM_ERROR_NOSUCHPATH ||
+        code == CM_ERROR_BPLUS_NOMATCH ||
+        (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
+        code = 0;
+
         cm_FreeSpace(spacep);
 
         if (baseFidp)
             smb_ReleaseFID(baseFidp);
 
         if (code) {
+            cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             free(realPathp);
             return code;
@@ -7737,14 +8581,18 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
         if (!lastNamep)
            lastNamep = realPathp;
-        else 
+        else
            lastNamep++;
 
-        if (!smb_IsLegalFilename(lastNamep))
+        if (!smb_IsLegalFilename(lastNamep)) {
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
             return CM_ERROR_BADNTFILENAME;
+        }
 
         if (!foundscp) {
-            if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
+            if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
                 code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW, userp, &req, &scp);
             } else {
@@ -7772,20 +8620,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      */
     if (code == 0) {
         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
-        if (code) {     
-            if (dscp) 
-                cm_ReleaseSCache(dscp);
+        if (code) {
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
             return code;
         }
+        checkDoneRequired = 1;
 
         if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
-            if (dscp) 
-                cm_ReleaseSCache(dscp);
+            cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -7815,8 +8663,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                     scp = targetScp;
                    code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
                    if (code) {
-                       if (dscp)
-                           cm_ReleaseSCache(dscp);
+                        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                        cm_ReleaseSCache(dscp);
                        if (scp)
                            cm_ReleaseSCache(scp);
                        cm_ReleaseUser(userp);
@@ -7832,19 +8680,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
         /* don't create if not found */
-        if (dscp) 
-            cm_ReleaseSCache(dscp);
+        cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         free(realPathp);
         return CM_ERROR_NOSUCHFILE;
     }
     else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assertx(dscp != NULL, "null cm_scache_t");
+        /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
                   osi_LogSaveClientString(smb_logp, lastNamep));
         openAction = 2;                /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
+        smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                           &req);
         if (code == 0) {
@@ -7885,19 +8734,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                         }
                     }
                     code = cm_SetAttr(scp, &setAttr, userp, &req);
-                }       
+                }
             }  /* lookup succeeded */
         }
     } else {
-        /* create directory */
-        osi_assertx(dscp != NULL, "null cm_scache_t");
+        /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
         osi_Log1(smb_logp,
                   "smb_ReceiveNTTranCreate creating directory %S",
                   osi_LogSaveClientString(smb_logp, lastNamep));
         openAction = 2;                /* created directory */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
-        code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
+        smb_SetInitialModeBitsForDir(extAttributes, &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,
@@ -7912,14 +8762,14 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
              */
             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
                               userp, &req, &scp);
-        }       
+        }
     }
 
     if (code) {
         /* something went wrong creating or truncating the file */
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
-       if (scp) 
+       if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         free(realPathp);
@@ -7940,15 +8790,17 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                 */
                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
                           scp, targetScp);
-               if (ldp)
+               if (checkDoneRequired) {
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                    checkDoneRequired = 0;
+                }
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -7958,7 +8810,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 
     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
@@ -7997,13 +8849,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
 
         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
-        
+
         lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
         lock_ReleaseWrite(&scp->rw);
 
         if (code) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -8016,8 +8868,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 
     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
-    if (ldp)
+    if (checkDoneRequired) {
        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        checkDoneRequired = 0;
+    }
 
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
@@ -8045,7 +8899,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     lock_ReleaseMutex(&fidp->mx);
 
     /* we don't need this any longer */
-    if (dscp) 
+    if (dscp)
         cm_ReleaseSCache(dscp);
 
     cm_Open(scp, 0, userp);
@@ -8089,7 +8943,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((USHORT *)outData) = fidp->fid; outData += 2;        /* fid */
         *((ULONG *)outData) = openAction; outData += 4;
         *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         *((FILETIME *)outData) = ft; outData += 8;     /* creation time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last access time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last write time */
@@ -8098,7 +8952,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
         *((USHORT *)outData) = 0; outData += 2;        /* filetype */
-        *((USHORT *)outData) = 0; outData += 2;        /* dev state */
+        *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
+        outData += 2;  /* dev state */
         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
                                scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                                scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
@@ -8108,7 +8963,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         parmOffset = 8*4 + 39;
         parmOffset += 1;       /* pad to 4 */
         dataOffset = parmOffset + 104;
-        
+
         parmSlot = 1;
         outp->oddByte = 1;
         /* Total Parameter Count */
@@ -8129,7 +8984,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
         smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
         smb_SetSMBDataLength(outp, 105);
-        
+
         lock_ObtainRead(&scp->rw);
         outData = smb_GetSMBData(outp, NULL);
         outData++;                     /* round to get to parmOffset */
@@ -8138,7 +8993,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((USHORT *)outData) = fidp->fid; outData += 2;        /* fid */
         *((ULONG *)outData) = openAction; outData += 4;
         *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         *((FILETIME *)outData) = ft; outData += 8;     /* creation time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last access time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last write time */
@@ -8147,25 +9002,30 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
         *((USHORT *)outData) = 0; outData += 2;        /* filetype */
-        *((USHORT *)outData) = 0; outData += 2;        /* dev state */
+        *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
+        outData += 2;  /* dev state */
         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
                                scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                                scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         outData += 1;  /* is a dir? */
-        memset(outData,0,24); outData += 24; /* Volume ID and file ID */
+        /* Setting the GUID results in failures with cygwin */
+        memset(outData,0,24); outData += 24; /* GUID */
         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
     }
 
-    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
-         LargeIntegerGreaterThanZero(fidp->scp->length) && 
+    if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+         LargeIntegerGreaterThanZero(scp->length) &&
          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
-        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
-                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
-                           userp);
+        prefetch = 1;
     }
     lock_ReleaseRead(&scp->rw);
 
+    if (prefetch)
+        cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
+                           scp->length.LowPart, scp->length.HighPart,
+                           userp);
+
     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
 
     cm_ReleaseUser(userp);
@@ -8181,11 +9041,11 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
        smb_packet_t *outp)
 {
     smb_packet_t *savedPacketp;
-    ULONG filter; 
+    ULONG filter;
     USHORT fid, watchtree;
     smb_fid_t *fidp;
     cm_scache_t *scp;
-        
+
     filter = smb_GetSMBParm(inp, 19) |
              (smb_GetSMBParm(inp, 20) << 16);
     fid = smb_GetSMBParm(inp, 21);
@@ -8193,24 +9053,32 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
 
     fidp = smb_FindFID(vcp, fid, 0);
     if (!fidp) {
-        osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
+        osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         return CM_ERROR_BADFD;
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
 
     /* Create a copy of the Directory Watch Packet to use when sending the
      * notification if in the future a matching change is detected.
      */
     savedPacketp = smb_CopyPacket(inp);
-    smb_HoldVC(vcp);
-    if (savedPacketp->vcp)
-       smb_ReleaseVC(savedPacketp->vcp);
-    savedPacketp->vcp = vcp;
+    if (vcp != savedPacketp->vcp) {
+        smb_HoldVC(vcp);
+        if (savedPacketp->vcp)
+            smb_ReleaseVC(savedPacketp->vcp);
+        savedPacketp->vcp = vcp;
+    }
 
     /* Add the watch to the list of events to send notifications for */
     lock_ObtainMutex(&smb_Dir_Watch_Lock);
@@ -8218,8 +9086,7 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
     smb_Directory_Watches = savedPacketp;
     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
 
-    scp = fidp->scp;
-    osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"", 
+    osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
              fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
              filter, fid, watchtree);
@@ -8254,94 +9121,187 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
     else
         scp->flags |= CM_SCACHEFLAG_WATCHED;
     lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
     smb_ReleaseFID(fidp);
 
     outp->flags |= SMB_PACKETFLAG_NOSEND;
     return 0;
 }
 
-unsigned char nullSecurityDesc[36] = {
+unsigned char nullSecurityDesc[] = {
     0x01,                              /* security descriptor revision */
     0x00,                              /* reserved, should be zero */
-    0x00, 0x80,                                /* security descriptor control;
-                                         * 0x8000 : self-relative format */
+    0x04, 0x80,                                /* security descriptor control;
+                                         * 0x0004 : null-DACL present - everyone has full access
+                                         * 0x8000 : relative format */
     0x14, 0x00, 0x00, 0x00,            /* offset of owner SID */
-    0x1c, 0x00, 0x00, 0x00,            /* offset of group SID */
+    0x20, 0x00, 0x00, 0x00,            /* offset of group SID */
     0x00, 0x00, 0x00, 0x00,            /* offset of DACL would go here */
     0x00, 0x00, 0x00, 0x00,            /* offset of SACL would go here */
-    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                        /* "null SID" owner SID */
-    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-                                        /* "null SID" group SID */
-};      
+    0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
+    0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00,
+    0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
+    0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00
+};
 
 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int parmOffset, parmCount, dataOffset, dataCount;
+    int totalParmCount, totalDataCount;
     int parmSlot;
-    int maxData;
+    int maxData, maxParm;
+    int inTotalParm, inTotalData;
+    int inParm, inData;
+    int inParmOffset, inDataOffset;
     char *outData;
     char *parmp;
     USHORT *sparmp;
     ULONG *lparmp;
     USHORT fid;
     ULONG securityInformation;
+    smb_fid_t *fidp;
+    long code = 0;
+    DWORD dwLength;
 
-    parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
+    /*
+     * For details on the meanings of the various
+     * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
+     * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
+     */
+
+    inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
+        | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
+
+    inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
+        | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
+
+    maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
+        | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
+
+    maxData = smb_GetSMBOffsetParm(inp, 7, 1)
+        | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
+
+    inParm = smb_GetSMBOffsetParm(inp, 9, 1)
+        | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
+
+    inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
-    parmp = inp->data + parmOffset;
+
+    inData = smb_GetSMBOffsetParm(inp, 13, 1)
+        | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
+
+    inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
+        | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
+
+    parmp = inp->data + inParmOffset;
     sparmp = (USHORT *) parmp;
     lparmp = (ULONG *) parmp;
 
     fid = sparmp[0];
     securityInformation = lparmp[1];
 
-    maxData = smb_GetSMBOffsetParm(inp, 7, 1)
-        | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
+    fidp = smb_FindFID(vcp, fid, 0);
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
+        return CM_ERROR_BADFD;
+    }
 
-    if (maxData < 36)
-        dataCount = 0;
-    else
-        dataCount = 36;
+    lock_ObtainMutex(&fidp->mx);
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+    lock_ReleaseMutex(&fidp->mx);
+
+    osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
+             fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
+              securityInformation);
+
+    smb_ReleaseFID(fidp);
+
+    if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
+    {
+        code = CM_ERROR_BAD_LEVEL;
+        goto done;
+    }
+
+    dwLength = sizeof( nullSecurityDesc);
+
+    totalDataCount = dwLength;
+    totalParmCount = 4;
+
+    if (maxData >= totalDataCount) {
+        dataCount = totalDataCount;
+        parmCount = min(totalParmCount, maxParm);
+    } else if (maxParm >= totalParmCount) {
+        totalDataCount = dataCount = 0;
+        parmCount = totalParmCount;
+    } else {
+        totalDataCount = dataCount = 0;
+        totalParmCount = parmCount = 0;
+    }
 
     /* out parms */
     parmOffset = 8*4 + 39;
     parmOffset += 1;   /* pad to 4 */
-    parmCount = 4;
+
     dataOffset = parmOffset + parmCount;
 
     parmSlot = 1;
     outp->oddByte = 1;
     /* Total Parameter Count */
-    smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
     /* Total Data Count */
-    smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
     /* Parameter Count */
     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
     /* Parameter Offset */
-    smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
     /* Parameter Displacement */
     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
     /* Data Count */
     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
     /* Data Offset */
-    smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
     /* Data Displacement */
     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
-    smb_SetSMBParmByte(outp, parmSlot, 0);     /* Setup Count */
-    smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
+    /* Setup Count */
+    smb_SetSMBParmByte(outp, parmSlot, 0);
 
-    outData = smb_GetSMBData(outp, NULL);
-    outData++;                 /* round to get to parmOffset */
-    *((ULONG *)outData) = 36; outData += 4;    /* length */
+    if (parmCount == totalParmCount && dwLength == dataCount) {
+        smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
 
-    if (maxData >= 36) {
-        memcpy(outData, nullSecurityDesc, 36);
-        outData += 36;
-        return 0;
-    } else
-        return CM_ERROR_BUFFERTOOSMALL;
+        /* Data */
+        outData = smb_GetSMBData(outp, NULL);
+        outData++;                     /* round to get to dataOffset */
+
+        *((ULONG *)outData) = dataCount; outData += 4; /* SD Length (4 bytes) */
+        memcpy(outData, nullSecurityDesc, dataCount);
+        outData += dataCount;
+
+        code = 0;
+    } else if (parmCount >= 4) {
+        smb_SetSMBDataLength(outp, 1 + parmCount);
+
+        /* Data */
+        outData = smb_GetSMBData(outp, NULL);
+        outData++;                     /* round to get to dataOffset */
+
+        *((ULONG *)outData) = dwLength; outData += 4;  /* SD Length (4 bytes) */
+        code = CM_ERROR_BUFFERTOOSMALL;
+    } else {
+        smb_SetSMBDataLength(outp, 0);
+        code = CM_ERROR_BUFFER_OVERFLOW;
+    }
+
+  done:
+    return code;
 }
 
 /* SMB_COM_NT_TRANSACT
@@ -8359,7 +9319,7 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
-        
+
     switch (function) {
     case 1:                     /* NT_TRANSACT_CREATE */
         return smb_ReceiveNTTranCreate(vcp, inp, outp);
@@ -8383,7 +9343,7 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
         break;
     }
-    return CM_ERROR_INVAL;
+    return CM_ERROR_BADOP;
 }
 
 /*
@@ -8393,8 +9353,8 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  * If we don't know the file name (i.e. a callback break), filename is
  * NULL, and we return a zero-length list.
  *
- * At present there is not a single call to smb_NotifyChange that 
- * has the isDirectParent parameter set to FALSE.  
+ * At present there is not a single call to smb_NotifyChange that
+ * has the isDirectParent parameter set to FALSE.
  */
 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
        cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
@@ -8455,20 +9415,19 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch = watch;
             watch = watch->nextp;
             continue;
-        }      
+        }
 
         if (fidp->scp != dscp ||
             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
             (filter & notifyFilter) == 0 ||
-            (!isDirectParent && !wtree)) 
+            (!isDirectParent && !wtree))
         {
             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
-            smb_ReleaseFID(fidp);
             lastWatch = watch;
             watch = watch->nextp;
+            smb_ReleaseFID(fidp);
             continue;
         }
-        smb_ReleaseFID(fidp);
 
         osi_Log4(smb_logp,
                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
@@ -8497,7 +9456,7 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
            osi_Log0(smb_logp, "      Notify Change Stream Size");
        if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
            osi_Log0(smb_logp, "      Notify Change Stream Write");
-                    
+
        /* A watch can only be notified once.  Remove it from the list */
         nextWatch = watch->nextp;
         if (watch == smb_Directory_Watches)
@@ -8584,7 +9543,7 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
                 *((DWORD *)outData) = otherNameLen*2;
                 outData += 4;  /* File Name Length */
                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
-            }       
+            }
         }
 
         /*
@@ -8605,10 +9564,12 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
 
         smb_SendPacket(watch->vcp, watch);
         smb_FreePacket(watch);
+
+        smb_ReleaseFID(fidp);
         watch = nextWatch;
     }
     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
-}       
+}
 
 /* SMB_COM_NT_CANCEL */
 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -8639,23 +9600,25 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
 
             if (vcp != watch->vcp)
-                osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
+                osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
                           vcp, watch->vcp);
 
             fidp = smb_FindFID(vcp, fid, 0);
             if (fidp) {
-                osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S", 
+                osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
                          fid, watchtree,
                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
 
                 scp = fidp->scp;
                osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
-                lock_ObtainWrite(&scp->rw);
-                if (watchtree)
-                    scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
-                else
-                    scp->flags &= ~CM_SCACHEFLAG_WATCHED;
-                lock_ReleaseWrite(&scp->rw);
+                if (scp) {
+                    lock_ObtainWrite(&scp->rw);
+                   if (watchtree)
+                        scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
+                    else
+                       scp->flags &= ~CM_SCACHEFLAG_WATCHED;
+                    lock_ReleaseWrite(&scp->rw);
+                }
                 smb_ReleaseFID(fidp);
             } else {
                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
@@ -8710,24 +9673,29 @@ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     tp = smb_GetSMBData(inp, NULL);
     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+    if (!oldPathp)
+        return CM_ERROR_BADSMB;
     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+    if (!newPathp)
+        return CM_ERROR_BADSMB;
 
     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
              osi_LogSaveClientString(smb_logp, oldPathp),
              osi_LogSaveClientString(smb_logp, newPathp),
-             ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
+             ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
 
     if (rename_type == RENAME_FLAG_RENAME) {
         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
-    } else { /* RENAME_FLAG_HARD_LINK */
+    } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
         code = smb_Link(vcp,inp,oldPathp,newPathp);
-    }
+    } else
+        code = CM_ERROR_BADOP;
     return code;
 }
 
 void smb3_Init()
 {
-    lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
+    lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
 }
 
 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
@@ -8750,3 +9718,23 @@ cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_
     return userp;
 }
 
+cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
+{
+    smb_username_t *unp;
+    cm_user_t *     userp;
+
+    unp = smb_FindUserByName(usern, machine, flags);
+    if (!unp->userp) {
+        lock_ObtainMutex(&unp->mx);
+        unp->flags |= SMB_USERNAMEFLAG_SID;
+        unp->userp = cm_NewUser();
+        lock_ReleaseMutex(&unp->mx);
+        osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
+    }  else    {
+        osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
+    }
+    userp = unp->userp;
+    cm_HoldUser(userp);
+    smb_ReleaseUsername(unp);
+    return userp;
+}